xref: /onnv-gate/usr/src/cmd/ssh/sshd/auth-options.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4*0Sstevel@tonic-gate  *                    All rights reserved
5*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
6*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
7*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
8*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
9*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
10*0Sstevel@tonic-gate  */
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate #include "includes.h"
13*0Sstevel@tonic-gate RCSID("$OpenBSD: auth-options.c,v 1.26 2002/07/30 17:03:55 markus Exp $");
14*0Sstevel@tonic-gate 
15*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #include "xmalloc.h"
18*0Sstevel@tonic-gate #include "match.h"
19*0Sstevel@tonic-gate #include "log.h"
20*0Sstevel@tonic-gate #include "canohost.h"
21*0Sstevel@tonic-gate #include "channels.h"
22*0Sstevel@tonic-gate #include "auth-options.h"
23*0Sstevel@tonic-gate #include "servconf.h"
24*0Sstevel@tonic-gate #include "misc.h"
25*0Sstevel@tonic-gate #include "monitor_wrap.h"
26*0Sstevel@tonic-gate #include "auth.h"
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate /* Flags set authorized_keys flags */
29*0Sstevel@tonic-gate int no_port_forwarding_flag = 0;
30*0Sstevel@tonic-gate int no_agent_forwarding_flag = 0;
31*0Sstevel@tonic-gate int no_x11_forwarding_flag = 0;
32*0Sstevel@tonic-gate int no_pty_flag = 0;
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate /* "command=" option. */
35*0Sstevel@tonic-gate char *forced_command = NULL;
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /* "environment=" options. */
38*0Sstevel@tonic-gate struct envstring *custom_environment = NULL;
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate extern ServerOptions options;
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate void
43*0Sstevel@tonic-gate auth_clear_options(void)
44*0Sstevel@tonic-gate {
45*0Sstevel@tonic-gate 	no_agent_forwarding_flag = 0;
46*0Sstevel@tonic-gate 	no_port_forwarding_flag = 0;
47*0Sstevel@tonic-gate 	no_pty_flag = 0;
48*0Sstevel@tonic-gate 	no_x11_forwarding_flag = 0;
49*0Sstevel@tonic-gate 	while (custom_environment) {
50*0Sstevel@tonic-gate 		struct envstring *ce = custom_environment;
51*0Sstevel@tonic-gate 		custom_environment = ce->next;
52*0Sstevel@tonic-gate 		xfree(ce->s);
53*0Sstevel@tonic-gate 		xfree(ce);
54*0Sstevel@tonic-gate 	}
55*0Sstevel@tonic-gate 	if (forced_command) {
56*0Sstevel@tonic-gate 		xfree(forced_command);
57*0Sstevel@tonic-gate 		forced_command = NULL;
58*0Sstevel@tonic-gate 	}
59*0Sstevel@tonic-gate 	channel_clear_permitted_opens();
60*0Sstevel@tonic-gate 	auth_debug_reset();
61*0Sstevel@tonic-gate }
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate /*
64*0Sstevel@tonic-gate  * return 1 if access is granted, 0 if not.
65*0Sstevel@tonic-gate  * side effect: sets key option flags
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate int
68*0Sstevel@tonic-gate auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
69*0Sstevel@tonic-gate {
70*0Sstevel@tonic-gate 	const char *cp;
71*0Sstevel@tonic-gate 	int i;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	/* reset options */
74*0Sstevel@tonic-gate 	auth_clear_options();
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	if (!opts)
77*0Sstevel@tonic-gate 		return 1;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	while (*opts && *opts != ' ' && *opts != '\t') {
80*0Sstevel@tonic-gate 		cp = "no-port-forwarding";
81*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
82*0Sstevel@tonic-gate 			auth_debug_add("Port forwarding disabled.");
83*0Sstevel@tonic-gate 			no_port_forwarding_flag = 1;
84*0Sstevel@tonic-gate 			opts += strlen(cp);
85*0Sstevel@tonic-gate 			goto next_option;
86*0Sstevel@tonic-gate 		}
87*0Sstevel@tonic-gate 		cp = "no-agent-forwarding";
88*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
89*0Sstevel@tonic-gate 			auth_debug_add("Agent forwarding disabled.");
90*0Sstevel@tonic-gate 			no_agent_forwarding_flag = 1;
91*0Sstevel@tonic-gate 			opts += strlen(cp);
92*0Sstevel@tonic-gate 			goto next_option;
93*0Sstevel@tonic-gate 		}
94*0Sstevel@tonic-gate 		cp = "no-X11-forwarding";
95*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
96*0Sstevel@tonic-gate 			auth_debug_add("X11 forwarding disabled.");
97*0Sstevel@tonic-gate 			no_x11_forwarding_flag = 1;
98*0Sstevel@tonic-gate 			opts += strlen(cp);
99*0Sstevel@tonic-gate 			goto next_option;
100*0Sstevel@tonic-gate 		}
101*0Sstevel@tonic-gate 		cp = "no-pty";
102*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
103*0Sstevel@tonic-gate 			auth_debug_add("Pty allocation disabled.");
104*0Sstevel@tonic-gate 			no_pty_flag = 1;
105*0Sstevel@tonic-gate 			opts += strlen(cp);
106*0Sstevel@tonic-gate 			goto next_option;
107*0Sstevel@tonic-gate 		}
108*0Sstevel@tonic-gate 		cp = "command=\"";
109*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
110*0Sstevel@tonic-gate 			opts += strlen(cp);
111*0Sstevel@tonic-gate 			forced_command = xmalloc(strlen(opts) + 1);
112*0Sstevel@tonic-gate 			i = 0;
113*0Sstevel@tonic-gate 			while (*opts) {
114*0Sstevel@tonic-gate 				if (*opts == '"')
115*0Sstevel@tonic-gate 					break;
116*0Sstevel@tonic-gate 				if (*opts == '\\' && opts[1] == '"') {
117*0Sstevel@tonic-gate 					opts += 2;
118*0Sstevel@tonic-gate 					forced_command[i++] = '"';
119*0Sstevel@tonic-gate 					continue;
120*0Sstevel@tonic-gate 				}
121*0Sstevel@tonic-gate 				forced_command[i++] = *opts++;
122*0Sstevel@tonic-gate 			}
123*0Sstevel@tonic-gate 			if (!*opts) {
124*0Sstevel@tonic-gate 				debug("%.100s, line %lu: missing end quote",
125*0Sstevel@tonic-gate 				    file, linenum);
126*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: missing end quote",
127*0Sstevel@tonic-gate 				    file, linenum);
128*0Sstevel@tonic-gate 				xfree(forced_command);
129*0Sstevel@tonic-gate 				forced_command = NULL;
130*0Sstevel@tonic-gate 				goto bad_option;
131*0Sstevel@tonic-gate 			}
132*0Sstevel@tonic-gate 			forced_command[i] = 0;
133*0Sstevel@tonic-gate 			auth_debug_add("Forced command: %.900s", forced_command);
134*0Sstevel@tonic-gate 			opts++;
135*0Sstevel@tonic-gate 			goto next_option;
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 		cp = "environment=\"";
138*0Sstevel@tonic-gate 		if (options.permit_user_env &&
139*0Sstevel@tonic-gate 		    strncasecmp(opts, cp, strlen(cp)) == 0) {
140*0Sstevel@tonic-gate 			char *s;
141*0Sstevel@tonic-gate 			struct envstring *new_envstring;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 			opts += strlen(cp);
144*0Sstevel@tonic-gate 			s = xmalloc(strlen(opts) + 1);
145*0Sstevel@tonic-gate 			i = 0;
146*0Sstevel@tonic-gate 			while (*opts) {
147*0Sstevel@tonic-gate 				if (*opts == '"')
148*0Sstevel@tonic-gate 					break;
149*0Sstevel@tonic-gate 				if (*opts == '\\' && opts[1] == '"') {
150*0Sstevel@tonic-gate 					opts += 2;
151*0Sstevel@tonic-gate 					s[i++] = '"';
152*0Sstevel@tonic-gate 					continue;
153*0Sstevel@tonic-gate 				}
154*0Sstevel@tonic-gate 				s[i++] = *opts++;
155*0Sstevel@tonic-gate 			}
156*0Sstevel@tonic-gate 			if (!*opts) {
157*0Sstevel@tonic-gate 				debug("%.100s, line %lu: missing end quote",
158*0Sstevel@tonic-gate 				    file, linenum);
159*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: missing end quote",
160*0Sstevel@tonic-gate 				    file, linenum);
161*0Sstevel@tonic-gate 				xfree(s);
162*0Sstevel@tonic-gate 				goto bad_option;
163*0Sstevel@tonic-gate 			}
164*0Sstevel@tonic-gate 			s[i] = 0;
165*0Sstevel@tonic-gate 			auth_debug_add("Adding to environment: %.900s", s);
166*0Sstevel@tonic-gate 			debug("Adding to environment: %.900s", s);
167*0Sstevel@tonic-gate 			opts++;
168*0Sstevel@tonic-gate 			new_envstring = xmalloc(sizeof(struct envstring));
169*0Sstevel@tonic-gate 			new_envstring->s = s;
170*0Sstevel@tonic-gate 			new_envstring->next = custom_environment;
171*0Sstevel@tonic-gate 			custom_environment = new_envstring;
172*0Sstevel@tonic-gate 			goto next_option;
173*0Sstevel@tonic-gate 		}
174*0Sstevel@tonic-gate 		cp = "from=\"";
175*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
176*0Sstevel@tonic-gate 			const char *remote_ip = get_remote_ipaddr();
177*0Sstevel@tonic-gate 			const char *remote_host = get_canonical_hostname(
178*0Sstevel@tonic-gate 			    options.verify_reverse_mapping);
179*0Sstevel@tonic-gate 			char *patterns = xmalloc(strlen(opts) + 1);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 			opts += strlen(cp);
182*0Sstevel@tonic-gate 			i = 0;
183*0Sstevel@tonic-gate 			while (*opts) {
184*0Sstevel@tonic-gate 				if (*opts == '"')
185*0Sstevel@tonic-gate 					break;
186*0Sstevel@tonic-gate 				if (*opts == '\\' && opts[1] == '"') {
187*0Sstevel@tonic-gate 					opts += 2;
188*0Sstevel@tonic-gate 					patterns[i++] = '"';
189*0Sstevel@tonic-gate 					continue;
190*0Sstevel@tonic-gate 				}
191*0Sstevel@tonic-gate 				patterns[i++] = *opts++;
192*0Sstevel@tonic-gate 			}
193*0Sstevel@tonic-gate 			if (!*opts) {
194*0Sstevel@tonic-gate 				debug("%.100s, line %lu: missing end quote",
195*0Sstevel@tonic-gate 				    file, linenum);
196*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: missing end quote",
197*0Sstevel@tonic-gate 				    file, linenum);
198*0Sstevel@tonic-gate 				xfree(patterns);
199*0Sstevel@tonic-gate 				goto bad_option;
200*0Sstevel@tonic-gate 			}
201*0Sstevel@tonic-gate 			patterns[i] = 0;
202*0Sstevel@tonic-gate 			opts++;
203*0Sstevel@tonic-gate 			if (match_host_and_ip(remote_host, remote_ip,
204*0Sstevel@tonic-gate 			    patterns) != 1) {
205*0Sstevel@tonic-gate 				xfree(patterns);
206*0Sstevel@tonic-gate 				log("Authentication tried for %.100s with "
207*0Sstevel@tonic-gate 				    "correct key but not from a permitted "
208*0Sstevel@tonic-gate 				    "host (host=%.200s, ip=%.200s).",
209*0Sstevel@tonic-gate 				    pw->pw_name, remote_host, remote_ip);
210*0Sstevel@tonic-gate 				auth_debug_add("Your host '%.200s' is not "
211*0Sstevel@tonic-gate 				    "permitted to use this key for login.",
212*0Sstevel@tonic-gate 				    remote_host);
213*0Sstevel@tonic-gate 				/* deny access */
214*0Sstevel@tonic-gate 				return 0;
215*0Sstevel@tonic-gate 			}
216*0Sstevel@tonic-gate 			xfree(patterns);
217*0Sstevel@tonic-gate 			/* Host name matches. */
218*0Sstevel@tonic-gate 			goto next_option;
219*0Sstevel@tonic-gate 		}
220*0Sstevel@tonic-gate 		cp = "permitopen=\"";
221*0Sstevel@tonic-gate 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
222*0Sstevel@tonic-gate 			char host[256], sport[6];
223*0Sstevel@tonic-gate 			u_short port;
224*0Sstevel@tonic-gate 			char *patterns = xmalloc(strlen(opts) + 1);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 			opts += strlen(cp);
227*0Sstevel@tonic-gate 			i = 0;
228*0Sstevel@tonic-gate 			while (*opts) {
229*0Sstevel@tonic-gate 				if (*opts == '"')
230*0Sstevel@tonic-gate 					break;
231*0Sstevel@tonic-gate 				if (*opts == '\\' && opts[1] == '"') {
232*0Sstevel@tonic-gate 					opts += 2;
233*0Sstevel@tonic-gate 					patterns[i++] = '"';
234*0Sstevel@tonic-gate 					continue;
235*0Sstevel@tonic-gate 				}
236*0Sstevel@tonic-gate 				patterns[i++] = *opts++;
237*0Sstevel@tonic-gate 			}
238*0Sstevel@tonic-gate 			if (!*opts) {
239*0Sstevel@tonic-gate 				debug("%.100s, line %lu: missing end quote",
240*0Sstevel@tonic-gate 				    file, linenum);
241*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: missing end quote",
242*0Sstevel@tonic-gate 				    file, linenum);
243*0Sstevel@tonic-gate 				xfree(patterns);
244*0Sstevel@tonic-gate 				goto bad_option;
245*0Sstevel@tonic-gate 			}
246*0Sstevel@tonic-gate 			patterns[i] = 0;
247*0Sstevel@tonic-gate 			opts++;
248*0Sstevel@tonic-gate 			if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
249*0Sstevel@tonic-gate 			    sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
250*0Sstevel@tonic-gate 				debug("%.100s, line %lu: Bad permitopen specification "
251*0Sstevel@tonic-gate 				    "<%.100s>", file, linenum, patterns);
252*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: "
253*0Sstevel@tonic-gate 				    "Bad permitopen specification", file, linenum);
254*0Sstevel@tonic-gate 				xfree(patterns);
255*0Sstevel@tonic-gate 				goto bad_option;
256*0Sstevel@tonic-gate 			}
257*0Sstevel@tonic-gate 			if ((port = a2port(sport)) == 0) {
258*0Sstevel@tonic-gate 				debug("%.100s, line %lu: Bad permitopen port <%.100s>",
259*0Sstevel@tonic-gate 				    file, linenum, sport);
260*0Sstevel@tonic-gate 				auth_debug_add("%.100s, line %lu: "
261*0Sstevel@tonic-gate 				    "Bad permitopen port", file, linenum);
262*0Sstevel@tonic-gate 				xfree(patterns);
263*0Sstevel@tonic-gate 				goto bad_option;
264*0Sstevel@tonic-gate 			}
265*0Sstevel@tonic-gate 			if (options.allow_tcp_forwarding)
266*0Sstevel@tonic-gate 				channel_add_permitted_opens(host, port);
267*0Sstevel@tonic-gate 			xfree(patterns);
268*0Sstevel@tonic-gate 			goto next_option;
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate next_option:
271*0Sstevel@tonic-gate 		/*
272*0Sstevel@tonic-gate 		 * Skip the comma, and move to the next option
273*0Sstevel@tonic-gate 		 * (or break out if there are no more).
274*0Sstevel@tonic-gate 		 */
275*0Sstevel@tonic-gate 		if (!*opts)
276*0Sstevel@tonic-gate 			fatal("Bugs in auth-options.c option processing.");
277*0Sstevel@tonic-gate 		if (*opts == ' ' || *opts == '\t')
278*0Sstevel@tonic-gate 			break;		/* End of options. */
279*0Sstevel@tonic-gate 		if (*opts != ',')
280*0Sstevel@tonic-gate 			goto bad_option;
281*0Sstevel@tonic-gate 		opts++;
282*0Sstevel@tonic-gate 		/* Process the next option. */
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	if (!use_privsep)
286*0Sstevel@tonic-gate 		auth_debug_send();
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	/* grant access */
289*0Sstevel@tonic-gate 	return 1;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate bad_option:
292*0Sstevel@tonic-gate 	log("Bad options in %.100s file, line %lu: %.50s",
293*0Sstevel@tonic-gate 	    file, linenum, opts);
294*0Sstevel@tonic-gate 	auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
295*0Sstevel@tonic-gate 	    file, linenum, opts);
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	if (!use_privsep)
298*0Sstevel@tonic-gate 		auth_debug_send();
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	/* deny access */
301*0Sstevel@tonic-gate 	return 0;
302*0Sstevel@tonic-gate }
303