~ubuntu-branches/ubuntu/trusty/freeipa/trusty

« back to all changes in this revision

Viewing changes to daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2013-06-17 22:15:21 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130617221521-z8zya289o8xgrv3u
Tags: 3.2.1-0ubuntu1
* Merge from unreleased debian git
  - rebase to 3.2.1
  - add ipa-client-automount to freeipa-client, and patch it so it
    works on Debian/Ubuntu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
6
 *
 
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.
 
11
 *
 
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/>.
 
14
 *
 
15
 * Additional permission under GPLv3 section 7:
 
16
 *
 
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.
 
21
 *
 
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
 
31
 * Interfaces.
 
32
 *
 
33
 * Authors:
 
34
 * Simo Sorce <ssorce@redhat.com>
 
35
 *
 
36
 * Copyright (C) 2007-2010 Red Hat, Inc.
 
37
 * All rights reserved.
 
38
 * END COPYRIGHT BLOCK **/
 
39
 
 
40
#include "ipapwd.h"
 
41
#include "util.h"
 
42
 
 
43
/* Attribute defines */
 
44
#define IPA_OTP_USER_AUTH_TYPE "ipaUserAuthType"
 
45
 
 
46
/* Type of connection for this operation;*/
 
47
#define LDAP_EXTOP_PASSMOD_CONN_SECURE
 
48
 
 
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 */
 
52
 
 
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;
 
57
 
 
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
 
61
 * the directory */
 
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", */
 
67
    "des-cbc-crc:normal",
 
68
/*    "des-cbc-crc:v4",
 
69
    "des-cbc-crc:afs3", */
 
70
    NULL
 
71
};
 
72
 
 
73
static PRInt32 g_allowed_auth_types = 0;
 
74
 
 
75
/*
 
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.
 
80
 */
 
81
bool ipapwd_is_auth_type_allowed(char **auth_type_list, int auth_type)
 
82
{
 
83
    char *auth_type_value = NULL;
 
84
    int i = 0;
 
85
 
 
86
    /* Get the string value for the authentication type we are checking for. */
 
87
    switch (auth_type) {
 
88
    case IPA_OTP_AUTH_TYPE_OTP:
 
89
        auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_OTP;
 
90
        break;
 
91
    case IPA_OTP_AUTH_TYPE_PASSWORD:
 
92
        auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PASSWORD;
 
93
        break;
 
94
    case IPA_OTP_AUTH_TYPE_PKINIT:
 
95
        auth_type_value = IPA_OTP_AUTH_TYPE_VALUE_PKINIT;
 
96
        break;
 
97
    default: /* Unknown type.*/
 
98
        return false;
 
99
    }
 
100
 
 
101
    if (auth_type_list == NULL) {
 
102
        /* Check if the requested authentication type is in the global list. */
 
103
        PRInt32 auth_type_flags;
 
104
 
 
105
        /* Do an atomic read of the allowed auth types bit field. */
 
106
        auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0);
 
107
 
 
108
        /* Check if the flag for the desired auth type is set. */
 
109
        return auth_type_flags & auth_type;
 
110
    }
 
111
 
 
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) {
 
115
            return true;
 
116
        }
 
117
    }
 
118
 
 
119
    return false;
 
120
}
 
121
 
 
122
/*
 
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.
 
126
 */
 
127
bool ipapwd_parse_otp_config_entry(Slapi_Entry * e, bool apply)
 
128
{
 
129
    PRInt32 allowed_auth_types = 0;
 
130
    PRInt32 default_auth_types = 0;
 
131
    char **auth_types = NULL;
 
132
 
 
133
    /* If no auth types are set, we default to only allowing password
 
134
     * authentication.  Other authentication types can be allowed at the
 
135
     * user level. */
 
136
    default_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD;
 
137
 
 
138
    if (e == NULL) {
 
139
        /* There is no config entry, so just set the defaults. */
 
140
        allowed_auth_types = default_auth_types;
 
141
        goto done;
 
142
    }
 
143
 
 
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. */
 
148
 
 
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;
 
154
        goto done;
 
155
    }
 
156
 
 
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;
 
160
    }
 
161
 
 
162
    if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PASSWORD)) {
 
163
        allowed_auth_types |= IPA_OTP_AUTH_TYPE_PASSWORD;
 
164
    }
 
165
 
 
166
    if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_OTP)) {
 
167
        allowed_auth_types |= IPA_OTP_AUTH_TYPE_OTP;
 
168
    }
 
169
 
 
170
    if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_PKINIT)) {
 
171
        allowed_auth_types |= IPA_OTP_AUTH_TYPE_PKINIT;
 
172
    }
 
173
 
 
174
    if (ipapwd_is_auth_type_allowed(auth_types, IPA_OTP_AUTH_TYPE_RADIUS)) {
 
175
        allowed_auth_types |= IPA_OTP_AUTH_TYPE_RADIUS;
 
176
    }
 
177
 
 
178
    slapi_ch_array_free(auth_types);
 
179
 
 
180
done:
 
181
    if (apply) {
 
182
        /* Atomically set the global allowed types. */
 
183
        PR_ATOMIC_SET(&g_allowed_auth_types, allowed_auth_types);
 
184
    }
 
185
 
 
186
    return true;
 
187
}
 
188
 
 
189
bool ipapwd_otp_is_disabled(void)
 
190
{
 
191
    PRInt32 auth_type_flags;
 
192
 
 
193
    /* Do an atomic read of the allowed auth types bit field. */
 
194
    auth_type_flags = PR_ATOMIC_ADD(&g_allowed_auth_types, 0);
 
195
 
 
196
    /* Check if the disabled bit is set. */
 
197
    return auth_type_flags & IPA_OTP_AUTH_TYPE_DISABLED;
 
198
}
 
199
 
 
200
static struct ipapwd_krbcfg *ipapwd_getConfig(void)
 
201
{
 
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;
 
207
    Slapi_Attr *a;
 
208
    Slapi_Value *v;
 
209
    BerElement *be = NULL;
 
210
    ber_tag_t tag, tvno;
 
211
    ber_int_t ttype;
 
212
    const struct berval *bval;
 
213
    struct berval *mkey = NULL;
 
214
    char **encsalts;
 
215
    char **tmparray;
 
216
    char *tmpstr;
 
217
    int i, ret;
 
218
 
 
219
    config = calloc(1, sizeof(struct ipapwd_krbcfg));
 
220
    if (!config) {
 
221
        LOG_OOM();
 
222
        goto free_and_error;
 
223
    }
 
224
    kmkey = calloc(1, sizeof(krb5_keyblock));
 
225
    if (!kmkey) {
 
226
        LOG_OOM();
 
227
        goto free_and_error;
 
228
    }
 
229
    config->kmkey = kmkey;
 
230
 
 
231
    krberr = krb5_init_context(&config->krbctx);
 
232
    if (krberr) {
 
233
        LOG_FATAL("krb5_init_context failed\n");
 
234
        goto free_and_error;
 
235
    }
 
236
 
 
237
    ret = krb5_get_default_realm(config->krbctx, &config->realm);
 
238
    if (ret) {
 
239
        LOG_FATAL("Failed to get default realm?!\n");
 
240
        goto free_and_error;
 
241
    }
 
242
 
 
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");
 
247
        goto free_and_error;
 
248
    }
 
249
 
 
250
    /*** get the Kerberos Master Key ***/
 
251
 
 
252
    ret = slapi_entry_attr_find(realm_entry, "krbMKey", &a);
 
253
    if (ret == -1) {
 
254
        LOG_FATAL("No master key??\n");
 
255
        goto free_and_error;
 
256
    }
 
257
 
 
258
    /* there should be only one value here */
 
259
    ret = slapi_attr_first_value(a, &v);
 
260
    if (ret == -1) {
 
261
        LOG_FATAL("No master key??\n");
 
262
        goto free_and_error;
 
263
    }
 
264
 
 
265
    bval = slapi_value_get_berval(v);
 
266
    if (!bval) {
 
267
        LOG_FATAL("Error retrieving master key berval\n");
 
268
        goto free_and_error;
 
269
    }
 
270
 
 
271
    be = ber_init(discard_const(bval));
 
272
    if (!be) {
 
273
        LOG_FATAL("ber_init() failed!\n");
 
274
        goto free_and_error;
 
275
    }
 
276
 
 
277
    tag = ber_scanf(be, "{i{iO}}", &tvno, &ttype, &mkey);
 
278
    if (tag == LBER_ERROR) {
 
279
        LOG_FATAL("Bad Master key encoding ?!\n");
 
280
        goto free_and_error;
 
281
    }
 
282
 
 
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) {
 
289
        LOG_OOM();
 
290
        goto free_and_error;
 
291
    }
 
292
    memcpy(kmkey->contents, mkey->bv_val, mkey->bv_len);
 
293
    ber_bvfree(mkey);
 
294
    ber_free(be, 1);
 
295
    mkey = NULL;
 
296
    be = NULL;
 
297
 
 
298
    /*** get the Supported Enc/Salt types ***/
 
299
 
 
300
    encsalts = slapi_entry_attr_get_charray(realm_entry,
 
301
                                            "krbSupportedEncSaltTypes");
 
302
    if (encsalts) {
 
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);
 
309
    } else {
 
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);
 
316
    }
 
317
    if (ret) {
 
318
        LOG_FATAL("Can't get Supported EncSalt Types\n");
 
319
        goto free_and_error;
 
320
    }
 
321
 
 
322
    /*** get the Preferred Enc/Salt types ***/
 
323
 
 
324
    encsalts = slapi_entry_attr_get_charray(realm_entry,
 
325
                                            "krbDefaultEncSaltTypes");
 
326
    if (encsalts) {
 
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);
 
333
    } else {
 
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);
 
340
    }
 
341
    if (ret) {
 
342
        LOG_FATAL("Can't get Preferred EncSalt Types\n");
 
343
        goto free_and_error;
 
344
    }
 
345
 
 
346
    slapi_entry_free(realm_entry);
 
347
 
 
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");
 
352
        goto free_and_error;
 
353
    }
 
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) {
 
360
        LOG_OOM();
 
361
        goto free_and_error;
 
362
    }
 
363
    for (i = 0; config->passsync_mgrs[i]; i++) /* count */ ;
 
364
    config->num_passsync_mgrs = i;
 
365
 
 
366
    slapi_entry_free(config_entry);
 
367
 
 
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");
 
374
        goto free_and_error;
 
375
    } else {
 
376
        tmparray = slapi_entry_attr_get_charray(config_entry,
 
377
                                                "ipaConfigString");
 
378
        for (i = 0; tmparray && tmparray[i]; i++) {
 
379
            if (strcasecmp(tmparray[i], "AllowLMhash") == 0) {
 
380
                config->allow_lm_hash = true;
 
381
                continue;
 
382
            }
 
383
            if (strcasecmp(tmparray[i], "AllowNThash") == 0) {
 
384
                config->allow_nt_hash = true;
 
385
                continue;
 
386
            }
 
387
        }
 
388
        if (tmparray) slapi_ch_array_free(tmparray);
 
389
    }
 
390
 
 
391
    slapi_entry_free(config_entry);
 
392
 
 
393
    return config;
 
394
 
 
395
free_and_error:
 
396
    if (mkey) ber_bvfree(mkey);
 
397
    if (be) ber_free(be, 1);
 
398
    if (kmkey) {
 
399
        free(kmkey->contents);
 
400
        free(kmkey);
 
401
    }
 
402
    if (config) {
 
403
        if (config->krbctx) {
 
404
            if (config->realm)
 
405
                krb5_free_default_realm(config->krbctx, config->realm);
 
406
            krb5_free_context(config->krbctx);
 
407
        }
 
408
        free(config->pref_encsalts);
 
409
        free(config->supp_encsalts);
 
410
        slapi_ch_array_free(config->passsync_mgrs);
 
411
        free(config);
 
412
    }
 
413
    slapi_entry_free(config_entry);
 
414
    slapi_entry_free(realm_entry);
 
415
    return NULL;
 
416
}
 
417
 
 
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)
 
422
 */
 
423
static int pwd_get_values(const Slapi_Entry *ent, const char *attrname,
 
424
                          Slapi_ValueSet** results, char** actual_type_name,
 
425
                          int *buffer_flags)
 
426
{
 
427
    int flags=0;
 
428
    int type_name_disposition = 0;
 
429
    int ret;
 
430
 
 
431
    ret = slapi_vattr_values_get((Slapi_Entry *)ent, (char *)attrname,
 
432
                                 results, &type_name_disposition,
 
433
                                 actual_type_name, flags, buffer_flags);
 
434
 
 
435
    return ret;
 
436
}
 
437
 
 
438
static void pwd_values_free(Slapi_ValueSet** results,
 
439
                            char** actual_type_name, int buffer_flags)
 
440
{
 
441
    slapi_vattr_values_free(results, actual_type_name, buffer_flags);
 
442
}
 
443
 
 
444
static int ipapwd_rdn_count(const char *dn)
 
445
{
 
446
    int rdnc = 0;
 
447
    LDAPDN ldn;
 
448
    int ret;
 
449
 
 
450
    ret = ldap_str2dn(dn, &ldn, LDAP_DN_FORMAT_LDAPV3);
 
451
    if (ret != LDAP_SUCCESS) {
 
452
        LOG_TRACE("ldap_str2dn(dn) failed ?!");
 
453
        return -1;
 
454
    }
 
455
 
 
456
    for (rdnc = 0; ldn != NULL && ldn[rdnc]; rdnc++) /* count */ ;
 
457
    ldap_dnfree(ldn);
 
458
 
 
459
    return rdnc;
 
460
}
 
461
 
 
462
int ipapwd_getPolicy(const char *dn,
 
463
                     Slapi_Entry *target,
 
464
                     struct ipapwd_policy *policy)
 
465
{
 
466
    const char *krbPwdPolicyReference;
 
467
    const char *pdn;
 
468
    const Slapi_DN *psdn;
 
469
    Slapi_Backend *be;
 
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;
 
478
    int buffer_flags=0;
 
479
    Slapi_ValueSet* results = NULL;
 
480
    char* actual_type_name = NULL;
 
481
    int tmpint;
 
482
 
 
483
    LOG_TRACE("Searching policy for [%s]\n", dn);
 
484
 
 
485
    sdn = slapi_sdn_new_dn_byref(dn);
 
486
    if (sdn == NULL) {
 
487
        LOG_OOM();
 
488
        ret = -1;
 
489
        goto done;
 
490
    }
 
491
 
 
492
    pwd_get_values(target, "krbPwdPolicyReference",
 
493
                   &results, &actual_type_name, &buffer_flags);
 
494
    if (results) {
 
495
        Slapi_Value *sv;
 
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);
 
501
    } else {
 
502
        /* Find ancestor base DN */
 
503
        be = slapi_be_select(sdn);
 
504
        psdn = slapi_be_getsuffix(be, 0);
 
505
        if (psdn == NULL) {
 
506
            LOG_FATAL("Invalid DN [%s]\n", dn);
 
507
            ret = -1;
 
508
            goto done;
 
509
        }
 
510
        pdn = slapi_sdn_get_dn(psdn);
 
511
        scope = LDAP_SCOPE_SUBTREE;
 
512
    }
 
513
 
 
514
    pb = slapi_pblock_new();
 
515
    slapi_search_internal_set_pb(pb,
 
516
                                 pdn, scope,
 
517
                                 "(objectClass=krbPwdPolicy)",
 
518
                                 attrs, 0,
 
519
                                 NULL, /* Controls */
 
520
                                 NULL, /* UniqueID */
 
521
                                 ipapwd_plugin_id,
 
522
                                 0); /* Flags */
 
523
 
 
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);
 
529
        ret = -1;
 
530
        goto done;
 
531
    }
 
532
 
 
533
    /* get entries */
 
534
    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &es);
 
535
    if (!es) {
 
536
        LOG_TRACE("No entries ?!");
 
537
        ret = -1;
 
538
        goto done;
 
539
    }
 
540
 
 
541
    /* count entries */
 
542
    for (i = 0; es[i]; i++) /* count */ ;
 
543
 
 
544
    /* if there is only one, return that */
 
545
    if (i == 1) {
 
546
        pe = es[0];
 
547
        goto fill;
 
548
    }
 
549
 
 
550
    /* count number of RDNs in DN */
 
551
    rdnc = ipapwd_rdn_count(dn);
 
552
    if (rdnc == -1) {
 
553
        LOG_TRACE("ipapwd_rdn_count(dn) failed");
 
554
        ret = -1;
 
555
        goto done;
 
556
    }
 
557
 
 
558
    pe = NULL;
 
559
    dist = -1;
 
560
 
 
561
    /* find closest entry */
 
562
    for (i = 0; es[i]; i++) {
 
563
        const Slapi_DN *esdn;
 
564
 
 
565
        esdn = slapi_entry_get_sdn_const(es[i]);
 
566
        if (esdn == NULL) continue;
 
567
        if (0 == slapi_sdn_compare(esdn, sdn)) {
 
568
            pe = es[i];
 
569
            dist = 0;
 
570
            break;
 
571
        }
 
572
        if (slapi_sdn_issuffix(sdn, esdn)) {
 
573
            const char *dn1;
 
574
            int c1;
 
575
 
 
576
            dn1 = slapi_sdn_get_dn(esdn);
 
577
            if (!dn1) continue;
 
578
            c1 = ipapwd_rdn_count(dn1);
 
579
            if (c1 == -1) continue;
 
580
            if ((dist == -1) ||
 
581
                ((rdnc - c1) < dist)) {
 
582
                dist = rdnc - c1;
 
583
                pe = es[i];
 
584
            }
 
585
        }
 
586
        if (dist == 0) break; /* found closest */
 
587
    }
 
588
 
 
589
    if (pe == NULL) {
 
590
        ret = -1;
 
591
        goto done;
 
592
    }
 
593
 
 
594
fill:
 
595
    policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife");
 
596
 
 
597
    tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife");
 
598
    if (tmpint != 0) {
 
599
        policy->max_pwd_life = tmpint;
 
600
    }
 
601
 
 
602
    tmpint = slapi_entry_attr_get_int(pe, "krbPwdMinLength");
 
603
    if (tmpint != 0) {
 
604
        policy->min_pwd_length = tmpint;
 
605
    }
 
606
 
 
607
    policy->history_length = slapi_entry_attr_get_int(pe,
 
608
                                                      "krbPwdHistoryLength");
 
609
 
 
610
    policy->min_complexity = slapi_entry_attr_get_int(pe,
 
611
                                                      "krbPwdMinDiffChars");
 
612
 
 
613
    ret = 0;
 
614
 
 
615
done:
 
616
    if (results) {
 
617
        pwd_values_free(&results, &actual_type_name, buffer_flags);
 
618
    }
 
619
    if (pb) {
 
620
        slapi_free_search_results_internal(pb);
 
621
        slapi_pblock_destroy(pb);
 
622
    }
 
623
    if (sdn) slapi_sdn_free(&sdn);
 
624
    return ret;
 
625
}
 
626
 
 
627
 
 
628
/*==Common-public-functions=============================================*/
 
629
 
 
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,
 
632
                        char *attr, int acc)
 
633
{
 
634
    Slapi_Value *sval;
 
635
    int rc;
 
636
 
 
637
    /* Check ACIs */
 
638
    slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, is_root);
 
639
 
 
640
    if (!*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 */
 
645
            rc = LDAP_SUCCESS;
 
646
            goto done;
 
647
        }
 
648
    }
 
649
 
 
650
    /* Check if this is a krbPrincial and therefore needs us to generate other
 
651
     * hashes */
 
652
    sval = slapi_value_new_string("krbPrincipalAux");
 
653
    if (!sval) {
 
654
        rc = LDAP_OPERATIONS_ERROR;
 
655
        goto done;
 
656
    }
 
657
    *is_krb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
 
658
    slapi_value_free(&sval);
 
659
 
 
660
    sval = slapi_value_new_string("sambaSamAccount");
 
661
    if (!sval) {
 
662
        rc = LDAP_OPERATIONS_ERROR;
 
663
        goto done;
 
664
    }
 
665
    *is_smb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
 
666
    slapi_value_free(&sval);
 
667
 
 
668
    sval = slapi_value_new_string("ipaNTUserAttrs");
 
669
    if (!sval) {
 
670
        rc = LDAP_OPERATIONS_ERROR;
 
671
        goto done;
 
672
    }
 
673
    *is_ipant = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
 
674
                                                  sval);
 
675
    slapi_value_free(&sval);
 
676
 
 
677
    rc = LDAP_SUCCESS;
 
678
 
 
679
done:
 
680
    return rc;
 
681
}
 
682
 
 
683
int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
 
684
                      struct ipapwd_krbcfg **config, int check_flags)
 
685
{
 
686
    int ret, ssf;
 
687
    int rc = LDAP_SUCCESS;
 
688
    Slapi_Backend *be;
 
689
    const Slapi_DN *psdn;
 
690
    Slapi_DN *sdn;
 
691
    char *dn = NULL;
 
692
 
 
693
    LOG_TRACE("=>\n");
 
694
 
 
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;
 
703
            goto done;
 
704
        }
 
705
 
 
706
        if (ssf <= 1) {
 
707
            *errMesg = "Operation requires a secure connection.\n";
 
708
            rc = LDAP_CONFIDENTIALITY_REQUIRED;
 
709
            goto done;
 
710
        }
 
711
    }
 
712
#endif
 
713
 
 
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);
 
717
        if (ret) {
 
718
            LOG("Tried to change password for an invalid DN [%s]\n",
 
719
                dn ? dn : "<NULL>");
 
720
            *errMesg = "Invalid DN";
 
721
            rc = LDAP_OPERATIONS_ERROR;
 
722
            goto done;
 
723
        }
 
724
        sdn = slapi_sdn_new_dn_byref(dn);
 
725
        if (!sdn) {
 
726
            LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>");
 
727
            *errMesg = "Internal Error";
 
728
            rc = LDAP_OPERATIONS_ERROR;
 
729
            goto done;
 
730
        }
 
731
        be = slapi_be_select(sdn);
 
732
        slapi_sdn_free(&sdn);
 
733
 
 
734
        psdn = slapi_be_getsuffix(be, 0);
 
735
        if (!psdn) {
 
736
            *errMesg = "Invalid DN";
 
737
            rc = LDAP_OPERATIONS_ERROR;
 
738
            goto done;
 
739
        }
 
740
    }
 
741
 
 
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;
 
748
    }
 
749
 
 
750
done:
 
751
    return rc;
 
752
}
 
753
 
 
754
/* check password strenght and history */
 
755
int ipapwd_CheckPolicy(struct ipapwd_data *data)
 
756
{
 
757
    struct ipapwd_policy pol = {0};
 
758
    time_t acct_expiration;
 
759
    time_t pwd_expiration;
 
760
    time_t last_pwd_change;
 
761
    char **pwd_history;
 
762
    char *tmpstr;
 
763
    int ret;
 
764
 
 
765
    pol.max_pwd_life = IPAPWD_DEFAULT_PWDLIFE;
 
766
    pol.min_pwd_length = IPAPWD_DEFAULT_MINLEN;
 
767
 
 
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.
 
777
             */
 
778
            data->timeNow -= 1;
 
779
            data->expireTime = data->timeNow;
 
780
        }
 
781
 
 
782
        /* do not load policies */
 
783
    } else {
 
784
 
 
785
        /* find the entry with the password policy */
 
786
        ret = ipapwd_getPolicy(data->dn, data->target, &pol);
 
787
        if (ret) {
 
788
            LOG_TRACE("No password policy, use defaults");
 
789
        }
 
790
    }
 
791
 
 
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);
 
796
 
 
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);
 
801
 
 
802
    tmpstr = slapi_entry_attr_get_charptr(data->target,
 
803
                                          "krbLastPwdChange");
 
804
    last_pwd_change = ipapwd_gentime_to_time_t(tmpstr);
 
805
    slapi_ch_free_string(&tmpstr);
 
806
 
 
807
    pwd_history = slapi_entry_attr_get_charray(data->target,
 
808
                                               "passwordHistory");
 
809
 
 
810
    /* check policy */
 
811
    ret = ipapwd_check_policy(&pol, data->password,
 
812
                                    data->timeNow,
 
813
                                    acct_expiration,
 
814
                                    pwd_expiration,
 
815
                                    last_pwd_change,
 
816
                                    pwd_history);
 
817
 
 
818
    slapi_ch_array_free(pwd_history);
 
819
 
 
820
    if (data->expireTime == 0) {
 
821
        data->expireTime = data->timeNow + pol.max_pwd_life;
 
822
    }
 
823
 
 
824
    data->policy = pol;
 
825
 
 
826
    return ret;
 
827
}
 
828
 
 
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
 
832
 */
 
833
int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist)
 
834
{
 
835
    Slapi_DN *sdn;
 
836
    int search_result = 0;
 
837
 
 
838
    LOG_TRACE("=>\n");
 
839
 
 
840
    sdn = slapi_sdn_new_dn_byref(dn);
 
841
    search_result = slapi_search_internal_get_entry(sdn, attrlist, e2,
 
842
                                                    ipapwd_plugin_id);
 
843
    if (search_result != LDAP_SUCCESS) {
 
844
        LOG_TRACE("No such entry-(%s), err (%d)\n", dn, search_result);
 
845
    }
 
846
 
 
847
    slapi_sdn_free(&sdn);
 
848
    LOG_TRACE("<= result: %d\n", search_result);
 
849
    return search_result;
 
850
}
 
851
 
 
852
int ipapwd_get_cur_kvno(Slapi_Entry *target)
 
853
{
 
854
    Slapi_Attr *krbPrincipalKey = NULL;
 
855
    Slapi_ValueSet *svs;
 
856
    Slapi_Value *sv;
 
857
    BerElement *be = NULL;
 
858
    const struct berval *cbval;
 
859
    ber_tag_t tag, tmp;
 
860
    ber_int_t tkvno;
 
861
    int hint;
 
862
    int kvno;
 
863
    int ret;
 
864
 
 
865
    /* retrieve current kvno and and keys */
 
866
    ret = slapi_entry_attr_find(target, "krbPrincipalKey", &krbPrincipalKey);
 
867
    if (ret != 0) {
 
868
        return 0;
 
869
    }
 
870
 
 
871
    kvno = 0;
 
872
 
 
873
    slapi_attr_get_valueset(krbPrincipalKey, &svs);
 
874
    hint = slapi_valueset_first_value(svs, &sv);
 
875
    while (hint != -1) {
 
876
        cbval = slapi_value_get_berval(sv);
 
877
        if (!cbval) {
 
878
            LOG_TRACE("Error retrieving berval from Slapi_Value\n");
 
879
            goto next;
 
880
        }
 
881
        be = ber_init(discard_const(cbval));
 
882
        if (!be) {
 
883
            LOG_TRACE("ber_init() failed!\n");
 
884
            goto next;
 
885
        }
 
886
 
 
887
        tag = ber_scanf(be, "{xxt[i]", &tmp, &tkvno);
 
888
        if (tag == LBER_ERROR) {
 
889
            LOG_TRACE("Bad OLD key encoding ?!\n");
 
890
            ber_free(be, 1);
 
891
            goto next;
 
892
        }
 
893
 
 
894
        if (tkvno > kvno) {
 
895
            kvno = tkvno;
 
896
        }
 
897
 
 
898
        ber_free(be, 1);
 
899
next:
 
900
        hint = slapi_valueset_next_value(svs, hint, &sv);
 
901
    }
 
902
 
 
903
    return kvno;
 
904
}
 
905
 
 
906
/* Modify the Password attributes of the entry */
 
907
int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
 
908
                       struct ipapwd_data *data, int is_krb)
 
909
{
 
910
    int ret = 0;
 
911
    Slapi_Mods *smods = NULL;
 
912
    Slapi_Value **svals = NULL;
 
913
    Slapi_Value **ntvals = NULL;
 
914
    Slapi_Value **pwvals = NULL;
 
915
    struct tm utctime;
 
916
    char timestr[GENERALIZED_TIME_LENGTH+1];
 
917
    char *lm = NULL;
 
918
    char *nt = NULL;
 
919
    int is_smb = 0;
 
920
    int is_ipant = 0;
 
921
    int is_host = 0;
 
922
    Slapi_Value *sambaSamAccount;
 
923
    Slapi_Value *ipaNTUserAttrs;
 
924
    Slapi_Value *ipaHost;
 
925
    char *errMesg = NULL;
 
926
    char *modtime = NULL;
 
927
 
 
928
    LOG_TRACE("=>\n");
 
929
 
 
930
    sambaSamAccount = slapi_value_new_string("sambaSamAccount");
 
931
    if (slapi_entry_attr_has_syntax_value(data->target,
 
932
                                          "objectClass", sambaSamAccount)) {
 
933
        is_smb = 1;
 
934
    }
 
935
    slapi_value_free(&sambaSamAccount);
 
936
 
 
937
    ipaNTUserAttrs = slapi_value_new_string("ipaNTUserAttrs");
 
938
    if (slapi_entry_attr_has_syntax_value(data->target,
 
939
                                          "objectClass", ipaNTUserAttrs)) {
 
940
        is_ipant = 1;
 
941
    }
 
942
    slapi_value_free(&ipaNTUserAttrs);
 
943
 
 
944
    ipaHost = slapi_value_new_string("ipaHost");
 
945
    if (slapi_entry_attr_has_syntax_value(data->target,
 
946
                                          "objectClass", ipaHost)) {
 
947
        is_host = 1;
 
948
    }
 
949
    slapi_value_free(&ipaHost);
 
950
 
 
951
    ret = ipapwd_gen_hashes(krbcfg, data,
 
952
                            data->password,
 
953
                            is_krb, is_smb, is_ipant,
 
954
                            &svals, &nt, &lm, &ntvals, &errMesg);
 
955
    if (ret) {
 
956
        goto free_and_return;
 
957
    }
 
958
 
 
959
    smods = slapi_mods_new();
 
960
 
 
961
    if (svals) {
 
962
        slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
 
963
                                  "krbPrincipalKey", svals);
 
964
 
 
965
                /* krbLastPwdChange is used to tell whether a host entry has a
 
966
                 * keytab so don't set it on hosts.
 
967
                 */
 
968
        if (!is_host) {
 
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;
 
974
                        }
 
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);
 
979
 
 
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;
 
985
                        }
 
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);
 
990
                }
 
991
        }
 
992
 
 
993
    if (lm && is_smb) {
 
994
        slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
 
995
                              "sambaLMPassword", lm);
 
996
    }
 
997
 
 
998
    if (nt && is_smb) {
 
999
        slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
 
1000
                              "sambaNTPassword", nt);
 
1001
    }
 
1002
 
 
1003
    if (ntvals && is_ipant) {
 
1004
        slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
 
1005
                                  "ipaNTHash", ntvals);
 
1006
    }
 
1007
 
 
1008
    if (is_smb) {
 
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");
 
1015
        } else {
 
1016
            modtime = slapi_ch_smprintf("%ld", (long)data->timeNow);
 
1017
        }
 
1018
        if (!modtime) {
 
1019
            LOG_FATAL("failed to smprintf string!\n");
 
1020
            ret = LDAP_OPERATIONS_ERROR;
 
1021
            goto free_and_return;
 
1022
        }
 
1023
        slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
 
1024
                              "sambaPwdLastset", modtime);
 
1025
    }
 
1026
    if (is_krb) {
 
1027
        if (data->changetype == IPA_CHANGETYPE_ADMIN) {
 
1028
            slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
 
1029
                                 "krbLoginFailedCount", "0");
 
1030
        }
 
1031
    }
 
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);
 
1037
 
 
1038
    /* set password history */
 
1039
    if (data->policy.history_length > 0) {
 
1040
        pwvals = ipapwd_setPasswordHistory(smods, data);
 
1041
        if (pwvals) {
 
1042
            slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
 
1043
                                      "passwordHistory", pwvals);
 
1044
        }
 
1045
    }
 
1046
 
 
1047
    /* FIXME:
 
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 */
 
1051
 
 
1052
    /* commit changes */
 
1053
    ret = ipapwd_apply_mods(data->dn, smods);
 
1054
 
 
1055
    LOG_TRACE("<= result: %d\n", ret);
 
1056
 
 
1057
free_and_return:
 
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);
 
1065
 
 
1066
    return ret;
 
1067
}
 
1068
 
 
1069
 
 
1070
Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
 
1071
                                        struct ipapwd_data *data)
 
1072
{
 
1073
    Slapi_Value **pH = NULL;
 
1074
    char **pwd_history = NULL;
 
1075
    char **new_pwd_history = NULL;
 
1076
    int n = 0;
 
1077
    int ret;
 
1078
    int i;
 
1079
 
 
1080
    pwd_history = slapi_entry_attr_get_charray(data->target,
 
1081
                                               "passwordHistory");
 
1082
 
 
1083
    ret = ipapwd_generate_new_history(data->password, data->timeNow,
 
1084
                                      data->policy.history_length,
 
1085
                                      pwd_history, &new_pwd_history, &n);
 
1086
 
 
1087
    if (ret && data->policy.history_length) {
 
1088
        LOG_FATAL("failed to generate new password history!\n");
 
1089
        goto done;
 
1090
    }
 
1091
 
 
1092
    pH = (Slapi_Value **)slapi_ch_calloc(n + 1, sizeof(Slapi_Value *));
 
1093
    if (!pH) {
 
1094
        LOG_OOM();
 
1095
        goto done;
 
1096
    }
 
1097
 
 
1098
    for (i = 0; i < n; i++) {
 
1099
        pH[i] = slapi_value_new_string(new_pwd_history[i]);
 
1100
        if (!pH[i]) {
 
1101
            ipapwd_free_slapi_value_array(&pH);
 
1102
            LOG_OOM();
 
1103
            goto done;
 
1104
        }
 
1105
    }
 
1106
 
 
1107
done:
 
1108
    slapi_ch_array_free(pwd_history);
 
1109
    for (i = 0; i < n; i++) {
 
1110
        free(new_pwd_history[i]);
 
1111
    }
 
1112
    free(new_pwd_history);
 
1113
    return pH;
 
1114
}
 
1115
 
 
1116
/* Construct Mods pblock and perform the modify operation
 
1117
 * Sets result of operation in SLAPI_PLUGIN_INTOP_RESULT
 
1118
 */
 
1119
int ipapwd_apply_mods(const char *dn, Slapi_Mods *mods)
 
1120
{
 
1121
    Slapi_PBlock *pb;
 
1122
    int ret;
 
1123
 
 
1124
    LOG_TRACE("=>\n");
 
1125
 
 
1126
    if (!mods || (slapi_mods_get_num_mods(mods) == 0)) {
 
1127
        return -1;
 
1128
    }
 
1129
 
 
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 */
 
1136
                                 0); /* Flags */
 
1137
 
 
1138
    ret = slapi_modify_internal_pb(pb);
 
1139
    if (ret) {
 
1140
        LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
 
1141
    } else {
 
1142
 
 
1143
        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
 
1144
 
 
1145
        if (ret != LDAP_SUCCESS){
 
1146
            LOG_TRACE("WARNING: modify error %d on entry '%s'\n", ret, dn);
 
1147
        } else {
 
1148
            LOG_TRACE("<= Successful\n");
 
1149
        }
 
1150
    }
 
1151
 
 
1152
    slapi_pblock_destroy(pb);
 
1153
 
 
1154
    return ret;
 
1155
}
 
1156
 
 
1157
int ipapwd_set_extradata(const char *dn,
 
1158
                         const char *principal,
 
1159
                         time_t unixtime)
 
1160
{
 
1161
    Slapi_Mods *smods;
 
1162
    Slapi_Value *va[2] = { NULL };
 
1163
    struct berval bv;
 
1164
    char *xdata;
 
1165
    int xd_len;
 
1166
    int p_len;
 
1167
    int ret;
 
1168
 
 
1169
    p_len = strlen(principal);
 
1170
    xd_len = 2 + 4 + p_len + 1;
 
1171
    xdata = malloc(xd_len);
 
1172
    if (!xdata) {
 
1173
        return LDAP_OPERATIONS_ERROR;
 
1174
    }
 
1175
 
 
1176
    smods = slapi_mods_new();
 
1177
 
 
1178
    /* data type id */
 
1179
    xdata[0] = 0x00;
 
1180
    xdata[1] = 0x02;
 
1181
 
 
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;
 
1187
 
 
1188
    /* append the principal name */
 
1189
    strncpy(&xdata[6], principal, p_len);
 
1190
 
 
1191
    xdata[xd_len -1] = 0;
 
1192
 
 
1193
    bv.bv_val = xdata;
 
1194
    bv.bv_len = xd_len;
 
1195
    va[0] = slapi_value_new_berval(&bv);
 
1196
 
 
1197
    slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE, "krbExtraData", va);
 
1198
 
 
1199
    ret = ipapwd_apply_mods(dn, smods);
 
1200
 
 
1201
    slapi_value_free(&va[0]);
 
1202
    slapi_mods_free(&smods);
 
1203
 
 
1204
    return ret;
 
1205
}
 
1206
 
 
1207
void ipapwd_free_slapi_value_array(Slapi_Value ***svals)
 
1208
{
 
1209
    Slapi_Value **sv = *svals;
 
1210
    int i;
 
1211
 
 
1212
    if (sv) {
 
1213
        for (i = 0; sv[i]; i++) {
 
1214
            slapi_value_free(&sv[i]);
 
1215
        }
 
1216
    }
 
1217
 
 
1218
    slapi_ch_free((void **)sv);
 
1219
}
 
1220
 
 
1221
void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg)
 
1222
{
 
1223
    struct ipapwd_krbcfg *c = *cfg;
 
1224
 
 
1225
    if (!c) return;
 
1226
 
 
1227
    krb5_free_default_realm(c->krbctx, c->realm);
 
1228
    krb5_free_context(c->krbctx);
 
1229
    free(c->kmkey->contents);
 
1230
    free(c->kmkey);
 
1231
    free(c->supp_encsalts);
 
1232
    free(c->pref_encsalts);
 
1233
    slapi_ch_array_free(c->passsync_mgrs);
 
1234
    free(c);
 
1235
    *cfg = NULL;
 
1236
};
 
1237