]> andersk Git - gssapi-openssh.git/commitdiff
o Merge to OPENSSH_3_6_1P1_GSSAPI_20030425.
authorcphillip <cphillip>
Mon, 5 May 2003 15:53:22 +0000 (15:53 +0000)
committercphillip <cphillip>
Mon, 5 May 2003 15:53:22 +0000 (15:53 +0000)
34 files changed:
openssh/Makefile.in
openssh/acconfig.h
openssh/auth-pam.c
openssh/auth.h
openssh/auth1.c
openssh/auth2-gss.c
openssh/auth2.c
openssh/compat.c
openssh/compat.h
openssh/configure.ac
openssh/gss-genr.c
openssh/gss-serv-gsi.c [new file with mode: 0644]
openssh/gss-serv-krb5.c [new file with mode: 0644]
openssh/gss-serv.c
openssh/kex.c
openssh/kex.h
openssh/kexgss.c [deleted file]
openssh/kexgssc.c
openssh/kexgsss.c
openssh/makegssname.pl [new file with mode: 0644]
openssh/misc.c
openssh/monitor.c
openssh/monitor.h
openssh/monitor_wrap.c
openssh/monitor_wrap.h
openssh/servconf.c
openssh/servconf.h
openssh/session.c
openssh/ssh-gss.h
openssh/ssh-keyscan.c
openssh/sshconnect1.c
openssh/sshconnect2.c
openssh/sshd.c
openssh/sshd_config

index f661fba533524a60a60a978f70ac9200797837a3..2f15b39bf90cd3584a009ae8feb166c3db89b6fb 100644 (file)
@@ -68,8 +68,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \
        key.o dispatch.o kex.o mac.o uuencode.o misc.o \
        rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o kexgex.o \
        kexdhc.o kexgexc.o scard.o msg.o progressmeter.o \
-       kexgss.o kexgssc.o gss-genr.o \
-       entropy.o pathnames.o
+       entropy.o pathnames.o kexgssc.o gss-genr.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
        sshconnect.o sshconnect1.o sshconnect2.o
@@ -81,9 +80,9 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
        auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
        auth2-none.o auth2-passwd.o auth2-pubkey.o \
        monitor_mm.o monitor.o monitor_wrap.o monitor_fdpass.o \
-       kexdhs.o kexgexs.o \
-       auth-krb5.o auth-krb4.o \
-       kexgsss.o auth2-gss.o gss-serv.o \
+       kexdhs.o kexgexs.o kexgsss.o \
+       auth-krb5.o auth-krb4.o auth2-gss.o \
+       gss-serv.o gss-serv-krb5.o gss-serv-gsi.o \
        loginrec.o auth-pam.o auth2-pam.o auth-sia.o md5crypt.o
 
 MANPAGES       = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
@@ -329,12 +328,12 @@ install-files: scard-install
 #       o Creating and chmod'ing PRIVSEP_PATH.
 #       o Stripping of installed binaries.
 #       o The conditionals around ssh-rand-helper*.
-#     o Install docs into $GL/doc/gsi_openssh.
+#     o Install docs into $GL/doc/gsi_openssh by adding 'gpt-install-docs' target.
 #     o Add links for gsi tools (gsissh -> ssh, etc).
 #     o Refer to the new man and cat pages.
 #
 
-gpt-install-files:
+gpt-install-files: gpt-install-docs
        $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
        $(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir)
        $(srcdir)/mkinstalldirs $(DESTDIR)$(datadir)
@@ -410,6 +409,8 @@ gpt-install-files:
        -rm -f $(DESTDIR)$(mandir)/$${docdir}1/gsiscp.1; \
        ln -s ./scp.1 $(DESTDIR)$(mandir)/$${docdir}1/gsiscp.1;
        # end cat
+
+gpt-install-docs:
        # make doc dir and copy docs into it
        if [ ! -d $(DESTDIR)$(docdir) ]; then \
                $(srcdir)/mkinstalldirs $(DESTDIR)$(docdir); \
index 6c5ca4b0e24001360bb78b599847024a7c1cda83..7425f694d2952ff54443adbf0e54aa897a04889d 100644 (file)
 /* Define this is you want GSSAPI support in the version 2 protocol */
 #undef GSSAPI
 
-/* Define this if GSSAPI supports gss_export_cred() */
-#undef HAVE_GSSAPI_EXT
-
 /* Define if you want Kerberos 5 support */
 #undef KRB5
 
 /* Define if you want GSI/Globus authentication support */
 #undef GSI
 
+/* Define this if you want support for startup/shutdown hooks */
+#undef SESSION_HOOKS
+
 /* Define if you want S/Key support */
 #undef SKEY
 
index 09fc3d5052f4ff2087e9252b8a864b1a8425b89e..a8ba48652905daee42e9ffc5d807cd3dfb850dd4 100644 (file)
@@ -413,6 +413,16 @@ char **fetch_pam_environment(void)
 #endif /* HAVE_PAM_GETENVLIST */
 }
 
+void free_pam_environment(char **env)
+{
+       int i;
+
+       if (env != NULL) {
+               for (i = 0; env[i] != NULL; i++)
+                       xfree(env[i]);
+       }
+}
+
 /* Set a PAM environment string. We need to do this so that the session
  * modules can handle things like Kerberos/GSI credentials that appear
  * during the ssh authentication process.
@@ -433,16 +443,6 @@ int do_pam_putenv(char *name, char *value) {
        return(ret);
 }
 
-void free_pam_environment(char **env)
-{
-       int i;
-
-       if (env != NULL) {
-               for (i = 0; env[i] != NULL; i++)
-                       xfree(env[i]);
-       }
-}
-
 /* Print any messages that have been generated during authentication */
 /* or account checking to stderr */
 void print_pam_messages(void)
index 8e63132c92df6307a1f0f062237ea17b6278a600..2e351d6d15c92a40f507c97039c15b32af62181b 100644 (file)
@@ -69,6 +69,9 @@ struct Authctxt {
        krb5_ccache      krb5_fwd_ccache;
        krb5_principal   krb5_user;
        char            *krb5_ticket_file;
+#endif
+#ifdef SESSION_HOOKS
+        char            *session_env_file;
 #endif
        void *methoddata;
 };
index ccd43941e6fb2d477eb4848ef02251f2e1c4224a..10d74dc3ebc166a47bfbf83e59d8e864f293cc7c 100644 (file)
@@ -30,15 +30,14 @@ RCSID("$OpenBSD: auth1.c,v 1.47 2003/02/06 21:22:42 markus Exp $");
 
 /* import */
 extern ServerOptions options;
-extern Authmethod method_gssapi;
-
-
 
 #ifdef GSSAPI
 #ifdef GSI
 #include "globus_gss_assist.h"
 #endif
 
+extern Authmethod method_gssapi;
+
 int     userauth_gssapi(Authctxt *authctxt);
 
 void
index c20796123a2516bb28fd8084528aa985cb64a176..4204528cc64682966f8e063688a296c28de298fb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,7 +39,7 @@
 #include "ssh-gss.h"
 
 extern ServerOptions options;
-extern unsigned char ssh1_key_digest[16];
+unsigned char ssh1_key_digest[16];
 
 static int
 userauth_external(Authctxt *authctxt)
@@ -49,8 +49,10 @@ userauth_external(Authctxt *authctxt)
         return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
 }
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_errtok(int, u_int32_t, void *);
 
 /* We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like
@@ -65,6 +67,7 @@ userauth_gssapi(Authctxt *authctxt)
         int             present;
         OM_uint32       ms;
         u_int           len;
+        char *         doid = NULL;
         
         if (!authctxt->valid || authctxt->user == NULL)
                 return 0;
@@ -82,41 +85,66 @@ userauth_gssapi(Authctxt *authctxt)
 
         ssh_gssapi_supported_oids(&supported);
         do {
-                if (oid.elements)
-                        xfree(oid.elements);
-                oid.elements = packet_get_string(&len);
-                oid.length = len;
-                gss_test_oid_set_member(&ms, &oid, supported, &present);
                 mechs--;
+                
+                if (doid)
+                        xfree(doid);
+                
+                debug("Trying to get OID string");
+                doid = packet_get_string(&len);
+                debug("Got string");
+                
+                       if (doid[0]!=0x06 || doid[1]!=len-2) {
+                               log("Mechanism OID received using the old encoding form");
+                               oid.elements = doid;
+                               oid.length = len;
+                       } else {
+                               oid.elements = doid + 2;
+                               oid.length   = len - 2;
+                       }
+               gss_test_oid_set_member(&ms, &oid, supported, &present);
         } while (mechs>0 && !present);
         
         if (!present) {
-                xfree(oid.elements);
+                xfree(doid);
                 return(0);
         }
                 
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid))))
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid)))) {
+               ssh_gssapi_userauth_error(ctxt);
                return(0);
+       }
        
         authctxt->methoddata=(void *)ctxt;
 
         /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
 
-       if (!compat20)
-        packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
-       else
-       packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
-        packet_put_string(oid.elements,oid.length);
+       if (!compat20) {
+
+       packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
+       packet_put_string(oid.elements,oid.length);
+
+       } else {
+
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
+
+       /* Just return whatever they sent */
+       packet_put_string(doid,len);
+
+       } /* !compat20 */
+               
         packet_send();
         packet_write_wait();
-        xfree(oid.elements);
+        xfree(doid);
 
        if (!compat20)
        dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
                                &input_gssapi_token);
        else
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
-                    &input_gssapi_token);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
+                     &input_gssapi_token);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,
+                    &input_gssapi_errtok);
         authctxt->postponed = 1;
         
         return 0;
@@ -136,47 +164,77 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
                 
         gssctxt=authctxt->methoddata;
         recv_tok.value=packet_get_string(&len);
-       recv_tok.length=len; /* int vs. size_t */
+        recv_tok.length=len; /* int vs. size_t */
         
         maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
                                                 &send_tok, NULL));
         packet_check_eom();
-        
-        if (send_tok.length != 0) {
-                /* Send a packet back to the client */
-               if (!compat20)
-               packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
-               else
-               packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
-                packet_put_string(send_tok.value,send_tok.length);
-                packet_send();
-                packet_write_wait();
-                gss_release_buffer(&min_status, &send_tok);        
-        }
-        
+                        
         if (GSS_ERROR(maj_status)) {
-                /* Failure <sniff> */
-               if (gssctxt) {  /* may be NULL under privsep */
-                   ssh_gssapi_send_error(gssctxt->oid,maj_status,min_status);
-               } else {
-                   ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
-               }
+               ssh_gssapi_userauth_error(gssctxt);
+               if (send_tok.length != 0) {
+                   if (!compat20)
+                       packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+                   else
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_send();
+                               packet_write_wait();
+                       }
                 authctxt->postponed = 0;
                dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
                 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
                 userauth_finish(authctxt, 0, "gssapi");
+        } else {
+                       if (send_tok.length != 0) {
+                   if (!compat20)
+                       packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+                   else
+                               packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+                               packet_put_string(send_tok.value,send_tok.length);
+                               packet_send();
+                               packet_write_wait();
+                }
+               if (maj_status == GSS_S_COMPLETE) {
+                       dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+                       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+                       if (!compat20)
+                       input_gssapi_exchange_complete(0, 0, ctxt);
+                       else
+                       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+                                    &input_gssapi_exchange_complete);
+                }
         }
-                        
-        if (maj_status == GSS_S_COMPLETE) {
-               dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
-                dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
-               /* ssh1 does not have an extra message here */
-               if (!compat20)
-               input_gssapi_exchange_complete(0, 0, ctxt);
-               else
-               dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
-                            &input_gssapi_exchange_complete);
-        }
+        
+        gss_release_buffer(&min_status, &send_tok);        
+}
+
+static void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+        Authctxt *authctxt = ctxt;
+        Gssctxt *gssctxt;
+        gss_buffer_desc send_tok,recv_tok;
+        OM_uint32 maj_status;
+        
+        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+                fatal("No authentication or GSSAPI context");
+                
+        gssctxt=authctxt->methoddata;
+        recv_tok.value=packet_get_string(&recv_tok.length);
+        
+        /* Push the error token into GSSAPI to see what it says */
+        maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
+                                                &send_tok, NULL));
+        packet_check_eom();
+
+       /* We can't return anything to the client, even if we wanted to */
+       dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL);
+
+       /* The client will have already moved on to the next auth */
+       
 }
 
 /* This is called when the client thinks we've completed authentication.
@@ -217,7 +275,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
        }
 
         gssctxt=authctxt->methoddata;
-
+        
        /* ssh1 needs to exchange the hash of the keys */
        if (!compat20) {
 
@@ -250,10 +308,32 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
 finish:
         authctxt->postponed = 0;
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
         userauth_finish(authctxt, authenticated, "gssapi");
 }
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
+       char *errstr;
+       OM_uint32 maj,min;
+       
+       errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+       if (errstr) {
+           if (!compat20) {
+               packet_send_debug(errstr);
+           } else {
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
+               packet_put_int(maj);
+               packet_put_int(min);
+               packet_put_cstring(errstr);
+               packet_put_cstring("");
+               packet_send();
+               packet_write_wait();
+               xfree(errstr);
+           }
+       }
+}
+
 Authmethod method_external = {
        "external-keyx",
        userauth_external,
index 524f84dfaf6a4271f82533481ea681ac8628bb1d..42ade5d6db773b0548d1e4389831b54027f98f4e 100644 (file)
@@ -51,14 +51,14 @@ Authctxt *x_authctxt = NULL;
 /* methods */
 
 extern Authmethod method_none;
-#ifdef GSSAPI
-extern Authmethod method_external;
-extern Authmethod method_gssapi;
-#endif
 extern Authmethod method_pubkey;
 extern Authmethod method_passwd;
 extern Authmethod method_kbdint;
 extern Authmethod method_hostbased;
+#ifdef GSSAPI
+extern Authmethod method_external;
+extern Authmethod method_gssapi;
+#endif
 
 Authmethod *authmethods[] = {
        &method_none,
@@ -232,6 +232,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                authctxt->style = style ? xstrdup(style) : NULL;
                if (use_privsep && (authctxt->attempt == 1))
                        mm_inform_authserv(service, style);
+       } else if (strcmp(service, authctxt->service) != 0) {
+               packet_disconnect("Change of service not allowed: "
+                   "(%s,%s) -> (%s,%s)",
+                   authctxt->user, authctxt->service, user, service);
        }
        /* reset state */
        auth2_challenge_stop(authctxt);
@@ -249,7 +253,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                debug2("input_userauth_request: try method %s", method);
                authenticated = m->userauth(authctxt);
        }
-
        userauth_finish(authctxt, authenticated, method);
 
        xfree(service);
index b2e9cde40612a5017005ce2fb7f9abecaeeebfe8..b3960b506fd50e4b3c0ddac8e241750edf088c58 100644 (file)
@@ -81,7 +81,13 @@ compat_datafellows(const char *version)
                { "OpenSSH_2.9p*",      SSH_OLD_GSSAPI },
                { "OpenSSH_2.*,"
                  "OpenSSH_3.0*,"
-                 "OpenSSH_3.1*",       SSH_BUG_EXTEOF|SSH_BUG_GSS_EMPTYUSER},
+                 "OpenSSH_3.1*",       SSH_BUG_EXTEOF|SSH_BUG_GSS_EMPTYUSER|
+                                       SSH_BUG_GSSAPI_BER},
+               { "OpenSSH_3.2*,"
+                 "OpenSSH_3.3*,"
+                 "OpenSSH_3.4*,"
+                 "OpenSSH_3.5*,"
+                 "OpenSSH_3.6.1*",     SSH_BUG_GSSAPI_BER},
                { "Sun_SSH_1.0*",       SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
                { "OpenSSH*",           0 },
                { "*MindTerm*",         0 },
index 8d7496fd1ff4717e35fd726f145490ec69eb6a95..b982d3e8f945ef9cf96641659dcdd747e900a1c1 100644 (file)
@@ -56,8 +56,9 @@
 #define SSH_BUG_K5USER         0x00400000
 #define SSH_BUG_PROBE          0x00800000
 #define SSH_BUG_FIRSTKEX       0x01000000
-#define SSH_OLD_GSSAPI         0x10000000
-#define SSH_BUG_GSS_EMPTYUSER  0x20000000
+#define SSH_OLD_GSSAPI         0x02000000
+#define SSH_BUG_GSSAPI_BER     0x04000000
+#define SSH_BUG_GSS_EMPTYUSER  0x10000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
index b3876dec855a25b165e6503f399b331e2e9721b5..ebcb4cf20a8b0fe57762862297118071ed807d5b 100644 (file)
@@ -531,14 +531,6 @@ AC_ARG_WITH(mechglue,
                LIBS="$LIBS ${mechglue_lib}"
                AC_MSG_RESULT(${mechglue_lib})
 
-#              if test -e ${withval}/gssapi.h ; then
-#                  CPPFLAGS="$CPPFLAGS -I${withval}"
-#              elif test -e ${withval}/include/gssapi.h ; then
-#                  CPPFLAGS="$CPPFLAGS -I${withval}/include"
-#              else
-#                  AC_MSG_ERROR("Can't find gssapi.h in ${withval}");
-#              fi
-               
                AC_CHECK_LIB(dl, dlopen, , )
                if test $ac_cv_lib_dl_dlopen = yes; then
                   LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic"
@@ -546,7 +538,6 @@ AC_ARG_WITH(mechglue,
 
                AC_DEFINE(GSSAPI)
                AC_DEFINE(MECHGLUE)
-               AC_DEFINE(HAVE_GSSAPI_EXT)
                GSSAPI="mechglue"
 
        ]
@@ -580,6 +571,7 @@ AC_ARG_WITH(globus-flavor,
 
 if test "x$gsi_path" != "xno" ; then
        # Globus GSSAPI configuration
+       AC_MSG_CHECKING(for Globus GSI)
        AC_DEFINE(GSI)
 
        if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
@@ -590,67 +582,38 @@ if test "x$gsi_path" != "xno" ; then
                GSSAPI="GSI"
        fi
 
-       # Find GLOBUS/GSI installation Directory
-
-       AC_MSG_CHECKING(for Globus installation)
-       globus_dev_dir=$gsi_path
-       if test "x$globus_dev_dir" = "xyes" ; then
-                AC_MSG_ERROR(Cannot find Globus installation -- a path must be specified!)
+       if test "x$globus_install_dir" = "xyes" ; then
+                AC_MSG_ERROR(--with-globus=PATH must specify a path)
        fi
-       AC_MSG_RESULT($globus_dev_dir)
-
-       # Find GLOBUS/GSI flavor Directory
 
-       AC_MSG_CHECKING(for Globus flavor)
         if test "x$globus_flavor_type" = "xno" ; then
-                AC_MSG_ERROR(No Globus flavor type specified)
-        elif test "x$globus_flavor_type" = "xyes" ; then
-                AC_MSG_ERROR(No Globus flavor type specified)
-       else
-                AC_DEFINE(HAVE_GSSAPI_EXT)
-                GLOBUS_FLAVOR_TYPE_INCL_DIR="${globus_dev_dir}/include/${globus_flavor_type}"
-               if test ! -d "$GLOBUS_FLAVOR_TYPE_INCL_DIR" ; then
-                       AC_MSG_ERROR(Cannot find Globus flavor-specific include directory: ${GLOBUS_FLAVOR_TYPE_INCL_DIR})
-                fi
-               GSI_CPPFLAGS="-I${GLOBUS_FLAVOR_TYPE_INCL_DIR}"
+                AC_MSG_ERROR(--with-globus-flavor=TYPE must be specified)
+       fi
+        if test "x$globus_flavor_type" = "xyes" ; then
+                AC_MSG_ERROR(--with-globus-flavor=TYPE must specify a flavor type)
        fi
-       AC_MSG_RESULT($globus_flavor_type)
-
-       # Build possible libraries off of the flavor name
-
-        libglobus_gss_assist="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a"
-        libglobus_gssapi_gsi="${gsi_path}/lib/libglobus_gssapi_gsi_${globus_flavor_type}.a"
-
-       # Test that the base gss_assist library is present
 
-       if test -r ${libglobus_gss_assist} ; then
-               LIBS="$LIBS ${libglobus_gss_assist}"
+       GLOBUS_INCLUDE="${gsi_path}/include/${globus_flavor_type}"
+       if test ! -d "$GLOBUS_INCLUDE" ; then
+               AC_MSG_ERROR(Cannot find Globus flavor-specific include directory: ${GLOBUS_INCLUDE})
+       fi
+       GSI_CPPFLAGS="-I${GLOBUS_INCLUDE}"
+       
+       if test -x ${gsi_path}/bin/globus-makefile-header ; then
+               GSI_LIBS=`${gsi_path}/bin/globus-makefile-header -static -flavor=${globus_flavor_type} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
+       elif test -x ${gsi_path}/sbin/globus-makefile-header ; then
+               GSI_LDFLAGS="-L${gsi_path}/lib"
+               GSI_LIBS=`${gsi_path}/sbin/globus-makefile-header -flavor=${globus_flavor_type} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
        else
-               AC_MSG_ERROR([*** libglobus_gss_assist missing])
+               AC_MSG_ERROR(Cannot find globus-makefile-header: Globus installation is incomplete)
        fi
-
-       AC_MSG_CHECKING(for libglobus_gss_assist)
-       AC_TRY_LINK(
-               [],
-               [],
-               [
-                       AC_MSG_RESULT(yes)
-               ],
-               [
-                       AC_MSG_ERROR([*** libglobus_gss_assist missing])
-               ]
-       )
-
-       # If we aren't using mechglue, test that gssapi_gsi is present
-       if test "$GSSAPI" != "mechglue"; then
-               if test -r ${libglobus_gssapi_gsi} ; then
-                       LIBS="$LIBS ${libglobus_gssapi_gsi}"
-               else
-                       AC_MSG_ERROR([*** libglobus_gssapi_gsi missing])
-               fi
+       if test -z "$GSI_LIBS" ; then
+               AC_MSG_ERROR(globus-makefile-header failed)
        fi
 
-       AC_MSG_CHECKING(for libglobus_gssapi_gsi)
+       CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+
+       # test that we got the libraries OK
        AC_TRY_LINK(
                [],
                [],
@@ -658,11 +621,12 @@ if test "x$gsi_path" != "xno" ; then
                        AC_MSG_RESULT(yes)
                ],
                [
-                       AC_MSG_ERROR([*** libglobus_gssapi_gsi missing])
+                       AC_MSG_ERROR(link with Globus libraries failed)
                ]
        )
-
-       CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+       INSTALL_GSISSH="yes"
+else
+       INSTALL_GSISSH=""
 fi
 # End Globus/GSI section
 
@@ -770,6 +734,9 @@ AC_CHECK_FUNCS(\
 
 AC_SEARCH_LIBS(nanosleep, rt posix4, AC_DEFINE(HAVE_NANOSLEEP))
 
+dnl IRIX has basename() in libgen
+AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
+
 dnl Make sure strsep prototype is defined before defining HAVE_STRSEP
 AC_CHECK_DECL(strsep, [AC_CHECK_FUNCS(strsep)])
 
@@ -958,112 +925,9 @@ AC_ARG_WITH(ssl-dir,
        ]
 )
 
-# Patch up SSL libraries for GSI authentication as needed
-if test "x$globus_flavor_type" != "xno" ; then
-       #
-       # For Globus 2, always link with the static libraries
-       #
-
-       libssl_utils="${gsi_path}/lib/libglobus_ssl_utils_${globus_flavor_type}.a"
-
-       #
-       # Trouble arrives at GT 2.1.3+ with the reorg of globus_ssl_utils.  Compensating for
-       # the new library linking required here through file tests to see which libraries to 
-       # link against.
-       #
-
-       libgsi_proxy_core="${gsi_path}/lib/libglobus_gsi_proxy_core_${globus_flavor_type}.a"
-       libgsi_credential="${gsi_path}/lib/libglobus_gsi_credential_${globus_flavor_type}.a"
-       libgsi_callback="${gsi_path}/lib/libglobus_gsi_callback_${globus_flavor_type}.a"
-       liboldgaa="${gsi_path}/lib/libglobus_oldgaa_${globus_flavor_type}.a"
-       libgsi_sysconfig="${gsi_path}/lib/libglobus_gsi_sysconfig_${globus_flavor_type}.a"
-       libproxy_ssl="${gsi_path}/lib/libglobus_proxy_ssl_${globus_flavor_type}.a"
-       libgsi_cert_utils="${gsi_path}/lib/libglobus_gsi_cert_utils_${globus_flavor_type}.a"
-       libopenssl_error="${gsi_path}/lib/libglobus_openssl_error_${globus_flavor_type}.a"
-       libopenssl="${gsi_path}/lib/libglobus_openssl_${globus_flavor_type}.a"
-
-       if test -r ${libgsi_proxy_core} \
-            -a -r ${libgsi_credential} \
-            -a -r ${libgsi_callback} \
-            -a -r ${liboldgaa} \
-            -a -r ${libgsi_sysconfig} \
-            -a -r ${libproxy_ssl} \
-            -a -r ${libgsi_cert_utils} \
-            -a -r ${libopenssl_error} \
-            -a -r ${libopenssl} ; then
-               LIBS="$LIBS ${libgsi_proxy_core}"
-               LIBS="$LIBS ${libgsi_credential}"
-               LIBS="$LIBS ${libgsi_callback}"
-               LIBS="$LIBS ${liboldgaa}"
-               LIBS="$LIBS ${libgsi_sysconfig}"
-               LIBS="$LIBS ${libproxy_ssl}"
-               LIBS="$LIBS ${libgsi_cert_utils}"
-               LIBS="$LIBS ${libopenssl_error}"
-               LIBS="$LIBS ${libopenssl}"
-       elif test -r ${libssl_utils}; then
-               LIBS="$LIBS ${libssl_utils}"
-       else
-               AC_MSG_ERROR([*** missing one or more Globus GSI libraries])
-       fi
-
-       AC_MSG_CHECKING(for Globus GSI libraries)
-       AC_TRY_LINK(
-               [],
-               [],
-               [
-                       AC_MSG_RESULT(yes)
-               ],
-               [
-                       AC_MSG_ERROR([*** missing one or more Globus GSI libraries])
-               ]
-       )
-
-       #
-       # Standard openssl libraries.  They need to appear near the end of the link line.
-       #
-
-       LIBS="$LIBS ${gsi_path}/lib/libssl_${globus_flavor_type}.a"
-       LIBS="$LIBS ${gsi_path}/lib/libcrypto_${globus_flavor_type}.a"
-
-       AC_MSG_CHECKING(for Globus OpenSSL libraries)
-       AC_TRY_LINK(
-               [],
-               [],
-               [
-                       AC_MSG_RESULT(yes)
-               ],
-               [
-                       AC_MSG_ERROR([*** missing one or more Globus OpenSSL libraries])
-               ]
-       )
-
-       #
-       # Another "GT 2.1.3+"ism.
-       #
-
-       libcommon_path="${gsi_path}/lib/libglobus_common_${globus_flavor_type}.a"
-       if test -r ${libcommon_path}; then
-               LIBS="$LIBS ${libcommon_path}"
-               AC_MSG_CHECKING(for libglobus_common)
-               AC_TRY_LINK(
-                       [],
-                       [],
-                       [
-                               AC_MSG_RESULT(yes)
-                       ],
-                       [
-                               AC_MSG_ERROR([*** libglobus_common missing])
-                       ]
-               )
-       fi
-else
-       if test "x$gsi_path" != "xno" ; then
-               # Older GSI needs -lssl too
-               LIBS="$LIBS -lssl -lcrypto"
-       else # if no GSI authentication (i.e., OpenSSL default)
-               LIBS="$LIBS -lcrypto"
-       fi
-fi # globus_flavor_type
+if test -z "$GSI_LIBS" ; then
+LIBS="$LIBS -lcrypto"
+fi
 
 AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL),
        [
@@ -2245,6 +2109,11 @@ AC_ARG_WITH(afs,
 )
 LIBS="$LIBS $KLIBS $K5LIBS"
 
+AC_ARG_WITH(session-hooks,
+        [  --with-session-hooks    Enable hooks for executing external commands                                       before/after a session],
+        [ AC_DEFINE(SESSION_HOOKS) ]
+)
+
 # Looking for programs, paths and files
 
 PRIVSEP_PATH=/var/empty
index 159c55e90eb951184e50bb6f6b50dc36af8c1138..f0a160b965a116ff009907ba010327725bfa6080 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved. *
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
 
 #include "ssh-gss.h"
 
-/* Assorted globals for tracking the clients identity once they've
- * authenticated */
-gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */
-gss_cred_id_t   gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */
-enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY;
-
-unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */
-
-/* The mechanism name used in the list below is defined in the internet
- * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding 
- * of the underlying GSSAPI mechanism's OID.
- *
- * Also from the draft, before considering adding SPNEGO, bear in mind that
- * "mechanisms ... MUST NOT use SPNEGO as the underlying GSSAPI mechanism"
- */
-
-/* These must be in the same order as ssh_gss_id, in ssh-gss.h */
-
-ssh_gssapi_mech supported_mechs[]= {
-#ifdef KRB5
- /* Official OID - 1.2.850.113554.1.2.2 */
- {"Se3H81ismmOC3OE+FwYCiQ==","Kerberos",
-       {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}},
-#endif
-#ifdef GSI
- /* gssapi_ssleay 1.3.6.1.4.1.3536.1.1 */
- {"N3+k7/4wGxHyuP8Yxi4RhA==",
-  "GSI",
-  {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}
- },
-#endif /* GSI */
- {NULL,NULL,{0,0}}
-};
-
-char gssprefix[]=KEX_GSS_SHA1;
+typedef struct {
+       char *encoded;
+       gss_OID oid;
+} ssh_gss_kex_mapping;
+       
+static ssh_gss_kex_mapping *gss_enc2oid;
 
 /* Return a list of the gss-group1-sha1-x mechanisms supported by this
  * program.
  *
- * We only support the mechanisms that we've indicated in the list above,
- * but we check that they're supported by the GSSAPI mechanism on the 
- * machine. We also check, before including them in the list, that
- * we have the necesary information in order to carry out the key exchange
- * (that is, that the user has credentials, the server's creds are accessible,
- * etc)
+ * On the client side, we don't need to worry about whether we 'know'
+ * about the mechanism or not - we assume that any mechanism that we've been
+ * linked against is suitable for inclusion.
  *
- * The way that this is done is fairly nasty, as we do a lot of work that
- * is then thrown away. This should possibly be implemented with a cache
- * that stores the results (in an expanded Gssctxt structure), which are
- * then used by the first calls if that key exchange mechanism is chosen.
+ * XXX - We might want to make this configurable in the future, so as to
+ * XXX - allow the user control over which mechanisms to use.
  */
  
 char * 
-ssh_gssapi_mechanisms(char *host) {
+ssh_gssapi_client_mechanisms(char *host) {
        gss_OID_set     supported;
-       OM_uint32       maj_status, min_status;
+       OM_uint32       min_status;
        Buffer          buf;
        int             i = 0;
-       int             present;
-       int             mech_count=0;
-       char *          mechs;
-       Gssctxt *       ctx = NULL;     
-
+       char            *mechs;
+       char            *encoded;
+       int             enclen;
+       char            digest[EVP_MAX_MD_SIZE];
+       char            deroid[2];
+       const EVP_MD    *evp_md = EVP_md5();
+       EVP_MD_CTX      md;
+       int             oidpos=0;
+       
        if (datafellows & SSH_OLD_GSSAPI) return NULL;
        
-       gss_indicate_mechs(&min_status, &supported);
+       gss_indicate_mechs(&min_status,&supported);
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
+                                       *((supported->count*2)+1));
+       } else {
+               gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
+                                       *(supported->count+1));
+       }
        
-       buffer_init(&buf);      
-
-       do {
-               if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                       &supported_mechs[i].oid,
-                                                       supported,
-                                                       &present))) {
-                       present=0;
-               }
-               if (present) {
-                       if (!GSS_ERROR(ssh_gssapi_client_ctx(&ctx,
-                                                      &supported_mechs[i].oid,
-                                                      host))) {
-                               /* Append gss_group1_sha1_x to our list */
-                               if (++mech_count > 1) {
-                                   buffer_append(&buf, ",", 1);
+       buffer_init(&buf);
+
+
+       for (i=0;i<supported->count;i++) {
+
+               gss_enc2oid[oidpos].encoded=NULL;
+               
+               if (supported->elements[i].length<128 &&
+                   ssh_gssapi_check_mechanism(&(supported->elements[i]),host)) {
+
+                       /* Earlier versions of this code interpreted the
+                        * spec incorrectly with regard to OID encoding. They
+                        * also mis-encoded the krb5 OID. The following
+                        * _temporary_ code interfaces with these broken
+                        * servers */
+
+                       if (datafellows & SSH_BUG_GSSAPI_BER) {
+                               char *bodge=NULL;
+                               gss_OID_desc krb5oid={9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
+                               gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"};
+                               
+                               if (supported->elements[i].length==krb5oid.length &&
+                                   memcmp(supported->elements[i].elements,
+                                          krb5oid.elements, krb5oid.length)==0) {
+                                       bodge="Se3H81ismmOC3OE+FwYCiQ==";
+                               }
+                               
+                               if (supported->elements[i].length==gsioid.length &&
+                                   memcmp(supported->elements[i].elements,
+                                          gsioid.elements, gsioid.length)==0) {
+                                       bodge="N3+k7/4wGxHyuP8Yxi4RhA==";
+                               }
+
+                               if (bodge) {                            
+                                       if (oidpos!=0) {
+                                               buffer_put_char(&buf,',');
+                                       }
+                               
+                                       buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1);
+                                       buffer_append(&buf, bodge, strlen(bodge));
+
+                                       gss_enc2oid[oidpos].oid=&(supported->elements[i]);
+                                       gss_enc2oid[oidpos].encoded=bodge;
+                       
+                                       oidpos++;
                                }
-                               buffer_append(&buf, gssprefix,
-                                             strlen(gssprefix));
-                               buffer_append(&buf, 
-                                             supported_mechs[i].enc_name,
-                                             strlen(supported_mechs[i].enc_name));
-                               debug("GSSAPI mechanism %s (%s%s) supported",
-                                     supported_mechs[i].name, gssprefix,
-                                     supported_mechs[i].enc_name);
-                       } else {
-                           debug("no credentials for GSSAPI mechanism %s",
-                                 supported_mechs[i].name);
                        }
-               } else {
-                   debug("GSSAPI mechanism %s not supported",
-                         supported_mechs[i].name);
+                       
+                       /* Add the required DER encoding octets and MD5 hash */
+                       deroid[0]=0x06; /* Object Identifier */
+                       deroid[1]=supported->elements[i].length;
+
+                       EVP_DigestInit(&md, evp_md);
+                       EVP_DigestUpdate(&md,deroid,2);
+                       EVP_DigestUpdate(&md,
+                                        supported->elements[i].elements,
+                                        supported->elements[i].length);
+                       EVP_DigestFinal(&md, digest, NULL);
+                       
+                       /* Base64 encode it */
+                       encoded=xmalloc(EVP_MD_size(evp_md)*2);
+                       enclen=__b64_ntop(digest, EVP_MD_size(evp_md),
+                                         encoded,EVP_MD_size(evp_md)*2);
+                       if (oidpos!=0) {
+                               buffer_put_char(&buf,',');
+                       }       
+                       buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1);
+                       buffer_append(&buf, encoded, enclen);
+
+                       debug("Mechanism encoded as %s",encoded);
+
+                       gss_enc2oid[oidpos].oid=&(supported->elements[i]);
+                       gss_enc2oid[oidpos].encoded=encoded;                    
+                       oidpos++;
                }
-       } while (supported_mechs[++i].name != NULL);
+       }
+       gss_enc2oid[oidpos].oid=NULL;
+       gss_enc2oid[oidpos].encoded=NULL;
        
        buffer_put_char(&buf,'\0');
        
@@ -153,11 +173,41 @@ ssh_gssapi_mechanisms(char *host) {
        buffer_get(&buf,mechs,buffer_len(&buf));
        buffer_free(&buf);
        if (strlen(mechs)==0)
-          return(NULL);
+               return(NULL);
        else
-          return(mechs);
+               return(mechs);
+}
+
+gss_OID
+ssh_gssapi_client_id_kex(Gssctxt *ctx, char *name) {
+       int i=0;
+       
+       if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
+               return(NULL);
+       }
+       
+       name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the ID string */
+       
+       while (gss_enc2oid[i].encoded!=NULL &&
+               strcmp(name,gss_enc2oid[i].encoded)!=0) {
+               i++;
+       }
+       
+       if (gss_enc2oid[i].oid!=NULL) {
+               ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid);
+       }
+
+       return gss_enc2oid[i].oid;
 }
 
+/* Check that the OID in a data stream matches that in the context */
+int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) {
+  
+  return (ctx!=NULL && ctx->oid != GSS_C_NO_OID && 
+         ctx->oid->length == len &&
+         memcmp(ctx->oid->elements,data,len)==0);
+}
+       
 /* Set the contexts OID from a data stream */
 void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) { 
   if (ctx->oid != GSS_C_NO_OID) {
@@ -175,80 +225,58 @@ void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) {
   ssh_gssapi_set_oid_data(ctx,oid->elements,oid->length);
 }
 
-/* Find out which GSS type (out of the list we define in ssh-gss.h) a
- * particular connection is using 
- */
-enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) {
-       enum ssh_gss_id i=0;
-       
-       while(supported_mechs[i].name!=NULL) {
-          if (supported_mechs[i].oid.length == ctxt->oid->length &&
-              (memcmp(supported_mechs[i].oid.elements,
-                      ctxt->oid->elements,ctxt->oid->length) == 0))
-              return i;
-          i++;
-       }
-       return(GSS_LAST_ENTRY);
-}
-
-/* Set the GSS context's OID to the oid indicated by the given key exchange
- * name. */
-gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
-  enum ssh_gss_id i=0;
-  
-  if (strncmp(name, gssprefix, strlen(gssprefix)-1) !=0) {
-     return(NULL);
-  }
-  
-  name+=strlen(gssprefix); /* Move to the start of the MIME string */
-  
-  while (supported_mechs[i].name!=NULL &&
-        strcmp(name,supported_mechs[i].enc_name)!=0) {
-       i++;
-  }
-
-  if (supported_mechs[i].name==NULL)
-     return (NULL);
-
-  if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid);
-
-  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i].name,
-       gssprefix, supported_mechs[i].enc_name);
+/* All this effort to report an error ... */
 
-  return &supported_mechs[i].oid;
+void
+ssh_gssapi_error(Gssctxt *ctxt) {
+       
+       debug(ssh_gssapi_last_error(ctxt,NULL,NULL));
 }
 
-
-/* All this effort to report an error ... */
-void
-ssh_gssapi_error(gss_OID mech, OM_uint32 major_status,
-                OM_uint32 minor_status) {
-       OM_uint32 lmaj, lmin;
-        gss_buffer_desc msg = {0,NULL};
+char *
+ssh_gssapi_last_error(Gssctxt *ctxt, 
+                     OM_uint32 *major_status, OM_uint32 *minor_status) {
+       OM_uint32 lmin;
+        gss_buffer_desc msg;
         OM_uint32 ctx;
+        Buffer b;
+        char *ret;
         
+        buffer_init(&b);
+
+       if (major_status!=NULL) *major_status=ctxt->major;
+       if (minor_status!=NULL) *minor_status=ctxt->minor;
+       
         ctx = 0;
        /* The GSSAPI error */
         do {
-               lmaj = gss_display_status(&lmin, major_status,
-                                         GSS_C_GSS_CODE,
-                                         mech, &ctx, &msg);
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);         
+               gss_display_status(&lmin, ctxt->major,
+                                  GSS_C_GSS_CODE, ctxt->oid,
+                                  &ctx, &msg);
+
+               buffer_append(&b,msg.value,msg.length);
+               buffer_put_char(&b,'\n');
+               
+                       gss_release_buffer(&lmin, &msg);
+        } while (ctx!=0);
 
         /* The mechanism specific error */
         do {
-               lmaj = gss_display_status(&lmin, minor_status,
-                                         GSS_C_MECH_CODE,
-                                         mech, &ctx, &msg);
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
+               gss_display_status(&lmin, ctxt->minor,
+                                  GSS_C_MECH_CODE, ctxt->oid,
+                                  &ctx, &msg);
+               
+               buffer_append(&b,msg.value,msg.length);
+               buffer_put_char(&b,'\n');
+               
+               gss_release_buffer(&lmin, &msg);
         } while (ctx!=0);
+        
+        buffer_put_char(&b,'\0');
+        ret=xmalloc(buffer_len(&b));
+        buffer_get(&b,ret,buffer_len(&b));
+        buffer_free(&b);
+        return(ret);
 }
 
 /* Initialise our GSSAPI context. We use this opaque structure to contain all
@@ -260,6 +288,8 @@ void
 ssh_gssapi_build_ctx(Gssctxt **ctx)
 {
        *ctx=xmalloc(sizeof (Gssctxt));
+       (*ctx)->major=0;
+       (*ctx)->minor=0;
        (*ctx)->context=GSS_C_NO_CONTEXT;
        (*ctx)->name=GSS_C_NO_NAME;
        (*ctx)->oid=GSS_C_NO_OID;
@@ -311,7 +341,6 @@ OM_uint32
 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                            gss_buffer_desc* send_tok, OM_uint32 *flags) 
 {
-       OM_uint32 maj_status, min_status;
        int deleg_flag = 0;
        
        if (deleg_creds) {
@@ -319,7 +348,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                debug("Delegating credentials");
        }
                
-       maj_status=gss_init_sec_context(&min_status,
+       ctx->major=gss_init_sec_context(&ctx->minor,
                                        GSS_C_NO_CREDENTIAL, /* def. cred */
                                        &ctx->context,
                                        ctx->name,
@@ -334,28 +363,26 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                                        send_tok,
                                        flags,
                                        NULL);
-       ctx->status=maj_status;
-       if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
+       if (GSS_ERROR(ctx->major)) {
+               ssh_gssapi_error(ctx);
        }
-       return(maj_status);
+       return(ctx->major);
 }
 
 /* Create a service name for the given host */
 OM_uint32
 ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
-       gss_buffer_desc gssbuf = {0,NULL};
-       OM_uint32 maj_status, min_status;
+       gss_buffer_desc gssbuf;
        char *xhost;
        
        /* Make a copy of the host name, in case it was returned by a
         * previous call to gethostbyname(). */ 
        xhost = xstrdup(host);
 
-       /* Make sure we have the FQHN. Some GSSAPI implementations don't do
+       /* Make sure we have the FQDN. Some GSSAPI implementations don't do
         * this for us themselves */
        resolve_localhost(&xhost);
-
+       
         gssbuf.length = sizeof("host@")+strlen(xhost);
 
         gssbuf.value = xmalloc(gssbuf.length);
@@ -364,16 +391,16 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
                return(-1);
         }
         snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost);
-        if ((maj_status=gss_import_name(&min_status,
+        if ((ctx->major=gss_import_name(&ctx->minor,
                                        &gssbuf,
                                         GSS_C_NT_HOSTBASED_SERVICE,
                                         &ctx->name))) {
-               ssh_gssapi_error(ctx->oid, maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
        
        xfree(xhost);
        xfree(gssbuf.value);
-       return(maj_status);
+       return(ctx->major);
 }
 
 /* Acquire credentials for a server running on the current host.
@@ -383,21 +410,22 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
 /* Returns a GSSAPI error code */
 OM_uint32
 ssh_gssapi_acquire_cred(Gssctxt *ctx) {
-       OM_uint32 maj_status, min_status;
+       OM_uint32 status;
        char lname[MAXHOSTNAMELEN];
        gss_OID_set oidset;
        
-       gss_create_empty_oid_set(&min_status,&oidset);
-       gss_add_oid_set_member(&min_status,ctx->oid,&oidset);
+       gss_create_empty_oid_set(&status,&oidset);
+       gss_add_oid_set_member(&status,ctx->oid,&oidset);
        
         if (gethostname(lname, MAXHOSTNAMELEN)) {
                 return(-1);
         }
 
-       if ((maj_status=ssh_gssapi_import_name(ctx,lname))) {
-               return(maj_status);
+       if (GSS_ERROR(ssh_gssapi_import_name(ctx,lname))) {
+               return(ctx->major);
        }
-       if ((maj_status=gss_acquire_cred(&min_status,
+       
+       if ((ctx->major=gss_acquire_cred(&ctx->minor,
                                    ctx->name,
                                    0,
                                    oidset,
@@ -405,73 +433,58 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) {
                                    &ctx->creds,
                                    NULL,
                                    NULL))) {
-           ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
                                
-       gss_release_oid_set(&min_status, &oidset);
-       return(maj_status);
-}
-
-/* Extract the client details from a given context. This can only reliably
- * be called once for a context */
-
-OM_uint32 
-ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type,
-                    gss_buffer_desc *name, gss_cred_id_t *creds) {
-
-       OM_uint32 maj_status,min_status;
-       
-       *type=ssh_gssapi_get_ctype(ctx);
-       if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
-       }
-       
-       /* This is icky. There appears to be no way to copy this structure,
-        * rather than the pointer to it, so we simply copy the pointer and
-        * mark the originator as empty so we don't destroy it. 
-        */
-       *creds=ctx->client_creds;
-       ctx->client_creds=GSS_C_NO_CREDENTIAL;
-       return(maj_status);
+       gss_release_oid_set(&status, &oidset);
+       return(ctx->major);
 }
 
 OM_uint32
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) {
-       OM_uint32 maj_status,min_status;
        
        /* ssh1 needs to exchange the hash of the keys */
        /* will us this hash to return it */
        if (!compat20) {
-               if ((maj_status=gss_wrap(&min_status,ctx->context,
-                                       0,
-                                       GSS_C_QOP_DEFAULT,
-                                       buffer,
-                                       NULL,
-                                       hash)))
-                       ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               if ((ctx->major=gss_wrap(&ctx->minor,ctx->context,
+                                        0,
+                                        GSS_C_QOP_DEFAULT,
+                                        buffer,
+                                        NULL,
+                                        hash)))
+                   ssh_gssapi_error(ctx);
        }
        else
 
-       if ((maj_status=gss_get_mic(&min_status,ctx->context,
+       if ((ctx->major=gss_get_mic(&ctx->minor,ctx->context,
                                    GSS_C_QOP_DEFAULT, buffer, hash))) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
        
-       return(maj_status);
+       return(ctx->major);
 }
 
-OM_uint32 
-ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) {
-       gss_buffer_desc token = {0,NULL};
-       OM_uint32 major,minor;
-       
+OM_uint32
+ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
        if (*ctx) ssh_gssapi_delete_ctx(ctx);
        ssh_gssapi_build_ctx(ctx);
        ssh_gssapi_set_oid(*ctx,oid);
-       ssh_gssapi_import_name(*ctx,host);
-       major=ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
+       return(ssh_gssapi_acquire_cred(*ctx));
+}
+
+int
+ssh_gssapi_check_mechanism(gss_OID oid, char *host) {
+       Gssctxt * ctx = NULL;
+       gss_buffer_desc token;
+       OM_uint32 major,minor;
+       
+       ssh_gssapi_build_ctx(&ctx);
+       ssh_gssapi_set_oid(ctx,oid);
+       ssh_gssapi_import_name(ctx,host);
+       major=ssh_gssapi_init_ctx(ctx,0, GSS_C_NO_BUFFER, &token, NULL);
        gss_release_buffer(&minor,&token);
-       return(major);
+       ssh_gssapi_delete_ctx(&ctx);
+       return(!GSS_ERROR(major));
 }
 
 #endif /* GSSAPI */
diff --git a/openssh/gss-serv-gsi.c b/openssh/gss-serv-gsi.c
new file mode 100644 (file)
index 0000000..dcf60e0
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef GSSAPI
+#ifdef GSI
+
+#include "auth.h"
+#include "auth-pam.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+
+#include "ssh-gss.h"
+
+#include <globus_gss_assist.h>
+
+static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
+static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
+static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
+
+ssh_gssapi_mech gssapi_gsi_mech_old = {
+       "N3+k7/4wGxHyuP8Yxi4RhA==",
+       "GSI",
+       {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
+       NULL,
+       &ssh_gssapi_gsi_userok,
+       &ssh_gssapi_gsi_localname,
+       &ssh_gssapi_gsi_storecreds
+};
+
+ssh_gssapi_mech gssapi_gsi_mech = {
+       "dZuIebMjgUqaxvbF7hDbAw==",
+       "GSI",
+       {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
+       NULL,
+       &ssh_gssapi_gsi_userok,
+       &ssh_gssapi_gsi_localname,
+       &ssh_gssapi_gsi_storecreds
+};
+
+/*
+ * Check if this user is OK to login under GSI. User has been authenticated
+ * as identity in global 'client_name.value' and is trying to log in as passed
+ * username in 'name'.
+ *
+ * Returns non-zero if user is authorized, 0 otherwise.
+ */
+static int
+ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
+{
+    int authorized = 0;
+    
+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+       return 0;
+    }
+#endif
+
+    /* This returns 0 on success */
+    authorized = (globus_gss_assist_userok(client->name.value,
+                                          name) == 0);
+    
+    log("GSI user %s is%s authorized as target user %s",
+       (char *) client->name.value, (authorized ? "" : " not"), name);
+    
+    return authorized;
+}
+
+/*
+ * Return the local username associated with the GSI credentials.
+ */
+int
+ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
+{
+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+       return 0;
+    }
+#endif
+    return(globus_gss_assist_gridmap(client->name.value, user) == 0);
+}
+
+/*
+ * Export GSI credentials to disk.
+ */
+static void
+ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
+{
+       OM_uint32       major_status;
+       OM_uint32       minor_status;
+       gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
+       char *          p;
+       
+       if (!client || !client->creds) {
+           return;
+       }
+
+       major_status = gss_export_cred(&minor_status,
+                                      client->creds,
+                                      GSS_C_NO_OID,
+                                      1,
+                                      &export_cred);
+       if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
+           Gssctxt *ctx;
+           ssh_gssapi_build_ctx(&ctx);
+           ctx->major = major_status;
+           ctx->minor = minor_status;
+           ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
+           ssh_gssapi_error(ctx);
+           ssh_gssapi_delete_ctx(&ctx);
+           return;
+       }
+       
+       p = strchr((char *) export_cred.value, '=');
+       if (p == NULL) {
+           log("Failed to parse exported credentials string '%.100s'",
+               (char *)export_cred.value);
+           gss_release_buffer(&minor_status, &export_cred);
+           return;
+       }
+       *p++ = '\0';
+       if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
+           client->store.envvar = strdup("X509_USER_PROXY");
+       } else {
+           client->store.envvar = strdup((char *)export_cred.value);
+       }
+       client->store.envval = strdup(p);
+#ifdef USE_PAM
+       do_pam_putenv(client->store.envvar, client->store.envval);
+#endif
+       if (strncmp(p, "FILE:", 5) == 0) {
+           p += 5;
+       }
+       if (access(p, R_OK) == 0) {
+           client->store.filename = strdup(p);
+       }
+       gss_release_buffer(&minor_status, &export_cred);
+}
+
+#endif /* GSI */
+#endif /* GSSAPI */
diff --git a/openssh/gss-serv-krb5.c b/openssh/gss-serv-krb5.c
new file mode 100644 (file)
index 0000000..c7f3ad1
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef GSSAPI
+#ifdef KRB5
+
+#include "auth.h"
+#include "auth-pam.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+#ifdef HEIMDAL
+#include <krb5.h>
+#else
+#include <gssapi_krb5.h>
+#define krb5_get_err_text(context,code) error_message(code)
+#endif
+
+static int ssh_gssapi_krb5_init();
+static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name);
+static int ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user);
+static void ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client);
+
+static krb5_context krb_context = NULL;
+
+/* We've been using a wrongly encoded mechanism ID for yonks */
+
+ssh_gssapi_mech gssapi_kerberos_mech_old = {
+       "Se3H81ismmOC3OE+FwYCiQ==",
+       "Kerberos",
+       {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+       &ssh_gssapi_krb5_init,
+       &ssh_gssapi_krb5_userok,
+       &ssh_gssapi_krb5_localname,
+       &ssh_gssapi_krb5_storecreds
+};
+
+ssh_gssapi_mech gssapi_kerberos_mech = {
+       "toWM5Slw5Ew8Mqkay+al2g==",
+       "Kerberos",
+       {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+       NULL,
+       &ssh_gssapi_krb5_userok,
+       &ssh_gssapi_krb5_localname,
+       &ssh_gssapi_krb5_storecreds
+};
+       
+/* Initialise the krb5 library, so we can use it for those bits that
+ * GSSAPI won't do */
+
+static int 
+ssh_gssapi_krb5_init() {
+       krb5_error_code problem;
+       
+       if (krb_context !=NULL)
+               return 1;
+               
+       problem = krb5_init_context(&krb_context);
+       if (problem) {
+               log("Cannot initialize krb5 context");
+               return 0;
+       }
+       krb5_init_ets(krb_context);
+
+       return 1;       
+}                      
+
+/* Check if this user is OK to login. This only works with krb5 - other 
+ * GSSAPI mechanisms will need their own.
+ * Returns true if the user is OK to log in, otherwise returns 0
+ */
+
+static int
+ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) {
+       krb5_principal princ;
+       int retval;
+
+       if (ssh_gssapi_krb5_init() == 0)
+               return 0;
+               
+       if ((retval=krb5_parse_name(krb_context, client->name.value, 
+                                   &princ))) {
+               log("krb5_parse_name(): %.100s", 
+                       krb5_get_err_text(krb_context,retval));
+               return 0;
+       }
+       if (krb5_kuserok(krb_context, princ, name)) {
+               retval = 1;
+               log("Authorized to %s, krb5 principal %s (krb5_kuserok)",name,
+                   (char *)client->name.value);
+       }
+       else
+               retval = 0;
+       
+       krb5_free_principal(krb_context, princ);
+       return retval;
+}
+
+/* Retrieve the local username associated with a set of Kerberos 
+ * credentials. Hopefully we can use this for the 'empty' username
+ * logins discussed in the draft  */
+static int
+ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
+       krb5_principal princ;
+       int retval;
+       
+       if (ssh_gssapi_krb5_init() == 0)
+               return 0;
+
+       if ((retval=krb5_parse_name(krb_context, client->name.value, 
+                                   &princ))) {
+               log("krb5_parse_name(): %.100s", 
+                       krb5_get_err_text(krb_context,retval));
+               return 0;
+       }
+       
+       /* We've got to return a malloc'd string */
+       *user = (char *)xmalloc(256);
+       if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
+               xfree(*user);
+               *user = NULL;
+               return(0);
+       }
+       
+       return(1);
+}
+       
+/* Make sure that this is called _after_ we've setuid to the user */
+
+/* This writes out any forwarded credentials. Its specific to the Kerberos
+ * GSSAPI mechanism
+ *
+ * We assume that our caller has made sure that the user has selected
+ * delegated credentials, and that the client_creds structure is correctly
+ * populated.
+ */
+
+static void
+ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) {
+       krb5_ccache ccache;
+       krb5_error_code problem;
+       krb5_principal princ;
+       char ccname[35];
+       static char name[40];
+       int tmpfd;
+       OM_uint32 maj_status,min_status;
+       gss_cred_id_t krb5_cred_handle;
+
+       if (client->creds==NULL) {
+               debug("No credentials stored"); 
+               return;
+       }
+               
+       if (ssh_gssapi_krb5_init() == 0)
+               return;
+
+       if (options.gss_use_session_ccache) {
+               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
+       
+               if ((tmpfd = mkstemp(ccname))==-1) {
+                       log("mkstemp(): %.100s", strerror(errno));
+                       return;
+               }
+               if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
+                       log("fchmod(): %.100s", strerror(errno));
+                       close(tmpfd);
+                       return;
+               }
+        } else {
+               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
+               tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+               if (tmpfd == -1) {
+                       log("open(): %.100s", strerror(errno));
+                       return;
+               }
+        }
+
+               close(tmpfd);
+        snprintf(name, sizeof(name), "FILE:%s",ccname);
+        if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
+                log("krb5_cc_default(): %.100s", 
+                       krb5_get_err_text(krb_context,problem));
+                return;
+        }
+
+       if ((problem = krb5_parse_name(krb_context, client->name.value, 
+                                      &princ))) {
+               log("krb5_parse_name(): %.100s", 
+                       krb5_get_err_text(krb_context,problem));
+               krb5_cc_destroy(krb_context,ccache);
+               return;
+       }
+       
+       if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
+               log("krb5_cc_initialize(): %.100s", 
+                       krb5_get_err_text(krb_context,problem));
+               krb5_free_principal(krb_context,princ);
+               krb5_cc_destroy(krb_context,ccache);
+               return;
+       }
+       
+       krb5_free_principal(krb_context,princ);
+
+#ifdef MECHGLUE
+       krb5_cred_handle =
+           __gss_get_mechanism_cred(client->creds,
+                                    &(gssapi_kerberos_mech.oid));
+#else
+       krb5_cred_handle = client->creds;
+#endif
+
+       if ((maj_status = gss_krb5_copy_ccache(&min_status, 
+                                              client->creds, 
+                                              ccache))) {
+               log("gss_krb5_copy_ccache() failed");
+               krb5_cc_destroy(krb_context,ccache);
+               return;
+       }
+       
+       krb5_cc_close(krb_context,ccache);
+
+#ifdef USE_PAM
+       do_pam_putenv("KRB5CCNAME",name);
+#endif
+
+       client->store.filename=strdup(ccname);
+       client->store.envvar="KRB5CCNAME";
+       client->store.envval=strdup(name);
+
+       return;
+}
+
+#endif /* KRB5 */
+
+#endif /* GSSAPI */
index 0edb918e4fa63ff763df43cd82936d055a920c11..39cdb3f6933404040e6caae06e6736931ce06d81 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,7 +27,6 @@
 #ifdef GSSAPI
 
 #include "ssh.h"
-#include "ssh1.h"
 #include "ssh2.h"
 #include "xmalloc.h"
 #include "buffer.h"
@@ -44,7 +43,6 @@
 #include "dispatch.h"
 #include "servconf.h"
 #include "compat.h"
-#include "misc.h"
 #include "monitor_wrap.h"
 
 #include "ssh-gss.h"
@@ -53,652 +51,100 @@ extern ServerOptions options;
 extern u_char *session_id2;
 extern int session_id2_len;
 
-typedef struct ssh_gssapi_cred_cache {
-       char *filename;
-       char *envvar;
-       char *envval;
-       void *data;
-} ssh_gssapi_cred_cache;
+static ssh_gssapi_client gssapi_client =
+       { {0,NULL}, GSS_C_NO_CREDENTIAL, NULL, {NULL,NULL,NULL}};
 
-static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL};
-
-/*
- * Environment variables pointing to delegated credentials
- */
-static char *delegation_env[] = {
-  "X509_USER_PROXY",           /* GSSAPI/SSLeay */
-  "KRB5CCNAME",                        /* Krb5 and possibly SSLeay */
-  NULL
-};
-
-static void gssapi_unsetenv(const char *var);
+ssh_gssapi_mech gssapi_null_mech 
+  = {NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
 
 #ifdef KRB5
-
-#ifdef HEIMDAL
-#include <krb5.h>
-#else
-#include <gssapi_krb5.h>
-#define krb5_get_err_text(context,code) error_message(code)
-#endif
-
-static krb5_context krb_context = NULL;
-
-/* Initialise the krb5 library, so we can use it for those bits that
- * GSSAPI won't do */
-
-int ssh_gssapi_krb5_init() {
-       krb5_error_code problem;
-       
-       if (krb_context !=NULL)
-               return 1;
-               
-       problem = krb5_init_context(&krb_context);
-       if (problem) {
-               log("Cannot initialize krb5 context");
-               return 0;
-       }
-       krb5_init_ets(krb_context);
-
-       return 1;       
-}                      
-
-/* Check if this user is OK to login. This only works with krb5 - other 
- * GSSAPI mechanisms will need their own.
- * Returns true if the user is OK to log in, otherwise returns 0
- */
-
-int
-ssh_gssapi_krb5_userok(char *name) {
-       krb5_principal princ;
-       int retval;
-
-       if (ssh_gssapi_krb5_init() == 0)
-               return 0;
-               
-       if ((retval=krb5_parse_name(krb_context, gssapi_client_name.value, 
-                                   &princ))) {
-               log("krb5_parse_name(): %.100s", 
-                       krb5_get_err_text(krb_context,retval));
-               return 0;
-       }
-       if (krb5_kuserok(krb_context, princ, name)) {
-               retval = 1;
-               log("Authorized to %s, krb5 principal %s (krb5_kuserok)",name,
-                   (char *)gssapi_client_name.value);
-       }
-       else
-               retval = 0;
-       
-       krb5_free_principal(krb_context, princ);
-       return retval;
-}
-
-int
-ssh_gssapi_krb5_localname(char **user)
-{
-    krb5_principal princ;
-
-    if (ssh_gssapi_krb5_init() == 0)
-       return 0;
-
-    if (krb5_parse_name(krb_context, gssapi_client_name.value, &princ)) {
-       return(0);
-    }
-    *user = (char *)xmalloc(256);
-    if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
-       xfree(*user);
-       *user = NULL;
-       return(0);
-    }
-    return(1);
-}
-       
-/* Make sure that this is called _after_ we've setuid to the user */
-
-/* This writes out any forwarded credentials. Its specific to the Kerberos
- * GSSAPI mechanism
- *
- * We assume that our caller has made sure that the user has selected
- * delegated credentials, and that the client_creds structure is correctly
- * populated.
- */
-
-OM_uint32
-ssh_gssapi_krb5_storecreds(gss_buffer_t export_buffer) {
-       krb5_ccache ccache;
-       krb5_error_code problem;
-       krb5_principal princ;
-       char ccname[35];
-       static char name[40];
-       int tmpfd;
-       OM_uint32 maj_status,min_status;
-       gss_cred_id_t krb5_cred_handle;
-
-
-       if (gssapi_client_creds==NULL) {
-               debug("No credentials stored"); 
-               return GSS_S_NO_CRED;
-       }
-               
-       if (ssh_gssapi_krb5_init() == 0)
-               return GSS_S_FAILURE;
-
-       if (options.gss_use_session_ccache) {
-               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
-       
-               if ((tmpfd = mkstemp(ccname))==-1) {
-                       log("mkstemp(): %.100s", strerror(errno));
-                       return GSS_S_FAILURE;
-               }
-               if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
-                       log("fchmod(): %.100s", strerror(errno));
-                       close(tmpfd);
-                       return GSS_S_FAILURE;
-               }
-        } else {
-               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
-               tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
-               if (tmpfd == -1) {
-                       log("open(): %.100s", strerror(errno));
-                       return GSS_S_FAILURE;
-               }
-        }
-
-               close(tmpfd);
-        snprintf(name, sizeof(name), "FILE:%s",ccname);
-        if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
-                log("krb5_cc_default(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-                return GSS_S_FAILURE;
-        }
-
-       if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value, 
-                                      &princ))) {
-               log("krb5_parse_name(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
-               log("krb5_cc_initialize(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-               krb5_free_principal(krb_context,princ);
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       krb5_free_principal(krb_context,princ);
-
-#ifdef MECHGLUE
-       krb5_cred_handle =
-           __gss_get_mechanism_cred(gssapi_client_creds,
-                                    &(supported_mechs[GSS_KERBEROS].oid));
-#else
-       krb5_cred_handle = gssapi_client_creds;
+extern ssh_gssapi_mech gssapi_kerberos_mech;
+extern ssh_gssapi_mech gssapi_kerberos_mech_old;
 #endif
-
-       if ((maj_status = gss_krb5_copy_ccache(&min_status, 
-                                              krb5_cred_handle, 
-                                              ccache))) {
-               log("gss_krb5_copy_ccache() failed");
-               ssh_gssapi_error(&supported_mechs[GSS_KERBEROS].oid,
-                                maj_status,min_status);
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       krb5_cc_close(krb_context,ccache);
-
-       export_buffer->length = strlen("KRB5CCNAME")+strlen(name)+1;
-       export_buffer->value = xmalloc(export_buffer->length+1);
-       sprintf(export_buffer->value, "%s=%s", "KRB5CCNAME", name);
-
-       return GSS_S_COMPLETE;
-}
-
-#endif /* KRB5 */
-
 #ifdef GSI
-#include <globus_gss_assist.h>
-
-/*
- * Check if this user is OK to login under GSI. User has been authenticated
- * as identity in global 'client_name.value' and is trying to log in as passed
- * username in 'name'.
- *
- * Returns non-zero if user is authorized, 0 otherwise.
- */
-int
-ssh_gssapi_gsi_userok(char *name)
-{
-    int authorized = 0;
-    
-#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-       return 0;
-    }
+extern ssh_gssapi_mech gssapi_gsi_mech;
+extern ssh_gssapi_mech gssapi_gsi_mech_old;
 #endif
 
-    /* globus_gss_assist_userok() returns 0 on success */
-    authorized = (globus_gss_assist_userok(gssapi_client_name.value,
-                                          name) == 0);
-    
-    log("GSI user %s is%s authorized as target user %s",
-       (char *) gssapi_client_name.value, (authorized ? "" : " not"), name);
-    
-    return authorized;
-}
-
-/*
- * Return the local username associated with the GSI credentials.
- */
-int
-ssh_gssapi_gsi_localname(char **user)
-{
-#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-       return 0;
-    }
-#endif
-    return(globus_gss_assist_gridmap(gssapi_client_name.value, user) == 0);
-}
-
-/*
- * Handle setting up child environment for GSI.
- *
- * Make sure that this is called _after_ we've setuid to the user.
- */
-OM_uint32
-ssh_gssapi_gsi_storecreds(gss_buffer_t export_buffer)
-{
-       OM_uint32       major_status;
-       OM_uint32       minor_status;
-
-       if (gssapi_client_creds != NULL)
-       {
-               char *creds_env = NULL;
-
-               /*
-                * This is the current hack with the GSI gssapi library to
-                * export credentials to disk.
-                */
-
-               debug("Exporting delegated credentials");
-               
-               minor_status = 0xdee0;  /* Magic value */
-               major_status =
-                       gss_inquire_cred(&minor_status,
-                                        gssapi_client_creds,
-                                        (gss_name_t *) &creds_env,
-                                        NULL,
-                                        NULL,
-                                        NULL);
-
-               if ((major_status == GSS_S_COMPLETE) &&
-                   (minor_status == 0xdee1) &&
-                   (creds_env != NULL))
-               {
-                       char            *value;
-                               
-                       /*
-                        * String is of the form:
-                        * X509_USER_DELEG_PROXY=filename
-                        * so we parse out the filename
-                        * and then set X509_USER_PROXY
-                        * to point at it.
-                        */
-                       value = strchr(creds_env, '=');
-                       
-                       if (value != NULL)
-                       {
-                               *value = '\0';
-                               value++;
-                               export_buffer->length=
-                                   strlen("X509_USER_PROXY")+strlen(value)+1;
-                               export_buffer->value =
-                                   xmalloc(export_buffer->length+1);
-                               sprintf(export_buffer->value, "%s=%s",
-                                       "X509_USER_PROXY", value);
-                               
-                               return GSS_S_COMPLETE;
-                       }
-                       else
-                       {
-                           log("Failed to parse delegated credentials string '%s'",
-                               creds_env);
-                       }
-               }
-               else
-               {
-                   log("Failed to export delegated credentials (error %u)",
-                       (unsigned int)major_status);
-               }
-       }
-       return 0;
-}
-
-#endif /* GSI */
-
-void
-ssh_gssapi_cleanup_creds(void *ignored)
-{
-       /* OM_uint32 min_stat; */
-
-       if (gssapi_cred_store.filename!=NULL) {
-               /* Unlink probably isn't sufficient */
-               debug("removing gssapi cred file \"%s\"",gssapi_cred_store.filename);
-               unlink(gssapi_cred_store.filename);
-       }
-       /* DK ?? 
-       if (gssapi_client_creds != GSS_C_NO_CREDENTIAL)
-               gss_release_cred(&min_stat, &gssapi_client_creds);
-       */
-}
-
-OM_uint32
-ssh_gssapi_export_cred(OM_uint32 *            minor_status,
-                      const gss_cred_id_t    cred_handle,
-                      const gss_OID          desired_mech,
-                      OM_uint32              option_req,
-                      gss_buffer_t           export_buffer)
-{
-       OM_uint32 maj_stat = GSS_S_FAILURE;
-
-       if (option_req != 1) return GSS_S_UNAVAILABLE;
-       if (desired_mech != NULL) return GSS_S_BAD_MECH;
-
-       switch (gssapi_client_type) {
+ssh_gssapi_mech* supported_mechs[]= {
 #ifdef KRB5
-       case GSS_KERBEROS:
-               maj_stat = ssh_gssapi_krb5_storecreds(export_buffer);
-               break;
+  &gssapi_kerberos_mech,
+  &gssapi_kerberos_mech_old, /* Support for legacy clients */
 #endif
 #ifdef GSI
-       case GSS_GSI:
-               maj_stat = ssh_gssapi_gsi_storecreds(export_buffer);
-               break;
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               /* GSSAPI not used in this authentication */
-               debug("No GSSAPI credentials stored");
-               break;
-       default:
-               log("ssh_gssapi_do_child: Unknown mechanism");
-       
-       }
-
-       if (GSS_ERROR(maj_stat)) {
-               *minor_status = GSS_S_FAILURE;
-       }
-       return maj_stat;
-}
-
-void 
-ssh_gssapi_storecreds()
-{
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
-       char *p;
-
-       if (gssapi_client_creds == GSS_C_NO_CREDENTIAL)
-               return;
-
-#ifdef HAVE_GSSAPI_EXT
-       maj_stat = gss_export_cred(&min_stat, gssapi_client_creds,
-                                  GSS_C_NO_OID, 1, &export_cred);
-       if (GSS_ERROR(maj_stat) && maj_stat != GSS_S_UNAVAILABLE) {
-               ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
-               return;
-       }
-#endif
-
-       /* If gss_export_cred() is not available, use old methods */
-       if (export_cred.length == 0) {
-           ssh_gssapi_export_cred(&min_stat, gssapi_client_creds,
-                                  GSS_C_NO_OID, 1, &export_cred);
-           if (GSS_ERROR(maj_stat)) {
-               ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
-           }
-       }
-
-       p = strchr((char *) export_cred.value, '=');
-       if (p == NULL) {
-               log("Failed to parse exported credentials string '%.100s'",
-                   (char *)export_cred.value);
-               gss_release_buffer(&min_stat, &export_cred);
-               return;
-       }
-       *p++ = '\0';
-#ifdef GSI
-       if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0)
-           gssapi_cred_store.envvar = strdup("X509_USER_PROXY");
-       else
+  &gssapi_gsi_mech,
+  &gssapi_gsi_mech_old,        /* Support for legacy clients */
 #endif
-       gssapi_cred_store.envvar = strdup((char *)export_cred.value);
-       gssapi_cred_store.envval = strdup(p);
-#ifdef USE_PAM
-       do_pam_putenv(gssapi_cred_store.envvar, gssapi_cred_store.envval);
-#endif
-       if (strncmp(p, "FILE:", 5) == 0) {
-           p += 5;
-       }
-       if (access(p, R_OK) == 0) {
-           gssapi_cred_store.filename = strdup(p);
-       }
-       gss_release_buffer(&min_stat, &export_cred);
-
-       if (options.gss_cleanup_creds) {
-               fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
-       }
-}
+  &gssapi_null_mech,
+};
 
-/* This allows GSSAPI methods to do things to the childs environment based
- * on the passed authentication process and credentials.
+/* Return a list of the gss-group1-sha1-x mechanisms supported by this
+ * program.
  *
- * Question: If we didn't use userauth_external for some reason, should we
- * still delegate credentials?
- */
-void 
-ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
-{
-
-       if (gssapi_cred_store.envvar!=NULL && 
-           gssapi_cred_store.envval!=NULL) {
-           
-               debug("Setting %s to %s", gssapi_cred_store.envvar,
-                                         gssapi_cred_store.envval);                              
-               child_set_env(envp, envsizep, gssapi_cred_store.envvar, 
-                                             gssapi_cred_store.envval);
-       }
-
-       switch(gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS: break;
-#endif
-#ifdef GSI
-       case GSS_GSI: break;
-#endif
-       case GSS_LAST_ENTRY:
-               debug("No GSSAPI credentials stored");
-               break;
-       default:
-               log("ssh_gssapi_do_child: Unknown mechanism");
-       }
-}
-
-int
-ssh_gssapi_userok(char *user)
-{
-       if (gssapi_client_name.length==0 || 
-           gssapi_client_name.value==NULL) {
-               debug("No suitable client data");
-               return 0;
-       }
-       switch (gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS:
-               return(ssh_gssapi_krb5_userok(user));
-               break; /* Not reached */
-#endif
-#ifdef GSI
-       case GSS_GSI:
-               return(ssh_gssapi_gsi_userok(user));
-               break; /* Not reached */
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               debug("Client not GSSAPI");
-               break;
-       default:
-               debug("Unknown client authentication type");
-       }
-       return(0);
-}
-
-int
-ssh_gssapi_localname(char **user)
-{
-       *user = NULL;
-       if (gssapi_client_name.length==0 || 
-           gssapi_client_name.value==NULL) {
-               debug("No suitable client data");
-               return(0);;
-       }
-       switch (gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS:
-               return(ssh_gssapi_krb5_localname(user));
-               break; /* Not reached */
-#endif
-#ifdef GSI
-       case GSS_GSI:
-               return(ssh_gssapi_gsi_localname(user));
-               break; /* Not reached */
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               debug("Client not GSSAPI");
-               break;
-       default:
-               debug("Unknown client authentication type");
-       }
-       return(0);
-}
-
-/*
- * Clean our environment on startup. This means removing any environment
- * strings that might inadvertantly been in root's environment and 
- * could cause serious security problems if we think we set them.
+ * We only support the mechanisms that we've indicated in the list above,
+ * but we check that they're supported by the GSSAPI mechanism on the 
+ * machine. We also check, before including them in the list, that
+ * we have the necesary information in order to carry out the key exchange
+ * (that is, that the user has credentials, the server's creds are accessible,
+ * etc)
+ *
+ * The way that this is done is fairly nasty, as we do a lot of work that
+ * is then thrown away. This should possibly be implemented with a cache
+ * that stores the results (in an expanded Gssctxt structure), which are
+ * then used by the first calls if that key exchange mechanism is chosen.
  */
-void
-ssh_gssapi_clean_env(void)
-{
-  char *envstr;
-  int envstr_index;
-
-  
-   for (envstr_index = 0;
-       (envstr = delegation_env[envstr_index]) != NULL;
-       envstr_index++) {
-
-     if (getenv(envstr)) {
-       debug("Clearing environment variable %s", envstr);
-       gssapi_unsetenv(envstr);
-     }
-   }
-}
-
-/*
- * Wrapper around unsetenv.
- */
-static void
-gssapi_unsetenv(const char *var)
-{
-#ifdef HAVE_UNSETENV
-    unsetenv(var);
-
-#else /* !HAVE_UNSETENV */
-    extern char **environ;
-    char **p1 = environ;       /* New array list */
-    char **p2 = environ;       /* Current array list */
-    int len = strlen(var);
-
-    /*
-     * Walk through current environ array (p2) copying each pointer
-     * to new environ array (p1) unless the pointer is to the item
-     * we want to delete. Copy happens in place.
-     */
-    while (*p2) {
-       if ((strncmp(*p2, var, len) == 0) &&
-           ((*p2)[len] == '=')) {
-           /*
-            * *p2 points at item to be deleted, just skip over it
-            */
-           p2++;
-       } else {
-           /*
-            * *p2 points at item we want to save, so copy it
-            */
-           *p1 = *p2;
-           p1++;
-           p2++;
-       }
-    }
-
-    /* And make sure new array is NULL terminated */
-    *p1 = NULL;
-#endif /* HAVE_UNSETENV */
-}
 
+/* Unpriviledged */ 
 char * 
-ssh_server_gssapi_mechanisms() {
+ssh_gssapi_server_mechanisms() {
        gss_OID_set     supported;
+       Gssctxt         *ctx = NULL;
        OM_uint32       maj_status, min_status;
        Buffer          buf;
        int             i = 0;
+       int             first = 0;
        int             present;
-       int             mech_count=0;
        char *          mechs;
-       Gssctxt *       ctx = NULL;     
 
        if (datafellows & SSH_OLD_GSSAPI) return NULL;
        
-       PRIVSEP(gss_indicate_mechs(&min_status, &supported));
+       ssh_gssapi_supported_oids(&supported);
        
-       buffer_init(&buf);      
+       buffer_init(&buf);
 
-       do {
+       while(supported_mechs[i]->name != NULL) {
                if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                       &supported_mechs[i].oid,
+                                                       &supported_mechs[i]->oid,
                                                        supported,
                                                        &present))) {
                        present=0;
                }
+
                if (present) {
-                       if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
-                                              &supported_mechs[i].oid)))) {
-                               /* Append gss_group1_sha1_x to our list */
-                               if (++mech_count > 1) {
-                                   buffer_append(&buf, ",", 1);
-                               }
-                               buffer_append(&buf, gssprefix,
-                                             strlen(gssprefix));
-                               buffer_append(&buf, 
-                                             supported_mechs[i].enc_name,
-                                             strlen(supported_mechs[i].enc_name));
-                               debug("GSSAPI mechanism %s (%s%s) supported",
-                                     supported_mechs[i].name, gssprefix,
-                                     supported_mechs[i].enc_name);
-                       } else {
-                           debug("no credentials for GSSAPI mechanism %s",
-                                 supported_mechs[i].name);
-                       }
-               } else {
+                   if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
+                                          &supported_mechs[i]->oid)))) {
+                       /* Append gss_group1_sha1_x to our list */
+                       if (first++!=0)
+                               buffer_put_char(&buf,',');
+                       buffer_append(&buf, KEX_GSS_SHA1,
+                                     sizeof(KEX_GSS_SHA1)-1);
+                       buffer_append(&buf, 
+                                     supported_mechs[i]->enc_name,
+                                     strlen(supported_mechs[i]->enc_name));
+                       debug("GSSAPI mechanism %s (%s%s) supported",
+                             supported_mechs[i]->name, KEX_GSS_SHA1,
+                             supported_mechs[i]->enc_name);
+                   } else {
+                       debug("no credentials for GSSAPI mechanism %s",
+                             supported_mechs[i]->name);
+                   }
+               } else {
                    debug("GSSAPI mechanism %s not supported",
-                         supported_mechs[i].name);
+                         supported_mechs[i]->name);
                }
-       } while (supported_mechs[++i].name != NULL);
+               ssh_gssapi_delete_ctx(&ctx);
+               i++;
+       }
        
        buffer_put_char(&buf,'\0');
        
@@ -711,16 +157,9 @@ ssh_server_gssapi_mechanisms() {
           return(mechs);
 }
 
-OM_uint32
-ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
-       if (*ctx) ssh_gssapi_delete_ctx(ctx);
-       ssh_gssapi_build_ctx(ctx);
-       ssh_gssapi_set_oid(*ctx,oid);
-       return(ssh_gssapi_acquire_cred(*ctx));
-}
-
+/* Unpriviledged */
 void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
-       enum ssh_gss_id i =0;
+       int i =0;
        OM_uint32 maj_status,min_status;
        int present;
        gss_OID_set supported;
@@ -728,34 +167,82 @@ void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
        gss_create_empty_oid_set(&min_status,oidset);
        PRIVSEP(gss_indicate_mechs(&min_status, &supported));
 
-       while (supported_mechs[i].name!=NULL) {
+       while (supported_mechs[i]->name!=NULL) {
                if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                      &supported_mechs[i].oid,
+                                                      &supported_mechs[i]->oid,
                                                       supported,
                                                       &present))) {
                        present=0;
                }
                if (present) {
                        gss_add_oid_set_member(&min_status,
-                                              &supported_mechs[i].oid,
+                                              &supported_mechs[i]->oid,
                                               oidset); 
                }
                i++;
        }
 }      
 
-/* Wrapper arround accept_sec_context
+/* Find out which GSS type (out of the list we define in ssh-gss.h) a
+ * particular connection is using 
+ */
+
+/* Priviledged (called ssh_gssapi_accept_ctx -> ssh_gssapi_getclient ->) */
+ssh_gssapi_mech *
+ssh_gssapi_get_ctype(Gssctxt *ctxt) {
+       int i=0;
+       
+       while(supported_mechs[i]->name!=NULL) {
+           if (supported_mechs[i]->oid.length == ctxt->oid->length &&
+               (memcmp(supported_mechs[i]->oid.elements,
+                       ctxt->oid->elements,ctxt->oid->length)==0)) {
+               return supported_mechs[i];
+           }
+           i++;
+       }
+       return NULL;
+}
+
+/* Return the OID that corresponds to the given context name */
+/* Unpriviledged */
+gss_OID 
+ssh_gssapi_server_id_kex(char *name) {
+  int i=0;
+  
+  if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
+     return(NULL);
+  }
+  
+  name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
+  
+  while (supported_mechs[i]->name!=NULL &&
+        strcmp(name,supported_mechs[i]->enc_name)!=0) {
+       i++;
+  }
+
+  if (supported_mechs[i]->name==NULL)
+     return (NULL);
+
+  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
+       KEX_GSS_SHA1, supported_mechs[i]->enc_name);
+
+  return &supported_mechs[i]->oid;
+}
+
+/* Wrapper around accept_sec_context
  * Requires that the context contains:
  *    oid              
  *    credentials      (from ssh_gssapi_acquire_cred)
  */
+/* Priviledged */
 OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
                                gss_buffer_desc *send_tok, OM_uint32 *flags) 
 {
-       OM_uint32 maj_status, min_status;
+       OM_uint32 status;
        gss_OID mech;
        
-       maj_status=gss_accept_sec_context(&min_status,
+       ctx->major=gss_accept_sec_context(&ctx->minor,
                                          &ctx->context,
                                          ctx->creds,
                                          recv_tok,
@@ -766,8 +253,8 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
                                          flags,
                                          NULL,
                                          &ctx->client_creds);
-       if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_send_error(ctx->oid,maj_status,min_status);
+       if (GSS_ERROR(ctx->major)) {
+               ssh_gssapi_error(ctx);
        }
        
        if (ctx->client_creds) {
@@ -779,7 +266,7 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
        /* FIXME: We should check that the me
         * the one that we asked for (in ctx->oid) */
 
-       ctx->status=maj_status;
+       status=ctx->major;
        
        /* Now, if we're complete and we have the right flags, then
         * we flag the user as also having been authenticated
@@ -787,49 +274,115 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
        
        if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && 
                               (*flags & GSS_C_INTEG_FLAG))) &&
-           (maj_status == GSS_S_COMPLETE)) {
-               if (ssh_gssapi_getclient(ctx,&gssapi_client_type,
-                                        &gssapi_client_name,
-                                        &gssapi_client_creds))
+           (ctx->major == GSS_S_COMPLETE)) {
+               if (ssh_gssapi_getclient(ctx,&gssapi_client.mech,
+                                        &gssapi_client.name,
+                                        &gssapi_client.creds))
                        fatal("Couldn't convert client name");
        }
 
-       return(maj_status);
+       /* Make sure that the getclient call hasn't stamped on this */
+       return(status);
+}
+
+/* Extract the client details from a given context. This can only reliably
+ * be called once for a context */
+
+/* Priviledged (called from accept_secure_ctx) */
+OM_uint32 
+ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
+                    gss_buffer_desc *name, gss_cred_id_t *creds) {
+
+       *type=ssh_gssapi_get_ctype(ctx);
+       if ((ctx->major=gss_display_name(&ctx->minor,ctx->client,name,NULL))) {
+               ssh_gssapi_error(ctx);
+               return(ctx->major);
+       }
+       
+       /* This is icky. There appears to be no way to copy this structure,
+        * rather than the pointer to it, so we simply copy the pointer and
+        * mark the originator as empty so we don't destroy it. 
+        */
+       *creds=ctx->client_creds;
+       ctx->client_creds=GSS_C_NO_CREDENTIAL;
+       return(ctx->major);
 }
 
+/* As user - called through fatal cleanup hook */
 void
-ssh_gssapi_send_error(gss_OID mech, OM_uint32 major_status,
-                     OM_uint32 minor_status) {
-       OM_uint32 lmaj, lmin;
-        gss_buffer_desc msg = {0,NULL};
-        OM_uint32 ctx;
-        
-        ctx = 0;
-       /* The GSSAPI error */
-        do {
-               lmaj = PRIVSEP(gss_display_status(&lmin, major_status,
-                                                 GSS_C_GSS_CODE,
-                                                 mech,
-                                                 &ctx, &msg));
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       packet_send_debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);         
-
-        /* The mechanism specific error */
-        do {
-               lmaj = PRIVSEP(gss_display_status(&lmin, minor_status,
-                                                 GSS_C_MECH_CODE,
-                                                 mech,
-                                                 &ctx, &msg));
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       packet_send_debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);
+ssh_gssapi_cleanup_creds(void *ignored)
+{
+       if (gssapi_client.store.filename!=NULL) {
+               /* Unlink probably isn't sufficient */
+               debug("removing gssapi cred file\"%s\"",gssapi_client.store.filename);
+               unlink(gssapi_client.store.filename);
+       }
+}
+
+/* As user */
+void 
+ssh_gssapi_storecreds()
+{
+       if (gssapi_client.mech && gssapi_client.mech->storecreds) {
+               (*gssapi_client.mech->storecreds)(&gssapi_client);
+               if (options.gss_cleanup_creds) {
+                       fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
+               }
+       } else {
+               debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+       }
 }
 
-#endif /* GSSAPI */
+/* This allows GSSAPI methods to do things to the childs environment based
+ * on the passed authentication process and credentials.
+ */
+/* As user */
+void 
+ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
+{
+
+       if (gssapi_client.store.envvar!=NULL && 
+           gssapi_client.store.envval!=NULL) {
+           
+               debug("Setting %s to %s", gssapi_client.store.envvar,
+                                         gssapi_client.store.envval);                            
+               child_set_env(envp, envsizep, gssapi_client.store.envvar, 
+                                             gssapi_client.store.envval);
+       }
+}
+
+/* Priviledged */
+int
+ssh_gssapi_userok(char *user)
+{
+       if (gssapi_client.name.length==0 || 
+           gssapi_client.name.value==NULL) {
+               debug("No suitable client data");
+               return 0;
+       }
+       if (gssapi_client.mech && gssapi_client.mech->userok) {
+               return((*gssapi_client.mech->userok)(&gssapi_client,user));
+       } else {
+               debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
+       }
+       return(0);
+}
+
+/* Priviledged */
+int
+ssh_gssapi_localname(char **user)
+{
+       *user = NULL;
+       if (gssapi_client.name.length==0 || 
+           gssapi_client.name.value==NULL) {
+               debug("No suitable client data");
+               return(0);;
+       }
+       if (gssapi_client.mech && gssapi_client.mech->localname) {
+               return((*gssapi_client.mech->localname)(&gssapi_client,user));
+       } else {
+               debug("Unknown client authentication type");
+       }
+       return(0);
+}
+#endif
index 3269d264ce0e54a0d3a500ebd92dcd9b81d6a187..612b02f04e0e204e300c47cd0bc111e3f2d5b224 100644 (file)
@@ -300,8 +300,7 @@ choose_kex(Kex *k, char *client, char *server)
        } else if (strcmp(k->name, KEX_DHGEX) == 0) {
                k->kex_type = KEX_DH_GEX_SHA1;
 #ifdef GSSAPI
-       } else if (strncmp(k->name, KEX_GSS_SHA1,
-                          sizeof(KEX_GSS_SHA1)-1) == 0) {
+       } else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
                k->kex_type = KEX_GSS_GRP1_SHA1;
 #endif
        } else
index 90a0a2de00a24edb7c87541a218dc42430ee375f..d907e5ab10f86535dcacb1df7403a3e0de27f34f 100644 (file)
@@ -114,13 +114,13 @@ struct Kex {
        Buffer  peer;
        int     done;
        int     flags;
-       char    *host;
+       char    *host;
        char    *client_version_string;
        char    *server_version_string;
+       struct  KexOptions options;
        int     (*verify_host_key)(Key *);
        Key     *(*load_host_key)(int);
        int     (*host_key_index)(Key *);
-       struct  KexOptions options;
        void    (*kex[KEX_MAX])(Kex *);
 };
 
@@ -137,11 +137,9 @@ void        kexdh_client(Kex *);
 void    kexdh_server(Kex *);
 void    kexgex_client(Kex *);
 void    kexgex_server(Kex *);
-void    kexgex_client(Kex *);
-void    kexgex_server(Kex *);
 #ifdef GSSAPI
-void    kexgss_client(Kex *);
-void    kexgss_server(Kex *);
+void     kexgss_client(Kex *);
+void     kexgss_server(Kex *);
 #endif
 
 u_char *
@@ -150,11 +148,6 @@ kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
 u_char *
 kexgex_hash(char *, char *, char *, int, char *, int, u_char *, int,
     int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *);
-u_char *
-#ifdef GSSAPI
-kex_gssapi_hash(char *, char *, char *, int, char *, int, u_char *, int,
-    BIGNUM *, BIGNUM *, BIGNUM *);
-#endif
 
 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
 void   dump_digest(char *, u_char *, int);
diff --git a/openssh/kexgss.c b/openssh/kexgss.c
deleted file mode 100644 (file)
index f2d5425..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef GSSAPI
-
-#include <openssl/crypto.h>
-#include <openssl/bn.h>
-
-#include "buffer.h"
-#include "bufaux.h"
-#include "ssh2.h"
-#include "kex.h"
-
-/* This is now the same as the DH hash ... */
-
-u_char *
-kex_gssapi_hash(
-    char *client_version_string,
-    char *server_version_string,
-    char *ckexinit, int ckexinitlen,
-    char *skexinit, int skexinitlen,
-    u_char *serverhostkeyblob, int sbloblen,
-    BIGNUM *client_dh_pub,
-    BIGNUM *server_dh_pub,
-    BIGNUM *shared_secret)
-{
-       Buffer b;
-       static u_char digest[EVP_MAX_MD_SIZE];
-       EVP_MD *evp_md = EVP_sha1();
-       EVP_MD_CTX md;
-
-       buffer_init(&b);
-       buffer_put_string(&b, client_version_string, strlen(client_version_string));
-       buffer_put_string(&b, server_version_string, strlen(server_version_string));
-
-       /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
-       buffer_put_int(&b, ckexinitlen+1);
-       buffer_put_char(&b, SSH2_MSG_KEXINIT);
-       buffer_append(&b, ckexinit, ckexinitlen);
-       buffer_put_int(&b, skexinitlen+1);
-       buffer_put_char(&b, SSH2_MSG_KEXINIT);
-       buffer_append(&b, skexinit, skexinitlen);
-
-       buffer_put_string(&b, serverhostkeyblob, sbloblen);
-       buffer_put_bignum2(&b, client_dh_pub);
-       buffer_put_bignum2(&b, server_dh_pub);
-       buffer_put_bignum2(&b, shared_secret);
-
-#ifdef DEBUG_KEX
-       buffer_dump(&b);
-#endif
-       EVP_DigestInit(&md, evp_md);
-       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
-       EVP_DigestFinal(&md, digest, NULL);
-
-       buffer_free(&b);
-
-#ifdef DEBUG_KEX
-       dump_digest("hash", digest, evp_md->md_size);
-#endif
-       return digest;
-}
-
-#endif /* GSSAPI */
index 8cf27306fdbed1bd2d02b7ca111e67eb2e2ffde7..b5afa52a76d07ca39570f8daa22938aa12aae674 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "dh.h"
 #include "ssh2.h"
 #include "ssh-gss.h"
-#include "monitor_wrap.h"
 #include "canohost.h"
 
-
 void
 kexgss_client(Kex *kex)
 {
@@ -55,13 +53,15 @@ kexgss_client(Kex *kex)
        unsigned char *kbuf;
        unsigned char *hash;
        unsigned char *serverhostkey;
+       char *msg;
+       char *lang;
        int type = 0;
        int first = 1;
-       int slen = 0;
+       int slen = 0, strlen;
        
        /* Initialise our GSSAPI world */
        ssh_gssapi_build_ctx(&ctxt);
-       if (ssh_gssapi_id_kex(ctxt,kex->name)==NULL) {
+       if (ssh_gssapi_client_id_kex(ctxt,kex->name)==NULL) {
                fatal("Couldn't identify host exchange");
        }
        if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1))) {
@@ -91,8 +91,14 @@ kexgss_client(Kex *kex)
                                               &ret_flags);
 
                if (GSS_ERROR(maj_status)) {
+                       if (send_tok.length!=0) {
+                               /* Hmmm - not sure about this */
+                               packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+                               packet_put_string(send_tok.value,
+                                                 send_tok.length);
+                       }                         
                        fatal("gss_init_context failed");
-               } 
+               }
 
                /* If we've got an old receive buffer get rid of it */
                if (token_ptr != GSS_C_NO_BUFFER)
@@ -141,20 +147,20 @@ kexgss_client(Kex *kex)
                                debug("Received GSSAPI_CONTINUE");
                                if (maj_status == GSS_S_COMPLETE) 
                                        fatal("GSSAPI Continue received from server when complete");
-                               recv_tok.value=packet_get_string(&slen);
-                               recv_tok.length=slen; /* int vs. size_t */
+                               recv_tok.value=packet_get_string(&strlen);
+                               recv_tok.length=strlen; /* int vs. size_t */
                                break;
                        case SSH2_MSG_KEXGSS_COMPLETE:
                                debug("Received GSSAPI_COMPLETE");
                                packet_get_bignum2(dh_server_pub);
-                               msg_tok.value=packet_get_string(&slen);
-                               msg_tok.length=slen; /* int vs. size_t */
+                               msg_tok.value=packet_get_string(&strlen);
+                               msg_tok.length=strlen; /* int vs. size_t */
 
                                /* Is there a token included? */
                                if (packet_get_char()) {
                                        recv_tok.value=
-                                           packet_get_string(&slen);
-                                       recv_tok.length=slen; /* int/size_t */
+                                           packet_get_string(&strlen);
+                                       recv_tok.length=strlen; /*int/size_t*/
                                        /* If we're already complete - protocol error */
                                        if (maj_status == GSS_S_COMPLETE)
                                                packet_disconnect("Protocol error: received token when complete");
@@ -164,13 +170,24 @@ kexgss_client(Kex *kex)
                                                packet_disconnect("Protocol error: did not receive final token");
                                }
                                break;
+                       case SSH2_MSG_KEXGSS_ERROR:
+                               debug("Received Error");
+                               maj_status=packet_get_int();
+                               min_status=packet_get_int();
+                               msg=packet_get_string(NULL);
+                               lang=packet_get_string(NULL);
+                               fprintf(stderr,"GSSAPI Error: \n%s",msg);
                        default:
                                packet_disconnect("Protocol error: didn't expect packet type %d",
                                type);
                        }
                        token_ptr=&recv_tok;
+               } else {
+                       /* No data, and not complete */
+                       if (maj_status!=GSS_S_COMPLETE) {
+                               fatal("Not complete, and no token output");
+                       }
                }
-
        } while (maj_status & GSS_S_CONTINUE_NEEDED);
        
        /* We _must_ have received a COMPLETE message in reply from the 
@@ -193,8 +210,8 @@ kexgss_client(Kex *kex)
         memset(kbuf, 0, klen);
         xfree(kbuf);
         
-       slen=0;
-        hash = kex_gssapi_hash(
+        /* The GSS hash is identical to the DH one */
+        hash = kex_dh_hash(
            kex->client_version_string,
             kex->server_version_string,
             buffer_ptr(&kex->my), buffer_len(&kex->my),
index ea17b2d15fbb93cb43cb8a7013d474fe69399eb8..b4e0f2cd9eee7ccb067bbcad9bea951c27f4a96d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "ssh2.h"
 #include "ssh-gss.h"
 #include "monitor_wrap.h"
-#include "canohost.h"
+
+static void kex_gss_send_error(Gssctxt *ctxt);
 
 void
 kexgss_server(Kex *kex)
 {
-
        OM_uint32 maj_status, min_status;
        
        /* Some GSSAPI implementations use the input value of ret_flags (an
@@ -62,22 +62,24 @@ kexgss_server(Kex *kex)
         BIGNUM *shared_secret = NULL;
         BIGNUM *dh_client_pub = NULL;
        int type =0;
-       gss_OID oid;
        u_int slen;
+       gss_OID oid;
        
        /* Initialise GSSAPI */
 
        debug2("%s: Identifying %s",__func__,kex->name);
-       oid=ssh_gssapi_id_kex(ctxt,kex->name);
+       oid=ssh_gssapi_server_id_kex(kex->name);
        if (oid==NULL) {
           packet_disconnect("Unknown gssapi mechanism");
        }
        
        debug2("%s: Acquiring credentials",__func__);
        
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid))))
-          packet_disconnect("Unable to acquire credentials for the server");
-
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid)))) {
+               kex_gss_send_error(ctxt);
+               packet_disconnect("Unable to acquire credentials for the server");
+        }
+                                                                                                                                
        do {
                debug("Wait SSH2_MSG_GSSAPI_INIT");
                type = packet_read();
@@ -91,14 +93,12 @@ kexgss_server(Kex *kex)
                        dh_client_pub = BN_new();
                        
                        if (dh_client_pub == NULL)
-                               fatal("dh_client_pub == NULL");
+                               packet_disconnect("dh_client_pub == NULL");
                        packet_get_bignum2(dh_client_pub);
                        
                        /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
                        break;
                case SSH2_MSG_KEXGSS_CONTINUE:
-                       if (dh_client_pub == NULL)
-                               packet_disconnect("Received KEXGSS_CONTINUE without initialising");
                        recv_tok.value=packet_get_string(&slen);
                        recv_tok.length=slen; /* int vs. size_t */
                        break;
@@ -111,12 +111,19 @@ kexgss_server(Kex *kex)
                                                         &send_tok, &ret_flags));
 
                gss_release_buffer(&min_status,&recv_tok);
-
+               
 #ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
                 if (ret_flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG) {
                         packet_disconnect("Limited proxy is not allowed in gssapi key exchange.");
                 }
 #endif
+
+               if (maj_status!=GSS_S_COMPLETE && send_tok.length==0) {
+                       fatal("Zero length token output when incomplete");
+               }
+
+               if (dh_client_pub == NULL)
+                       fatal("No client public key");
                
                if (maj_status & GSS_S_CONTINUE_NEEDED) {
                        debug("Sending GSSAPI_CONTINUE");
@@ -129,21 +136,23 @@ kexgss_server(Kex *kex)
        } while (maj_status & GSS_S_CONTINUE_NEEDED);
 
        if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
+               kex_gss_send_error(ctxt);
+               if (send_tok.length>0) {
+                       packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_send();
+                       packet_write_wait();
+               }       
                packet_disconnect("gssapi key exchange handshake failed");
        }
-
+       
        debug("gss_complete");
-       if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
-               packet_disconnect("gssapi mutual authentication failed");
-       }
+       if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+               packet_disconnect("gssapi_mutual authentication failed");
                
-       if (!(ret_flags & GSS_C_INTEG_FLAG)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
+       if (!(ret_flags & GSS_C_INTEG_FLAG))
                packet_disconnect("gssapi channel integrity not established");
-       }               
-       
+                       
        dh = dh_new_group1();
        dh_gen_key(dh, kex->we_need * 8);
        
@@ -159,7 +168,8 @@ kexgss_server(Kex *kex)
        memset(kbuf, 0, klen);
        xfree(kbuf);
        
-        hash = kex_gssapi_hash(
+       /* The GSSAPI hash is identical to the Diffie Helman one */
+        hash = kex_dh_hash(
             kex->client_version_string,
             kex->server_version_string,
             buffer_ptr(&kex->peer), buffer_len(&kex->peer),
@@ -181,12 +191,8 @@ kexgss_server(Kex *kex)
        gssbuf.length = 20; /* Hashlen appears to always be 20 */
        
        if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
-               if (ctxt) { /* may be NULL under privsep */
-                   ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
-               } else {
-                   ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
-               }
-               packet_disconnect("Couldn't get MIC");
+               kex_gss_send_error(ctxt);
+               fatal("Couldn't get MIC");
        }
        
        packet_start(SSH2_MSG_KEXGSS_COMPLETE);
@@ -220,4 +226,22 @@ kexgss_server(Kex *kex)
        kex_finish(kex);
 }
 
+static void 
+kex_gss_send_error(Gssctxt *ctxt) {
+       char *errstr;
+       OM_uint32 maj,min;
+               
+       errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+       if (errstr) {
+               packet_start(SSH2_MSG_KEXGSS_ERROR);
+               packet_put_int(maj);
+               packet_put_int(min);
+               packet_put_cstring(errstr);
+               packet_put_cstring("");
+               packet_send();
+               packet_write_wait();
+               /* XXX - We should probably log the error locally here */
+               xfree(errstr);
+       }
+}
 #endif /* GSSAPI */
diff --git a/openssh/makegssname.pl b/openssh/makegssname.pl
new file mode 100644 (file)
index 0000000..1350cdd
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+use Convert::ASN1 qw(:tag);
+use Digest::MD5 qw(md5);
+use MIME::Base64;
+use Data::Dumper;
+$oid=shift;
+my $asn=Convert::ASN1->new;
+$asn->prepare("oid OBJECT IDENTIFIER");
+$encoded=$asn->encode(oid => $oid);
+Convert::ASN1::asn_dump($encoded);
+print Dumper($asn->decode($encoded));
+
+@entries=unpack("C*",$encoded);
+
+print "DER representation: ";
+foreach $entry (@entries) {
+  print "\\x";
+  printf "%02X",$entry;
+}
+print "\n";
+
+$digest = md5($encoded);
+# We only want the first 10 characters;
+# Conversations with the authors suggest that we want to use all of the
+# characters of the digest.
+#$digest = substr($digest,0,10);
+print "gsskeyex representation: ",encode_base64($digest),"\n";
+
+sub encode_object_id {
+  $string="";
+
+  my @data = ($_[0] =~ /(\d+)/g);
+
+  if(@data < 2) {
+      @data = (0);
+  }
+  else {
+      my $first = $data[1] + ($data[0] * 40);
+      splice(@data,0,2,$first);
+  }
+
+#  my $l = length $string;
+  $string .= pack("cw*", 0, @data);
+#  substr($string,$l,1) = asn_encode_length(length($string) - $l - 1);
+  return $string;
+}
+
+
index 512fb22fbe5abda6e86bddb280a3f96fc92fa25e..eac6ccd5802fc95e318a54f8e7abd6ed5f6c2f02 100644 (file)
@@ -113,11 +113,14 @@ set_nodelay(int fd)
 /* Characters considered whitespace in strsep calls. */
 #define WHITESPACE " \t\r\n"
 
+/* Characters considered as quotations. */
+#define QUOTES "'\""
+
 /* return next token in configuration line */
 char *
 strdelim(char **s)
 {
-       char *old;
+       char *old, *p, *q;
        int wspace = 0;
 
        if (*s == NULL)
@@ -125,7 +128,22 @@ strdelim(char **s)
 
        old = *s;
 
-       *s = strpbrk(*s, WHITESPACE "=");
+        if ((q=strchr(QUOTES, (int) *old)) && *q)
+        {
+            /* find next quote character, point old to start of quoted
+             * string */
+            for (p = ++old;*p && *p!=*q; p++)
+                 ;
+            
+            /* find start of next token */
+            *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
+            
+            /* terminate 'old' token */
+            *p = '\0';
+            return (old);
+        }
+
+        *s = strpbrk(*s, WHITESPACE "=");
        if (*s == NULL)
                return (old);
 
index 65acd443407cb8cbb61cb7bd4b864e6ff5cf2dea..6e8d03db07b930bbe53c252b49d63758ca5c6552 100644 (file)
@@ -125,27 +125,27 @@ int mm_answer_sessid(int, Buffer *);
 int mm_answer_pam_start(int, Buffer *);
 #endif
 
+#ifdef KRB4
+int mm_answer_krb4(int, Buffer *);
+#endif
+#ifdef KRB5
+int mm_answer_krb5(int, Buffer *);
+#endif
+
 #ifdef GSSAPI
 int mm_answer_gss_setup_ctx(int, Buffer *);
 int mm_answer_gss_accept_ctx(int, Buffer *);
 int mm_answer_gss_userok(int, Buffer *);
-int mm_answer_gss_localname(int, Buffer *);
 int mm_answer_gss_sign(int, Buffer *);
+int mm_answer_gss_error(int, Buffer *);
 int mm_answer_gss_indicate_mechs(int, Buffer *);
-int mm_answer_gss_display_status(int, Buffer *);
+int mm_answer_gss_localname(int, Buffer *);
 #endif
 
 #ifdef GSI
 int mm_answer_gsi_gridmap(int, Buffer *);
 #endif
 
-#ifdef KRB4
-int mm_answer_krb4(int, Buffer *);
-#endif
-#ifdef KRB5
-int mm_answer_krb5(int, Buffer *);
-#endif
-
 static Authctxt *authctxt;
 static BIGNUM *ssh1_challenge = NULL;  /* used for ssh1 rsa auth */
 
@@ -195,10 +195,10 @@ struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
     {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
-    {MONITOR_REQ_GSSLOCALNAME, MON_AUTH, mm_answer_gss_localname},
+    {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
 #endif
     {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
     {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
@@ -210,8 +210,8 @@ struct mon_table mon_dispatch_postauth20[] = {
     {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
     {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
 #endif
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
@@ -244,7 +244,6 @@ struct mon_table mon_dispatch_proto15[] = {
     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
     {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
 #endif
 #ifdef GSI
     {MONITOR_REQ_GSIGRIDMAP, MON_PERMIT, mm_answer_gsi_gridmap},
@@ -267,7 +266,6 @@ struct mon_table mon_dispatch_postauth15[] = {
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
     {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
 #endif
     {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
@@ -323,19 +321,16 @@ monitor_child_preauth(struct monitor *pmonitor)
 #ifdef GSSAPI          
                /* and for the GSSAPI key exchange */
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
 #endif
        } else {
                mon_dispatch = mon_dispatch_proto15;
 
                monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
 #ifdef GSSAPI          
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
 #endif
 #ifdef GSI
                monitor_permit(mon_dispatch, MONITOR_REQ_GSIGRIDMAP, 1);
@@ -390,12 +385,19 @@ monitor_child_postauth(struct monitor *pmonitor)
                monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
 
+#ifdef GSSAPI
+               /* and for the GSSAPI key exchange */
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
+#endif
+
        } else {
                mon_dispatch = mon_dispatch_postauth15;
                monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
        }
 #ifdef GSSAPI          
-       monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+       monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
 #endif
        if (!no_pty_flag) {
                monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
@@ -1538,6 +1540,9 @@ mm_get_kex(Buffer *m)
        kex->we_need = buffer_get_int(m);
        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+#ifdef GSSAPI
+       kex->kex[KEX_GSS_GRP1_SHA1] =kexgss_server;
+#endif
        kex->server = 1;
        kex->hostkey_type = buffer_get_int(m);
        kex->kex_type = buffer_get_int(m);
@@ -1739,6 +1744,9 @@ mm_answer_gss_setup_ctx(int socket, Buffer *m) {
 
         mm_request_send(socket,MONITOR_ANS_GSSSETUP,m);
 
+       /* Now we have a context, enable the step and sign */
+       monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,1);
+
         return(0);
 }
 
@@ -1760,8 +1768,14 @@ mm_answer_gss_accept_ctx(int socket, Buffer *m) {
 
         gss_release_buffer(&minor, &out);
 
+       /* Complete - now we can do signing */
+       if (major==GSS_S_COMPLETE) {
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,0);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN,1);            
+       }
         return(0);
 }
+
 int
 mm_answer_gss_userok(int socket, Buffer *m) {
        int authenticated;
@@ -1774,31 +1788,12 @@ mm_answer_gss_userok(int socket, Buffer *m) {
         debug3("%s: sending result %d", __func__, authenticated);
         mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m);
 
+       /* XXX - auth method could also be 'external' */
        auth_method="gssapi";
        
         /* Monitor loop will terminate if authenticated */
         return(authenticated);
 }
-int
-mm_answer_gss_localname(int socket, Buffer *m) {
-       char *name;
-
-       ssh_gssapi_localname(&name);
-
-        buffer_clear(m);
-       if (name) {
-           buffer_put_cstring(m, name);
-           debug3("%s: sending result %s", __func__, name);
-           xfree(name);
-       } else {
-           buffer_put_cstring(m, "");
-           debug3("%s: sending result \"\"", __func__);
-       }
-
-        mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
-
-        return(0);
-}
 
 int
 mm_answer_gss_sign(int socket, Buffer *m) {
@@ -1835,6 +1830,24 @@ mm_answer_gss_sign(int socket, Buffer *m) {
         return(0);
 }
 
+int
+mm_answer_gss_error(int socket, Buffer *m) {
+        OM_uint32 major,minor;
+        char *msg;
+
+       msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
+       buffer_clear(m);
+       buffer_put_int(m,major);
+       buffer_put_int(m,minor);
+       buffer_put_cstring(m,msg);
+
+       mm_request_send(socket,MONITOR_ANS_GSSERR,m);
+
+       xfree(msg);
+       
+        return(0);
+}
+
 int
 mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
         OM_uint32 major,minor;
@@ -1851,49 +1864,35 @@ mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
                              mech_set->elements[i].length);
        }
 
+#if !defined(MECHGLUE) /* mechglue memory management bug ??? */
+       gss_release_oid_set(&minor,&mech_set);
+#endif
+       
        mm_request_send(socket,MONITOR_ANS_GSSMECHS,m);
 
        return(0);
 }
 
 int
-mm_answer_gss_display_status(int socket, Buffer *m) {
-        OM_uint32 major,minor,status_value,message_context;
-       int status_type;
-       gss_OID_desc mech_type_desc;
-       gss_OID mech_type;
-       gss_buffer_desc status_string;
-       u_int length;
-
-       status_value = buffer_get_int(m);
-       status_type = buffer_get_int(m);
-       mech_type_desc.elements = buffer_get_string(m, &length);
-       mech_type_desc.length = length;
-       if (length != 0) {
-           mech_type = &mech_type_desc;
-       } else if (gsscontext) {
-           mech_type = gsscontext->oid;
-       } else {
-           mech_type = GSS_C_NO_OID;
-       }
-       message_context = buffer_get_int(m);
-
-       major=gss_display_status(&minor, status_value, status_type, mech_type,
-                                &message_context, &status_string);
-
-       buffer_clear(m);
-       buffer_put_int(m, message_context);
-       buffer_put_string(m, status_string.value, status_string.length);
+mm_answer_gss_localname(int socket, Buffer *m) {
+       char *name;
 
-       mm_request_send(socket,MONITOR_ANS_GSSSTAT,m);
+       ssh_gssapi_localname(&name);
 
-       if (mech_type_desc.elements) {
-           xfree(mech_type_desc.elements);
+        buffer_clear(m);
+       if (name) {
+           buffer_put_cstring(m, name);
+           debug3("%s: sending result %s", __func__, name);
+           xfree(name);
+       } else {
+           buffer_put_cstring(m, "");
+           debug3("%s: sending result \"\"", __func__);
        }
 
-       return 0;
-}
+        mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
 
+        return(0);
+}
 #endif /* GSSAPI */
 
 #ifdef GSI
index 80261a543b0ea3764f2527c1c9c119074b4c293e..06ade4f269bf58ba39ce62fb1c4a46edfd4a88bc 100644 (file)
@@ -39,14 +39,16 @@ enum monitor_reqtype {
        MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
        MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
        MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+#ifdef GSSAPI
        MONITOR_REQ_GSSSETUP,MONITOR_ANS_GSSSETUP,
        MONITOR_REQ_GSSSTEP,MONITOR_ANS_GSSSTEP,
        MONITOR_REQ_GSSSIGN,MONITOR_ANS_GSSSIGN,
-       MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS,
-       MONITOR_REQ_GSSSTAT,MONITOR_ANS_GSSSTAT,
        MONITOR_REQ_GSSUSEROK,MONITOR_ANS_GSSUSEROK,
+       MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS,
        MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME,
        MONITOR_REQ_GSIGRIDMAP,MONITOR_ANS_GSIGRIDMAP,
+       MONITOR_REQ_GSSERR,MONITOR_ANS_GSSERR,
+#endif
        MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
        MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
        MONITOR_REQ_KEYEXPORT,
index 8637e4c4c92fa6f6b7b33878eeb51dea5debf325..b68003287135e495c0ee2f501e18f3de11611f59 100644 (file)
@@ -952,6 +952,77 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
 
        return (success);
 }
+
+#ifdef KRB4
+int
+mm_auth_krb4(Authctxt *authctxt, void *_auth, char **client, void *_reply)
+{
+       KTEXT auth, reply;
+       Buffer m;
+       u_int rlen;
+       int success = 0;
+       char *p;
+
+       debug3("%s entering", __func__);
+       auth = _auth;
+       reply = _reply;
+
+       buffer_init(&m);
+       buffer_put_string(&m, auth->dat, auth->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB4, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB4, &m);
+
+       success = buffer_get_int(&m);
+       if (success) {
+               *client = buffer_get_string(&m, NULL);
+               p = buffer_get_string(&m, &rlen);
+               if (rlen >= MAX_KTXT_LEN)
+                       fatal("%s: reply from monitor too large", __func__);
+               reply->length = rlen;
+               memcpy(reply->dat, p, rlen);
+               memset(p, 0, rlen);
+               xfree(p);
+       }
+       buffer_free(&m);
+       return (success);
+}
+#endif
+
+#ifdef KRB5
+int
+mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
+{
+       krb5_data *tkt, *reply;
+       Buffer m;
+       int success;
+
+       debug3("%s entering", __func__);
+       tkt = (krb5_data *) argp;
+       reply = (krb5_data *) resp;
+
+       buffer_init(&m);
+       buffer_put_string(&m, tkt->data, tkt->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB5, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB5, &m);
+
+       success = buffer_get_int(&m);
+       if (success) {
+               u_int len;
+
+               *userp = buffer_get_string(&m, NULL);
+               reply->data = buffer_get_string(&m, &len);
+               reply->length = len;
+       } else {
+               memset(reply, 0, sizeof(*reply));
+               *userp = NULL;
+       }
+
+       buffer_free(&m);
+       return (success);
+}
+#endif
 #ifdef GSSAPI
 OM_uint32
 mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
@@ -965,32 +1036,33 @@ mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
         buffer_put_string(&m,oid->elements,oid->length);
 
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSSETUP",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
+
         major=buffer_get_int(&m);
 
+       buffer_free(&m);
         return(major);
 }
 
 OM_uint32
 mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
                          gss_buffer_desc *out, OM_uint32 *flags) {
-
         Buffer m;
         OM_uint32 major;
 
         buffer_init(&m);
         buffer_put_string(&m, in->value, in->length);
-        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSSTEP", __func__);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
 
         major=buffer_get_int(&m);
         out->value=buffer_get_string(&m,&out->length);
         if (flags) *flags=buffer_get_int(&m);
 
+       buffer_free(&m);
+       
         return(major);
 }
 
@@ -1002,7 +1074,6 @@ mm_ssh_gssapi_userok(char *user) {
         buffer_init(&m);
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSUSEROK", __func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
                                   &m);
 
@@ -1013,30 +1084,6 @@ mm_ssh_gssapi_userok(char *user) {
         return(authenticated);
 }
 
-int
-mm_ssh_gssapi_localname(char **lname)
-{
-        Buffer m;
-
-       buffer_init(&m);
-        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
-        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
-                                  &m);
-
-       *lname = buffer_get_string(&m, NULL);
-
-        buffer_free(&m);
-       if (lname[0] == '\0') {
-           debug3("%s: gssapi identity mapping failed", __func__);
-       } else {
-           debug3("%s: gssapi identity mapped to %s", __func__, *lname);
-       }
-       
-        return(0);
-}
-
 OM_uint32
 mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
         Buffer m;
@@ -1046,80 +1093,91 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
         buffer_put_string(&m, data->value, data->length);
 
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSSIGN",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+
         major=buffer_get_int(&m);
         hash->value = buffer_get_string(&m, &hash->length);
 
+       buffer_free(&m);
+       
         return(major);
 }
 
+char *
+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
+       Buffer m;
+       OM_uint32 maj,min;
+       char *errstr;
+       
+       buffer_init(&m);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
+
+       maj = buffer_get_int(&m);
+       min = buffer_get_int(&m);
+
+       if (major) *major=maj;
+       if (minor) *minor=min;
+       
+       errstr=buffer_get_string(&m,NULL);
+
+       buffer_free(&m);
+       
+       return(errstr);
+}      
+
 OM_uint32
 mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
 {
         Buffer m;
-       OM_uint32 major;
-       int i=0;
-
+       OM_uint32 major,minor;
+       int count;
+       gss_OID_desc oid;
        buffer_init(&m);
 
        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
                                  &m);
         major=buffer_get_int(&m);
-       *mech_set = xmalloc(sizeof(gss_OID_set_desc));
-        (*mech_set)->count=buffer_get_int(&m);
-       (*mech_set)->elements=xmalloc(sizeof(gss_OID_desc)*(*mech_set)->count);
-       for (i=0; i < (*mech_set)->count; i++) {
+       count=buffer_get_int(&m);
+       
+        gss_create_empty_oid_set(&minor,mech_set);
+       while(count-->0) {
            u_int length;
-           (*mech_set)->elements[i].elements=buffer_get_string(&m, &length);
-           (*mech_set)->elements[i].length = length;
+           oid.elements=buffer_get_string(&m,&length);
+           oid.length=length;
+           gss_add_oid_set_member(&minor,&oid,mech_set);
        }
 
+       buffer_free(&m);
+       
         return(major);
 }
 
-OM_uint32
-mm_gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value,
-                     int status_type, const gss_OID mech_type,
-                     OM_uint32 *message_context, gss_buffer_t status_string)
+int
+mm_ssh_gssapi_localname(char **lname)
 {
         Buffer m;
-       OM_uint32 major;
 
        buffer_init(&m);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
 
-       buffer_put_int(&m, status_value);
-       buffer_put_int(&m, status_type);
-       if (mech_type) {
-           buffer_put_string(&m, mech_type->elements, mech_type->length);
-       } else {
-           buffer_put_string(&m, "", 0);
-       }
-       if (message_context) {
-           buffer_put_int(&m, *message_context);
-       } else {
-           buffer_put_int(&m, 0);
-       }
+        debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
+                                  &m);
 
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTAT, &m);
+       *lname = buffer_get_string(&m, NULL);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
-        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTAT,
-                                 &m);
-       
-       if (message_context) {
-           *message_context = buffer_get_int(&m);
+        buffer_free(&m);
+       if (lname[0] == '\0') {
+           debug3("%s: gssapi identity mapping failed", __func__);
        } else {
-           buffer_get_int(&m);
+           debug3("%s: gssapi identity mapped to %s", __func__, *lname);
        }
-       status_string->value = buffer_get_string(&m, &status_string->length);
-
-       return major;
-}
+       
+        return(0);
+}      
 #endif /* GSSAPI */
 
 #ifdef GSI
@@ -1132,7 +1190,6 @@ int mm_gsi_gridmap(char *subject_name, char **lname)
        buffer_put_cstring(&m, subject_name);
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSIGRIDMAP, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSIGRIDMAP", __func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSIGRIDMAP,
                                   &m);
 
@@ -1152,74 +1209,3 @@ int mm_gsi_gridmap(char *subject_name, char **lname)
 }
 
 #endif /* GSI */
-
-#ifdef KRB4
-int
-mm_auth_krb4(Authctxt *authctxt, void *_auth, char **client, void *_reply)
-{
-       KTEXT auth, reply;
-       Buffer m;
-       u_int rlen;
-       int success = 0;
-       char *p;
-
-       debug3("%s entering", __func__);
-       auth = _auth;
-       reply = _reply;
-
-       buffer_init(&m);
-       buffer_put_string(&m, auth->dat, auth->length);
-
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB4, &m);
-       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB4, &m);
-
-       success = buffer_get_int(&m);
-       if (success) {
-               *client = buffer_get_string(&m, NULL);
-               p = buffer_get_string(&m, &rlen);
-               if (rlen >= MAX_KTXT_LEN)
-                       fatal("%s: reply from monitor too large", __func__);
-               reply->length = rlen;
-               memcpy(reply->dat, p, rlen);
-               memset(p, 0, rlen);
-               xfree(p);
-       }
-       buffer_free(&m);
-       return (success);
-}
-#endif
-
-#ifdef KRB5
-int
-mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
-{
-       krb5_data *tkt, *reply;
-       Buffer m;
-       int success;
-
-       debug3("%s entering", __func__);
-       tkt = (krb5_data *) argp;
-       reply = (krb5_data *) resp;
-
-       buffer_init(&m);
-       buffer_put_string(&m, tkt->data, tkt->length);
-
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB5, &m);
-       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB5, &m);
-
-       success = buffer_get_int(&m);
-       if (success) {
-               u_int len;
-
-               *userp = buffer_get_string(&m, NULL);
-               reply->data = buffer_get_string(&m, &len);
-               reply->length = len;
-       } else {
-               memset(reply, 0, sizeof(*reply));
-               *userp = NULL;
-       }
-
-       buffer_free(&m);
-       return (success);
-}
-#endif
index 09766e73210d3cb22719815d7536a3b9fbb0acd5..91e94d3549081a265274f86b1885f915f0eeed62 100644 (file)
@@ -70,11 +70,8 @@ int mm_ssh_gssapi_userok(char *user);
 int mm_ssh_gssapi_localname(char **user);
 OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
                                gss_OID_set *mech_set);
-OM_uint32 mm_gss_display_status(OM_uint32 *minor_status,
-                               OM_uint32 status_value,
-                               int status_type, const gss_OID mech_type,
-                               OM_uint32 *message_context,
-                               gss_buffer_t status_string);
+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+
 #endif
 
 #ifdef GSI
index 7aa0c73e9c45bb88260c9252c0843f182d0948a9..12b7b835d63d96cc84027599be5e5e61c931745c 100644 (file)
@@ -101,6 +101,11 @@ initialize_server_options(ServerOptions *options)
 #endif
 #ifdef AFS
        options->afs_token_passing = -1;
+#endif
+#ifdef  SESSION_HOOKS
+        options->session_hooks_allow = -1;
+        options->session_hooks_startup_cmd = NULL;
+        options->session_hooks_shutdown_cmd = NULL;
 #endif
        options->password_authentication = -1;
        options->kbd_interactive_authentication = -1;
@@ -230,6 +235,14 @@ fill_default_server_options(ServerOptions *options)
 #ifdef AFS
        if (options->afs_token_passing == -1)
                options->afs_token_passing = 0;
+#endif
+#ifdef SESSION_HOOKS
+        if (options->session_hooks_allow == -1)
+        {
+            options->session_hooks_allow = 0;
+            options->session_hooks_startup_cmd = NULL;
+            options->session_hooks_shutdown_cmd = NULL;
+        }
 #endif
        if (options->password_authentication == -1)
                options->password_authentication = 1;
@@ -306,6 +319,9 @@ typedef enum {
 #endif
 #ifdef AFS
        sAFSTokenPassing,
+#endif
+#ifdef SESSION_HOOKS
+        sAllowSessionHooks, sSessionHookStartupCmd, sSessionHookShutdownCmd,
 #endif
        sChallengeResponseAuthentication,
        sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
@@ -366,6 +382,11 @@ static struct {
 #ifdef AFS
        { "afstokenpassing", sAFSTokenPassing },
 #endif
+#ifdef SESSION_HOOKS
+        { "allowsessionhooks", sAllowSessionHooks },
+        { "sessionhookstartupcmd", sSessionHookStartupCmd },
+        { "sessionhookshutdowncmd", sSessionHookShutdownCmd },
+#endif        
        { "passwordauthentication", sPasswordAuthentication },
        { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
        { "challengeresponseauthentication", sChallengeResponseAuthentication },
@@ -707,7 +728,22 @@ parse_flag:
                intptr = &options->afs_token_passing;
                goto parse_flag;
 #endif
-
+#ifdef SESSION_HOOKS
+        case sAllowSessionHooks:
+                intptr = &options->session_hooks_allow;
+                goto parse_flag;
+        case sSessionHookStartupCmd:
+        case sSessionHookShutdownCmd:
+                arg = strdelim(&cp);
+                if (!arg || *arg == '\0')
+                    fatal("%s line %d: empty session hook command",
+                          filename, linenum);
+                if (opcode==sSessionHookStartupCmd)
+                    options->session_hooks_startup_cmd = strdup(arg);
+                else
+                    options->session_hooks_shutdown_cmd = strdup(arg);
+                break;
+#endif                  
        case sPasswordAuthentication:
                intptr = &options->password_authentication;
                goto parse_flag;
index 1c947da6ce03b1794bc5cd83572b62b6e4015d27..98cdda4c7a12db815f5693473ac7bf4fdc8ba2d7 100644 (file)
@@ -97,6 +97,11 @@ typedef struct {
 #endif
 #ifdef AFS
        int     afs_token_passing;      /* If true, permit AFS token passing. */
+#endif
+#ifdef SESSION_HOOKS
+        int     session_hooks_allow;        /* If true, permit user hooks */
+        char*   session_hooks_startup_cmd;  /* cmd to be executed before */
+        char*   session_hooks_shutdown_cmd; /* cmd to be executed after */
 #endif
        int     password_authentication;        /* If true, permit password
                                                 * authentication. */
index 323d096adcd7d458ca58639f49241014c422dffd..a2b039fa21f9d54b683b1f222d5bb2d30144c161 100644 (file)
@@ -91,6 +91,11 @@ static void do_authenticated2(Authctxt *);
 
 static int session_pty_req(Session *);
 
+#ifdef SESSION_HOOKS
+static void execute_session_hook(char* prog, Authctxt *authctxt,
+                                 int startup, int save);
+#endif
+
 /* import */
 extern ServerOptions options;
 extern char *__progname;
@@ -229,6 +234,21 @@ do_authenticated(Authctxt *authctxt)
        /* remove agent socket */
        if (auth_sock_name != NULL)
                auth_sock_cleanup_proc(authctxt->pw);
+
+#ifdef SESSION_HOOKS
+        if (options.session_hooks_allow &&
+            options.session_hooks_shutdown_cmd)
+        {
+            execute_session_hook(options.session_hooks_shutdown_cmd,
+                                 authctxt,
+                                 /* startup = */ 0, /* save = */ 0);
+
+            if (authctxt->session_env_file)
+            {
+                free(authctxt->session_env_file);
+            }
+        }
+#endif
 #ifdef KRB4
        if (options.kerberos_ticket_cleanup)
                krb4_cleanup_proc(authctxt);
@@ -718,6 +738,25 @@ do_pre_login(Session *s)
 void
 do_exec(Session *s, const char *command)
 {
+#if defined(SESSION_HOOKS)
+    if (options.session_hooks_allow &&
+        (options.session_hooks_startup_cmd ||
+         options.session_hooks_shutdown_cmd))
+    {
+        char env_file[1000];
+        struct stat st;
+        do
+        {
+            snprintf(env_file,
+                     sizeof(env_file),
+                     "/tmp/ssh_env_%d%d%d",
+                     getuid(),
+                     getpid(),
+                     rand());
+        } while (stat(env_file, &st)==0);
+        s->authctxt->session_env_file = strdup(env_file);
+    }
+#endif
        if (forced_command) {
                original_command = command;
                command = forced_command;
@@ -939,6 +978,117 @@ read_environment_file(char ***env, u_int *envsize,
        fclose(f);
 }
 
+#ifdef SESSION_HOOKS
+#define SSH_SESSION_ENV_FILE "SSH_SESSION_ENV_FILE"
+
+typedef enum { no_op, execute, clear_env, restore_env,
+               read_env, save_or_rm_env } session_action_t;
+
+static session_action_t action_order[2][5] = {
+    { clear_env, read_env, execute, save_or_rm_env, restore_env }, /*shutdown*/
+    { execute, read_env, save_or_rm_env, no_op, no_op }            /*startup */
+};
+
+static
+void execute_session_hook(char* prog, Authctxt *authctxt,
+                          int startup, int save)
+{
+    extern char **environ;
+
+    struct stat  st;
+    char         **saved_env, **tmpenv;
+    char         *env_file = authctxt->session_env_file;
+    int          i, status = 0;
+
+    for (i=0; i<5; i++)
+    {
+        switch (action_order[startup][i])
+        {
+          case no_op:
+            break;
+
+          case execute:
+            {
+                FILE* fp;
+                char  buf[1000];
+
+                snprintf(buf,
+                         sizeof(buf),
+                         "%s -c '%s'",
+                         authctxt->pw->pw_shell,
+                         prog);
+
+                debug("executing session hook: [%s]", buf);
+                setenv(SSH_SESSION_ENV_FILE, env_file, /* overwrite = */ 1);
+
+                /* flusing is recommended in the popen(3) man page, to avoid
+                   intermingling of output */
+                fflush(stdout);
+                fflush(stderr);
+                if ((fp=popen(buf, "w")) == NULL)
+                {
+                    perror("Unable to run session hook");
+                    return;
+                }
+                status = pclose(fp);
+                debug2("session hook executed, status=%d", status);
+                unsetenv(SSH_SESSION_ENV_FILE);
+            }
+            break;
+
+          case clear_env:
+            saved_env = environ;
+            tmpenv = (char**) malloc(sizeof(char*));
+            tmpenv[0] = NULL;
+            environ = tmpenv;
+            break;
+
+          case restore_env:
+            environ = saved_env;
+            free(tmpenv);
+            break;
+
+          case read_env:
+            if (status==0 && stat(env_file, &st)==0)
+            {
+                int envsize = 0;
+
+                debug("reading environment from %s", env_file);
+                while (environ[envsize++]) ;
+                read_environment_file(&environ, &envsize, env_file);
+            }
+            break;
+
+          case save_or_rm_env:
+            if (status==0 && save)
+            {
+                FILE* fp;
+                int    envcount=0;
+
+                debug2("saving environment to %s", env_file);
+                if ((fp = fopen(env_file, "w")) == NULL) /* hmm: file perms? */
+                {
+                    perror("Unable to save session hook info");
+                }
+                while (environ[envcount])
+                {
+                    fprintf(fp, "%s\n", environ[envcount++]);
+                }
+                fflush(fp);
+                fclose(fp);
+            }
+            else if (stat(env_file, &st)==0)
+            {
+                debug2("removing environment file %s", env_file);
+                remove(env_file);
+            }
+            break;
+        }
+    }
+
+}
+#endif
+
 void copy_environment(char **source, char ***env, u_int *envsize)
 {
        char *var_name, *var_val;
@@ -1458,6 +1608,16 @@ do_child(Session *s, const char *command)
        }
 #endif /* AFS_KRB5 */
 
+#ifdef SESSION_HOOKS
+        if (options.session_hooks_allow &&
+            options.session_hooks_startup_cmd)
+        {
+            execute_session_hook(options.session_hooks_startup_cmd,
+                                 s->authctxt,
+                                 /* startup = */ 1,
+                                 options.session_hooks_shutdown_cmd != NULL);
+        }
+#endif
 #ifdef AFS
        /* Try to get AFS tokens for the local cell. */
        if (k_hasafs()) {
index 3f5f028ecd11aa2bd7c3cac3fdd618653f537665..5dbf7f1eba68ac163627d4c658a6cb1a383d3b5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN                 61
 #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE     63    
 #define SSH2_MSG_USERAUTH_GSSAPI_ERROR                 64  
+#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK                        65
 
 #define KEX_GSS_SHA1                                   "gss-group1-sha1-"
 
-enum ssh_gss_id {
-#ifdef KRB5
-       GSS_KERBEROS,
-#endif
-#ifdef GSI
-       GSS_GSI,
-#endif /* GSI */
-       GSS_LAST_ENTRY
-};
+typedef struct {
+        char *filename;
+        char *envvar;
+        char *envval;
+        void *data;
+} ssh_gssapi_ccache;
 
-typedef struct ssh_gss_mech_struct {
+typedef struct {
+       gss_buffer_desc name;
+       gss_cred_id_t   creds;
+       struct ssh_gssapi_mech_struct *mech;
+       ssh_gssapi_ccache store;
+} ssh_gssapi_client;
+
+typedef struct ssh_gssapi_mech_struct {
         char *enc_name;
         char *name;
         gss_OID_desc oid;
+       int (*dochild) (ssh_gssapi_client *);
+       int (*userok) (ssh_gssapi_client *, char *);
+       int (*localname) (ssh_gssapi_client *, char **);
+       void (*storecreds) (ssh_gssapi_client *);
 } ssh_gssapi_mech;
 
+
+
 typedef struct {
-       OM_uint32       status; /* both */
+       OM_uint32       major; /* both */
+       OM_uint32       minor; /* both */
        gss_ctx_id_t    context; /* both */
        gss_name_t      name; /* both */
        gss_OID         oid; /* both */
@@ -85,19 +97,16 @@ typedef struct {
        gss_cred_id_t   client_creds; /* server */
 } Gssctxt;
 
-extern ssh_gssapi_mech supported_mechs[];
-extern char gssprefix[];
-extern gss_buffer_desc gssapi_client_name;
-extern gss_cred_id_t   gssapi_client_creds;
-extern enum ssh_gss_id gssapi_client_type;
+extern ssh_gssapi_mech *supported_mechs[];
 
 char *ssh_gssapi_mechanisms(char *host);
-char *ssh_server_gssapi_mechanisms();
-gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
+char *ssh_gssapi_client_mechanisms(char *host);
+gss_OID ssh_gssapi_client_id_kex(Gssctxt *ctx, char *name);
+int  ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len);
 void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
 void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
 void ssh_gssapi_supported_oids(gss_OID_set *oidset);
-enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt);
+ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *ctxt);
 
 OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host);
 OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx);
@@ -109,21 +118,21 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,
                                gss_buffer_desc *send_tok,
                                OM_uint32 *flags);
 OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx,
-                               enum ssh_gss_id *type,
+                               ssh_gssapi_mech **mech,
                                gss_buffer_desc *name,
                                gss_cred_id_t *creds);
-void ssh_gssapi_error(gss_OID mech,
-                     OM_uint32 major_status, OM_uint32 minor_status);
-void ssh_gssapi_send_error(gss_OID mech,
-                          OM_uint32 major_status,OM_uint32 minor_status);
+void ssh_gssapi_error(Gssctxt *ctx);
+char *ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
 void ssh_gssapi_build_ctx(Gssctxt **ctx);
 void ssh_gssapi_delete_ctx(Gssctxt **ctx);
-OM_uint32 ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid,char *host);
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid);
 
+int ssh_gssapi_check_mechanism(gss_OID oid, char *host);
+
 /* In the server */
+gss_OID ssh_gssapi_server_id_kex(char *name);
 int ssh_gssapi_userok(char *name);
-int ssh_gssapi_localname(char **lname);
+int ssh_gssapi_localname(char **name);
 void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit, 
                       Buffer *server_kexinit);
 
@@ -133,7 +142,7 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer,
 void ssh_gssapi_do_child(char ***envp, u_int *envsizep);                 
 void ssh_gssapi_cleanup_creds(void *ignored);
 void ssh_gssapi_storecreds();
-void ssh_gssapi_clean_env();
+char *ssh_gssapi_server_mechanisms();
 
 #ifdef GSI
 int gsi_gridmap(char *subject_name, char **mapped_name);
index 9bc66c2af7fdc132bcaf9d08203a2d5252ae138e..e2a7b730e55ac7b67cdf5fd205334e217dfae2da 100644 (file)
@@ -357,9 +357,6 @@ keygrab_ssh2(con *c)
        c->c_kex = kex_setup(myproposal);
        c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
        c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
-#ifdef GSSAPI
-       c->c_kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
-#endif
        c->c_kex->verify_host_key = hostjump;
 
        if (!(j = setjmp(kexjmp))) {
index 37b4c70b444858301854934e514a55a2334473a9..9838cc3b0d42ec2cb723c871081ed5fe02c0e2e8 100644 (file)
@@ -960,67 +960,68 @@ try_password_authentication(char *prompt)
 
 #ifdef GSSAPI
 #ifdef GSI
+static gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"};
 char * get_gsi_name()
 {
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
   gss_name_t pname = GSS_C_NO_NAME;
   gss_buffer_desc tmpname;
   gss_buffer_t tmpnamed = &tmpname;
-  char *retname;
+  char *retname=NULL;
   gss_OID_set oidset;
   gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
+  Gssctxt *ctx = NULL;
 
-  gss_create_empty_oid_set(&min_stat,&oidset);
-  gss_add_oid_set_member(&min_stat,&supported_mechs[GSS_GSI].oid,&oidset);
-  maj_stat = gss_acquire_cred(&min_stat,
-                              GSS_C_NO_NAME,
-                              GSS_C_INDEFINITE,
-                              oidset,
-                              GSS_C_INITIATE,
-                              &gss_cred,
-                              NULL,
-                              NULL);
-
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ssh_gssapi_build_ctx(&ctx);
+
+  gss_create_empty_oid_set(&ctx->minor,&oidset);
+  gss_add_oid_set_member(&ctx->minor,&gsioid,&oidset);
+  ssh_gssapi_set_oid(ctx,&gsioid);
+  ctx->major = gss_acquire_cred(&ctx->minor,
+                               GSS_C_NO_NAME,
+                               GSS_C_INDEFINITE,
+                               oidset,
+                               GSS_C_INITIATE,
+                               &gss_cred,
+                               NULL,
+                               NULL);
+
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
 
   debug("calling gss_inquire_cred");
-  maj_stat = gss_inquire_cred(&min_stat,
-                              gss_cred,
-                              &pname,
-                              NULL,
-                              NULL,
-                              NULL);
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ctx->major = gss_inquire_cred(&ctx->minor,
+                               gss_cred,
+                               &pname,
+                               NULL,
+                               NULL,
+                               NULL);
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
 
-  maj_stat = gss_display_name(&min_stat,
-                             pname,
-                             tmpnamed,
-                             NULL);
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ctx->major = gss_display_name(&ctx->minor,
+                               pname,
+                               tmpnamed,
+                               NULL);
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
   debug("gss_display_name finsished");
-  retname = (char *)malloc(tmpname.length + 1);
-  if (!retname) {
-      goto error;
-  }
+  retname = xmalloc(tmpname.length + 1);
   memcpy(retname, tmpname.value, tmpname.length);
   retname[tmpname.length] = '\0';
 
-  gss_release_name(&min_stat, &pname);
-  gss_release_buffer(&min_stat, tmpnamed);
+  gss_release_name(&ctx->minor, &pname);
+  gss_release_buffer(&ctx->minor, tmpnamed);
 
+ cleanup:
+  if (!retname) {
+      debug("Failed to set GSI username from credentials");
+      ssh_gssapi_error(ctx);
+  }
+  if (ctx) ssh_gssapi_delete_ctx(&ctx);
   return retname;
-
- error:
-  debug("Failed to set GSI username from credentials");
-  ssh_gssapi_error(&supported_mechs[GSS_GSI].oid, maj_stat, min_stat);
-  return NULL;
 }
 #endif /* GSI */
 
@@ -1037,8 +1038,6 @@ int try_gssapi_authentication(char *host, Options *options)
   gss_OID name_type;
   gss_OID_set gss_mechs, my_mechs;
   int my_mech_num, i, present;
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
   int ret_stat = 0;                             /* 1 == success */
   OM_uint32 req_flags = 0;
   OM_uint32 ret_flags;
@@ -1047,6 +1046,8 @@ int try_gssapi_authentication(char *host, Options *options)
   unsigned int slen;
   Gssctxt *ctx = NULL;
 
+  ssh_gssapi_build_ctx(&ctx);
+
   xhost = xstrdup(get_canonical_hostname(1));
   resolve_localhost(&xhost);
 
@@ -1081,44 +1082,33 @@ int try_gssapi_authentication(char *host, Options *options)
 
   name_tok.value = service_name;
   name_tok.length = strlen(service_name) + 1;
-  maj_stat = gss_import_name(&min_stat, &name_tok,
-                             name_type, &target_name);
+  ctx->major = gss_import_name(&ctx->minor, &name_tok,
+                              name_type, &target_name);
 
   free(service_name);
   service_name = NULL;
 
-  if (maj_stat != GSS_S_COMPLETE) {
-    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+  if (ctx->major != GSS_S_COMPLETE) {
+    ssh_gssapi_error(ctx);
     goto cleanup;
   }
 
-  maj_stat = gss_indicate_mechs(&min_stat, &gss_mechs);
+  ctx->major = gss_indicate_mechs(&ctx->minor, &gss_mechs);
 
-  if (maj_stat != GSS_S_COMPLETE) {
-    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+  if (ctx->major != GSS_S_COMPLETE) {
+    ssh_gssapi_error(ctx);
     goto cleanup;
   }
 
   /* The GSSAPI supports the mechs in gss_mechs, but which ones do
      we have credentials for?  We only get one try, so we don't want
      to propose a mechanism we know is going to fail. */
-  maj_stat = gss_create_empty_oid_set(&min_stat, &my_mechs);
-  for (i=0; supported_mechs[i].name != NULL; i++) {
-      maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[i].oid,
-                                        gss_mechs, &present);
-      if (present) {
-         if (!GSS_ERROR(ssh_gssapi_client_ctx(&ctx, &supported_mechs[i].oid,
-                                              host))) {
-             maj_stat = gss_add_oid_set_member(&min_stat,
-                                               &supported_mechs[i].oid,
-                                               &my_mechs);
-             debug("GSSAPI mechanism %s supported", supported_mechs[i].name);
-         } else {
-             debug("no credentials for GSSAPI mechanism %s",
-                   supported_mechs[i].name);
-         }
-      } else {
-         debug("GSSAPI mechanism %s not supported", supported_mechs[i].name);
+  ctx->major = gss_create_empty_oid_set(&ctx->minor, &my_mechs);
+  for (i=0; i<gss_mechs->count; i++) {
+      if (ssh_gssapi_check_mechanism(&(gss_mechs->elements[i]), host)) {
+         ctx->major = gss_add_oid_set_member(&ctx->minor,
+                                             &(gss_mechs->elements[i]),
+                                             &my_mechs);
       }
   }
 
@@ -1137,20 +1127,19 @@ int try_gssapi_authentication(char *host, Options *options)
 #ifdef GSI
   /* Send GSI before Kerberos, because if GSI fails, we can always fall
      back and try regular Kerberos authentication with our Kerberos cred. */
-  maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[GSS_GSI].oid,
-                                    my_mechs, &present);
+  ctx->major = gss_test_oid_set_member(&ctx->minor, &gsioid,
+                                      my_mechs, &present);
   if (present) {
-      packet_put_string(supported_mechs[GSS_GSI].oid.elements,
-                        supported_mechs[GSS_GSI].oid.length);
+      packet_put_string(gsioid.elements,gsioid.length);
   }
 #endif
   for (my_mech_num = 0; my_mech_num < my_mechs->count; my_mech_num++) {
 #ifdef GSI
       /* Skip GSI.  We already sent it above. */
       if ((my_mechs->elements[my_mech_num].length ==
-          supported_mechs[GSS_GSI].oid.length) &&
+          gsioid.length) &&
          memcmp(my_mechs->elements[my_mech_num].elements,
-                supported_mechs[GSS_GSI].oid.elements,
+                gsioid.elements,
                 my_mechs->elements[my_mech_num].length) == 0) {
          continue;
       }
@@ -1190,6 +1179,8 @@ int try_gssapi_authentication(char *host, Options *options)
   mech_oid.length = slen;      /* safe typecast */
   packet_get_all();
 
+  ssh_gssapi_set_oid(ctx, &mech_oid);
+
   /*
    * Perform the context-establishement loop.
    *
@@ -1210,12 +1201,12 @@ int try_gssapi_authentication(char *host, Options *options)
   gss_context = GSS_C_NO_CONTEXT;
 
   do {
-    maj_stat =
-      gss_init_sec_context(&min_stat,
+    ctx->major =
+      gss_init_sec_context(&ctx->minor,
                            GSS_C_NO_CREDENTIAL,
                            &gss_context,
                            target_name,
-                           &mech_oid,
+                           ctx->oid,
                            req_flags,
                            0,
                            NULL,        /* no channel bindings */
@@ -1226,10 +1217,10 @@ int try_gssapi_authentication(char *host, Options *options)
                            NULL);       /* ignore time_rec */
 
     if (token_ptr != GSS_C_NO_BUFFER)
-      (void) gss_release_buffer(&min_stat, &recv_tok);
+      (void) gss_release_buffer(&ctx->minor, &recv_tok);
 
-    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
-      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+    if (ctx->major != GSS_S_COMPLETE && ctx->major != GSS_S_CONTINUE_NEEDED) {
+      ssh_gssapi_error(ctx);
 
       /* Send an abort message */
       packet_start(SSH_MSG_AUTH_GSSAPI_ABORT);
@@ -1246,10 +1237,10 @@ int try_gssapi_authentication(char *host, Options *options)
       packet_send();
       packet_write_wait();
 
-      (void) gss_release_buffer(&min_stat, &send_tok);
+      (void) gss_release_buffer(&ctx->minor, &send_tok);
     }
 
-    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+    if (ctx->major == GSS_S_CONTINUE_NEEDED) {
 
       debug("Continue needed. Reading response...");
 
@@ -1279,7 +1270,7 @@ int try_gssapi_authentication(char *host, Options *options)
       packet_get_all();
       token_ptr = &recv_tok;
     }
-  } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+  } while (ctx->major == GSS_S_CONTINUE_NEEDED);
 
   /* Success */
   ret_stat = 1;
@@ -1310,15 +1301,15 @@ int try_gssapi_authentication(char *host, Options *options)
     wrapped_buf.length=slen;   /* safe typecast */
     packet_get_all();
 
-    maj_stat = gss_unwrap(&min_stat,
+    ctx->major = gss_unwrap(&ctx->minor,
                           gss_context,
                           &wrapped_buf,
                           &unwrapped_buf,
                           &conf_state,
                           &qop_state);
 
-    if (maj_stat != GSS_S_COMPLETE) {
-      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+    if (ctx->major != GSS_S_COMPLETE) {
+      ssh_gssapi_error(ctx);
       packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
                         "Unwrapping of hash failed.");
     }
@@ -1337,7 +1328,7 @@ int try_gssapi_authentication(char *host, Options *options)
 
     debug("Verified SSHD keys through GSSAPI-secured channel.");
 
-    gss_release_buffer(&min_stat, &unwrapped_buf);
+    gss_release_buffer(&ctx->minor, &unwrapped_buf);
 
   } else {
       packet_disconnect("Protocol error during GSSAPI authentication:"
@@ -1348,7 +1339,9 @@ int try_gssapi_authentication(char *host, Options *options)
 
  cleanup:
   if (target_name != NULL)
-      (void) gss_release_name(&min_stat, &target_name);
+      (void) gss_release_name(&ctx->minor, &target_name);
+  if (ctx)
+      ssh_gssapi_delete_ctx(&ctx);
 
   return ret_stat;
 }
index 9b7b61aacec15f11c08ed09d6d0ca1cce2557295..b5d1ba1010425a62bbe9054558ae7335a322d5ad 100644 (file)
@@ -97,7 +97,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        orig = myproposal[PROPOSAL_KEX_ALGS];
        canonhost = xstrdup(get_canonical_hostname(1));
        resolve_localhost(&canonhost);
-       gss = ssh_gssapi_mechanisms(canonhost);
+       gss = ssh_gssapi_client_mechanisms(canonhost);
        xfree(canonhost);
        canonhost=NULL;
        if (gss) {
@@ -139,13 +139,12 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
         /* If we've got GSSAPI algorithms, then we also support the
          * 'null' hostkey, as a last resort */
        if (options.gss_keyex && gss) {
-               orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
-               len = strlen(orig)+sizeof(",null");
-               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
-               snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig);  
+                orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+                len = strlen(orig)+sizeof(",null");
+                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
+                snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig);
        }
 #endif
-
        /* start key exchange */
        kex = kex_setup(myproposal);
        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
@@ -157,11 +156,9 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        kex->server_version_string=server_version_string;
        kex->verify_host_key=&verify_host_key_callback;
        kex->host=host;
-
 #ifdef GSSAPI
        kex->options.gss_deleg_creds=options.gss_deleg_creds;
 #endif
-
        xxx_kex = kex;
 
        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -233,9 +230,11 @@ int        userauth_hostbased(Authctxt *);
 #ifdef GSSAPI
 int    userauth_external(Authctxt *authctxt);
 int    userauth_gssapi(Authctxt *authctxt);
-void   input_gssapi_response(int type, u_int32_t plen, void *ctxt);
-void   input_gssapi_token(int type, u_int32_t plen, void *ctxt);
-void   input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
+void   input_gssapi_response(int type, u_int32_t, void *);
+void   input_gssapi_token(int type, u_int32_t, void *);
+void   input_gssapi_hash(int type, u_int32_t, void *);
+void   input_gssapi_error(int, u_int32_t, void *);
+void   input_gssapi_errtok(int, u_int32_t, void *);
 #endif
 
 void   userauth(Authctxt *, char *);
@@ -506,57 +505,77 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
 int 
 userauth_gssapi(Authctxt *authctxt)
 {
-       Gssctxt *gssctxt;
+       Gssctxt *gssctxt = NULL;
+       static gss_OID_set supported = NULL;
        static int mech=0;
+       OM_uint32 min;
+       int ok=0;
+
+       /* Things work better if we send one mechanism at a time, rather
+        * than them all at once. This means that if we fail at some point
+        * in the middle of a negotiation, we can come back and try something
+        * different. */
 
        if (datafellows & SSH_OLD_GSSAPI) return 0;
        
-       /* Try each mechanism in turn.  Give up if we've tried all
-          supported mechanisms.
+       /* Before we offer a mechanism, check that we can support it. Don't
+        * bother trying to get credentials - as the standard fallback will
+        * deal with that kind of failure.
         */
-       if (mech==GSS_LAST_ENTRY) return 0;
-       
-       /* Initialise as much of our context as we can, so failures can be
-        * trapped before sending any packets.
-        */
-       ssh_gssapi_build_ctx(&gssctxt);
 
-       if (ssh_gssapi_import_name(gssctxt,get_canonical_hostname(1))) {
-               return(0);
+       if (supported==NULL) gss_indicate_mechs(&min, &supported);
+       
+       while (mech<supported->count && !ok) {
+               if (gssctxt) ssh_gssapi_delete_ctx(&gssctxt);
+               ssh_gssapi_build_ctx(&gssctxt);
+               ssh_gssapi_set_oid(gssctxt,&supported->elements[mech]);
+
+               /* The DER encoding below only works for lengths<128,
+                * so check this here 
+                */
+               if (supported->elements[mech].length<128 &&
+                   !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
+                                                     authctxt->host))) {
+                       ok = 1; /* Mechanism works */
+               } else {
+                       mech++;
+               }
        }
        
+       if (!ok) return 0;
+       
        authctxt->methoddata=(void *)gssctxt;
                
        packet_start(SSH2_MSG_USERAUTH_REQUEST);
-#ifdef GSI
-        if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
-           packet_put_cstring("");
-       } else {
-#endif
-           packet_put_cstring(authctxt->server_user);
-#ifdef GSI
-       }
-#endif
+       packet_put_cstring(authctxt->server_user);
        packet_put_cstring(authctxt->service);
         packet_put_cstring(authctxt->method->name);
+       
+       packet_put_int(1);
 
-       /* FIXME: This assumes that our current GSSAPI implementation
-        * supports all of the mechanisms listed in supported_mechs.
-        * This may not be the case - we should use something along
-        * the lines of the code in gss_genr to remove the ones that
-        * aren't supported */
+       /* The newest gsskeyex draft stipulates that OIDs should
+        * be DER encoded, so we need to add the object type and
+        * length information back on */
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               packet_put_string(supported->elements[mech].elements,
+                                 supported->elements[mech].length);
+       } else {
+               packet_put_int((supported->elements[mech].length)+2);
+               packet_put_char(0x06);
+               packet_put_char(supported->elements[mech].length);
+               packet_put_raw(supported->elements[mech].elements,
+                              supported->elements[mech].length);
+       }
 
-       /* Try one GSSAPI mechanism at a time. */
-       packet_put_int(1);
-       packet_put_string(supported_mechs[mech].oid.elements,
-                         supported_mechs[mech].oid.length);
         packet_send();
         packet_write_wait();
 
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,&input_gssapi_error);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,&input_gssapi_errtok);
        
-       mech++;                 /* Move to next mechanism for next time. */
+       mech++; /* Move along to next candidate */
 
         return 1;
 }
@@ -577,16 +596,40 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
        
        /* Setup our OID */
        oidv=packet_get_string(&oidlen);
-       ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
        
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               if (!ssh_gssapi_check_oid(gssctxt,oidv,oidlen)) {
+                       fatal("Server returned different OID than expected");
+               }
+               ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
+       } else {
+               if(oidv[0]!=0x06 || oidv[1]!=oidlen-2) {
+                       debug("Badly encoded mechanism OID received");
+                       clear_auth_state(authctxt);
+                       userauth(authctxt,NULL);
+                       return;
+               }
+               if (!ssh_gssapi_check_oid(gssctxt,oidv+2,oidlen-2)) {
+                       fatal("Server returned different OID than expected");
+               }
+               ssh_gssapi_set_oid_data(gssctxt,oidv+2,oidlen-2);
+       }
+               
        packet_check_eom();
        
        status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
                                     GSS_C_NO_BUFFER, &send_tok, 
                                     NULL);
        if (GSS_ERROR(status)) {
+               if (send_tok.length>0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_send();
+                       packet_write_wait();
+               }
                /* Start again with next method on list */
                debug("Trying to start again");
+               clear_auth_state(authctxt);
                userauth(authctxt,NULL);
                return;
        }
@@ -621,7 +664,14 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
        packet_check_eom();
        
        if (GSS_ERROR(status)) {
+               if (send_tok.length>0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_send();
+                       packet_write_wait();
+               }
                /* Start again with the next method in the list */
+               clear_auth_state(authctxt);
                userauth(authctxt,NULL);
                return;
        }
@@ -641,6 +691,54 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
        }
 }
 
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok,recv_tok;
+       OM_uint32 status;
+       
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+       
+       recv_tok.value=packet_get_string(&recv_tok.length);
+
+       /* Stick it into GSSAPI and see what it says */
+       status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+                                  &recv_tok, &send_tok, NULL);
+
+       packet_check_eom();
+       
+       /* We can't send a packet to the server */
+
+       /* The draft says that we should wait for the server to fail 
+        * before starting the next authentication. So, we clear the
+        * state, but don't do anything else */
+       clear_auth_state(authctxt);
+       return;
+}
+
+void
+input_gssapi_error(int type, u_int32_t plen, void *ctxt)
+{
+       OM_uint32 maj,min;
+       char *msg;
+       char *lang;
+       
+       maj=packet_get_int();
+       min=packet_get_int();
+       msg=packet_get_string(NULL);
+       lang=packet_get_string(NULL);
+
+       packet_check_eom();
+       
+       fprintf(stderr, "Server GSSAPI Error:\n%s\n", msg);
+       xfree(msg);
+       xfree(lang);
+}
+
 int
 userauth_external(Authctxt *authctxt)
 {
@@ -785,7 +883,12 @@ clear_auth_state(Authctxt *authctxt)
 {
        /* XXX clear authentication state */
        dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
-
+#ifdef GSSAPI
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL);
+#endif
+       
        if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
                debug3("clear_auth_state: key_free %p", authctxt->last_key);
                key_free(authctxt->last_key);
index 1e5897b840564f44c6e23e6c34462ce2dd532f1e..6eceb4828c71f2f4de4e3535707ef9e8bd8d9e67 100644 (file)
@@ -1088,10 +1088,6 @@ main(int ac, char **av)
        if (test_flag)
                exit(0);
 
-#ifdef GSSAPI
-       ssh_gssapi_clean_env();
-#endif /* GSSAPI */
-
        /*
         * Clear out any supplemental groups we may have inherited.  This
         * prevents inadvertent creation of files with bad modes (in the
@@ -1800,7 +1796,7 @@ do_ssh1_kex(void)
     Buffer buf;
     unsigned char *data;
     unsigned int data_len;
-    extern unsigned char ssh1_key_digest[16];   /* in gss-genr.c */
+    extern unsigned char ssh1_key_digest[16];   /* in auth2-gss.c */
 
 
     debug("Calculating MD5 hash of server and host keys...");
@@ -1894,7 +1890,7 @@ do_ssh2_kex(void)
                orig= NULL;
                
         if (options.gss_keyex)
-               gss = ssh_server_gssapi_mechanisms();
+               gss = ssh_gssapi_server_mechanisms();
         else
                gss = NULL;
         
index 40ecd720cda9cf6fda00bf09d8ef197b8c7045f6..65802a0311a6d9808b5b03cf168db472627f5d86 100644 (file)
 # Kerberos TGT Passing only works with the AFS kaserver
 #KerberosTgtPassing no
 
+# Session hooks: if allowed, specify the commands to execute
+#AllowSessionHooks yes
+#SessionHookStartupCmd /bin/true
+#SessionHookShutdownCmd /bin/true
+
 # Set this to 'yes' to enable PAM keyboard-interactive authentication 
 # Warning: enabling this may bypass the setting of 'PasswordAuthentication'
 #PAMAuthenticationViaKbdInt no
This page took 0.269344 seconds and 5 git commands to generate.