1
/** BEGIN COPYRIGHT BLOCK
2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation, either version 3 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
* Additional permission under GPLv3 section 7:
17
* In the following paragraph, "GPL" means the GNU General Public
18
* License, version 3 or any later version, and "Non-GPL Code" means
19
* code that is governed neither by the GPL nor a license
20
* compatible with the GPL.
22
* You may link the code of this Program with Non-GPL Code and convey
23
* linked combinations including the two, provided that such Non-GPL
24
* Code only links to the code of this Program through those well
25
* defined interfaces identified in the file named EXCEPTION found in
26
* the source code files (the "Approved Interfaces"). The files of
27
* Non-GPL Code may instantiate templates or use macros or inline
28
* functions from the Approved Interfaces without causing the resulting
29
* work to be covered by the GPL. Only the copyright holders of this
30
* Program may make changes or additions to the list of Approved
34
* Simo Sorce <ssorce@redhat.com>
36
* Copyright (C) 2007-2010 Red Hat, Inc.
37
* All rights reserved.
38
* END COPYRIGHT BLOCK **/
43
/* Attribute defines */
44
#define IPA_OTP_USER_AUTH_TYPE "ipaUserAuthType"
46
/* Type of connection for this operation;*/
47
#define LDAP_EXTOP_PASSMOD_CONN_SECURE
49
/* Uncomment the following #undef FOR TESTING:
50
* allows non-SSL connections to use the password change extended op */
51
/* #undef LDAP_EXTOP_PASSMOD_CONN_SECURE */
53
extern void *ipapwd_plugin_id;
54
extern const char *ipa_realm_dn;
55
extern const char *ipa_etc_config_dn;
56
extern const char *ipa_pwd_config_dn;
58
/* These are the default enc:salt types if nothing is defined.
59
* TODO: retrieve the configure set of ecntypes either from the
60
* kfc.conf file or by synchronizing the file content into
62
static const char *ipapwd_def_encsalts[] = {
63
"des3-hmac-sha1:normal",
64
/* "arcfour-hmac:normal",
65
"des-hmac-sha1:normal",
66
"des-cbc-md5:normal", */
69
"des-cbc-crc:afs3", */
73
static PRInt32 g_allowed_auth_types = 0;
76
* Checks if an authentication type is allowed. A NULL terminated
77
* list of allowed auth type values is passed in along with the flag
78
* for the auth type you are inquiring about. If auth_type_list is
79
* NULL, the global config will be consulted.
81
bool ipapwd_is_auth_type_allowed(char **auth_type_list, int auth_type)
83
char *auth_type_value = NULL;
86
/* Get the string value for the authentication type we are checking for. */
88
case IPA_OTP_AUTH_TYPE_OTP:
89
auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_OTP;
91
case IPA_OTP_AUTH_TYPE_PASSWORD:
92
auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PASSWORD;
94
case IPA_OTP_AUTH_TYPE_PKINIT:
95
auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PKINIT;
97
default: /* Unknown type.*/
101
if (auth_type_list == NULL) {
102
/* Check if the requested authentication type is in the global list. */
103
PRInt32 auth_type_flags;
105
/* Do an atomic read of the allowed auth types bit field. */
106
auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0);
108
/* Check if the flag for the desired auth type is set. */
109
return auth_type_flags & auth_type;
112
/* Check if the requested authentication type is in the user list. */
113
for (i = 0; auth_type_list[i]; i++) {
114
if (strcasecmp(auth_type_list[i], auth_type_value) == 0) {
123
* Parses and validates an OTP config entry. If apply is non-zero, then
124
* we will load and start using the new config. You can simply
125
* validate config without making any changes by setting apply to false.
127
bool ipapwd_parse_otp_config_entry(Slapi_Entry * e, bool apply)
129
PRInt32 allowed_auth_types = 0;
130
PRInt32 default_auth_types = 0;
131
char **auth_types = NULL;
133
/* If no auth types are set, we default to only allowing password
134
* authentication. Other authentication types can be allowed at the
136
default_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD;
139
/* There is no config entry, so just set the defaults. */
140
allowed_auth_types = default_auth_types;
144
/* Parse and validate the config entry. We currently tolerate invalid
145
* config settings, so there is no real validation performed. We will
146
* likely want to reject invalid config as we expand the plug-in
147
* functionality, so the validation logic is here for us to use later. */
149
/* Fetch the auth type values from the config entry. */
150
auth_types = slapi_entry_attr_get_charray(e, IPA_OTP_USER_AUTH_TYPE);
151
if (auth_types == NULL) {
152
/* No allowed auth types are specified, so set the defaults. */
153
allowed_auth_types = default_auth_types;
157
/* Check each type to see if it is set. */
158
if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_DISABLED)) {
159
allowed_auth_types |= IPA_OTP_AUTH_TYPE_DISABLED;
162
if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PASSWORD)) {
163
allowed_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD;
166
if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_OTP)) {
167
allowed_auth_types |= IPA_OTP_AUTH_TYPE_OTP;
170
if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PKINIT)) {
171
allowed_auth_types |= IPA_OTP_AUTH_TYPE_PKINIT;
174
if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_RADIUS)) {
175
allowed_auth_types |= IPA_OTP_AUTH_TYPE_RADIUS;
178
slapi_ch_array_free(auth_types);
182
/* Atomically set the global allowed types. */
183
PR_ATOMIC_SET(&g_allowed_auth_types, allowed_auth_types);
189
bool ipapwd_otp_is_disabled(void)
191
PRInt32 auth_type_flags;
193
/* Do an atomic read of the allowed auth types bit field. */
194
auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0);
196
/* Check if the disabled bit is set. */
197
return auth_type_flags & IPA_OTP_AUTH_TYPE_DISABLED;
200
static struct ipapwd_krbcfg *ipapwd_getConfig(void)
202
krb5_error_code krberr;
203
struct ipapwd_krbcfg *config = NULL;
204
krb5_keyblock *kmkey = NULL;
205
Slapi_Entry *realm_entry = NULL;
206
Slapi_Entry *config_entry = NULL;
209
BerElement *be = NULL;
212
const struct berval *bval;
213
struct berval *mkey = NULL;
219
config = calloc(1, sizeof(struct ipapwd_krbcfg));
224
kmkey = calloc(1, sizeof(krb5_keyblock));
229
config->kmkey = kmkey;
231
krberr = krb5_init_context(&config->krbctx);
233
LOG_FATAL("krb5_init_context failed\n");
237
ret = krb5_get_default_realm(config->krbctx, &config->realm);
239
LOG_FATAL("Failed to get default realm?!\n");
243
/* get the Realm Container entry */
244
ret = ipapwd_getEntry(ipa_realm_dn, &realm_entry, NULL);
245
if (ret != LDAP_SUCCESS) {
246
LOG_FATAL("No realm Entry?\n");
250
/*** get the Kerberos Master Key ***/
252
ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
254
LOG_FATAL("No master key??\n");
258
/* there should be only one value here */
259
ret = slapi_attr_first_value(a, &v);
261
LOG_FATAL("No master key??\n");
265
bval = slapi_value_get_berval(v);
267
LOG_FATAL("Error retrieving master key berval\n");
271
be = ber_init(discard_const(bval));
273
LOG_FATAL("ber_init() failed!\n");
277
tag = ber_scanf(be, "{i{iO}}", &tvno, &ttype, &mkey);
278
if (tag == LBER_ERROR) {
279
LOG_FATAL("Bad Master key encoding ?!\n");
283
config->mkvno = tvno;
284
kmkey->magic = KV5M_KEYBLOCK;
285
kmkey->enctype = ttype;
286
kmkey->length = mkey->bv_len;
287
kmkey->contents = malloc(mkey->bv_len);
288
if (!kmkey->contents) {
292
memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
298
/*** get the Supported Enc/Salt types ***/
300
encsalts = slapi_entry_attr_get_charray(realm_entry,
301
"krbSupportedEncSaltTypes");
303
for (i = 0; encsalts[i]; i++) /* count */ ;
304
ret = parse_bval_key_salt_tuples(config->krbctx,
305
(const char * const *)encsalts, i,
306
&config->supp_encsalts,
307
&config->num_supp_encsalts);
308
slapi_ch_array_free(encsalts);
310
LOG("No configured salt types use defaults\n");
311
for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
312
ret = parse_bval_key_salt_tuples(config->krbctx,
313
ipapwd_def_encsalts, i,
314
&config->supp_encsalts,
315
&config->num_supp_encsalts);
318
LOG_FATAL("Can't get Supported EncSalt Types\n");
322
/*** get the Preferred Enc/Salt types ***/
324
encsalts = slapi_entry_attr_get_charray(realm_entry,
325
"krbDefaultEncSaltTypes");
327
for (i = 0; encsalts[i]; i++) /* count */ ;
328
ret = parse_bval_key_salt_tuples(config->krbctx,
329
(const char * const *)encsalts, i,
330
&config->pref_encsalts,
331
&config->num_pref_encsalts);
332
slapi_ch_array_free(encsalts);
334
LOG("No configured salt types use defaults\n");
335
for (i = 0; ipapwd_def_encsalts[i]; i++) /* count */ ;
336
ret = parse_bval_key_salt_tuples(config->krbctx,
337
ipapwd_def_encsalts, i,
338
&config->pref_encsalts,
339
&config->num_pref_encsalts);
342
LOG_FATAL("Can't get Preferred EncSalt Types\n");
346
slapi_entry_free(realm_entry);
348
/* get the Realm Container entry */
349
ret = ipapwd_getEntry(ipa_pwd_config_dn, &config_entry, NULL);
350
if (ret != LDAP_SUCCESS) {
351
LOG_FATAL("No config Entry? Impossible!\n");
354
config->passsync_mgrs =
355
slapi_entry_attr_get_charray(config_entry, "passSyncManagersDNs");
356
/* now add Directory Manager, it is always added by default */
357
tmpstr = slapi_ch_strdup("cn=Directory Manager");
358
slapi_ch_array_add(&config->passsync_mgrs, tmpstr);
359
if (config->passsync_mgrs == NULL) {
363
for (i = 0; config->passsync_mgrs[i]; i++) /* count */ ;
364
config->num_passsync_mgrs = i;
366
slapi_entry_free(config_entry);
368
/* get the ipa etc/ipaConfig entry */
369
config->allow_lm_hash = false;
370
config->allow_nt_hash = false;
371
ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL);
372
if (ret != LDAP_SUCCESS) {
373
LOG_FATAL("No config Entry?\n");
376
tmparray = slapi_entry_attr_get_charray(config_entry,
378
for (i = 0; tmparray && tmparray[i]; i++) {
379
if (strcasecmp(tmparray[i], "AllowLMhash") == 0) {
380
config->allow_lm_hash = true;
383
if (strcasecmp(tmparray[i], "AllowNThash") == 0) {
384
config->allow_nt_hash = true;
388
if (tmparray) slapi_ch_array_free(tmparray);
391
slapi_entry_free(config_entry);
396
if (mkey) ber_bvfree(mkey);
397
if (be) ber_free(be, 1);
399
free(kmkey->contents);
403
if (config->krbctx) {
405
krb5_free_default_realm(config->krbctx, config->realm);
406
krb5_free_context(config->krbctx);
408
free(config->pref_encsalts);
409
free(config->supp_encsalts);
410
slapi_ch_array_free(config->passsync_mgrs);
413
slapi_entry_free(config_entry);
414
slapi_entry_free(realm_entry);
418
/* Easier handling for virtual attributes. You must call pwd_values_free()
419
* to free memory allocated here. It must be called before
420
* slapi_free_search_results_internal(entries) or
421
* slapi_pblock_destroy(pb)
423
static int pwd_get_values(const Slapi_Entry *ent, const char *attrname,
424
Slapi_ValueSet** results, char** actual_type_name,
428
int type_name_disposition = 0;
431
ret = slapi_vattr_values_get((Slapi_Entry *)ent, (char *)attrname,
432
results, &type_name_disposition,
433
actual_type_name, flags, buffer_flags);
438
static void pwd_values_free(Slapi_ValueSet** results,
439
char** actual_type_name, int buffer_flags)
441
slapi_vattr_values_free(results, actual_type_name, buffer_flags);
444
static int ipapwd_rdn_count(const char *dn)
450
ret = ldap_str2dn(dn, &ldn, LDAP_DN_FORMAT_LDAPV3);
451
if (ret != LDAP_SUCCESS) {
452
LOG_TRACE("ldap_str2dn(dn) failed ?!");
456
for (rdnc = 0; ldn != NULL && ldn[rdnc]; rdnc++) /* count */ ;
462
int ipapwd_getPolicy(const char *dn,
464
struct ipapwd_policy *policy)
466
const char *krbPwdPolicyReference;
468
const Slapi_DN *psdn;
470
Slapi_PBlock *pb = NULL;
471
char *attrs[] = { "krbMaxPwdLife", "krbMinPwdLife",
472
"krbPwdMinDiffChars", "krbPwdMinLength",
473
"krbPwdHistoryLength", NULL};
474
Slapi_Entry **es = NULL;
475
Slapi_Entry *pe = NULL;
476
int ret, res, dist, rdnc, scope, i;
477
Slapi_DN *sdn = NULL;
479
Slapi_ValueSet* results = NULL;
480
char* actual_type_name = NULL;
483
LOG_TRACE("Searching policy for [%s]\n", dn);
485
sdn = slapi_sdn_new_dn_byref(dn);
492
pwd_get_values(target, "krbPwdPolicyReference",
493
&results, &actual_type_name, &buffer_flags);
496
slapi_valueset_first_value(results, &sv);
497
krbPwdPolicyReference = slapi_value_get_string(sv);
498
pdn = krbPwdPolicyReference;
499
scope = LDAP_SCOPE_BASE;
500
LOG_TRACE("using policy reference: %s\n", pdn);
502
/* Find ancestor base DN */
503
be = slapi_be_select(sdn);
504
psdn = slapi_be_getsuffix(be, 0);
506
LOG_FATAL("Invalid DN [%s]\n", dn);
510
pdn = slapi_sdn_get_dn(psdn);
511
scope = LDAP_SCOPE_SUBTREE;
514
pb = slapi_pblock_new();
515
slapi_search_internal_set_pb(pb,
517
"(objectClass=krbPwdPolicy)",
524
/* do search the tree */
525
ret = slapi_search_internal_pb(pb);
526
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
527
if (ret == -1 || res != LDAP_SUCCESS) {
528
LOG_FATAL("Couldn't find policy, err (%d)\n", res ? res : ret);
534
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &es);
536
LOG_TRACE("No entries ?!");
542
for (i = 0; es[i]; i++) /* count */ ;
544
/* if there is only one, return that */
550
/* count number of RDNs in DN */
551
rdnc = ipapwd_rdn_count(dn);
553
LOG_TRACE("ipapwd_rdn_count(dn) failed");
561
/* find closest entry */
562
for (i = 0; es[i]; i++) {
563
const Slapi_DN *esdn;
565
esdn = slapi_entry_get_sdn_const(es[i]);
566
if (esdn == NULL) continue;
567
if (0 == slapi_sdn_compare(esdn, sdn)) {
572
if (slapi_sdn_issuffix(sdn, esdn)) {
576
dn1 = slapi_sdn_get_dn(esdn);
578
c1 = ipapwd_rdn_count(dn1);
579
if (c1 == -1) continue;
581
((rdnc - c1) < dist)) {
586
if (dist == 0) break; /* found closest */
595
policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife");
597
tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife");
599
policy->max_pwd_life = tmpint;
602
tmpint = slapi_entry_attr_get_int(pe, "krbPwdMinLength");
604
policy->min_pwd_length = tmpint;
607
policy->history_length = slapi_entry_attr_get_int(pe,
608
"krbPwdHistoryLength");
610
policy->min_complexity = slapi_entry_attr_get_int(pe,
611
"krbPwdMinDiffChars");
617
pwd_values_free(&results, &actual_type_name, buffer_flags);
620
slapi_free_search_results_internal(pb);
621
slapi_pblock_destroy(pb);
623
if (sdn) slapi_sdn_free(&sdn);
628
/*==Common-public-functions=============================================*/
630
int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
631
int *is_root, int *is_krb, int *is_smb, int *is_ipant,
638
slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, is_root);
641
/* verify this user is allowed to write a user password */
642
rc = slapi_access_allowed(pb, e, attr, NULL, acc);
643
if (rc != LDAP_SUCCESS) {
644
/* we have no business here, the operation will be denied anyway */
650
/* Check if this is a krbPrincial and therefore needs us to generate other
652
sval = slapi_value_new_string("krbPrincipalAux");
654
rc = LDAP_OPERATIONS_ERROR;
657
*is_krb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
658
slapi_value_free(&sval);
660
sval = slapi_value_new_string("sambaSamAccount");
662
rc = LDAP_OPERATIONS_ERROR;
665
*is_smb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
666
slapi_value_free(&sval);
668
sval = slapi_value_new_string("ipaNTUserAttrs");
670
rc = LDAP_OPERATIONS_ERROR;
673
*is_ipant = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
675
slapi_value_free(&sval);
683
int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
684
struct ipapwd_krbcfg **config, int check_flags)
687
int rc = LDAP_SUCCESS;
689
const Slapi_DN *psdn;
695
#ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE
696
if (check_flags & IPAPWD_CHECK_CONN_SECURE) {
697
/* Allow password modify on all connections with a Security Strength
698
* Factor (SSF) higher than 1 */
699
if (slapi_pblock_get(pb, SLAPI_OPERATION_SSF, &ssf) != 0) {
700
LOG("Could not get SSF from connection\n");
701
*errMesg = "Operation requires a secure connection.\n";
702
rc = LDAP_OPERATIONS_ERROR;
707
*errMesg = "Operation requires a secure connection.\n";
708
rc = LDAP_CONFIDENTIALITY_REQUIRED;
714
if (check_flags & IPAPWD_CHECK_DN) {
715
/* check we have a valid DN in the pblock or just abort */
716
ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
718
LOG("Tried to change password for an invalid DN [%s]\n",
720
*errMesg = "Invalid DN";
721
rc = LDAP_OPERATIONS_ERROR;
724
sdn = slapi_sdn_new_dn_byref(dn);
726
LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>");
727
*errMesg = "Internal Error";
728
rc = LDAP_OPERATIONS_ERROR;
731
be = slapi_be_select(sdn);
732
slapi_sdn_free(&sdn);
734
psdn = slapi_be_getsuffix(be, 0);
736
*errMesg = "Invalid DN";
737
rc = LDAP_OPERATIONS_ERROR;
742
/* get the kerberos context and master key */
743
*config = ipapwd_getConfig();
744
if (NULL == *config) {
745
LOG_FATAL("Error Retrieving Master Key");
746
*errMesg = "Fatal Internal Error";
747
rc = LDAP_OPERATIONS_ERROR;
754
/* check password strenght and history */
755
int ipapwd_CheckPolicy(struct ipapwd_data *data)
757
struct ipapwd_policy pol = {0};
758
time_t acct_expiration;
759
time_t pwd_expiration;
760
time_t last_pwd_change;
765
pol.max_pwd_life = IPAPWD_DEFAULT_PWDLIFE;
766
pol.min_pwd_length = IPAPWD_DEFAULT_MINLEN;
768
if (data->changetype != IPA_CHANGETYPE_NORMAL) {
769
/* We must skip policy checks (Admin change) but
770
* force a password change on the next login.
771
* But not if Directory Manager */
772
if (data->changetype == IPA_CHANGETYPE_ADMIN) {
773
/* The expiration date needs to be older than the current time
774
* otherwise the KDC may not immediately register the password
775
* as expired. The last password change needs to match the
776
* password expiration otherwise minlife issues will arise.
779
data->expireTime = data->timeNow;
782
/* do not load policies */
785
/* find the entry with the password policy */
786
ret = ipapwd_getPolicy(data->dn, data->target, &pol);
788
LOG_TRACE("No password policy, use defaults");
792
tmpstr = slapi_entry_attr_get_charptr(data->target,
793
"krbPrincipalExpiration");
794
acct_expiration = ipapwd_gentime_to_time_t(tmpstr);
795
slapi_ch_free_string(&tmpstr);
797
tmpstr = slapi_entry_attr_get_charptr(data->target,
798
"krbPasswordExpiration");
799
pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
800
slapi_ch_free_string(&tmpstr);
802
tmpstr = slapi_entry_attr_get_charptr(data->target,
804
last_pwd_change = ipapwd_gentime_to_time_t(tmpstr);
805
slapi_ch_free_string(&tmpstr);
807
pwd_history = slapi_entry_attr_get_charray(data->target,
811
ret = ipapwd_check_policy(&pol, data->password,
818
slapi_ch_array_free(pwd_history);
820
if (data->expireTime == 0) {
821
data->expireTime = data->timeNow + pol.max_pwd_life;
829
/* Searches the dn in directory,
830
* If found : fills in slapi_entry structure and returns 0
831
* If NOT found : returns the search result as LDAP_NO_SUCH_OBJECT
833
int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist)
836
int search_result = 0;
840
sdn = slapi_sdn_new_dn_byref(dn);
841
search_result = slapi_search_internal_get_entry(sdn, attrlist, e2,
843
if (search_result != LDAP_SUCCESS) {
844
LOG_TRACE("No such entry-(%s), err (%d)\n", dn, search_result);
847
slapi_sdn_free(&sdn);
848
LOG_TRACE("<= result: %d\n", search_result);
849
return search_result;
852
int ipapwd_get_cur_kvno(Slapi_Entry *target)
854
Slapi_Attr *krbPrincipalKey = NULL;
857
BerElement *be = NULL;
858
const struct berval *cbval;
865
/* retrieve current kvno and and keys */
866
ret = slapi_entry_attr_find(target, "krbPrincipalKey", &krbPrincipalKey);
873
slapi_attr_get_valueset(krbPrincipalKey, &svs);
874
hint = slapi_valueset_first_value(svs, &sv);
876
cbval = slapi_value_get_berval(sv);
878
LOG_TRACE("Error retrieving berval from Slapi_Value\n");
881
be = ber_init(discard_const(cbval));
883
LOG_TRACE("ber_init() failed!\n");
887
tag = ber_scanf(be, "{xxt[i]", &tmp, &tkvno);
888
if (tag == LBER_ERROR) {
889
LOG_TRACE("Bad OLD key encoding ?!\n");
900
hint = slapi_valueset_next_value(svs, hint, &sv);
906
/* Modify the Password attributes of the entry */
907
int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
908
struct ipapwd_data *data, int is_krb)
911
Slapi_Mods *smods = NULL;
912
Slapi_Value **svals = NULL;
913
Slapi_Value **ntvals = NULL;
914
Slapi_Value **pwvals = NULL;
916
char timestr[GENERALIZED_TIME_LENGTH+1];
922
Slapi_Value *sambaSamAccount;
923
Slapi_Value *ipaNTUserAttrs;
924
Slapi_Value *ipaHost;
925
char *errMesg = NULL;
926
char *modtime = NULL;
930
sambaSamAccount = slapi_value_new_string("sambaSamAccount");
931
if (slapi_entry_attr_has_syntax_value(data->target,
932
"objectClass", sambaSamAccount)) {
935
slapi_value_free(&sambaSamAccount);
937
ipaNTUserAttrs = slapi_value_new_string("ipaNTUserAttrs");
938
if (slapi_entry_attr_has_syntax_value(data->target,
939
"objectClass", ipaNTUserAttrs)) {
942
slapi_value_free(&ipaNTUserAttrs);
944
ipaHost = slapi_value_new_string("ipaHost");
945
if (slapi_entry_attr_has_syntax_value(data->target,
946
"objectClass", ipaHost)) {
949
slapi_value_free(&ipaHost);
951
ret = ipapwd_gen_hashes(krbcfg, data,
953
is_krb, is_smb, is_ipant,
954
&svals, &nt, &lm, &ntvals, &errMesg);
956
goto free_and_return;
959
smods = slapi_mods_new();
962
slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
963
"krbPrincipalKey", svals);
965
/* krbLastPwdChange is used to tell whether a host entry has a
966
* keytab so don't set it on hosts.
969
/* change Last Password Change field with the current date */
970
if (!gmtime_r(&(data->timeNow), &utctime)) {
971
LOG_FATAL("failed to retrieve current date (buggy gmtime_r ?)\n");
972
ret = LDAP_OPERATIONS_ERROR;
973
goto free_and_return;
975
strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
976
"%Y%m%d%H%M%SZ", &utctime);
977
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
978
"krbLastPwdChange", timestr);
980
/* set Password Expiration date */
981
if (!gmtime_r(&(data->expireTime), &utctime)) {
982
LOG_FATAL("failed to convert expiration date\n");
983
ret = LDAP_OPERATIONS_ERROR;
984
goto free_and_return;
986
strftime(timestr, GENERALIZED_TIME_LENGTH + 1,
987
"%Y%m%d%H%M%SZ", &utctime);
988
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
989
"krbPasswordExpiration", timestr);
994
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
995
"sambaLMPassword", lm);
999
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
1000
"sambaNTPassword", nt);
1003
if (ntvals && is_ipant) {
1004
slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
1005
"ipaNTHash", ntvals);
1009
/* with samba integration we need to also set sambaPwdLastSet or
1010
* samba will decide the user has to change the password again */
1011
if (data->changetype == IPA_CHANGETYPE_ADMIN) {
1012
/* if it is an admin change instead we need to let know to
1013
* samba as well that the use rmust change its password */
1014
modtime = slapi_ch_smprintf("0");
1016
modtime = slapi_ch_smprintf("%ld", (long)data->timeNow);
1019
LOG_FATAL("failed to smprintf string!\n");
1020
ret = LDAP_OPERATIONS_ERROR;
1021
goto free_and_return;
1023
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
1024
"sambaPwdLastset", modtime);
1027
if (data->changetype == IPA_CHANGETYPE_ADMIN) {
1028
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
1029
"krbLoginFailedCount", "0");
1032
/* let DS encode the password itself, this allows also other plugins to
1033
* intercept it to perform operations like synchronization with Active
1034
* Directory domains through the replication plugin */
1035
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
1036
"userPassword", data->password);
1038
/* set password history */
1039
if (data->policy.history_length > 0) {
1040
pwvals = ipapwd_setPasswordHistory(smods, data);
1042
slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
1043
"passwordHistory", pwvals);
1048
* instead of replace we should use a delete/add so that we are
1049
* completely sure nobody else modified the entry meanwhile and
1050
* fail if that's the case */
1052
/* commit changes */
1053
ret = ipapwd_apply_mods(data->dn, smods);
1055
LOG_TRACE("<= result: %d\n", ret);
1058
if (lm) slapi_ch_free((void **)&lm);
1059
if (nt) slapi_ch_free((void **)&nt);
1060
if (modtime) slapi_ch_free((void **)&modtime);
1061
slapi_mods_free(&smods);
1062
ipapwd_free_slapi_value_array(&svals);
1063
ipapwd_free_slapi_value_array(&ntvals);
1064
ipapwd_free_slapi_value_array(&pwvals);
1070
Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
1071
struct ipapwd_data *data)
1073
Slapi_Value **pH = NULL;
1074
char **pwd_history = NULL;
1075
char **new_pwd_history = NULL;
1080
pwd_history = slapi_entry_attr_get_charray(data->target,
1083
ret = ipapwd_generate_new_history(data->password, data->timeNow,
1084
data->policy.history_length,
1085
pwd_history, &new_pwd_history, &n);
1087
if (ret && data->policy.history_length) {
1088
LOG_FATAL("failed to generate new password history!\n");
1092
pH = (Slapi_Value **)slapi_ch_calloc(n + 1, sizeof(Slapi_Value *));
1098
for (i = 0; i < n; i++) {
1099
pH[i] = slapi_value_new_string(new_pwd_history[i]);
1101
ipapwd_free_slapi_value_array(&pH);
1108
slapi_ch_array_free(pwd_history);
1109
for (i = 0; i < n; i++) {
1110
free(new_pwd_history[i]);
1112
free(new_pwd_history);
1116
/* Construct Mods pblock and perform the modify operation
1117
* Sets result of operation in SLAPI_PLUGIN_INTOP_RESULT
1119
int ipapwd_apply_mods(const char *dn, Slapi_Mods *mods)
1126
if (!mods || (slapi_mods_get_num_mods(mods) == 0)) {
1130
pb = slapi_pblock_new();
1131
slapi_modify_internal_set_pb(pb, dn,
1132
slapi_mods_get_ldapmods_byref(mods),
1133
NULL, /* Controls */
1134
NULL, /* UniqueID */
1135
ipapwd_plugin_id, /* PluginID */
1138
ret = slapi_modify_internal_pb(pb);
1140
LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
1143
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
1145
if (ret != LDAP_SUCCESS){
1146
LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
1148
LOG_TRACE("<= Successful\n");
1152
slapi_pblock_destroy(pb);
1157
int ipapwd_set_extradata(const char *dn,
1158
const char *principal,
1162
Slapi_Value *va[2] = { NULL };
1169
p_len = strlen(principal);
1170
xd_len = 2 + 4 + p_len + 1;
1171
xdata = malloc(xd_len);
1173
return LDAP_OPERATIONS_ERROR;
1176
smods = slapi_mods_new();
1182
/* unix timestamp in Little Endian */
1183
xdata[2] = unixtime & 0xff;
1184
xdata[3] = (unixtime & 0xff00) >> 8;
1185
xdata[4] = (unixtime & 0xff0000) >> 16;
1186
xdata[5] = (unixtime & 0xff000000) >> 24;
1188
/* append the principal name */
1189
strncpy(&xdata[6], principal, p_len);
1191
xdata[xd_len -1] = 0;
1195
va[0] = slapi_value_new_berval(&bv);
1197
slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbExtraData", va);
1199
ret = ipapwd_apply_mods(dn, smods);
1201
slapi_value_free(&va[0]);
1202
slapi_mods_free(&smods);
1207
void ipapwd_free_slapi_value_array(Slapi_Value ***svals)
1209
Slapi_Value **sv = *svals;
1213
for (i = 0; sv[i]; i++) {
1214
slapi_value_free(&sv[i]);
1218
slapi_ch_free((void **)sv);
1221
void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
1223
struct ipapwd_krbcfg *c = *cfg;
1227
krb5_free_default_realm(c->krbctx, c->realm);
1228
krb5_free_context(c->krbctx);
1229
free(c->kmkey->contents);
1231
free(c->supp_encsalts);
1232
free(c->pref_encsalts);
1233
slapi_ch_array_free(c->passsync_mgrs);