| 1 | #include "putty.h" |
| 2 | |
| 3 | #include <string.h> |
| 4 | #include "sshgssc.h" |
| 5 | #include "misc.h" |
| 6 | |
| 7 | #ifndef NO_GSSAPI |
| 8 | |
| 9 | static Ssh_gss_stat ssh_gssapi_indicate_mech(struct ssh_gss_library *lib, |
| 10 | Ssh_gss_buf *mech) |
| 11 | { |
| 12 | /* Copy constant into mech */ |
| 13 | mech->length = GSS_MECH_KRB5->length; |
| 14 | mech->value = GSS_MECH_KRB5->elements; |
| 15 | return SSH_GSS_OK; |
| 16 | } |
| 17 | |
| 18 | static Ssh_gss_stat ssh_gssapi_import_name(struct ssh_gss_library *lib, |
| 19 | char *host, |
| 20 | Ssh_gss_name *srv_name) |
| 21 | { |
| 22 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 23 | OM_uint32 min_stat,maj_stat; |
| 24 | gss_buffer_desc host_buf; |
| 25 | char *pStr; |
| 26 | |
| 27 | pStr = dupcat("host@", host, NULL); |
| 28 | |
| 29 | host_buf.value = pStr; |
| 30 | host_buf.length = strlen(pStr); |
| 31 | |
| 32 | maj_stat = gss->import_name(&min_stat, &host_buf, |
| 33 | GSS_C_NT_HOSTBASED_SERVICE, srv_name); |
| 34 | /* Release buffer */ |
| 35 | sfree(pStr); |
| 36 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
| 37 | return SSH_GSS_FAILURE; |
| 38 | } |
| 39 | |
| 40 | static Ssh_gss_stat ssh_gssapi_acquire_cred(struct ssh_gss_library *lib, |
| 41 | Ssh_gss_ctx *ctx) |
| 42 | { |
| 43 | gssapi_ssh_gss_ctx *gssctx = snew(gssapi_ssh_gss_ctx); |
| 44 | |
| 45 | gssctx->maj_stat = gssctx->min_stat = GSS_S_COMPLETE; |
| 46 | gssctx->ctx = GSS_C_NO_CONTEXT; |
| 47 | *ctx = (Ssh_gss_ctx) gssctx; |
| 48 | |
| 49 | return SSH_GSS_OK; |
| 50 | } |
| 51 | |
| 52 | static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib, |
| 53 | Ssh_gss_ctx *ctx, |
| 54 | Ssh_gss_name srv_name, |
| 55 | int to_deleg, |
| 56 | Ssh_gss_buf *recv_tok, |
| 57 | Ssh_gss_buf *send_tok) |
| 58 | { |
| 59 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 60 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx*) *ctx; |
| 61 | OM_uint32 ret_flags; |
| 62 | |
| 63 | if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; |
| 64 | gssctx->maj_stat = gss->init_sec_context(&gssctx->min_stat, |
| 65 | GSS_C_NO_CREDENTIAL, |
| 66 | &gssctx->ctx, |
| 67 | srv_name, |
| 68 | (gss_OID) GSS_MECH_KRB5, |
| 69 | GSS_C_MUTUAL_FLAG | |
| 70 | GSS_C_INTEG_FLAG | to_deleg, |
| 71 | 0, |
| 72 | GSS_C_NO_CHANNEL_BINDINGS, |
| 73 | recv_tok, |
| 74 | NULL, /* ignore mech type */ |
| 75 | send_tok, |
| 76 | &ret_flags, |
| 77 | NULL); /* ignore time_rec */ |
| 78 | |
| 79 | if (gssctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; |
| 80 | if (gssctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; |
| 81 | return SSH_GSS_FAILURE; |
| 82 | } |
| 83 | |
| 84 | static Ssh_gss_stat ssh_gssapi_display_status(struct ssh_gss_library *lib, |
| 85 | Ssh_gss_ctx ctx, |
| 86 | Ssh_gss_buf *buf) |
| 87 | { |
| 88 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 89 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; |
| 90 | OM_uint32 lmin,lmax; |
| 91 | OM_uint32 ccc; |
| 92 | gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; |
| 93 | gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; |
| 94 | |
| 95 | /* Return empty buffer in case of failure */ |
| 96 | SSH_GSS_CLEAR_BUF(buf); |
| 97 | |
| 98 | /* get first mesg from GSS */ |
| 99 | ccc=0; |
| 100 | lmax=gss->display_status(&lmin,gssctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_maj); |
| 101 | |
| 102 | if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; |
| 103 | |
| 104 | /* get first mesg from Kerberos */ |
| 105 | ccc=0; |
| 106 | lmax=gss->display_status(&lmin,gssctx->min_stat,GSS_C_MECH_CODE,(gss_OID) GSS_MECH_KRB5,&ccc,&msg_min); |
| 107 | |
| 108 | if (lmax != GSS_S_COMPLETE) { |
| 109 | gss->release_buffer(&lmin, &msg_maj); |
| 110 | return SSH_GSS_FAILURE; |
| 111 | } |
| 112 | |
| 113 | /* copy data into buffer */ |
| 114 | buf->length = msg_maj.length + msg_min.length + 1; |
| 115 | buf->value = snewn(buf->length + 1, char); |
| 116 | |
| 117 | /* copy mem */ |
| 118 | memcpy((char *)buf->value, msg_maj.value, msg_maj.length); |
| 119 | ((char *)buf->value)[msg_maj.length] = ' '; |
| 120 | memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length); |
| 121 | ((char *)buf->value)[buf->length] = 0; |
| 122 | /* free mem & exit */ |
| 123 | gss->release_buffer(&lmin, &msg_maj); |
| 124 | gss->release_buffer(&lmin, &msg_min); |
| 125 | return SSH_GSS_OK; |
| 126 | } |
| 127 | |
| 128 | static Ssh_gss_stat ssh_gssapi_free_tok(struct ssh_gss_library *lib, |
| 129 | Ssh_gss_buf *send_tok) |
| 130 | { |
| 131 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 132 | OM_uint32 min_stat,maj_stat; |
| 133 | maj_stat = gss->release_buffer(&min_stat, send_tok); |
| 134 | |
| 135 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
| 136 | return SSH_GSS_FAILURE; |
| 137 | } |
| 138 | |
| 139 | static Ssh_gss_stat ssh_gssapi_release_cred(struct ssh_gss_library *lib, |
| 140 | Ssh_gss_ctx *ctx) |
| 141 | { |
| 142 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 143 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) *ctx; |
| 144 | OM_uint32 min_stat; |
| 145 | OM_uint32 maj_stat=GSS_S_COMPLETE; |
| 146 | |
| 147 | if (gssctx == NULL) return SSH_GSS_FAILURE; |
| 148 | if (gssctx->ctx != GSS_C_NO_CONTEXT) |
| 149 | maj_stat = gss->delete_sec_context(&min_stat,&gssctx->ctx,GSS_C_NO_BUFFER); |
| 150 | sfree(gssctx); |
| 151 | |
| 152 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
| 153 | return SSH_GSS_FAILURE; |
| 154 | } |
| 155 | |
| 156 | |
| 157 | static Ssh_gss_stat ssh_gssapi_release_name(struct ssh_gss_library *lib, |
| 158 | Ssh_gss_name *srv_name) |
| 159 | { |
| 160 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 161 | OM_uint32 min_stat,maj_stat; |
| 162 | maj_stat = gss->release_name(&min_stat, srv_name); |
| 163 | |
| 164 | if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; |
| 165 | return SSH_GSS_FAILURE; |
| 166 | } |
| 167 | |
| 168 | static Ssh_gss_stat ssh_gssapi_get_mic(struct ssh_gss_library *lib, |
| 169 | Ssh_gss_ctx ctx, Ssh_gss_buf *buf, |
| 170 | Ssh_gss_buf *hash) |
| 171 | { |
| 172 | struct gssapi_functions *gss = &lib->u.gssapi; |
| 173 | gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; |
| 174 | if (gssctx == NULL) return SSH_GSS_FAILURE; |
| 175 | return gss->get_mic(&(gssctx->min_stat), gssctx->ctx, 0, buf, hash); |
| 176 | } |
| 177 | |
| 178 | static Ssh_gss_stat ssh_gssapi_free_mic(struct ssh_gss_library *lib, |
| 179 | Ssh_gss_buf *hash) |
| 180 | { |
| 181 | /* On Unix this is the same freeing process as ssh_gssapi_free_tok. */ |
| 182 | return ssh_gssapi_free_tok(lib, hash); |
| 183 | } |
| 184 | |
| 185 | void ssh_gssapi_bind_fns(struct ssh_gss_library *lib) |
| 186 | { |
| 187 | lib->indicate_mech = ssh_gssapi_indicate_mech; |
| 188 | lib->import_name = ssh_gssapi_import_name; |
| 189 | lib->release_name = ssh_gssapi_release_name; |
| 190 | lib->init_sec_context = ssh_gssapi_init_sec_context; |
| 191 | lib->free_tok = ssh_gssapi_free_tok; |
| 192 | lib->acquire_cred = ssh_gssapi_acquire_cred; |
| 193 | lib->release_cred = ssh_gssapi_release_cred; |
| 194 | lib->get_mic = ssh_gssapi_get_mic; |
| 195 | lib->free_mic = ssh_gssapi_free_mic; |
| 196 | lib->display_status = ssh_gssapi_display_status; |
| 197 | } |
| 198 | |
| 199 | #else |
| 200 | |
| 201 | /* Dummy function so this source file defines something if NO_GSSAPI |
| 202 | is defined. */ |
| 203 | |
| 204 | int ssh_gssapi_init(void) |
| 205 | { |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | #endif |