1 From 4693de3d73bce0c0f1000bf2c0efd4c06190ecdf Mon Sep 17 00:00:00 2001
2 From: Sam Hartman <hartmans@debian.org>
3 Date: Mon, 19 Sep 2011 16:35:48 -0400
4 Subject: [PATCH] initial empty usernames on top of keyex and role
7 auth-pam.c | 51 +++++++++++++++++++++++++++++-
9 auth2-gss.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
10 auth2.c | 86 +++++++++++++++++++++++++++++++++++++++++----------
11 4 files changed, 206 insertions(+), 30 deletions(-)
13 Index: openssh/auth-pam.c
14 ===================================================================
15 --- openssh.orig/auth-pam.c 2011-09-21 18:55:39.000000000 -0400
16 +++ openssh/auth-pam.c 2011-09-21 18:57:32.000000000 -0400
20 * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
21 - * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
22 + * Copyright (c) 2003,2004,2006 Darren Tucker <dtucker@zip.com.au>
24 * Permission to use, copy, modify, and distribute this software for any
25 * purpose with or without fee is hereby granted, provided that the above
28 typedef pthread_t sp_pthread_t;
30 +#define pthread_create openssh_pthread_create
31 +#define pthread_exit openssh_pthread_exit
32 +#define pthread_cancel openssh_pthread_cancel
33 +#define pthread_join openssh_pthread_join
34 typedef pid_t sp_pthread_t;
38 # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b)))
42 +sshpam_getpw(const char *user)
46 + if ((pw = getpwnam(user)) != NULL)
49 + debug("PAM: faking passwd struct for user '%.100s'", user);
50 + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
52 + pw->pw_name = xstrdup(user); /* XXX leak */
53 + pw->pw_shell = "/bin/true";
54 + pw->pw_gecos = "sshd fake PAM user";
59 +sshpam_check_userchanged(void)
65 + debug("sshpam_check_userchanged");
66 + sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user);
67 + if (sshpam_err != PAM_SUCCESS)
68 + fatal("PAM: could not get PAM_USER: %s",
69 + pam_strerror(sshpam_handle, sshpam_err));
70 + if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) {
71 + debug("PAM: user mapped from '%.100s' to '%.100s'",
72 + sshpam_authctxt->pw->pw_name, user);
73 + if ((pw = getpwnam(user)) == NULL)
74 + fatal("PAM: could not get passwd entry for user "
75 + "'%.100s' provided by PAM_USER", user);
76 + pwfree(sshpam_authctxt->pw);
77 + sshpam_authctxt->pw = pw;
78 + sshpam_authctxt->valid = allowed_user(pw);
79 + debug("PAM: user '%.100s' now %svalid", user,
80 + sshpam_authctxt->valid ? "" : "in");
85 sshpam_password_change_required(int reqd)
89 import_environments(Buffer *b)
96 Index: openssh/auth-pam.h
97 ===================================================================
98 --- openssh.orig/auth-pam.h 2011-09-21 18:55:39.000000000 -0400
99 +++ openssh/auth-pam.h 2011-09-21 18:57:32.000000000 -0400
101 void sshpam_cleanup(void);
102 int sshpam_auth_passwd(Authctxt *, const char *);
103 int is_pam_session_open(void);
104 +struct passwd *sshpam_getpw(const char *);
107 Index: openssh/auth2-gss.c
108 ===================================================================
109 --- openssh.orig/auth2-gss.c 2011-09-21 18:55:39.000000000 -0400
110 +++ openssh/auth2-gss.c 2011-09-21 18:57:32.000000000 -0400
113 extern ServerOptions options;
115 +static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
116 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
117 static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
118 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
120 userauth_gsskeyex(Authctxt *authctxt)
122 int authenticated = 0;
124 - gss_buffer_desc mic, gssbuf;
126 + gss_buffer_desc mic, gssbuf, gssbuf2;
129 mic.value = packet_get_string(&len);
131 gssbuf.value = buffer_ptr(&b);
132 gssbuf.length = buffer_len(&b);
134 + /* client may have used empty username to determine target
135 + name from GSSAPI context */
136 + ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
138 + gssbuf2.value = buffer_ptr(&b2);
139 + gssbuf2.length = buffer_len(&b2);
141 /* gss_kex_context is NULL with privsep, so we can't check it here */
142 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
144 - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
146 + &gssbuf, &mic))) ||
147 + !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
148 + &gssbuf2, &mic)))) {
149 + if (authctxt->valid && authctxt->user && authctxt->user[0]) {
150 + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
159 return (authenticated);
164 - if (!authctxt->valid || authctxt->user == NULL)
165 + /* authctxt->valid may be 0 if we haven't yet determined
166 + username from gssapi context. */
168 + if (authctxt->user == NULL)
171 mechs = packet_get_int();
174 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
175 gss_buffer_desc recv_tok;
176 - OM_uint32 maj_status, min_status, flags;
177 + OM_uint32 maj_status, min_status, flags=0;
180 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
182 xfree(recv_tok.value);
184 if (GSS_ERROR(maj_status)) {
185 + ssh_gssapi_userauth_error(gssctxt);
186 if (send_tok.length != 0) {
187 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
188 packet_put_string(send_tok.value, send_tok.length);
190 gss_release_buffer(&maj_status, &send_tok);
194 +gssapi_set_username(Authctxt *authctxt)
196 + char *lname = NULL;
198 + if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
199 + PRIVSEP(ssh_gssapi_localname(&lname));
200 + if (lname && lname[0] != '\0') {
201 + if (authctxt->user) xfree(authctxt->user);
202 + authctxt->user = lname;
203 + debug("set username to %s from gssapi context", lname);
204 + authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
205 + if (authctxt->pw) {
206 + authctxt->valid = 1;
208 + if (options.use_pam)
209 + PRIVSEP(start_pam(authctxt));
213 + debug("failed to set username from gssapi context");
214 + packet_send_debug("failed to set username from gssapi context");
220 * This is called when the client thinks we've completed authentication.
221 * It should only be enabled in the dispatch handler by the function above,
223 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
224 fatal("No authentication or GSSAPI context");
226 + gssapi_set_username(authctxt);
228 gssctxt = authctxt->methoddata;
235 - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
237 + /* user should be set if valid but we double-check here */
238 + if (authctxt->valid && authctxt->user && authctxt->user[0]) {
239 + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
245 authctxt->postponed = 0;
246 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
248 gssbuf.value = buffer_ptr(&b);
249 gssbuf.length = buffer_len(&b);
251 + gssapi_set_username(authctxt);
253 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
255 - PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
256 + if (authctxt->valid && authctxt->user && authctxt->user[0]) {
258 + PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
263 logit("GSSAPI MIC check failed");
266 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
269 +static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
273 + errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
275 + packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
276 + packet_put_int(maj);
277 + packet_put_int(min);
278 + packet_put_cstring(errstr);
279 + packet_put_cstring("");
281 + packet_write_wait();
286 Authmethod method_gsskeyex = {
289 Index: openssh/auth2.c
290 ===================================================================
291 --- openssh.orig/auth2.c 2011-09-21 18:57:31.000000000 -0400
292 +++ openssh/auth2.c 2011-09-21 18:57:32.000000000 -0400
293 @@ -223,10 +223,30 @@
294 if (authctxt == NULL)
295 fatal("input_userauth_request: no authctxt");
297 - user = packet_get_cstring(NULL);
298 - service = packet_get_cstring(NULL);
299 - method = packet_get_cstring(NULL);
300 - debug("userauth-request for user %s service %s method %s", user, service, method);
301 + user = packet_get_string(NULL);
302 + service = packet_get_string(NULL);
303 + method = packet_get_string(NULL);
306 + if (user[0] == '\0') {
307 + debug("received empty username for %s", method);
308 + if (strcmp(method, "gssapi-keyex") == 0) {
309 + char *lname = NULL;
310 + PRIVSEP(ssh_gssapi_localname(&lname));
311 + if (lname && lname[0] != '\0') {
314 + debug("set username to %s from gssapi context", user);
316 + debug("failed to set username from gssapi context");
317 + packet_send_debug("failed to set username from gssapi context");
323 + debug("userauth-request for user %s service %s method %s",
324 + user[0] ? user : "<implicit>", service, method);
325 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
327 if ((role = strchr(user, '/')) != NULL)
328 @@ -237,11 +257,32 @@
329 else if (role && (style = strchr(role, ':')) != NULL)
332 - if (authctxt->attempt++ == 0) {
333 - /* setup auth context */
334 + /* If first time or username changed or empty username,
335 + setup/reset authentication context. */
336 + if ((authctxt->attempt++ == 0) ||
337 + (strcmp(user, authctxt->user) != 0) ||
338 + (strcmp(user, "") == 0)) {
339 + if (authctxt->user) {
340 + xfree(authctxt->user);
341 + authctxt->user = NULL;
343 + authctxt->valid = 0;
344 + authctxt->user = xstrdup(user);
345 + if (strcmp(service, "ssh-connection") != 0) {
346 + packet_disconnect("Unsupported service %s", service);
349 + /* If we're going to set the username based on the
350 + GSSAPI context later, then wait until then to
351 + verify it. Just put in placeholders for now. */
352 + if ((strcmp(user, "") == 0) &&
353 + ((strcmp(method, "gssapi") == 0) ||
354 + (strcmp(method, "gssapi-with-mic") == 0))) {
355 + authctxt->pw = fakepw();
358 authctxt->pw = PRIVSEP(getpwnamallow(user));
359 - authctxt->user = xstrdup(user);
360 - if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
361 + if (authctxt->pw) {
363 debug2("input_userauth_request: setting up authctxt for %s", user);
365 @@ -251,21 +292,26 @@
366 PRIVSEP(audit_event(SSH_INVALID_USER));
370 + } /* endif for setting username based on GSSAPI context */
374 PRIVSEP(start_pam(authctxt));
376 setproctitle("%s%s", authctxt->valid ? user : "unknown",
377 use_privsep ? " [net]" : "");
378 - authctxt->service = xstrdup(service);
379 - authctxt->style = style ? xstrdup(style) : NULL;
380 - authctxt->role = role ? xstrdup(role) : NULL;
382 - mm_inform_authserv(service, style, role);
384 - } else if (strcmp(user, authctxt->user) != 0 ||
385 - strcmp(service, authctxt->service) != 0) {
386 - packet_disconnect("Change of username or service not allowed: "
387 + if (authctxt->attempt == 1) {
388 + authctxt->service = xstrdup(service);
389 + authctxt->style = style ? xstrdup(style) : NULL;
390 + authctxt->role = role ? xstrdup(role) : NULL;
392 + mm_inform_authserv(service, style, role);
396 + if (strcmp(service, authctxt->service) != 0) {
397 + packet_disconnect("Change of service not allowed: "
398 "(%s,%s) -> (%s,%s)",
399 authctxt->user, authctxt->service, user, service);
401 Index: openssh/gss-serv.c
402 ===================================================================
403 --- openssh.orig/gss-serv.c 2011-09-21 18:55:39.000000000 -0400
404 +++ openssh/gss-serv.c 2011-09-21 18:57:32.000000000 -0400
412 +ssh_gssapi_localname(char **user)
415 + if (gssapi_client.displayname.length==0 ||
416 + gssapi_client.displayname.value==NULL) {
417 + debug("No suitable client data");
420 + if (gssapi_client.mech && gssapi_client.mech->localname) {
421 + return((*gssapi_client.mech->localname)(&gssapi_client,user));
423 + debug("Unknown client authentication type");
428 /* These bits are only used for rekeying. The unpriviledged child is running
429 * as the user, the monitor is root.
431 Index: openssh/monitor.c
432 ===================================================================
433 --- openssh.orig/monitor.c 2011-09-21 18:57:31.000000000 -0400
434 +++ openssh/monitor.c 2011-09-21 18:57:32.000000000 -0400
436 int mm_answer_gss_userok(int, Buffer *);
437 int mm_answer_gss_checkmic(int, Buffer *);
438 int mm_answer_gss_sign(int, Buffer *);
439 +int mm_answer_gss_error(int, Buffer *);
440 +int mm_answer_gss_localname(int, Buffer *);
441 int mm_answer_gss_updatecreds(int, Buffer *);
445 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
446 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
447 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
448 + {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
449 + {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
452 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
454 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
455 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
456 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
457 + {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
458 {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
460 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
462 {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
463 {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
466 + {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
467 + {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
468 + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
469 + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
472 - {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
473 + {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
474 {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
475 {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
476 {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
478 /* Permit requests for moduli and signatures */
479 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
480 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
483 /* and for the GSSAPI key exchange */
484 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
485 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
488 mon_dispatch = mon_dispatch_proto15;
489 @@ -483,14 +495,20 @@
490 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
491 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
492 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
495 /* and for the GSSAPI key exchange */
496 - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
498 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
499 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
503 mon_dispatch = mon_dispatch_postauth15;
504 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
507 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
510 monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
511 monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
512 @@ -2167,6 +2185,45 @@
513 return (authenticated);
517 +mm_answer_gss_error(int socket, Buffer *m) {
518 + OM_uint32 major,minor;
521 + msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
523 + buffer_put_int(m,major);
524 + buffer_put_int(m,minor);
525 + buffer_put_cstring(m,msg);
527 + mm_request_send(socket,MONITOR_ANS_GSSERR,m);
535 +mm_answer_gss_localname(int socket, Buffer *m) {
538 + ssh_gssapi_localname(&name);
542 + buffer_put_cstring(m, name);
543 + debug3("%s: sending result %s", __func__, name);
546 + buffer_put_cstring(m, "");
547 + debug3("%s: sending result \"\"", __func__);
550 + mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
556 mm_answer_gss_sign(int socket, Buffer *m)
558 Index: openssh/monitor.h
559 ===================================================================
560 --- openssh.orig/monitor.h 2011-09-21 18:57:31.000000000 -0400
561 +++ openssh/monitor.h 2011-09-21 18:57:32.000000000 -0400
563 MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
564 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
565 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
566 + MONITOR_REQ_GSSLOCALNAME, MONITOR_ANS_GSSLOCALNAME,
567 + MONITOR_REQ_GSSERR, MONITOR_ANS_GSSERR,
568 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
569 MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
570 MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
571 Index: openssh/monitor_wrap.c
572 ===================================================================
573 --- openssh.orig/monitor_wrap.c 2011-09-21 18:57:31.000000000 -0400
574 +++ openssh/monitor_wrap.c 2011-09-21 18:57:32.000000000 -0400
575 @@ -1306,6 +1306,54 @@
576 return (authenticated);
580 +mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
587 + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
588 + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
590 + maj = buffer_get_int(&m);
591 + min = buffer_get_int(&m);
593 + if (major) *major=maj;
594 + if (minor) *minor=min;
596 + errstr=buffer_get_string(&m,NULL);
604 +mm_ssh_gssapi_localname(char **lname)
609 + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
611 + debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
612 + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
615 + *lname = buffer_get_string(&m, NULL);
618 + if (lname[0] == '\0') {
619 + debug3("%s: gssapi identity mapping failed", __func__);
621 + debug3("%s: gssapi identity mapped to %s", __func__, *lname);
628 mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
630 Index: openssh/monitor_wrap.h
631 ===================================================================
632 --- openssh.orig/monitor_wrap.h 2011-09-21 18:57:31.000000000 -0400
633 +++ openssh/monitor_wrap.h 2011-09-21 18:57:32.000000000 -0400
635 int mm_ssh_gssapi_userok(char *user, struct passwd *);
636 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
637 OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
638 +int mm_ssh_gssapi_localname(char **user);
639 +char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
640 int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
643 Index: openssh/misc.c
644 ===================================================================
645 --- openssh.orig/misc.c 2011-09-21 18:57:31.000000000 -0400
646 +++ openssh/misc.c 2011-09-21 18:57:32.000000000 -0400
652 +pwfree(struct passwd *pw)
654 + xfree(pw->pw_name);
655 + xfree(pw->pw_passwd);
656 + xfree(pw->pw_gecos);
657 +#ifdef HAVE_PW_CLASS_IN_PASSWD
658 + xfree(pw->pw_class);
661 + xfree(pw->pw_shell);
666 * Convert ASCII string to TCP/IP port number.
667 * Port must be >=0 and <=65535.
668 Index: openssh/misc.h
669 ===================================================================
670 --- openssh.orig/misc.h 2011-09-21 18:57:31.000000000 -0400
671 +++ openssh/misc.h 2011-09-21 18:57:32.000000000 -0400
673 void sock_set_v6only(int);
675 struct passwd *pwcopy(struct passwd *);
676 +void pwfree(struct passwd *);
677 const char *ssh_gai_strerror(int);
679 typedef struct arglist arglist;
680 Index: openssh/ssh-gss.h
681 ===================================================================
682 --- openssh.orig/ssh-gss.h 2011-09-21 18:58:35.000000000 -0400
683 +++ openssh/ssh-gss.h 2011-09-21 18:58:49.000000000 -0400
685 OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
686 int ssh_gssapi_credentials_updated(Gssctxt *);
688 +int ssh_gssapi_localname(char **name);
690 typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,