1 /* $NetBSD: ad.c,v 1.3 2014/04/24 13:45:34 pettai Exp $ */
4 * Copyright (c) 2004 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include "kadm5_locl.h"
48 #include <krb5/resolve.h>
49 #include <krb5/base64.h>
56 #define CTX2LP(context) ((LDAP *)((context)->ldap_conn))
57 #define CTX2BASE(context) ((context)->base_dn)
63 #define UF_SCRIPT 0x00000001
64 #define UF_ACCOUNTDISABLE 0x00000002
65 #define UF_UNUSED_0 0x00000004
66 #define UF_HOMEDIR_REQUIRED 0x00000008
67 #define UF_LOCKOUT 0x00000010
68 #define UF_PASSWD_NOTREQD 0x00000020
69 #define UF_PASSWD_CANT_CHANGE 0x00000040
70 #define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
71 #define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100
72 #define UF_NORMAL_ACCOUNT 0x00000200
73 #define UF_UNUSED_1 0x00000400
74 #define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
75 #define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
76 #define UF_SERVER_TRUST_ACCOUNT 0x00002000
77 #define UF_UNUSED_2 0x00004000
78 #define UF_UNUSED_3 0x00008000
79 #define UF_PASSWD_NOT_EXPIRE 0x00010000
80 #define UF_MNS_LOGON_ACCOUNT 0x00020000
81 #define UF_SMARTCARD_REQUIRED 0x00040000
82 #define UF_TRUSTED_FOR_DELEGATION 0x00080000
83 #define UF_NOT_DELEGATED 0x00100000
84 #define UF_USE_DES_KEY_ONLY 0x00200000
85 #define UF_DONT_REQUIRE_PREAUTH 0x00400000
86 #define UF_UNUSED_4 0x00800000
87 #define UF_UNUSED_5 0x01000000
88 #define UF_UNUSED_6 0x02000000
89 #define UF_UNUSED_7 0x04000000
90 #define UF_UNUSED_8 0x08000000
91 #define UF_UNUSED_9 0x10000000
92 #define UF_UNUSED_10 0x20000000
93 #define UF_UNUSED_11 0x40000000
94 #define UF_UNUSED_12 0x80000000
102 sasl_interact(LDAP
*ld
, unsigned flags
, void *defaults
, void *interact
)
109 static Sockbuf_IO ldap_tsasl_io
= {
110 NULL
, /* sbi_setup */
111 NULL
, /* sbi_remove */
114 NULL
, /* sbi_write */
121 ldap_tsasl_bind_s(LDAP
*ld
,
123 LDAPControl
**serverControls
,
124 LDAPControl
**clientControls
,
127 char *attrs
[] = { "supportedSASLMechanisms", NULL
};
128 struct tsasl_peer
*peer
= NULL
;
129 struct tsasl_buffer in
, out
;
130 struct berval ccred
, *scred
;
136 ret
= tsasl_peer_init(TSASL_FLAGS_INITIATOR
| TSASL_FLAGS_CLEAR
,
137 "ldap", host
, &peer
);
138 if (ret
!= TSASL_DONE
) {
139 rc
= LDAP_LOCAL_ERROR
;
143 rc
= ldap_search_s(ld
, "", LDAP_SCOPE_BASE
, NULL
, attrs
, 0, &m0
);
144 if (rc
!= LDAP_SUCCESS
)
147 m
= ldap_first_entry(ld
, m0
);
153 vals
= ldap_get_values(ld
, m
, "supportedSASLMechanisms");
159 ret
= tsasl_find_best_mech(peer
, vals
, &mech
);
167 ret
= tsasl_select_mech(peer
, mech
);
168 if (ret
!= TSASL_DONE
) {
169 rc
= LDAP_LOCAL_ERROR
;
177 ret
= tsasl_request(peer
, &in
, &out
);
178 if (in
.tb_size
!= 0) {
183 if (ret
!= TSASL_DONE
&& ret
!= TSASL_CONTINUE
) {
184 rc
= LDAP_AUTH_UNKNOWN
;
188 ccred
.bv_val
= out
.tb_data
;
189 ccred
.bv_len
= out
.tb_size
;
191 rc
= ldap_sasl_bind_s(ld
, dn
, mech
, &ccred
,
192 serverControls
, clientControls
, &scred
);
193 tsasl_buffer_free(&out
);
195 if (rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
196 if(scred
&& scred
->bv_len
)
201 in
.tb_data
= malloc(scred
->bv_len
);
202 if (in
.tb_data
== NULL
) {
203 rc
= LDAP_LOCAL_ERROR
;
206 memcpy(in
.tb_data
, scred
->bv_val
, scred
->bv_len
);
207 in
.tb_size
= scred
->bv_len
;
210 } while (rc
== LDAP_SASL_BIND_IN_PROGRESS
);
213 if (rc
== LDAP_SUCCESS
) {
215 ber_sockbuf_add_io(ld
->ld_conns
->lconn_sb
, &ldap_tsasl_io
,
216 LBER_SBIOD_LEVEL_APPLICATION
, peer
);
219 } else if (peer
!= NULL
)
220 tsasl_peer_free(peer
);
224 #endif /* HAVE_TSASL */
228 check_ldap(kadm5_ad_context
*context
, int ret
)
233 case LDAP_SERVER_DOWN
: {
234 LDAP
*lp
= CTX2LP(context
);
236 context
->ldap_conn
= NULL
;
237 free(context
->base_dn
);
238 context
->base_dn
= NULL
;
251 laddattr(char ***al
, int *attrlen
, char *attr
)
254 a
= realloc(*al
, (*attrlen
+ 2) * sizeof(**al
));
258 a
[*attrlen
+ 1] = NULL
;
264 _kadm5_ad_connect(void *server_handle
)
266 kadm5_ad_context
*context
= server_handle
;
270 } *s
, *servers
= NULL
;
271 int i
, num_servers
= 0;
273 if (context
->ldap_conn
)
278 struct resource_record
*rr
;
281 asprintf(&domain
, "_ldap._tcp.%s", context
->realm
);
282 if (domain
== NULL
) {
283 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "malloc");
287 r
= dns_lookup(domain
, "SRV");
290 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "Didn't find ldap dns");
294 for (rr
= r
->head
; rr
!= NULL
; rr
= rr
->next
) {
295 if (rr
->type
!= rk_ns_t_srv
)
297 s
= realloc(servers
, sizeof(*servers
) * (num_servers
+ 1));
299 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "malloc");
305 servers
[num_servers
- 1].port
= rr
->u
.srv
->port
;
306 servers
[num_servers
- 1].server
= strdup(rr
->u
.srv
->target
);
311 if (num_servers
== 0) {
312 krb5_set_error_message(context
->context
, KADM5_NO_SRV
, "No AD server found in DNS");
316 for (i
= 0; i
< num_servers
; i
++) {
317 int lret
, version
= LDAP_VERSION3
;
320 lp
= ldap_init(servers
[i
].server
, servers
[i
].port
);
324 if (ldap_set_option(lp
, LDAP_OPT_PROTOCOL_VERSION
, &version
)) {
329 if (ldap_set_option(lp
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
)) {
335 lret
= ldap_tsasl_bind_s(lp
, NULL
, NULL
, NULL
, servers
[i
].server
);
338 lret
= ldap_sasl_interactive_bind_s(lp
, NULL
, NULL
, NULL
, NULL
,
340 sasl_interact
, NULL
);
342 if (lret
!= LDAP_SUCCESS
) {
343 krb5_set_error_message(context
->context
, 0,
344 "Couldn't contact any AD servers: %s",
345 ldap_err2string(lret
));
350 context
->ldap_conn
= lp
;
353 if (i
>= num_servers
) {
364 laddattr(&attr
, &attrlen
, "defaultNamingContext");
366 ret
= ldap_search_s(CTX2LP(context
), "", LDAP_SCOPE_BASE
,
367 "objectclass=*", attr
, 0, &m
);
369 if (check_ldap(context
, ret
))
372 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
373 m0
= ldap_first_entry(CTX2LP(context
), m
);
375 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
,
376 "Error in AD ldap responce");
380 vals
= ldap_get_values(CTX2LP(context
),
381 m0
, "defaultNamingContext");
383 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
,
384 "No naming context found");
387 context
->base_dn
= strdup(vals
[0]);
393 for (i
= 0; i
< num_servers
; i
++)
394 free(servers
[i
].server
);
400 for (i
= 0; i
< num_servers
; i
++)
401 free(servers
[i
].server
);
404 if (context
->ldap_conn
) {
405 ldap_unbind(CTX2LP(context
));
406 context
->ldap_conn
= NULL
;
408 return KADM5_RPC_ERROR
;
411 #define NTTIME_EPOCH 0x019DB1DED53E8000LL
414 nt2unixtime(const char *str
)
416 unsigned long long t
;
417 t
= strtoll(str
, NULL
, 10);
418 t
= ((t
- NTTIME_EPOCH
) / (long long)10000000);
419 if (t
> (((time_t)(~(long long)0)) >> 1))
425 unix2nttime(time_t unix_time
)
428 wt
= unix_time
* (long long)10000000 + (long long)NTTIME_EPOCH
;
432 /* XXX create filter in a better way */
435 ad_find_entry(kadm5_ad_context
*context
,
441 char *attr
[] = { "distinguishedName", NULL
};
450 "(&(objectClass=computer)(|(dNSHostName=%s)(servicePrincipalName=%s)))",
453 asprintf(&filter
, "(&(objectClass=account)(userPrincipalName=%s))", pn
);
455 return KADM5_RPC_ERROR
;
457 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
459 filter
, attr
, 0, &m
);
461 if (check_ldap(context
, ret
))
462 return KADM5_RPC_ERROR
;
464 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
466 m0
= ldap_first_entry(CTX2LP(context
), m
);
467 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
468 if (vals
== NULL
|| vals
[0] == NULL
) {
470 return KADM5_RPC_ERROR
;
473 *name
= strdup(vals
[0]);
476 return KADM5_UNK_PRINC
;
481 #endif /* OPENLDAP */
484 ad_get_cred(kadm5_ad_context
*context
, const char *password
)
493 asprintf(&service
, "%s/%s@%s", KRB5_TGS_NAME
,
494 context
->realm
, context
->realm
);
498 ret
= _kadm5_c_get_cred_cache(context
->context
,
499 context
->client_name
,
501 password
, krb5_prompter_posix
,
505 return ret
; /* XXX */
506 context
->ccache
= cc
;
511 kadm5_ad_chpass_principal(void *server_handle
,
512 krb5_principal principal
,
513 const char *password
)
515 kadm5_ad_context
*context
= server_handle
;
516 krb5_data result_code_string
, result_string
;
520 ret
= ad_get_cred(context
, NULL
);
524 krb5_data_zero (&result_code_string
);
525 krb5_data_zero (&result_string
);
527 ret
= krb5_set_password_using_ccache (context
->context
,
535 krb5_data_free (&result_code_string
);
536 krb5_data_free (&result_string
);
538 /* XXX do mapping here on error codes */
545 get_fqdn(krb5_context context
, const krb5_principal p
)
547 const char *s
, *hosttypes
[] = { "host", "ldap", "gc", "cifs", "dns" };
550 s
= krb5_principal_get_comp_string(context
, p
, 0);
554 for (i
= 0; i
< sizeof(hosttypes
)/sizeof(hosttypes
[0]); i
++) {
555 if (strcasecmp(s
, hosttypes
[i
]) == 0)
556 return krb5_principal_get_comp_string(context
, p
, 1);
564 kadm5_ad_create_principal(void *server_handle
,
565 kadm5_principal_ent_t entry
,
567 const char *password
)
569 kadm5_ad_context
*context
= server_handle
;
572 * KADM5_PRINC_EXPIRE_TIME
574 * return 0 || KADM5_DUP;
578 LDAPMod
*attrs
[8], rattrs
[7], *a
;
579 char *useraccvals
[2] = { NULL
, NULL
},
580 *samvals
[2], *dnsvals
[2], *spnvals
[5], *upnvals
[2], *tv
[2];
581 char *ocvals_spn
[] = { "top", "person", "organizationalPerson",
582 "user", "computer", NULL
};
583 char *p
, *realmless_p
, *p_msrealm
= NULL
, *dn
= NULL
;
585 char *s
, *samname
= NULL
, *short_spn
= NULL
;
587 int32_t uf_flags
= 0;
589 if ((mask
& KADM5_PRINCIPAL
) == 0)
590 return KADM5_BAD_MASK
;
592 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
593 attrs
[i
] = &rattrs
[i
];
596 ret
= ad_get_cred(context
, NULL
);
600 ret
= _kadm5_ad_connect(server_handle
);
604 fqdn
= get_fqdn(context
->context
, entry
->principal
);
606 ret
= krb5_unparse_name(context
->context
, entry
->principal
, &p
);
610 if (ad_find_entry(context
, fqdn
, p
, NULL
) == 0) {
615 if (mask
& KADM5_ATTRIBUTES
) {
616 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
617 uf_flags
|= UF_ACCOUNTDISABLE
|UF_LOCKOUT
;
618 if ((entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
) == 0)
619 uf_flags
|= UF_DONT_REQUIRE_PREAUTH
;
620 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
621 uf_flags
|= UF_SMARTCARD_REQUIRED
;
624 realmless_p
= strdup(p
);
625 if (realmless_p
== NULL
) {
629 s
= strrchr(realmless_p
, '@');
634 /* create computer account */
635 asprintf(&samname
, "%s$", fqdn
);
636 if (samname
== NULL
) {
640 s
= strchr(samname
, '.');
646 short_spn
= strdup(p
);
647 if (short_spn
== NULL
) {
651 s
= strchr(short_spn
, '.');
659 p_msrealm
= strdup(p
);
660 if (p_msrealm
== NULL
) {
664 s
= strrchr(p_msrealm
, '@');
672 asprintf(&dn
, "cn=%s, cn=Computers, %s", fqdn
, CTX2BASE(context
));
679 a
->mod_op
= LDAP_MOD_ADD
;
680 a
->mod_type
= "objectClass";
681 a
->mod_values
= ocvals_spn
;
684 a
->mod_op
= LDAP_MOD_ADD
;
685 a
->mod_type
= "userAccountControl";
686 a
->mod_values
= useraccvals
;
687 asprintf(&useraccvals
[0], "%d",
689 UF_PASSWD_NOT_EXPIRE
|
690 UF_WORKSTATION_TRUST_ACCOUNT
);
691 useraccvals
[1] = NULL
;
694 a
->mod_op
= LDAP_MOD_ADD
;
695 a
->mod_type
= "sAMAccountName";
696 a
->mod_values
= samvals
;
697 samvals
[0] = samname
;
701 a
->mod_op
= LDAP_MOD_ADD
;
702 a
->mod_type
= "dNSHostName";
703 a
->mod_values
= dnsvals
;
704 dnsvals
[0] = (char *)fqdn
;
708 /* XXX add even more spn's */
709 a
->mod_op
= LDAP_MOD_ADD
;
710 a
->mod_type
= "servicePrincipalName";
711 a
->mod_values
= spnvals
;
714 spnvals
[i
++] = realmless_p
;
716 spnvals
[i
++] = short_spn
;
718 spnvals
[i
++] = p_msrealm
;
722 a
->mod_op
= LDAP_MOD_ADD
;
723 a
->mod_type
= "userPrincipalName";
724 a
->mod_values
= upnvals
;
729 a
->mod_op
= LDAP_MOD_ADD
;
730 a
->mod_type
= "accountExpires";
732 tv
[0] = "9223372036854775807"; /* "never" */
737 /* create user account */
740 a
->mod_op
= LDAP_MOD_ADD
;
741 a
->mod_type
= "userAccountControl";
742 a
->mod_values
= useraccvals
;
743 asprintf(&useraccvals
[0], "%d",
745 UF_PASSWD_NOT_EXPIRE
);
746 useraccvals
[1] = NULL
;
749 a
->mod_op
= LDAP_MOD_ADD
;
750 a
->mod_type
= "sAMAccountName";
751 a
->mod_values
= samvals
;
752 samvals
[0] = realmless_p
;
756 a
->mod_op
= LDAP_MOD_ADD
;
757 a
->mod_type
= "userPrincipalName";
758 a
->mod_values
= upnvals
;
763 a
->mod_op
= LDAP_MOD_ADD
;
764 a
->mod_type
= "accountExpires";
766 tv
[0] = "9223372036854775807"; /* "never" */
771 attrs
[a
- &rattrs
[0]] = NULL
;
773 ret
= ldap_add_s(CTX2LP(context
), dn
, attrs
);
777 free(useraccvals
[0]);
788 if (check_ldap(context
, ret
))
789 return KADM5_RPC_ERROR
;
793 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
794 return KADM5_RPC_ERROR
;
799 kadm5_ad_delete_principal(void *server_handle
, krb5_principal principal
)
801 kadm5_ad_context
*context
= server_handle
;
807 ret
= ad_get_cred(context
, NULL
);
811 ret
= _kadm5_ad_connect(server_handle
);
815 fqdn
= get_fqdn(context
->context
, principal
);
817 ret
= krb5_unparse_name(context
->context
, principal
, &p
);
821 if (ad_find_entry(context
, fqdn
, p
, &dn
) != 0) {
823 return KADM5_UNK_PRINC
;
826 ret
= ldap_delete_s(CTX2LP(context
), dn
);
831 if (check_ldap(context
, ret
))
832 return KADM5_RPC_ERROR
;
835 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
836 return KADM5_RPC_ERROR
;
841 kadm5_ad_destroy(void *server_handle
)
843 kadm5_ad_context
*context
= server_handle
;
846 krb5_cc_destroy(context
->context
, context
->ccache
);
850 LDAP
*lp
= CTX2LP(context
);
853 if (context
->base_dn
)
854 free(context
->base_dn
);
857 free(context
->realm
);
858 free(context
->client_name
);
859 krb5_free_principal(context
->context
, context
->caller
);
860 if(context
->my_context
)
861 krb5_free_context(context
->context
);
866 kadm5_ad_flush(void *server_handle
)
868 kadm5_ad_context
*context
= server_handle
;
869 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
870 return KADM5_RPC_ERROR
;
874 kadm5_ad_get_principal(void *server_handle
,
875 krb5_principal principal
,
876 kadm5_principal_ent_t entry
,
879 kadm5_ad_context
*context
= server_handle
;
884 char *filter
, *p
, *q
, *u
;
889 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
893 * return 0 || KADM5_DUP;
896 memset(entry
, 0, sizeof(*entry
));
898 if (mask
& KADM5_KVNO
)
899 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
901 if (mask
& KADM5_PRINCIPAL
) {
902 laddattr(&attr
, &attrlen
, "userPrincipalName");
903 laddattr(&attr
, &attrlen
, "servicePrincipalName");
905 laddattr(&attr
, &attrlen
, "objectClass");
906 laddattr(&attr
, &attrlen
, "lastLogon");
907 laddattr(&attr
, &attrlen
, "badPwdCount");
908 laddattr(&attr
, &attrlen
, "badPasswordTime");
909 laddattr(&attr
, &attrlen
, "pwdLastSet");
910 laddattr(&attr
, &attrlen
, "accountExpires");
911 laddattr(&attr
, &attrlen
, "userAccountControl");
913 krb5_unparse_name_short(context
->context
, principal
, &p
);
914 krb5_unparse_name(context
->context
, principal
, &u
);
916 /* replace @ in domain part with a / */
918 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
922 "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
927 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
929 filter
, attr
, 0, &m
);
931 if (check_ldap(context
, ret
))
932 return KADM5_RPC_ERROR
;
934 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
936 m0
= ldap_first_entry(CTX2LP(context
), m
);
942 vals
= ldap_get_values(CTX2LP(context
), m0
, "servicePrincipalName");
944 printf("servicePrincipalName %s\n", vals
[0]);
945 vals
= ldap_get_values(CTX2LP(context
), m0
, "userPrincipalName");
947 printf("userPrincipalName %s\n", vals
[0]);
948 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
950 printf("userAccountControl %s\n", vals
[0]);
952 entry
->princ_expire_time
= 0;
953 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
954 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
956 entry
->princ_expire_time
= nt2unixtime(vals
[0]);
958 entry
->last_success
= 0;
959 if (mask
& KADM5_LAST_SUCCESS
) {
960 vals
= ldap_get_values(CTX2LP(context
), m0
, "lastLogon");
962 entry
->last_success
= nt2unixtime(vals
[0]);
964 if (mask
& KADM5_LAST_FAILED
) {
965 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPasswordTime");
967 entry
->last_failed
= nt2unixtime(vals
[0]);
969 if (mask
& KADM5_LAST_PWD_CHANGE
) {
970 vals
= ldap_get_values(CTX2LP(context
), m0
, "pwdLastSet");
972 entry
->last_pwd_change
= nt2unixtime(vals
[0]);
974 if (mask
& KADM5_FAIL_AUTH_COUNT
) {
975 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPwdCount");
977 entry
->fail_auth_count
= atoi(vals
[0]);
979 if (mask
& KADM5_ATTRIBUTES
) {
980 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
984 if (i
& (UF_ACCOUNTDISABLE
|UF_LOCKOUT
))
985 entry
->attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
986 if ((i
& UF_DONT_REQUIRE_PREAUTH
) == 0)
987 entry
->attributes
|= KRB5_KDB_REQUIRES_PRE_AUTH
;
988 if (i
& UF_SMARTCARD_REQUIRED
)
989 entry
->attributes
|= KRB5_KDB_REQUIRES_HW_AUTH
;
990 if ((i
& UF_WORKSTATION_TRUST_ACCOUNT
) == 0)
991 entry
->attributes
|= KRB5_KDB_DISALLOW_SVR
;
994 if (mask
& KADM5_KVNO
) {
995 vals
= ldap_get_values(CTX2LP(context
), m0
,
996 "msDS-KeyVersionNumber");
998 entry
->kvno
= atoi(vals
[0]);
1004 return KADM5_UNK_PRINC
;
1007 if (mask
& KADM5_PRINCIPAL
)
1008 krb5_copy_principal(context
->context
, principal
, &entry
->principal
);
1012 return KADM5_RPC_ERROR
;
1014 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1015 return KADM5_RPC_ERROR
;
1020 kadm5_ad_get_principals(void *server_handle
,
1021 const char *expression
,
1025 kadm5_ad_context
*context
= server_handle
;
1028 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1034 ret
= ad_get_cred(context
, NULL
);
1038 ret
= _kadm5_ad_connect(server_handle
);
1042 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1043 return KADM5_RPC_ERROR
;
1045 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1046 return KADM5_RPC_ERROR
;
1051 kadm5_ad_get_privs(void *server_handle
, uint32_t*privs
)
1053 kadm5_ad_context
*context
= server_handle
;
1054 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1055 return KADM5_RPC_ERROR
;
1059 kadm5_ad_modify_principal(void *server_handle
,
1060 kadm5_principal_ent_t entry
,
1063 kadm5_ad_context
*context
= server_handle
;
1067 * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1071 LDAPMessage
*m
= NULL
, *m0
;
1075 char *p
= NULL
, *s
= NULL
, *q
;
1077 LDAPMod
*attrs
[4], rattrs
[3], *a
;
1078 char *uaf
[2] = { NULL
, NULL
};
1079 char *kvno
[2] = { NULL
, NULL
};
1080 char *tv
[2] = { NULL
, NULL
};
1084 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
1085 attrs
[i
] = &rattrs
[i
];
1089 ret
= _kadm5_ad_connect(server_handle
);
1093 if (mask
& KADM5_KVNO
)
1094 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
1095 if (mask
& KADM5_PRINC_EXPIRE_TIME
)
1096 laddattr(&attr
, &attrlen
, "accountExpires");
1097 if (mask
& KADM5_ATTRIBUTES
)
1098 laddattr(&attr
, &attrlen
, "userAccountControl");
1099 laddattr(&attr
, &attrlen
, "distinguishedName");
1101 krb5_unparse_name(context
->context
, entry
->principal
, &p
);
1105 q
= strrchr(s
, '@');
1106 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
1110 "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1115 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
1117 filter
, attr
, 0, &m
);
1120 if (check_ldap(context
, ret
))
1121 return KADM5_RPC_ERROR
;
1123 if (ldap_count_entries(CTX2LP(context
), m
) <= 0) {
1124 ret
= KADM5_RPC_ERROR
;
1128 m0
= ldap_first_entry(CTX2LP(context
), m
);
1130 if (mask
& KADM5_ATTRIBUTES
) {
1133 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
1135 ret
= KADM5_RPC_ERROR
;
1141 return KADM5_RPC_ERROR
;
1143 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
1144 i
|= (UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1146 i
&= ~(UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1147 if (entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
)
1148 i
&= ~UF_DONT_REQUIRE_PREAUTH
;
1150 i
|= UF_DONT_REQUIRE_PREAUTH
;
1151 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
1152 i
|= UF_SMARTCARD_REQUIRED
;
1154 i
&= UF_SMARTCARD_REQUIRED
;
1155 if (entry
->attributes
& KRB5_KDB_DISALLOW_SVR
)
1156 i
&= ~UF_WORKSTATION_TRUST_ACCOUNT
;
1158 i
|= UF_WORKSTATION_TRUST_ACCOUNT
;
1160 asprintf(&uaf
[0], "%d", i
);
1162 a
->mod_op
= LDAP_MOD_REPLACE
;
1163 a
->mod_type
= "userAccountControl";
1164 a
->mod_values
= uaf
;
1168 if (mask
& KADM5_KVNO
) {
1169 vals
= ldap_get_values(CTX2LP(context
), m0
, "msDS-KeyVersionNumber");
1173 asprintf(&kvno
[0], "%d", entry
->kvno
);
1175 a
->mod_op
= LDAP_MOD_REPLACE
;
1176 a
->mod_type
= "msDS-KeyVersionNumber";
1177 a
->mod_values
= kvno
;
1182 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
1184 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
1186 ret
= KADM5_RPC_ERROR
;
1190 wt
= unix2nttime(entry
->princ_expire_time
);
1192 asprintf(&tv
[0], "%llu", wt
);
1194 a
->mod_op
= LDAP_MOD_REPLACE
;
1195 a
->mod_type
= "accountExpires";
1200 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
1202 ret
= KADM5_RPC_ERROR
;
1207 attrs
[a
- &rattrs
[0]] = NULL
;
1209 ret
= ldap_modify_s(CTX2LP(context
), dn
, attrs
);
1210 if (check_ldap(context
, ret
))
1211 return KADM5_RPC_ERROR
;
1224 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1225 return KADM5_RPC_ERROR
;
1230 kadm5_ad_randkey_principal(void *server_handle
,
1231 krb5_principal principal
,
1232 krb5_keyblock
**keys
,
1235 kadm5_ad_context
*context
= server_handle
;
1242 krb5_data result_code_string
, result_string
;
1243 int result_code
, plen
;
1252 krb5_generate_random_block(p
, sizeof(p
));
1253 plen
= base64_encode(p
, sizeof(p
), &password
);
1258 ret
= ad_get_cred(context
, NULL
);
1264 krb5_data_zero (&result_code_string
);
1265 krb5_data_zero (&result_string
);
1267 ret
= krb5_set_password_using_ccache (context
->context
,
1272 &result_code_string
,
1275 krb5_data_free (&result_code_string
);
1276 krb5_data_free (&result_string
);
1280 *keys
= malloc(sizeof(**keys
) * 1);
1281 if (*keys
== NULL
) {
1287 ret
= krb5_string_to_key(context
->context
,
1288 ENCTYPE_ARCFOUR_HMAC_MD5
,
1292 memset(password
, 0, plen
);
1300 memset(password
, 0, plen
);
1308 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1309 return KADM5_RPC_ERROR
;
1314 kadm5_ad_rename_principal(void *server_handle
,
1315 krb5_principal from
,
1318 kadm5_ad_context
*context
= server_handle
;
1319 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1320 return KADM5_RPC_ERROR
;
1324 kadm5_ad_chpass_principal_with_key(void *server_handle
,
1325 krb5_principal princ
,
1327 krb5_key_data
*key_data
)
1329 kadm5_ad_context
*context
= server_handle
;
1330 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1331 return KADM5_RPC_ERROR
;
1335 set_funcs(kadm5_ad_context
*c
)
1337 #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1338 SET(c
, chpass_principal
);
1339 SET(c
, chpass_principal_with_key
);
1340 SET(c
, create_principal
);
1341 SET(c
, delete_principal
);
1344 SET(c
, get_principal
);
1345 SET(c
, get_principals
);
1347 SET(c
, modify_principal
);
1348 SET(c
, randkey_principal
);
1349 SET(c
, rename_principal
);
1353 kadm5_ad_init_with_password_ctx(krb5_context context
,
1354 const char *client_name
,
1355 const char *password
,
1356 const char *service_name
,
1357 kadm5_config_params
*realm_params
,
1358 unsigned long struct_version
,
1359 unsigned long api_version
,
1360 void **server_handle
)
1363 kadm5_ad_context
*ctx
;
1365 ctx
= malloc(sizeof(*ctx
));
1368 memset(ctx
, 0, sizeof(*ctx
));
1371 ctx
->context
= context
;
1372 krb5_add_et_list (context
, initialize_kadm5_error_table_r
);
1374 ret
= krb5_parse_name(ctx
->context
, client_name
, &ctx
->caller
);
1380 if(realm_params
->mask
& KADM5_CONFIG_REALM
) {
1382 ctx
->realm
= strdup(realm_params
->realm
);
1383 if (ctx
->realm
== NULL
)
1386 ret
= krb5_get_default_realm(ctx
->context
, &ctx
->realm
);
1392 ctx
->client_name
= strdup(client_name
);
1394 if(password
!= NULL
&& *password
!= '\0')
1395 ret
= ad_get_cred(ctx
, password
);
1397 ret
= ad_get_cred(ctx
, NULL
);
1399 kadm5_ad_destroy(ctx
);
1404 ret
= _kadm5_ad_connect(ctx
);
1406 kadm5_ad_destroy(ctx
);
1411 *server_handle
= ctx
;
1416 kadm5_ad_init_with_password(const char *client_name
,
1417 const char *password
,
1418 const char *service_name
,
1419 kadm5_config_params
*realm_params
,
1420 unsigned long struct_version
,
1421 unsigned long api_version
,
1422 void **server_handle
)
1424 krb5_context context
;
1426 kadm5_ad_context
*ctx
;
1428 ret
= krb5_init_context(&context
);
1431 ret
= kadm5_ad_init_with_password_ctx(context
,
1440 krb5_free_context(context
);
1443 ctx
= *server_handle
;
1444 ctx
->my_context
= 1;