X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/42af6a672d16302ee1b8971a7cc164120f7572ab..ce3262cf6ddf5908eced52424c07682795f9523b:/unix/uxgss.c diff --git a/unix/uxgss.c b/unix/uxgss.c index 5e59ed76..b8fb0b07 100644 --- a/unix/uxgss.c +++ b/unix/uxgss.c @@ -1,196 +1,118 @@ +#include "putty.h" #ifndef NO_GSSAPI - -#include -#include +#include "pgssapi.h" #include "sshgss.h" -#include "misc.h" +#include "sshgssc.h" + +/* Unix code to set up the GSSAPI library list. */ + +struct ssh_gss_library ssh_gss_libraries[3]; +int n_ssh_gss_libraries = 0; +static int initialised = FALSE; + +const int ngsslibs = 3; +const char *const gsslibnames[3] = { + "libgssapi (Heimdal)", + "libgssapi_krb5 (MIT Kerberos)", + "libgss (Sun)", +}; +const struct keyval gsslibkeywords[] = { + { "libgssapi", 0 }, + { "libgssapi_krb5", 1 }, + { "libgss", 2 }, +}; + +#ifndef NO_LIBDL + +/* + * Run-time binding against a choice of GSSAPI implementations. We + * try loading several libraries, and produce an entry in + * ssh_gss_libraries[] for each one. + */ + +static void gss_init(struct ssh_gss_library *lib, void *dlhandle, + int id, const char *msg) +{ + lib->id = id; + lib->gsslogmsg = msg; -typedef struct uxSsh_gss_ctx { - OM_uint32 maj_stat; - OM_uint32 min_stat; - gss_ctx_id_t ctx; -} uxSsh_gss_ctx; +#define BIND_GSS_FN(name) \ + lib->u.gssapi.name = (t_gss_##name) dlsym(dlhandle, "gss_" #name) -int ssh_gss_init(void) -{ - /* On Windows this tries to load the SSPI library functions. On - Unix we assume we have GSSAPI at runtime if we were linked with - it at compile time */ - return 1; -} + BIND_GSS_FN(delete_sec_context); + BIND_GSS_FN(display_status); + BIND_GSS_FN(get_mic); + BIND_GSS_FN(import_name); + BIND_GSS_FN(init_sec_context); + BIND_GSS_FN(release_buffer); + BIND_GSS_FN(release_cred); + BIND_GSS_FN(release_name); -Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) -{ - /* Copy constant into mech */ - mech->len = gss_mech_krb5->length; - mech->data = gss_mech_krb5->elements; +#undef BIND_GSS_FN - return SSH_GSS_OK; + ssh_gssapi_bind_fns(lib); } -Ssh_gss_stat ssh_gss_import_name(char *host, - Ssh_gss_name *srv_name) +/* Dynamically load gssapi libs. */ +void ssh_gss_init(void) { - OM_uint32 min_stat,maj_stat; - gss_buffer_desc host_buf; - char *pStr; - - pStr = dupcat("host@", host, NULL); - - host_buf.value = pStr; - host_buf.length = strlen(pStr); - - maj_stat = gss_import_name(&min_stat, &host_buf, - GSS_C_NT_HOSTBASED_SERVICE, - (gss_name_t *)srv_name); - /* Release buffer */ - sfree(pStr); - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} + void *gsslib; -Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) -{ - uxSsh_gss_ctx *uxctx = snew(uxSsh_gss_ctx); + if (initialised) return; + initialised = TRUE; - uxctx->maj_stat = uxctx->min_stat = GSS_S_COMPLETE; - uxctx->ctx = GSS_C_NO_CONTEXT; - *ctx = (Ssh_gss_ctx) uxctx; + /* Heimdal's GSSAPI Library */ + if ((gsslib = dlopen("libgssapi.so.2", RTLD_LAZY)) != NULL) + gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib, + 0, "Using GSSAPI from libgssapi.so.2"); - return SSH_GSS_OK; -} + /* MIT Kerberos's GSSAPI Library */ + if ((gsslib = dlopen("libgssapi_krb5.so.2", RTLD_LAZY)) != NULL) + gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib, + 1, "Using GSSAPI from libgssapi_krb5.so.2"); -Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, - Ssh_gss_name srv_name, - int to_deleg, - Ssh_gss_buf *recv_tok, - Ssh_gss_buf *send_tok) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx*) *ctx; - OM_uint32 ret_flags; - - if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; - uxctx->maj_stat = gss_init_sec_context(&uxctx->min_stat, - GSS_C_NO_CREDENTIAL, - &uxctx->ctx, - (gss_name_t) srv_name, - (gss_OID) gss_mech_krb5, - GSS_C_MUTUAL_FLAG | - GSS_C_INTEG_FLAG | to_deleg, - 0, - NULL, /* no channel bindings */ - (gss_buffer_desc *)recv_tok, - NULL, /* ignore mech type */ - (gss_buffer_desc *)send_tok, - &ret_flags, - NULL); /* ignore time_rec */ - - if (uxctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; - if (uxctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; - return SSH_GSS_FAILURE; + /* Sun's GSSAPI Library */ + if ((gsslib = dlopen("libgss.so.1", RTLD_LAZY)) != NULL) + gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib, + 2, "Using GSSAPI from libgss.so.1"); } -Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; - OM_uint32 lmin,lmax; - OM_uint32 ccc; - gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; - gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; - - /* Return empty buffer in case of failure */ - SSH_GSS_CLEAR_BUF(buf); - - /* get first mesg from GSS */ - ccc=0; - lmax=gss_display_status(&lmin,uxctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) gss_mech_krb5,&ccc,&msg_maj); - - if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; - - /* get first mesg from Kerberos */ - ccc=0; - lmax=gss_display_status(&lmin,uxctx->min_stat,GSS_C_MECH_CODE,(gss_OID) gss_mech_krb5,&ccc,&msg_min); - - if (lmax != GSS_S_COMPLETE) { - gss_release_buffer(&lmin, &msg_maj); - return SSH_GSS_FAILURE; - } - - /* copy data into buffer */ - buf->len = msg_maj.length + msg_min.length + 1; - buf->data = snewn(buf->len + 1, char); - - /* copy mem */ - memcpy(buf->data, msg_maj.value, msg_maj.length); - buf->data[msg_maj.length] = ' '; - memcpy(buf->data + msg_maj.length + 1, msg_min.value, msg_min.length); - buf->data[buf->len] = 0; - /* free mem & exit */ - gss_release_buffer(&lmin, &msg_maj); - gss_release_buffer(&lmin, &msg_min); - return SSH_GSS_OK; -} +#else /* NO_LIBDL */ -Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok) -{ - OM_uint32 min_stat,maj_stat; - maj_stat = gss_release_buffer(&min_stat, (gss_buffer_desc *)send_tok); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} - -Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) *ctx; - OM_uint32 min_stat; - OM_uint32 maj_stat=GSS_S_COMPLETE; - - if (uxctx == NULL) return SSH_GSS_FAILURE; - if (uxctx->ctx != GSS_C_NO_CONTEXT) - maj_stat = gss_delete_sec_context(&min_stat,&uxctx->ctx,GSS_C_NO_BUFFER); - sfree(uxctx); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} +/* + * Link-time binding against GSSAPI. Here we just construct a single + * library structure containing pointers to the functions we linked + * against. + */ +#include -Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name) +/* Dynamically load gssapi libs. */ +void ssh_gss_init(void) { - OM_uint32 min_stat,maj_stat; - maj_stat = gss_release_name(&min_stat, (gss_name_t) srv_name); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} + if (initialised) return; + initialised = TRUE; -Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf, - Ssh_gss_buf *hash) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; - if (uxctx == NULL) return SSH_GSS_FAILURE; - return gss_get_mic(&(uxctx->min_stat), - uxctx->ctx, - 0, - (gss_buffer_desc *)buf, - (gss_buffer_desc *)hash); -} + n_ssh_gss_libraries = 1; + ssh_gss_libraries[0].gsslogmsg = "Using statically linked GSSAPI"; -Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash) -{ - /* On Unix this is the same freeing process as ssh_gss_free_tok. */ - return ssh_gss_free_tok(hash); -} +#define BIND_GSS_FN(name) \ + ssh_gss_libraries[0].u.gssapi.name = (t_gss_##name) gss_##name -#else + BIND_GSS_FN(delete_sec_context); + BIND_GSS_FN(display_status); + BIND_GSS_FN(get_mic); + BIND_GSS_FN(import_name); + BIND_GSS_FN(init_sec_context); + BIND_GSS_FN(release_buffer); + BIND_GSS_FN(release_cred); + BIND_GSS_FN(release_name); -/* Dummy function so this source file defines something if NO_GSSAPI - is defined. */ +#undef BIND_GSS_FN -int ssh_gss_init(void) -{ - return 1; + ssh_gssapi_bind_fns(&ssh_gss_libraries[0]); } -#endif +#endif /* NO_LIBDL */ + +#endif /* NO_GSSAPI */