| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Putty
Revision: 8138
Author: owen
Date: 10 Aug 2008 09:10:31
Changes:Initial commit of GSSAPI Kerberos support.
Files:| ... | ...@@ -459,6 +459,8 @@ | |
| 459 | 459 | int ssh_no_userauth; /* bypass "ssh-userauth" (SSH-2 only) */ |
| 460 | 460 | int try_tis_auth; |
| 461 | 461 | int try_ki_auth; |
| 462 | int try_gssapi_auth; /* attempt gssapi auth */ | |
| 463 | int gssapifwd; /* forward tgt via gss */ | |
| 462 | 464 | int ssh_subsys; /* run a subsystem rather than a command */ |
| 463 | 465 | int ssh_subsys2; /* fallback to go with remote_cmd_ptr2 */ |
| 464 | 466 | int ssh_no_shell; /* avoid running a shell */ |
| ... | ...@@ -0,0 +1,196 @@ | |
| 1 | #ifndef NO_GSSAPI | |
| 2 | ||
| 3 | #include <string.h> | |
| 4 | #include <gssapi/gssapi_krb5.h> | |
| 5 | #include "sshgss.h" | |
| 6 | #include "misc.h" | |
| 7 | ||
| 8 | typedef struct uxSsh_gss_ctx { | |
| 9 | OM_uint32 maj_stat; | |
| 10 | OM_uint32 min_stat; | |
| 11 | gss_ctx_id_t ctx; | |
| 12 | } uxSsh_gss_ctx; | |
| 13 | ||
| 14 | int ssh_gss_init(void) | |
| 15 | { | |
| 16 | /* On Windows this tries to load the SSPI library functions. On | |
| 17 | Unix we assume we have GSSAPI at runtime if we were linked with | |
| 18 | it at compile time */ | |
| 19 | return 1; | |
| 20 | } | |
| 21 | ||
| 22 | Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) | |
| 23 | { | |
| 24 | /* Copy constant into mech */ | |
| 25 | mech->len = gss_mech_krb5->length; | |
| 26 | mech->data = gss_mech_krb5->elements; | |
| 27 | ||
| 28 | return SSH_GSS_OK; | |
| 29 | } | |
| 30 | ||
| 31 | Ssh_gss_stat ssh_gss_import_name(char *host, | |
| 32 | Ssh_gss_name *srv_name) | |
| 33 | { | |
| 34 | OM_uint32 min_stat,maj_stat; | |
| 35 | gss_buffer_desc host_buf; | |
| 36 | char *pStr; | |
| 37 | ||
| 38 | pStr = dupcat("host@", host, NULL); | |
| 39 | ||
| 40 | host_buf.value = pStr; | |
| 41 | host_buf.length = strlen(pStr); | |
| 42 | ||
| 43 | maj_stat = gss_import_name(&min_stat, &host_buf, | |
| 44 | GSS_C_NT_HOSTBASED_SERVICE, | |
| 45 | (gss_name_t *)srv_name); | |
| 46 | /* Release buffer */ | |
| 47 | sfree(pStr); | |
| 48 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; | |
| 49 | return SSH_GSS_FAILURE; | |
| 50 | } | |
| 51 | ||
| 52 | Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) | |
| 53 | { | |
| 54 | uxSsh_gss_ctx *uxctx = snew(uxSsh_gss_ctx); | |
| 55 | ||
| 56 | uxctx->maj_stat = uxctx->min_stat = GSS_S_COMPLETE; | |
| 57 | uxctx->ctx = GSS_C_NO_CONTEXT; | |
| 58 | *ctx = (Ssh_gss_ctx) uxctx; | |
| 59 | ||
| 60 | return SSH_GSS_OK; | |
| 61 | } | |
| 62 | ||
| 63 | Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, | |
| 64 | Ssh_gss_name srv_name, | |
| 65 | int to_deleg, | |
| 66 | Ssh_gss_buf *recv_tok, | |
| 67 | Ssh_gss_buf *send_tok) | |
| 68 | { | |
| 69 | uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx*) *ctx; | |
| 70 | OM_uint32 ret_flags; | |
| 71 | ||
| 72 | if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; | |
| 73 | uxctx->maj_stat = gss_init_sec_context(&uxctx->min_stat, | |
| 74 | GSS_C_NO_CREDENTIAL, | |
| 75 | &uxctx->ctx, | |
| 76 | (gss_name_t) srv_name, | |
| 77 | (gss_OID) gss_mech_krb5, | |
| 78 | GSS_C_MUTUAL_FLAG | | |
| 79 | GSS_C_INTEG_FLAG | to_deleg, | |
| 80 | 0, | |
| 81 | NULL, /* no channel bindings */ | |
| 82 | (gss_buffer_desc *)recv_tok, | |
| 83 | NULL, /* ignore mech type */ | |
| 84 | (gss_buffer_desc *)send_tok, | |
| 85 | &ret_flags, | |
| 86 | NULL); /* ignore time_rec */ | |
| 87 | ||
| 88 | if (uxctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; | |
| 89 | if (uxctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; | |
| 90 | return SSH_GSS_FAILURE; | |
| 91 | } | |
| 92 | ||
| 93 | Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf) | |
| 94 | { | |
| 95 | uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; | |
| 96 | OM_uint32 lmin,lmax; | |
| 97 | OM_uint32 ccc; | |
| 98 | gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; | |
| 99 | gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; | |
| 100 | ||
| 101 | /* Return empty buffer in case of failure */ | |
| 102 | SSH_GSS_CLEAR_BUF(buf); | |
| 103 | ||
| 104 | /* get first mesg from GSS */ | |
| 105 | ccc=0; | |
| 106 | lmax=gss_display_status(&lmin,uxctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) gss_mech_krb5,&ccc,&msg_maj); | |
| 107 | ||
| 108 | if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; | |
| 109 | ||
| 110 | /* get first mesg from Kerberos */ | |
| 111 | ccc=0; | |
| 112 | lmax=gss_display_status(&lmin,uxctx->min_stat,GSS_C_MECH_CODE,(gss_OID) gss_mech_krb5,&ccc,&msg_min); | |
| 113 | ||
| 114 | if (lmax != GSS_S_COMPLETE) { | |
| 115 | gss_release_buffer(&lmin, &msg_maj); | |
| 116 | return SSH_GSS_FAILURE; | |
| 117 | } | |
| 118 | ||
| 119 | /* copy data into buffer */ | |
| 120 | buf->len = msg_maj.length + msg_min.length + 1; | |
| 121 | buf->data = snewn(buf->len + 1, char); | |
| 122 | ||
| 123 | /* copy mem */ | |
| 124 | memcpy(buf->data, msg_maj.value, msg_maj.length); | |
| 125 | buf->data[msg_maj.length] = ' '; | |
| 126 | memcpy(buf->data + msg_maj.length + 1, msg_min.value, msg_min.length); | |
| 127 | buf->data[buf->len] = 0; | |
| 128 | /* free mem & exit */ | |
| 129 | gss_release_buffer(&lmin, &msg_maj); | |
| 130 | gss_release_buffer(&lmin, &msg_min); | |
| 131 | return SSH_GSS_OK; | |
| 132 | } | |
| 133 | ||
| 134 | Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok) | |
| 135 | { | |
| 136 | OM_uint32 min_stat,maj_stat; | |
| 137 | maj_stat = gss_release_buffer(&min_stat, (gss_buffer_desc *)send_tok); | |
| 138 | ||
| 139 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; | |
| 140 | return SSH_GSS_FAILURE; | |
| 141 | } | |
| 142 | ||
| 143 | Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx) | |
| 144 | { | |
| 145 | uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) *ctx; | |
| 146 | OM_uint32 min_stat; | |
| 147 | OM_uint32 maj_stat=GSS_S_COMPLETE; | |
| 148 | ||
| 149 | if (uxctx == NULL) return SSH_GSS_FAILURE; | |
| 150 | if (uxctx->ctx != GSS_C_NO_CONTEXT) | |
| 151 | maj_stat = gss_delete_sec_context(&min_stat,&uxctx->ctx,GSS_C_NO_BUFFER); | |
| 152 | sfree(uxctx); | |
| 153 | ||
| 154 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; | |
| 155 | return SSH_GSS_FAILURE; | |
| 156 | } | |
| 157 | ||
| 158 | ||
| 159 | Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name) | |
| 160 | { | |
| 161 | OM_uint32 min_stat,maj_stat; | |
| 162 | maj_stat = gss_release_name(&min_stat, (gss_name_t) srv_name); | |
| 163 | ||
| 164 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; | |
| 165 | return SSH_GSS_FAILURE; | |
| 166 | } | |
| 167 | ||
| 168 | Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf, | |
| 169 | Ssh_gss_buf *hash) | |
| 170 | { | |
| 171 | uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; | |
| 172 | if (uxctx == NULL) return SSH_GSS_FAILURE; | |
| 173 | return gss_get_mic(&(uxctx->min_stat), | |
| 174 | uxctx->ctx, | |
| 175 | 0, | |
| 176 | (gss_buffer_desc *)buf, | |
| 177 | (gss_buffer_desc *)hash); | |
| 178 | } | |
| 179 | ||
| 180 | Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash) | |
| 181 | { | |
| 182 | /* On Unix this is the same freeing process as ssh_gss_free_tok. */ | |
| 183 | return ssh_gss_free_tok(hash); | |
| 184 | } | |
| 185 | ||
| 186 | #else | |
| 187 | ||
| 188 | /* Dummy function so this source file defines something if NO_GSSAPI | |
| 189 | is defined. */ | |
| 190 | ||
| 191 | int ssh_gss_init(void) | |
| 192 | { | |
| 193 | return 1; | |
| 194 | } | |
| 195 | ||
| 196 | #endif |
| ... | ...@@ -12,6 +12,7 @@ | |
| 12 | 12 | #include "putty.h" |
| 13 | 13 | #include "tree234.h" |
| 14 | 14 | #include "ssh.h" |
| 15 | #include "sshgss.h" | |
| 15 | 16 | |
| 16 | 17 | #ifndef FALSE |
| 17 | 18 | #define FALSE 0 |
| ... | ...@@ -112,6 +113,12 @@ | |
| 112 | 113 | #define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */ |
| 113 | 114 | #define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */ |
| 114 | 115 | #define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */ |
| 116 | #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 | |
| 117 | #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 | |
| 118 | #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 | |
| 119 | #define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 | |
| 120 | #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 | |
| 121 | #define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 | |
| 115 | 122 | |
| 116 | 123 | /* |
| 117 | 124 | * Packet type contexts, so that ssh2_pkt_type can correctly decode |
| ... | ...@@ -127,6 +134,7 @@ | |
| 127 | 134 | SSH2_PKTCTX_NOAUTH, |
| 128 | 135 | SSH2_PKTCTX_PUBLICKEY, |
| 129 | 136 | SSH2_PKTCTX_PASSWORD, |
| 137 | SSH2_PKTCTX_GSSAPI, | |
| 130 | 138 | SSH2_PKTCTX_KBDINTER |
| 131 | 139 | } Pkt_ACtx; |
| 132 | 140 | |
| ... | ...@@ -339,6 +347,12 @@ | |
| 339 | 347 | } |
| 340 | 348 | static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) |
| 341 | 349 | { |
| 350 | translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI); | |
| 351 | translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI); | |
| 352 | translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI); | |
| 353 | translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI); | |
| 354 | translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI); | |
| 355 | translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI); | |
| 342 | 356 | translate(SSH2_MSG_DISCONNECT); |
| 343 | 357 | translate(SSH2_MSG_IGNORE); |
| 344 | 358 | translate(SSH2_MSG_UNIMPLEMENTED); |
| ... | ...@@ -896,6 +910,11 @@ | |
| 896 | 910 | int kex_in_progress; |
| 897 | 911 | long next_rekey, last_rekey; |
| 898 | 912 | char *deferred_rekey_reason; /* points to STATIC string; don't free */ |
| 913 | ||
| 914 | /* | |
| 915 | * Fully qualified host name, which we need if doing GSSAPI. | |
| 916 | */ | |
| 917 | char *fullhostname; | |
| 899 | 918 | }; |
| 900 | 919 | |
| 901 | 920 | #define logevent(s) logevent(ssh->frontend, s) |
| ... | ...@@ -2875,6 +2894,7 @@ | |
| 2875 | 2894 | sk_addr_free(addr); |
| 2876 | 2895 | return err; |
| 2877 | 2896 | } |
| 2897 | ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */ | |
| 2878 | 2898 | |
| 2879 | 2899 | /* |
| 2880 | 2900 | * Open socket. |
| ... | ...@@ -7043,12 +7063,15 @@ | |
| 7043 | 7063 | AUTH_TYPE_PUBLICKEY_OFFER_LOUD, |
| 7044 | 7064 | AUTH_TYPE_PUBLICKEY_OFFER_QUIET, |
| 7045 | 7065 | AUTH_TYPE_PASSWORD, |
| 7066 | AUTH_TYPE_GSSAPI, | |
| 7046 | 7067 | AUTH_TYPE_KEYBOARD_INTERACTIVE, |
| 7047 | 7068 | AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET |
| 7048 | 7069 | } type; |
| 7049 | 7070 | int done_service_req; |
| 7050 | 7071 | int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter; |
| 7051 | 7072 | int tried_pubkey_config, done_agent; |
| 7073 | int can_gssapi; | |
| 7074 | int tried_gssapi; | |
| 7052 | 7075 | int kbd_inter_refused; |
| 7053 | 7076 | int we_are_in; |
| 7054 | 7077 | prompts_t *cur_prompt; |
| ... | ...@@ -7072,6 +7095,11 @@ | |
| 7072 | 7095 | int try_send; |
| 7073 | 7096 | int num_env, env_left, env_ok; |
| 7074 | 7097 | struct Packet *pktout; |
| 7098 | Ssh_gss_ctx gss_ctx; | |
| 7099 | Ssh_gss_buf gss_buf; | |
| 7100 | Ssh_gss_buf gss_rcvtok, gss_sndtok; | |
| 7101 | Ssh_gss_name gss_srv_name; | |
| 7102 | Ssh_gss_stat gss_stat; | |
| 7075 | 7103 | }; |
| 7076 | 7104 | crState(do_ssh2_authconn_state); |
| 7077 | 7105 | |
| ... | ...@@ -7079,6 +7107,8 @@ | |
| 7079 | 7107 | |
| 7080 | 7108 | s->done_service_req = FALSE; |
| 7081 | 7109 | s->we_are_in = FALSE; |
| 7110 | s->tried_gssapi = FALSE; | |
| 7111 | ||
| 7082 | 7112 | if (!ssh->cfg.ssh_no_userauth) { |
| 7083 | 7113 | /* |
| 7084 | 7114 | * Request userauth protocol, and await a response to it. |
| ... | ...@@ -7366,7 +7396,7 @@ | |
| 7366 | 7396 | break; |
| 7367 | 7397 | } |
| 7368 | 7398 | |
| 7369 | if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) { | |
| 7399 | if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) { | |
| 7370 | 7400 | bombout(("Strange packet received during authentication: " |
| 7371 | 7401 | "type %d", pktin->type)); |
| 7372 | 7402 | crStopV; |
| ... | ...@@ -7437,6 +7467,11 @@ | |
| 7437 | 7467 | in_commasep_string("password", methods, methlen); |
| 7438 | 7468 | s->can_keyb_inter = ssh->cfg.try_ki_auth && |
| 7439 | 7469 | in_commasep_string("keyboard-interactive", methods, methlen); |
| 7470 | #ifndef NO_GSSAPI | |
| 7471 | s->can_gssapi = ssh->cfg.try_gssapi_auth && | |
| 7472 | in_commasep_string("gssapi-with-mic", methods, methlen) && | |
| 7473 | ssh_gss_init(); | |
| 7474 | #endif | |
| 7440 | 7475 | } |
| 7441 | 7476 | |
| 7442 | 7477 | ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; |
| ... | ...@@ -7765,6 +7800,157 @@ | |
| 7765 | 7800 | key->alg->freekey(key->data); |
| 7766 | 7801 | } |
| 7767 | 7802 | |
| 7803 | #ifndef NO_GSSAPI | |
| 7804 | } else if (s->can_gssapi && !s->tried_gssapi) { | |
| 7805 | ||
| 7806 | /* GSSAPI Authentication */ | |
| 7807 | ||
| 7808 | int micoffset; | |
| 7809 | Ssh_gss_buf mic; | |
| 7810 | s->type = AUTH_TYPE_GSSAPI; | |
| 7811 | s->tried_gssapi = TRUE; | |
| 7812 | s->gotit = TRUE; | |
| 7813 | ssh->pkt_actx = SSH2_PKTCTX_GSSAPI; | |
| 7814 | ||
| 7815 | /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ | |
| 7816 | s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | |
| 7817 | ssh2_pkt_addstring(s->pktout, s->username); | |
| 7818 | ssh2_pkt_addstring(s->pktout, "ssh-connection"); | |
| 7819 | ssh2_pkt_addstring(s->pktout, "gssapi-with-mic"); | |
| 7820 | ||
| 7821 | /* add mechanism info */ | |
| 7822 | ssh_gss_indicate_mech(&s->gss_buf); | |
| 7823 | ||
| 7824 | /* number of GSSAPI mechanisms */ | |
| 7825 | ssh2_pkt_adduint32(s->pktout,1); | |
| 7826 | ||
| 7827 | /* length of OID + 2 */ | |
| 7828 | ssh2_pkt_adduint32(s->pktout, s->gss_buf.len + 2); | |
| 7829 | ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE); | |
| 7830 | ||
| 7831 | /* length of OID */ | |
| 7832 | ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.len); | |
| 7833 | ||
| 7834 | ssh_pkt_adddata(s->pktout, s->gss_buf.data, s->gss_buf.len); | |
| 7835 | ssh2_pkt_send(ssh, s->pktout); | |
| 7836 | crWaitUntilV(pktin); | |
| 7837 | if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) { | |
| 7838 | logevent("GSSAPI authentication request refused"); | |
| 7839 | continue; | |
| 7840 | } | |
| 7841 | ||
| 7842 | /* check returned packet ... */ | |
| 7843 | ||
| 7844 | ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len); | |
| 7845 | if (s->gss_rcvtok.len != s->gss_buf.len + 2 || | |
| 7846 | s->gss_rcvtok.data[0] != SSH2_GSS_OIDTYPE || | |
| 7847 | s->gss_rcvtok.data[1] != s->gss_buf.len || | |
| 7848 | memcmp(s->gss_rcvtok.data+2,s->gss_buf.data,s->gss_buf.len) ) { | |
| 7849 | logevent("GSSAPI authentication - wrong response from server"); | |
| 7850 | continue; | |
| 7851 | } | |
| 7852 | ||
| 7853 | /* now start running */ | |
| 7854 | s->gss_stat = ssh_gss_import_name(ssh->fullhostname, | |
| 7855 | &s->gss_srv_name); | |
| 7856 | if (s->gss_stat != SSH_GSS_OK) { | |
| 7857 | if (s->gss_stat == SSH_GSS_BAD_HOST_NAME) | |
| 7858 | logevent("GSSAPI import name failed - Bad service name"); | |
| 7859 | else | |
| 7860 | logevent("GSSAPI import name failed"); | |
| 7861 | continue; | |
| 7862 | } | |
| 7863 | ||
| 7864 | /* fetch TGT into GSS engine */ | |
| 7865 | s->gss_stat = ssh_gss_acquire_cred(&s->gss_ctx); | |
| 7866 | ||
| 7867 | if (s->gss_stat != SSH_GSS_OK) { | |
| 7868 | logevent("GSSAPI authentication failed to get credentials"); | |
| 7869 | ssh_gss_release_name(&s->gss_srv_name); | |
| 7870 | continue; | |
| 7871 | } | |
| 7872 | ||
| 7873 | /* initial tokens are empty */ | |
| 7874 | s->gss_rcvtok.len = s->gss_sndtok.len = 0; | |
| 7875 | s->gss_rcvtok.data = s->gss_sndtok.data = NULL; | |
| 7876 | ||
| 7877 | /* now enter the loop */ | |
| 7878 | do { | |
| 7879 | s->gss_stat = ssh_gss_init_sec_context(&s->gss_ctx, | |
| 7880 | s->gss_srv_name, | |
| 7881 | ssh->cfg.gssapifwd, | |
| 7882 | &s->gss_rcvtok, | |
| 7883 | &s->gss_sndtok); | |
| 7884 | ||
| 7885 | if (s->gss_stat!=SSH_GSS_S_COMPLETE && | |
| 7886 | s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) { | |
| 7887 | logevent("GSSAPI authentication initialisation failed"); | |
| 7888 | ||
| 7889 | if (ssh_gss_display_status(s->gss_ctx,&s->gss_buf) == SSH_GSS_OK) { | |
| 7890 | logevent(s->gss_buf.data); | |
| 7891 | sfree(s->gss_buf.data); | |
| 7892 | } | |
| 7893 | ||
| 7894 | break; | |
| 7895 | } | |
| 7896 | logevent("GSSAPI authentication initialised"); | |
| 7897 | ||
| 7898 | /* Client and server now exchange tokens until GSSAPI | |
| 7899 | * no longer says CONTINUE_NEEDED */ | |
| 7900 | ||
| 7901 | if (s->gss_sndtok.len != 0) { | |
| 7902 | s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); | |
| 7903 | ssh_pkt_addstring_start(s->pktout); | |
| 7904 | ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.data,s->gss_sndtok.len); | |
| 7905 | ssh2_pkt_send(ssh, s->pktout); | |
| 7906 | ssh_gss_free_tok(&s->gss_sndtok); | |
| 7907 | } | |
| 7908 | ||
| 7909 | if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) { | |
| 7910 | crWaitUntilV(pktin); | |
| 7911 | if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) { | |
| 7912 | logevent("GSSAPI authentication - bad server response"); | |
| 7913 | s->gss_stat = SSH_GSS_FAILURE; | |
| 7914 | break; | |
| 7915 | } | |
| 7916 | ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len); | |
| 7917 | } | |
| 7918 | } while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED); | |
| 7919 | ||
| 7920 | if (s->gss_stat != SSH_GSS_OK) { | |
| 7921 | ssh_gss_release_name(&s->gss_srv_name); | |
| 7922 | ssh_gss_release_cred(&s->gss_ctx); | |
| 7923 | continue; | |
| 7924 | } | |
| 7925 | logevent("GSSAPI authentication loop finished OK"); | |
| 7926 | ||
| 7927 | /* Now send the MIC */ | |
| 7928 | ||
| 7929 | s->pktout = ssh2_pkt_init(0); | |
| 7930 | micoffset = s->pktout->length; | |
| 7931 | ssh_pkt_addstring_start(s->pktout); | |
| 7932 | ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len); | |
| 7933 | ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST); | |
| 7934 | ssh_pkt_addstring(s->pktout, s->username); | |
| 7935 | ssh_pkt_addstring(s->pktout, "ssh-connection"); | |
| 7936 | ssh_pkt_addstring(s->pktout, "gssapi-with-mic"); | |
| 7937 | ||
| 7938 | s->gss_buf.data = (char *)s->pktout->data + micoffset; | |
| 7939 | s->gss_buf.len = s->pktout->length - micoffset; | |
| 7940 | ||
| 7941 | ssh_gss_get_mic(s->gss_ctx, &s->gss_buf, &mic); | |
| 7942 | s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC); | |
| 7943 | ssh_pkt_addstring_start(s->pktout); | |
| 7944 | ssh_pkt_addstring_data(s->pktout, mic.data, mic.len); | |
| 7945 | ssh2_pkt_send(ssh, s->pktout); | |
| 7946 | ssh_gss_free_mic(&mic); | |
| 7947 | ||
| 7948 | s->gotit = FALSE; | |
| 7949 | ||
| 7950 | ssh_gss_release_name(&s->gss_srv_name); | |
| 7951 | ssh_gss_release_cred(&s->gss_ctx); | |
| 7952 | continue; | |
| 7953 | #endif | |
| 7768 | 7954 | } else if (s->can_keyb_inter && !s->kbd_inter_refused) { |
| 7769 | 7955 | |
| 7770 | 7956 | /* |
| ... | ...@@ -8949,6 +9135,7 @@ | |
| 8949 | 9135 | sfree(ssh->do_ssh2_authconn_state); |
| 8950 | 9136 | sfree(ssh->v_c); |
| 8951 | 9137 | sfree(ssh->v_s); |
| 9138 | sfree(ssh->fullhostname); | |
| 8952 | 9139 | if (ssh->crcda_ctx) { |
| 8953 | 9140 | crcda_free_context(ssh->crcda_ctx); |
| 8954 | 9141 | ssh->crcda_ctx = NULL; |
| ... | ...@@ -107,8 +107,8 @@ | |
| 107 | 107 | { |
| 108 | 108 | if (!strcmp(name, "TermType")) |
| 109 | 109 | return dupstr(getenv("TERM")); |
| 110 | if (!strcmp(name, "UserName")) | |
| 111 | return get_username(); | |
| 110 | if (!strcmp(name, "UserName")) | |
| 111 | return get_username(); | |
| 112 | 112 | if (!strcmp(name, "SerialLine")) |
| 113 | 113 | return dupstr("/dev/ttyS0"); |
| 114 | 114 | return NULL; |
| ... | ...@@ -0,0 +1,112 @@ | |
| 1 | #define SSH2_GSS_OIDTYPE 0x06 | |
| 2 | typedef void *Ssh_gss_ctx; | |
| 3 | typedef void *Ssh_gss_name; | |
| 4 | ||
| 5 | typedef enum Ssh_gss_stat { | |
| 6 | SSH_GSS_OK = 0, | |
| 7 | SSH_GSS_S_CONTINUE_NEEDED, | |
| 8 | SSH_GSS_NO_MEM, | |
| 9 | SSH_GSS_BAD_HOST_NAME, | |
| 10 | SSH_GSS_FAILURE | |
| 11 | } Ssh_gss_stat; | |
| 12 | ||
| 13 | #define SSH_GSS_S_COMPLETE SSH_GSS_OK | |
| 14 | ||
| 15 | typedef struct Ssh_gss_buf { | |
| 16 | int len; | |
| 17 | char *data; | |
| 18 | } Ssh_gss_buf; | |
| 19 | ||
| 20 | #define SSH_GSS_EMPTY_BUF (Ssh_gss_buf) {0,NULL} | |
| 21 | ||
| 22 | #define SSH_GSS_CLEAR_BUF(buf) do { \ | |
| 23 | (*buf).len = 0; \ | |
| 24 | (*buf).data = NULL; \ | |
| 25 | } while (0) | |
| 26 | ||
| 27 | /* Functions, provided by either wingss.c or uxgss.c */ | |
| 28 | ||
| 29 | /* | |
| 30 | * Do startup-time initialisation for using GSSAPI. (On Windows, | |
| 31 | * for instance, this dynamically loads the GSSAPI DLL and | |
| 32 | * retrieves some function pointers.) | |
| 33 | * | |
| 34 | * Return value is 1 on success, or 0 if initialisation failed. | |
| 35 | * | |
| 36 | * May be called multiple times (since the most convenient place | |
| 37 | * to call it _from_ is the ssh.c setup code), and will harmlessly | |
| 38 | * return success if already initialised. | |
| 39 | */ | |
| 40 | int ssh_gss_init(void); | |
| 41 | ||
| 42 | /* | |
| 43 | * Fills in buf with a string describing the GSSAPI mechanism in | |
| 44 | * use. buf->data is not dynamically allocated. | |
| 45 | */ | |
| 46 | Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *buf); | |
| 47 | ||
| 48 | /* | |
| 49 | * Converts a name such as a hostname into a GSSAPI internal form, | |
| 50 | * which is placed in "out". The result should be freed by | |
| 51 | * ssh_gss_release_name(). | |
| 52 | */ | |
| 53 | Ssh_gss_stat ssh_gss_import_name(char *in, Ssh_gss_name *out); | |
| 54 | ||
| 55 | /* | |
| 56 | * Frees the contents of an Ssh_gss_name structure filled in by | |
| 57 | * ssh_gss_import_name(). | |
| 58 | */ | |
| 59 | Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *name); | |
| 60 | ||
| 61 | /* | |
| 62 | * The main GSSAPI security context setup function. The "out" | |
| 63 | * parameter will need to be freed by ssh_gss_free_tok. | |
| 64 | */ | |
| 65 | Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, Ssh_gss_name name, int delegate, | |
| 66 | Ssh_gss_buf *in, Ssh_gss_buf *out); | |
| 67 | ||
| 68 | /* | |
| 69 | * Frees the contents of an Ssh_gss_buf filled in by | |
| 70 | * ssh_gss_init_sec_context(). Do not accidentally call this on | |
| 71 | * something filled in by ssh_gss_get_mic() (which requires a | |
| 72 | * different free function) or something filled in by any other | |
| 73 | * way. | |
| 74 | */ | |
| 75 | Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *); | |
| 76 | ||
| 77 | /* | |
| 78 | * Acquires the credentials to perform authentication in the first | |
| 79 | * place. Needs to be freed by ssh_gss_release_cred(). | |
| 80 | */ | |
| 81 | Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *); | |
| 82 | ||
| 83 | /* | |
| 84 | * Frees the contents of an Ssh_gss_ctx filled in by | |
| 85 | * ssh_gss_acquire_cred(). | |
| 86 | */ | |
| 87 | Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *); | |
| 88 | ||
| 89 | /* | |
| 90 | * Gets a MIC for some input data. "out" needs to be freed by | |
| 91 | * ssh_gss_free_mic(). | |
| 92 | */ | |
| 93 | Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *in, | |
| 94 | Ssh_gss_buf *out); | |
| 95 | ||
| 96 | /* | |
| 97 | * Frees the contents of an Ssh_gss_buf filled in by | |
| 98 | * ssh_gss_get_mic(). Do not accidentally call this on something | |
| 99 | * filled in by ssh_gss_init_sec_context() (which requires a | |
| 100 | * different free function) or something filled in by any other | |
| 101 | * way. | |
| 102 | */ | |
| 103 | Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *); | |
| 104 | ||
| 105 | /* | |
| 106 | * Return an error message after authentication failed. The | |
| 107 | * message string is returned in "buf", with buf->len giving the | |
| 108 | * number of characters of printable message text and buf->data | |
| 109 | * containing one more character which is a trailing NUL. | |
| 110 | * buf->data should be manually freed by the caller. | |
| 111 | */ | |
| 112 | Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx, Ssh_gss_buf *buf); |
| ... | ...@@ -321,6 +321,7 @@ | |
| 321 | 321 | write_setting_i(sesskey, "Compression", cfg->compression); |
| 322 | 322 | write_setting_i(sesskey, "TryAgent", cfg->tryagent); |
| 323 | 323 | write_setting_i(sesskey, "AgentFwd", cfg->agentfwd); |
| 324 | write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd); | |
| 324 | 325 | write_setting_i(sesskey, "ChangeUsername", cfg->change_username); |
| 325 | 326 | wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, |
| 326 | 327 | cfg->ssh_cipherlist); |
| ... | ...@@ -330,6 +331,7 @@ | |
| 330 | 331 | write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth); |
| 331 | 332 | write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth); |
| 332 | 333 | write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth); |
| 334 | write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth); | |
| 333 | 335 | write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell); |
| 334 | 336 | write_setting_i(sesskey, "SshProt", cfg->sshprot); |
| 335 | 337 | write_setting_s(sesskey, "LogHost", cfg->loghost); |
| ... | ...@@ -581,7 +583,7 @@ | |
| 581 | 583 | gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n", |
| 582 | 584 | cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command)); |
| 583 | 585 | gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt)); |
| 584 | gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username)); | |
| 586 | gpps(sesskey, "UserName", get_username(), cfg->username, sizeof(cfg->username)); | |
| 585 | 587 | gpps(sesskey, "LocalUserName", "", cfg->localusername, |
| 586 | 588 | sizeof(cfg->localusername)); |
| 587 | 589 | gppi(sesskey, "NoPTY", 0, &cfg->nopty); |
| ... | ...@@ -589,6 +591,7 @@ | |
| 589 | 591 | gppi(sesskey, "TryAgent", 1, &cfg->tryagent); |
| 590 | 592 | gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd); |
| 591 | 593 | gppi(sesskey, "ChangeUsername", 0, &cfg->change_username); |
| 594 | gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd); | |
| 592 | 595 | gprefs(sesskey, "Cipher", "\0", |
| 593 | 596 | ciphernames, CIPHER_MAX, cfg->ssh_cipherlist); |
| 594 | 597 | { |
| ... | ...@@ -614,6 +617,7 @@ | |
| 614 | 617 | gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth); |
| 615 | 618 | gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth); |
| 616 | 619 | gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth); |
| 620 | gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth); | |
| 617 | 621 | gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell); |
| 618 | 622 | gppfile(sesskey, "PublicKeyFile", &cfg->keyfile); |
| 619 | 623 | gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd, |
| ... | ...@@ -924,6 +924,8 @@ | |
| 924 | 924 | "# You can define this path to point at your tools if you need to\n". |
| 925 | 925 | "# TOOLPATH = /opt/gcc/bin\n". |
| 926 | 926 | "CC = \$(TOOLPATH)cc\n". |
| 927 | "# If necessary set the path to krb5-config here\n". | |
| 928 | "KRB5CONFIG=krb5-config\n". | |
| 927 | 929 | "# You can manually set this to `gtk-config' or `pkg-config gtk+-1.2'\n". |
| 928 | 930 | "# (depending on what works on your system) if you want to enforce\n". |
| 929 | 931 | "# building with GTK 1.2, or you can set it to `pkg-config gtk+-2.0'\n". |
| ... | ...@@ -939,6 +941,11 @@ | |
| 939 | 941 | " -D _FILE_OFFSET_BITS=64\n". |
| 940 | 942 | "XLDFLAGS = \$(LDFLAGS) `\$(GTK_CONFIG) --libs`\n". |
| 941 | 943 | "ULDFLAGS = \$(LDFLAGS)\n". |
| 944 | "ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n". | |
| 945 | "CFLAGS+= `\$(KRB5CONFIG) --cflags gssapi`\n". | |
| 946 | "XLDFLAGS+= `\$(KRB5CONFIG) --libs gssapi`\n". | |
| 947 | "ULDFLAGS = `\$(KRB5CONFIG) --libs gssapi`\n". | |
| 948 | "endif\n"; | |
| 942 | 949 | "INSTALL=install\n", |
| 943 | 950 | "INSTALL_PROGRAM=\$(INSTALL)\n", |
| 944 | 951 | "INSTALL_DATA=\$(INSTALL)\n", |
| ... | ...@@ -0,0 +1,319 @@ | |
| 1 | #ifndef NO_GSSAPI | |
| 2 | ||
| 3 | #include <windows.h> | |
| 4 | #define SECURITY_WIN32 | |
| 5 | #include <security.h> | |
| 6 | #include "sshgss.h" | |
| 7 | #include "misc.h" | |
| 8 | ||
| 9 | #define NOTHING | |
| 10 | #define DECL_SSPI_FUNCTION(linkage, rettype, name, params) \ | |
| 11 | typedef rettype (WINAPI *t_##name) params; \ | |
| 12 | linkage t_##name p_##name | |
| 13 | #define GET_SSPI_FUNCTION(module, name) \ | |
| 14 | p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL | |
| 15 | ||
| 16 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 17 | AcquireCredentialsHandleA, | |
| 18 | (SEC_CHAR *, SEC_CHAR *, ULONG, PLUID, | |
| 19 | PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp)); | |
| 20 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 21 | InitializeSecurityContextA, | |
| 22 | (PCredHandle, PCtxtHandle, SEC_CHAR *, ULONG, ULONG, | |
| 23 | ULONG, PSecBufferDesc, ULONG, PCtxtHandle, | |
| 24 | PSecBufferDesc, PULONG, PTimeStamp)); | |
| 25 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 26 | FreeContextBuffer, | |
| 27 | (PVOID)); | |
| 28 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 29 | FreeCredentialsHandle, | |
| 30 | (PCredHandle)); | |
| 31 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 32 | DeleteSecurityContext, | |
| 33 | (PCtxtHandle)); | |
| 34 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 35 | QueryContextAttributesA, | |
| 36 | (PCtxtHandle, ULONG, PVOID)); | |
| 37 | DECL_SSPI_FUNCTION(static, SECURITY_STATUS, | |
| 38 | MakeSignature, | |
| 39 | (PCtxtHandle, ULONG, PSecBufferDesc, ULONG)); | |
| 40 | ||
| 41 | static HMODULE security_module = NULL; | |
| 42 | ||
| 43 | typedef struct winSsh_gss_ctx { | |
| 44 | unsigned long maj_stat; | |
| 45 | unsigned long min_stat; | |
| 46 | CredHandle cred_handle; | |
| 47 | CtxtHandle context; | |
| 48 | PCtxtHandle context_handle; | |
| 49 | TimeStamp expiry; | |
| 50 | } winSsh_gss_ctx; | |
| 51 | ||
| 52 | ||
| 53 | const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}; | |
| 54 | ||
| 55 | int ssh_gss_init(void) | |
| 56 | { | |
| 57 | if (security_module) | |
| 58 | return 1; /* already initialised */ | |
| 59 | ||
| 60 | security_module = LoadLibrary("secur32.dll"); | |
| 61 | if (security_module) { | |
| 62 | GET_SSPI_FUNCTION(security_module, AcquireCredentialsHandleA); | |
| 63 | GET_SSPI_FUNCTION(security_module, InitializeSecurityContextA); | |
| 64 | GET_SSPI_FUNCTION(security_module, FreeContextBuffer); | |
| 65 | GET_SSPI_FUNCTION(security_module, FreeCredentialsHandle); | |
| 66 | GET_SSPI_FUNCTION(security_module, DeleteSecurityContext); | |
| 67 | GET_SSPI_FUNCTION(security_module, QueryContextAttributesA); | |
| 68 | GET_SSPI_FUNCTION(security_module, MakeSignature); | |
| 69 | return 1; | |
| 70 | } | |
| 71 | return 0; | |
| 72 | } | |
| 73 | ||
| 74 | Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) | |
| 75 | { | |
| 76 | *mech = gss_mech_krb5; | |
| 77 | return SSH_GSS_OK; | |
| 78 | } | |
| 79 | ||
| 80 | ||
| 81 | Ssh_gss_stat ssh_gss_import_name(char *host, Ssh_gss_name *srv_name) | |
| 82 | { | |
| 83 | char *pStr; | |
| 84 | ||
| 85 | /* Check hostname */ | |
| 86 | if (host == NULL) return SSH_GSS_FAILURE; | |
| 87 | ||
| 88 | /* copy it into form host/FQDN */ | |
| 89 | pStr = dupcat("host/", host, NULL); | |
| 90 | ||
| 91 | *srv_name = (Ssh_gss_name) pStr; | |
| 92 | ||
| 93 | return SSH_GSS_OK; | |
| 94 | } | |
| 95 | ||
| 96 | Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) | |
| 97 | { | |
| 98 | winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx); | |
| 99 | ||
| 100 | /* prepare our "wrapper" structure */ | |
| 101 | winctx->maj_stat = winctx->min_stat = SEC_E_OK; | |
| 102 | winctx->context_handle = NULL; | |
| 103 | ||
| 104 | /* Specifying no principal name here means use the credentials of | |
| 105 | the current logged-in user */ | |
| 106 | ||
| 107 | winctx->maj_stat = p_AcquireCredentialsHandleA(NULL, | |
| 108 | "Kerberos", | |
| 109 | SECPKG_CRED_OUTBOUND, | |
| 110 | NULL, | |
| 111 | NULL, | |
| 112 | NULL, | |
| 113 | NULL, | |
| 114 | &winctx->cred_handle, | |
| 115 | &winctx->expiry); | |
| 116 | ||
| 117 | if (winctx->maj_stat != SEC_E_OK) return SSH_GSS_FAILURE; | |
| 118 | ||
| 119 | *ctx = (Ssh_gss_ctx) winctx; | |
| 120 | return SSH_GSS_OK; | |
| 121 | } | |
| 122 | ||
| 123 | ||
| 124 | Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, | |
| 125 | Ssh_gss_name srv_name, | |
| 126 | int to_deleg, | |
| 127 | Ssh_gss_buf *recv_tok, | |
| 128 | Ssh_gss_buf *send_tok) | |
| 129 | { | |
| 130 | winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx; | |
| 131 | SecBuffer wsend_tok = {send_tok->len,SECBUFFER_TOKEN,send_tok->data}; | |
| 132 | SecBuffer wrecv_tok = {recv_tok->len,SECBUFFER_TOKEN,recv_tok->data}; | |
| 133 | SecBufferDesc output_desc={SECBUFFER_VERSION,1,&wsend_tok}; | |
| 134 | SecBufferDesc input_desc ={SECBUFFER_VERSION,1,&wrecv_tok}; | |
| 135 | unsigned long flags=ISC_REQ_MUTUAL_AUTH|ISC_REQ_REPLAY_DETECT| | |
| 136 | ISC_REQ_CONFIDENTIALITY|ISC_REQ_ALLOCATE_MEMORY; | |
| 137 | unsigned long ret_flags=0; | |
| 138 | ||
| 139 | /* check if we have to delegate ... */ | |
| 140 | if (to_deleg) flags |= ISC_REQ_DELEGATE; | |
| 141 | winctx->maj_stat = p_InitializeSecurityContextA(&winctx->cred_handle, | |
| 142 | winctx->context_handle, | |
| 143 | (char*) srv_name, | |
| 144 | flags, | |
| 145 | 0, /* reserved */ | |
| 146 | SECURITY_NATIVE_DREP, | |
| 147 | &input_desc, | |
| 148 | 0, /* reserved */ | |
| 149 | &winctx->context, | |
| 150 | &output_desc, | |
| 151 | &ret_flags, | |
| 152 | &winctx->expiry); | |
| 153 | ||
| 154 | /* prepare for the next round */ | |
| 155 | winctx->context_handle = &winctx->context; | |
| 156 | send_tok->data = (char*) wsend_tok.pvBuffer; | |
| 157 | send_tok->len = wsend_tok.cbBuffer; | |
| 158 | ||
| 159 | /* check & return our status */ | |
| 160 | if (winctx->maj_stat==SEC_E_OK) return SSH_GSS_S_COMPLETE; | |
| 161 | if (winctx->maj_stat==SEC_I_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; | |
| 162 | ||
| 163 | return SSH_GSS_FAILURE; | |
| 164 | } | |
| 165 | ||
| 166 | Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok) | |
| 167 | { | |
| 168 | /* check input */ | |
| 169 | if (send_tok == NULL) return SSH_GSS_FAILURE; | |
| 170 | ||
| 171 | /* free Windows buffer */ | |
| 172 | p_FreeContextBuffer(send_tok->data); | |
| 173 | send_tok->len = 0; send_tok->data = NULL; | |
| 174 | ||
| 175 | return SSH_GSS_OK; | |
| 176 | } | |
| 177 | ||
| 178 | Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx) | |
| 179 | { | |
| 180 | winSsh_g |