d0bf6519da45f1194be23c1db4f69c24734f63a9
[openssh.git] / debian / patches / 0001-initial-empty-usernames-on-top-of-keyex-and-role.patch
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
5
6 ---
7  auth-pam.c  |   51 +++++++++++++++++++++++++++++-
8  auth-pam.h  |    1 +
9  auth2-gss.c |   98 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
10  auth2.c     |   86 +++++++++++++++++++++++++++++++++++++++++----------
11  4 files changed, 206 insertions(+), 30 deletions(-)
12
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
17 @@ -30,7 +30,7 @@
18   */
19  /*
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>
23   *
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
26 @@ -122,6 +122,10 @@
27   */
28  typedef pthread_t sp_pthread_t;
29  #else
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;
35  #endif
36  
37 @@ -272,6 +276,49 @@
38  # define pam_chauthtok(a,b)    (sshpam_chauthtok_ruid((a), (b)))
39  #endif
40  
41 +struct passwd *
42 +sshpam_getpw(const char *user)
43 +{
44 +       struct passwd *pw;
45 +
46 +       if ((pw = getpwnam(user)) != NULL)
47 +               return(pw);
48 +
49 +       debug("PAM: faking passwd struct for user '%.100s'", user);
50 +       if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
51 +               return NULL;
52 +       pw->pw_name = xstrdup(user);    /* XXX leak */
53 +       pw->pw_shell = "/bin/true";
54 +       pw->pw_gecos = "sshd fake PAM user";
55 +       return (pw);
56 +}
57 +
58 +void
59 +sshpam_check_userchanged(void)
60 +{
61 +       int sshpam_err;
62 +       struct passwd *pw;
63 +       const char *user;
64 +
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");
81 +       }
82 +}
83 +
84  void
85  sshpam_password_change_required(int reqd)
86  {
87 @@ -294,7 +341,7 @@
88  static void
89  import_environments(Buffer *b)
90  {
91 -       char *env;
92 +       char *env, *user;
93         u_int i, num_env;
94         int err;
95  
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
100 @@ -46,5 +46,6 @@
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 *);
105  
106  #endif /* USE_PAM */
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
111 @@ -47,6 +47,7 @@
112  
113  extern ServerOptions options;
114  
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);
119 @@ -59,8 +60,8 @@
120  userauth_gsskeyex(Authctxt *authctxt)
121  {
122         int authenticated = 0;
123 -       Buffer b;
124 -       gss_buffer_desc mic, gssbuf;
125 +       Buffer b, b2;
126 +       gss_buffer_desc mic, gssbuf, gssbuf2;
127         u_int len;
128  
129         mic.value = packet_get_string(&len);
130 @@ -74,13 +75,26 @@
131         gssbuf.value = buffer_ptr(&b);
132         gssbuf.length = buffer_len(&b);
133  
134 +       /* client may have used empty username to determine target
135 +          name from GSSAPI context */
136 +       ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
137 +
138 +       gssbuf2.value = buffer_ptr(&b2);
139 +       gssbuf2.length = buffer_len(&b2);
140 +
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, 
143 -           &gssbuf, &mic))))
144 -               authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
145 -                   authctxt->pw));
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,
151 +                                                      authctxt->pw));
152 +           }
153 +       }
154         
155         buffer_free(&b);
156 +       buffer_free(&b2);
157         xfree(mic.value);
158  
159         return (authenticated);
160 @@ -102,7 +116,10 @@
161         u_int len;
162         u_char *doid = NULL;
163  
164 -       if (!authctxt->valid || authctxt->user == NULL)
165 +       /* authctxt->valid may be 0 if we haven't yet determined
166 +          username from gssapi context. */
167 +
168 +       if (authctxt->user == NULL)
169                 return (0);
170  
171         mechs = packet_get_int();
172 @@ -172,7 +189,7 @@
173         Gssctxt *gssctxt;
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;
178         u_int len;
179  
180         if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
181 @@ -190,6 +207,7 @@
182         xfree(recv_tok.value);
183  
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);
189 @@ -253,6 +271,32 @@
190         gss_release_buffer(&maj_status, &send_tok);
191  }
192  
193 +static void
194 +gssapi_set_username(Authctxt *authctxt)
195 +{
196 +    char *lname = NULL;
197 +
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;
207 +#ifdef USE_PAM
208 +                if (options.use_pam)
209 +                    PRIVSEP(start_pam(authctxt));
210 +#endif
211 +            }
212 +        } else {
213 +            debug("failed to set username from gssapi context");
214 +            packet_send_debug("failed to set username from gssapi context");
215 +        }
216 +    }
217 +}
218 +
219  /*
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,
222 @@ -269,6 +313,8 @@
223         if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
224                 fatal("No authentication or GSSAPI context");
225  
226 +       gssapi_set_username(authctxt);
227 +
228         gssctxt = authctxt->methoddata;
229  
230         /*
231 @@ -278,8 +324,13 @@
232  
233         packet_check_eom();
234  
235 -       authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
236 -           authctxt->pw));
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,
240 +                                                     authctxt->pw));
241 +       } else {
242 +           authenticated = 0;
243 +       }
244  
245         authctxt->postponed = 0;
246         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
247 @@ -313,9 +364,15 @@
248         gssbuf.value = buffer_ptr(&b);
249         gssbuf.length = buffer_len(&b);
250  
251 +    gssapi_set_username(authctxt);
252 +
253         if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
254 -               authenticated = 
255 -                   PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
256 +           if (authctxt->valid && authctxt->user && authctxt->user[0]) {
257 +            authenticated =
258 +             PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
259 +           } else {
260 +            authenticated = 0;
261 +           }
262         else
263                 logit("GSSAPI MIC check failed");
264  
265 @@ -330,6 +387,23 @@
266         userauth_finish(authctxt, authenticated, "gssapi-with-mic");
267  }
268  
269 +static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
270 +       char *errstr;
271 +       OM_uint32 maj,min;
272 +       
273 +       errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
274 +       if (errstr) {
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("");
280 +               packet_send();
281 +               packet_write_wait();
282 +               xfree(errstr);
283 +       }
284 +}
285 +
286  Authmethod method_gsskeyex = {
287         "gssapi-keyex",
288         userauth_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");
296  
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);
304 +
305 +#ifdef GSSAPI
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') {
312 +                   xfree(user);
313 +                   user = lname;
314 +                   debug("set username to %s from gssapi context", user);
315 +               } else {
316 +                   debug("failed to set username from gssapi context");
317 +                   packet_send_debug("failed to set username from gssapi context");
318 +               }
319 +           }
320 +       }
321 +#endif
322 +
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);
326  
327         if ((role = strchr(user, '/')) != NULL)
328 @@ -237,11 +257,32 @@
329         else if (role && (style = strchr(role, ':')) != NULL)
330                 *style++ = '\0';
331  
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;
342 +               }
343 +               authctxt->valid = 0;
344 +        authctxt->user = xstrdup(user);
345 +        if (strcmp(service, "ssh-connection") != 0) {
346 +            packet_disconnect("Unsupported service %s", service);
347 +        }
348 +#ifdef GSSAPI
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();
356 +               } else {
357 +#endif
358                 authctxt->pw = PRIVSEP(getpwnamallow(user));
359 -               authctxt->user = xstrdup(user);
360 -               if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
361 +               if (authctxt->pw) {
362                         authctxt->valid = 1;
363                         debug2("input_userauth_request: setting up authctxt for %s", user);
364                 } else {
365 @@ -251,21 +292,26 @@
366                         PRIVSEP(audit_event(SSH_INVALID_USER));
367  #endif
368                 }
369 +#ifdef GSSAPI
370 +               } /* endif for setting username based on GSSAPI context */
371 +#endif
372  #ifdef USE_PAM
373                 if (options.use_pam)
374                         PRIVSEP(start_pam(authctxt));
375  #endif
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;
381 -               if (use_privsep)
382 -                       mm_inform_authserv(service, style, role);
383 -               userauth_banner();
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;
391 +            if (use_privsep)
392 +             mm_inform_authserv(service, style, role);
393 +            userauth_banner();
394 +               }
395 +       }
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);
400         }
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
405 @@ -495,6 +495,25 @@
406         return (0);
407  }
408  
409 +
410 +/* Privileged */
411 +int
412 +ssh_gssapi_localname(char **user)
413 +{
414 +       *user = NULL;
415 +       if (gssapi_client.displayname.length==0 || 
416 +           gssapi_client.displayname.value==NULL) {
417 +               debug("No suitable client data");
418 +               return(0);;
419 +       }
420 +       if (gssapi_client.mech && gssapi_client.mech->localname) {
421 +               return((*gssapi_client.mech->localname)(&gssapi_client,user));
422 +       } else {
423 +               debug("Unknown client authentication type");
424 +       }
425 +       return(0);
426 +}
427 +
428  /* These bits are only used for rekeying. The unpriviledged child is running 
429   * as the user, the monitor is root.
430   *
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
435 @@ -182,6 +182,8 @@
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 *);
442  #endif
443  
444 @@ -256,6 +258,8 @@
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},
450  #endif
451  #ifdef JPAKE
452      {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
453 @@ -272,6 +276,7 @@
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},
459  #endif
460      {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
461 @@ -303,8 +308,14 @@
462      {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
463      {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
464  #endif
465 +#ifdef GSSAPI
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},
470 +#endif
471  #ifdef USE_PAM
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},
477 @@ -382,9 +393,10 @@
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);
481 -#ifdef GSSAPI
482 +#ifdef GSSAPI          
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);
486  #endif
487         } else {
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);
493 +
494  #ifdef GSSAPI
495                 /* and for the GSSAPI key exchange */
496 -               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
497 -#endif         
498 +               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
499 +               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
500 +#endif
501 +
502         } else {
503                 mon_dispatch = mon_dispatch_postauth15;
504                 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
505         }
506 +#ifdef GSSAPI          
507 +       monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
508 +#endif
509         if (!no_pty_flag) {
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);
514  }
515  
516 +int
517 +mm_answer_gss_error(int socket, Buffer *m) {
518 +        OM_uint32 major,minor;
519 +        char *msg;
520 +
521 +       msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
522 +       buffer_clear(m);
523 +       buffer_put_int(m,major);
524 +       buffer_put_int(m,minor);
525 +       buffer_put_cstring(m,msg);
526 +
527 +       mm_request_send(socket,MONITOR_ANS_GSSERR,m);
528 +
529 +       xfree(msg);
530 +       
531 +        return(0);
532 +}
533 +
534 +int
535 +mm_answer_gss_localname(int socket, Buffer *m) {
536 +       char *name;
537 +
538 +       ssh_gssapi_localname(&name);
539 +
540 +        buffer_clear(m);
541 +       if (name) {
542 +           buffer_put_cstring(m, name);
543 +           debug3("%s: sending result %s", __func__, name);
544 +           xfree(name);
545 +       } else {
546 +           buffer_put_cstring(m, "");
547 +           debug3("%s: sending result \"\"", __func__);
548 +       }
549 +
550 +        mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
551 +
552 +        return(0);
553 +}
554 +
555  int 
556  mm_answer_gss_sign(int socket, Buffer *m)
557  {
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
562 @@ -52,6 +52,8 @@
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);
577  }
578  
579 +char *
580 +mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
581 +       Buffer m;
582 +       OM_uint32 maj,min;
583 +       char *errstr;
584 +       
585 +       buffer_init(&m);
586 +
587 +       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
588 +       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
589 +
590 +       maj = buffer_get_int(&m);
591 +       min = buffer_get_int(&m);
592 +
593 +       if (major) *major=maj;
594 +       if (minor) *minor=min;
595 +       
596 +       errstr=buffer_get_string(&m,NULL);
597 +
598 +       buffer_free(&m);
599 +       
600 +       return(errstr);
601 +}      
602 +
603 +int
604 +mm_ssh_gssapi_localname(char **lname)
605 +{
606 +        Buffer m;
607 +
608 +       buffer_init(&m);
609 +        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
610 +
611 +        debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
612 +        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
613 +                                  &m);
614 +
615 +       *lname = buffer_get_string(&m, NULL);
616 +
617 +        buffer_free(&m);
618 +       if (lname[0] == '\0') {
619 +           debug3("%s: gssapi identity mapping failed", __func__);
620 +       } else {
621 +           debug3("%s: gssapi identity mapped to %s", __func__, *lname);
622 +       }
623 +       
624 +        return(0);
625 +}      
626 +
627  OM_uint32
628  mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
629  {
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
634 @@ -62,6 +62,8 @@
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 *);
641  #endif
642  
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
647 @@ -224,6 +224,20 @@
648         return copy;
649  }
650  
651 +void
652 +pwfree(struct passwd *pw)
653 +{
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);
659 +#endif
660 +       xfree(pw->pw_dir);
661 +       xfree(pw->pw_shell);
662 +       xfree(pw);
663 +}
664 +
665  /*
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
672 @@ -38,6 +38,7 @@
673  void    sock_set_v6only(int);
674  
675  struct passwd *pwcopy(struct passwd *);
676 +void    pwfree(struct passwd *);
677  const char *ssh_gai_strerror(int);
678  
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
684 @@ -141,6 +141,7 @@
685  OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
686  int ssh_gssapi_credentials_updated(Gssctxt *);
687  
688 +int ssh_gssapi_localname(char **name);
689  /* In the server */
690  typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 
691      const char *);