2 * Copyright (c) 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "kadm5_locl.h"
50 __RCSID("$Heimdal: ad.c 17445 2006-05-05 10:37:46Z lha $"
55 #define CTX2LP(context) ((LDAP *)((context)->ldap_conn))
56 #define CTX2BASE(context) ((context)->base_dn)
62 #define UF_SCRIPT 0x00000001
63 #define UF_ACCOUNTDISABLE 0x00000002
64 #define UF_UNUSED_0 0x00000004
65 #define UF_HOMEDIR_REQUIRED 0x00000008
66 #define UF_LOCKOUT 0x00000010
67 #define UF_PASSWD_NOTREQD 0x00000020
68 #define UF_PASSWD_CANT_CHANGE 0x00000040
69 #define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
70 #define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100
71 #define UF_NORMAL_ACCOUNT 0x00000200
72 #define UF_UNUSED_1 0x00000400
73 #define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
74 #define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
75 #define UF_SERVER_TRUST_ACCOUNT 0x00002000
76 #define UF_UNUSED_2 0x00004000
77 #define UF_UNUSED_3 0x00008000
78 #define UF_PASSWD_NOT_EXPIRE 0x00010000
79 #define UF_MNS_LOGON_ACCOUNT 0x00020000
80 #define UF_SMARTCARD_REQUIRED 0x00040000
81 #define UF_TRUSTED_FOR_DELEGATION 0x00080000
82 #define UF_NOT_DELEGATED 0x00100000
83 #define UF_USE_DES_KEY_ONLY 0x00200000
84 #define UF_DONT_REQUIRE_PREAUTH 0x00400000
85 #define UF_UNUSED_4 0x00800000
86 #define UF_UNUSED_5 0x01000000
87 #define UF_UNUSED_6 0x02000000
88 #define UF_UNUSED_7 0x04000000
89 #define UF_UNUSED_8 0x08000000
90 #define UF_UNUSED_9 0x10000000
91 #define UF_UNUSED_10 0x20000000
92 #define UF_UNUSED_11 0x40000000
93 #define UF_UNUSED_12 0x80000000
101 sasl_interact(LDAP
*ld
, unsigned flags
, void *defaults
, void *interact
)
108 static Sockbuf_IO ldap_tsasl_io
= {
109 NULL
, /* sbi_setup */
110 NULL
, /* sbi_remove */
113 NULL
, /* sbi_write */
120 ldap_tsasl_bind_s(LDAP
*ld
,
122 LDAPControl
**serverControls
,
123 LDAPControl
**clientControls
,
126 char *attrs
[] = { "supportedSASLMechanisms", NULL
};
127 struct tsasl_peer
*peer
= NULL
;
128 struct tsasl_buffer in
, out
;
129 struct berval ccred
, *scred
;
135 ret
= tsasl_peer_init(TSASL_FLAGS_INITIATOR
| TSASL_FLAGS_CLEAR
,
136 "ldap", host
, &peer
);
137 if (ret
!= TSASL_DONE
) {
138 rc
= LDAP_LOCAL_ERROR
;
142 rc
= ldap_search_s(ld
, "", LDAP_SCOPE_BASE
, NULL
, attrs
, 0, &m0
);
143 if (rc
!= LDAP_SUCCESS
)
146 m
= ldap_first_entry(ld
, m0
);
152 vals
= ldap_get_values(ld
, m
, "supportedSASLMechanisms");
158 ret
= tsasl_find_best_mech(peer
, vals
, &mech
);
166 ret
= tsasl_select_mech(peer
, mech
);
167 if (ret
!= TSASL_DONE
) {
168 rc
= LDAP_LOCAL_ERROR
;
176 ret
= tsasl_request(peer
, &in
, &out
);
177 if (in
.tb_size
!= 0) {
182 if (ret
!= TSASL_DONE
&& ret
!= TSASL_CONTINUE
) {
183 rc
= LDAP_AUTH_UNKNOWN
;
187 ccred
.bv_val
= out
.tb_data
;
188 ccred
.bv_len
= out
.tb_size
;
190 rc
= ldap_sasl_bind_s(ld
, dn
, mech
, &ccred
,
191 serverControls
, clientControls
, &scred
);
192 tsasl_buffer_free(&out
);
194 if (rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
195 if(scred
&& scred
->bv_len
)
200 in
.tb_data
= malloc(scred
->bv_len
);
201 if (in
.tb_data
== NULL
) {
202 rc
= LDAP_LOCAL_ERROR
;
205 memcpy(in
.tb_data
, scred
->bv_val
, scred
->bv_len
);
206 in
.tb_size
= scred
->bv_len
;
209 } while (rc
== LDAP_SASL_BIND_IN_PROGRESS
);
212 if (rc
== LDAP_SUCCESS
) {
214 ber_sockbuf_add_io(ld
->ld_conns
->lconn_sb
, &ldap_tsasl_io
,
215 LBER_SBIOD_LEVEL_APPLICATION
, peer
);
218 } else if (peer
!= NULL
)
219 tsasl_peer_free(peer
);
223 #endif /* HAVE_TSASL */
227 check_ldap(kadm5_ad_context
*context
, int ret
)
232 case LDAP_SERVER_DOWN
: {
233 LDAP
*lp
= CTX2LP(context
);
235 context
->ldap_conn
= NULL
;
236 free(context
->base_dn
);
237 context
->base_dn
= NULL
;
250 laddattr(char ***al
, int *attrlen
, char *attr
)
253 a
= realloc(*al
, (*attrlen
+ 2) * sizeof(**al
));
257 a
[*attrlen
+ 1] = NULL
;
263 _kadm5_ad_connect(void *server_handle
)
265 kadm5_ad_context
*context
= server_handle
;
269 } *s
, *servers
= NULL
;
270 int i
, num_servers
= 0;
272 if (context
->ldap_conn
)
277 struct resource_record
*rr
;
280 asprintf(&domain
, "_ldap._tcp.%s", context
->realm
);
281 if (domain
== NULL
) {
282 krb5_set_error_string(context
->context
, "malloc");
286 r
= dns_lookup(domain
, "SRV");
289 krb5_set_error_string(context
->context
, "Didn't find ldap dns");
293 for (rr
= r
->head
; rr
!= NULL
; rr
= rr
->next
) {
294 if (rr
->type
!= T_SRV
)
296 s
= realloc(servers
, sizeof(*servers
) * (num_servers
+ 1));
298 krb5_set_error_string(context
->context
, "malloc");
304 servers
[num_servers
- 1].port
= rr
->u
.srv
->port
;
305 servers
[num_servers
- 1].server
= strdup(rr
->u
.srv
->target
);
310 if (num_servers
== 0) {
311 krb5_set_error_string(context
->context
, "No AD server found in DNS");
315 for (i
= 0; i
< num_servers
; i
++) {
316 int lret
, version
= LDAP_VERSION3
;
319 lp
= ldap_init(servers
[i
].server
, servers
[i
].port
);
323 if (ldap_set_option(lp
, LDAP_OPT_PROTOCOL_VERSION
, &version
)) {
328 if (ldap_set_option(lp
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
)) {
334 lret
= ldap_tsasl_bind_s(lp
, NULL
, NULL
, NULL
, servers
[i
].server
);
337 lret
= ldap_sasl_interactive_bind_s(lp
, NULL
, NULL
, NULL
, NULL
,
339 sasl_interact
, NULL
);
341 if (lret
!= LDAP_SUCCESS
) {
342 krb5_set_error_string(context
->context
,
343 "Couldn't contact any AD servers: %s",
344 ldap_err2string(lret
));
349 context
->ldap_conn
= lp
;
352 if (i
>= num_servers
) {
363 laddattr(&attr
, &attrlen
, "defaultNamingContext");
365 ret
= ldap_search_s(CTX2LP(context
), "", LDAP_SCOPE_BASE
,
366 "objectclass=*", attr
, 0, &m
);
368 if (check_ldap(context
, ret
))
371 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
372 m0
= ldap_first_entry(CTX2LP(context
), m
);
374 krb5_set_error_string(context
->context
,
375 "Error in AD ldap responce");
379 vals
= ldap_get_values(CTX2LP(context
),
380 m0
, "defaultNamingContext");
382 krb5_set_error_string(context
->context
,
383 "No naming context found");
386 context
->base_dn
= strdup(vals
[0]);
392 for (i
= 0; i
< num_servers
; i
++)
393 free(servers
[i
].server
);
399 for (i
= 0; i
< num_servers
; i
++)
400 free(servers
[i
].server
);
403 if (context
->ldap_conn
) {
404 ldap_unbind(CTX2LP(context
));
405 context
->ldap_conn
= NULL
;
407 return KADM5_RPC_ERROR
;
410 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
413 nt2unixtime(const char *str
)
415 unsigned long long t
;
416 t
= strtoll(str
, NULL
, 10);
417 t
= ((t
- NTTIME_EPOCH
) / (long long)10000000);
418 if (t
> (((time_t)(~(long long)0)) >> 1))
424 unix2nttime(time_t unix_time
)
427 wt
= unix_time
* (long long)10000000 + (long long)NTTIME_EPOCH
;
431 /* XXX create filter in a better way */
434 ad_find_entry(kadm5_ad_context
*context
,
440 char *attr
[] = { "distinguishedName", NULL
};
449 "(&(objectClass=computer)(|(dNSHostName=%s)(servicePrincipalName=%s)))",
452 asprintf(&filter
, "(&(objectClass=account)(userPrincipalName=%s))", pn
);
454 return KADM5_RPC_ERROR
;
456 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
458 filter
, attr
, 0, &m
);
460 if (check_ldap(context
, ret
))
461 return KADM5_RPC_ERROR
;
463 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
465 m0
= ldap_first_entry(CTX2LP(context
), m
);
466 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
467 if (vals
== NULL
|| vals
[0] == NULL
) {
469 return KADM5_RPC_ERROR
;
472 *name
= strdup(vals
[0]);
475 return KADM5_UNK_PRINC
;
480 #endif /* OPENLDAP */
483 ad_get_cred(kadm5_ad_context
*context
, const char *password
)
492 asprintf(&service
, "%s/%s@%s", KRB5_TGS_NAME
,
493 context
->realm
, context
->realm
);
497 ret
= _kadm5_c_get_cred_cache(context
->context
,
498 context
->client_name
,
500 password
, krb5_prompter_posix
,
504 return ret
; /* XXX */
505 context
->ccache
= cc
;
510 kadm5_ad_chpass_principal(void *server_handle
,
511 krb5_principal principal
,
512 const char *password
)
514 kadm5_ad_context
*context
= server_handle
;
515 krb5_data result_code_string
, result_string
;
519 ret
= ad_get_cred(context
, NULL
);
523 krb5_data_zero (&result_code_string
);
524 krb5_data_zero (&result_string
);
526 ret
= krb5_set_password_using_ccache (context
->context
,
534 krb5_data_free (&result_code_string
);
535 krb5_data_free (&result_string
);
537 /* XXX do mapping here on error codes */
544 get_fqdn(krb5_context context
, const krb5_principal p
)
546 const char *s
, *hosttypes
[] = { "host", "ldap", "gc", "cifs", "dns" };
549 s
= krb5_principal_get_comp_string(context
, p
, 0);
553 for (i
= 0; i
< sizeof(hosttypes
)/sizeof(hosttypes
[0]); i
++) {
554 if (strcasecmp(s
, hosttypes
[i
]) == 0)
555 return krb5_principal_get_comp_string(context
, p
, 1);
563 kadm5_ad_create_principal(void *server_handle
,
564 kadm5_principal_ent_t entry
,
566 const char *password
)
568 kadm5_ad_context
*context
= server_handle
;
571 * KADM5_PRINC_EXPIRE_TIME
573 * return 0 || KADM5_DUP;
577 LDAPMod
*attrs
[8], rattrs
[7], *a
;
578 char *useraccvals
[2] = { NULL
, NULL
},
579 *samvals
[2], *dnsvals
[2], *spnvals
[5], *upnvals
[2], *tv
[2];
580 char *ocvals_spn
[] = { "top", "person", "organizationalPerson",
581 "user", "computer", NULL
};
582 char *p
, *realmless_p
, *p_msrealm
= NULL
, *dn
= NULL
;
584 char *s
, *samname
= NULL
, *short_spn
= NULL
;
586 int32_t uf_flags
= 0;
588 if ((mask
& KADM5_PRINCIPAL
) == 0)
589 return KADM5_BAD_MASK
;
591 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
592 attrs
[i
] = &rattrs
[i
];
595 ret
= ad_get_cred(context
, NULL
);
599 ret
= _kadm5_ad_connect(server_handle
);
603 fqdn
= get_fqdn(context
->context
, entry
->principal
);
605 ret
= krb5_unparse_name(context
->context
, entry
->principal
, &p
);
609 if (ad_find_entry(context
, fqdn
, p
, NULL
) == 0) {
614 if (mask
& KADM5_ATTRIBUTES
) {
615 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
616 uf_flags
|= UF_ACCOUNTDISABLE
|UF_LOCKOUT
;
617 if ((entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
) == 0)
618 uf_flags
|= UF_DONT_REQUIRE_PREAUTH
;
619 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
620 uf_flags
|= UF_SMARTCARD_REQUIRED
;
623 realmless_p
= strdup(p
);
624 if (realmless_p
== NULL
) {
628 s
= strrchr(realmless_p
, '@');
633 /* create computer account */
634 asprintf(&samname
, "%s$", fqdn
);
635 if (samname
== NULL
) {
639 s
= strchr(samname
, '.');
645 short_spn
= strdup(p
);
646 if (short_spn
== NULL
) {
650 s
= strchr(short_spn
, '.');
658 p_msrealm
= strdup(p
);
659 if (p_msrealm
== NULL
) {
663 s
= strrchr(p_msrealm
, '@');
671 asprintf(&dn
, "cn=%s, cn=Computers, %s", fqdn
, CTX2BASE(context
));
678 a
->mod_op
= LDAP_MOD_ADD
;
679 a
->mod_type
= "objectClass";
680 a
->mod_values
= ocvals_spn
;
683 a
->mod_op
= LDAP_MOD_ADD
;
684 a
->mod_type
= "userAccountControl";
685 a
->mod_values
= useraccvals
;
686 asprintf(&useraccvals
[0], "%d",
688 UF_PASSWD_NOT_EXPIRE
|
689 UF_WORKSTATION_TRUST_ACCOUNT
);
690 useraccvals
[1] = NULL
;
693 a
->mod_op
= LDAP_MOD_ADD
;
694 a
->mod_type
= "sAMAccountName";
695 a
->mod_values
= samvals
;
696 samvals
[0] = samname
;
700 a
->mod_op
= LDAP_MOD_ADD
;
701 a
->mod_type
= "dNSHostName";
702 a
->mod_values
= dnsvals
;
703 dnsvals
[0] = (char *)fqdn
;
707 /* XXX add even more spn's */
708 a
->mod_op
= LDAP_MOD_ADD
;
709 a
->mod_type
= "servicePrincipalName";
710 a
->mod_values
= spnvals
;
713 spnvals
[i
++] = realmless_p
;
715 spnvals
[i
++] = short_spn
;
717 spnvals
[i
++] = p_msrealm
;
721 a
->mod_op
= LDAP_MOD_ADD
;
722 a
->mod_type
= "userPrincipalName";
723 a
->mod_values
= upnvals
;
728 a
->mod_op
= LDAP_MOD_ADD
;
729 a
->mod_type
= "accountExpires";
731 tv
[0] = "9223372036854775807"; /* "never" */
736 /* create user account */
739 a
->mod_op
= LDAP_MOD_ADD
;
740 a
->mod_type
= "userAccountControl";
741 a
->mod_values
= useraccvals
;
742 asprintf(&useraccvals
[0], "%d",
744 UF_PASSWD_NOT_EXPIRE
);
745 useraccvals
[1] = NULL
;
748 a
->mod_op
= LDAP_MOD_ADD
;
749 a
->mod_type
= "sAMAccountName";
750 a
->mod_values
= samvals
;
751 samvals
[0] = realmless_p
;
755 a
->mod_op
= LDAP_MOD_ADD
;
756 a
->mod_type
= "userPrincipalName";
757 a
->mod_values
= upnvals
;
762 a
->mod_op
= LDAP_MOD_ADD
;
763 a
->mod_type
= "accountExpires";
765 tv
[0] = "9223372036854775807"; /* "never" */
770 attrs
[a
- &rattrs
[0]] = NULL
;
772 ret
= ldap_add_s(CTX2LP(context
), dn
, attrs
);
776 free(useraccvals
[0]);
787 if (check_ldap(context
, ret
))
788 return KADM5_RPC_ERROR
;
792 krb5_set_error_string(context
->context
, "Function not implemented");
793 return KADM5_RPC_ERROR
;
798 kadm5_ad_delete_principal(void *server_handle
, krb5_principal principal
)
800 kadm5_ad_context
*context
= server_handle
;
806 ret
= ad_get_cred(context
, NULL
);
810 ret
= _kadm5_ad_connect(server_handle
);
814 fqdn
= get_fqdn(context
->context
, principal
);
816 ret
= krb5_unparse_name(context
->context
, principal
, &p
);
820 if (ad_find_entry(context
, fqdn
, p
, &dn
) != 0) {
822 return KADM5_UNK_PRINC
;
825 ret
= ldap_delete_s(CTX2LP(context
), dn
);
830 if (check_ldap(context
, ret
))
831 return KADM5_RPC_ERROR
;
834 krb5_set_error_string(context
->context
, "Function not implemented");
835 return KADM5_RPC_ERROR
;
840 kadm5_ad_destroy(void *server_handle
)
842 kadm5_ad_context
*context
= server_handle
;
845 krb5_cc_destroy(context
->context
, context
->ccache
);
849 LDAP
*lp
= CTX2LP(context
);
852 if (context
->base_dn
)
853 free(context
->base_dn
);
856 free(context
->realm
);
857 free(context
->client_name
);
858 krb5_free_principal(context
->context
, context
->caller
);
859 if(context
->my_context
)
860 krb5_free_context(context
->context
);
865 kadm5_ad_flush(void *server_handle
)
867 kadm5_ad_context
*context
= server_handle
;
869 krb5_set_error_string(context
->context
, "Function not implemented");
870 return KADM5_RPC_ERROR
;
872 krb5_set_error_string(context
->context
, "Function not implemented");
873 return KADM5_RPC_ERROR
;
878 kadm5_ad_get_principal(void *server_handle
,
879 krb5_principal principal
,
880 kadm5_principal_ent_t entry
,
883 kadm5_ad_context
*context
= server_handle
;
888 char *filter
, *p
, *q
, *u
;
893 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
897 * return 0 || KADM5_DUP;
900 memset(entry
, 0, sizeof(*entry
));
902 if (mask
& KADM5_KVNO
)
903 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
905 if (mask
& KADM5_PRINCIPAL
) {
906 laddattr(&attr
, &attrlen
, "userPrincipalName");
907 laddattr(&attr
, &attrlen
, "servicePrincipalName");
909 laddattr(&attr
, &attrlen
, "objectClass");
910 laddattr(&attr
, &attrlen
, "lastLogon");
911 laddattr(&attr
, &attrlen
, "badPwdCount");
912 laddattr(&attr
, &attrlen
, "badPasswordTime");
913 laddattr(&attr
, &attrlen
, "pwdLastSet");
914 laddattr(&attr
, &attrlen
, "accountExpires");
915 laddattr(&attr
, &attrlen
, "userAccountControl");
917 krb5_unparse_name_short(context
->context
, principal
, &p
);
918 krb5_unparse_name(context
->context
, principal
, &u
);
920 /* replace @ in domain part with a / */
922 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
926 "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
931 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
933 filter
, attr
, 0, &m
);
935 if (check_ldap(context
, ret
))
936 return KADM5_RPC_ERROR
;
938 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
940 m0
= ldap_first_entry(CTX2LP(context
), m
);
946 vals
= ldap_get_values(CTX2LP(context
), m0
, "servicePrincipalName");
948 printf("servicePrincipalName %s\n", vals
[0]);
949 vals
= ldap_get_values(CTX2LP(context
), m0
, "userPrincipalName");
951 printf("userPrincipalName %s\n", vals
[0]);
952 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
954 printf("userAccountControl %s\n", vals
[0]);
956 entry
->princ_expire_time
= 0;
957 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
958 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
960 entry
->princ_expire_time
= nt2unixtime(vals
[0]);
962 entry
->last_success
= 0;
963 if (mask
& KADM5_LAST_SUCCESS
) {
964 vals
= ldap_get_values(CTX2LP(context
), m0
, "lastLogon");
966 entry
->last_success
= nt2unixtime(vals
[0]);
968 if (mask
& KADM5_LAST_FAILED
) {
969 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPasswordTime");
971 entry
->last_failed
= nt2unixtime(vals
[0]);
973 if (mask
& KADM5_LAST_PWD_CHANGE
) {
974 vals
= ldap_get_values(CTX2LP(context
), m0
, "pwdLastSet");
976 entry
->last_pwd_change
= nt2unixtime(vals
[0]);
978 if (mask
& KADM5_FAIL_AUTH_COUNT
) {
979 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPwdCount");
981 entry
->fail_auth_count
= atoi(vals
[0]);
983 if (mask
& KADM5_ATTRIBUTES
) {
984 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
988 if (i
& (UF_ACCOUNTDISABLE
|UF_LOCKOUT
))
989 entry
->attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
990 if ((i
& UF_DONT_REQUIRE_PREAUTH
) == 0)
991 entry
->attributes
|= KRB5_KDB_REQUIRES_PRE_AUTH
;
992 if (i
& UF_SMARTCARD_REQUIRED
)
993 entry
->attributes
|= KRB5_KDB_REQUIRES_HW_AUTH
;
994 if ((i
& UF_WORKSTATION_TRUST_ACCOUNT
) == 0)
995 entry
->attributes
|= KRB5_KDB_DISALLOW_SVR
;
998 if (mask
& KADM5_KVNO
) {
999 vals
= ldap_get_values(CTX2LP(context
), m0
,
1000 "msDS-KeyVersionNumber");
1002 entry
->kvno
= atoi(vals
[0]);
1008 return KADM5_UNK_PRINC
;
1011 if (mask
& KADM5_PRINCIPAL
)
1012 krb5_copy_principal(context
->context
, principal
, &entry
->principal
);
1016 return KADM5_RPC_ERROR
;
1018 krb5_set_error_string(context
->context
, "Function not implemented");
1019 return KADM5_RPC_ERROR
;
1024 kadm5_ad_get_principals(void *server_handle
,
1025 const char *expression
,
1029 kadm5_ad_context
*context
= server_handle
;
1032 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1038 ret
= ad_get_cred(context
, NULL
);
1042 ret
= _kadm5_ad_connect(server_handle
);
1046 krb5_set_error_string(context
->context
, "Function not implemented");
1047 return KADM5_RPC_ERROR
;
1049 krb5_set_error_string(context
->context
, "Function not implemented");
1050 return KADM5_RPC_ERROR
;
1055 kadm5_ad_get_privs(void *server_handle
, uint32_t*privs
)
1057 kadm5_ad_context
*context
= server_handle
;
1058 krb5_set_error_string(context
->context
, "Function not implemented");
1059 return KADM5_RPC_ERROR
;
1063 kadm5_ad_modify_principal(void *server_handle
,
1064 kadm5_principal_ent_t entry
,
1067 kadm5_ad_context
*context
= server_handle
;
1071 * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1075 LDAPMessage
*m
= NULL
, *m0
;
1079 char *p
= NULL
, *s
= NULL
, *q
;
1081 LDAPMod
*attrs
[4], rattrs
[3], *a
;
1082 char *uaf
[2] = { NULL
, NULL
};
1083 char *kvno
[2] = { NULL
, NULL
};
1084 char *tv
[2] = { NULL
, NULL
};
1088 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
1089 attrs
[i
] = &rattrs
[i
];
1093 ret
= _kadm5_ad_connect(server_handle
);
1097 if (mask
& KADM5_KVNO
)
1098 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
1099 if (mask
& KADM5_PRINC_EXPIRE_TIME
)
1100 laddattr(&attr
, &attrlen
, "accountExpires");
1101 if (mask
& KADM5_ATTRIBUTES
)
1102 laddattr(&attr
, &attrlen
, "userAccountControl");
1103 laddattr(&attr
, &attrlen
, "distinguishedName");
1105 krb5_unparse_name(context
->context
, entry
->principal
, &p
);
1109 q
= strrchr(s
, '@');
1110 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
1114 "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1119 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
1121 filter
, attr
, 0, &m
);
1124 if (check_ldap(context
, ret
))
1125 return KADM5_RPC_ERROR
;
1127 if (ldap_count_entries(CTX2LP(context
), m
) <= 0) {
1128 ret
= KADM5_RPC_ERROR
;
1132 m0
= ldap_first_entry(CTX2LP(context
), m
);
1134 if (mask
& KADM5_ATTRIBUTES
) {
1137 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
1139 ret
= KADM5_RPC_ERROR
;
1145 return KADM5_RPC_ERROR
;
1147 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
1148 i
|= (UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1150 i
&= ~(UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1151 if (entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
)
1152 i
&= ~UF_DONT_REQUIRE_PREAUTH
;
1154 i
|= UF_DONT_REQUIRE_PREAUTH
;
1155 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
1156 i
|= UF_SMARTCARD_REQUIRED
;
1158 i
&= UF_SMARTCARD_REQUIRED
;
1159 if (entry
->attributes
& KRB5_KDB_DISALLOW_SVR
)
1160 i
&= ~UF_WORKSTATION_TRUST_ACCOUNT
;
1162 i
|= UF_WORKSTATION_TRUST_ACCOUNT
;
1164 asprintf(&uaf
[0], "%d", i
);
1166 a
->mod_op
= LDAP_MOD_REPLACE
;
1167 a
->mod_type
= "userAccountControl";
1168 a
->mod_values
= uaf
;
1172 if (mask
& KADM5_KVNO
) {
1173 vals
= ldap_get_values(CTX2LP(context
), m0
, "msDS-KeyVersionNumber");
1177 asprintf(&kvno
[0], "%d", entry
->kvno
);
1179 a
->mod_op
= LDAP_MOD_REPLACE
;
1180 a
->mod_type
= "msDS-KeyVersionNumber";
1181 a
->mod_values
= kvno
;
1186 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
1188 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
1190 ret
= KADM5_RPC_ERROR
;
1194 wt
= unix2nttime(entry
->princ_expire_time
);
1196 asprintf(&tv
[0], "%llu", wt
);
1198 a
->mod_op
= LDAP_MOD_REPLACE
;
1199 a
->mod_type
= "accountExpires";
1204 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
1206 ret
= KADM5_RPC_ERROR
;
1211 attrs
[a
- &rattrs
[0]] = NULL
;
1213 ret
= ldap_modify_s(CTX2LP(context
), dn
, attrs
);
1214 if (check_ldap(context
, ret
))
1215 return KADM5_RPC_ERROR
;
1228 krb5_set_error_string(context
->context
, "Function not implemented");
1229 return KADM5_RPC_ERROR
;
1234 kadm5_ad_randkey_principal(void *server_handle
,
1235 krb5_principal principal
,
1236 krb5_keyblock
**keys
,
1239 kadm5_ad_context
*context
= server_handle
;
1246 krb5_data result_code_string
, result_string
;
1247 int result_code
, plen
;
1256 krb5_generate_random_block(p
, sizeof(p
));
1257 plen
= base64_encode(p
, sizeof(p
), &password
);
1262 ret
= ad_get_cred(context
, NULL
);
1268 krb5_data_zero (&result_code_string
);
1269 krb5_data_zero (&result_string
);
1271 ret
= krb5_set_password_using_ccache (context
->context
,
1276 &result_code_string
,
1279 krb5_data_free (&result_code_string
);
1280 krb5_data_free (&result_string
);
1284 *keys
= malloc(sizeof(**keys
) * 1);
1285 if (*keys
== NULL
) {
1291 ret
= krb5_string_to_key(context
->context
,
1292 ENCTYPE_ARCFOUR_HMAC_MD5
,
1296 memset(password
, 0, sizeof(password
));
1304 memset(password
, 0, plen
);
1312 krb5_set_error_string(context
->context
, "Function not implemented");
1313 return KADM5_RPC_ERROR
;
1318 kadm5_ad_rename_principal(void *server_handle
,
1319 krb5_principal from
,
1322 kadm5_ad_context
*context
= server_handle
;
1323 krb5_set_error_string(context
->context
, "Function not implemented");
1324 return KADM5_RPC_ERROR
;
1328 kadm5_ad_chpass_principal_with_key(void *server_handle
,
1329 krb5_principal princ
,
1331 krb5_key_data
*key_data
)
1333 kadm5_ad_context
*context
= server_handle
;
1334 krb5_set_error_string(context
->context
, "Function not implemented");
1335 return KADM5_RPC_ERROR
;
1339 set_funcs(kadm5_ad_context
*c
)
1341 #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1342 SET(c
, chpass_principal
);
1343 SET(c
, chpass_principal_with_key
);
1344 SET(c
, create_principal
);
1345 SET(c
, delete_principal
);
1348 SET(c
, get_principal
);
1349 SET(c
, get_principals
);
1351 SET(c
, modify_principal
);
1352 SET(c
, randkey_principal
);
1353 SET(c
, rename_principal
);
1357 kadm5_ad_init_with_password_ctx(krb5_context context
,
1358 const char *client_name
,
1359 const char *password
,
1360 const char *service_name
,
1361 kadm5_config_params
*realm_params
,
1362 unsigned long struct_version
,
1363 unsigned long api_version
,
1364 void **server_handle
)
1367 kadm5_ad_context
*ctx
;
1369 ctx
= malloc(sizeof(*ctx
));
1372 memset(ctx
, 0, sizeof(*ctx
));
1375 ctx
->context
= context
;
1376 krb5_add_et_list (context
, initialize_kadm5_error_table_r
);
1378 ret
= krb5_parse_name(ctx
->context
, client_name
, &ctx
->caller
);
1384 if(realm_params
->mask
& KADM5_CONFIG_REALM
) {
1386 ctx
->realm
= strdup(realm_params
->realm
);
1387 if (ctx
->realm
== NULL
)
1390 ret
= krb5_get_default_realm(ctx
->context
, &ctx
->realm
);
1396 ctx
->client_name
= strdup(client_name
);
1398 if(password
!= NULL
&& *password
!= '\0')
1399 ret
= ad_get_cred(ctx
, password
);
1401 ret
= ad_get_cred(ctx
, NULL
);
1403 kadm5_ad_destroy(ctx
);
1408 ret
= _kadm5_ad_connect(ctx
);
1410 kadm5_ad_destroy(ctx
);
1415 *server_handle
= ctx
;
1420 kadm5_ad_init_with_password(const char *client_name
,
1421 const char *password
,
1422 const char *service_name
,
1423 kadm5_config_params
*realm_params
,
1424 unsigned long struct_version
,
1425 unsigned long api_version
,
1426 void **server_handle
)
1428 krb5_context context
;
1430 kadm5_ad_context
*ctx
;
1432 ret
= krb5_init_context(&context
);
1435 ret
= kadm5_ad_init_with_password_ctx(context
,
1444 krb5_free_context(context
);
1447 ctx
= *server_handle
;
1448 ctx
->my_context
= 1;