xref: /freebsd/crypto/openssh/auth2.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Markus Friedl.
15  * 4. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #include "includes.h"
32 RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $");
33 
34 #include <openssl/dsa.h>
35 #include <openssl/rsa.h>
36 #include <openssl/evp.h>
37 
38 #include "xmalloc.h"
39 #include "rsa.h"
40 #include "ssh.h"
41 #include "pty.h"
42 #include "packet.h"
43 #include "buffer.h"
44 #include "cipher.h"
45 #include "servconf.h"
46 #include "compat.h"
47 #include "channels.h"
48 #include "bufaux.h"
49 #include "ssh2.h"
50 #include "auth.h"
51 #include "session.h"
52 #include "dispatch.h"
53 #include "auth.h"
54 #include "key.h"
55 #include "kex.h"
56 
57 #include "dsa.h"
58 #include "uidswap.h"
59 
60 /* import */
61 extern ServerOptions options;
62 extern unsigned char *session_id2;
63 extern int session_id2_len;
64 
65 /* protocol */
66 
67 void	input_service_request(int type, int plen);
68 void	input_userauth_request(int type, int plen);
69 void	protocol_error(int type, int plen);
70 
71 /* auth */
72 int	ssh2_auth_none(struct passwd *pw);
73 int	ssh2_auth_password(struct passwd *pw);
74 int	ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
75 
76 /* helper */
77 struct passwd*	 auth_set_user(char *u, char *s);
78 int	user_dsa_key_allowed(struct passwd *pw, Key *key);
79 
80 typedef struct Authctxt Authctxt;
81 struct Authctxt {
82 	char *user;
83 	char *service;
84 	struct passwd pw;
85 	int valid;
86 };
87 static Authctxt	*authctxt = NULL;
88 static int userauth_success = 0;
89 
90 /*
91  * loop until userauth_success == TRUE
92  */
93 
94 void
95 do_authentication2()
96 {
97 	/* turn off skey/kerberos, not supported by SSH2 */
98 #ifdef SKEY
99 	options.skey_authentication = 0;
100 #endif
101 #ifdef KRB4
102 	options.krb4_authentication = 0;
103 #endif
104 
105 	dispatch_init(&protocol_error);
106 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
107 	dispatch_run(DISPATCH_BLOCK, &userauth_success);
108 	do_authenticated2();
109 }
110 
111 void
112 protocol_error(int type, int plen)
113 {
114 	log("auth: protocol error: type %d plen %d", type, plen);
115 	packet_start(SSH2_MSG_UNIMPLEMENTED);
116 	packet_put_int(0);
117 	packet_send();
118 	packet_write_wait();
119 }
120 
121 void
122 input_service_request(int type, int plen)
123 {
124 	unsigned int len;
125 	int accept = 0;
126 	char *service = packet_get_string(&len);
127 	packet_done();
128 
129 	if (strcmp(service, "ssh-userauth") == 0) {
130 		if (!userauth_success) {
131 			accept = 1;
132 			/* now we can handle user-auth requests */
133 			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
134 		}
135 	}
136 	/* XXX all other service requests are denied */
137 
138 	if (accept) {
139 		packet_start(SSH2_MSG_SERVICE_ACCEPT);
140 		packet_put_cstring(service);
141 		packet_send();
142 		packet_write_wait();
143 	} else {
144 		debug("bad service request %s", service);
145 		packet_disconnect("bad service request %s", service);
146 	}
147 	xfree(service);
148 }
149 
150 void
151 input_userauth_request(int type, int plen)
152 {
153 	static void (*authlog) (const char *fmt,...) = verbose;
154 	static int attempt = 0;
155 	unsigned int len, rlen;
156 	int authenticated = 0;
157 	char *raw, *user, *service, *method, *authmsg = NULL;
158 	struct passwd *pw;
159 
160 	if (++attempt == AUTH_FAIL_MAX)
161 		packet_disconnect("too many failed userauth_requests");
162 
163 	raw = packet_get_raw(&rlen);
164 	if (plen != rlen)
165 		fatal("plen != rlen");
166 	user = packet_get_string(&len);
167 	service = packet_get_string(&len);
168 	method = packet_get_string(&len);
169 	debug("userauth-request for user %s service %s method %s", user, service, method);
170 
171 	/* XXX we only allow the ssh-connection service */
172 	pw = auth_set_user(user, service);
173 	if (pw && strcmp(service, "ssh-connection")==0) {
174 		if (strcmp(method, "none") == 0) {
175 			authenticated =	ssh2_auth_none(pw);
176 		} else if (strcmp(method, "password") == 0) {
177 			authenticated =	ssh2_auth_password(pw);
178 		} else if (strcmp(method, "publickey") == 0) {
179 			authenticated =	ssh2_auth_pubkey(pw, raw, rlen);
180 		}
181 	}
182 	if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
183 		authenticated = 0;
184 		log("ROOT LOGIN REFUSED FROM %.200s",
185 		    get_canonical_hostname());
186 	}
187 
188 	/* Raise logging level */
189 	if (authenticated == 1 ||
190 	    attempt == AUTH_FAIL_LOG ||
191 	    strcmp(method, "password") == 0)
192 		authlog = log;
193 
194 	/* Log before sending the reply */
195 	if (authenticated == 1) {
196 		authmsg = "Accepted";
197 	} else if (authenticated == 0) {
198 		authmsg = "Failed";
199 	} else {
200 		authmsg = "Postponed";
201 	}
202 	authlog("%s %s for %.200s from %.200s port %d ssh2",
203 		authmsg,
204 		method,
205 		pw && pw->pw_uid == 0 ? "ROOT" : user,
206 		get_remote_ipaddr(),
207 		get_remote_port());
208 
209 	/* XXX todo: check if multiple auth methods are needed */
210 	if (authenticated == 1) {
211 		/* turn off userauth */
212 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
213 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
214 		packet_send();
215 		packet_write_wait();
216 		/* now we can break out */
217 		userauth_success = 1;
218 	} else if (authenticated == 0) {
219 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
220 		packet_put_cstring("publickey,password");	/* XXX dynamic */
221 		packet_put_char(0);				/* XXX partial success, unused */
222 		packet_send();
223 		packet_write_wait();
224 	}
225 
226 	xfree(service);
227 	xfree(user);
228 	xfree(method);
229 }
230 
231 int
232 ssh2_auth_none(struct passwd *pw)
233 {
234 	packet_done();
235 	return auth_password(pw, "");
236 }
237 int
238 ssh2_auth_password(struct passwd *pw)
239 {
240 	char *password;
241 	int authenticated = 0;
242 	int change;
243 	unsigned int len;
244 	change = packet_get_char();
245 	if (change)
246 		log("password change not supported");
247 	password = packet_get_string(&len);
248 	packet_done();
249 	if (options.password_authentication &&
250 	    auth_password(pw, password) == 1)
251 		authenticated = 1;
252 	memset(password, 0, len);
253 	xfree(password);
254 	return authenticated;
255 }
256 int
257 ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
258 {
259 	Buffer b;
260 	Key *key;
261 	char *pkalg, *pkblob, *sig;
262 	unsigned int alen, blen, slen;
263 	int have_sig;
264 	int authenticated = 0;
265 
266 	if (options.dsa_authentication == 0) {
267 		debug("pubkey auth disabled");
268 		return 0;
269 	}
270 	if (datafellows & SSH_BUG_PUBKEYAUTH) {
271 		log("bug compatibility with ssh-2.0.13 pubkey not implemented");
272 		return 0;
273 	}
274 	have_sig = packet_get_char();
275 	pkalg = packet_get_string(&alen);
276 	if (strcmp(pkalg, KEX_DSS) != 0) {
277 		xfree(pkalg);
278 		log("bad pkalg %s", pkalg);	/*XXX*/
279 		return 0;
280 	}
281 	pkblob = packet_get_string(&blen);
282 	key = dsa_key_from_blob(pkblob, blen);
283 	if (key != NULL) {
284 		if (have_sig) {
285 			sig = packet_get_string(&slen);
286 			packet_done();
287 			buffer_init(&b);
288 			buffer_append(&b, session_id2, session_id2_len);
289 			buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
290 			if (slen + 4 > rlen)
291 				fatal("bad rlen/slen");
292 			buffer_append(&b, raw, rlen - slen - 4);
293 #ifdef DEBUG_DSS
294 			buffer_dump(&b);
295 #endif
296 			/* test for correct signature */
297 			if (user_dsa_key_allowed(pw, key) &&
298 			    dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
299 				authenticated = 1;
300 			buffer_clear(&b);
301 			xfree(sig);
302 		} else {
303 			packet_done();
304 			debug("test key...");
305 			/* test whether pkalg/pkblob are acceptable */
306 			/* XXX fake reply and always send PK_OK ? */
307 			/*
308 			 * XXX this allows testing whether a user is allowed
309 			 * to login: if you happen to have a valid pubkey this
310 			 * message is sent. the message is NEVER sent at all
311 			 * if a user is not allowed to login. is this an
312 			 * issue? -markus
313 			 */
314 			if (user_dsa_key_allowed(pw, key)) {
315 				packet_start(SSH2_MSG_USERAUTH_PK_OK);
316 				packet_put_string(pkalg, alen);
317 				packet_put_string(pkblob, blen);
318 				packet_send();
319 				packet_write_wait();
320 				authenticated = -1;
321 			}
322 		}
323 		key_free(key);
324 	}
325 	xfree(pkalg);
326 	xfree(pkblob);
327 	return authenticated;
328 }
329 
330 /* set and get current user */
331 
332 struct passwd*
333 auth_get_user(void)
334 {
335 	return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
336 }
337 
338 struct passwd*
339 auth_set_user(char *u, char *s)
340 {
341 	struct passwd *pw, *copy;
342 
343 	if (authctxt == NULL) {
344 		authctxt = xmalloc(sizeof(*authctxt));
345 		authctxt->valid = 0;
346 		authctxt->user = xstrdup(u);
347 		authctxt->service = xstrdup(s);
348 		setproctitle("%s", u);
349 		pw = getpwnam(u);
350 		if (!pw || !allowed_user(pw)) {
351 			log("auth_set_user: illegal user %s", u);
352 			return NULL;
353 		}
354 		copy = &authctxt->pw;
355 		memset(copy, 0, sizeof(*copy));
356 		copy->pw_name = xstrdup(pw->pw_name);
357 		copy->pw_passwd = xstrdup(pw->pw_passwd);
358 		copy->pw_uid = pw->pw_uid;
359 		copy->pw_gid = pw->pw_gid;
360 		copy->pw_dir = xstrdup(pw->pw_dir);
361 		copy->pw_shell = xstrdup(pw->pw_shell);
362 		copy->pw_class = xstrdup(pw->pw_class);
363 		copy->pw_expire = pw->pw_expire;
364 		copy->pw_change = pw->pw_change;
365 		authctxt->valid = 1;
366 	} else {
367 		if (strcmp(u, authctxt->user) != 0 ||
368 		    strcmp(s, authctxt->service) != 0) {
369 			log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
370 			    u, s, authctxt->user, authctxt->service);
371 			return NULL;
372 		}
373 	}
374 	return auth_get_user();
375 }
376 
377 /* return 1 if user allows given key */
378 int
379 user_dsa_key_allowed(struct passwd *pw, Key *key)
380 {
381 	char line[8192], file[1024];
382 	int found_key = 0;
383 	unsigned int bits = -1;
384 	FILE *f;
385 	unsigned long linenum = 0;
386 	struct stat st;
387 	Key *found;
388 
389 	/* Temporarily use the user's uid. */
390 	temporarily_use_uid(pw->pw_uid);
391 
392 	/* The authorized keys. */
393 	snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
394 	    SSH_USER_PERMITTED_KEYS2);
395 
396 	/* Fail quietly if file does not exist */
397 	if (stat(file, &st) < 0) {
398 		/* Restore the privileged uid. */
399 		restore_uid();
400 		return 0;
401 	}
402 	/* Open the file containing the authorized keys. */
403 	f = fopen(file, "r");
404 	if (!f) {
405 		/* Restore the privileged uid. */
406 		restore_uid();
407 		return 0;
408 	}
409 	if (options.strict_modes) {
410 		int fail = 0;
411 		char buf[1024];
412 		/* Check open file in order to avoid open/stat races */
413 		if (fstat(fileno(f), &st) < 0 ||
414 		    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
415 		    (st.st_mode & 022) != 0) {
416 			snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
417 			    "bad ownership or modes for '%s'.", pw->pw_name, file);
418 			fail = 1;
419 		} else {
420 			/* Check path to SSH_USER_PERMITTED_KEYS */
421 			int i;
422 			static const char *check[] = {
423 				"", SSH_USER_DIR, NULL
424 			};
425 			for (i = 0; check[i]; i++) {
426 				snprintf(line, sizeof line, "%.500s/%.100s",
427 				    pw->pw_dir, check[i]);
428 				if (stat(line, &st) < 0 ||
429 				    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
430 				    (st.st_mode & 022) != 0) {
431 					snprintf(buf, sizeof buf,
432 					    "DSA authentication refused for %.100s: "
433 					    "bad ownership or modes for '%s'.",
434 					    pw->pw_name, line);
435 					fail = 1;
436 					break;
437 				}
438 			}
439 		}
440 		if (fail) {
441 			log(buf);
442 			fclose(f);
443 			restore_uid();
444 			return 0;
445 		}
446 	}
447 	found_key = 0;
448 	found = key_new(KEY_DSA);
449 
450 	while (fgets(line, sizeof(line), f)) {
451 		char *cp;
452 		linenum++;
453 		/* Skip leading whitespace, empty and comment lines. */
454 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
455 			;
456 		if (!*cp || *cp == '\n' || *cp == '#')
457 			continue;
458 		bits = key_read(found, &cp);
459 		if (bits == 0)
460 			continue;
461 		if (key_equal(found, key)) {
462 			found_key = 1;
463 			debug("matching key found: file %s, line %ld",
464 			    file, linenum);
465 			break;
466 		}
467 	}
468 	restore_uid();
469 	fclose(f);
470 	key_free(found);
471 	return found_key;
472 }
473