| 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 |