1 /* smbk5pwd.c - Overlay for managing Samba and Heimdal passwords */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2013 The OpenLDAP Foundation.
6 * Portions Copyright 2004-2005 by Howard Chu, Symas Corp.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * Support for table-driven configuration added by Pierangelo Masarati.
19 * Support for sambaPwdMustChange and sambaPwdCanChange added by Marco D'Ettorre.
20 * Support for shadowLastChange added by SATOH Fumiyasu @ OSS Technology, Inc.
25 #ifndef SLAPD_OVER_SMBK5PWD
26 #define SLAPD_OVER_SMBK5PWD SLAPD_MOD_DYNAMIC
29 #ifdef SLAPD_OVER_SMBK5PWD
33 #include <ac/string.h>
42 /* make ASN1_MALLOC_ENCODE use our allocator */
43 #define malloc ch_malloc
46 #include <kadm5/admin.h>
49 #ifndef HDB_INTERFACE_VERSION
50 #define HDB_MASTER_KEY_SET master_key_set
52 #define HDB_MASTER_KEY_SET hdb_master_key_set
55 static krb5_context context;
56 static void *kadm_context;
57 static kadm5_config_params conf;
60 static AttributeDescription *ad_krb5Key;
61 static AttributeDescription *ad_krb5KeyVersionNumber;
62 static AttributeDescription *ad_krb5PrincipalName;
63 static AttributeDescription *ad_krb5ValidEnd;
64 static ObjectClass *oc_krb5KDCEntry;
70 typedef unsigned char DES_cblock[8];
72 #include <openssl/des.h>
73 #include <openssl/md4.h>
75 #error Unsupported crypto backend.
77 #include "ldap_utf8.h"
79 static AttributeDescription *ad_sambaLMPassword;
80 static AttributeDescription *ad_sambaNTPassword;
81 static AttributeDescription *ad_sambaPwdLastSet;
82 static AttributeDescription *ad_sambaPwdMustChange;
83 static AttributeDescription *ad_sambaPwdCanChange;
84 static ObjectClass *oc_sambaSamAccount;
88 static AttributeDescription *ad_shadowLastChange;
89 static ObjectClass *oc_shadowAccount;
92 /* Per-instance configuration information */
93 typedef struct smbk5pwd_t {
95 #define SMBK5PWD_F_KRB5 (0x1U)
96 #define SMBK5PWD_F_SAMBA (0x2U)
97 #define SMBK5PWD_F_SHADOW (0x4U)
99 #define SMBK5PWD_DO_KRB5(pi) ((pi)->mode & SMBK5PWD_F_KRB5)
100 #define SMBK5PWD_DO_SAMBA(pi) ((pi)->mode & SMBK5PWD_F_SAMBA)
101 #define SMBK5PWD_DO_SHADOW(pi) ((pi)->mode & SMBK5PWD_F_SHADOW)
108 /* How many seconds before forcing a password change? */
109 time_t smb_must_change;
110 /* How many seconds after allowing a password change? */
111 time_t smb_can_change;
119 static const unsigned SMBK5PWD_F_ALL =
132 static int smbk5pwd_modules_init( smbk5pwd_t *pi );
135 static const char hex[] = "0123456789abcdef";
137 /* From liblutil/passwd.c... */
138 static void lmPasswd_to_key(
139 const char *lmPasswd,
142 const unsigned char *lpw = (const unsigned char *)lmPasswd;
143 unsigned char *k = (unsigned char *)key;
145 /* make room for parity bits */
147 k[1] = ((lpw[0]&0x01)<<7) | (lpw[1]>>1);
148 k[2] = ((lpw[1]&0x03)<<6) | (lpw[2]>>2);
149 k[3] = ((lpw[2]&0x07)<<5) | (lpw[3]>>3);
150 k[4] = ((lpw[3]&0x0F)<<4) | (lpw[4]>>4);
151 k[5] = ((lpw[4]&0x1F)<<3) | (lpw[5]>>5);
152 k[6] = ((lpw[5]&0x3F)<<2) | (lpw[6]>>6);
153 k[7] = ((lpw[6]&0x7F)<<1);
156 des_set_odd_parity( key );
160 #define MAX_PWLEN 256
164 const char in[HASHLEN],
172 out->bv_val = ch_malloc(HASHLEN*2 + 1);
173 out->bv_len = HASHLEN*2;
176 b = (unsigned char *)in;
177 for (i=0; i<HASHLEN; i++) {
179 *a++ = hex[*b++ & 0x0f];
185 struct berval *passwd,
189 char UcasePassword[15];
191 DES_cblock StdText = "KGS!@#$%";
194 DES_key_schedule schedule;
195 #elif defined(HAVE_GNUTLS)
196 gcry_cipher_hd_t h = NULL;
199 err = gcry_cipher_open( &h, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0 );
203 strncpy( UcasePassword, passwd->bv_val, 14 );
204 UcasePassword[14] = '\0';
205 ldap_pvt_str2upper( UcasePassword );
207 lmPasswd_to_key( UcasePassword, &key );
209 err = gcry_cipher_setkey( h, &key, sizeof(key) );
211 err = gcry_cipher_encrypt( h, &hbuf[0], sizeof(key), &StdText, sizeof(key) );
213 gcry_cipher_reset( h );
214 lmPasswd_to_key( &UcasePassword[7], &key );
215 err = gcry_cipher_setkey( h, &key, sizeof(key) );
217 err = gcry_cipher_encrypt( h, &hbuf[1], sizeof(key), &StdText, sizeof(key) );
220 gcry_cipher_close( h );
222 #elif defined(HAVE_OPENSSL)
223 des_set_key_unchecked( &key, schedule );
224 des_ecb_encrypt( &StdText, &hbuf[0], schedule , DES_ENCRYPT );
226 lmPasswd_to_key( &UcasePassword[7], &key );
227 des_set_key_unchecked( &key, schedule );
228 des_ecb_encrypt( &StdText, &hbuf[1], schedule , DES_ENCRYPT );
231 hexify( (char *)hbuf, hash );
235 struct berval *passwd,
239 /* Windows currently only allows 14 character passwords, but
240 * may support up to 256 in the future. We assume this means
241 * 256 UCS2 characters, not 256 bytes...
248 if (passwd->bv_len > MAX_PWLEN*2)
249 passwd->bv_len = MAX_PWLEN*2;
253 MD4_Update( &ctx, passwd->bv_val, passwd->bv_len );
254 MD4_Final( (unsigned char *)hbuf, &ctx );
255 #elif defined(HAVE_GNUTLS)
256 gcry_md_hash_buffer(GCRY_MD_MD4, hbuf, passwd->bv_val, passwd->bv_len );
259 hexify( hbuf, hash );
261 #endif /* DO_SAMBA */
265 static int smbk5pwd_op_cleanup(
271 /* clear out the current key */
272 ldap_pvt_thread_pool_setkey( op->o_threadctx, smbk5pwd_op_cleanup,
273 NULL, 0, NULL, NULL );
275 /* free the callback */
277 op->o_callback = cb->sc_next;
278 op->o_tmpfree( cb, op->o_tmpmemctx );
282 static int smbk5pwd_op_bind(
286 /* If this is a simple Bind, stash the Op pointer so our chk
287 * function can find it. Set a cleanup callback to clear it
288 * out when the Bind completes.
290 if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
292 ldap_pvt_thread_pool_setkey( op->o_threadctx,
293 smbk5pwd_op_cleanup, op, 0, NULL, NULL );
294 cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
295 cb->sc_cleanup = smbk5pwd_op_cleanup;
296 cb->sc_next = op->o_callback;
299 return SLAP_CB_CONTINUE;
302 static LUTIL_PASSWD_CHK_FUNC k5key_chk;
303 static LUTIL_PASSWD_HASH_FUNC k5key_hash;
304 static const struct berval k5key_scheme = BER_BVC("{K5KEY}");
306 /* This password scheme stores no data in the userPassword attribute
307 * other than the scheme name. It assumes the invoking entry is a
308 * krb5KDCentry and compares the passed-in credentials against the
309 * krb5Key attribute. The krb5Key may be multi-valued, but they are
310 * simply multiple keytypes generated from the same input string, so
311 * only the first value needs to be compared here.
313 * Since the lutil_passwd API doesn't pass the Entry object in, we
314 * have to fetch it ourselves in order to get access to the other
315 * attributes. We accomplish this with the help of the overlay's Bind
316 * function, which stores the current Operation pointer in thread-specific
317 * storage so we can retrieve it here. The Operation provides all
318 * the necessary context for us to get Entry from the database.
320 static int k5key_chk(
321 const struct berval *sc,
322 const struct berval *passwd,
323 const struct berval *cred,
336 /* Find our thread context, find our Operation */
337 ctx = ldap_pvt_thread_pool_context();
339 if ( ldap_pvt_thread_pool_getkey( ctx, smbk5pwd_op_cleanup, &op_tmp, NULL )
341 return LUTIL_PASSWD_ERR;
344 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
345 if ( rc != LDAP_SUCCESS ) return LUTIL_PASSWD_ERR;
347 rc = LUTIL_PASSWD_ERR;
352 a = attr_find( e->e_attrs, ad_krb5PrincipalName );
355 memset( &ent, 0, sizeof(ent) );
356 ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal);
359 a = attr_find( e->e_attrs, ad_krb5ValidEnd );
362 struct lutil_timet tt;
363 if ( lutil_parsetime( a->a_vals[0].bv_val, &tm ) == 0 &&
364 lutil_tm2time( &tm, &tt ) == 0 && tt.tt_usec < op->o_time ) {
365 /* Account is expired */
366 rc = LUTIL_PASSWD_ERR;
371 krb5_get_pw_salt( context, ent.principal, &salt );
372 krb5_free_principal( context, ent.principal );
374 a = attr_find( e->e_attrs, ad_krb5Key );
378 ent.keys.val = &ekey;
379 decode_Key((unsigned char *) a->a_vals[0].bv_val,
380 (size_t) a->a_vals[0].bv_len, &ent.keys.val[0], &l);
381 if ( db->HDB_MASTER_KEY_SET )
382 hdb_unseal_keys( context, db, &ent );
384 krb5_string_to_key_salt( context, ekey.key.keytype, cred->bv_val,
387 krb5_free_salt( context, salt );
389 if ( memcmp( ekey.key.keyvalue.data, key.keyvalue.data,
390 key.keyvalue.length ) == 0 ) rc = LUTIL_PASSWD_OK;
392 krb5_free_keyblock_contents( context, &key );
393 krb5_free_keyblock_contents( context, &ekey.key );
396 be_entry_release_r( op, e );
400 static int k5key_hash(
401 const struct berval *scheme,
402 const struct berval *passwd,
406 ber_dupbv( hash, (struct berval *)&k5key_scheme );
407 return LUTIL_PASSWD_OK;
411 static int smbk5pwd_exop_passwd(
416 req_pwdexop_s *qpw = &op->oq_pwdexop;
419 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
420 smbk5pwd_t *pi = on->on_bi.bi_private;
423 /* Not the operation we expected, pass it on... */
424 if ( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) ) {
425 return SLAP_CB_CONTINUE;
428 op->o_bd->bd_info = (BackendInfo *)on->on_info;
429 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
430 if ( rc != LDAP_SUCCESS ) return rc;
432 term = qpw->rs_new.bv_val[qpw->rs_new.bv_len];
433 qpw->rs_new.bv_val[qpw->rs_new.bv_len] = '\0';
445 if ( !SMBK5PWD_DO_KRB5( pi ) ) break;
447 if ( !is_entry_objectclass(e, oc_krb5KDCEntry, 0 ) ) break;
449 a = attr_find( e->e_attrs, ad_krb5PrincipalName );
452 memset( &ent, 0, sizeof(ent) );
453 ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal);
456 a = attr_find( e->e_attrs, ad_krb5KeyVersionNumber );
459 if ( lutil_atoi( &kvno, a->a_vals[0].bv_val ) != 0 ) {
460 Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: "
461 "dn=\"%s\" unable to parse krb5KeyVersionNumber=\"%s\"\n",
462 op->o_log_prefix, e->e_name.bv_val, a->a_vals[0].bv_val );
466 /* shouldn't happen, this is a required attr */
467 Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: "
468 "dn=\"%s\" missing krb5KeyVersionNumber\n",
469 op->o_log_prefix, e->e_name.bv_val, 0 );
472 ret = hdb_generate_key_set_password(context, ent.principal,
473 qpw->rs_new.bv_val, &ent.keys.val, &nkeys);
474 ent.keys.len = nkeys;
475 hdb_seal_keys(context, db, &ent);
476 krb5_free_principal( context, ent.principal );
478 keys = ch_malloc( (ent.keys.len + 1) * sizeof(struct berval));
480 for (i = 0; i < ent.keys.len; i++) {
484 ASN1_MALLOC_ENCODE(Key, buf, len, &ent.keys.val[i], &len, ret);
488 keys[i].bv_val = (char *)buf;
489 keys[i].bv_len = len;
491 BER_BVZERO( &keys[i] );
493 hdb_free_keys(context, ent.keys.len, ent.keys.val);
495 if ( i != ent.keys.len ) {
496 ber_bvarray_free( keys );
500 ml = ch_malloc(sizeof(Modifications));
501 if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next;
502 ml->sml_next = qpw->rs_mods;
505 ml->sml_desc = ad_krb5Key;
506 ml->sml_op = LDAP_MOD_REPLACE;
507 #ifdef SLAP_MOD_INTERNAL
508 ml->sml_flags = SLAP_MOD_INTERNAL;
511 ml->sml_values = keys;
512 ml->sml_nvalues = NULL;
514 ml = ch_malloc(sizeof(Modifications));
515 ml->sml_next = qpw->rs_mods;
518 ml->sml_desc = ad_krb5KeyVersionNumber;
519 ml->sml_op = LDAP_MOD_REPLACE;
520 #ifdef SLAP_MOD_INTERNAL
521 ml->sml_flags = SLAP_MOD_INTERNAL;
524 ml->sml_values = ch_malloc( 2 * sizeof(struct berval));
525 ml->sml_values[0].bv_val = ch_malloc( 64 );
526 ml->sml_values[0].bv_len = sprintf(ml->sml_values[0].bv_val,
528 BER_BVZERO( &ml->sml_values[1] );
529 ml->sml_nvalues = NULL;
535 if ( SMBK5PWD_DO_SAMBA( pi ) && is_entry_objectclass(e, oc_sambaSamAccount, 0 ) ) {
542 /* Expand incoming UTF8 string to UCS4 */
543 l = ldap_utf8_chars(qpw->rs_new.bv_val);
544 wcs = ch_malloc((l+1) * sizeof(wchar_t));
546 ldap_x_utf8s_to_wcs( wcs, qpw->rs_new.bv_val, l );
548 /* Truncate UCS4 to UCS2 */
550 for (j=0; j<l; j++) {
553 *c++ = (wc >> 8) & 0xff;
556 pwd.bv_val = (char *)wcs;
559 ml = ch_malloc(sizeof(Modifications));
560 if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next;
561 ml->sml_next = qpw->rs_mods;
564 keys = ch_malloc( 2 * sizeof(struct berval) );
565 BER_BVZERO( &keys[1] );
566 nthash( &pwd, keys );
568 ml->sml_desc = ad_sambaNTPassword;
569 ml->sml_op = LDAP_MOD_REPLACE;
570 #ifdef SLAP_MOD_INTERNAL
571 ml->sml_flags = SLAP_MOD_INTERNAL;
574 ml->sml_values = keys;
575 ml->sml_nvalues = NULL;
577 /* Truncate UCS2 to 8-bit ASCII */
580 for (j=1; j<l; j++) {
585 pwd.bv_val[pwd.bv_len] = '\0';
587 ml = ch_malloc(sizeof(Modifications));
588 ml->sml_next = qpw->rs_mods;
591 keys = ch_malloc( 2 * sizeof(struct berval) );
592 BER_BVZERO( &keys[1] );
593 lmhash( &pwd, keys );
595 ml->sml_desc = ad_sambaLMPassword;
596 ml->sml_op = LDAP_MOD_REPLACE;
597 #ifdef SLAP_MOD_INTERNAL
598 ml->sml_flags = SLAP_MOD_INTERNAL;
601 ml->sml_values = keys;
602 ml->sml_nvalues = NULL;
606 ml = ch_malloc(sizeof(Modifications));
607 ml->sml_next = qpw->rs_mods;
610 keys = ch_malloc( 2 * sizeof(struct berval) );
611 keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) );
612 keys[0].bv_len = snprintf(keys[0].bv_val,
613 LDAP_PVT_INTTYPE_CHARS(long),
614 "%ld", slap_get_time());
615 BER_BVZERO( &keys[1] );
617 ml->sml_desc = ad_sambaPwdLastSet;
618 ml->sml_op = LDAP_MOD_REPLACE;
619 #ifdef SLAP_MOD_INTERNAL
620 ml->sml_flags = SLAP_MOD_INTERNAL;
623 ml->sml_values = keys;
624 ml->sml_nvalues = NULL;
626 if (pi->smb_must_change)
628 ml = ch_malloc(sizeof(Modifications));
629 ml->sml_next = qpw->rs_mods;
632 keys = ch_malloc( 2 * sizeof(struct berval) );
633 keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) );
634 keys[0].bv_len = snprintf(keys[0].bv_val,
635 LDAP_PVT_INTTYPE_CHARS(long),
636 "%ld", slap_get_time() + pi->smb_must_change);
637 BER_BVZERO( &keys[1] );
639 ml->sml_desc = ad_sambaPwdMustChange;
640 ml->sml_op = LDAP_MOD_REPLACE;
641 #ifdef SLAP_MOD_INTERNAL
642 ml->sml_flags = SLAP_MOD_INTERNAL;
645 ml->sml_values = keys;
646 ml->sml_nvalues = NULL;
649 if (pi->smb_can_change)
651 ml = ch_malloc(sizeof(Modifications));
652 ml->sml_next = qpw->rs_mods;
655 keys = ch_malloc( 2 * sizeof(struct berval) );
656 keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) );
657 keys[0].bv_len = snprintf(keys[0].bv_val,
658 LDAP_PVT_INTTYPE_CHARS(long),
659 "%ld", slap_get_time() + pi->smb_can_change);
660 BER_BVZERO( &keys[1] );
662 ml->sml_desc = ad_sambaPwdCanChange;
663 ml->sml_op = LDAP_MOD_REPLACE;
664 #ifdef SLAP_MOD_INTERNAL
665 ml->sml_flags = SLAP_MOD_INTERNAL;
668 ml->sml_values = keys;
669 ml->sml_nvalues = NULL;
672 #endif /* DO_SAMBA */
676 if ( SMBK5PWD_DO_SHADOW( pi ) && is_entry_objectclass(e, oc_shadowAccount, 0 ) ) {
679 ml = ch_malloc(sizeof(Modifications));
680 if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next;
681 ml->sml_next = qpw->rs_mods;
684 keys = ch_malloc( sizeof(struct berval) * 2);
685 BER_BVZERO( &keys[1] );
686 keys[0].bv_val = ch_malloc( LDAP_PVT_INTTYPE_CHARS(long) );
687 keys[0].bv_len = snprintf(keys[0].bv_val,
688 LDAP_PVT_INTTYPE_CHARS(long),
689 "%ld", (long)(slap_get_time() / (60 * 60 * 24)));
691 ml->sml_desc = ad_shadowLastChange;
692 ml->sml_op = LDAP_MOD_REPLACE;
693 #ifdef SLAP_MOD_INTERNAL
694 ml->sml_flags = SLAP_MOD_INTERNAL;
697 ml->sml_values = keys;
698 ml->sml_nvalues = NULL;
700 #endif /* DO_SHADOW */
702 be_entry_release_r( op, e );
703 qpw->rs_new.bv_val[qpw->rs_new.bv_len] = term;
705 return SLAP_CB_CONTINUE;
708 static slap_overinst smbk5pwd;
710 /* back-config stuff */
712 PC_SMB_MUST_CHANGE = 1,
717 static ConfigDriver smbk5pwd_cf_func;
720 * NOTE: uses OID arcs OLcfgCtAt:1 and OLcfgCtOc:1
723 static ConfigTable smbk5pwd_cfats[] = {
724 { "smbk5pwd-enable", "arg",
725 2, 0, 0, ARG_MAGIC|PC_SMB_ENABLE, smbk5pwd_cf_func,
726 "( OLcfgCtAt:1.1 NAME 'olcSmbK5PwdEnable' "
727 "DESC 'Modules to be enabled' "
728 "SYNTAX OMsDirectoryString )", NULL, NULL },
729 { "smbk5pwd-must-change", "time",
730 2, 2, 0, ARG_MAGIC|ARG_INT|PC_SMB_MUST_CHANGE, smbk5pwd_cf_func,
731 "( OLcfgCtAt:1.2 NAME 'olcSmbK5PwdMustChange' "
732 "DESC 'Credentials validity interval' "
733 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
734 { "smbk5pwd-can-change", "time",
735 2, 2, 0, ARG_MAGIC|ARG_INT|PC_SMB_CAN_CHANGE, smbk5pwd_cf_func,
736 "( OLcfgCtAt:1.3 NAME 'olcSmbK5PwdCanChange' "
737 "DESC 'Credentials minimum validity interval' "
738 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
740 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
743 static ConfigOCs smbk5pwd_cfocs[] = {
745 "NAME 'olcSmbK5PwdConfig' "
746 "DESC 'smbk5pwd overlay configuration' "
747 "SUP olcOverlayConfig "
750 "$ olcSmbK5PwdMustChange "
751 "$ olcSmbK5PwdCanChange "
752 ") )", Cft_Overlay, smbk5pwd_cfats },
758 * add here other functionalities; handle their initialization
759 * as appropriate in smbk5pwd_modules_init().
761 static slap_verbmasks smbk5pwd_modules[] = {
762 { BER_BVC( "krb5" ), SMBK5PWD_F_KRB5 },
763 { BER_BVC( "samba" ), SMBK5PWD_F_SAMBA },
764 { BER_BVC( "shadow" ), SMBK5PWD_F_SHADOW },
769 smbk5pwd_cf_func( ConfigArgs *c )
771 slap_overinst *on = (slap_overinst *)c->bi;
774 smbk5pwd_t *pi = on->on_bi.bi_private;
776 if ( c->op == SLAP_CONFIG_EMIT ) {
778 case PC_SMB_MUST_CHANGE:
780 c->value_int = pi->smb_must_change;
781 #else /* ! DO_SAMBA */
783 #endif /* ! DO_SAMBA */
786 case PC_SMB_CAN_CHANGE:
788 c->value_int = pi->smb_can_change;
789 #else /* ! DO_SAMBA */
791 #endif /* ! DO_SAMBA */
795 c->rvalue_vals = NULL;
797 mask_to_verbs( smbk5pwd_modules, pi->mode, &c->rvalue_vals );
798 if ( c->rvalue_vals == NULL ) {
810 } else if ( c->op == LDAP_MOD_DELETE ) {
812 case PC_SMB_MUST_CHANGE:
815 case PC_SMB_CAN_CHANGE:
825 i = verb_to_mask( c->line, smbk5pwd_modules );
826 pi->mode &= ~smbk5pwd_modules[i].mask;
838 case PC_SMB_MUST_CHANGE:
840 if ( c->value_int < 0 ) {
841 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
842 "<%s> invalid negative value \"%d\".",
843 c->log, c->argv[ 0 ], 0 );
846 pi->smb_must_change = c->value_int;
847 #else /* ! DO_SAMBA */
848 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
849 "<%s> only meaningful "
850 "when compiled with -DDO_SAMBA.\n",
851 c->log, c->argv[ 0 ], 0 );
853 #endif /* ! DO_SAMBA */
856 case PC_SMB_CAN_CHANGE:
858 if ( c->value_int < 0 ) {
859 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
860 "<%s> invalid negative value \"%d\".",
861 c->log, c->argv[ 0 ], 0 );
864 pi->smb_can_change = c->value_int;
865 #else /* ! DO_SAMBA */
866 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
867 "<%s> only meaningful "
868 "when compiled with -DDO_SAMBA.\n",
869 c->log, c->argv[ 0 ], 0 );
871 #endif /* ! DO_SAMBA */
874 case PC_SMB_ENABLE: {
875 slap_mask_t mode = pi->mode, m = 0;
877 rc = verbs_to_mask( c->argc, c->argv, smbk5pwd_modules, &m );
879 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
880 "<%s> unknown module \"%s\".\n",
881 c->log, c->argv[ 0 ], c->argv[ rc ] );
885 /* we can hijack the smbk5pwd_t structure because
886 * from within the configuration, this is the only
891 if ( SMBK5PWD_DO_KRB5( pi ) ) {
892 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
893 "<%s> module \"%s\" only allowed when compiled with -DDO_KRB5.\n",
894 c->log, c->argv[ 0 ], c->argv[ rc ] );
898 #endif /* ! DO_KRB5 */
901 if ( SMBK5PWD_DO_SAMBA( pi ) ) {
902 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
903 "<%s> module \"%s\" only allowed when compiled with -DDO_SAMBA.\n",
904 c->log, c->argv[ 0 ], c->argv[ rc ] );
908 #endif /* ! DO_SAMBA */
911 if ( SMBK5PWD_DO_SHADOW( pi ) ) {
912 Debug( LDAP_DEBUG_ANY, "%s: smbk5pwd: "
913 "<%s> module \"%s\" only allowed when compiled with -DDO_SHADOW.\n",
914 c->log, c->argv[ 0 ], c->argv[ rc ] );
918 #endif /* ! DO_SHADOW */
921 BackendDB db = *c->be;
923 /* Re-initialize the module, because
924 * the configuration might have changed */
925 db.bd_info = (BackendInfo *)on;
926 rc = smbk5pwd_modules_init( pi );
943 smbk5pwd_modules_init( smbk5pwd_t *pi )
947 AttributeDescription **adp;
951 { "krb5Key", &ad_krb5Key },
952 { "krb5KeyVersionNumber", &ad_krb5KeyVersionNumber },
953 { "krb5PrincipalName", &ad_krb5PrincipalName },
954 { "krb5ValidEnd", &ad_krb5ValidEnd },
960 { "sambaLMPassword", &ad_sambaLMPassword },
961 { "sambaNTPassword", &ad_sambaNTPassword },
962 { "sambaPwdLastSet", &ad_sambaPwdLastSet },
963 { "sambaPwdMustChange", &ad_sambaPwdMustChange },
964 { "sambaPwdCanChange", &ad_sambaPwdCanChange },
967 #endif /* DO_SAMBA */
970 { "shadowLastChange", &ad_shadowLastChange },
973 #endif /* DO_SHADOW */
976 /* this is to silence the unused var warning */
977 dummy_ad.name = NULL;
980 if ( SMBK5PWD_DO_KRB5( pi ) && oc_krb5KDCEntry == NULL ) {
982 extern HDB *_kadm5_s_get_db(void *);
986 /* Make sure all of our necessary schema items are loaded */
987 oc_krb5KDCEntry = oc_find( "krb5KDCEntry" );
988 if ( !oc_krb5KDCEntry ) {
989 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
990 "unable to find \"krb5KDCEntry\" objectClass.\n",
995 for ( i = 0; krb5_ad[ i ].name != NULL; i++ ) {
998 *(krb5_ad[ i ].adp) = NULL;
1000 rc = slap_str2ad( krb5_ad[ i ].name, krb5_ad[ i ].adp, &text );
1001 if ( rc != LDAP_SUCCESS ) {
1002 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1003 "unable to find \"%s\" attributeType: %s (%d).\n",
1004 krb5_ad[ i ].name, text, rc );
1005 oc_krb5KDCEntry = NULL;
1010 /* Initialize Kerberos context */
1011 ret = krb5_init_context(&context);
1013 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1014 "unable to initialize krb5 context (%d).\n",
1016 oc_krb5KDCEntry = NULL;
1020 ret = kadm5_s_init_with_password_ctx( context,
1021 KADM5_ADMIN_SERVICE,
1023 KADM5_ADMIN_SERVICE,
1024 &conf, 0, 0, &kadm_context );
1026 char *err_str, *err_msg = "<unknown error>";
1027 err_str = krb5_get_error_string( context );
1029 err_msg = (char *)krb5_get_err_text( context, ret );
1030 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1031 "unable to initialize krb5 admin context: %s (%d).\n",
1032 err_str ? err_str : err_msg, ret, 0 );
1034 krb5_free_error_string( context, err_str );
1035 krb5_free_context( context );
1036 oc_krb5KDCEntry = NULL;
1040 db = _kadm5_s_get_db( kadm_context );
1042 #endif /* DO_KRB5 */
1045 if ( SMBK5PWD_DO_SAMBA( pi ) && oc_sambaSamAccount == NULL ) {
1048 oc_sambaSamAccount = oc_find( "sambaSamAccount" );
1049 if ( !oc_sambaSamAccount ) {
1050 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1051 "unable to find \"sambaSamAccount\" objectClass.\n",
1056 for ( i = 0; samba_ad[ i ].name != NULL; i++ ) {
1059 *(samba_ad[ i ].adp) = NULL;
1061 rc = slap_str2ad( samba_ad[ i ].name, samba_ad[ i ].adp, &text );
1062 if ( rc != LDAP_SUCCESS ) {
1063 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1064 "unable to find \"%s\" attributeType: %s (%d).\n",
1065 samba_ad[ i ].name, text, rc );
1066 oc_sambaSamAccount = NULL;
1071 #endif /* DO_SAMBA */
1074 if ( SMBK5PWD_DO_SHADOW( pi ) && oc_shadowAccount == NULL ) {
1077 oc_shadowAccount = oc_find( "shadowAccount" );
1078 if ( !oc_shadowAccount ) {
1079 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1080 "unable to find \"shadowAccount\" objectClass.\n",
1085 for ( i = 0; shadow_ad[ i ].name != NULL; i++ ) {
1088 *(shadow_ad[ i ].adp) = NULL;
1090 rc = slap_str2ad( shadow_ad[ i ].name, shadow_ad[ i ].adp, &text );
1091 if ( rc != LDAP_SUCCESS ) {
1092 Debug( LDAP_DEBUG_ANY, "smbk5pwd: "
1093 "unable to find \"%s\" attributeType: %s (%d).\n",
1094 shadow_ad[ i ].name, text, rc );
1095 oc_shadowAccount = NULL;
1100 #endif /* DO_SHADOW */
1106 smbk5pwd_db_init(BackendDB *be, ConfigReply *cr)
1108 slap_overinst *on = (slap_overinst *)be->bd_info;
1111 pi = ch_calloc( 1, sizeof( smbk5pwd_t ) );
1115 on->on_bi.bi_private = (void *)pi;
1121 smbk5pwd_db_open(BackendDB *be, ConfigReply *cr)
1123 slap_overinst *on = (slap_overinst *)be->bd_info;
1124 smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private;
1128 if ( pi->mode == 0 ) {
1129 pi->mode = SMBK5PWD_F_ALL;
1132 rc = smbk5pwd_modules_init( pi );
1141 smbk5pwd_db_destroy(BackendDB *be, ConfigReply *cr)
1143 slap_overinst *on = (slap_overinst *)be->bd_info;
1144 smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private;
1154 smbk5pwd_initialize(void)
1158 smbk5pwd.on_bi.bi_type = "smbk5pwd";
1160 smbk5pwd.on_bi.bi_db_init = smbk5pwd_db_init;
1161 smbk5pwd.on_bi.bi_db_open = smbk5pwd_db_open;
1162 smbk5pwd.on_bi.bi_db_destroy = smbk5pwd_db_destroy;
1164 smbk5pwd.on_bi.bi_extended = smbk5pwd_exop_passwd;
1167 smbk5pwd.on_bi.bi_op_bind = smbk5pwd_op_bind;
1169 lutil_passwd_add( (struct berval *)&k5key_scheme, k5key_chk, k5key_hash );
1172 smbk5pwd.on_bi.bi_cf_ocs = smbk5pwd_cfocs;
1174 rc = config_register_schema( smbk5pwd_cfats, smbk5pwd_cfocs );
1179 return overlay_register( &smbk5pwd );
1182 #if SLAPD_OVER_SMBK5PWD == SLAPD_MOD_DYNAMIC
1183 int init_module(int argc, char *argv[]) {
1184 return smbk5pwd_initialize();
1188 #endif /* defined(SLAPD_OVER_SMBK5PWD) */