auth-options.c revision 192595
1/* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 djm Exp $ */
2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 *                    All rights reserved
6 * As far as I am concerned, the code I have written for this software
7 * can be used freely for any purpose.  Any derived versions of this
8 * software must be clearly marked as such, and if the derived work is
9 * incompatible with the protocol description in the RFC file, it must be
10 * called by a name other than "ssh" or "Secure Shell".
11 */
12
13#include "includes.h"
14
15#include <sys/types.h>
16
17#include <netdb.h>
18#include <pwd.h>
19#include <string.h>
20#include <stdio.h>
21#include <stdarg.h>
22
23#include "openbsd-compat/sys-queue.h"
24#include "xmalloc.h"
25#include "match.h"
26#include "log.h"
27#include "canohost.h"
28#include "buffer.h"
29#include "channels.h"
30#include "auth-options.h"
31#include "servconf.h"
32#include "misc.h"
33#include "key.h"
34#include "hostfile.h"
35#include "auth.h"
36#ifdef GSSAPI
37#include "ssh-gss.h"
38#endif
39#include "monitor_wrap.h"
40
41/* Flags set authorized_keys flags */
42int no_port_forwarding_flag = 0;
43int no_agent_forwarding_flag = 0;
44int no_x11_forwarding_flag = 0;
45int no_pty_flag = 0;
46int no_user_rc = 0;
47
48/* "command=" option. */
49char *forced_command = NULL;
50
51/* "environment=" options. */
52struct envstring *custom_environment = NULL;
53
54/* "tunnel=" option. */
55int forced_tun_device = -1;
56
57extern ServerOptions options;
58
59void
60auth_clear_options(void)
61{
62	no_agent_forwarding_flag = 0;
63	no_port_forwarding_flag = 0;
64	no_pty_flag = 0;
65	no_x11_forwarding_flag = 0;
66	no_user_rc = 0;
67	while (custom_environment) {
68		struct envstring *ce = custom_environment;
69		custom_environment = ce->next;
70		xfree(ce->s);
71		xfree(ce);
72	}
73	if (forced_command) {
74		xfree(forced_command);
75		forced_command = NULL;
76	}
77	forced_tun_device = -1;
78	channel_clear_permitted_opens();
79	auth_debug_reset();
80}
81
82/*
83 * return 1 if access is granted, 0 if not.
84 * side effect: sets key option flags
85 */
86int
87auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
88{
89	const char *cp;
90	int i;
91
92	/* reset options */
93	auth_clear_options();
94
95	if (!opts)
96		return 1;
97
98	while (*opts && *opts != ' ' && *opts != '\t') {
99		cp = "no-port-forwarding";
100		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
101			auth_debug_add("Port forwarding disabled.");
102			no_port_forwarding_flag = 1;
103			opts += strlen(cp);
104			goto next_option;
105		}
106		cp = "no-agent-forwarding";
107		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
108			auth_debug_add("Agent forwarding disabled.");
109			no_agent_forwarding_flag = 1;
110			opts += strlen(cp);
111			goto next_option;
112		}
113		cp = "no-X11-forwarding";
114		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
115			auth_debug_add("X11 forwarding disabled.");
116			no_x11_forwarding_flag = 1;
117			opts += strlen(cp);
118			goto next_option;
119		}
120		cp = "no-pty";
121		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
122			auth_debug_add("Pty allocation disabled.");
123			no_pty_flag = 1;
124			opts += strlen(cp);
125			goto next_option;
126		}
127		cp = "no-user-rc";
128		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
129			auth_debug_add("User rc file execution disabled.");
130			no_user_rc = 1;
131			opts += strlen(cp);
132			goto next_option;
133		}
134		cp = "command=\"";
135		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
136			opts += strlen(cp);
137			forced_command = xmalloc(strlen(opts) + 1);
138			i = 0;
139			while (*opts) {
140				if (*opts == '"')
141					break;
142				if (*opts == '\\' && opts[1] == '"') {
143					opts += 2;
144					forced_command[i++] = '"';
145					continue;
146				}
147				forced_command[i++] = *opts++;
148			}
149			if (!*opts) {
150				debug("%.100s, line %lu: missing end quote",
151				    file, linenum);
152				auth_debug_add("%.100s, line %lu: missing end quote",
153				    file, linenum);
154				xfree(forced_command);
155				forced_command = NULL;
156				goto bad_option;
157			}
158			forced_command[i] = '\0';
159			auth_debug_add("Forced command: %.900s", forced_command);
160			opts++;
161			goto next_option;
162		}
163		cp = "environment=\"";
164		if (options.permit_user_env &&
165		    strncasecmp(opts, cp, strlen(cp)) == 0) {
166			char *s;
167			struct envstring *new_envstring;
168
169			opts += strlen(cp);
170			s = xmalloc(strlen(opts) + 1);
171			i = 0;
172			while (*opts) {
173				if (*opts == '"')
174					break;
175				if (*opts == '\\' && opts[1] == '"') {
176					opts += 2;
177					s[i++] = '"';
178					continue;
179				}
180				s[i++] = *opts++;
181			}
182			if (!*opts) {
183				debug("%.100s, line %lu: missing end quote",
184				    file, linenum);
185				auth_debug_add("%.100s, line %lu: missing end quote",
186				    file, linenum);
187				xfree(s);
188				goto bad_option;
189			}
190			s[i] = '\0';
191			auth_debug_add("Adding to environment: %.900s", s);
192			debug("Adding to environment: %.900s", s);
193			opts++;
194			new_envstring = xmalloc(sizeof(struct envstring));
195			new_envstring->s = s;
196			new_envstring->next = custom_environment;
197			custom_environment = new_envstring;
198			goto next_option;
199		}
200		cp = "from=\"";
201		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
202			const char *remote_ip = get_remote_ipaddr();
203			const char *remote_host = get_canonical_hostname(
204			    options.use_dns);
205			char *patterns = xmalloc(strlen(opts) + 1);
206
207			opts += strlen(cp);
208			i = 0;
209			while (*opts) {
210				if (*opts == '"')
211					break;
212				if (*opts == '\\' && opts[1] == '"') {
213					opts += 2;
214					patterns[i++] = '"';
215					continue;
216				}
217				patterns[i++] = *opts++;
218			}
219			if (!*opts) {
220				debug("%.100s, line %lu: missing end quote",
221				    file, linenum);
222				auth_debug_add("%.100s, line %lu: missing end quote",
223				    file, linenum);
224				xfree(patterns);
225				goto bad_option;
226			}
227			patterns[i] = '\0';
228			opts++;
229			switch (match_host_and_ip(remote_host, remote_ip,
230			    patterns)) {
231			case 1:
232				xfree(patterns);
233				/* Host name matches. */
234				goto next_option;
235			case -1:
236				debug("%.100s, line %lu: invalid criteria",
237				    file, linenum);
238				auth_debug_add("%.100s, line %lu: "
239				    "invalid criteria", file, linenum);
240				/* FALLTHROUGH */
241			case 0:
242				xfree(patterns);
243				logit("Authentication tried for %.100s with "
244				    "correct key but not from a permitted "
245				    "host (host=%.200s, ip=%.200s).",
246				    pw->pw_name, remote_host, remote_ip);
247				auth_debug_add("Your host '%.200s' is not "
248				    "permitted to use this key for login.",
249				    remote_host);
250				break;
251			}
252			/* deny access */
253			return 0;
254		}
255		cp = "permitopen=\"";
256		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
257			char *host, *p;
258			int port;
259			char *patterns = xmalloc(strlen(opts) + 1);
260
261			opts += strlen(cp);
262			i = 0;
263			while (*opts) {
264				if (*opts == '"')
265					break;
266				if (*opts == '\\' && opts[1] == '"') {
267					opts += 2;
268					patterns[i++] = '"';
269					continue;
270				}
271				patterns[i++] = *opts++;
272			}
273			if (!*opts) {
274				debug("%.100s, line %lu: missing end quote",
275				    file, linenum);
276				auth_debug_add("%.100s, line %lu: missing "
277				    "end quote", file, linenum);
278				xfree(patterns);
279				goto bad_option;
280			}
281			patterns[i] = '\0';
282			opts++;
283			p = patterns;
284			host = hpdelim(&p);
285			if (host == NULL || strlen(host) >= NI_MAXHOST) {
286				debug("%.100s, line %lu: Bad permitopen "
287				    "specification <%.100s>", file, linenum,
288				    patterns);
289				auth_debug_add("%.100s, line %lu: "
290				    "Bad permitopen specification", file,
291				    linenum);
292				xfree(patterns);
293				goto bad_option;
294			}
295			host = cleanhostname(host);
296			if (p == NULL || (port = a2port(p)) <= 0) {
297				debug("%.100s, line %lu: Bad permitopen port "
298				    "<%.100s>", file, linenum, p ? p : "");
299				auth_debug_add("%.100s, line %lu: "
300				    "Bad permitopen port", file, linenum);
301				xfree(patterns);
302				goto bad_option;
303			}
304			if (options.allow_tcp_forwarding)
305				channel_add_permitted_opens(host, port);
306			xfree(patterns);
307			goto next_option;
308		}
309		cp = "tunnel=\"";
310		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
311			char *tun = NULL;
312			opts += strlen(cp);
313			tun = xmalloc(strlen(opts) + 1);
314			i = 0;
315			while (*opts) {
316				if (*opts == '"')
317					break;
318				tun[i++] = *opts++;
319			}
320			if (!*opts) {
321				debug("%.100s, line %lu: missing end quote",
322				    file, linenum);
323				auth_debug_add("%.100s, line %lu: missing end quote",
324				    file, linenum);
325				xfree(tun);
326				forced_tun_device = -1;
327				goto bad_option;
328			}
329			tun[i] = '\0';
330			forced_tun_device = a2tun(tun, NULL);
331			xfree(tun);
332			if (forced_tun_device == SSH_TUNID_ERR) {
333				debug("%.100s, line %lu: invalid tun device",
334				    file, linenum);
335				auth_debug_add("%.100s, line %lu: invalid tun device",
336				    file, linenum);
337				forced_tun_device = -1;
338				goto bad_option;
339			}
340			auth_debug_add("Forced tun device: %d", forced_tun_device);
341			opts++;
342			goto next_option;
343		}
344next_option:
345		/*
346		 * Skip the comma, and move to the next option
347		 * (or break out if there are no more).
348		 */
349		if (!*opts)
350			fatal("Bugs in auth-options.c option processing.");
351		if (*opts == ' ' || *opts == '\t')
352			break;		/* End of options. */
353		if (*opts != ',')
354			goto bad_option;
355		opts++;
356		/* Process the next option. */
357	}
358
359	if (!use_privsep)
360		auth_debug_send();
361
362	/* grant access */
363	return 1;
364
365bad_option:
366	logit("Bad options in %.100s file, line %lu: %.50s",
367	    file, linenum, opts);
368	auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
369	    file, linenum, opts);
370
371	if (!use_privsep)
372		auth_debug_send();
373
374	/* deny access */
375	return 0;
376}
377