kadm5_ret_t _kadm5_set_keys(kadm5_server_context *context, hdb_entry *ent, const char *password) { Key *keys; size_t num_keys; kadm5_ret_t ret; ret = hdb_generate_key_set_password(context->context, ent->principal, password, &keys, &num_keys); if (ret) return ret; _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val); ent->keys.val = keys; ent->keys.len = num_keys; hdb_entry_set_pw_change_time(context->context, ent, 0); if (krb5_config_get_bool_default(context->context, NULL, FALSE, "kadmin", "save-password", NULL)) { ret = hdb_entry_set_password(context->context, context->db, ent, password); if (ret) return ret; } return 0; }
static krb5_boolean get_config_bool (krb5_context context, krb5_boolean def_value, const char *realm, const char *name) { krb5_boolean b; b = krb5_config_get_bool_default(context, NULL, def_value, "realms", realm, name, NULL); if (b != def_value) return b; b = krb5_config_get_bool_default (context, NULL, def_value, "libdefaults", name, NULL); if (b != def_value) return b; return def_value; }
/** * This function prunes an HDB entry's keys that are too old to have been used * to mint still valid tickets (based on the entry's maximum ticket lifetime). * * @param context Context * @param entry HDB entry */ krb5_error_code hdb_prune_keys(krb5_context context, hdb_entry *entry) { HDB_extension *ext; HDB_Ext_KeySet *keys; size_t nelem; ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); if (ext == NULL) return 0; keys = &ext->data.u.hist_keys; nelem = keys->len; /* Optionally drop key history for keys older than now - max_life */ if (entry->max_life != NULL && nelem > 0 && krb5_config_get_bool_default(context, NULL, FALSE, "kadmin", "prune-key-history", NULL)) { hdb_keyset *elem; time_t ceiling = time(NULL) - *entry->max_life; time_t keep_time = 0; size_t i; /* * Compute most recent key timestamp that predates the current time * by at least the entry's maximum ticket lifetime. */ for (i = 0; i < nelem; ++i) { elem = &keys->val[i]; if (elem->set_time && *elem->set_time < ceiling && (keep_time == 0 || *elem->set_time > keep_time)) keep_time = *elem->set_time; } /* Drop obsolete entries */ if (keep_time) { for (i = 0; i < nelem; /* see below */) { elem = &keys->val[i]; if (elem->set_time && *elem->set_time < keep_time) { remove_HDB_Ext_KeySet(keys, i); /* * Removing the i'th element shifts the tail down, continue * at same index with reduced upper bound. */ --nelem; continue; } ++i; } } } return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_get_host_realm_int (krb5_context context, const char *host, krb5_boolean use_dns, krb5_realm **realms) { const char *p, *q; krb5_boolean dns_locate_enable; dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, "libdefaults", "dns_lookup_realm", NULL); for (p = host; p != NULL; p = strchr (p + 1, '.')) { if(config_find_realm(context, p, realms) == 0) { if(strcasecmp(*realms[0], "dns_locate") == 0) { if(use_dns) for (q = host; q != NULL; q = strchr(q + 1, '.')) if(dns_find_realm(context, q, realms) == 0) return 0; continue; } else return 0; } else if(use_dns && dns_locate_enable) { if(dns_find_realm(context, p, realms) == 0) return 0; } } p = strchr(host, '.'); if(p != NULL) { p++; *realms = malloc(2 * sizeof(krb5_realm)); if (*realms == NULL) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } (*realms)[0] = strdup(p); if((*realms)[0] == NULL) { free(*realms); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } strupr((*realms)[0]); (*realms)[1] = NULL; return 0; } krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, N_("unable to find realm of host %s", ""), host); return KRB5_ERR_HOST_REALM_UNKNOWN; }
static krb5_error_code fcc_store_cred(krb5_context context, krb5_ccache id, krb5_creds *creds) { int ret; int fd; ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY | O_CLOEXEC, 0); if(ret) return ret; { krb5_storage *sp; sp = krb5_storage_emem(); krb5_storage_set_eof_code(sp, KRB5_CC_END); storage_set_flags(context, sp, FCACHE(id)->version); if (!krb5_config_get_bool_default(context, NULL, TRUE, "libdefaults", "fcc-mit-ticketflags", NULL)) krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER); ret = krb5_store_creds(sp, creds); if (ret == 0) ret = write_storage(context, sp, fd); krb5_storage_free(sp); } fcc_unlock(context, fd); if (close(fd) < 0) { if (ret == 0) { ret = errno; krb5_set_error_message (context, ret, N_("close %s: %s", ""), FILENAME(id), strerror(ret)); } } return ret; }
KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_appdefault_boolean(krb5_context context, const char *appname, krb5_const_realm realm, const char *option, krb5_boolean def_val, krb5_boolean *ret_val) { if(appname == NULL) appname = getprogname(); def_val = krb5_config_get_bool_default(context, NULL, def_val, "libdefaults", option, NULL); if(realm != NULL) def_val = krb5_config_get_bool_default(context, NULL, def_val, "realms", realm, option, NULL); def_val = krb5_config_get_bool_default(context, NULL, def_val, "appdefaults", option, NULL); if(realm != NULL) def_val = krb5_config_get_bool_default(context, NULL, def_val, "appdefaults", realm, option, NULL); if(appname != NULL) { def_val = krb5_config_get_bool_default(context, NULL, def_val, "appdefaults", appname, option, NULL); if(realm != NULL) def_val = krb5_config_get_bool_default(context, NULL, def_val, "appdefaults", appname, realm, option, NULL); } *ret_val = def_val; }
void kcm_configure(int argc, char **argv) { krb5_error_code ret; int optind = 0; const char *p; while(getarg(args, num_args, argc, argv, &optind)) warnx("error at argument `%s'", argv[optind]); if(help_flag) usage (0); if (version_flag) { print_version(NULL); exit(0); } argc -= optind; argv += optind; if (argc != 0) usage(1); { char **files; if(config_file == NULL) config_file = _PATH_KCM_CONF; ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(kcm_context, 1, ret, "getting configuration files"); ret = krb5_set_config_files(kcm_context, files); krb5_free_config_files(files); if(ret) krb5_err(kcm_context, 1, ret, "reading configuration files"); } if(max_request_str) max_request = parse_bytes(max_request_str, NULL); if(max_request == 0){ p = krb5_config_get_string (kcm_context, NULL, "kcm", "max-request", NULL); if(p) max_request = parse_bytes(p, NULL); } if (system_principal == NULL) { system_principal = kcm_system_config_get_string("principal"); } if (system_principal != NULL) { ret = ccache_init_system(); if (ret) krb5_err(kcm_context, 1, ret, "initializing system ccache"); } #ifdef SUPPORT_DETACH if(detach_from_console == -1) detach_from_console = krb5_config_get_bool_default(kcm_context, NULL, DETACH_IS_DEFAULT, "kcm", "detach", NULL); #endif kcm_openlog(); if(max_request == 0) max_request = 64 * 1024; }
static krb5_error_code init_context_from_config_file(krb5_context context) { krb5_error_code ret; const char * tmp; char **s; krb5_enctype *tmptypes; INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout"); INIT_FIELD(context, time, host_timeout, 3, "host_timeout"); INIT_FIELD(context, int, max_retries, 3, "max_retries"); INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); ret = krb5_config_get_bool_default(context, NULL, FALSE, "libdefaults", "allow_weak_crypto", NULL); if (ret) { krb5_enctype_enable(context, ETYPE_DES_CBC_CRC); krb5_enctype_enable(context, ETYPE_DES_CBC_MD4); krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); krb5_enctype_enable(context, ETYPE_DES_CBC_NONE); krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE); krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE); } ret = set_etypes (context, "default_etypes", &tmptypes); if(ret) return ret; free(context->etypes); context->etypes = tmptypes; ret = set_etypes (context, "default_etypes_des", &tmptypes); if(ret) return ret; free(context->etypes_des); context->etypes_des = tmptypes; ret = set_etypes (context, "default_as_etypes", &tmptypes); if(ret) return ret; free(context->as_etypes); context->as_etypes = tmptypes; ret = set_etypes (context, "default_tgs_etypes", &tmptypes); if(ret) return ret; free(context->tgs_etypes); context->tgs_etypes = tmptypes; ret = set_etypes (context, "permitted_enctypes", &tmptypes); if(ret) return ret; free(context->permitted_enctypes); context->permitted_enctypes = tmptypes; /* default keytab name */ tmp = NULL; if(!issuid()) tmp = getenv("KRB5_KTNAME"); if(tmp != NULL) context->default_keytab = tmp; else INIT_FIELD(context, string, default_keytab, KEYTAB_DEFAULT, "default_keytab_name"); INIT_FIELD(context, string, default_keytab_modify, NULL, "default_keytab_modify_name"); INIT_FIELD(context, string, time_fmt, "%Y-%m-%dT%H:%M:%S", "time_format"); INIT_FIELD(context, string, date_fmt, "%Y-%m-%d", "date_format"); INIT_FIELD(context, bool, log_utc, FALSE, "log_utc"); /* init dns-proxy slime */ tmp = krb5_config_get_string(context, NULL, "libdefaults", "dns_proxy", NULL); if(tmp) roken_gethostby_setup(context->http_proxy, tmp); krb5_free_host_realm (context, context->default_realms); context->default_realms = NULL; { krb5_addresses addresses; char **adr, **a; krb5_set_extra_addresses(context, NULL); adr = krb5_config_get_strings(context, NULL, "libdefaults", "extra_addresses", NULL); memset(&addresses, 0, sizeof(addresses)); for(a = adr; a && *a; a++) { ret = krb5_parse_address(context, *a, &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } krb5_config_free_strings(adr); krb5_set_ignore_addresses(context, NULL); adr = krb5_config_get_strings(context, NULL, "libdefaults", "ignore_addresses", NULL); memset(&addresses, 0, sizeof(addresses)); for(a = adr; a && *a; a++) { ret = krb5_parse_address(context, *a, &addresses); if (ret == 0) { krb5_add_ignore_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } krb5_config_free_strings(adr); } INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces"); INIT_FIELD(context, int, fcache_vno, 0, "fcache_version"); /* prefer dns_lookup_kdc over srv_lookup. */ INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); INIT_FIELD(context, int, max_msg_size, 1000 * 1024, "maximum_message_size"); INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname"); INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac"); if (context->default_cc_name) free(context->default_cc_name); context->default_cc_name = NULL; context->default_cc_name_set = 0; s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); if(s) { char **p; if (context->debug_dest) krb5_closelog(context, context->debug_dest); krb5_initlog(context, "libkrb5", &context->debug_dest); for(p = s; *p; p++) krb5_addlog_dest(context, context->debug_dest, *p); krb5_config_free_strings(s); } tmp = krb5_config_get_string(context, NULL, "libdefaults", "check-rd-req-server", NULL); if (tmp == NULL && !issuid()) tmp = getenv("KRB5_CHECK_RD_REQ_SERVER"); if(tmp) { if (strcasecmp(tmp, "ignore") == 0) context->flags |= KRB5_CTX_F_RD_REQ_IGNORE; } ret = krb5_config_get_bool_default(context, NULL, TRUE, "libdefaults", "fcache_strict_checking", NULL); if (ret) context->flags |= KRB5_CTX_F_FCACHE_STRICT_CHECKING; return 0; }
static kadm5_ret_t kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, krb5_data *in, krb5_data *out) { kadm5_ret_t ret; int32_t cmd, mask, tmp; kadm5_server_context *contextp = kadm_handlep; char client[128], name[128], name2[128]; const char *op = ""; krb5_principal princ, princ2; kadm5_principal_ent_rec ent; char *password, *expression; krb5_keyblock *new_keys; krb5_key_salt_tuple *ks_tuple = NULL; krb5_boolean keepold = FALSE; int n_ks_tuple = 0; int n_keys; char **princs; int n_princs; int keys_ok = 0; krb5_storage *sp; krb5_unparse_name_fixed(contextp->context, contextp->caller, client, sizeof(client)); sp = krb5_storage_from_data(in); if (sp == NULL) krb5_errx(contextp->context, 1, "out of memory"); krb5_ret_int32(sp, &cmd); switch(cmd){ case kadm_get:{ op = "GET"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } mask |= KADM5_PRINCIPAL; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET_KEYS, princ); if (ret == 0) keys_ok = 1; else ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0){ if (keys_ok) kadm5_store_principal_ent(sp, &ent); else kadm5_store_principal_ent_nokeys(sp, &ent); kadm5_free_principal_ent(kadm_handlep, &ent); } krb5_free_principal(contextp->context, princ); break; } case kadm_delete:{ op = "DELETE"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } ret = kadm5_delete_principal(kadm_handlep, princ); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_create:{ op = "CREATE"; ret = kadm5_ret_principal_ent(sp, &ent); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); goto fail; } ret = krb5_ret_string(sp, &password); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); goto fail; } krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); memset(password, 0, strlen(password)); free(password); goto fail; } ret = kadm5_create_principal(kadm_handlep, &ent, mask, password); kadm5_free_principal_ent(kadm_handlep, &ent); memset(password, 0, strlen(password)); free(password); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_modify:{ op = "MODIFY"; ret = kadm5_ret_principal_ent(sp, &ent); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ kadm5_free_principal_ent(contextp, &ent); goto fail; } krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY, ent.principal); if(ret){ kadm5_free_principal_ent(contextp, &ent); goto fail; } ret = kadm5_modify_principal(kadm_handlep, &ent, mask); kadm5_free_principal_ent(kadm_handlep, &ent); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_rename:{ op = "RENAME"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_principal(sp, &princ2); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ2, name2, sizeof(name2)); krb5_warnx(contextp->context, "%s: %s %s -> %s", client, op, name, name2); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, princ2) || _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); if(ret){ krb5_free_principal(contextp->context, princ); krb5_free_principal(contextp->context, princ2); goto fail; } ret = kadm5_rename_principal(kadm_handlep, princ, princ2); krb5_free_principal(contextp->context, princ); krb5_free_principal(contextp->context, princ2); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_chpass:{ op = "CHPASS"; ret = krb5_ret_principal(sp, &princ); if (ret) goto fail; ret = krb5_ret_string(sp, &password); if (ret) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &keepold); if (ret && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is allowed if at least one of: * * a) allowed by sysadmin * b) it's for the principal him/herself and this was an * initial ticket * c) the user is on the CPW ACL. * * All changes are checked for password quality. */ if (krb5_config_get_bool_default(contextp->context, NULL, TRUE, "kadmin", "allow_self_change_password", NULL) && initial && krb5_principal_compare (contextp->context, contextp->caller, princ)) { ret = 0; } else { ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); } if (ret == 0) { krb5_data pwd_data; const char *pwd_reason; pwd_data.data = password; pwd_data.length = strlen(password); pwd_reason = kadm5_check_password_quality (contextp->context, princ, &pwd_data); if (pwd_reason != NULL) ret = KADM5_PASS_Q_DICT; } if(ret) { krb5_free_principal(contextp->context, princ); memset(password, 0, strlen(password)); free(password); goto fail; } ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL, password); krb5_free_principal(contextp->context, princ); memset(password, 0, strlen(password)); free(password); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_chpass_with_key:{ int i; krb5_key_data *key_data; int n_key_data; op = "CHPASS_WITH_KEY"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_int32(sp, &n_key_data); if (ret) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &keepold); if (ret && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } /* n_key_data will be squeezed into an int16_t below. */ if (n_key_data < 0 || n_key_data >= 1 << 16 || (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) { ret = ERANGE; krb5_free_principal(contextp->context, princ); goto fail; } key_data = malloc (n_key_data * sizeof(*key_data)); if (key_data == NULL && n_key_data != 0) { ret = ENOMEM; krb5_free_principal(contextp->context, princ); goto fail; } for (i = 0; i < n_key_data; ++i) { ret = kadm5_ret_key_data (sp, &key_data[i]); if (ret) { int16_t dummy = i; kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); krb5_free_principal(contextp->context, princ); goto fail; } } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is only allowed if the user is on the CPW ACL, * this it to force password quality check on the user. */ ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) { int16_t dummy = n_key_data; kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); krb5_free_principal(contextp->context, princ); goto fail; } ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold, n_key_data, key_data); { int16_t dummy = n_key_data; kadm5_free_key_data (contextp, &dummy, key_data); } free (key_data); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_randkey:{ op = "RANDKEY"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is allowed if at least one of: * a) it's for the principal him/herself and this was an initial ticket * b) the user is on the CPW ACL. */ if (initial && krb5_principal_compare (contextp->context, contextp->caller, princ)) ret = 0; else ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) { krb5_free_principal(contextp->context, princ); goto fail; } /* * See comments in kadm5_c_randkey_principal() regarding the * protocol. */ ret = krb5_ret_int32(sp, &keepold); if (ret != 0 && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &n_ks_tuple); if (ret != 0 && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } else if (ret == 0) { size_t i; if (n_ks_tuple < 0) { ret = EOVERFLOW; krb5_free_principal(contextp->context, princ); goto fail; } if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) { ret = errno; krb5_free_principal(contextp->context, princ); goto fail; } for (i = 0; i < n_ks_tuple; i++) { ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype); if (ret != 0) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype); if (ret != 0) { krb5_free_principal(contextp->context, princ); goto fail; } } } ret = kadm5_randkey_principal_3(kadm_handlep, princ, keepold, n_ks_tuple, ks_tuple, &new_keys, &n_keys); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0){ int i; krb5_store_int32(sp, n_keys); for(i = 0; i < n_keys; i++){ krb5_store_keyblock(sp, new_keys[i]); krb5_free_keyblock_contents(contextp->context, &new_keys[i]); } free(new_keys); } break; } case kadm_get_privs:{ uint32_t privs; ret = kadm5_get_privs(kadm_handlep, &privs); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0) krb5_store_uint32(sp, privs); break; } case kadm_get_princs:{ op = "LIST"; ret = krb5_ret_int32(sp, &tmp); if(ret) goto fail; if(tmp){ ret = krb5_ret_string(sp, &expression); if(ret) goto fail; }else expression = NULL; krb5_warnx(contextp->context, "%s: %s %s", client, op, expression ? expression : "*"); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_LIST, NULL); if(ret){ free(expression); goto fail; } ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs); free(expression); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0){ int i; krb5_store_int32(sp, n_princs); for(i = 0; i < n_princs; i++) krb5_store_string(sp, princs[i]); kadm5_free_name_list(kadm_handlep, princs, &n_princs); } break; } default: krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, KADM5_FAILURE); break; } krb5_storage_to_data(sp, out); krb5_storage_free(sp); return 0; fail: krb5_warn(contextp->context, ret, "%s", op); krb5_storage_seek(sp, 0, SEEK_SET); krb5_store_int32(sp, ret); krb5_storage_to_data(sp, out); krb5_storage_free(sp); return 0; }
static krb5_error_code ccache_init_system(void) { kcm_ccache ccache; krb5_error_code ret; if (system_cache_name == NULL) system_cache_name = kcm_system_config_get_string("cc_name"); ret = kcm_ccache_new(kcm_context, system_cache_name ? system_cache_name : "SYSTEM", &ccache); if (ret) return ret; ccache->flags |= KCM_FLAGS_OWNER_IS_SYSTEM; ccache->flags |= KCM_FLAGS_USE_KEYTAB; ret = parse_owners(ccache); if (ret) return ret; ret = krb5_parse_name(kcm_context, system_principal, &ccache->client); if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } if (system_server == NULL) system_server = kcm_system_config_get_string("server"); if (system_server != NULL) { ret = krb5_parse_name(kcm_context, system_server, &ccache->server); if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } } if (system_keytab == NULL) system_keytab = kcm_system_config_get_string("keytab_name"); if (system_keytab != NULL) { ret = krb5_kt_resolve(kcm_context, system_keytab, &ccache->key.keytab); } else { ret = krb5_kt_default(kcm_context, &ccache->key.keytab); } if (ret) { kcm_release_ccache(kcm_context, ccache); return ret; } if (renew_life == NULL) renew_life = kcm_system_config_get_string("renew_life"); if (renew_life == NULL) renew_life = "1 month"; if (renew_life != NULL) { ccache->renew_life = parse_time(renew_life, "s"); if (ccache->renew_life < 0) { kcm_release_ccache(kcm_context, ccache); return EINVAL; } } if (ticket_life == NULL) ticket_life = kcm_system_config_get_string("ticket_life"); if (ticket_life != NULL) { ccache->tkt_life = parse_time(ticket_life, "s"); if (ccache->tkt_life < 0) { kcm_release_ccache(kcm_context, ccache); return EINVAL; } } if (system_perms == NULL) system_perms = kcm_system_config_get_string("mode"); if (system_perms != NULL) { int mode; if (sscanf(system_perms, "%o", &mode) != 1) return EINVAL; ccache->mode = mode; } if (disallow_getting_krbtgt == -1) { disallow_getting_krbtgt = krb5_config_get_bool_default(kcm_context, NULL, FALSE, "kcm", "disallow-getting-krbtgt", NULL); } /* enqueue default actions for credentials cache */ ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL); kcm_release_ccache(kcm_context, ccache); /* retained by event queue */ return ret; }
krb5_kdc_configuration * configure(krb5_context context, int argc, char **argv) { krb5_kdc_configuration *config; krb5_error_code ret; int optidx = 0; const char *p; while(getarg(args, num_args, argc, argv, &optidx)) warnx("error at argument `%s'", argv[optidx]); if(help_flag) usage (0); if (version_flag) { print_version(NULL); exit(0); } if (builtin_hdb_flag) { char *list; ret = hdb_list_builtin(context, &list); if (ret) krb5_err(context, 1, ret, "listing builtin hdb backends"); printf("builtin hdb backends: %s\n", list); free(list); exit(0); } argc -= optidx; argv += optidx; if (argc != 0) usage(1); { char **files; if (config_file == NULL) { asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); if (config_file == NULL) errx(1, "out of memory"); } ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(context, 1, ret, "getting configuration files"); ret = krb5_set_config_files(context, files); krb5_free_config_files(files); if(ret) krb5_err(context, 1, ret, "reading configuration files"); } ret = krb5_kdc_get_config(context, &config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_default_config"); kdc_openlog(context, "kdc", config); ret = krb5_kdc_set_dbinfo(context, config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); if(max_request_str) max_request_tcp = max_request_udp = parse_bytes(max_request_str, NULL); if(max_request_tcp == 0){ p = krb5_config_get_string (context, NULL, "kdc", "max-request", NULL); if(p) max_request_tcp = max_request_udp = parse_bytes(p, NULL); } if(require_preauth != -1) config->require_preauth = require_preauth; if(port_str == NULL){ p = krb5_config_get_string(context, NULL, "kdc", "ports", NULL); if (p != NULL) port_str = strdup(p); } explicit_addresses.len = 0; if (addresses_str.num_strings) { int i; for (i = 0; i < addresses_str.num_strings; ++i) add_one_address (context, addresses_str.strings[i], i == 0); free_getarg_strings (&addresses_str); } else { char **foo = krb5_config_get_strings (context, NULL, "kdc", "addresses", NULL); if (foo != NULL) { add_one_address (context, *foo++, TRUE); while (*foo) add_one_address (context, *foo++, FALSE); } } if(enable_v4 != -1) config->enable_v4 = enable_v4; if(enable_v4_cross_realm != -1) config->enable_v4_cross_realm = enable_v4_cross_realm; if(enable_524 != -1) config->enable_524 = enable_524; if(enable_http == -1) enable_http = krb5_config_get_bool(context, NULL, "kdc", "enable-http", NULL); if(request_log == NULL) request_log = krb5_config_get_string(context, NULL, "kdc", "kdc-request-log", NULL); if (krb5_config_get_string(context, NULL, "kdc", "enforce-transited-policy", NULL)) krb5_errx(context, 1, "enforce-transited-policy deprecated, " "use [kdc]transited-policy instead"); if (enable_kaserver != -1) config->enable_kaserver = enable_kaserver; #ifdef SUPPORT_DETACH if(detach_from_console == -1) detach_from_console = krb5_config_get_bool_default(context, NULL, DETACH_IS_DEFAULT, "kdc", "detach", NULL); #endif /* SUPPORT_DETACH */ if(max_request_tcp == 0) max_request_tcp = 64 * 1024; if(max_request_udp == 0) max_request_udp = 64 * 1024; if (port_str == NULL) port_str = "+"; if (v4_realm) config->v4_realm = v4_realm; if(config->v4_realm == NULL && (config->enable_kaserver || config->enable_v4)) krb5_errx(context, 1, "Kerberos 4 enabled but no realm configured"); if(disable_des == -1) disable_des = krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "disable-des", NULL); if(disable_des) { krb5_enctype_disable(context, ETYPE_DES_CBC_CRC); krb5_enctype_disable(context, ETYPE_DES_CBC_MD4); krb5_enctype_disable(context, ETYPE_DES_CBC_MD5); krb5_enctype_disable(context, ETYPE_DES_CBC_NONE); krb5_enctype_disable(context, ETYPE_DES_CFB64_NONE); krb5_enctype_disable(context, ETYPE_DES_PCBC_NONE); kdc_log(context, config, 0, "DES was disabled, turned off Kerberos V4, 524 " "and kaserver"); config->enable_v4 = 0; config->enable_524 = 0; config->enable_kaserver = 0; } krb5_kdc_windc_init(context); #ifdef PKINIT #ifdef __APPLE__ config->enable_pkinit = 1; if (config->pkinit_kdc_identity == NULL) { if (config->pkinit_kdc_friendly_name == NULL) config->pkinit_kdc_friendly_name = strdup("O=System Identity,CN=com.apple.kerberos.kdc"); config->pkinit_kdc_identity = strdup("KEYCHAIN:"); } if (config->pkinit_kdc_anchors == NULL) config->pkinit_kdc_anchors = strdup("KEYCHAIN:"); #endif /* __APPLE__ */ if (config->enable_pkinit) { if (config->pkinit_kdc_identity == NULL) krb5_errx(context, 1, "pkinit enabled but no identity"); if (config->pkinit_kdc_anchors == NULL) krb5_errx(context, 1, "pkinit enabled but no X509 anchors"); krb5_kdc_pk_initialize(context, config, config->pkinit_kdc_identity, config->pkinit_kdc_anchors, config->pkinit_kdc_cert_pool, config->pkinit_kdc_revoke); } #endif /* PKINIT */ return config; }
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL _krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser, krb5_boolean an2ln_ok) { static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT; krb5_error_code ret; struct plctx ctx; char **rules; /* * XXX we should have a struct with a krb5_context field and a * krb5_error_code fied and pass the address of that as the ctx * argument of heim_base_once_f(). For now we use a static to * communicate failures. Actually, we ignore failures anyways, * since we can't return them. */ heim_base_once_f(®_def_plugins, context, reg_def_plugins_once); ctx.flags = 0; ctx.luser = luser; ctx.principal = principal; ctx.result = FALSE; ctx.k5login_dir = krb5_config_get_string(context, NULL, "libdefaults", "k5login_directory", NULL); if (an2ln_ok) ctx.flags |= KUSEROK_ANAME_TO_LNAME_OK; if (krb5_config_get_bool_default(context, NULL, FALSE, "libdefaults", "k5login_authoritative", NULL)) ctx.flags |= KUSEROK_K5LOGIN_IS_AUTHORITATIVE; if ((ctx.flags & KUSEROK_K5LOGIN_IS_AUTHORITATIVE) && plugin_reg_ret) return plugin_reg_ret; /* fail safe */ rules = krb5_config_get_strings(context, NULL, "libdefaults", "kuserok", NULL); if (rules == NULL) { /* Default: check ~/.k5login */ ctx.rule = "USER-K5LOGIN"; ret = plcallback(context, &kuserok_user_k5login_plug, NULL, &ctx); if (ret == 0) goto out; ctx.rule = "SIMPLE"; ret = plcallback(context, &kuserok_simple_plug, NULL, &ctx); if (ret == 0) goto out; ctx.result = FALSE; } else { size_t n; for (n = 0; rules[n]; n++) { ctx.rule = rules[n]; ret = _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_KUSEROK, KRB5_PLUGIN_KUSEROK_VERSION_0, 0, &ctx, plcallback); if (ret != KRB5_PLUGIN_NO_HANDLE) goto out; } } out: krb5_config_free_strings(rules); return ctx.result; }
static kadm5_ret_t kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, krb5_data *in, krb5_data *out) { kadm5_ret_t ret; int32_t cmd, mask, tmp; kadm5_server_context *contextp = kadm_handlep; char client[128], name[128], name2[128]; const char *op = ""; krb5_principal princ, princ2; kadm5_principal_ent_rec ent; char *password, *expression; krb5_keyblock *new_keys; krb5_key_salt_tuple *ks_tuple = NULL; krb5_boolean keepold = FALSE; int n_ks_tuple = 0; int n_keys; char **princs; int n_princs; int keys_ok = 0; krb5_storage *sp; krb5_unparse_name_fixed(contextp->context, contextp->caller, client, sizeof(client)); sp = krb5_storage_from_data(in); if (sp == NULL) krb5_errx(contextp->context, 1, "out of memory"); krb5_ret_int32(sp, &cmd); switch(cmd){ case kadm_get:{ op = "GET"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } mask |= KADM5_PRINCIPAL; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* If the caller doesn't have KADM5_PRIV_GET, we're done. */ ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); if (ret) { krb5_free_principal(contextp->context, princ); goto fail; } /* Then check to see if it is ok to return keys */ if ((mask & KADM5_KEY_DATA) != 0) { ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET_KEYS, princ); if (ret == 0) { keys_ok = 1; } else if ((mask == (KADM5_PRINCIPAL|KADM5_KEY_DATA)) || (mask == (KADM5_PRINCIPAL|KADM5_KVNO|KADM5_KEY_DATA))) { /* * Requests for keys will get bogus keys, which is useful if * the client just wants to see what (kvno, enctype)s the * principal has keys for, but terrible if the client wants to * write the keys into a keytab or modify the principal and * write the bogus keys back to the server. * * We use a heuristic to detect which case we're handling here. * If the client only asks for the flags in the above * condition, then it's very likely a kadmin ext_keytab, * add_enctype, or other request that should not see bogus * keys. We deny them. * * The kadmin get command can be coaxed into making a request * with the same mask. But the default long and terse output * modes request other things too, so in all likelihood this * heuristic will not hurt any kadmin get uses. */ krb5_free_principal(contextp->context, princ); goto fail; } } ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if (ret == 0){ if (keys_ok) kadm5_store_principal_ent(sp, &ent); else kadm5_store_principal_ent_nokeys(sp, &ent); kadm5_free_principal_ent(kadm_handlep, &ent); } krb5_free_principal(contextp->context, princ); break; } case kadm_delete:{ op = "DELETE"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } ret = kadm5_delete_principal(kadm_handlep, princ); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_create:{ op = "CREATE"; ret = kadm5_ret_principal_ent(sp, &ent); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); goto fail; } ret = krb5_ret_string(sp, &password); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); goto fail; } krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal); if(ret){ kadm5_free_principal_ent(contextp->context, &ent); memset(password, 0, strlen(password)); free(password); goto fail; } ret = kadm5_create_principal(kadm_handlep, &ent, mask, password); kadm5_free_principal_ent(kadm_handlep, &ent); memset(password, 0, strlen(password)); free(password); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_modify:{ op = "MODIFY"; ret = kadm5_ret_principal_ent(sp, &ent); if(ret) goto fail; ret = krb5_ret_int32(sp, &mask); if(ret){ kadm5_free_principal_ent(contextp, &ent); goto fail; } krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY, ent.principal); if(ret){ kadm5_free_principal_ent(contextp, &ent); goto fail; } ret = kadm5_modify_principal(kadm_handlep, &ent, mask); kadm5_free_principal_ent(kadm_handlep, &ent); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_rename:{ op = "RENAME"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_principal(sp, &princ2); if(ret){ krb5_free_principal(contextp->context, princ); goto fail; } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ2, name2, sizeof(name2)); krb5_warnx(contextp->context, "%s: %s %s -> %s", client, op, name, name2); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, princ2) || _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); if(ret){ krb5_free_principal(contextp->context, princ); krb5_free_principal(contextp->context, princ2); goto fail; } ret = kadm5_rename_principal(kadm_handlep, princ, princ2); krb5_free_principal(contextp->context, princ); krb5_free_principal(contextp->context, princ2); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_chpass:{ op = "CHPASS"; ret = krb5_ret_principal(sp, &princ); if (ret) goto fail; ret = krb5_ret_string(sp, &password); if (ret) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &keepold); if (ret && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is allowed if at least one of: * * a) allowed by sysadmin * b) it's for the principal him/herself and this was an * initial ticket, but then, check with the password quality * function. * c) the user is on the CPW ACL. */ if (krb5_config_get_bool_default(contextp->context, NULL, TRUE, "kadmin", "allow_self_change_password", NULL) && initial && krb5_principal_compare (contextp->context, contextp->caller, princ)) { krb5_data pwd_data; const char *pwd_reason; pwd_data.data = password; pwd_data.length = strlen(password); pwd_reason = kadm5_check_password_quality (contextp->context, princ, &pwd_data); if (pwd_reason != NULL) ret = KADM5_PASS_Q_DICT; else ret = 0; } else ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) { krb5_free_principal(contextp->context, princ); memset(password, 0, strlen(password)); free(password); goto fail; } ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL, password); krb5_free_principal(contextp->context, princ); memset(password, 0, strlen(password)); free(password); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_chpass_with_key:{ int i; krb5_key_data *key_data; int n_key_data; op = "CHPASS_WITH_KEY"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; ret = krb5_ret_int32(sp, &n_key_data); if (ret) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &keepold); if (ret && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } /* n_key_data will be squeezed into an int16_t below. */ if (n_key_data < 0 || n_key_data >= 1 << 16 || (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) { ret = ERANGE; krb5_free_principal(contextp->context, princ); goto fail; } key_data = malloc (n_key_data * sizeof(*key_data)); if (key_data == NULL && n_key_data != 0) { ret = ENOMEM; krb5_free_principal(contextp->context, princ); goto fail; } for (i = 0; i < n_key_data; ++i) { ret = kadm5_ret_key_data (sp, &key_data[i]); if (ret) { int16_t dummy = i; kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); krb5_free_principal(contextp->context, princ); goto fail; } } krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is only allowed if the user is on the CPW ACL, * this it to force password quality check on the user. */ ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) { int16_t dummy = n_key_data; kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); krb5_free_principal(contextp->context, princ); goto fail; } ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold, n_key_data, key_data); { int16_t dummy = n_key_data; kadm5_free_key_data (contextp, &dummy, key_data); } free (key_data); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); break; } case kadm_randkey:{ op = "RANDKEY"; ret = krb5_ret_principal(sp, &princ); if(ret) goto fail; krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is allowed if at least one of: * a) it's for the principal him/herself and this was an initial ticket * b) the user is on the CPW ACL. */ if (initial && krb5_principal_compare (contextp->context, contextp->caller, princ)) ret = 0; else ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) { krb5_free_principal(contextp->context, princ); goto fail; } /* * See comments in kadm5_c_randkey_principal() regarding the * protocol. */ ret = krb5_ret_int32(sp, &keepold); if (ret != 0 && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &n_ks_tuple); if (ret != 0 && ret != HEIM_ERR_EOF) { krb5_free_principal(contextp->context, princ); goto fail; } else if (ret == 0) { size_t i; if (n_ks_tuple < 0) { ret = EOVERFLOW; krb5_free_principal(contextp->context, princ); goto fail; } if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) { ret = errno; krb5_free_principal(contextp->context, princ); goto fail; } for (i = 0; i < n_ks_tuple; i++) { ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype); if (ret != 0) { krb5_free_principal(contextp->context, princ); goto fail; } ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype); if (ret != 0) { krb5_free_principal(contextp->context, princ); goto fail; } } } ret = kadm5_randkey_principal_3(kadm_handlep, princ, keepold, n_ks_tuple, ks_tuple, &new_keys, &n_keys); krb5_free_principal(contextp->context, princ); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0){ int i; krb5_store_int32(sp, n_keys); for(i = 0; i < n_keys; i++){ krb5_store_keyblock(sp, new_keys[i]); krb5_free_keyblock_contents(contextp->context, &new_keys[i]); } free(new_keys); } break; } case kadm_get_privs:{ uint32_t privs; ret = kadm5_get_privs(kadm_handlep, &privs); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0) krb5_store_uint32(sp, privs); break; } case kadm_get_princs:{ op = "LIST"; ret = krb5_ret_int32(sp, &tmp); if(ret) goto fail; if(tmp){ ret = krb5_ret_string(sp, &expression); if(ret) goto fail; }else expression = NULL; krb5_warnx(contextp->context, "%s: %s %s", client, op, expression ? expression : "*"); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_LIST, NULL); if(ret){ free(expression); goto fail; } ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs); free(expression); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, ret); if(ret == 0){ int i; krb5_store_int32(sp, n_princs); for(i = 0; i < n_princs; i++) krb5_store_string(sp, princs[i]); kadm5_free_name_list(kadm_handlep, princs, &n_princs); } break; } default: krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd); krb5_storage_free(sp); sp = krb5_storage_emem(); krb5_store_int32(sp, KADM5_FAILURE); break; } krb5_storage_to_data(sp, out); krb5_storage_free(sp); return 0; fail: krb5_warn(contextp->context, ret, "%s", op); krb5_storage_seek(sp, 0, SEEK_SET); krb5_store_int32(sp, ret); krb5_storage_to_data(sp, out); krb5_storage_free(sp); return 0; }
krb5_kdc_configuration * configure(krb5_context context, int argc, char **argv, int *optidx) { krb5_kdc_configuration *config; krb5_error_code ret; const char *p; *optidx = 0; while(getarg(args, num_args, argc, argv, optidx)) warnx("error at argument `%s'", argv[*optidx]); if(help_flag) usage (0); if (version_flag) { print_version(NULL); exit(0); } if (builtin_hdb_flag) { char *list; ret = hdb_list_builtin(context, &list); if (ret) krb5_err(context, 1, ret, "listing builtin hdb backends"); printf("builtin hdb backends: %s\n", list); free(list); exit(0); } { char **files; int aret; if (config_file == NULL) { aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); if (aret == -1 || config_file == NULL) errx(1, "out of memory"); } ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(context, 1, ret, "getting configuration files"); ret = krb5_set_config_files(context, files); krb5_free_config_files(files); if(ret) krb5_err(context, 1, ret, "reading configuration files"); } ret = krb5_kdc_get_config(context, &config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_default_config"); kdc_openlog(context, "kdc", config); ret = krb5_kdc_set_dbinfo(context, config); if (ret) krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); if(max_request_str) max_request_tcp = max_request_udp = parse_bytes(max_request_str, NULL); if(max_request_tcp == 0){ p = krb5_config_get_string (context, NULL, "kdc", "max-request", NULL); if(p) max_request_tcp = max_request_udp = parse_bytes(p, NULL); } if(require_preauth != -1) config->require_preauth = require_preauth; if(port_str == NULL){ p = krb5_config_get_string(context, NULL, "kdc", "ports", NULL); if (p != NULL) port_str = strdup(p); } explicit_addresses.len = 0; if (addresses_str.num_strings) { int i; for (i = 0; i < addresses_str.num_strings; ++i) add_one_address (context, addresses_str.strings[i], i == 0); free_getarg_strings (&addresses_str); } else { char **foo = krb5_config_get_strings (context, NULL, "kdc", "addresses", NULL); if (foo != NULL) { add_one_address (context, *foo++, TRUE); while (*foo) add_one_address (context, *foo++, FALSE); } } if(enable_http == -1) enable_http = krb5_config_get_bool(context, NULL, "kdc", "enable-http", NULL); if(request_log == NULL) request_log = krb5_config_get_string(context, NULL, "kdc", "kdc-request-log", NULL); if (krb5_config_get_string(context, NULL, "kdc", "enforce-transited-policy", NULL)) krb5_errx(context, 1, "enforce-transited-policy deprecated, " "use [kdc]transited-policy instead"); #ifdef SUPPORT_DETACH if(detach_from_console == -1) detach_from_console = krb5_config_get_bool_default(context, NULL, DETACH_IS_DEFAULT, "kdc", "detach", NULL); #endif /* SUPPORT_DETACH */ if(max_request_tcp == 0) max_request_tcp = 64 * 1024; if(max_request_udp == 0) max_request_udp = 64 * 1024; if (port_str == NULL) port_str = "+"; if(disable_des == -1) disable_des = krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "disable-des", NULL); if(disable_des) { krb5_enctype_disable(context, ETYPE_DES_CBC_CRC); krb5_enctype_disable(context, ETYPE_DES_CBC_MD4); krb5_enctype_disable(context, ETYPE_DES_CBC_MD5); krb5_enctype_disable(context, ETYPE_DES_CBC_NONE); krb5_enctype_disable(context, ETYPE_DES_CFB64_NONE); krb5_enctype_disable(context, ETYPE_DES_PCBC_NONE); } krb5_kdc_windc_init(context); krb5_kdc_pkinit_config(context, config); return config; }
krb5_error_code krb5_kdc_pk_initialize(krb5_context context, krb5_kdc_configuration *config, const char *user_id, const char *anchors, char **pool, char **revoke_list) { const char *file; char *fn = NULL; krb5_error_code ret; file = krb5_config_get_string(context, NULL, "libdefaults", "moduli", NULL); ret = _krb5_parse_moduli(context, file, &moduli); if (ret) krb5_err(context, 1, ret, "PKINIT: failed to load modidi file"); principal_mappings.len = 0; principal_mappings.val = NULL; ret = _krb5_pk_load_id(context, &kdc_identity, user_id, anchors, pool, revoke_list, NULL, NULL, NULL); if (ret) { krb5_warn(context, ret, "PKINIT: "); config->enable_pkinit = 0; return ret; } { hx509_query *q; hx509_cert cert; ret = hx509_query_alloc(context->hx509ctx, &q); if (ret) { krb5_warnx(context, "PKINIT: out of memory"); return ENOMEM; } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); if (config->pkinit_kdc_friendly_name) hx509_query_match_friendly_name(q, config->pkinit_kdc_friendly_name); ret = hx509_certs_find(context->hx509ctx, kdc_identity->certs, q, &cert); hx509_query_free(context->hx509ctx, q); if (ret == 0) { if (hx509_cert_check_eku(context->hx509ctx, cert, &asn1_oid_id_pkkdcekuoid, 0)) { hx509_name name; char *str; ret = hx509_cert_get_subject(cert, &name); if (ret == 0) { hx509_name_to_string(name, &str); krb5_warnx(context, "WARNING Found KDC certificate (%s)" "is missing the PK-INIT KDC EKU, this is bad for " "interoperability.", str); hx509_name_free(&name); free(str); } } hx509_cert_free(cert); } else krb5_warnx(context, "PKINIT: failed to find a signing " "certifiate with a public key"); } if (krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "pkinit_allow_proxy_certificate", NULL)) config->pkinit_allow_proxy_certs = 1; file = krb5_config_get_string(context, NULL, "kdc", "pkinit_mappings_file", NULL); if (file == NULL) { int aret; aret = asprintf(&fn, "%s/pki-mapping", hdb_db_dir(context)); if (aret == -1) { krb5_warnx(context, "PKINIT: out of memory"); return ENOMEM; } file = fn; } load_mappings(context, file); if (fn) free(fn); return 0; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache = NULL; HDB *db = NULL; int optidx = 0; int type, exit_code; setprogname(argv[0]); if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); if(version_flag){ print_version(NULL); exit(0); } ret = krb5_init_context(&context); if(ret) exit(1); if(local_realm) krb5_set_default_realm(context, local_realm); if(v4_realm == NULL) { ret = krb5_get_default_realm(context, &v4_realm); if(ret) krb5_err(context, 1, ret, "krb5_get_default_realm"); } if(afs_cell == NULL) { afs_cell = strdup(v4_realm); if(afs_cell == NULL) krb5_errx(context, 1, "out of memory"); strlwr(afs_cell); } if(encrypt_flag && decrypt_flag) krb5_errx(context, 1, "only one of `--encrypt' and `--decrypt' is meaningful"); if(source_type != NULL) { type = parse_source_type(source_type); if(type == 0) krb5_errx(context, 1, "unknown source type `%s'", source_type); } else type = HPROP_HEIMDAL; if(!to_stdout) get_creds(context, &ccache); if(decrypt_flag || encrypt_flag) { ret = hdb_read_master_key(context, mkeyfile, &mkey5); if(ret && ret != ENOENT) krb5_err(context, 1, ret, "hdb_read_master_key"); if(ret) krb5_errx(context, 1, "No master key file found"); } if (IS_TYPE_V4(type) && v4_realm == NULL) krb5_errx(context, 1, "Its a Kerberos 4 database " "but no realm configured"); switch(type) { case HPROP_KASERVER: if (database == NULL) database = DEFAULT_DATABASE; ka_use_null_salt = krb5_config_get_bool_default(context, NULL, FALSE, "hprop", "afs_uses_null_salt", NULL); break; case HPROP_KRB4_DUMP: if (database == NULL) krb5_errx(context, 1, "no dump file specified"); break; case HPROP_MIT_DUMP: if (database == NULL) krb5_errx(context, 1, "no dump file specified"); break; case HPROP_HEIMDAL: ret = hdb_create (context, &db, database); if(ret) krb5_err(context, 1, ret, "hdb_create: %s", database); ret = db->hdb_open(context, db, O_RDONLY, 0); if(ret) krb5_err(context, 1, ret, "db->hdb_open"); break; default: krb5_errx(context, 1, "unknown dump type `%d'", type); break; } if (to_stdout) exit_code = dump_database (context, type, database, db); else exit_code = propagate_database (context, type, database, db, ccache, optidx, argc, argv); if(ccache != NULL) krb5_cc_destroy(context, ccache); if(db != NULL) (*db->hdb_destroy)(context, db); krb5_free_context(context); return exit_code; }
krb5_error_code krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) { krb5_kdc_configuration *c; c = calloc(1, sizeof(*c)); if (c == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } c->require_preauth = TRUE; c->kdc_warn_pwexpire = 0; c->encode_as_rep_as_tgs_rep = FALSE; c->tgt_use_strongest_session_key = FALSE; c->preauth_use_strongest_session_key = FALSE; c->svc_use_strongest_session_key = FALSE; c->use_strongest_server_key = TRUE; c->check_ticket_addresses = TRUE; c->allow_null_ticket_addresses = TRUE; c->allow_anonymous = FALSE; c->trpolicy = TRPOLICY_ALWAYS_CHECK; c->enable_pkinit = FALSE; c->pkinit_princ_in_cert = TRUE; c->pkinit_require_binding = TRUE; c->db = NULL; c->num_db = 0; c->logf = NULL; c->require_preauth = krb5_config_get_bool_default(context, NULL, c->require_preauth, "kdc", "require-preauth", NULL); #ifdef DIGEST c->enable_digest = krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "enable-digest", NULL); { const char *digests; digests = krb5_config_get_string(context, NULL, "kdc", "digests_allowed", NULL); if (digests == NULL) digests = "ntlm-v2"; c->digests_allowed = parse_flags(digests,_kdc_digestunits, 0); if (c->digests_allowed == -1) { kdc_log(context, c, 0, "unparsable digest units (%s), turning off digest", digests); c->enable_digest = 0; } else if (c->digests_allowed == 0) { kdc_log(context, c, 0, "no digest enable, turning digest off", digests); c->enable_digest = 0; } } #endif #ifdef KX509 c->enable_kx509 = krb5_config_get_bool_default(context, NULL, FALSE, "kdc", "enable-kx509", NULL); if (c->enable_kx509) { c->kx509_template = krb5_config_get_string(context, NULL, "kdc", "kx509_template", NULL); c->kx509_ca = krb5_config_get_string(context, NULL, "kdc", "kx509_ca", NULL); if (c->kx509_ca == NULL || c->kx509_template == NULL) { kdc_log(context, c, 0, "missing kx509 configuration, turning off"); c->enable_kx509 = FALSE; } } #endif c->tgt_use_strongest_session_key = krb5_config_get_bool_default(context, NULL, c->tgt_use_strongest_session_key, "kdc", "tgt-use-strongest-session-key", NULL); c->preauth_use_strongest_session_key = krb5_config_get_bool_default(context, NULL, c->preauth_use_strongest_session_key, "kdc", "preauth-use-strongest-session-key", NULL); c->svc_use_strongest_session_key = krb5_config_get_bool_default(context, NULL, c->svc_use_strongest_session_key, "kdc", "svc-use-strongest-session-key", NULL); c->use_strongest_server_key = krb5_config_get_bool_default(context, NULL, c->use_strongest_server_key, "kdc", "use-strongest-server-key", NULL); c->check_ticket_addresses = krb5_config_get_bool_default(context, NULL, c->check_ticket_addresses, "kdc", "check-ticket-addresses", NULL); c->allow_null_ticket_addresses = krb5_config_get_bool_default(context, NULL, c->allow_null_ticket_addresses, "kdc", "allow-null-ticket-addresses", NULL); c->allow_anonymous = krb5_config_get_bool_default(context, NULL, c->allow_anonymous, "kdc", "allow-anonymous", NULL); c->max_datagram_reply_length = krb5_config_get_int_default(context, NULL, 1400, "kdc", "max-kdc-datagram-reply-length", NULL); { const char *trpolicy_str; trpolicy_str = krb5_config_get_string_default(context, NULL, "DEFAULT", "kdc", "transited-policy", NULL); if(strcasecmp(trpolicy_str, "always-check") == 0) { c->trpolicy = TRPOLICY_ALWAYS_CHECK; } else if(strcasecmp(trpolicy_str, "allow-per-principal") == 0) { c->trpolicy = TRPOLICY_ALLOW_PER_PRINCIPAL; } else if(strcasecmp(trpolicy_str, "always-honour-request") == 0) { c->trpolicy = TRPOLICY_ALWAYS_HONOUR_REQUEST; } else if(strcasecmp(trpolicy_str, "DEFAULT") == 0) { /* default */ } else { kdc_log(context, c, 0, "unknown transited-policy: %s, " "reverting to default (always-check)", trpolicy_str); } } c->encode_as_rep_as_tgs_rep = krb5_config_get_bool_default(context, NULL, c->encode_as_rep_as_tgs_rep, "kdc", "encode_as_rep_as_tgs_rep", NULL); c->kdc_warn_pwexpire = krb5_config_get_time_default (context, NULL, c->kdc_warn_pwexpire, "kdc", "kdc_warn_pwexpire", NULL); c->enable_pkinit = krb5_config_get_bool_default(context, NULL, c->enable_pkinit, "kdc", "enable-pkinit", NULL); c->pkinit_kdc_identity = krb5_config_get_string(context, NULL, "kdc", "pkinit_identity", NULL); c->pkinit_kdc_anchors = krb5_config_get_string(context, NULL, "kdc", "pkinit_anchors", NULL); c->pkinit_kdc_cert_pool = krb5_config_get_strings(context, NULL, "kdc", "pkinit_pool", NULL); c->pkinit_kdc_revoke = krb5_config_get_strings(context, NULL, "kdc", "pkinit_revoke", NULL); c->pkinit_kdc_ocsp_file = krb5_config_get_string(context, NULL, "kdc", "pkinit_kdc_ocsp", NULL); c->pkinit_kdc_friendly_name = krb5_config_get_string(context, NULL, "kdc", "pkinit_kdc_friendly_name", NULL); c->pkinit_princ_in_cert = krb5_config_get_bool_default(context, NULL, c->pkinit_princ_in_cert, "kdc", "pkinit_principal_in_certificate", NULL); c->pkinit_require_binding = krb5_config_get_bool_default(context, NULL, c->pkinit_require_binding, "kdc", "pkinit_win2k_require_binding", NULL); c->pkinit_dh_min_bits = krb5_config_get_int_default(context, NULL, 0, "kdc", "pkinit_dh_min_bits", NULL); *config = c; return 0; }
static void store_tickets(struct passwd *pwd, int ticket_newfiles, int ticket_store, int token_install) { char cc_file[MAXPATHLEN]; krb5_ccache ccache_store; #ifdef KRB524 int get_krb4_ticket = 0; char krb4_ticket_file[MAXPATHLEN]; #endif if (ticket_newfiles) snprintf(cc_file, sizeof(cc_file), "FILE:/tmp/krb5cc_%d", pwd->pw_uid); else snprintf(cc_file, sizeof(cc_file), "%s", krb5_cc_default_name(context)); if (ticket_store) { ret = krb5_cc_resolve(context, cc_file, &ccache_store); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "krb5_cc_gen_new"); exit(1); } ret = krb5_cc_copy_cache(context, ccache, ccache_store); if (ret != 0) krb5_syslog(context, LOG_ERR, ret, "krb5_cc_copy_cache"); chown(krb5_cc_get_name(context, ccache_store), pwd->pw_uid, pwd->pw_gid); fprintf(back, BI_SETENV " KRB5CCNAME %s:%s\n", krb5_cc_get_type(context, ccache_store), krb5_cc_get_name(context, ccache_store)); #ifdef KRB524 get_krb4_ticket = krb5_config_get_bool_default (context, NULL, get_krb4_ticket, "libdefaults", "krb4_get_tickets", NULL); if (get_krb4_ticket) { CREDENTIALS c; krb5_creds cred; krb5_cc_cursor cursor; ret = krb5_cc_start_seq_get(context, ccache, &cursor); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "start seq"); exit(1); } ret = krb5_cc_next_cred(context, ccache, &cursor, &cred); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "next cred"); exit(1); } ret = krb5_cc_end_seq_get(context, ccache, &cursor); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "end seq"); exit(1); } ret = krb524_convert_creds_kdc_ccache(context, ccache, &cred, &c); if (ret != 0) { krb5_syslog(context, LOG_ERR, ret, "convert"); } else { snprintf(krb4_ticket_file, sizeof(krb4_ticket_file), "%s%d", TKT_ROOT, pwd->pw_uid); krb_set_tkt_string(krb4_ticket_file); tf_setup(&c, c.pname, c.pinst); chown(krb4_ticket_file, pwd->pw_uid, pwd->pw_gid); } } #endif } /* Need to chown the ticket file */ #ifdef KRB524 if (get_krb4_ticket) fprintf(back, BI_SETENV " KRBTKFILE %s\n", krb4_ticket_file); #endif }
krb5_error_code hdb_ldap_create(krb5_context context, HDB ** db, const char *arg) { struct hdbldapdb *h; const char *create_base = NULL; if (arg == NULL && arg[0] == '\0') { krb5_set_error_string(context, "ldap search base not configured"); return ENOMEM; /* XXX */ } if (structural_object == NULL) { const char *p; p = krb5_config_get_string(context, NULL, "kdc", "hdb-ldap-structural-object", NULL); if (p == NULL) p = default_structural_object; structural_object = strdup(p); if (structural_object == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } } samba_forwardable = krb5_config_get_bool_default(context, NULL, TRUE, "kdc", "hdb-samba-forwardable", NULL); *db = malloc(sizeof(**db)); if (*db == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } memset(*db, 0, sizeof(**db)); h = malloc(sizeof(*h)); if (h == NULL) { krb5_set_error_string(context, "malloc: out of memory"); free(*db); *db = NULL; return ENOMEM; } memset(h, 0, sizeof(*h)); asprintf(&(*db)->hdb_name, "ldap:%s", arg); (*db)->hdb_db = h; h->h_base = strdup(arg); if (h->h_base == NULL) { LDAP_destroy(context, *db); krb5_set_error_string(context, "strdup: out of memory"); *db = NULL; return ENOMEM; } create_base = krb5_config_get_string(context, NULL, "kdc", "hdb-ldap-create-base", NULL); if (create_base == NULL) create_base = h->h_base; h->h_createbase = strdup(create_base); if (h->h_createbase == NULL) { LDAP_destroy(context, *db); krb5_set_error_string(context, "strdup: out of memory"); *db = NULL; return ENOMEM; } (*db)->hdb_master_key_set = 0; (*db)->hdb_openp = 0; (*db)->hdb_open = LDAP_open; (*db)->hdb_close = LDAP_close; (*db)->hdb_fetch = LDAP_fetch; (*db)->hdb_store = LDAP_store; (*db)->hdb_remove = LDAP_remove; (*db)->hdb_firstkey = LDAP_firstkey; (*db)->hdb_nextkey = LDAP_nextkey; (*db)->hdb_lock = LDAP_lock; (*db)->hdb_unlock = LDAP_unlock; (*db)->hdb_rename = LDAP_rename; (*db)->hdb__get = NULL; (*db)->hdb__put = NULL; (*db)->hdb__del = NULL; (*db)->hdb_destroy = LDAP_destroy; return 0; }
static krb5_error_code init_tgs_req (krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, krb5_keyblock **subkey, TGS_REQ *t, krb5_key_usage usage) { krb5_error_code ret = 0; memset(t, 0, sizeof(*t)); t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->padata, 1); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } { krb5_auth_context ac; krb5_keyblock *key = NULL; ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", krbtgt->server->realm, "tgs_require_subkey", NULL)) { ret = krb5_generate_subkey (context, &krbtgt->session, &key); if (ret) { krb5_auth_con_free (context, ac); goto fail; } ret = krb5_auth_con_setlocalsubkey(context, ac, key); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } } ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key ? key : &krbtgt->session); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } ret = make_pa_tgs_req(context, ac, &t->req_body, t->padata->val, krbtgt, usage); if(ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free(context, ac); goto fail; } *subkey = key; krb5_auth_con_free(context, ac); } fail: if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }
static krb5_error_code fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, const char *serv_string, int port, int proto) { char *host = NULL; int ret; struct addrinfo *ai; struct addrinfo hints; char portstr[NI_MAXSERV]; ret = krb5_config_get_bool_default(context, NULL, KRB5_FALLBACK_DEFAULT, "libdefaults", "use_fallback", NULL); if (!ret) { kd->flags |= KD_FALLBACK; return 0; } _krb5_debug(context, 2, "fallback lookup %d for realm %s (service %s)", kd->fallback_count, kd->realm, serv_string); /* * Don't try forever in case the DNS server keep returning us * entries (like wildcard entries or the .nu TLD) * * Also don't try LKDC realms since fallback wont work on them at all. */ if(kd->fallback_count >= 5 || krb5_realm_is_lkdc(kd->realm)) { kd->flags |= KD_FALLBACK; return 0; } if(kd->fallback_count == 0) ret = asprintf(&host, "%s.%s.", serv_string, kd->realm); else ret = asprintf(&host, "%s-%d.%s.", serv_string, kd->fallback_count, kd->realm); if (ret < 0 || host == NULL) return ENOMEM; make_hints(&hints, proto); snprintf(portstr, sizeof(portstr), "%d", port); ret = getaddrinfo(host, portstr, &hints, &ai); if (ret) { /* no more hosts, so we're done here */ free(host); kd->flags |= KD_FALLBACK; } else { struct krb5_krbhst_info *hi; size_t hostlen = strlen(host); hi = calloc(1, sizeof(*hi) + hostlen); if(hi == NULL) { free(host); return ENOMEM; } hi->proto = proto; hi->port = hi->def_port = port; hi->ai = ai; memmove(hi->hostname, host, hostlen); hi->hostname[hostlen] = '\0'; free(host); append_host_hostinfo(kd, hi); kd->fallback_count++; } return 0; }