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