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 <sys/types.h>
14 #include <sys/queue.h>
15 
16 #include <netdb.h>
17 #include <pwd.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <stdarg.h>
21 
22 #include "xmalloc.h"
23 #include "match.h"
24 #include "log.h"
25 #include "canohost.h"
26 #include "buffer.h"
27 #include "channels.h"
28 #include "auth-options.h"
29 #include "servconf.h"
30 #include "misc.h"
31 #include "key.h"
32 #include "hostfile.h"
33 #include "auth.h"
34 #include "monitor_wrap.h"
35 
36 __RCSID("$MirOS: src/usr.bin/ssh/auth-options.c,v 1.6 2009/03/22 15:01:11 tg Exp $");
37 
38 /* Flags set authorised_keys flags */
39 int no_port_forwarding_flag = 0;
40 int no_agent_forwarding_flag = 0;
41 int no_x11_forwarding_flag = 0;
42 int no_pty_flag = 0;
43 int no_user_rc = 0;
44 
45 /* "command=" option. */
46 char *forced_command = NULL;
47 
48 /* "environment=" options. */
49 struct envstring *custom_environment = NULL;
50 
51 /* "tunnel=" option. */
52 int forced_tun_device = -1;
53 
54 extern ServerOptions options;
55 
56 void
auth_clear_options(void)57 auth_clear_options(void)
58 {
59 	no_agent_forwarding_flag = 0;
60 	no_port_forwarding_flag = 0;
61 	no_pty_flag = 0;
62 	no_x11_forwarding_flag = 0;
63 	no_user_rc = 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  */
83 int
auth_parse_options(struct passwd * pw,char * opts,char * file,u_long linenum)84 auth_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 = "no-user-rc";
125 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
126 			auth_debug_add("User rc file execution disabled.");
127 			no_user_rc = 1;
128 			opts += strlen(cp);
129 			goto next_option;
130 		}
131 		cp = "command=\"";
132 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
133 			opts += strlen(cp);
134 			forced_command = xmalloc(strlen(opts) + 1);
135 			i = 0;
136 			while (*opts) {
137 				if (*opts == '"')
138 					break;
139 				if (*opts == '\\' && opts[1] == '"') {
140 					opts += 2;
141 					forced_command[i++] = '"';
142 					continue;
143 				}
144 				forced_command[i++] = *opts++;
145 			}
146 			if (!*opts) {
147 				debug("%.100s, line %lu: missing end quote",
148 				    file, linenum);
149 				auth_debug_add("%.100s, line %lu: missing end quote",
150 				    file, linenum);
151 				xfree(forced_command);
152 				forced_command = NULL;
153 				goto bad_option;
154 			}
155 			forced_command[i] = '\0';
156 			auth_debug_add("Forced command: %.900s", forced_command);
157 			opts++;
158 			goto next_option;
159 		}
160 		cp = "environment=\"";
161 		if (options.permit_user_env &&
162 		    strncasecmp(opts, cp, strlen(cp)) == 0) {
163 			char *s;
164 			struct envstring *new_envstring;
165 
166 			opts += strlen(cp);
167 			s = xmalloc(strlen(opts) + 1);
168 			i = 0;
169 			while (*opts) {
170 				if (*opts == '"')
171 					break;
172 				if (*opts == '\\' && opts[1] == '"') {
173 					opts += 2;
174 					s[i++] = '"';
175 					continue;
176 				}
177 				s[i++] = *opts++;
178 			}
179 			if (!*opts) {
180 				debug("%.100s, line %lu: missing end quote",
181 				    file, linenum);
182 				auth_debug_add("%.100s, line %lu: missing end quote",
183 				    file, linenum);
184 				xfree(s);
185 				goto bad_option;
186 			}
187 			s[i] = '\0';
188 			auth_debug_add("Adding to environment: %.900s", s);
189 			debug("Adding to environment: %.900s", s);
190 			opts++;
191 			new_envstring = xmalloc(sizeof(struct envstring));
192 			new_envstring->s = s;
193 			new_envstring->next = custom_environment;
194 			custom_environment = new_envstring;
195 			goto next_option;
196 		}
197 		cp = "from=\"";
198 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
199 			const char *remote_ip = get_remote_ipaddr();
200 			const char *remote_host = get_canonical_hostname(
201 			    options.use_dns);
202 			char *patterns = xmalloc(strlen(opts) + 1);
203 
204 			opts += strlen(cp);
205 			i = 0;
206 			while (*opts) {
207 				if (*opts == '"')
208 					break;
209 				if (*opts == '\\' && opts[1] == '"') {
210 					opts += 2;
211 					patterns[i++] = '"';
212 					continue;
213 				}
214 				patterns[i++] = *opts++;
215 			}
216 			if (!*opts) {
217 				debug("%.100s, line %lu: missing end quote",
218 				    file, linenum);
219 				auth_debug_add("%.100s, line %lu: missing end quote",
220 				    file, linenum);
221 				xfree(patterns);
222 				goto bad_option;
223 			}
224 			patterns[i] = '\0';
225 			opts++;
226 			switch (match_host_and_ip(remote_host, remote_ip,
227 			    patterns)) {
228 			case 1:
229 				xfree(patterns);
230 				/* Host name matches. */
231 				goto next_option;
232 			case -1:
233 				debug("%.100s, line %lu: invalid criteria",
234 				    file, linenum);
235 				auth_debug_add("%.100s, line %lu: "
236 				    "invalid criteria", file, linenum);
237 				/* FALLTHROUGH */
238 			case 0:
239 				xfree(patterns);
240 				logit("Authentication tried for %.100s with "
241 				    "correct key but not from a permitted "
242 				    "host (host=%.200s, ip=%.200s).",
243 				    pw->pw_name, remote_host, remote_ip);
244 				auth_debug_add("Your host '%.200s' is not "
245 				    "permitted to use this key for login.",
246 				    remote_host);
247 				break;
248 			}
249 			/* deny access */
250 			return 0;
251 		}
252 		cp = "permitopen=\"";
253 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
254 			char *host, *p;
255 			int port;
256 			char *patterns = xmalloc(strlen(opts) + 1);
257 
258 			opts += strlen(cp);
259 			i = 0;
260 			while (*opts) {
261 				if (*opts == '"')
262 					break;
263 				if (*opts == '\\' && opts[1] == '"') {
264 					opts += 2;
265 					patterns[i++] = '"';
266 					continue;
267 				}
268 				patterns[i++] = *opts++;
269 			}
270 			if (!*opts) {
271 				debug("%.100s, line %lu: missing end quote",
272 				    file, linenum);
273 				auth_debug_add("%.100s, line %lu: missing "
274 				    "end quote", file, linenum);
275 				xfree(patterns);
276 				goto bad_option;
277 			}
278 			patterns[i] = '\0';
279 			opts++;
280 			p = patterns;
281 			host = hpdelim(&p);
282 			if (host == NULL || strlen(host) >= NI_MAXHOST) {
283 				debug("%.100s, line %lu: Bad permitopen "
284 				    "specification <%.100s>", file, linenum,
285 				    patterns);
286 				auth_debug_add("%.100s, line %lu: "
287 				    "Bad permitopen specification", file,
288 				    linenum);
289 				xfree(patterns);
290 				goto bad_option;
291 			}
292 			host = cleanhostname(host);
293 			if (p == NULL || (port = a2port(p)) <= 0) {
294 				debug("%.100s, line %lu: Bad permitopen port "
295 				    "<%.100s>", file, linenum, p ? p : "");
296 				auth_debug_add("%.100s, line %lu: "
297 				    "Bad permitopen port", file, linenum);
298 				xfree(patterns);
299 				goto bad_option;
300 			}
301 			if (options.allow_tcp_forwarding)
302 				channel_add_permitted_opens(host, port);
303 			xfree(patterns);
304 			goto next_option;
305 		}
306 		cp = "tunnel=\"";
307 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
308 			char *tun = NULL;
309 			opts += strlen(cp);
310 			tun = xmalloc(strlen(opts) + 1);
311 			i = 0;
312 			while (*opts) {
313 				if (*opts == '"')
314 					break;
315 				tun[i++] = *opts++;
316 			}
317 			if (!*opts) {
318 				debug("%.100s, line %lu: missing end quote",
319 				    file, linenum);
320 				auth_debug_add("%.100s, line %lu: missing end quote",
321 				    file, linenum);
322 				xfree(tun);
323 				forced_tun_device = -1;
324 				goto bad_option;
325 			}
326 			tun[i] = '\0';
327 			forced_tun_device = a2tun(tun, NULL);
328 			xfree(tun);
329 			if (forced_tun_device == SSH_TUNID_ERR) {
330 				debug("%.100s, line %lu: invalid tun device",
331 				    file, linenum);
332 				auth_debug_add("%.100s, line %lu: invalid tun device",
333 				    file, linenum);
334 				forced_tun_device = -1;
335 				goto bad_option;
336 			}
337 			auth_debug_add("Forced tun device: %d", forced_tun_device);
338 			opts++;
339 			goto next_option;
340 		}
341 next_option:
342 		/*
343 		 * Skip the comma, and move to the next option
344 		 * (or break out if there are no more).
345 		 */
346 		if (!*opts)
347 			fatal("Bugs in auth-options.c option processing.");
348 		if (*opts == ' ' || *opts == '\t')
349 			break;		/* End of options. */
350 		if (*opts != ',')
351 			goto bad_option;
352 		opts++;
353 		/* Process the next option. */
354 	}
355 
356 	if (!use_privsep)
357 		auth_debug_send();
358 
359 	/* grant access */
360 	return 1;
361 
362 bad_option:
363 	logit("Bad options in %.100s file, line %lu: %.50s",
364 	    file, linenum, opts);
365 	auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
366 	    file, linenum, opts);
367 
368 	if (!use_privsep)
369 		auth_debug_send();
370 
371 	/* deny access */
372 	return 0;
373 }
374