int gssd_acquire_cred(char *server_name, const gss_OID oid) { gss_buffer_desc name; gss_name_t target_name; u_int32_t maj_stat, min_stat; u_int32_t ignore_maj_stat, ignore_min_stat; gss_buffer_desc pbuf; /* If server_name is NULL, get cred for GSS_C_NO_NAME */ if (server_name == NULL) { target_name = GSS_C_NO_NAME; } else { name.value = (void *)server_name; name.length = strlen(server_name); maj_stat = gss_import_name(&min_stat, &name, oid, &target_name); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); return (FALSE); } } maj_stat = gss_acquire_cred(&min_stat, target_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &gssd_creds, NULL, NULL); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_acquire_cred", maj_stat, min_stat, g_mechOid); ignore_maj_stat = gss_display_name(&ignore_min_stat, target_name, &pbuf, NULL); if (ignore_maj_stat == GSS_S_COMPLETE) { printerr(1, "Unable to obtain credentials for '%.*s'\n", pbuf.length, pbuf.value); ignore_maj_stat = gss_release_buffer(&ignore_min_stat, &pbuf); } } ignore_maj_stat = gss_release_name(&ignore_min_stat, &target_name); return (maj_stat == GSS_S_COMPLETE); }
int svcgssd_limit_krb5_enctypes(void) { u_int maj_stat, min_stat; krb5_enctype old_kernel_enctypes[] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4 }; krb5_enctype new_kernel_enctypes[] = { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96, ENCTYPE_DES3_CBC_SHA1, ENCTYPE_ARCFOUR_HMAC, ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4 }; krb5_enctype *default_enctypes, *enctypes; int default_num_enctypes, num_enctypes; if (linux_version_code() < MAKE_VERSION(2, 6, 35)) { default_enctypes = old_kernel_enctypes; default_num_enctypes = sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]); } else { default_enctypes = new_kernel_enctypes; default_num_enctypes = sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]); } get_kernel_supported_enctypes(); if (parsed_enctypes != NULL) { enctypes = parsed_enctypes; num_enctypes = parsed_num_enctypes; printerr(2, "%s: Calling gss_set_allowable_enctypes with %d " "enctypes from the kernel\n", __func__, num_enctypes); } else { enctypes = default_enctypes; num_enctypes = default_num_enctypes; printerr(2, "%s: Calling gss_set_allowable_enctypes with %d " "enctypes from defaults\n", __func__, num_enctypes); } maj_stat = set_allowable_enctypes(&min_stat, gssd_creds, &krb5oid, num_enctypes, enctypes); if (maj_stat != GSS_S_COMPLETE) { printerr(1, "WARNING: gss_set_allowable_enctypes failed\n"); pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes", maj_stat, min_stat, &krb5oid); return -1; } return 0; }
int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) { u_int maj_stat, min_stat; gss_cred_id_t credh; gss_OID_set_desc desired_mechs; krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4 }; int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); /* We only care about getting a krb5 cred */ desired_mechs.count = 1; desired_mechs.elements = &krb5oid; maj_stat = gss_acquire_cred(&min_stat, NULL, 0, &desired_mechs, GSS_C_INITIATE, &credh, NULL, NULL); if (maj_stat != GSS_S_COMPLETE) { if (get_verbosity() > 0) pgsserr("gss_acquire_cred", maj_stat, min_stat, &krb5oid); return -1; } maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, num_enctypes, &enctypes); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_set_allowable_enctypes", maj_stat, min_stat, &krb5oid); gss_release_cred(&min_stat, &credh); return -1; } sec->cred = credh; return 0; }
static int get_hostbased_client_name(gss_name_t client_name, gss_OID mech, char **hostbased_name) { u_int32_t maj_stat, min_stat; gss_buffer_desc name; gss_OID name_type = GSS_C_NO_OID; char *cname; int res = -1; *hostbased_name = NULL; /* preset in case we fail */ /* Get the client's gss authenticated name */ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); if (maj_stat != GSS_S_COMPLETE) { pgsserr("get_hostbased_client_name: gss_display_name", maj_stat, min_stat, mech); goto out_err; } if (name.length >= 0xffff) { /* don't overflow */ printerr(0, "ERROR: get_hostbased_client_name: " "received gss_name is too long (%d bytes)\n", name.length); goto out_rel_buf; } /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to * an NT_HOSTBASED_SERVICE name */ if (g_OID_equal(&krb5oid, mech)) { if (get_krb5_hostbased_name(&name, &cname) == 0) *hostbased_name = cname; } /* No support for SPKM3, just print a warning (for now) */ if (g_OID_equal(&spkm3oid, mech)) { printerr(1, "WARNING: get_hostbased_client_name: " "no hostbased_name support for SPKM3\n"); } res = 0; out_rel_buf: gss_release_buffer(&min_stat, &name); out_err: return res; }
int serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) { OM_uint32 maj_stat, min_stat; void *return_ctx = 0; OM_uint32 vers; gss_krb5_lucid_context_v1_t *lctx = 0; int retcode = 0; printerr(3, "lucid version!\n"); maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, 1, &return_ctx); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_export_lucid_sec_context", maj_stat, min_stat, &krb5oid); goto out_err; } /* Check the version returned, we only support v1 right now */ vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version; switch (vers) { case 1: lctx = (gss_krb5_lucid_context_v1_t *) return_ctx; break; default: printerr(0, "ERROR: unsupported lucid sec context version %d\n", vers); goto out_err; break; } /* * Now lctx points to a lucid context that we can send down to kernel * * Note: we send down different information to the kernel depending * on the protocol version and the enctyption type. * For protocol version 0 with all enctypes besides DES3, we use * the original format. For protocol version != 0 or DES3, we * send down the new style information. */ if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4) retcode = prepare_krb5_rfc1964_buffer(lctx, buf); else retcode = prepare_krb5_rfc4121_buffer(lctx, buf); maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_export_lucid_sec_context", maj_stat, min_stat, &krb5oid); printerr(0, "WARN: failed to free lucid sec context\n"); } if (retcode) { printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n", __FUNCTION__, retcode); goto out_err; } return 0; out_err: printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); return -1; }
static int get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) { u_int32_t maj_stat, min_stat; gss_buffer_desc name; char *sname; int res = -1; uid_t uid, gid; gss_OID name_type = GSS_C_NO_OID; char *secname; maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); if (maj_stat != GSS_S_COMPLETE) { pgsserr("get_ids: gss_display_name", maj_stat, min_stat, mech); goto out; } if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */ !(sname = calloc(name.length + 1, 1))) { printerr(0, "WARNING: get_ids: error allocating %d bytes " "for sname\n", name.length + 1); gss_release_buffer(&min_stat, &name); goto out; } memcpy(sname, name.value, name.length); printerr(1, "sname = %s\n", sname); gss_release_buffer(&min_stat, &name); res = -EINVAL; if ((secname = mech2file(mech)) == NULL) { printerr(0, "WARNING: get_ids: error mapping mech to " "file for name '%s'\n", sname); goto out_free; } nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid); if (res < 0) { /* * -ENOENT means there was no mapping, any other error * value means there was an error trying to do the * mapping. * If there was no mapping, we send down the value -1 * to indicate that the anonuid/anongid for the export * should be used. */ if (res == -ENOENT) { cred->cr_uid = -1; cred->cr_gid = -1; cred->cr_ngroups = 0; res = 0; goto out_free; } printerr(1, "WARNING: get_ids: failed to map name '%s' " "to uid/gid: %s\n", sname, strerror(-res)); goto out_free; } cred->cr_uid = uid; cred->cr_gid = gid; add_supplementary_groups(secname, sname, cred); res = 0; out_free: free(sname); out: return res; }