X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/23e4df365f332a92d97fae27212b2cf777d5b8e0..b3d375b244187cd77f45dc013668e6273e133179:/unix/uxgss.c diff --git a/unix/uxgss.c b/unix/uxgss.c index 7bc6dca4..b8fb0b07 100644 --- a/unix/uxgss.c +++ b/unix/uxgss.c @@ -1,197 +1,118 @@ #include "putty.h" - #ifndef NO_GSSAPI - -#include -#include +#include "pgssapi.h" #include "sshgss.h" -#include "misc.h" - -static gss_OID_desc putty_gss_mech_krb5_desc = - { 9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; -static gss_OID const putty_gss_mech_krb5 = &putty_gss_mech_krb5_desc; - -typedef struct uxSsh_gss_ctx { - OM_uint32 maj_stat; - OM_uint32 min_stat; - gss_ctx_id_t ctx; -} uxSsh_gss_ctx; - -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; -} - -Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) +#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) { - /* Copy constant into mech */ - mech->length = putty_gss_mech_krb5->length; - mech->value = putty_gss_mech_krb5->elements; + lib->id = id; + lib->gsslogmsg = msg; - return SSH_GSS_OK; -} +#define BIND_GSS_FN(name) \ + lib->u.gssapi.name = (t_gss_##name) dlsym(dlhandle, "gss_" #name) -Ssh_gss_stat ssh_gss_import_name(char *host, - Ssh_gss_name *srv_name) -{ - OM_uint32 min_stat,maj_stat; - gss_buffer_desc host_buf; - char *pStr; + 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); - pStr = dupcat("host@", host, NULL); +#undef BIND_GSS_FN - host_buf.value = pStr; - host_buf.length = strlen(pStr); - - maj_stat = gss_import_name(&min_stat, &host_buf, - GSS_C_NT_HOSTBASED_SERVICE, srv_name); - /* Release buffer */ - sfree(pStr); - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; + ssh_gssapi_bind_fns(lib); } -Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) +/* Dynamically load gssapi libs. */ +void ssh_gss_init(void) { - uxSsh_gss_ctx *uxctx = snew(uxSsh_gss_ctx); + void *gsslib; - uxctx->maj_stat = uxctx->min_stat = GSS_S_COMPLETE; - uxctx->ctx = GSS_C_NO_CONTEXT; - *ctx = (Ssh_gss_ctx) uxctx; + if (initialised) return; + initialised = TRUE; - return SSH_GSS_OK; -} + /* 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"); -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, - srv_name, - (gss_OID) putty_gss_mech_krb5, - GSS_C_MUTUAL_FLAG | - GSS_C_INTEG_FLAG | to_deleg, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - recv_tok, - NULL, /* ignore mech type */ - 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; -} + /* 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_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) putty_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) putty_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->length = msg_maj.length + msg_min.length + 1; - buf->value = snewn(buf->length + 1, char); - - /* copy mem */ - memcpy((char *)buf->value, msg_maj.value, msg_maj.length); - ((char *)buf->value)[msg_maj.length] = ' '; - memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length); - ((char *)buf->value)[buf->length] = 0; - /* free mem & exit */ - gss_release_buffer(&lmin, &msg_maj); - gss_release_buffer(&lmin, &msg_min); - return SSH_GSS_OK; + /* 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_free_tok(Ssh_gss_buf *send_tok) -{ - OM_uint32 min_stat,maj_stat; - maj_stat = gss_release_buffer(&min_stat, send_tok); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} +#else /* NO_LIBDL */ -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, 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, buf, 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 */