kadm5_ret_t _kadm5_bump_pw_expire(kadm5_server_context *context, hdb_entry *ent) { if (ent->pw_end != NULL) { time_t life; life = krb5_config_get_time_default(context->context, NULL, 365 * 24 * 60 * 60, "kadmin", "password_lifetime", NULL); *(ent->pw_end) = time(NULL) + life; } return 0; }
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; }
/* * Construct an hdb_entry from a directory entry. */ static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, hdb_entry_ex * ent) { char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; struct berval **keys; struct berval **vals; int tmp, tmp_time, i, ret, have_arcfour = 0; memset(ent, 0, sizeof(*ent)); ent->entry.flags = int2HDBFlags(0); ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name); if (ret == 0) { ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal); if (ret) goto out; } else { ret = LDAP_get_string_value(db, msg, "uid", &unparsed_name); if (ret == 0) { ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal); if (ret) goto out; } else { krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb-ldap: ldap entry missing" "principal name"); return HDB_ERR_NOENTRY; } } { int integer; ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber", &integer); if (ret) ent->entry.kvno = 0; else ent->entry.kvno = integer; } keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (keys != NULL) { int i; size_t l; ent->entry.keys.len = ldap_count_values_len(keys); ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key)); if (ent->entry.keys.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "calloc: out of memory"); goto out; } for (i = 0; i < ent->entry.keys.len; i++) { decode_Key((unsigned char *) keys[i]->bv_val, (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l); } ber_bvecfree(keys); } else { #if 1 /* * This violates the ASN1 but it allows a principal to * be related to a general directory entry without creating * the keys. Hopefully it's OK. */ ent->entry.keys.len = 0; ent->entry.keys.val = NULL; #else ret = HDB_ERR_NOENTRY; goto out; #endif } vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); if (vals != NULL) { int i; ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); if (ent->entry.etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret,"malloc: out of memory"); goto out; } ent->entry.etypes->len = ldap_count_values_len(vals); ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int)); if (ent->entry.etypes->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); ent->entry.etypes->len = 0; goto out; } for (i = 0; i < ent->entry.etypes->len; i++) { char *buf; buf = malloc(vals[i]->bv_len + 1); if (buf == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } memcpy(buf, vals[i]->bv_val, vals[i]->bv_len); buf[vals[i]->bv_len] = '\0'; ent->entry.etypes->val[i] = atoi(buf); free(buf); } ldap_value_free_len(vals); } for (i = 0; i < ent->entry.keys.len; i++) { if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { have_arcfour = 1; break; } } /* manually construct the NT (type 23) key */ ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN); if (ret == 0 && have_arcfour == 0) { unsigned *etypes; Key *keys; int i; keys = realloc(ent->entry.keys.val, (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0])); if (keys == NULL) { free(ntPasswordIN); ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ent->entry.keys.val = keys; memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key)); ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16); if (ret) { krb5_set_error_message(context, ret, "malloc: out of memory"); free(ntPasswordIN); ret = ENOMEM; goto out; } ret = hex_decode(ntPasswordIN, ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16); ent->entry.keys.len++; if (ent->entry.etypes == NULL) { ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); if (ent->entry.etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ent->entry.etypes->val = NULL; ent->entry.etypes->len = 0; } for (i = 0; i < ent->entry.etypes->len; i++) if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5) break; /* If there is no ARCFOUR enctype, add one */ if (i == ent->entry.etypes->len) { etypes = realloc(ent->entry.etypes->val, (ent->entry.etypes->len + 1) * sizeof(ent->entry.etypes->val[0])); if (etypes == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ent->entry.etypes->val = etypes; ent->entry.etypes->val[ent->entry.etypes->len] = ETYPE_ARCFOUR_HMAC_MD5; ent->entry.etypes->len++; } } ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp", &ent->entry.created_by.time); if (ret) ent->entry.created_by.time = time(NULL); ent->entry.created_by.principal = NULL; ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); if (ret == 0) { if (LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal) != 0) { ent->entry.created_by.principal = NULL; } free(dn); } ent->entry.modified_by = (Event *) malloc(sizeof(Event)); if (ent->entry.modified_by == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", &ent->entry.modified_by->time); if (ret == 0) { ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); if (LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal)) ent->entry.modified_by->principal = NULL; free(dn); } else { free(ent->entry.modified_by); ent->entry.modified_by = NULL; } ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start)); if (ent->entry.valid_start == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", ent->entry.valid_start); if (ret) { /* OPTIONAL */ free(ent->entry.valid_start); ent->entry.valid_start = NULL; } ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); if (ent->entry.valid_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", ent->entry.valid_end); if (ret) { /* OPTIONAL */ free(ent->entry.valid_end); ent->entry.valid_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time); if (ret == 0) { if (ent->entry.valid_end == NULL) { ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); if (ent->entry.valid_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } *ent->entry.valid_end = tmp_time; } ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); if (ent->entry.pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", ent->entry.pw_end); if (ret) { /* OPTIONAL */ free(ent->entry.pw_end); ent->entry.pw_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); if (ret == 0) { time_t delta; if (ent->entry.pw_end == NULL) { ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); if (ent->entry.pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } delta = krb5_config_get_time_default(context, NULL, 365 * 24 * 60 * 60, "kadmin", "password_lifetime", NULL); *ent->entry.pw_end = tmp_time + delta; } ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); if (ret == 0) { if (ent->entry.pw_end == NULL) { ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); if (ent->entry.pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } *ent->entry.pw_end = tmp_time; } /* OPTIONAL */ ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); if (ret == 0) hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time); { int max_life; ent->entry.max_life = malloc(sizeof(*ent->entry.max_life)); if (ent->entry.max_life == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life); if (ret) { free(ent->entry.max_life); ent->entry.max_life = NULL; } else *ent->entry.max_life = max_life; } { int max_renew; ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew)); if (ent->entry.max_renew == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew); if (ret) { free(ent->entry.max_renew); ent->entry.max_renew = NULL; } else *ent->entry.max_renew = max_renew; } ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp); if (ret) tmp = 0; ent->entry.flags = int2HDBFlags(tmp); /* Try and find Samba flags to put into the mix */ ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags); if (ret == 0) { /* parse the [UXW...] string: 'N' No password 'D' Disabled 'H' Homedir required 'T' Temp account. 'U' User account (normal) 'M' MNS logon user account - what is this ? 'W' Workstation account 'S' Server account 'L' Locked account 'X' No Xpiry on password 'I' Interdomain trust account */ int i; int flags_len = strlen(samba_acct_flags); if (flags_len < 2) goto out2; if (samba_acct_flags[0] != '[' || samba_acct_flags[flags_len - 1] != ']') goto out2; /* Allow forwarding */ if (samba_forwardable) ent->entry.flags.forwardable = TRUE; for (i=0; i < flags_len; i++) { switch (samba_acct_flags[i]) { case ' ': case '[': case ']': break; case 'N': /* how to handle no password in kerberos? */ break; case 'D': ent->entry.flags.invalid = TRUE; break; case 'H': break; case 'T': /* temp duplicate */ ent->entry.flags.invalid = TRUE; break; case 'U': ent->entry.flags.client = TRUE; break; case 'M': break; case 'W': case 'S': ent->entry.flags.server = TRUE; ent->entry.flags.client = TRUE; break; case 'L': ent->entry.flags.invalid = TRUE; break; case 'X': if (ent->entry.pw_end) { free(ent->entry.pw_end); ent->entry.pw_end = NULL; } break; case 'I': ent->entry.flags.server = TRUE; ent->entry.flags.client = TRUE; break; } } out2: free(samba_acct_flags); } ret = 0; out: if (unparsed_name) free(unparsed_name); if (ret) hdb_free_entry(context, ent); return ret; }