static int parse_hdbflags2int(HDBFlags *f, const char *s) { int ret; unsigned int tmp; ret = parse_integer (&tmp, s); if (ret == 1) *f = int2HDBFlags (tmp); return ret; }
static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_ldb_ent_type ent_type) { HDBFlags flags = int2HDBFlags(0); /* we don't allow kadmin deletes */ flags.immutable = 1; /* mark the principal as invalid to start with */ flags.invalid = 1; flags.renewable = 1; /* All accounts are servers, but this may be disabled again in the caller */ flags.server = 1; /* Account types - clear the invalid bit if it turns out to be valid */ if (userAccountControl & UF_NORMAL_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } flags.invalid = 0; } if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } flags.invalid = 0; } if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } flags.invalid = 0; } if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } flags.invalid = 0; } /* Not permitted to act as a client if disabled */ if (userAccountControl & UF_ACCOUNTDISABLE) { flags.client = 0; } if (userAccountControl & UF_LOCKOUT) { flags.invalid = 1; } /* if (userAccountControl & UF_PASSWORD_NOTREQD) { flags.invalid = 1; } */ /* UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent */ if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) { flags.invalid = 1; } /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in LDB_message2entry() */ /* if (userAccountControl & UF_MNS_LOGON_ACCOUNT) { flags.invalid = 1; } */ if (userAccountControl & UF_SMARTCARD_REQUIRED) { flags.require_hwauth = 1; } if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) { flags.ok_as_delegate = 1; } if (!(userAccountControl & UF_NOT_DELEGATED)) { flags.forwardable = 1; flags.proxiable = 1; } if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) { flags.require_preauth = 0; } else { flags.require_preauth = 1; } return flags; }
/* * 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; }