]> andersk Git - openssh.git/blame - auth2.c
- OpenBSD CVS Updates:
[openssh.git] / auth2.c
CommitLineData
a306f2dd 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#include "includes.h"
74fc9186 30RCSID("$OpenBSD: auth2.c,v 1.11 2000/06/19 00:50:11 markus Exp $");
a306f2dd 31
32#include <openssl/dsa.h>
33#include <openssl/rsa.h>
34#include <openssl/evp.h>
35
36#include "xmalloc.h"
37#include "rsa.h"
38#include "ssh.h"
39#include "pty.h"
40#include "packet.h"
41#include "buffer.h"
42#include "cipher.h"
43#include "servconf.h"
44#include "compat.h"
45#include "channels.h"
46#include "bufaux.h"
47#include "ssh2.h"
48#include "auth.h"
49#include "session.h"
50#include "dispatch.h"
51#include "auth.h"
52#include "key.h"
53#include "kex.h"
54
55#include "dsa.h"
56#include "uidswap.h"
38c295d6 57#include "auth-options.h"
a306f2dd 58
59/* import */
60extern ServerOptions options;
61extern unsigned char *session_id2;
62extern int session_id2_len;
63
64/* protocol */
65
66void input_service_request(int type, int plen);
67void input_userauth_request(int type, int plen);
68void protocol_error(int type, int plen);
69
70/* auth */
71int ssh2_auth_none(struct passwd *pw);
72int ssh2_auth_password(struct passwd *pw);
38c295d6 73int ssh2_auth_pubkey(struct passwd *pw, char *service);
a306f2dd 74
75/* helper */
76struct passwd* auth_set_user(char *u, char *s);
77int user_dsa_key_allowed(struct passwd *pw, Key *key);
78
79typedef struct Authctxt Authctxt;
80struct Authctxt {
81 char *user;
82 char *service;
83 struct passwd pw;
84 int valid;
85};
86static Authctxt *authctxt = NULL;
87static int userauth_success = 0;
88
89/*
90 * loop until userauth_success == TRUE
91 */
92
93void
94do_authentication2()
95{
3189621b 96 /* turn off skey/kerberos, not supported by SSH2 */
8cb940db 97#ifdef SKEY
3189621b 98 options.skey_authentication = 0;
8cb940db 99#endif
100#ifdef KRB4
3189621b 101 options.kerberos_authentication = 0;
8cb940db 102#endif
3189621b 103
a306f2dd 104 dispatch_init(&protocol_error);
105 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
106 dispatch_run(DISPATCH_BLOCK, &userauth_success);
107 do_authenticated2();
108}
109
110void
111protocol_error(int type, int plen)
112{
113 log("auth: protocol error: type %d plen %d", type, plen);
114 packet_start(SSH2_MSG_UNIMPLEMENTED);
115 packet_put_int(0);
116 packet_send();
117 packet_write_wait();
118}
119
120void
121input_service_request(int type, int plen)
122{
123 unsigned int len;
124 int accept = 0;
125 char *service = packet_get_string(&len);
126 packet_done();
127
128 if (strcmp(service, "ssh-userauth") == 0) {
129 if (!userauth_success) {
130 accept = 1;
131 /* now we can handle user-auth requests */
132 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
133 }
134 }
135 /* XXX all other service requests are denied */
136
137 if (accept) {
138 packet_start(SSH2_MSG_SERVICE_ACCEPT);
139 packet_put_cstring(service);
140 packet_send();
141 packet_write_wait();
142 } else {
143 debug("bad service request %s", service);
144 packet_disconnect("bad service request %s", service);
145 }
146 xfree(service);
147}
148
149void
150input_userauth_request(int type, int plen)
151{
152 static void (*authlog) (const char *fmt,...) = verbose;
153 static int attempt = 0;
38c295d6 154 unsigned int len;
a306f2dd 155 int authenticated = 0;
38c295d6 156 char *user, *service, *method, *authmsg = NULL;
a306f2dd 157 struct passwd *pw;
c1ef8333 158#ifdef WITH_AIXAUTHENTICATE
159 extern char *aixloginmsg;
160#endif /* WITH_AIXAUTHENTICATE */
a306f2dd 161
a306f2dd 162 user = packet_get_string(&len);
163 service = packet_get_string(&len);
164 method = packet_get_string(&len);
c1ef8333 165 if (++attempt == AUTH_FAIL_MAX) {
166#ifdef WITH_AIXAUTHENTICATE
167 loginfailed(user,get_canonical_hostname(),"ssh");
168#endif /* WITH_AIXAUTHENTICATE */
169 packet_disconnect("too many failed userauth_requests");
170 }
a306f2dd 171 debug("userauth-request for user %s service %s method %s", user, service, method);
172
173 /* XXX we only allow the ssh-connection service */
174 pw = auth_set_user(user, service);
175 if (pw && strcmp(service, "ssh-connection")==0) {
176 if (strcmp(method, "none") == 0) {
177 authenticated = ssh2_auth_none(pw);
178 } else if (strcmp(method, "password") == 0) {
179 authenticated = ssh2_auth_password(pw);
180 } else if (strcmp(method, "publickey") == 0) {
38c295d6 181 authenticated = ssh2_auth_pubkey(pw, service);
a306f2dd 182 }
183 }
184 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
185 authenticated = 0;
186 log("ROOT LOGIN REFUSED FROM %.200s",
187 get_canonical_hostname());
188 }
189
190#ifdef USE_PAM
191 if (authenticated && !do_pam_account(pw->pw_name, NULL))
192 authenticated = 0;
193#endif /* USE_PAM */
194
1d1ffb87 195 /* Raise logging level */
196 if (authenticated == 1 ||
197 attempt == AUTH_FAIL_LOG ||
198 strcmp(method, "password") == 0)
199 authlog = log;
200
201 /* Log before sending the reply */
a306f2dd 202 if (authenticated == 1) {
203 authmsg = "Accepted";
1d1ffb87 204 } else if (authenticated == 0) {
205 authmsg = "Failed";
206 } else {
207 authmsg = "Postponed";
208 }
209 authlog("%s %s for %.200s from %.200s port %d ssh2",
210 authmsg,
211 method,
212 pw && pw->pw_uid == 0 ? "ROOT" : user,
213 get_remote_ipaddr(),
214 get_remote_port());
215
216 /* XXX todo: check if multiple auth methods are needed */
217 if (authenticated == 1) {
c1ef8333 218#ifdef WITH_AIXAUTHENTICATE
219 /* We don't have a pty yet, so just label the line as "ssh" */
220 if (loginsuccess(user,get_canonical_hostname(),"ssh",
221 &aixloginmsg) < 0)
222 aixloginmsg = NULL;
223#endif /* WITH_AIXAUTHENTICATE */
a306f2dd 224 /* turn off userauth */
225 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
226 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
227 packet_send();
228 packet_write_wait();
229 /* now we can break out */
230 userauth_success = 1;
231 } else if (authenticated == 0) {
a306f2dd 232 packet_start(SSH2_MSG_USERAUTH_FAILURE);
233 packet_put_cstring("publickey,password"); /* XXX dynamic */
234 packet_put_char(0); /* XXX partial success, unused */
235 packet_send();
236 packet_write_wait();
a306f2dd 237 }
a306f2dd 238
239 xfree(service);
240 xfree(user);
241 xfree(method);
242}
243
244int
245ssh2_auth_none(struct passwd *pw)
246{
247 packet_done();
248#ifdef USE_PAM
249 return auth_pam_password(pw, "");
250#else /* USE_PAM */
251 return auth_password(pw, "");
252#endif /* USE_PAM */
253}
254int
255ssh2_auth_password(struct passwd *pw)
256{
257 char *password;
258 int authenticated = 0;
259 int change;
260 unsigned int len;
261 change = packet_get_char();
262 if (change)
263 log("password change not supported");
264 password = packet_get_string(&len);
265 packet_done();
266 if (options.password_authentication &&
267#ifdef USE_PAM
268 auth_pam_password(pw, password) == 1)
269#else /* USE_PAM */
270 auth_password(pw, password) == 1)
271#endif /* USE_PAM */
272 authenticated = 1;
273 memset(password, 0, len);
274 xfree(password);
275 return authenticated;
276}
277int
38c295d6 278ssh2_auth_pubkey(struct passwd *pw, char *service)
a306f2dd 279{
280 Buffer b;
281 Key *key;
282 char *pkalg, *pkblob, *sig;
283 unsigned int alen, blen, slen;
284 int have_sig;
285 int authenticated = 0;
286
1d1ffb87 287 if (options.dsa_authentication == 0) {
a306f2dd 288 debug("pubkey auth disabled");
289 return 0;
290 }
291 have_sig = packet_get_char();
292 pkalg = packet_get_string(&alen);
293 if (strcmp(pkalg, KEX_DSS) != 0) {
294 xfree(pkalg);
295 log("bad pkalg %s", pkalg); /*XXX*/
296 return 0;
297 }
298 pkblob = packet_get_string(&blen);
299 key = dsa_key_from_blob(pkblob, blen);
300 if (key != NULL) {
301 if (have_sig) {
302 sig = packet_get_string(&slen);
303 packet_done();
304 buffer_init(&b);
74fc9186 305 if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
306 buffer_put_string(&b, session_id2, session_id2_len);
307 } else {
308 buffer_append(&b, session_id2, session_id2_len);
309 }
38c295d6 310 /* reconstruct packet */
a306f2dd 311 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
38c295d6 312 buffer_put_cstring(&b, pw->pw_name);
313 buffer_put_cstring(&b,
314 datafellows & SSH_BUG_PUBKEYAUTH ?
315 "ssh-userauth" :
316 service);
317 buffer_put_cstring(&b, "publickey");
318 buffer_put_char(&b, have_sig);
319 buffer_put_cstring(&b, KEX_DSS);
320 buffer_put_string(&b, pkblob, blen);
a306f2dd 321#ifdef DEBUG_DSS
322 buffer_dump(&b);
323#endif
324 /* test for correct signature */
325 if (user_dsa_key_allowed(pw, key) &&
326 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
327 authenticated = 1;
328 buffer_clear(&b);
329 xfree(sig);
330 } else {
331 packet_done();
332 debug("test key...");
333 /* test whether pkalg/pkblob are acceptable */
334 /* XXX fake reply and always send PK_OK ? */
1d1ffb87 335 /*
336 * XXX this allows testing whether a user is allowed
337 * to login: if you happen to have a valid pubkey this
338 * message is sent. the message is NEVER sent at all
339 * if a user is not allowed to login. is this an
340 * issue? -markus
341 */
a306f2dd 342 if (user_dsa_key_allowed(pw, key)) {
343 packet_start(SSH2_MSG_USERAUTH_PK_OK);
344 packet_put_string(pkalg, alen);
345 packet_put_string(pkblob, blen);
346 packet_send();
347 packet_write_wait();
348 authenticated = -1;
349 }
350 }
351 key_free(key);
352 }
353 xfree(pkalg);
354 xfree(pkblob);
355 return authenticated;
356}
357
358/* set and get current user */
359
360struct passwd*
361auth_get_user(void)
362{
363 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
364}
365
366struct passwd*
367auth_set_user(char *u, char *s)
368{
369 struct passwd *pw, *copy;
370
371 if (authctxt == NULL) {
372 authctxt = xmalloc(sizeof(*authctxt));
373 authctxt->valid = 0;
374 authctxt->user = xstrdup(u);
375 authctxt->service = xstrdup(s);
376 setproctitle("%s", u);
377 pw = getpwnam(u);
378 if (!pw || !allowed_user(pw)) {
379 log("auth_set_user: illegal user %s", u);
380 return NULL;
381 }
382#ifdef USE_PAM
383 start_pam(pw);
384#endif
385 copy = &authctxt->pw;
386 memset(copy, 0, sizeof(*copy));
387 copy->pw_name = xstrdup(pw->pw_name);
388 copy->pw_passwd = xstrdup(pw->pw_passwd);
389 copy->pw_uid = pw->pw_uid;
390 copy->pw_gid = pw->pw_gid;
391 copy->pw_dir = xstrdup(pw->pw_dir);
392 copy->pw_shell = xstrdup(pw->pw_shell);
393 authctxt->valid = 1;
394 } else {
395 if (strcmp(u, authctxt->user) != 0 ||
396 strcmp(s, authctxt->service) != 0) {
397 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
398 u, s, authctxt->user, authctxt->service);
399 return NULL;
400 }
401 }
402 return auth_get_user();
403}
404
405/* return 1 if user allows given key */
406int
407user_dsa_key_allowed(struct passwd *pw, Key *key)
408{
409 char line[8192], file[1024];
410 int found_key = 0;
411 unsigned int bits = -1;
412 FILE *f;
413 unsigned long linenum = 0;
414 struct stat st;
415 Key *found;
416
417 /* Temporarily use the user's uid. */
418 temporarily_use_uid(pw->pw_uid);
419
420 /* The authorized keys. */
421 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
422 SSH_USER_PERMITTED_KEYS2);
423
424 /* Fail quietly if file does not exist */
425 if (stat(file, &st) < 0) {
426 /* Restore the privileged uid. */
427 restore_uid();
428 return 0;
429 }
430 /* Open the file containing the authorized keys. */
431 f = fopen(file, "r");
432 if (!f) {
433 /* Restore the privileged uid. */
434 restore_uid();
435 return 0;
436 }
437 if (options.strict_modes) {
438 int fail = 0;
439 char buf[1024];
440 /* Check open file in order to avoid open/stat races */
441 if (fstat(fileno(f), &st) < 0 ||
442 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
443 (st.st_mode & 022) != 0) {
444 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
445 "bad ownership or modes for '%s'.", pw->pw_name, file);
446 fail = 1;
447 } else {
448 /* Check path to SSH_USER_PERMITTED_KEYS */
449 int i;
450 static const char *check[] = {
451 "", SSH_USER_DIR, NULL
452 };
453 for (i = 0; check[i]; i++) {
454 snprintf(line, sizeof line, "%.500s/%.100s",
455 pw->pw_dir, check[i]);
456 if (stat(line, &st) < 0 ||
457 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
458 (st.st_mode & 022) != 0) {
459 snprintf(buf, sizeof buf,
460 "DSA authentication refused for %.100s: "
461 "bad ownership or modes for '%s'.",
462 pw->pw_name, line);
463 fail = 1;
464 break;
465 }
466 }
467 }
468 if (fail) {
469 log(buf);
470 fclose(f);
471 restore_uid();
472 return 0;
473 }
474 }
475 found_key = 0;
476 found = key_new(KEY_DSA);
477
478 while (fgets(line, sizeof(line), f)) {
38c295d6 479 char *cp, *options = NULL;
a306f2dd 480 linenum++;
481 /* Skip leading whitespace, empty and comment lines. */
482 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
483 ;
484 if (!*cp || *cp == '\n' || *cp == '#')
485 continue;
38c295d6 486
a306f2dd 487 bits = key_read(found, &cp);
38c295d6 488 if (bits == 0) {
489 /* no key? check if there are options for this key */
490 int quoted = 0;
491 options = cp;
492 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
493 if (*cp == '\\' && cp[1] == '"')
494 cp++; /* Skip both */
495 else if (*cp == '"')
496 quoted = !quoted;
497 }
498 /* Skip remaining whitespace. */
499 for (; *cp == ' ' || *cp == '\t'; cp++)
500 ;
501 bits = key_read(found, &cp);
502 if (bits == 0) {
503 /* still no key? advance to next line*/
504 continue;
505 }
506 }
507 if (key_equal(found, key) &&
508 auth_parse_options(pw, options, linenum) == 1) {
a306f2dd 509 found_key = 1;
510 debug("matching key found: file %s, line %ld",
511 file, linenum);
512 break;
513 }
514 }
515 restore_uid();
516 fclose(f);
517 key_free(found);
518 return found_key;
519}
This page took 0.26929 seconds and 5 git commands to generate.