krb5_error_code kg_init_name(krb5_context context, krb5_principal principal, krb5_authdata_context ad_context, krb5_flags flags, krb5_gss_name_t *ret_name) { krb5_error_code code; krb5_gss_name_t name; *ret_name = NULL; assert(principal != NULL); if (principal == NULL) return EINVAL; name = xmalloc(sizeof(krb5_gss_name_rec)); if (name == NULL) return ENOMEM; memset(name, 0, sizeof(krb5_gss_name_rec)); code = k5_mutex_init(&name->lock); if (code != 0) goto cleanup; if ((flags & KG_INIT_NAME_NO_COPY) == 0) { code = krb5_copy_principal(context, principal, &name->princ); if (code != 0) goto cleanup; if (ad_context != NULL) { code = krb5_authdata_context_copy(context, ad_context, &name->ad_context); if (code != 0) goto cleanup; } } else { name->princ = principal; name->ad_context = ad_context; } if ((flags & KG_INIT_NAME_INTERN) && !kg_save_name((gss_name_t)name)) { code = G_VALIDATE_FAILED; goto cleanup; } *ret_name = name; cleanup: if (code != 0) kg_release_name(context, 0, &name); return code; }
static errcode_t rw_setup(profile_t profile) { prf_file_t file; errcode_t retval = 0; if (!profile) return PROF_NO_PROFILE; if (profile->magic != PROF_MAGIC_PROFILE) return PROF_MAGIC_PROFILE; file = profile->first_file; retval = profile_lock_global(); if (retval) return retval; /* Don't update the file if we've already made modifications */ if (file->data->flags & PROFILE_FILE_DIRTY) { profile_unlock_global(); return 0; } if ((file->data->flags & PROFILE_FILE_SHARED) != 0) { prf_data_t new_data; new_data = profile_make_prf_data(file->data->filespec); if (new_data == NULL) { retval = ENOMEM; } else { retval = k5_mutex_init(&new_data->lock); if (retval == 0) { new_data->root = NULL; new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED; new_data->timestamp = 0; new_data->upd_serial = file->data->upd_serial; } } if (retval != 0) { profile_unlock_global(); free(new_data); return retval; } profile_dereference_data_locked(file->data); file->data = new_data; } profile_unlock_global(); retval = profile_update_file(file); return retval; }
/* Mutex allocation functions, for use in plugins that may not know what options a given set of libraries was compiled with. */ int KRB5_CALLCONV krb5int_mutex_alloc (k5_mutex_t **m) { k5_mutex_t *ptr; int err; ptr = malloc (sizeof (k5_mutex_t)); if (ptr == NULL) return ENOMEM; err = k5_mutex_init (ptr); if (err) { free (ptr); return err; } *m = ptr; return 0; }
/*ARGSUSED*/ krb5_error_code krb5_rc_resolve_type(krb5_context context, krb5_rcache *id, char *type) { struct krb5_rc_typelist *t; krb5_error_code err; err = k5_mutex_lock(&rc_typelist_lock); if (err) return err; for (t = typehead;t && strcmp(t->ops->type,type);t = t->next) ; if (!t) { k5_mutex_unlock(&rc_typelist_lock); return KRB5_RC_TYPE_NOTFOUND; } /* allocate *id? nah */ (*id)->ops = t->ops; k5_mutex_unlock(&rc_typelist_lock); return k5_mutex_init(&(*id)->lock); }
/* Convert a JSON value to a krb5 GSS name or to NULL. */ static int json_to_kgname(krb5_context context, k5_json_value v, krb5_gss_name_t *name_out) { k5_json_array array; krb5_gss_name_t name = NULL; *name_out = NULL; if (k5_json_get_tid(v) == K5_JSON_TID_NULL) return 0; if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY) return -1; array = v; if (k5_json_array_length(array) != 3) return -1; name = calloc(1, sizeof(*name)); if (name == NULL) return -1; if (k5_mutex_init(&name->lock)) { free(name); return -1; } if (json_to_principal(context, k5_json_array_get(array, 0), &name->princ)) goto invalid; if (json_to_optional_string(k5_json_array_get(array, 1), &name->service)) goto invalid; if (json_to_optional_string(k5_json_array_get(array, 2), &name->host)) goto invalid; *name_out = name; return 0; invalid: kg_release_name(context, &name); return -1; }
/* * This function reads the parameters from the krb5.conf file. The * parameters read here are DAL-LDAP specific attributes. Some of * these are ldap_server .... */ krb5_error_code krb5_ldap_read_server_params(krb5_context context, char *conf_section, int srv_type) { char *servers, *save_ptr, *item; const char *delims = "\t\n\f\v\r ,", *name; krb5_error_code ret = 0; kdb5_dal_handle *dal_handle = context->dal_handle; krb5_ldap_context *ldap_context = dal_handle->db_context; /* copy the conf_section into ldap_context for later use */ if (conf_section != NULL) { ldap_context->conf_section = strdup(conf_section); if (ldap_context->conf_section == NULL) return ENOMEM; } /* This mutex is used in the LDAP connection pool. */ if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) return KRB5_KDB_SERVER_INTERNAL_ERR; /* Read the maximum number of LDAP connections per server. */ if (ldap_context->max_server_conns == 0) { ret = prof_get_integer_def(context, conf_section, KRB5_CONF_LDAP_CONNS_PER_SERVER, DEFAULT_CONNS_PER_SERVER, &ldap_context->max_server_conns); if (ret) return ret; } if (ldap_context->max_server_conns < 2) { k5_setmsg(context, EINVAL, _("Minimum connections required per server is 2")); return EINVAL; } /* Read the DN used to connect to the LDAP server. */ if (ldap_context->bind_dn == NULL) { name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_DN, KRB5_CONF_LDAP_KADMIND_DN); ret = prof_get_string_def(context, conf_section, name, &ldap_context->bind_dn); if (ret) return ret; } /* Read the filename containing stashed DN passwords. */ if (ldap_context->service_password_file == NULL) { ret = prof_get_string_def(context, conf_section, KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE, &ldap_context->service_password_file); if (ret) return ret; } if (ldap_context->sasl_mech == NULL) { name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_MECH, KRB5_CONF_LDAP_KADMIND_SASL_MECH); ret = prof_get_string_def(context, conf_section, name, &ldap_context->sasl_mech); if (ret) return ret; } if (ldap_context->sasl_authcid == NULL) { name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_AUTHCID, KRB5_CONF_LDAP_KADMIND_SASL_AUTHCID); ret = prof_get_string_def(context, conf_section, name, &ldap_context->sasl_authcid); if (ret) return ret; } if (ldap_context->sasl_authzid == NULL) { name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_AUTHZID, KRB5_CONF_LDAP_KADMIND_SASL_AUTHZID); ret = prof_get_string_def(context, conf_section, name, &ldap_context->sasl_authzid); if (ret) return ret; } if (ldap_context->sasl_realm == NULL) { name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_REALM, KRB5_CONF_LDAP_KADMIND_SASL_REALM); ret = prof_get_string_def(context, conf_section, name, &ldap_context->sasl_realm); if (ret) return ret; } /* Read the LDAP server URL list. */ if (ldap_context->server_info_list == NULL) { ret = profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section, KRB5_CONF_LDAP_SERVERS, NULL, &servers); if (ret) return attr_read_error(context, ret, KRB5_CONF_LDAP_SERVERS); if (servers == NULL) { ret = add_server_entry(context, "ldapi://"); if (ret) return ret; } else { item = strtok_r(servers, delims, &save_ptr); while (item != NULL) { ret = add_server_entry(context, item); if (ret) { profile_release_string(servers); return ret; } item = strtok_r(NULL, delims, &save_ptr); } profile_release_string(servers); } } ret = prof_get_boolean_def(context, conf_section, KRB5_CONF_DISABLE_LAST_SUCCESS, FALSE, &ldap_context->disable_last_success); if (ret) return ret; return prof_get_boolean_def(context, conf_section, KRB5_CONF_DISABLE_LOCKOUT, FALSE, &ldap_context->disable_lockout); }
OM_uint32 kg_compose_deleg_cred(OM_uint32 *minor_status, krb5_gss_cred_id_t impersonator_cred, krb5_creds *subject_creds, OM_uint32 time_req, krb5_gss_cred_id_t *output_cred, OM_uint32 *time_rec, krb5_context context) { OM_uint32 major_status; krb5_error_code code; krb5_gss_cred_id_t cred = NULL; *output_cred = NULL; k5_mutex_assert_locked(&impersonator_cred->lock); if (!kg_is_initiator_cred(impersonator_cred) || impersonator_cred->name == NULL || impersonator_cred->impersonator != NULL) { code = G_BAD_USAGE; goto cleanup; } assert(impersonator_cred->name->princ != NULL); assert(subject_creds != NULL); assert(subject_creds->client != NULL); cred = xmalloc(sizeof(*cred)); if (cred == NULL) { code = ENOMEM; goto cleanup; } memset(cred, 0, sizeof(*cred)); code = k5_mutex_init(&cred->lock); if (code != 0) goto cleanup; cred->usage = GSS_C_INITIATE; cred->tgt_expire = subject_creds->times.endtime; code = kg_init_name(context, subject_creds->client, NULL, NULL, NULL, 0, &cred->name); if (code != 0) goto cleanup; code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache); if (code != 0) goto cleanup; cred->destroy_ccache = 1; code = krb5_cc_initialize(context, cred->ccache, subject_creds->client); if (code != 0) goto cleanup; /* * Only return a "proxy" credential for use with constrained * delegation if the subject credentials are forwardable. * Submitting non-forwardable credentials to the KDC for use * with constrained delegation will only return an error. */ if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) { code = make_proxy_cred(context, cred, impersonator_cred); if (code != 0) goto cleanup; } code = krb5_cc_store_cred(context, cred->ccache, subject_creds); if (code != 0) goto cleanup; if (time_rec != NULL) { krb5_timestamp now; code = krb5_timeofday(context, &now); if (code != 0) goto cleanup; *time_rec = cred->tgt_expire - now; } major_status = GSS_S_COMPLETE; *minor_status = 0; *output_cred = cred; cleanup: if (code != 0) { *minor_status = code; major_status = GSS_S_FAILURE; } if (GSS_ERROR(major_status) && cred != NULL) { k5_mutex_destroy(&cred->lock); krb5_cc_destroy(context, cred->ccache); kg_release_name(context, &cred->name); xfree(cred); } return major_status; }
krb5_error_code kg_init_name(krb5_context context, krb5_principal principal, char *service, char *host, krb5_authdata_context ad_context, krb5_flags flags, krb5_gss_name_t *ret_name) { krb5_error_code code; krb5_gss_name_t name; *ret_name = NULL; assert(principal != NULL); if (principal == NULL) return EINVAL; name = xmalloc(sizeof(krb5_gss_name_rec)); if (name == NULL) return ENOMEM; memset(name, 0, sizeof(krb5_gss_name_rec)); code = k5_mutex_init(&name->lock); if (code != 0) goto cleanup; if ((flags & KG_INIT_NAME_NO_COPY) == 0) { code = krb5_copy_principal(context, principal, &name->princ); if (code != 0) goto cleanup; if (ad_context != NULL) { code = krb5_authdata_context_copy(context, ad_context, &name->ad_context); if (code != 0) goto cleanup; } code = ENOMEM; if (service != NULL) { name->service = strdup(service); if (name->service == NULL) goto cleanup; } if (host != NULL) { name->host = strdup(host); if (name->host == NULL) goto cleanup; } code = 0; } else { name->princ = principal; name->service = service; name->host = host; name->ad_context = ad_context; } *ret_name = name; cleanup: if (code != 0) kg_release_name(context, &name); return code; }
errcode_t profile_open_file(const_profile_filespec_t filespec, prf_file_t *ret_prof) { prf_file_t prf; errcode_t retval; char *home_env = 0; prf_data_t data; char *expanded_filename; retval = CALL_INIT_FUNCTION(profile_library_initializer); if (retval) return retval; scan_shared_trees_unlocked(); prf = malloc(sizeof(struct _prf_file_t)); if (!prf) return ENOMEM; memset(prf, 0, sizeof(struct _prf_file_t)); prf->magic = PROF_MAGIC_FILE; if (filespec[0] == '~' && filespec[1] == '/') { home_env = getenv("HOME"); #ifdef HAVE_PWD_H if (home_env == NULL) { uid_t uid; struct passwd *pw, pwx; char pwbuf[BUFSIZ]; uid = getuid(); if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) && pw != NULL && pw->pw_dir[0] != 0) home_env = pw->pw_dir; } #endif } if (home_env) { if (asprintf(&expanded_filename, "%s%s", home_env, filespec + 1) < 0) expanded_filename = 0; } else expanded_filename = strdup(filespec); if (expanded_filename == 0) { free(prf); return ENOMEM; } retval = k5_mutex_lock(&g_shared_trees_mutex); if (retval) { free(expanded_filename); free(prf); scan_shared_trees_unlocked(); return retval; } scan_shared_trees_locked(); for (data = g_shared_trees; data; data = data->next) { if (!strcmp(data->filespec, expanded_filename) /* Check that current uid has read access. */ && r_access(data->filespec)) break; } if (data) { data->refcount++; (void) k5_mutex_unlock(&g_shared_trees_mutex); retval = profile_update_file_data(data); free(expanded_filename); prf->data = data; *ret_prof = prf; scan_shared_trees_unlocked(); return retval; } (void) k5_mutex_unlock(&g_shared_trees_mutex); data = profile_make_prf_data(expanded_filename); if (data == NULL) { free(prf); free(expanded_filename); return ENOMEM; } free(expanded_filename); prf->data = data; retval = k5_mutex_init(&data->lock); if (retval) { free(data); free(prf); return retval; } retval = profile_update_file(prf); if (retval) { profile_close_file(prf); return retval; } retval = k5_mutex_lock(&g_shared_trees_mutex); if (retval) { profile_close_file(prf); scan_shared_trees_unlocked(); return retval; } scan_shared_trees_locked(); data->flags |= PROFILE_FILE_SHARED; data->next = g_shared_trees; g_shared_trees = data; scan_shared_trees_locked(); (void) k5_mutex_unlock(&g_shared_trees_mutex); *ret_prof = prf; return 0; }
/* Convert a JSON array value to a krb5 GSS credential. */ static int json_to_kgcred(krb5_context context, k5_json_array array, krb5_gss_cred_id_t *cred_out) { krb5_gss_cred_id_t cred; k5_json_number n; k5_json_bool b; krb5_boolean is_new; OM_uint32 tmp; *cred_out = NULL; if (k5_json_array_length(array) != 14) return -1; cred = calloc(1, sizeof(*cred)); if (cred == NULL) return -1; if (k5_mutex_init(&cred->lock)) { free(cred); return -1; } n = check_element(array, 0, K5_JSON_TID_NUMBER); if (n == NULL) goto invalid; cred->usage = k5_json_number_value(n); if (json_to_kgname(context, k5_json_array_get(array, 1), &cred->name)) goto invalid; if (json_to_principal(context, k5_json_array_get(array, 2), &cred->impersonator)) goto invalid; b = check_element(array, 3, K5_JSON_TID_BOOL); if (b == NULL) goto invalid; cred->default_identity = k5_json_bool_value(b); b = check_element(array, 4, K5_JSON_TID_BOOL); if (b == NULL) goto invalid; cred->iakerb_mech = k5_json_bool_value(b); if (json_to_keytab(context, k5_json_array_get(array, 5), &cred->keytab)) goto invalid; if (json_to_rcache(context, k5_json_array_get(array, 6), &cred->rcache)) goto invalid; if (json_to_ccache(context, k5_json_array_get(array, 7), &cred->ccache, &is_new)) goto invalid; cred->destroy_ccache = is_new; if (json_to_keytab(context, k5_json_array_get(array, 8), &cred->client_keytab)) goto invalid; b = check_element(array, 9, K5_JSON_TID_BOOL); if (b == NULL) goto invalid; cred->have_tgt = k5_json_bool_value(b); n = check_element(array, 10, K5_JSON_TID_NUMBER); if (n == NULL) goto invalid; cred->expire = k5_json_number_value(n); n = check_element(array, 11, K5_JSON_TID_NUMBER); if (n == NULL) goto invalid; cred->refresh_time = k5_json_number_value(n); if (json_to_etypes(k5_json_array_get(array, 12), &cred->req_enctypes)) goto invalid; if (json_to_optional_string(k5_json_array_get(array, 13), &cred->password)) goto invalid; *cred_out = cred; return 0; invalid: (void)krb5_gss_release_cred(&tmp, (gss_cred_id_t *)&cred); return -1; }
/* Load a dynamic profile module as specified by modspec and create a vtable * profile for it in *ret_profile. */ static errcode_t init_load_module(const char *modspec, profile_t *ret_profile) { char *modpath = NULL, *residual = NULL; struct errinfo einfo = { 0 }; prf_lib_handle_t lib_handle = NULL; struct plugin_file_handle *plhandle = NULL; void *cbdata = NULL, (*fptr)(); int have_lock = 0, have_cbdata = 0; struct profile_vtable vtable = { 1 }; /* Set minor_ver to 1, rest null. */ errcode_t err; profile_module_init_fn initfn; err = parse_modspec(modspec, &modpath, &residual); if (err) goto cleanup; /* Allocate a reference-counted library handle container. */ lib_handle = malloc(sizeof(*lib_handle)); if (lib_handle == NULL) goto cleanup; err = k5_mutex_init(&lib_handle->lock); if (err) goto cleanup; have_lock = 1; /* Open the module and get its initializer. */ err = krb5int_open_plugin(modpath, &plhandle, &einfo); if (err) goto cleanup; err = krb5int_get_plugin_func(plhandle, "profile_module_init", &fptr, &einfo); if (err == ENOENT) err = PROF_MODULE_INVALID; if (err) goto cleanup; /* Get the profile vtable and callback data pointer. */ initfn = (profile_module_init_fn)fptr; err = (*initfn)(residual, &vtable, &cbdata); if (err) goto cleanup; have_cbdata = 1; /* Create a vtable profile with the information obtained. */ lib_handle->plugin_handle = plhandle; lib_handle->refcount = 1; err = init_module(&vtable, cbdata, lib_handle, ret_profile); cleanup: free(modpath); free(residual); k5_clear_error(&einfo); if (err) { if (have_cbdata && vtable.cleanup) vtable.cleanup(cbdata); if (have_lock) k5_mutex_destroy(&lib_handle->lock); free(lib_handle); if (plhandle) krb5int_close_plugin(plhandle); } return err; }
krb5_error_code KRB5_CALLCONV krb5_mkt_resolve(krb5_context context, const char *name, krb5_keytab *id) { krb5_mkt_data *data = 0; krb5_mkt_list_node *list; krb5_error_code err = 0; /* First determine if a memory keytab of this name already exists */ err = KTGLOCK; if (err) return(err); for (list = krb5int_mkt_list; list; list = list->next) { if (strcmp(name,KTNAME(list->keytab)) == 0) { /* Found */ *id = list->keytab; goto done; } } /* We will now create the new key table with the specified name. * We do not drop the global lock, therefore the name will indeed * be unique when we add it. */ if ((list = (krb5_mkt_list_node *)malloc(sizeof(krb5_mkt_list_node))) == NULL) { err = ENOMEM; goto done; } if ((list->keytab = (krb5_keytab)malloc(sizeof(struct _krb5_kt))) == NULL) { free(list); err = ENOMEM; goto done; } list->keytab->ops = &krb5_mkt_ops; if ((data = (krb5_mkt_data *)malloc(sizeof(krb5_mkt_data))) == NULL) { free(list->keytab); free(list); err = ENOMEM; goto done; } data->name = NULL; err = k5_mutex_init(&data->lock); if (err) { free(data); free(list->keytab); free(list); goto done; } if ((data->name = strdup(name)) == NULL) { k5_mutex_destroy(&data->lock); free(data); free(list->keytab); free(list); err = ENOMEM; goto done; } data->link = NULL; data->refcount = 0; list->keytab->data = (krb5_pointer)data; list->keytab->magic = KV5M_KEYTAB; list->next = krb5int_mkt_list; krb5int_mkt_list = list; *id = list->keytab; done: err = KTLOCK(*id); if (err) { k5_mutex_destroy(&data->lock); if (data && data->name) free(data->name); free(data); if (list && list->keytab) free(list->keytab); free(list); } else { KTREFCNT(*id)++; KTUNLOCK(*id); } KTGUNLOCK; return(err); }