/* Create a service name for the given host */ OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { gss_buffer_desc gssbuf; char *xhost; char *val; /* Make a copy of the host name, in case it was returned by a * previous call to gethostbyname(). */ xhost = xstrdup(host); /* Make sure we have the FQDN. Some GSSAPI implementations don't do * this for us themselves */ resolve_localhost(&xhost); xasprintf(&val, "host@%s", xhost); gssbuf.value = val; gssbuf.length = strlen(gssbuf.value); if ((ctx->major = gss_import_name(&ctx->minor, &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) ssh_gssapi_error(ctx); free(xhost); free(gssbuf.value); return (ctx->major); }
OM_uint32 ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) { gss_buffer_desc gssbuf; gss_name_t gssname; OM_uint32 status; gss_OID_set oidset; gssbuf.value = (void *) name; gssbuf.length = strlen(gssbuf.value); gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); ctx->major = gss_import_name(&ctx->minor, &gssbuf, GSS_C_NT_USER_NAME, &gssname); if (!ctx->major) ctx->major = gss_acquire_cred(&ctx->minor, gssname, 0, oidset, GSS_C_INITIATE, &ctx->client_creds, NULL, NULL); gss_release_name(&status, &gssname); gss_release_oid_set(&status, &oidset); if (ctx->major) ssh_gssapi_error(ctx); return(ctx->major); }
/* Privileged */ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags) { OM_uint32 status; gss_OID mech; ctx->major = gss_accept_sec_context(&ctx->minor, &ctx->context, ctx->creds, recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech, send_tok, flags, NULL, &ctx->client_creds); if (GSS_ERROR(ctx->major)) ssh_gssapi_error(ctx); if (ctx->client_creds) debug("Received some client credentials"); else debug("Got no client credentials"); status = ctx->major; /* Now, if we're complete and we have the right flags, then * we flag the user as also having been authenticated */ if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { if (ssh_gssapi_getclient(ctx, &gssapi_client)) fatal("Couldn't convert client name"); } return (status); }
/* Privileged (called from ssh_gssapi_server_ctx) */ static OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx) { OM_uint32 status; char lname[NI_MAXHOST]; gss_OID_set oidset; if (options.gss_strict_acceptor) { gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); if (gethostname(lname, MAXHOSTNAMELEN)) { gss_release_oid_set(&status, &oidset); return (-1); } if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { gss_release_oid_set(&status, &oidset); return (ctx->major); } if ((ctx->major = gss_acquire_cred(&ctx->minor, ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) ssh_gssapi_error(ctx); gss_release_oid_set(&status, &oidset); return (ctx->major); } else { ctx->name = GSS_C_NO_NAME; ctx->creds = GSS_C_NO_CREDENTIAL; } return GSS_S_COMPLETE; }
/* Privileged (called from ssh_gssapi_server_ctx) */ static OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx) { OM_uint32 status; char lname[NI_MAXHOST]; gss_OID_set oidset; gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); if (gethostname(lname, sizeof(lname))) { gss_release_oid_set(&status, &oidset); return (-1); } if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { gss_release_oid_set(&status, &oidset); return (ctx->major); } if ((ctx->major = gss_acquire_cred(&ctx->minor, ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) ssh_gssapi_error(ctx); gss_release_oid_set(&status, &oidset); return (ctx->major); }
/* * Wrapper to init_sec_context. Requires that the context contains: * * oid * server name (from ssh_gssapi_import_name) */ OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds, gss_buffer_t recv_tok, gss_buffer_t send_tok) { int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host, deleg_creds, recv_tok, send_tok); if (deleg_creds) { flags |= GSS_C_DELEG_FLAG; debug("Delegating GSS-API credentials"); } /* Build target principal */ if (ctx->desired_name == GSS_C_NO_NAME && !ssh_gssapi_import_name(ctx, server_host)) { return (ctx->major); } ctx->major = gss_init_sec_context(&ctx->minor, GSS_C_NO_CREDENTIAL, &ctx->context, ctx->desired_name, ctx->desired_mech, flags, 0, /* default lifetime */ NULL, /* no channel bindings */ recv_tok, NULL, /* actual mech type */ send_tok, &ctx->flags, NULL); /* actual lifetime */ if (GSS_ERROR(ctx->major)) ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()"); return (ctx->major); }
OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) { if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); return (ctx->major); }
/* Privileged (called from accept_secure_ctx) */ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; gss_buffer_desc ename; client->mech = NULL; while (supported_mechs[i]->name != NULL) { if (supported_mechs[i]->oid.length == ctx->oid->length && (memcmp(supported_mechs[i]->oid.elements, ctx->oid->elements, ctx->oid->length) == 0)) client->mech = supported_mechs[i]; i++; } if (client->mech == NULL) return GSS_S_FAILURE; if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); return (ctx->major); } if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, &ename))) { ssh_gssapi_error(ctx); return (ctx->major); } if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, &client->exportedname))) { return (ctx->major); } /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; return (ctx->major); }
/* Create a service name for the given host */ OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { gss_buffer_desc gssbuf; gssbuf.length = sizeof("host@") + strlen(host); gssbuf.value = xmalloc(gssbuf.length); snprintf(gssbuf.value, gssbuf.length, "host@%s", host); if ((ctx->major = gss_import_name(&ctx->minor, &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) ssh_gssapi_error(ctx); xfree(gssbuf.value); return (ctx->major); }
/* Create a service name for the given host */ OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { gss_buffer_desc gssbuf; char *val; xasprintf(&val, "host@%s", host); gssbuf.value = val; gssbuf.length = strlen(gssbuf.value); if ((ctx->major = gss_import_name(&ctx->minor, &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) ssh_gssapi_error(ctx); free(gssbuf.value); return (ctx->major); }
/* * Wrapper to init_sec_context * Requires that the context contains: * oid * server name (from ssh_gssapi_import_name) */ OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, gss_buffer_desc* send_tok, OM_uint32 *flags) { int deleg_flag = 0; if (deleg_creds) { deleg_flag = GSS_C_DELEG_FLAG; debug("Delegating credentials"); } ctx->major = gss_init_sec_context(&ctx->minor, GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); if (GSS_ERROR(ctx->major)) ssh_gssapi_error(ctx); return (ctx->major); }
/* Privileged (called from accept_secure_ctx) */ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; int equal = 0; gss_name_t new_name = GSS_C_NO_NAME; gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; if (options.gss_store_rekey && client->used && ctx->client_creds) { if (client->mech->oid.length != ctx->oid->length || (memcmp(client->mech->oid.elements, ctx->oid->elements, ctx->oid->length) !=0)) { debug("Rekeyed credentials have different mechanism"); return GSS_S_COMPLETE; } if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ctx->client_creds, ctx->oid, &new_name, NULL, NULL, NULL))) { ssh_gssapi_error(ctx); return (ctx->major); } ctx->major = gss_compare_name(&ctx->minor, client->name, new_name, &equal); if (GSS_ERROR(ctx->major)) { ssh_gssapi_error(ctx); return (ctx->major); } if (!equal) { debug("Rekeyed credentials have different name"); return GSS_S_COMPLETE; } debug("Marking rekeyed credentials for export"); gss_release_name(&ctx->minor, &client->name); gss_release_cred(&ctx->minor, &client->creds); client->name = new_name; client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; client->updated = 1; return GSS_S_COMPLETE; } client->mech = NULL; while (supported_mechs[i]->name != NULL) { if (supported_mechs[i]->oid.length == ctx->oid->length && (memcmp(supported_mechs[i]->oid.elements, ctx->oid->elements, ctx->oid->length) == 0)) client->mech = supported_mechs[i]; i++; } if (client->mech == NULL) return GSS_S_FAILURE; if (ctx->client_creds && (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { ssh_gssapi_error(ctx); return (ctx->major); } if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); return (ctx->major); } if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, &ename))) { ssh_gssapi_error(ctx); return (ctx->major); } if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, &client->exportedname))) { return (ctx->major); } gss_release_buffer(&ctx->minor, &ename); /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; return (ctx->major); }
/* * Export GSI credentials to disk. */ static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) { OM_uint32 major_status; OM_uint32 minor_status; gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; char * p; if (!client || !client->creds) { return; } major_status = gss_export_cred(&minor_status, client->creds, GSS_C_NO_OID, 1, &export_cred); if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { Gssctxt *ctx; ssh_gssapi_build_ctx(&ctx); ctx->major = major_status; ctx->minor = minor_status; ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid); ssh_gssapi_error(ctx); ssh_gssapi_delete_ctx(&ctx); return; } p = strchr((char *) export_cred.value, '='); if (p == NULL) { logit("Failed to parse exported credentials string '%.100s'", (char *)export_cred.value); gss_release_buffer(&minor_status, &export_cred); return; } *p++ = '\0'; if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { client->store.envvar = strdup("X509_USER_PROXY"); } else { client->store.envvar = strdup((char *)export_cred.value); } if (access(p, R_OK) == 0) { if (client->store.filename) { if (rename(p, client->store.filename) < 0) { logit("Failed to rename %s to %s: %s", p, client->store.filename, strerror(errno)); free(client->store.filename); client->store.filename = strdup(p); } else { p = client->store.filename; } } else { client->store.filename = strdup(p); } } client->store.envval = strdup(p); #ifdef USE_PAM if (options.use_pam) do_pam_putenv(client->store.envvar, client->store.envval); #endif gss_release_buffer(&minor_status, &export_cred); }