2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
28 #include <openssl/dsa.h>
29 #include <openssl/rsa.h>
30 #include <openssl/evp.h>
53 #include "auth-options.h"
61 extern ServerOptions options;
62 extern unsigned char *session_id2;
63 extern int session_id2_len;
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);
72 int ssh2_auth_none(struct passwd *pw);
73 int ssh2_auth_password(struct passwd *pw);
74 int ssh2_auth_pubkey(struct passwd *pw, char *service);
77 struct passwd* auth_set_user(char *u, char *s);
78 int user_dsa_key_allowed(struct passwd *pw, Key *key);
80 typedef struct Authctxt Authctxt;
87 static Authctxt *authctxt = NULL;
88 static int userauth_success = 0;
91 * loop until userauth_success == TRUE
97 /* turn off skey/kerberos, not supported by SSH2 */
99 options.skey_authentication = 0;
102 options.kerberos_authentication = 0;
105 dispatch_init(&protocol_error);
106 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
107 dispatch_run(DISPATCH_BLOCK, &userauth_success);
112 protocol_error(int type, int plen)
114 log("auth: protocol error: type %d plen %d", type, plen);
115 packet_start(SSH2_MSG_UNIMPLEMENTED);
122 input_service_request(int type, int plen)
126 char *service = packet_get_string(&len);
129 if (strcmp(service, "ssh-userauth") == 0) {
130 if (!userauth_success) {
132 /* now we can handle user-auth requests */
133 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
136 /* XXX all other service requests are denied */
139 packet_start(SSH2_MSG_SERVICE_ACCEPT);
140 packet_put_cstring(service);
144 debug("bad service request %s", service);
145 packet_disconnect("bad service request %s", service);
151 input_userauth_request(int type, int plen)
153 static void (*authlog) (const char *fmt,...) = verbose;
154 static int attempt = 0;
156 int authenticated = 0;
157 char *user, *service, *method, *authmsg = NULL;
159 #ifdef WITH_AIXAUTHENTICATE
160 extern char *aixloginmsg;
161 #endif /* WITH_AIXAUTHENTICATE */
163 user = packet_get_string(&len);
164 service = packet_get_string(&len);
165 method = packet_get_string(&len);
166 if (++attempt == AUTH_FAIL_MAX) {
167 #ifdef WITH_AIXAUTHENTICATE
168 loginfailed(user,get_canonical_hostname(),"ssh");
169 #endif /* WITH_AIXAUTHENTICATE */
170 packet_disconnect("too many failed userauth_requests");
172 debug("userauth-request for user %s service %s method %s", user, service, method);
174 /* XXX we only allow the ssh-connection service */
175 pw = auth_set_user(user, service);
176 if (pw && strcmp(service, "ssh-connection")==0) {
177 if (strcmp(method, "none") == 0) {
178 authenticated = ssh2_auth_none(pw);
179 } else if (strcmp(method, "password") == 0) {
180 authenticated = ssh2_auth_password(pw);
181 } else if (strcmp(method, "publickey") == 0) {
182 authenticated = ssh2_auth_pubkey(pw, service);
187 if (authenticated && !check_nt_auth(strcmp(method, "password") == 0, pw->pw_uid)) {
188 packet_disconnect("Authentication rejected for uid %d.",
194 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
196 log("ROOT LOGIN REFUSED FROM %.200s",
197 get_canonical_hostname());
201 if (authenticated && !do_pam_account(pw->pw_name, NULL))
205 /* Raise logging level */
206 if (authenticated == 1 ||
207 attempt == AUTH_FAIL_LOG ||
208 strcmp(method, "password") == 0)
211 /* Log before sending the reply */
212 if (authenticated == 1) {
213 authmsg = "Accepted";
214 } else if (authenticated == 0) {
217 authmsg = "Postponed";
219 authlog("%s %s for %.200s from %.200s port %d ssh2",
222 pw && pw->pw_uid == 0 ? "ROOT" : user,
226 /* XXX todo: check if multiple auth methods are needed */
227 if (authenticated == 1) {
228 #ifdef WITH_AIXAUTHENTICATE
229 /* We don't have a pty yet, so just label the line as "ssh" */
230 if (loginsuccess(user,get_canonical_hostname(),"ssh",
233 #endif /* WITH_AIXAUTHENTICATE */
234 /* turn off userauth */
235 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
236 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
239 /* now we can break out */
240 userauth_success = 1;
241 } else if (authenticated == 0) {
242 packet_start(SSH2_MSG_USERAUTH_FAILURE);
243 packet_put_cstring("publickey,password"); /* XXX dynamic */
244 packet_put_char(0); /* XXX partial success, unused */
255 ssh2_auth_none(struct passwd *pw)
258 extern int saved_argc;
259 extern char **saved_argv;
265 return auth_pam_password(pw, "");
266 #elif defined(HAVE_OSF_SIA)
267 return(sia_validate_user(NULL, saved_argc, saved_argv,
268 get_canonical_hostname(), pw->pw_name, NULL, 0, NULL,
270 #else /* !HAVE_OSF_SIA && !USE_PAM */
271 return auth_password(pw, "");
275 ssh2_auth_password(struct passwd *pw)
278 int authenticated = 0;
282 extern int saved_argc;
283 extern char **saved_argv;
285 change = packet_get_char();
287 log("password change not supported");
288 password = packet_get_string(&len);
290 if (options.password_authentication &&
292 auth_pam_password(pw, password) == 1)
293 #elif defined(HAVE_OSF_SIA)
294 sia_validate_user(NULL, saved_argc, saved_argv,
295 get_canonical_hostname(), pw->pw_name, NULL, 0,
296 NULL, password) == SIASUCCESS)
297 #else /* !USE_PAM && !HAVE_OSF_SIA */
298 auth_password(pw, password) == 1)
301 memset(password, 0, len);
303 return authenticated;
306 ssh2_auth_pubkey(struct passwd *pw, char *service)
310 char *pkalg, *pkblob, *sig;
311 unsigned int alen, blen, slen;
313 int authenticated = 0;
315 if (options.dsa_authentication == 0) {
316 debug("pubkey auth disabled");
319 have_sig = packet_get_char();
320 pkalg = packet_get_string(&alen);
321 if (strcmp(pkalg, KEX_DSS) != 0) {
323 log("bad pkalg %s", pkalg); /*XXX*/
326 pkblob = packet_get_string(&blen);
327 key = dsa_key_from_blob(pkblob, blen);
330 sig = packet_get_string(&slen);
333 if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
334 buffer_put_string(&b, session_id2, session_id2_len);
336 buffer_append(&b, session_id2, session_id2_len);
338 /* reconstruct packet */
339 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
340 buffer_put_cstring(&b, pw->pw_name);
341 buffer_put_cstring(&b,
342 datafellows & SSH_BUG_PUBKEYAUTH ?
345 buffer_put_cstring(&b, "publickey");
346 buffer_put_char(&b, have_sig);
347 buffer_put_cstring(&b, KEX_DSS);
348 buffer_put_string(&b, pkblob, blen);
352 /* test for correct signature */
353 if (user_dsa_key_allowed(pw, key) &&
354 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
360 debug("test key...");
361 /* test whether pkalg/pkblob are acceptable */
362 /* XXX fake reply and always send PK_OK ? */
364 * XXX this allows testing whether a user is allowed
365 * to login: if you happen to have a valid pubkey this
366 * message is sent. the message is NEVER sent at all
367 * if a user is not allowed to login. is this an
370 if (user_dsa_key_allowed(pw, key)) {
371 packet_start(SSH2_MSG_USERAUTH_PK_OK);
372 packet_put_string(pkalg, alen);
373 packet_put_string(pkblob, blen);
383 return authenticated;
386 /* set and get current user */
391 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
395 auth_set_user(char *u, char *s)
397 struct passwd *pw, *copy;
399 if (authctxt == NULL) {
400 authctxt = xmalloc(sizeof(*authctxt));
402 authctxt->user = xstrdup(u);
403 authctxt->service = xstrdup(s);
404 setproctitle("%s", u);
406 if (!pw || !allowed_user(pw)) {
407 log("auth_set_user: illegal user %s", u);
413 copy = &authctxt->pw;
414 memset(copy, 0, sizeof(*copy));
415 copy->pw_name = xstrdup(pw->pw_name);
416 copy->pw_passwd = xstrdup(pw->pw_passwd);
417 copy->pw_uid = pw->pw_uid;
418 copy->pw_gid = pw->pw_gid;
419 #ifdef HAVE_PW_CLASS_IN_PASSWD
420 copy->pw_class = xstrdup(pw->pw_class);
422 copy->pw_dir = xstrdup(pw->pw_dir);
423 copy->pw_shell = xstrdup(pw->pw_shell);
426 if (strcmp(u, authctxt->user) != 0 ||
427 strcmp(s, authctxt->service) != 0) {
428 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
429 u, s, authctxt->user, authctxt->service);
433 return auth_get_user();
436 /* return 1 if user allows given key */
438 user_dsa_key_allowed(struct passwd *pw, Key *key)
440 char line[8192], file[1024];
442 unsigned int bits = -1;
444 unsigned long linenum = 0;
448 /* Temporarily use the user's uid. */
449 temporarily_use_uid(pw->pw_uid);
451 /* The authorized keys. */
452 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
453 SSH_USER_PERMITTED_KEYS2);
455 /* Fail quietly if file does not exist */
456 if (stat(file, &st) < 0) {
457 /* Restore the privileged uid. */
461 /* Open the file containing the authorized keys. */
462 f = fopen(file, "r");
464 /* Restore the privileged uid. */
468 if (options.strict_modes) {
471 /* Check open file in order to avoid open/stat races */
472 if (fstat(fileno(f), &st) < 0 ||
473 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
474 (st.st_mode & 022) != 0) {
475 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
476 "bad ownership or modes for '%s'.", pw->pw_name, file);
479 /* Check path to SSH_USER_PERMITTED_KEYS */
481 static const char *check[] = {
482 "", SSH_USER_DIR, NULL
484 for (i = 0; check[i]; i++) {
485 snprintf(line, sizeof line, "%.500s/%.100s",
486 pw->pw_dir, check[i]);
487 if (stat(line, &st) < 0 ||
488 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
489 (st.st_mode & 022) != 0) {
490 snprintf(buf, sizeof buf,
491 "DSA authentication refused for %.100s: "
492 "bad ownership or modes for '%s'.",
507 found = key_new(KEY_DSA);
509 while (fgets(line, sizeof(line), f)) {
510 char *cp, *options = NULL;
512 /* Skip leading whitespace, empty and comment lines. */
513 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
515 if (!*cp || *cp == '\n' || *cp == '#')
518 bits = key_read(found, &cp);
520 /* no key? check if there are options for this key */
523 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
524 if (*cp == '\\' && cp[1] == '"')
525 cp++; /* Skip both */
529 /* Skip remaining whitespace. */
530 for (; *cp == ' ' || *cp == '\t'; cp++)
532 bits = key_read(found, &cp);
534 /* still no key? advance to next line*/
538 if (key_equal(found, key) &&
539 auth_parse_options(pw, options, linenum) == 1) {
541 debug("matching key found: file %s, line %ld",