]> andersk Git - gssapi-openssh.git/blame - openssh/auth1.c
setup kexgss_client like other kex client functions for OpenSSH 3.6 merge
[gssapi-openssh.git] / openssh / auth1.c
CommitLineData
3c0ef626 1/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved
4 *
5 * As far as I am concerned, the code I have written for this software
6 * can be used freely for any purpose. Any derived versions of this
7 * software must be clearly marked as such, and if the derived work is
8 * incompatible with the protocol description in the RFC file, it must be
9 * called by a name other than "ssh" or "Secure Shell".
10 */
11
12#include "includes.h"
d03f4262 13RCSID("$OpenBSD: auth1.c,v 1.44 2002/09/26 11:38:43 markus Exp $");
3c0ef626 14
15#include "xmalloc.h"
16#include "rsa.h"
17#include "ssh1.h"
099f4607 18#include "dispatch.h"
3c0ef626 19#include "packet.h"
20#include "buffer.h"
21#include "mpaux.h"
22#include "log.h"
23#include "servconf.h"
24#include "compat.h"
25#include "auth.h"
1e608e42 26#include "channels.h"
3c0ef626 27#include "session.h"
3c0ef626 28#include "uidswap.h"
510132b6 29#include "monitor_wrap.h"
3c0ef626 30
31/* import */
32extern ServerOptions options;
b59afbfe 33extern Authmethod method_gssapi;
34
35
3c0ef626 36
099f4607 37#ifdef GSSAPI
feefe038 38#ifdef GSI
39#include "globus_gss_assist.h"
40#endif
41
755621a1 42int userauth_gssapi(Authctxt *authctxt);
43
099f4607 44void
45auth1_gss_protocol_error(int type, u_int32_t plen, void *ctxt)
46{
47 Authctxt *authctxt = ctxt;
48 /* Other side told us to abort, dont need to tell him */
49 /* maybe we can us some other method. */
50 if (type == SSH_MSG_AUTH_GSSAPI_ABORT) {
51 log("auth1: GSSAPI aborting");
52 dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
53 authctxt->success = 1; /* get out of loop*/
54 return;
55 }
56
57 log("auth1: protocol error: type %d plen %d", type, plen);
58 packet_disconnect("Protocol error during GSSAPI authentication: "
59 "Unknown packet type %d", type);
60}
755621a1 61
c35f5009 62#ifdef GSI
b59afbfe 63int
64gsi_gridmap(char *subject_name, char **mapped_name)
65{
b311f64e 66#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
67 if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
68 return 0;
69 }
70#endif
b59afbfe 71 return(globus_gss_assist_gridmap(subject_name, mapped_name) == 0);
72}
c35f5009 73#endif
b59afbfe 74
755621a1 75/*
76 * SSH1 GSSAPI clients may send us a user name of the form:
77 *
78 * (1) username:x:SSL Subject Name
79 * or
80 * (2) username:i:SSL Subject Name
81 * or
82 * (3) username
83 *
84 * if case 1, then uname is an explicit name (ssh -l uname). Keep this
85 * name always, rewrite the user parameter to be just uname. We'll pull
86 * the GSSAPI idenity out and deal with (or skip it) later.
87 *
88 * if case 2, then uname is implicit (user didn't use the -l option), so
89 * use the default gridmap mapping and replace uname with whatever
90 * the gridmap maps to. If the gridmap mapping fails, drop down
91 * to just uname
92 *
93 * if case 3, then leave it be.
94 *
95 * This function may return the original pointer to the orginal string,
96 * the original pointer to a modified string, or a completely new pointer.
97 */
98static char *
99ssh1_gssapi_parse_userstring(char *userstring)
100{
101 char name_type = '\0'; /* explicit 'x' or implicit 'i' */
102 char *ssl_subject_name = NULL;
103 char *delim = NULL;
104
105 debug("Looking at username '%s' for gssapi-ssleay type name", userstring);
106 if((delim = strchr(userstring, ':')) != NULL) {
107 /* Parse and split into components */
108 ssl_subject_name = strchr(delim + 1, ':');
109
110 if (ssl_subject_name) {
111 /* Successful parse, split into components */
112 *delim = '\0';
113 name_type = *(delim + 1);
114 *ssl_subject_name = '\0';
115 ssl_subject_name++;
116
117 debug("Name parsed. type = '%c'. ssl subject name is \"%s\"",
118 name_type, ssl_subject_name);
119
120 } else {
121
122 debug("Don't understand name format. Letting it pass.");
123 }
124 }
125
126#ifdef GSI
127 if(ssl_subject_name) {
128 char *gridmapped_name = NULL;
129 switch (name_type) {
130 case 'x':
131 debug("explicit name given, using %s as username", userstring);
132 break;
133
134 case 'i':
135 /* gridmap check */
136 debug("implicit name given. gridmapping '%s'", ssl_subject_name);
137
b59afbfe 138 PRIVSEP(gsi_gridmap(ssl_subject_name, &gridmapped_name));
139 if (gridmapped_name && gridmapped_name[0] != '\0') {
755621a1 140 userstring = gridmapped_name;
141 debug("I gridmapped and got %s", userstring);
142
143 } else {
144 debug("I gridmapped and got null, reverting to %s", userstring);
145 }
146 break;
147
148 default:
149 debug("Unknown name type '%c'. Ignoring.", name_type);
150 break;
151 }
152 } else {
153 debug("didn't find any :'s so I assume it's just a user name");
154 }
155#endif /* GSI */
156
157 return userstring;
158}
099f4607 159#endif
160
3c0ef626 161/*
162 * convert ssh auth msg type into description
163 */
164static char *
165get_authname(int type)
166{
167 static char buf[1024];
168 switch (type) {
169 case SSH_CMSG_AUTH_PASSWORD:
170 return "password";
171 case SSH_CMSG_AUTH_RSA:
172 return "rsa";
173 case SSH_CMSG_AUTH_RHOSTS_RSA:
174 return "rhosts-rsa";
175 case SSH_CMSG_AUTH_RHOSTS:
176 return "rhosts";
177 case SSH_CMSG_AUTH_TIS:
178 case SSH_CMSG_AUTH_TIS_RESPONSE:
179 return "challenge-response";
180#if defined(KRB4) || defined(KRB5)
181 case SSH_CMSG_AUTH_KERBEROS:
182 return "kerberos";
099f4607 183#endif
184#if defined(GSSAPI)
185 case SSH_CMSG_AUTH_GSSAPI:
186 return "gssapi";
3c0ef626 187#endif
188 }
189 snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
190 return buf;
191}
192
193/*
194 * read packets, try to authenticate the user and
195 * return only if authentication is successful
196 */
197static void
198do_authloop(Authctxt *authctxt)
199{
200 int authenticated = 0;
201 u_int bits;
1e608e42 202 Key *client_host_key;
3c0ef626 203 BIGNUM *n;
204 char *client_user, *password;
205 char info[1024];
206 u_int dlen;
3c0ef626 207 u_int ulen;
208 int type = 0;
209 struct passwd *pw = authctxt->pw;
210
211 debug("Attempting authentication for %s%.100s.",
1e608e42 212 authctxt->valid ? "" : "illegal user ", authctxt->user);
3c0ef626 213
214 /* If the user has no password, accept authentication immediately. */
215 if (options.password_authentication &&
216#if defined(KRB4) || defined(KRB5)
217 (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
218#endif
510132b6 219 PRIVSEP(auth_password(authctxt, ""))) {
3c0ef626 220 auth_log(authctxt, 1, "without authentication", "");
221 return;
222 }
223
224 /* Indicate that authentication is needed. */
225 packet_start(SSH_SMSG_FAILURE);
226 packet_send();
227 packet_write_wait();
228
229 client_user = NULL;
230
231 for (;;) {
232 /* default to fail */
233 authenticated = 0;
234
235 info[0] = '\0';
236
237 /* Get a packet from the client. */
1e608e42 238 type = packet_read();
3c0ef626 239
240 /* Process the packet. */
241 switch (type) {
242
243#if defined(KRB4) || defined(KRB5)
244 case SSH_CMSG_AUTH_KERBEROS:
245 if (!options.kerberos_authentication) {
246 verbose("Kerberos authentication disabled.");
247 } else {
248 char *kdata = packet_get_string(&dlen);
1e608e42 249 packet_check_eom();
250
3c0ef626 251 if (kdata[0] == 4) { /* KRB_PROT_VERSION */
252#ifdef KRB4
d03f4262 253 KTEXT_ST tkt, reply;
3c0ef626 254 tkt.length = dlen;
255 if (tkt.length < MAX_KTXT_LEN)
256 memcpy(tkt.dat, kdata, tkt.length);
1e608e42 257
d03f4262 258 if (PRIVSEP(auth_krb4(authctxt, &tkt,
259 &client_user, &reply))) {
3c0ef626 260 authenticated = 1;
261 snprintf(info, sizeof(info),
262 " tktuser %.100s",
263 client_user);
d03f4262 264
265 packet_start(
266 SSH_SMSG_AUTH_KERBEROS_RESPONSE);
267 packet_put_string((char *)
268 reply.dat, reply.length);
269 packet_send();
270 packet_write_wait();
3c0ef626 271 }
272#endif /* KRB4 */
273 } else {
274#ifdef KRB5
d03f4262 275 krb5_data tkt, reply;
3c0ef626 276 tkt.length = dlen;
277 tkt.data = kdata;
1e608e42 278
d03f4262 279 if (PRIVSEP(auth_krb5(authctxt, &tkt,
280 &client_user, &reply))) {
3c0ef626 281 authenticated = 1;
282 snprintf(info, sizeof(info),
283 " tktuser %.100s",
284 client_user);
d03f4262 285
286 /* Send response to client */
287 packet_start(
288 SSH_SMSG_AUTH_KERBEROS_RESPONSE);
289 packet_put_string((char *)
290 reply.data, reply.length);
291 packet_send();
292 packet_write_wait();
293
294 if (reply.length)
295 xfree(reply.data);
3c0ef626 296 }
297#endif /* KRB5 */
298 }
299 xfree(kdata);
300 }
301 break;
302#endif /* KRB4 || KRB5 */
0b582e46 303
0b582e46 304#ifdef GSSAPI
099f4607 305 case SSH_CMSG_AUTH_GSSAPI:
306 if (!options.gss_authentication) {
307 verbose("GSSAPI authentication disabled.");
308 break;
309 }
310 /*
311 * GSSAPI was first added to ssh1 in ssh-1.2.27, and
312 * was added to the SecurtCRT product. In order
313 * to continue operating with these, we will add
314 * the equivelent GSSAPI support to SSH1.
315 * Will use the gssapi routines from the ssh2 as
316 * they are almost identical. But they use dispatch
317 * so we need to setup the dispatch tables here
318 * auth1.c for use only by the gssapi code.
319 * Since we already have the packet, we will call
320 * userauth_gssapi then start the dispatch loop.
321 */
322 if (!authctxt->valid) {
323 packet_disconnect("Authentication rejected for invalid user");
324 }
325 dispatch_init(&auth1_gss_protocol_error);
b59afbfe 326 method_gssapi.userauth(authctxt);
099f4607 327 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
328 if (authctxt->postponed) { /* failed, try other methods */
329 authctxt->success = 0;
330 authctxt->postponed = 0;
331 break;
332 }
099f4607 333 authenticated = 1;
334 break;
0b582e46 335#endif /* GSSAPI */
3c0ef626 336
337#if defined(AFS) || defined(KRB5)
338 /* XXX - punt on backward compatibility here. */
339 case SSH_CMSG_HAVE_KERBEROS_TGT:
340 packet_send_debug("Kerberos TGT passing disabled before authentication.");
341 break;
342#ifdef AFS
343 case SSH_CMSG_HAVE_AFS_TOKEN:
344 packet_send_debug("AFS token passing disabled before authentication.");
345 break;
346#endif /* AFS */
347#endif /* AFS || KRB5 */
1e608e42 348
3c0ef626 349 case SSH_CMSG_AUTH_RHOSTS:
350 if (!options.rhosts_authentication) {
351 verbose("Rhosts authentication disabled.");
352 break;
353 }
354 /*
355 * Get client user name. Note that we just have to
356 * trust the client; this is one reason why rhosts
357 * authentication is insecure. (Another is
358 * IP-spoofing on a local network.)
359 */
360 client_user = packet_get_string(&ulen);
1e608e42 361 packet_check_eom();
3c0ef626 362
363 /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
364 authenticated = auth_rhosts(pw, client_user);
365
366 snprintf(info, sizeof info, " ruser %.100s", client_user);
367 break;
368
369 case SSH_CMSG_AUTH_RHOSTS_RSA:
370 if (!options.rhosts_rsa_authentication) {
371 verbose("Rhosts with RSA authentication disabled.");
372 break;
373 }
374 /*
375 * Get client user name. Note that we just have to
376 * trust the client; root on the client machine can
377 * claim to be any user.
378 */
379 client_user = packet_get_string(&ulen);
380
381 /* Get the client host key. */
1e608e42 382 client_host_key = key_new(KEY_RSA1);
3c0ef626 383 bits = packet_get_int();
1e608e42 384 packet_get_bignum(client_host_key->rsa->e);
385 packet_get_bignum(client_host_key->rsa->n);
3c0ef626 386
1e608e42 387 if (bits != BN_num_bits(client_host_key->rsa->n))
3c0ef626 388 verbose("Warning: keysize mismatch for client_host_key: "
1e608e42 389 "actual %d, announced %d",
44a053a3 390 BN_num_bits(client_host_key->rsa->n), bits);
1e608e42 391 packet_check_eom();
3c0ef626 392
1e608e42 393 authenticated = auth_rhosts_rsa(pw, client_user,
394 client_host_key);
395 key_free(client_host_key);
3c0ef626 396
397 snprintf(info, sizeof info, " ruser %.100s", client_user);
398 break;
399
400 case SSH_CMSG_AUTH_RSA:
401 if (!options.rsa_authentication) {
402 verbose("RSA authentication disabled.");
403 break;
404 }
405 /* RSA authentication requested. */
1e608e42 406 if ((n = BN_new()) == NULL)
407 fatal("do_authloop: BN_new failed");
408 packet_get_bignum(n);
409 packet_check_eom();
3c0ef626 410 authenticated = auth_rsa(pw, n);
411 BN_clear_free(n);
412 break;
413
414 case SSH_CMSG_AUTH_PASSWORD:
415 if (!options.password_authentication) {
416 verbose("Password authentication disabled.");
417 break;
418 }
419 /*
420 * Read user password. It is in plain text, but was
421 * transmitted over the encrypted channel so it is
422 * not visible to an outside observer.
423 */
424 password = packet_get_string(&dlen);
1e608e42 425 packet_check_eom();
3c0ef626 426
3c0ef626 427 /* Try authentication with the password. */
510132b6 428 authenticated = PRIVSEP(auth_password(authctxt, password));
3c0ef626 429
430 memset(password, 0, strlen(password));
431 xfree(password);
432 break;
433
434 case SSH_CMSG_AUTH_TIS:
435 debug("rcvd SSH_CMSG_AUTH_TIS");
436 if (options.challenge_response_authentication == 1) {
437 char *challenge = get_challenge(authctxt);
438 if (challenge != NULL) {
439 debug("sending challenge '%s'", challenge);
440 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
441 packet_put_cstring(challenge);
442 xfree(challenge);
443 packet_send();
444 packet_write_wait();
445 continue;
446 }
447 }
448 break;
449 case SSH_CMSG_AUTH_TIS_RESPONSE:
450 debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
451 if (options.challenge_response_authentication == 1) {
452 char *response = packet_get_string(&dlen);
453 debug("got response '%s'", response);
1e608e42 454 packet_check_eom();
3c0ef626 455 authenticated = verify_response(authctxt, response);
456 memset(response, 'r', dlen);
457 xfree(response);
458 }
459 break;
460
461 default:
462 /*
463 * Any unknown messages will be ignored (and failure
464 * returned) during authentication.
465 */
466 log("Unknown message during authentication: type %d", type);
467 break;
468 }
469#ifdef BSD_AUTH
470 if (authctxt->as) {
471 auth_close(authctxt->as);
472 authctxt->as = NULL;
473 }
474#endif
475 if (!authctxt->valid && authenticated)
476 fatal("INTERNAL ERROR: authenticated invalid user %s",
477 authctxt->user);
478
d03f4262 479#ifdef _UNICOS
480 if (type == SSH_CMSG_AUTH_PASSWORD && !authenticated)
481 cray_login_failure(authctxt->user, IA_UDBERR);
482 if (authenticated && cray_access_denied(authctxt->user)) {
483 authenticated = 0;
484 fatal("Access denied for user %s.",authctxt->user);
485 }
486#endif /* _UNICOS */
487
3c0ef626 488#ifdef HAVE_CYGWIN
489 if (authenticated &&
1e608e42 490 !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) {
3c0ef626 491 packet_disconnect("Authentication rejected for uid %d.",
1e608e42 492 pw == NULL ? -1 : pw->pw_uid);
3c0ef626 493 authenticated = 0;
494 }
495#else
496 /* Special handling for root */
d03f4262 497 if (!use_privsep &&
498 authenticated && authctxt->pw->pw_uid == 0 &&
3c0ef626 499 !auth_root_allowed(get_authname(type)))
500 authenticated = 0;
501#endif
502#ifdef USE_PAM
510132b6 503 if (!use_privsep && authenticated &&
504 !do_pam_account(pw->pw_name, client_user))
3c0ef626 505 authenticated = 0;
506#endif
507
508 /* Log before sending the reply */
509 auth_log(authctxt, authenticated, get_authname(type), info);
510
511 if (client_user != NULL) {
512 xfree(client_user);
513 client_user = NULL;
514 }
515
516 if (authenticated)
517 return;
518
519 if (authctxt->failures++ > AUTH_FAIL_MAX) {
3c0ef626 520 packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
521 }
522
523 packet_start(SSH_SMSG_FAILURE);
524 packet_send();
525 packet_write_wait();
526 }
527}
528
529/*
530 * Performs authentication of an incoming connection. Session key has already
531 * been exchanged and encryption is enabled.
532 */
510132b6 533Authctxt *
1e608e42 534do_authentication(void)
3c0ef626 535{
536 Authctxt *authctxt;
3c0ef626 537 u_int ulen;
510132b6 538 char *user, *style = NULL;
3c0ef626 539
540 /* Get the name of the user that we wish to log in as. */
1e608e42 541 packet_read_expect(SSH_CMSG_USER);
3c0ef626 542
543 /* Get the user name. */
544 user = packet_get_string(&ulen);
1e608e42 545 packet_check_eom();
3c0ef626 546
755621a1 547#ifdef GSSAPI
96c41595 548 /* Parse GSSAPI identity from userstring */
549 user = ssh1_gssapi_parse_userstring(user);
0b582e46 550#endif /* GSSAPI */
3c0ef626 551
552 if ((style = strchr(user, ':')) != NULL)
553 *style++ = '\0';
554
510132b6 555#ifdef KRB5
3c0ef626 556 /* XXX - SSH.com Kerberos v5 braindeath. */
510132b6 557 if ((datafellows & SSH_BUG_K5USER) &&
558 options.kerberos_authentication) {
559 char *p;
560 if ((p = strchr(user, '@')) != NULL)
561 *p = '\0';
562 }
563#endif
1e608e42 564
3c0ef626 565 authctxt = authctxt_new();
566 authctxt->user = user;
567 authctxt->style = style;
568
569 /* Verify that the user is a valid user. */
510132b6 570 if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
3c0ef626 571 authctxt->valid = 1;
510132b6 572 else
3c0ef626 573 debug("do_authentication: illegal user %s", user);
3c0ef626 574
510132b6 575 setproctitle("%s%s", authctxt->pw ? user : "unknown",
576 use_privsep ? " [net]" : "");
3c0ef626 577
578#ifdef USE_PAM
510132b6 579 PRIVSEP(start_pam(authctxt->pw == NULL ? "NOUSER" : user));
3c0ef626 580#endif
581
582 /*
583 * If we are not running as root, the user must have the same uid as
584 * the server. (Unless you are running Windows)
585 */
586#ifndef HAVE_CYGWIN
510132b6 587 if (!use_privsep && getuid() != 0 && authctxt->pw &&
588 authctxt->pw->pw_uid != getuid())
3c0ef626 589 packet_disconnect("Cannot change user when server not running as root.");
590#endif
591
592 /*
593 * Loop until the user has been authenticated or the connection is
594 * closed, do_authloop() returns only if authentication is successful
595 */
596 do_authloop(authctxt);
597
598 /* The user has been authenticated and accepted. */
599 packet_start(SSH_SMSG_SUCCESS);
600 packet_send();
601 packet_write_wait();
602
510132b6 603 return (authctxt);
3c0ef626 604}
This page took 0.14527 seconds and 5 git commands to generate.