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"
54 #define CTX2LP(context) ((LDAP *)((context)->ldap_conn))
55 #define CTX2BASE(context) ((context)->base_dn)
61 #define UF_SCRIPT 0x00000001
62 #define UF_ACCOUNTDISABLE 0x00000002
63 #define UF_UNUSED_0 0x00000004
64 #define UF_HOMEDIR_REQUIRED 0x00000008
65 #define UF_LOCKOUT 0x00000010
66 #define UF_PASSWD_NOTREQD 0x00000020
67 #define UF_PASSWD_CANT_CHANGE 0x00000040
68 #define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
69 #define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100
70 #define UF_NORMAL_ACCOUNT 0x00000200
71 #define UF_UNUSED_1 0x00000400
72 #define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
73 #define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
74 #define UF_SERVER_TRUST_ACCOUNT 0x00002000
75 #define UF_UNUSED_2 0x00004000
76 #define UF_UNUSED_3 0x00008000
77 #define UF_PASSWD_NOT_EXPIRE 0x00010000
78 #define UF_MNS_LOGON_ACCOUNT 0x00020000
79 #define UF_SMARTCARD_REQUIRED 0x00040000
80 #define UF_TRUSTED_FOR_DELEGATION 0x00080000
81 #define UF_NOT_DELEGATED 0x00100000
82 #define UF_USE_DES_KEY_ONLY 0x00200000
83 #define UF_DONT_REQUIRE_PREAUTH 0x00400000
84 #define UF_UNUSED_4 0x00800000
85 #define UF_UNUSED_5 0x01000000
86 #define UF_UNUSED_6 0x02000000
87 #define UF_UNUSED_7 0x04000000
88 #define UF_UNUSED_8 0x08000000
89 #define UF_UNUSED_9 0x10000000
90 #define UF_UNUSED_10 0x20000000
91 #define UF_UNUSED_11 0x40000000
92 #define UF_UNUSED_12 0x80000000
100 sasl_interact(LDAP
*ld
, unsigned flags
, void *defaults
, void *interact
)
107 static Sockbuf_IO ldap_tsasl_io
= {
108 NULL
, /* sbi_setup */
109 NULL
, /* sbi_remove */
112 NULL
, /* sbi_write */
119 ldap_tsasl_bind_s(LDAP
*ld
,
121 LDAPControl
**serverControls
,
122 LDAPControl
**clientControls
,
125 char *attrs
[] = { "supportedSASLMechanisms", NULL
};
126 struct tsasl_peer
*peer
= NULL
;
127 struct tsasl_buffer in
, out
;
128 struct berval ccred
, *scred
;
134 ret
= tsasl_peer_init(TSASL_FLAGS_INITIATOR
| TSASL_FLAGS_CLEAR
,
135 "ldap", host
, &peer
);
136 if (ret
!= TSASL_DONE
) {
137 rc
= LDAP_LOCAL_ERROR
;
141 rc
= ldap_search_s(ld
, "", LDAP_SCOPE_BASE
, NULL
, attrs
, 0, &m0
);
142 if (rc
!= LDAP_SUCCESS
)
145 m
= ldap_first_entry(ld
, m0
);
151 vals
= ldap_get_values(ld
, m
, "supportedSASLMechanisms");
157 ret
= tsasl_find_best_mech(peer
, vals
, &mech
);
165 ret
= tsasl_select_mech(peer
, mech
);
166 if (ret
!= TSASL_DONE
) {
167 rc
= LDAP_LOCAL_ERROR
;
175 ret
= tsasl_request(peer
, &in
, &out
);
176 if (in
.tb_size
!= 0) {
181 if (ret
!= TSASL_DONE
&& ret
!= TSASL_CONTINUE
) {
182 rc
= LDAP_AUTH_UNKNOWN
;
186 ccred
.bv_val
= out
.tb_data
;
187 ccred
.bv_len
= out
.tb_size
;
189 rc
= ldap_sasl_bind_s(ld
, dn
, mech
, &ccred
,
190 serverControls
, clientControls
, &scred
);
191 tsasl_buffer_free(&out
);
193 if (rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
194 if(scred
&& scred
->bv_len
)
199 in
.tb_data
= malloc(scred
->bv_len
);
200 if (in
.tb_data
== NULL
) {
201 rc
= LDAP_LOCAL_ERROR
;
204 memcpy(in
.tb_data
, scred
->bv_val
, scred
->bv_len
);
205 in
.tb_size
= scred
->bv_len
;
208 } while (rc
== LDAP_SASL_BIND_IN_PROGRESS
);
211 if (rc
== LDAP_SUCCESS
) {
213 ber_sockbuf_add_io(ld
->ld_conns
->lconn_sb
, &ldap_tsasl_io
,
214 LBER_SBIOD_LEVEL_APPLICATION
, peer
);
217 } else if (peer
!= NULL
)
218 tsasl_peer_free(peer
);
222 #endif /* HAVE_TSASL */
226 check_ldap(kadm5_ad_context
*context
, int ret
)
231 case LDAP_SERVER_DOWN
: {
232 LDAP
*lp
= CTX2LP(context
);
234 context
->ldap_conn
= NULL
;
235 free(context
->base_dn
);
236 context
->base_dn
= NULL
;
249 laddattr(char ***al
, int *attrlen
, char *attr
)
252 a
= realloc(*al
, (*attrlen
+ 2) * sizeof(**al
));
256 a
[*attrlen
+ 1] = NULL
;
262 _kadm5_ad_connect(void *server_handle
)
264 kadm5_ad_context
*context
= server_handle
;
268 } *s
, *servers
= NULL
;
269 int i
, num_servers
= 0;
271 if (context
->ldap_conn
)
276 struct resource_record
*rr
;
279 asprintf(&domain
, "_ldap._tcp.%s", context
->realm
);
280 if (domain
== NULL
) {
281 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "malloc");
285 r
= dns_lookup(domain
, "SRV");
288 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "Didn't find ldap dns");
292 for (rr
= r
->head
; rr
!= NULL
; rr
= rr
->next
) {
293 if (rr
->type
!= rk_ns_t_srv
)
295 s
= realloc(servers
, sizeof(*servers
) * (num_servers
+ 1));
297 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "malloc");
303 servers
[num_servers
- 1].port
= rr
->u
.srv
->port
;
304 servers
[num_servers
- 1].server
= strdup(rr
->u
.srv
->target
);
309 if (num_servers
== 0) {
310 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "No AD server found in DNS");
314 for (i
= 0; i
< num_servers
; i
++) {
315 int lret
, version
= LDAP_VERSION3
;
318 lp
= ldap_init(servers
[i
].server
, servers
[i
].port
);
322 if (ldap_set_option(lp
, LDAP_OPT_PROTOCOL_VERSION
, &version
)) {
327 if (ldap_set_option(lp
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
)) {
333 lret
= ldap_tsasl_bind_s(lp
, NULL
, NULL
, NULL
, servers
[i
].server
);
336 lret
= ldap_sasl_interactive_bind_s(lp
, NULL
, NULL
, NULL
, NULL
,
338 sasl_interact
, NULL
);
340 if (lret
!= LDAP_SUCCESS
) {
341 krb5_set_error_message(context
->context
, 0,
342 "Couldn't contact any AD servers: %s",
343 ldap_err2string(lret
));
348 context
->ldap_conn
= lp
;
351 if (i
>= num_servers
) {
362 laddattr(&attr
, &attrlen
, "defaultNamingContext");
364 ret
= ldap_search_s(CTX2LP(context
), "", LDAP_SCOPE_BASE
,
365 "objectclass=*", attr
, 0, &m
);
367 if (check_ldap(context
, ret
))
370 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
371 m0
= ldap_first_entry(CTX2LP(context
), m
);
373 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
,
374 "Error in AD ldap responce");
378 vals
= ldap_get_values(CTX2LP(context
),
379 m0
, "defaultNamingContext");
381 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
,
382 "No naming context found");
385 context
->base_dn
= strdup(vals
[0]);
391 for (i
= 0; i
< num_servers
; i
++)
392 free(servers
[i
].server
);
398 for (i
= 0; i
< num_servers
; i
++)
399 free(servers
[i
].server
);
402 if (context
->ldap_conn
) {
403 ldap_unbind(CTX2LP(context
));
404 context
->ldap_conn
= NULL
;
406 return KADM5_RPC_ERROR
;
409 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
412 nt2unixtime(const char *str
)
414 unsigned long long t
;
415 t
= strtoll(str
, NULL
, 10);
416 t
= ((t
- NTTIME_EPOCH
) / (long long)10000000);
417 if (t
> (((time_t)(~(long long)0)) >> 1))
423 unix2nttime(time_t unix_time
)
426 wt
= unix_time
* (long long)10000000 + (long long)NTTIME_EPOCH
;
430 /* XXX create filter in a better way */
433 ad_find_entry(kadm5_ad_context
*context
,
439 char *attr
[] = { "distinguishedName", NULL
};
448 "(&(objectClass=computer)(|(dNSHostName=%s)(servicePrincipalName=%s)))",
451 asprintf(&filter
, "(&(objectClass=account)(userPrincipalName=%s))", pn
);
453 return KADM5_RPC_ERROR
;
455 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
457 filter
, attr
, 0, &m
);
459 if (check_ldap(context
, ret
))
460 return KADM5_RPC_ERROR
;
462 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
464 m0
= ldap_first_entry(CTX2LP(context
), m
);
465 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
466 if (vals
== NULL
|| vals
[0] == NULL
) {
468 return KADM5_RPC_ERROR
;
471 *name
= strdup(vals
[0]);
474 return KADM5_UNK_PRINC
;
479 #endif /* OPENLDAP */
482 ad_get_cred(kadm5_ad_context
*context
, const char *password
)
492 aret
= asprintf(&service
, "%s/%s@%s", KRB5_TGS_NAME
,
493 context
->realm
, context
->realm
);
494 if (aret
== -1 || service
== NULL
)
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
,
514 krb5_key_salt_tuple
*ks_tuple
,
515 const char *password
)
517 kadm5_ad_context
*context
= server_handle
;
518 krb5_data result_code_string
, result_string
;
523 return KADM5_KEEPOLD_NOSUPP
;
526 return KADM5_KS_TUPLE_NOSUPP
;
528 ret
= ad_get_cred(context
, NULL
);
532 krb5_data_zero (&result_code_string
);
533 krb5_data_zero (&result_string
);
535 ret
= krb5_set_password_using_ccache (context
->context
,
543 krb5_data_free (&result_code_string
);
544 krb5_data_free (&result_string
);
546 /* XXX do mapping here on error codes */
553 get_fqdn(krb5_context context
, const krb5_principal p
)
555 const char *s
, *hosttypes
[] = { "host", "ldap", "gc", "cifs", "dns" };
558 s
= krb5_principal_get_comp_string(context
, p
, 0);
562 for (i
= 0; i
< sizeof(hosttypes
)/sizeof(hosttypes
[0]); i
++) {
563 if (strcasecmp(s
, hosttypes
[i
]) == 0)
564 return krb5_principal_get_comp_string(context
, p
, 1);
572 kadm5_ad_create_principal(void *server_handle
,
573 kadm5_principal_ent_t entry
,
576 krb5_key_salt_tuple
*ks_tuple
,
577 const char *password
)
579 kadm5_ad_context
*context
= server_handle
;
582 * KADM5_PRINC_EXPIRE_TIME
584 * return 0 || KADM5_DUP;
588 LDAPMod
*attrs
[8], rattrs
[7], *a
;
589 char *useraccvals
[2] = { NULL
, NULL
},
590 *samvals
[2], *dnsvals
[2], *spnvals
[5], *upnvals
[2], *tv
[2];
591 char *ocvals_spn
[] = { "top", "person", "organizationalPerson",
592 "user", "computer", NULL
};
593 char *p
, *realmless_p
, *p_msrealm
= NULL
, *dn
= NULL
;
595 char *s
, *samname
= NULL
, *short_spn
= NULL
;
597 int32_t uf_flags
= 0;
599 if ((mask
& KADM5_PRINCIPAL
) == 0)
600 return KADM5_BAD_MASK
;
603 * We should get around to implementing this... At the moment, the
604 * the server side API is implemented but the wire protocol has not
608 return KADM5_KS_TUPLE_NOSUPP
;
610 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
611 attrs
[i
] = &rattrs
[i
];
614 ret
= ad_get_cred(context
, NULL
);
618 ret
= _kadm5_ad_connect(server_handle
);
622 fqdn
= get_fqdn(context
->context
, entry
->principal
);
624 ret
= krb5_unparse_name(context
->context
, entry
->principal
, &p
);
628 if (ad_find_entry(context
, fqdn
, p
, NULL
) == 0) {
633 if (mask
& KADM5_ATTRIBUTES
) {
634 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
635 uf_flags
|= UF_ACCOUNTDISABLE
|UF_LOCKOUT
;
636 if ((entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
) == 0)
637 uf_flags
|= UF_DONT_REQUIRE_PREAUTH
;
638 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
639 uf_flags
|= UF_SMARTCARD_REQUIRED
;
642 realmless_p
= strdup(p
);
643 if (realmless_p
== NULL
) {
647 s
= strrchr(realmless_p
, '@');
652 /* create computer account */
653 asprintf(&samname
, "%s$", fqdn
);
654 if (samname
== NULL
) {
658 s
= strchr(samname
, '.');
664 short_spn
= strdup(p
);
665 if (short_spn
== NULL
) {
669 s
= strchr(short_spn
, '.');
677 p_msrealm
= strdup(p
);
678 if (p_msrealm
== NULL
) {
682 s
= strrchr(p_msrealm
, '@');
690 asprintf(&dn
, "cn=%s, cn=Computers, %s", fqdn
, CTX2BASE(context
));
697 a
->mod_op
= LDAP_MOD_ADD
;
698 a
->mod_type
= "objectClass";
699 a
->mod_values
= ocvals_spn
;
702 a
->mod_op
= LDAP_MOD_ADD
;
703 a
->mod_type
= "userAccountControl";
704 a
->mod_values
= useraccvals
;
705 asprintf(&useraccvals
[0], "%d",
707 UF_PASSWD_NOT_EXPIRE
|
708 UF_WORKSTATION_TRUST_ACCOUNT
);
709 useraccvals
[1] = NULL
;
712 a
->mod_op
= LDAP_MOD_ADD
;
713 a
->mod_type
= "sAMAccountName";
714 a
->mod_values
= samvals
;
715 samvals
[0] = samname
;
719 a
->mod_op
= LDAP_MOD_ADD
;
720 a
->mod_type
= "dNSHostName";
721 a
->mod_values
= dnsvals
;
722 dnsvals
[0] = (char *)fqdn
;
726 /* XXX add even more spn's */
727 a
->mod_op
= LDAP_MOD_ADD
;
728 a
->mod_type
= "servicePrincipalName";
729 a
->mod_values
= spnvals
;
732 spnvals
[i
++] = realmless_p
;
734 spnvals
[i
++] = short_spn
;
736 spnvals
[i
++] = p_msrealm
;
740 a
->mod_op
= LDAP_MOD_ADD
;
741 a
->mod_type
= "userPrincipalName";
742 a
->mod_values
= upnvals
;
747 a
->mod_op
= LDAP_MOD_ADD
;
748 a
->mod_type
= "accountExpires";
750 tv
[0] = "9223372036854775807"; /* "never" */
755 /* create user account */
758 a
->mod_op
= LDAP_MOD_ADD
;
759 a
->mod_type
= "userAccountControl";
760 a
->mod_values
= useraccvals
;
761 asprintf(&useraccvals
[0], "%d",
763 UF_PASSWD_NOT_EXPIRE
);
764 useraccvals
[1] = NULL
;
767 a
->mod_op
= LDAP_MOD_ADD
;
768 a
->mod_type
= "sAMAccountName";
769 a
->mod_values
= samvals
;
770 samvals
[0] = realmless_p
;
774 a
->mod_op
= LDAP_MOD_ADD
;
775 a
->mod_type
= "userPrincipalName";
776 a
->mod_values
= upnvals
;
781 a
->mod_op
= LDAP_MOD_ADD
;
782 a
->mod_type
= "accountExpires";
784 tv
[0] = "9223372036854775807"; /* "never" */
789 attrs
[a
- &rattrs
[0]] = NULL
;
791 ret
= ldap_add_s(CTX2LP(context
), dn
, attrs
);
795 free(useraccvals
[0]);
806 if (check_ldap(context
, ret
))
807 return KADM5_RPC_ERROR
;
811 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
812 return KADM5_RPC_ERROR
;
817 kadm5_ad_delete_principal(void *server_handle
, krb5_principal principal
)
819 kadm5_ad_context
*context
= server_handle
;
825 ret
= ad_get_cred(context
, NULL
);
829 ret
= _kadm5_ad_connect(server_handle
);
833 fqdn
= get_fqdn(context
->context
, principal
);
835 ret
= krb5_unparse_name(context
->context
, principal
, &p
);
839 if (ad_find_entry(context
, fqdn
, p
, &dn
) != 0) {
841 return KADM5_UNK_PRINC
;
844 ret
= ldap_delete_s(CTX2LP(context
), dn
);
849 if (check_ldap(context
, ret
))
850 return KADM5_RPC_ERROR
;
853 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
854 return KADM5_RPC_ERROR
;
859 kadm5_ad_destroy(void *server_handle
)
861 kadm5_ad_context
*context
= server_handle
;
864 krb5_cc_destroy(context
->context
, context
->ccache
);
868 LDAP
*lp
= CTX2LP(context
);
871 if (context
->base_dn
)
872 free(context
->base_dn
);
875 free(context
->realm
);
876 free(context
->client_name
);
877 krb5_free_principal(context
->context
, context
->caller
);
878 if(context
->my_context
)
879 krb5_free_context(context
->context
);
884 kadm5_ad_flush(void *server_handle
)
886 kadm5_ad_context
*context
= server_handle
;
887 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
888 return KADM5_RPC_ERROR
;
892 kadm5_ad_get_principal(void *server_handle
,
893 krb5_principal principal
,
894 kadm5_principal_ent_t entry
,
897 kadm5_ad_context
*context
= server_handle
;
902 char *filter
, *p
, *q
, *u
;
907 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
911 * return 0 || KADM5_DUP;
914 memset(entry
, 0, sizeof(*entry
));
916 if (mask
& KADM5_KVNO
)
917 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
919 if (mask
& KADM5_PRINCIPAL
) {
920 laddattr(&attr
, &attrlen
, "userPrincipalName");
921 laddattr(&attr
, &attrlen
, "servicePrincipalName");
923 laddattr(&attr
, &attrlen
, "objectClass");
924 laddattr(&attr
, &attrlen
, "lastLogon");
925 laddattr(&attr
, &attrlen
, "badPwdCount");
926 laddattr(&attr
, &attrlen
, "badPasswordTime");
927 laddattr(&attr
, &attrlen
, "pwdLastSet");
928 laddattr(&attr
, &attrlen
, "accountExpires");
929 laddattr(&attr
, &attrlen
, "userAccountControl");
931 krb5_unparse_name_short(context
->context
, principal
, &p
);
932 krb5_unparse_name(context
->context
, principal
, &u
);
934 /* replace @ in domain part with a / */
936 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
940 "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
945 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
947 filter
, attr
, 0, &m
);
949 if (check_ldap(context
, ret
))
950 return KADM5_RPC_ERROR
;
952 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
954 m0
= ldap_first_entry(CTX2LP(context
), m
);
960 vals
= ldap_get_values(CTX2LP(context
), m0
, "servicePrincipalName");
962 printf("servicePrincipalName %s\n", vals
[0]);
963 vals
= ldap_get_values(CTX2LP(context
), m0
, "userPrincipalName");
965 printf("userPrincipalName %s\n", vals
[0]);
966 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
968 printf("userAccountControl %s\n", vals
[0]);
970 entry
->princ_expire_time
= 0;
971 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
972 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
974 entry
->princ_expire_time
= nt2unixtime(vals
[0]);
976 entry
->last_success
= 0;
977 if (mask
& KADM5_LAST_SUCCESS
) {
978 vals
= ldap_get_values(CTX2LP(context
), m0
, "lastLogon");
980 entry
->last_success
= nt2unixtime(vals
[0]);
982 if (mask
& KADM5_LAST_FAILED
) {
983 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPasswordTime");
985 entry
->last_failed
= nt2unixtime(vals
[0]);
987 if (mask
& KADM5_LAST_PWD_CHANGE
) {
988 vals
= ldap_get_values(CTX2LP(context
), m0
, "pwdLastSet");
990 entry
->last_pwd_change
= nt2unixtime(vals
[0]);
992 if (mask
& KADM5_FAIL_AUTH_COUNT
) {
993 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPwdCount");
995 entry
->fail_auth_count
= atoi(vals
[0]);
997 if (mask
& KADM5_ATTRIBUTES
) {
998 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
1002 if (i
& (UF_ACCOUNTDISABLE
|UF_LOCKOUT
))
1003 entry
->attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
1004 if ((i
& UF_DONT_REQUIRE_PREAUTH
) == 0)
1005 entry
->attributes
|= KRB5_KDB_REQUIRES_PRE_AUTH
;
1006 if (i
& UF_SMARTCARD_REQUIRED
)
1007 entry
->attributes
|= KRB5_KDB_REQUIRES_HW_AUTH
;
1008 if ((i
& UF_WORKSTATION_TRUST_ACCOUNT
) == 0)
1009 entry
->attributes
|= KRB5_KDB_DISALLOW_SVR
;
1012 if (mask
& KADM5_KVNO
) {
1013 vals
= ldap_get_values(CTX2LP(context
), m0
,
1014 "msDS-KeyVersionNumber");
1016 entry
->kvno
= atoi(vals
[0]);
1022 return KADM5_UNK_PRINC
;
1025 if (mask
& KADM5_PRINCIPAL
)
1026 krb5_copy_principal(context
->context
, principal
, &entry
->principal
);
1030 return KADM5_RPC_ERROR
;
1032 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1033 return KADM5_RPC_ERROR
;
1038 kadm5_ad_get_principals(void *server_handle
,
1039 const char *expression
,
1043 kadm5_ad_context
*context
= server_handle
;
1046 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1052 ret
= ad_get_cred(context
, NULL
);
1056 ret
= _kadm5_ad_connect(server_handle
);
1060 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1061 return KADM5_RPC_ERROR
;
1063 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1064 return KADM5_RPC_ERROR
;
1069 kadm5_ad_get_privs(void *server_handle
, uint32_t*privs
)
1071 kadm5_ad_context
*context
= server_handle
;
1072 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1073 return KADM5_RPC_ERROR
;
1077 kadm5_ad_modify_principal(void *server_handle
,
1078 kadm5_principal_ent_t entry
,
1081 kadm5_ad_context
*context
= server_handle
;
1085 * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1089 LDAPMessage
*m
= NULL
, *m0
;
1093 char *p
= NULL
, *s
= NULL
, *q
;
1095 LDAPMod
*attrs
[4], rattrs
[3], *a
;
1096 char *uaf
[2] = { NULL
, NULL
};
1097 char *kvno
[2] = { NULL
, NULL
};
1098 char *tv
[2] = { NULL
, NULL
};
1102 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
1103 attrs
[i
] = &rattrs
[i
];
1107 ret
= _kadm5_ad_connect(server_handle
);
1111 if (mask
& KADM5_KVNO
)
1112 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
1113 if (mask
& KADM5_PRINC_EXPIRE_TIME
)
1114 laddattr(&attr
, &attrlen
, "accountExpires");
1115 if (mask
& KADM5_ATTRIBUTES
)
1116 laddattr(&attr
, &attrlen
, "userAccountControl");
1117 laddattr(&attr
, &attrlen
, "distinguishedName");
1119 krb5_unparse_name(context
->context
, entry
->principal
, &p
);
1123 q
= strrchr(s
, '@');
1124 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
1128 "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1133 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
1135 filter
, attr
, 0, &m
);
1138 if (check_ldap(context
, ret
))
1139 return KADM5_RPC_ERROR
;
1141 if (ldap_count_entries(CTX2LP(context
), m
) <= 0) {
1142 ret
= KADM5_RPC_ERROR
;
1146 m0
= ldap_first_entry(CTX2LP(context
), m
);
1148 if (mask
& KADM5_ATTRIBUTES
) {
1151 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
1153 ret
= KADM5_RPC_ERROR
;
1159 return KADM5_RPC_ERROR
;
1161 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
1162 i
|= (UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1164 i
&= ~(UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1165 if (entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
)
1166 i
&= ~UF_DONT_REQUIRE_PREAUTH
;
1168 i
|= UF_DONT_REQUIRE_PREAUTH
;
1169 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
1170 i
|= UF_SMARTCARD_REQUIRED
;
1172 i
&= UF_SMARTCARD_REQUIRED
;
1173 if (entry
->attributes
& KRB5_KDB_DISALLOW_SVR
)
1174 i
&= ~UF_WORKSTATION_TRUST_ACCOUNT
;
1176 i
|= UF_WORKSTATION_TRUST_ACCOUNT
;
1178 asprintf(&uaf
[0], "%d", i
);
1180 a
->mod_op
= LDAP_MOD_REPLACE
;
1181 a
->mod_type
= "userAccountControl";
1182 a
->mod_values
= uaf
;
1186 if (mask
& KADM5_KVNO
) {
1187 vals
= ldap_get_values(CTX2LP(context
), m0
, "msDS-KeyVersionNumber");
1191 asprintf(&kvno
[0], "%d", entry
->kvno
);
1193 a
->mod_op
= LDAP_MOD_REPLACE
;
1194 a
->mod_type
= "msDS-KeyVersionNumber";
1195 a
->mod_values
= kvno
;
1200 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
1202 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
1204 ret
= KADM5_RPC_ERROR
;
1208 wt
= unix2nttime(entry
->princ_expire_time
);
1210 asprintf(&tv
[0], "%llu", wt
);
1212 a
->mod_op
= LDAP_MOD_REPLACE
;
1213 a
->mod_type
= "accountExpires";
1218 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
1220 ret
= KADM5_RPC_ERROR
;
1225 attrs
[a
- &rattrs
[0]] = NULL
;
1227 ret
= ldap_modify_s(CTX2LP(context
), dn
, attrs
);
1228 if (check_ldap(context
, ret
))
1229 return KADM5_RPC_ERROR
;
1242 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1243 return KADM5_RPC_ERROR
;
1249 kadm5_ad_randkey_principal(void *server_handle
,
1250 krb5_principal principal
,
1251 krb5_boolean keepold
,
1253 krb5_key_salt_tuple
*ks_tuple
,
1254 krb5_keyblock
**keys
,
1257 kadm5_ad_context
*context
= server_handle
;
1260 return KADM5_KEEPOLD_NOSUPP
;
1267 krb5_data result_code_string
, result_string
;
1268 int result_code
, plen
;
1277 krb5_generate_random_block(p
, sizeof(p
));
1278 plen
= base64_encode(p
, sizeof(p
), &password
);
1283 ret
= ad_get_cred(context
, NULL
);
1289 krb5_data_zero (&result_code_string
);
1290 krb5_data_zero (&result_string
);
1292 ret
= krb5_set_password_using_ccache (context
->context
,
1297 &result_code_string
,
1300 krb5_data_free (&result_code_string
);
1301 krb5_data_free (&result_string
);
1305 *keys
= malloc(sizeof(**keys
) * 1);
1306 if (*keys
== NULL
) {
1312 ret
= krb5_string_to_key(context
->context
,
1313 ENCTYPE_ARCFOUR_HMAC_MD5
,
1317 memset(password
, 0, sizeof(password
));
1325 memset(password
, 0, plen
);
1333 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1334 return KADM5_RPC_ERROR
;
1339 kadm5_ad_rename_principal(void *server_handle
,
1340 krb5_principal from
,
1343 kadm5_ad_context
*context
= server_handle
;
1344 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1345 return KADM5_RPC_ERROR
;
1349 kadm5_ad_chpass_principal_with_key(void *server_handle
,
1350 krb5_principal princ
,
1353 krb5_key_data
*key_data
)
1355 kadm5_ad_context
*context
= server_handle
;
1356 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1357 return KADM5_RPC_ERROR
;
1361 kadm5_ad_lock(void *server_handle
)
1367 kadm5_ad_unlock(void *server_handle
)
1373 set_funcs(kadm5_ad_context
*c
)
1375 #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1376 SET(c
, chpass_principal
);
1377 SET(c
, chpass_principal_with_key
);
1378 SET(c
, create_principal
);
1379 SET(c
, delete_principal
);
1382 SET(c
, get_principal
);
1383 SET(c
, get_principals
);
1385 SET(c
, modify_principal
);
1386 SET(c
, randkey_principal
);
1387 SET(c
, rename_principal
);
1393 kadm5_ad_init_with_password_ctx(krb5_context context
,
1394 const char *client_name
,
1395 const char *password
,
1396 const char *service_name
,
1397 kadm5_config_params
*realm_params
,
1398 unsigned long struct_version
,
1399 unsigned long api_version
,
1400 void **server_handle
)
1403 kadm5_ad_context
*ctx
;
1405 ctx
= malloc(sizeof(*ctx
));
1408 memset(ctx
, 0, sizeof(*ctx
));
1411 ctx
->context
= context
;
1412 krb5_add_et_list (context
, initialize_kadm5_error_table_r
);
1414 ret
= krb5_parse_name(ctx
->context
, client_name
, &ctx
->caller
);
1420 if(realm_params
->mask
& KADM5_CONFIG_REALM
) {
1422 ctx
->realm
= strdup(realm_params
->realm
);
1423 if (ctx
->realm
== NULL
)
1426 ret
= krb5_get_default_realm(ctx
->context
, &ctx
->realm
);
1432 ctx
->client_name
= strdup(client_name
);
1434 if(password
!= NULL
&& *password
!= '\0')
1435 ret
= ad_get_cred(ctx
, password
);
1437 ret
= ad_get_cred(ctx
, NULL
);
1439 kadm5_ad_destroy(ctx
);
1444 ret
= _kadm5_ad_connect(ctx
);
1446 kadm5_ad_destroy(ctx
);
1451 *server_handle
= ctx
;
1456 kadm5_ad_init_with_password(const char *client_name
,
1457 const char *password
,
1458 const char *service_name
,
1459 kadm5_config_params
*realm_params
,
1460 unsigned long struct_version
,
1461 unsigned long api_version
,
1462 void **server_handle
)
1464 krb5_context context
;
1466 kadm5_ad_context
*ctx
;
1468 ret
= krb5_init_context(&context
);
1471 ret
= kadm5_ad_init_with_password_ctx(context
,
1480 krb5_free_context(context
);
1483 ctx
= *server_handle
;
1484 ctx
->my_context
= 1;