static krb5_error_code LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry, const char *attribute, KerberosTime * kt) { char *tmp, *gentime; struct tm tm; int ret; *kt = 0; ret = LDAP_get_string_value(db, entry, attribute, &gentime); if (ret) return ret; tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm); if (tmp == NULL) { free(gentime); return HDB_ERR_NOENTRY; } free(gentime); *kt = timegm(&tm); return 0; }
static krb5_error_code LDAP_get_integer_value(HDB * db, LDAPMessage * entry, const char *attribute, int *ptr) { krb5_error_code ret; char *val; ret = LDAP_get_string_value(db, entry, attribute, &val); if (ret) return ret; *ptr = atoi(val); free(val); return 0; }
static krb5_error_code LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, krb5_principal * principal) { krb5_error_code ret; int rc; const char *filter = "(objectClass=krb5Principal)"; LDAPMessage *res = NULL, *e; char *p; ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, filter, krb5principal_attrs, 0, NULL, NULL, NULL, 0, &res); if (check_ldap(context, db, rc)) { ret = HDB_ERR_NOENTRY; krb5_set_error_message(context, ret, "ldap_search_ext_s: " "filter: %s error: %s", filter, ldap_err2string(rc)); goto out; } e = ldap_first_entry(HDB2LDAP(db), res); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p); if (ret) { ret = HDB_ERR_NOENTRY; goto out; } ret = krb5_parse_name(context, p, principal); free(p); out: if (res) ldap_msgfree(res); return ret; }
/* * Construct an hdb_entry from a directory entry. */ static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, hdb_entry * ent) { char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; int ret; unsigned long tmp; struct berval **keys; char **values; int tmp_time; memset(ent, 0, sizeof(*ent)); ent->flags = int2HDBFlags(0); ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name); if (ret == 0) { ret = krb5_parse_name(context, unparsed_name, &ent->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->principal); if (ret) goto out; } else { krb5_set_error_string(context, "hdb-ldap: ldap entry missing" "principal name"); return HDB_ERR_NOENTRY; } } ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber", &ent->kvno); if (ret) ent->kvno = 0; keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); if (keys != NULL) { int i; size_t l; ent->keys.len = ldap_count_values_len(keys); ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key)); if (ent->keys.val == NULL) { krb5_set_error_string(context, "calloc: out of memory"); ret = ENOMEM; goto out; } for (i = 0; i < ent->keys.len; i++) { decode_Key((unsigned char *) keys[i]->bv_val, (size_t) keys[i]->bv_len, &ent->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->keys.len = 0; ent->keys.val = NULL; #else ret = HDB_ERR_NOENTRY; goto out; #endif } values = ldap_get_values(HDB2LDAP(db), msg, "krb5EncryptionType"); if (values != NULL) { int i; ent->etypes = malloc(sizeof(*(ent->etypes))); if (ent->etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->len = ldap_count_values(values); ent->etypes->val = calloc(ent->etypes->len, sizeof(int)); if (ent->etypes->val == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } for (i = 0; i < ent->etypes->len; i++) { ent->etypes->val[i] = atoi(values[i]); } ldap_value_free(values); } /* manually construct the NT (type 23) key */ ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN); if (ret == 0) { int *etypes; Key *keys; keys = realloc(ent->keys.val, (ent->keys.len + 1) * sizeof(ent->keys.val[0])); if (keys == NULL) { free(ntPasswordIN); krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->keys.val = keys; memset(&ent->keys.val[ent->keys.len], 0, sizeof(Key)); ent->keys.val[ent->keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; ret = krb5_data_alloc (&ent->keys.val[ent->keys.len].key.keyvalue, 16); if (ret) { krb5_set_error_string(context, "malloc: out of memory"); free(ntPasswordIN); ret = ENOMEM; goto out; } ret = hex_decode(ntPasswordIN, ent->keys.val[ent->keys.len].key.keyvalue.data, 16); ent->keys.len++; if (ent->etypes == NULL) { ent->etypes = malloc(sizeof(*(ent->etypes))); if (ent->etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->val = NULL; ent->etypes->len = 0; } etypes = realloc(ent->etypes->val, (ent->etypes->len + 1) * sizeof(ent->etypes->val[0])); if (etypes == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ent->etypes->val = etypes; ent->etypes->val[ent->etypes->len] = ETYPE_ARCFOUR_HMAC_MD5; ent->etypes->len++; } ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp", &ent->created_by.time); if (ret) ent->created_by.time = time(NULL); ent->created_by.principal = NULL; ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); if (ret == 0) { if (LDAP_dn2principal(context, db, dn, &ent->created_by.principal) != 0) { ent->created_by.principal = NULL; } free(dn); } ent->modified_by = (Event *) malloc(sizeof(Event)); if (ent->modified_by == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", &ent->modified_by->time); if (ret == 0) { ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); if (LDAP_dn2principal(context, db, dn, &ent->modified_by->principal)) ent->modified_by->principal = NULL; free(dn); } else { free(ent->modified_by); ent->modified_by = NULL; } ent->valid_start = malloc(sizeof(*ent->valid_start)); if (ent->valid_start == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", ent->valid_start); if (ret) { /* OPTIONAL */ free(ent->valid_start); ent->valid_start = NULL; } ent->valid_end = malloc(sizeof(*ent->valid_end)); if (ent->valid_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", ent->valid_end); if (ret) { /* OPTIONAL */ free(ent->valid_end); ent->valid_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time); if (ret == 0) { if (ent->valid_end == NULL) { ent->valid_end = malloc(sizeof(*ent->valid_end)); if (ent->valid_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } } *ent->valid_end = tmp_time; } ent->pw_end = malloc(sizeof(*ent->pw_end)); if (ent->pw_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", ent->pw_end); if (ret) { /* OPTIONAL */ free(ent->pw_end); ent->pw_end = NULL; } ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); if (ret == 0) { if (ent->pw_end == NULL) { ent->pw_end = malloc(sizeof(*ent->pw_end)); if (ent->pw_end == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } } *ent->pw_end = tmp_time; } #if 0 /* we we have last_pw_change */ ent->last_pw_change = malloc(sizeof(*ent->last_pw_change)); if (ent->last_pw_change == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); if (ret) { /* OPTIONAL */ free(ent->last_pw_change); ent->last_pw_change = NULL; } else *ent->last_pw_change = tmp_time; #endif ent->max_life = malloc(sizeof(*ent->max_life)); if (ent->max_life == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", ent->max_life); if (ret) { free(ent->max_life); ent->max_life = NULL; } ent->max_renew = malloc(sizeof(*ent->max_renew)); if (ent->max_renew == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", ent->max_renew); if (ret) { free(ent->max_renew); ent->max_renew = NULL; } values = ldap_get_values(HDB2LDAP(db), msg, "krb5KDCFlags"); if (values != NULL) { errno = 0; tmp = strtoul(values[0], (char **) NULL, 10); if (tmp == ULONG_MAX && errno == ERANGE) { krb5_set_error_string(context, "strtoul: could not convert flag"); ret = ERANGE; goto out; } } else { tmp = 0; } ent->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->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->flags.invalid = TRUE; break; case 'H': break; case 'T': /* temp duplicate */ ent->flags.invalid = TRUE; break; case 'U': ent->flags.client = TRUE; break; case 'M': break; case 'W': case 'S': ent->flags.server = TRUE; ent->flags.client = TRUE; break; case 'L': ent->flags.invalid = TRUE; break; case 'X': if (ent->pw_end) { free(ent->pw_end); ent->pw_end = NULL; } break; case 'I': ent->flags.server = TRUE; ent->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; }