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
)
491 asprintf(&service
, "%s/%s@%s", KRB5_TGS_NAME
,
492 context
->realm
, context
->realm
);
496 ret
= _kadm5_c_get_cred_cache(context
->context
,
497 context
->client_name
,
499 password
, krb5_prompter_posix
,
503 return ret
; /* XXX */
504 context
->ccache
= cc
;
509 kadm5_ad_chpass_principal(void *server_handle
,
510 krb5_principal principal
,
511 const char *password
)
513 kadm5_ad_context
*context
= server_handle
;
514 krb5_data result_code_string
, result_string
;
518 ret
= ad_get_cred(context
, NULL
);
522 krb5_data_zero (&result_code_string
);
523 krb5_data_zero (&result_string
);
525 ret
= krb5_set_password_using_ccache (context
->context
,
533 krb5_data_free (&result_code_string
);
534 krb5_data_free (&result_string
);
536 /* XXX do mapping here on error codes */
543 get_fqdn(krb5_context context
, const krb5_principal p
)
545 const char *s
, *hosttypes
[] = { "host", "ldap", "gc", "cifs", "dns" };
548 s
= krb5_principal_get_comp_string(context
, p
, 0);
552 for (i
= 0; i
< sizeof(hosttypes
)/sizeof(hosttypes
[0]); i
++) {
553 if (strcasecmp(s
, hosttypes
[i
]) == 0)
554 return krb5_principal_get_comp_string(context
, p
, 1);
562 kadm5_ad_create_principal(void *server_handle
,
563 kadm5_principal_ent_t entry
,
565 const char *password
)
567 kadm5_ad_context
*context
= server_handle
;
570 * KADM5_PRINC_EXPIRE_TIME
572 * return 0 || KADM5_DUP;
576 LDAPMod
*attrs
[8], rattrs
[7], *a
;
577 char *useraccvals
[2] = { NULL
, NULL
},
578 *samvals
[2], *dnsvals
[2], *spnvals
[5], *upnvals
[2], *tv
[2];
579 char *ocvals_spn
[] = { "top", "person", "organizationalPerson",
580 "user", "computer", NULL
};
581 char *p
, *realmless_p
, *p_msrealm
= NULL
, *dn
= NULL
;
583 char *s
, *samname
= NULL
, *short_spn
= NULL
;
585 int32_t uf_flags
= 0;
587 if ((mask
& KADM5_PRINCIPAL
) == 0)
588 return KADM5_BAD_MASK
;
590 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
591 attrs
[i
] = &rattrs
[i
];
594 ret
= ad_get_cred(context
, NULL
);
598 ret
= _kadm5_ad_connect(server_handle
);
602 fqdn
= get_fqdn(context
->context
, entry
->principal
);
604 ret
= krb5_unparse_name(context
->context
, entry
->principal
, &p
);
608 if (ad_find_entry(context
, fqdn
, p
, NULL
) == 0) {
613 if (mask
& KADM5_ATTRIBUTES
) {
614 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
615 uf_flags
|= UF_ACCOUNTDISABLE
|UF_LOCKOUT
;
616 if ((entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
) == 0)
617 uf_flags
|= UF_DONT_REQUIRE_PREAUTH
;
618 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
619 uf_flags
|= UF_SMARTCARD_REQUIRED
;
622 realmless_p
= strdup(p
);
623 if (realmless_p
== NULL
) {
627 s
= strrchr(realmless_p
, '@');
632 /* create computer account */
633 asprintf(&samname
, "%s$", fqdn
);
634 if (samname
== NULL
) {
638 s
= strchr(samname
, '.');
644 short_spn
= strdup(p
);
645 if (short_spn
== NULL
) {
649 s
= strchr(short_spn
, '.');
657 p_msrealm
= strdup(p
);
658 if (p_msrealm
== NULL
) {
662 s
= strrchr(p_msrealm
, '@');
670 asprintf(&dn
, "cn=%s, cn=Computers, %s", fqdn
, CTX2BASE(context
));
677 a
->mod_op
= LDAP_MOD_ADD
;
678 a
->mod_type
= "objectClass";
679 a
->mod_values
= ocvals_spn
;
682 a
->mod_op
= LDAP_MOD_ADD
;
683 a
->mod_type
= "userAccountControl";
684 a
->mod_values
= useraccvals
;
685 asprintf(&useraccvals
[0], "%d",
687 UF_PASSWD_NOT_EXPIRE
|
688 UF_WORKSTATION_TRUST_ACCOUNT
);
689 useraccvals
[1] = NULL
;
692 a
->mod_op
= LDAP_MOD_ADD
;
693 a
->mod_type
= "sAMAccountName";
694 a
->mod_values
= samvals
;
695 samvals
[0] = samname
;
699 a
->mod_op
= LDAP_MOD_ADD
;
700 a
->mod_type
= "dNSHostName";
701 a
->mod_values
= dnsvals
;
702 dnsvals
[0] = (char *)fqdn
;
706 /* XXX add even more spn's */
707 a
->mod_op
= LDAP_MOD_ADD
;
708 a
->mod_type
= "servicePrincipalName";
709 a
->mod_values
= spnvals
;
712 spnvals
[i
++] = realmless_p
;
714 spnvals
[i
++] = short_spn
;
716 spnvals
[i
++] = p_msrealm
;
720 a
->mod_op
= LDAP_MOD_ADD
;
721 a
->mod_type
= "userPrincipalName";
722 a
->mod_values
= upnvals
;
727 a
->mod_op
= LDAP_MOD_ADD
;
728 a
->mod_type
= "accountExpires";
730 tv
[0] = "9223372036854775807"; /* "never" */
735 /* create user account */
738 a
->mod_op
= LDAP_MOD_ADD
;
739 a
->mod_type
= "userAccountControl";
740 a
->mod_values
= useraccvals
;
741 asprintf(&useraccvals
[0], "%d",
743 UF_PASSWD_NOT_EXPIRE
);
744 useraccvals
[1] = NULL
;
747 a
->mod_op
= LDAP_MOD_ADD
;
748 a
->mod_type
= "sAMAccountName";
749 a
->mod_values
= samvals
;
750 samvals
[0] = realmless_p
;
754 a
->mod_op
= LDAP_MOD_ADD
;
755 a
->mod_type
= "userPrincipalName";
756 a
->mod_values
= upnvals
;
761 a
->mod_op
= LDAP_MOD_ADD
;
762 a
->mod_type
= "accountExpires";
764 tv
[0] = "9223372036854775807"; /* "never" */
769 attrs
[a
- &rattrs
[0]] = NULL
;
771 ret
= ldap_add_s(CTX2LP(context
), dn
, attrs
);
775 free(useraccvals
[0]);
786 if (check_ldap(context
, ret
))
787 return KADM5_RPC_ERROR
;
791 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
792 return KADM5_RPC_ERROR
;
797 kadm5_ad_delete_principal(void *server_handle
, krb5_principal principal
)
799 kadm5_ad_context
*context
= server_handle
;
805 ret
= ad_get_cred(context
, NULL
);
809 ret
= _kadm5_ad_connect(server_handle
);
813 fqdn
= get_fqdn(context
->context
, principal
);
815 ret
= krb5_unparse_name(context
->context
, principal
, &p
);
819 if (ad_find_entry(context
, fqdn
, p
, &dn
) != 0) {
821 return KADM5_UNK_PRINC
;
824 ret
= ldap_delete_s(CTX2LP(context
), dn
);
829 if (check_ldap(context
, ret
))
830 return KADM5_RPC_ERROR
;
833 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
834 return KADM5_RPC_ERROR
;
839 kadm5_ad_destroy(void *server_handle
)
841 kadm5_ad_context
*context
= server_handle
;
844 krb5_cc_destroy(context
->context
, context
->ccache
);
848 LDAP
*lp
= CTX2LP(context
);
851 if (context
->base_dn
)
852 free(context
->base_dn
);
855 free(context
->realm
);
856 free(context
->client_name
);
857 krb5_free_principal(context
->context
, context
->caller
);
858 if(context
->my_context
)
859 krb5_free_context(context
->context
);
864 kadm5_ad_flush(void *server_handle
)
866 kadm5_ad_context
*context
= server_handle
;
867 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
868 return KADM5_RPC_ERROR
;
872 kadm5_ad_get_principal(void *server_handle
,
873 krb5_principal principal
,
874 kadm5_principal_ent_t entry
,
877 kadm5_ad_context
*context
= server_handle
;
882 char *filter
, *p
, *q
, *u
;
887 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
891 * return 0 || KADM5_DUP;
894 memset(entry
, 0, sizeof(*entry
));
896 if (mask
& KADM5_KVNO
)
897 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
899 if (mask
& KADM5_PRINCIPAL
) {
900 laddattr(&attr
, &attrlen
, "userPrincipalName");
901 laddattr(&attr
, &attrlen
, "servicePrincipalName");
903 laddattr(&attr
, &attrlen
, "objectClass");
904 laddattr(&attr
, &attrlen
, "lastLogon");
905 laddattr(&attr
, &attrlen
, "badPwdCount");
906 laddattr(&attr
, &attrlen
, "badPasswordTime");
907 laddattr(&attr
, &attrlen
, "pwdLastSet");
908 laddattr(&attr
, &attrlen
, "accountExpires");
909 laddattr(&attr
, &attrlen
, "userAccountControl");
911 krb5_unparse_name_short(context
->context
, principal
, &p
);
912 krb5_unparse_name(context
->context
, principal
, &u
);
914 /* replace @ in domain part with a / */
916 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
920 "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
925 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
927 filter
, attr
, 0, &m
);
929 if (check_ldap(context
, ret
))
930 return KADM5_RPC_ERROR
;
932 if (ldap_count_entries(CTX2LP(context
), m
) > 0) {
934 m0
= ldap_first_entry(CTX2LP(context
), m
);
940 vals
= ldap_get_values(CTX2LP(context
), m0
, "servicePrincipalName");
942 printf("servicePrincipalName %s\n", vals
[0]);
943 vals
= ldap_get_values(CTX2LP(context
), m0
, "userPrincipalName");
945 printf("userPrincipalName %s\n", vals
[0]);
946 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
948 printf("userAccountControl %s\n", vals
[0]);
950 entry
->princ_expire_time
= 0;
951 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
952 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
954 entry
->princ_expire_time
= nt2unixtime(vals
[0]);
956 entry
->last_success
= 0;
957 if (mask
& KADM5_LAST_SUCCESS
) {
958 vals
= ldap_get_values(CTX2LP(context
), m0
, "lastLogon");
960 entry
->last_success
= nt2unixtime(vals
[0]);
962 if (mask
& KADM5_LAST_FAILED
) {
963 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPasswordTime");
965 entry
->last_failed
= nt2unixtime(vals
[0]);
967 if (mask
& KADM5_LAST_PWD_CHANGE
) {
968 vals
= ldap_get_values(CTX2LP(context
), m0
, "pwdLastSet");
970 entry
->last_pwd_change
= nt2unixtime(vals
[0]);
972 if (mask
& KADM5_FAIL_AUTH_COUNT
) {
973 vals
= ldap_get_values(CTX2LP(context
), m0
, "badPwdCount");
975 entry
->fail_auth_count
= atoi(vals
[0]);
977 if (mask
& KADM5_ATTRIBUTES
) {
978 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
982 if (i
& (UF_ACCOUNTDISABLE
|UF_LOCKOUT
))
983 entry
->attributes
|= KRB5_KDB_DISALLOW_ALL_TIX
;
984 if ((i
& UF_DONT_REQUIRE_PREAUTH
) == 0)
985 entry
->attributes
|= KRB5_KDB_REQUIRES_PRE_AUTH
;
986 if (i
& UF_SMARTCARD_REQUIRED
)
987 entry
->attributes
|= KRB5_KDB_REQUIRES_HW_AUTH
;
988 if ((i
& UF_WORKSTATION_TRUST_ACCOUNT
) == 0)
989 entry
->attributes
|= KRB5_KDB_DISALLOW_SVR
;
992 if (mask
& KADM5_KVNO
) {
993 vals
= ldap_get_values(CTX2LP(context
), m0
,
994 "msDS-KeyVersionNumber");
996 entry
->kvno
= atoi(vals
[0]);
1002 return KADM5_UNK_PRINC
;
1005 if (mask
& KADM5_PRINCIPAL
)
1006 krb5_copy_principal(context
->context
, principal
, &entry
->principal
);
1010 return KADM5_RPC_ERROR
;
1012 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1013 return KADM5_RPC_ERROR
;
1018 kadm5_ad_get_principals(void *server_handle
,
1019 const char *expression
,
1023 kadm5_ad_context
*context
= server_handle
;
1026 * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1032 ret
= ad_get_cred(context
, NULL
);
1036 ret
= _kadm5_ad_connect(server_handle
);
1040 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1041 return KADM5_RPC_ERROR
;
1043 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1044 return KADM5_RPC_ERROR
;
1049 kadm5_ad_get_privs(void *server_handle
, uint32_t*privs
)
1051 kadm5_ad_context
*context
= server_handle
;
1052 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1053 return KADM5_RPC_ERROR
;
1057 kadm5_ad_modify_principal(void *server_handle
,
1058 kadm5_principal_ent_t entry
,
1061 kadm5_ad_context
*context
= server_handle
;
1065 * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1069 LDAPMessage
*m
= NULL
, *m0
;
1073 char *p
= NULL
, *s
= NULL
, *q
;
1075 LDAPMod
*attrs
[4], rattrs
[3], *a
;
1076 char *uaf
[2] = { NULL
, NULL
};
1077 char *kvno
[2] = { NULL
, NULL
};
1078 char *tv
[2] = { NULL
, NULL
};
1082 for (i
= 0; i
< sizeof(rattrs
)/sizeof(rattrs
[0]); i
++)
1083 attrs
[i
] = &rattrs
[i
];
1087 ret
= _kadm5_ad_connect(server_handle
);
1091 if (mask
& KADM5_KVNO
)
1092 laddattr(&attr
, &attrlen
, "msDS-KeyVersionNumber");
1093 if (mask
& KADM5_PRINC_EXPIRE_TIME
)
1094 laddattr(&attr
, &attrlen
, "accountExpires");
1095 if (mask
& KADM5_ATTRIBUTES
)
1096 laddattr(&attr
, &attrlen
, "userAccountControl");
1097 laddattr(&attr
, &attrlen
, "distinguishedName");
1099 krb5_unparse_name(context
->context
, entry
->principal
, &p
);
1103 q
= strrchr(s
, '@');
1104 if (q
&& (p
!= q
&& *(q
- 1) != '\\'))
1108 "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1113 ret
= ldap_search_s(CTX2LP(context
), CTX2BASE(context
),
1115 filter
, attr
, 0, &m
);
1118 if (check_ldap(context
, ret
))
1119 return KADM5_RPC_ERROR
;
1121 if (ldap_count_entries(CTX2LP(context
), m
) <= 0) {
1122 ret
= KADM5_RPC_ERROR
;
1126 m0
= ldap_first_entry(CTX2LP(context
), m
);
1128 if (mask
& KADM5_ATTRIBUTES
) {
1131 vals
= ldap_get_values(CTX2LP(context
), m0
, "userAccountControl");
1133 ret
= KADM5_RPC_ERROR
;
1139 return KADM5_RPC_ERROR
;
1141 if (entry
->attributes
& KRB5_KDB_DISALLOW_ALL_TIX
)
1142 i
|= (UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1144 i
&= ~(UF_ACCOUNTDISABLE
|UF_LOCKOUT
);
1145 if (entry
->attributes
& KRB5_KDB_REQUIRES_PRE_AUTH
)
1146 i
&= ~UF_DONT_REQUIRE_PREAUTH
;
1148 i
|= UF_DONT_REQUIRE_PREAUTH
;
1149 if (entry
->attributes
& KRB5_KDB_REQUIRES_HW_AUTH
)
1150 i
|= UF_SMARTCARD_REQUIRED
;
1152 i
&= UF_SMARTCARD_REQUIRED
;
1153 if (entry
->attributes
& KRB5_KDB_DISALLOW_SVR
)
1154 i
&= ~UF_WORKSTATION_TRUST_ACCOUNT
;
1156 i
|= UF_WORKSTATION_TRUST_ACCOUNT
;
1158 asprintf(&uaf
[0], "%d", i
);
1160 a
->mod_op
= LDAP_MOD_REPLACE
;
1161 a
->mod_type
= "userAccountControl";
1162 a
->mod_values
= uaf
;
1166 if (mask
& KADM5_KVNO
) {
1167 vals
= ldap_get_values(CTX2LP(context
), m0
, "msDS-KeyVersionNumber");
1171 asprintf(&kvno
[0], "%d", entry
->kvno
);
1173 a
->mod_op
= LDAP_MOD_REPLACE
;
1174 a
->mod_type
= "msDS-KeyVersionNumber";
1175 a
->mod_values
= kvno
;
1180 if (mask
& KADM5_PRINC_EXPIRE_TIME
) {
1182 vals
= ldap_get_values(CTX2LP(context
), m0
, "accountExpires");
1184 ret
= KADM5_RPC_ERROR
;
1188 wt
= unix2nttime(entry
->princ_expire_time
);
1190 asprintf(&tv
[0], "%llu", wt
);
1192 a
->mod_op
= LDAP_MOD_REPLACE
;
1193 a
->mod_type
= "accountExpires";
1198 vals
= ldap_get_values(CTX2LP(context
), m0
, "distinguishedName");
1200 ret
= KADM5_RPC_ERROR
;
1205 attrs
[a
- &rattrs
[0]] = NULL
;
1207 ret
= ldap_modify_s(CTX2LP(context
), dn
, attrs
);
1208 if (check_ldap(context
, ret
))
1209 return KADM5_RPC_ERROR
;
1222 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1223 return KADM5_RPC_ERROR
;
1228 kadm5_ad_randkey_principal(void *server_handle
,
1229 krb5_principal principal
,
1230 krb5_keyblock
**keys
,
1233 kadm5_ad_context
*context
= server_handle
;
1240 krb5_data result_code_string
, result_string
;
1241 int result_code
, plen
;
1250 krb5_generate_random_block(p
, sizeof(p
));
1251 plen
= base64_encode(p
, sizeof(p
), &password
);
1256 ret
= ad_get_cred(context
, NULL
);
1262 krb5_data_zero (&result_code_string
);
1263 krb5_data_zero (&result_string
);
1265 ret
= krb5_set_password_using_ccache (context
->context
,
1270 &result_code_string
,
1273 krb5_data_free (&result_code_string
);
1274 krb5_data_free (&result_string
);
1278 *keys
= malloc(sizeof(**keys
) * 1);
1279 if (*keys
== NULL
) {
1285 ret
= krb5_string_to_key(context
->context
,
1286 ENCTYPE_ARCFOUR_HMAC_MD5
,
1290 memset(password
, 0, sizeof(password
));
1298 memset(password
, 0, plen
);
1306 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1307 return KADM5_RPC_ERROR
;
1312 kadm5_ad_rename_principal(void *server_handle
,
1313 krb5_principal from
,
1316 kadm5_ad_context
*context
= server_handle
;
1317 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1318 return KADM5_RPC_ERROR
;
1322 kadm5_ad_chpass_principal_with_key(void *server_handle
,
1323 krb5_principal princ
,
1325 krb5_key_data
*key_data
)
1327 kadm5_ad_context
*context
= server_handle
;
1328 krb5_set_error_message(context
->context
, KADM5_RPC_ERROR
, "Function not implemented");
1329 return KADM5_RPC_ERROR
;
1333 set_funcs(kadm5_ad_context
*c
)
1335 #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1336 SET(c
, chpass_principal
);
1337 SET(c
, chpass_principal_with_key
);
1338 SET(c
, create_principal
);
1339 SET(c
, delete_principal
);
1342 SET(c
, get_principal
);
1343 SET(c
, get_principals
);
1345 SET(c
, modify_principal
);
1346 SET(c
, randkey_principal
);
1347 SET(c
, rename_principal
);
1351 kadm5_ad_init_with_password_ctx(krb5_context context
,
1352 const char *client_name
,
1353 const char *password
,
1354 const char *service_name
,
1355 kadm5_config_params
*realm_params
,
1356 unsigned long struct_version
,
1357 unsigned long api_version
,
1358 void **server_handle
)
1361 kadm5_ad_context
*ctx
;
1363 ctx
= malloc(sizeof(*ctx
));
1366 memset(ctx
, 0, sizeof(*ctx
));
1369 ctx
->context
= context
;
1370 krb5_add_et_list (context
, initialize_kadm5_error_table_r
);
1372 ret
= krb5_parse_name(ctx
->context
, client_name
, &ctx
->caller
);
1378 if(realm_params
->mask
& KADM5_CONFIG_REALM
) {
1380 ctx
->realm
= strdup(realm_params
->realm
);
1381 if (ctx
->realm
== NULL
)
1384 ret
= krb5_get_default_realm(ctx
->context
, &ctx
->realm
);
1390 ctx
->client_name
= strdup(client_name
);
1392 if(password
!= NULL
&& *password
!= '\0')
1393 ret
= ad_get_cred(ctx
, password
);
1395 ret
= ad_get_cred(ctx
, NULL
);
1397 kadm5_ad_destroy(ctx
);
1402 ret
= _kadm5_ad_connect(ctx
);
1404 kadm5_ad_destroy(ctx
);
1409 *server_handle
= ctx
;
1414 kadm5_ad_init_with_password(const char *client_name
,
1415 const char *password
,
1416 const char *service_name
,
1417 kadm5_config_params
*realm_params
,
1418 unsigned long struct_version
,
1419 unsigned long api_version
,
1420 void **server_handle
)
1422 krb5_context context
;
1424 kadm5_ad_context
*ctx
;
1426 ret
= krb5_init_context(&context
);
1429 ret
= kadm5_ad_init_with_password_ctx(context
,
1438 krb5_free_context(context
);
1441 ctx
= *server_handle
;
1442 ctx
->my_context
= 1;