1c19800e8SDoug Rabson /*
2*ae771770SStanislav Sedov * Copyright (c) 2004 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson * All rights reserved.
5c19800e8SDoug Rabson *
6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson * are met:
9c19800e8SDoug Rabson *
10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson *
13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson *
17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson * without specific prior written permission.
20c19800e8SDoug Rabson *
21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson * SUCH DAMAGE.
32c19800e8SDoug Rabson */
33c19800e8SDoug Rabson
34c19800e8SDoug Rabson #define HAVE_TSASL 1
35c19800e8SDoug Rabson
36c19800e8SDoug Rabson #include "kadm5_locl.h"
37c19800e8SDoug Rabson #if 1
38c19800e8SDoug Rabson #undef OPENLDAP
39c19800e8SDoug Rabson #undef HAVE_TSASL
40c19800e8SDoug Rabson #endif
41c19800e8SDoug Rabson #ifdef OPENLDAP
42c19800e8SDoug Rabson #include <ldap.h>
43c19800e8SDoug Rabson #ifdef HAVE_TSASL
44c19800e8SDoug Rabson #include <tsasl.h>
45c19800e8SDoug Rabson #endif
46c19800e8SDoug Rabson #include <resolve.h>
47c19800e8SDoug Rabson #include <base64.h>
48c19800e8SDoug Rabson #endif
49c19800e8SDoug Rabson
50*ae771770SStanislav Sedov RCSID("$Id$");
51c19800e8SDoug Rabson
52c19800e8SDoug Rabson #ifdef OPENLDAP
53c19800e8SDoug Rabson
54c19800e8SDoug Rabson #define CTX2LP(context) ((LDAP *)((context)->ldap_conn))
55c19800e8SDoug Rabson #define CTX2BASE(context) ((context)->base_dn)
56c19800e8SDoug Rabson
57c19800e8SDoug Rabson /*
58c19800e8SDoug Rabson * userAccountControl
59c19800e8SDoug Rabson */
60c19800e8SDoug Rabson
61c19800e8SDoug Rabson #define UF_SCRIPT 0x00000001
62c19800e8SDoug Rabson #define UF_ACCOUNTDISABLE 0x00000002
63c19800e8SDoug Rabson #define UF_UNUSED_0 0x00000004
64c19800e8SDoug Rabson #define UF_HOMEDIR_REQUIRED 0x00000008
65c19800e8SDoug Rabson #define UF_LOCKOUT 0x00000010
66c19800e8SDoug Rabson #define UF_PASSWD_NOTREQD 0x00000020
67c19800e8SDoug Rabson #define UF_PASSWD_CANT_CHANGE 0x00000040
68c19800e8SDoug Rabson #define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
69c19800e8SDoug Rabson #define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100
70c19800e8SDoug Rabson #define UF_NORMAL_ACCOUNT 0x00000200
71c19800e8SDoug Rabson #define UF_UNUSED_1 0x00000400
72c19800e8SDoug Rabson #define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
73c19800e8SDoug Rabson #define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
74c19800e8SDoug Rabson #define UF_SERVER_TRUST_ACCOUNT 0x00002000
75c19800e8SDoug Rabson #define UF_UNUSED_2 0x00004000
76c19800e8SDoug Rabson #define UF_UNUSED_3 0x00008000
77c19800e8SDoug Rabson #define UF_PASSWD_NOT_EXPIRE 0x00010000
78c19800e8SDoug Rabson #define UF_MNS_LOGON_ACCOUNT 0x00020000
79c19800e8SDoug Rabson #define UF_SMARTCARD_REQUIRED 0x00040000
80c19800e8SDoug Rabson #define UF_TRUSTED_FOR_DELEGATION 0x00080000
81c19800e8SDoug Rabson #define UF_NOT_DELEGATED 0x00100000
82c19800e8SDoug Rabson #define UF_USE_DES_KEY_ONLY 0x00200000
83c19800e8SDoug Rabson #define UF_DONT_REQUIRE_PREAUTH 0x00400000
84c19800e8SDoug Rabson #define UF_UNUSED_4 0x00800000
85c19800e8SDoug Rabson #define UF_UNUSED_5 0x01000000
86c19800e8SDoug Rabson #define UF_UNUSED_6 0x02000000
87c19800e8SDoug Rabson #define UF_UNUSED_7 0x04000000
88c19800e8SDoug Rabson #define UF_UNUSED_8 0x08000000
89c19800e8SDoug Rabson #define UF_UNUSED_9 0x10000000
90c19800e8SDoug Rabson #define UF_UNUSED_10 0x20000000
91c19800e8SDoug Rabson #define UF_UNUSED_11 0x40000000
92c19800e8SDoug Rabson #define UF_UNUSED_12 0x80000000
93c19800e8SDoug Rabson
94c19800e8SDoug Rabson /*
95c19800e8SDoug Rabson *
96c19800e8SDoug Rabson */
97c19800e8SDoug Rabson
98c19800e8SDoug Rabson #ifndef HAVE_TSASL
99c19800e8SDoug Rabson static int
sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * interact)100c19800e8SDoug Rabson sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *interact)
101c19800e8SDoug Rabson {
102c19800e8SDoug Rabson return LDAP_SUCCESS;
103c19800e8SDoug Rabson }
104c19800e8SDoug Rabson #endif
105c19800e8SDoug Rabson
106c19800e8SDoug Rabson #if 0
107c19800e8SDoug Rabson static Sockbuf_IO ldap_tsasl_io = {
108c19800e8SDoug Rabson NULL, /* sbi_setup */
109c19800e8SDoug Rabson NULL, /* sbi_remove */
110c19800e8SDoug Rabson NULL, /* sbi_ctrl */
111c19800e8SDoug Rabson NULL, /* sbi_read */
112c19800e8SDoug Rabson NULL, /* sbi_write */
113c19800e8SDoug Rabson NULL /* sbi_close */
114c19800e8SDoug Rabson };
115c19800e8SDoug Rabson #endif
116c19800e8SDoug Rabson
117c19800e8SDoug Rabson #ifdef HAVE_TSASL
118c19800e8SDoug Rabson static int
ldap_tsasl_bind_s(LDAP * ld,LDAP_CONST char * dn,LDAPControl ** serverControls,LDAPControl ** clientControls,const char * host)119c19800e8SDoug Rabson ldap_tsasl_bind_s(LDAP *ld,
120c19800e8SDoug Rabson LDAP_CONST char *dn,
121c19800e8SDoug Rabson LDAPControl **serverControls,
122c19800e8SDoug Rabson LDAPControl **clientControls,
123c19800e8SDoug Rabson const char *host)
124c19800e8SDoug Rabson {
125c19800e8SDoug Rabson char *attrs[] = { "supportedSASLMechanisms", NULL };
126c19800e8SDoug Rabson struct tsasl_peer *peer = NULL;
127c19800e8SDoug Rabson struct tsasl_buffer in, out;
128c19800e8SDoug Rabson struct berval ccred, *scred;
129c19800e8SDoug Rabson LDAPMessage *m, *m0;
130c19800e8SDoug Rabson const char *mech;
131c19800e8SDoug Rabson char **vals;
132c19800e8SDoug Rabson int ret, rc;
133c19800e8SDoug Rabson
134c19800e8SDoug Rabson ret = tsasl_peer_init(TSASL_FLAGS_INITIATOR | TSASL_FLAGS_CLEAR,
135c19800e8SDoug Rabson "ldap", host, &peer);
136c19800e8SDoug Rabson if (ret != TSASL_DONE) {
137c19800e8SDoug Rabson rc = LDAP_LOCAL_ERROR;
138c19800e8SDoug Rabson goto out;
139c19800e8SDoug Rabson }
140c19800e8SDoug Rabson
141c19800e8SDoug Rabson rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &m0);
142c19800e8SDoug Rabson if (rc != LDAP_SUCCESS)
143c19800e8SDoug Rabson goto out;
144c19800e8SDoug Rabson
145c19800e8SDoug Rabson m = ldap_first_entry(ld, m0);
146c19800e8SDoug Rabson if (m == NULL) {
147c19800e8SDoug Rabson ldap_msgfree(m0);
148c19800e8SDoug Rabson goto out;
149c19800e8SDoug Rabson }
150c19800e8SDoug Rabson
151c19800e8SDoug Rabson vals = ldap_get_values(ld, m, "supportedSASLMechanisms");
152c19800e8SDoug Rabson if (vals == NULL) {
153c19800e8SDoug Rabson ldap_msgfree(m0);
154c19800e8SDoug Rabson goto out;
155c19800e8SDoug Rabson }
156c19800e8SDoug Rabson
157c19800e8SDoug Rabson ret = tsasl_find_best_mech(peer, vals, &mech);
158c19800e8SDoug Rabson if (ret) {
159c19800e8SDoug Rabson ldap_msgfree(m0);
160c19800e8SDoug Rabson goto out;
161c19800e8SDoug Rabson }
162c19800e8SDoug Rabson
163c19800e8SDoug Rabson ldap_msgfree(m0);
164c19800e8SDoug Rabson
165c19800e8SDoug Rabson ret = tsasl_select_mech(peer, mech);
166c19800e8SDoug Rabson if (ret != TSASL_DONE) {
167c19800e8SDoug Rabson rc = LDAP_LOCAL_ERROR;
168c19800e8SDoug Rabson goto out;
169c19800e8SDoug Rabson }
170c19800e8SDoug Rabson
171c19800e8SDoug Rabson in.tb_data = NULL;
172c19800e8SDoug Rabson in.tb_size = 0;
173c19800e8SDoug Rabson
174c19800e8SDoug Rabson do {
175c19800e8SDoug Rabson ret = tsasl_request(peer, &in, &out);
176c19800e8SDoug Rabson if (in.tb_size != 0) {
177c19800e8SDoug Rabson free(in.tb_data);
178c19800e8SDoug Rabson in.tb_data = NULL;
179c19800e8SDoug Rabson in.tb_size = 0;
180c19800e8SDoug Rabson }
181c19800e8SDoug Rabson if (ret != TSASL_DONE && ret != TSASL_CONTINUE) {
182c19800e8SDoug Rabson rc = LDAP_AUTH_UNKNOWN;
183c19800e8SDoug Rabson goto out;
184c19800e8SDoug Rabson }
185c19800e8SDoug Rabson
186c19800e8SDoug Rabson ccred.bv_val = out.tb_data;
187c19800e8SDoug Rabson ccred.bv_len = out.tb_size;
188c19800e8SDoug Rabson
189c19800e8SDoug Rabson rc = ldap_sasl_bind_s(ld, dn, mech, &ccred,
190c19800e8SDoug Rabson serverControls, clientControls, &scred);
191c19800e8SDoug Rabson tsasl_buffer_free(&out);
192c19800e8SDoug Rabson
193c19800e8SDoug Rabson if (rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS) {
194c19800e8SDoug Rabson if(scred && scred->bv_len)
195c19800e8SDoug Rabson ber_bvfree(scred);
196c19800e8SDoug Rabson goto out;
197c19800e8SDoug Rabson }
198c19800e8SDoug Rabson
199c19800e8SDoug Rabson in.tb_data = malloc(scred->bv_len);
200c19800e8SDoug Rabson if (in.tb_data == NULL) {
201c19800e8SDoug Rabson rc = LDAP_LOCAL_ERROR;
202c19800e8SDoug Rabson goto out;
203c19800e8SDoug Rabson }
204c19800e8SDoug Rabson memcpy(in.tb_data, scred->bv_val, scred->bv_len);
205c19800e8SDoug Rabson in.tb_size = scred->bv_len;
206c19800e8SDoug Rabson ber_bvfree(scred);
207c19800e8SDoug Rabson
208c19800e8SDoug Rabson } while (rc == LDAP_SASL_BIND_IN_PROGRESS);
209c19800e8SDoug Rabson
210c19800e8SDoug Rabson out:
211c19800e8SDoug Rabson if (rc == LDAP_SUCCESS) {
212c19800e8SDoug Rabson #if 0
213c19800e8SDoug Rabson ber_sockbuf_add_io(ld->ld_conns->lconn_sb, &ldap_tsasl_io,
214c19800e8SDoug Rabson LBER_SBIOD_LEVEL_APPLICATION, peer);
215c19800e8SDoug Rabson
216c19800e8SDoug Rabson #endif
217c19800e8SDoug Rabson } else if (peer != NULL)
218c19800e8SDoug Rabson tsasl_peer_free(peer);
219c19800e8SDoug Rabson
220c19800e8SDoug Rabson return rc;
221c19800e8SDoug Rabson }
222c19800e8SDoug Rabson #endif /* HAVE_TSASL */
223c19800e8SDoug Rabson
224c19800e8SDoug Rabson
225c19800e8SDoug Rabson static int
check_ldap(kadm5_ad_context * context,int ret)226c19800e8SDoug Rabson check_ldap(kadm5_ad_context *context, int ret)
227c19800e8SDoug Rabson {
228c19800e8SDoug Rabson switch (ret) {
229c19800e8SDoug Rabson case LDAP_SUCCESS:
230c19800e8SDoug Rabson return 0;
231c19800e8SDoug Rabson case LDAP_SERVER_DOWN: {
232c19800e8SDoug Rabson LDAP *lp = CTX2LP(context);
233c19800e8SDoug Rabson ldap_unbind(lp);
234c19800e8SDoug Rabson context->ldap_conn = NULL;
235c19800e8SDoug Rabson free(context->base_dn);
236c19800e8SDoug Rabson context->base_dn = NULL;
237c19800e8SDoug Rabson return 1;
238c19800e8SDoug Rabson }
239c19800e8SDoug Rabson default:
240c19800e8SDoug Rabson return 1;
241c19800e8SDoug Rabson }
242c19800e8SDoug Rabson }
243c19800e8SDoug Rabson
244c19800e8SDoug Rabson /*
245c19800e8SDoug Rabson *
246c19800e8SDoug Rabson */
247c19800e8SDoug Rabson
248c19800e8SDoug Rabson static void
laddattr(char *** al,int * attrlen,char * attr)249c19800e8SDoug Rabson laddattr(char ***al, int *attrlen, char *attr)
250c19800e8SDoug Rabson {
251c19800e8SDoug Rabson char **a;
252c19800e8SDoug Rabson a = realloc(*al, (*attrlen + 2) * sizeof(**al));
253c19800e8SDoug Rabson if (a == NULL)
254c19800e8SDoug Rabson return;
255c19800e8SDoug Rabson a[*attrlen] = attr;
256c19800e8SDoug Rabson a[*attrlen + 1] = NULL;
257c19800e8SDoug Rabson (*attrlen)++;
258c19800e8SDoug Rabson *al = a;
259c19800e8SDoug Rabson }
260c19800e8SDoug Rabson
261c19800e8SDoug Rabson static kadm5_ret_t
_kadm5_ad_connect(void * server_handle)262c19800e8SDoug Rabson _kadm5_ad_connect(void *server_handle)
263c19800e8SDoug Rabson {
264c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
265c19800e8SDoug Rabson struct {
266c19800e8SDoug Rabson char *server;
267c19800e8SDoug Rabson int port;
268c19800e8SDoug Rabson } *s, *servers = NULL;
269c19800e8SDoug Rabson int i, num_servers = 0;
270c19800e8SDoug Rabson
271c19800e8SDoug Rabson if (context->ldap_conn)
272c19800e8SDoug Rabson return 0;
273c19800e8SDoug Rabson
274c19800e8SDoug Rabson {
275c19800e8SDoug Rabson struct dns_reply *r;
276c19800e8SDoug Rabson struct resource_record *rr;
277c19800e8SDoug Rabson char *domain;
278c19800e8SDoug Rabson
279c19800e8SDoug Rabson asprintf(&domain, "_ldap._tcp.%s", context->realm);
280c19800e8SDoug Rabson if (domain == NULL) {
281*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_NO_SRV, "malloc");
282c19800e8SDoug Rabson return KADM5_NO_SRV;
283c19800e8SDoug Rabson }
284c19800e8SDoug Rabson
285c19800e8SDoug Rabson r = dns_lookup(domain, "SRV");
286c19800e8SDoug Rabson free(domain);
287c19800e8SDoug Rabson if (r == NULL) {
288*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_NO_SRV, "Didn't find ldap dns");
289c19800e8SDoug Rabson return KADM5_NO_SRV;
290c19800e8SDoug Rabson }
291c19800e8SDoug Rabson
292c19800e8SDoug Rabson for (rr = r->head ; rr != NULL; rr = rr->next) {
293*ae771770SStanislav Sedov if (rr->type != rk_ns_t_srv)
294c19800e8SDoug Rabson continue;
295c19800e8SDoug Rabson s = realloc(servers, sizeof(*servers) * (num_servers + 1));
296c19800e8SDoug Rabson if (s == NULL) {
297*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "malloc");
298c19800e8SDoug Rabson dns_free_data(r);
299c19800e8SDoug Rabson goto fail;
300c19800e8SDoug Rabson }
301c19800e8SDoug Rabson servers = s;
302c19800e8SDoug Rabson num_servers++;
303c19800e8SDoug Rabson servers[num_servers - 1].port = rr->u.srv->port;
304c19800e8SDoug Rabson servers[num_servers - 1].server = strdup(rr->u.srv->target);
305c19800e8SDoug Rabson }
306c19800e8SDoug Rabson dns_free_data(r);
307c19800e8SDoug Rabson }
308c19800e8SDoug Rabson
309c19800e8SDoug Rabson if (num_servers == 0) {
310*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_NO_SRV, "No AD server found in DNS");
311c19800e8SDoug Rabson return KADM5_NO_SRV;
312c19800e8SDoug Rabson }
313c19800e8SDoug Rabson
314c19800e8SDoug Rabson for (i = 0; i < num_servers; i++) {
315c19800e8SDoug Rabson int lret, version = LDAP_VERSION3;
316c19800e8SDoug Rabson LDAP *lp;
317c19800e8SDoug Rabson
318c19800e8SDoug Rabson lp = ldap_init(servers[i].server, servers[i].port);
319c19800e8SDoug Rabson if (lp == NULL)
320c19800e8SDoug Rabson continue;
321c19800e8SDoug Rabson
322c19800e8SDoug Rabson if (ldap_set_option(lp, LDAP_OPT_PROTOCOL_VERSION, &version)) {
323c19800e8SDoug Rabson ldap_unbind(lp);
324c19800e8SDoug Rabson continue;
325c19800e8SDoug Rabson }
326c19800e8SDoug Rabson
327c19800e8SDoug Rabson if (ldap_set_option(lp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF)) {
328c19800e8SDoug Rabson ldap_unbind(lp);
329c19800e8SDoug Rabson continue;
330c19800e8SDoug Rabson }
331c19800e8SDoug Rabson
332c19800e8SDoug Rabson #ifdef HAVE_TSASL
333c19800e8SDoug Rabson lret = ldap_tsasl_bind_s(lp, NULL, NULL, NULL, servers[i].server);
334c19800e8SDoug Rabson
335c19800e8SDoug Rabson #else
336c19800e8SDoug Rabson lret = ldap_sasl_interactive_bind_s(lp, NULL, NULL, NULL, NULL,
337c19800e8SDoug Rabson LDAP_SASL_QUIET,
338c19800e8SDoug Rabson sasl_interact, NULL);
339c19800e8SDoug Rabson #endif
340c19800e8SDoug Rabson if (lret != LDAP_SUCCESS) {
341*ae771770SStanislav Sedov krb5_set_error_message(context->context, 0,
342c19800e8SDoug Rabson "Couldn't contact any AD servers: %s",
343c19800e8SDoug Rabson ldap_err2string(lret));
344c19800e8SDoug Rabson ldap_unbind(lp);
345c19800e8SDoug Rabson continue;
346c19800e8SDoug Rabson }
347c19800e8SDoug Rabson
348c19800e8SDoug Rabson context->ldap_conn = lp;
349c19800e8SDoug Rabson break;
350c19800e8SDoug Rabson }
351c19800e8SDoug Rabson if (i >= num_servers) {
352c19800e8SDoug Rabson goto fail;
353c19800e8SDoug Rabson }
354c19800e8SDoug Rabson
355c19800e8SDoug Rabson {
356c19800e8SDoug Rabson LDAPMessage *m, *m0;
357c19800e8SDoug Rabson char **attr = NULL;
358c19800e8SDoug Rabson int attrlen = 0;
359c19800e8SDoug Rabson char **vals;
360c19800e8SDoug Rabson int ret;
361c19800e8SDoug Rabson
362c19800e8SDoug Rabson laddattr(&attr, &attrlen, "defaultNamingContext");
363c19800e8SDoug Rabson
364c19800e8SDoug Rabson ret = ldap_search_s(CTX2LP(context), "", LDAP_SCOPE_BASE,
365c19800e8SDoug Rabson "objectclass=*", attr, 0, &m);
366c19800e8SDoug Rabson free(attr);
367c19800e8SDoug Rabson if (check_ldap(context, ret))
368c19800e8SDoug Rabson goto fail;
369c19800e8SDoug Rabson
370c19800e8SDoug Rabson if (ldap_count_entries(CTX2LP(context), m) > 0) {
371c19800e8SDoug Rabson m0 = ldap_first_entry(CTX2LP(context), m);
372c19800e8SDoug Rabson if (m0 == NULL) {
373*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR,
374c19800e8SDoug Rabson "Error in AD ldap responce");
375c19800e8SDoug Rabson ldap_msgfree(m);
376c19800e8SDoug Rabson goto fail;
377c19800e8SDoug Rabson }
378c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context),
379c19800e8SDoug Rabson m0, "defaultNamingContext");
380c19800e8SDoug Rabson if (vals == NULL) {
381*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR,
382c19800e8SDoug Rabson "No naming context found");
383c19800e8SDoug Rabson goto fail;
384c19800e8SDoug Rabson }
385c19800e8SDoug Rabson context->base_dn = strdup(vals[0]);
386c19800e8SDoug Rabson } else
387c19800e8SDoug Rabson goto fail;
388c19800e8SDoug Rabson ldap_msgfree(m);
389c19800e8SDoug Rabson }
390c19800e8SDoug Rabson
391c19800e8SDoug Rabson for (i = 0; i < num_servers; i++)
392c19800e8SDoug Rabson free(servers[i].server);
393c19800e8SDoug Rabson free(servers);
394c19800e8SDoug Rabson
395c19800e8SDoug Rabson return 0;
396c19800e8SDoug Rabson
397c19800e8SDoug Rabson fail:
398c19800e8SDoug Rabson for (i = 0; i < num_servers; i++)
399c19800e8SDoug Rabson free(servers[i].server);
400c19800e8SDoug Rabson free(servers);
401c19800e8SDoug Rabson
402c19800e8SDoug Rabson if (context->ldap_conn) {
403c19800e8SDoug Rabson ldap_unbind(CTX2LP(context));
404c19800e8SDoug Rabson context->ldap_conn = NULL;
405c19800e8SDoug Rabson }
406c19800e8SDoug Rabson return KADM5_RPC_ERROR;
407c19800e8SDoug Rabson }
408c19800e8SDoug Rabson
409c19800e8SDoug Rabson #define NTTIME_EPOCH 0x019DB1DED53E8000LL
410c19800e8SDoug Rabson
411c19800e8SDoug Rabson static time_t
nt2unixtime(const char * str)412c19800e8SDoug Rabson nt2unixtime(const char *str)
413c19800e8SDoug Rabson {
414c19800e8SDoug Rabson unsigned long long t;
415c19800e8SDoug Rabson t = strtoll(str, NULL, 10);
416c19800e8SDoug Rabson t = ((t - NTTIME_EPOCH) / (long long)10000000);
417c19800e8SDoug Rabson if (t > (((time_t)(~(long long)0)) >> 1))
418c19800e8SDoug Rabson return 0;
419c19800e8SDoug Rabson return (time_t)t;
420c19800e8SDoug Rabson }
421c19800e8SDoug Rabson
422c19800e8SDoug Rabson static long long
unix2nttime(time_t unix_time)423c19800e8SDoug Rabson unix2nttime(time_t unix_time)
424c19800e8SDoug Rabson {
425c19800e8SDoug Rabson long long wt;
426c19800e8SDoug Rabson wt = unix_time * (long long)10000000 + (long long)NTTIME_EPOCH;
427c19800e8SDoug Rabson return wt;
428c19800e8SDoug Rabson }
429c19800e8SDoug Rabson
430c19800e8SDoug Rabson /* XXX create filter in a better way */
431c19800e8SDoug Rabson
432c19800e8SDoug Rabson static int
ad_find_entry(kadm5_ad_context * context,const char * fqdn,const char * pn,char ** name)433c19800e8SDoug Rabson ad_find_entry(kadm5_ad_context *context,
434c19800e8SDoug Rabson const char *fqdn,
435c19800e8SDoug Rabson const char *pn,
436c19800e8SDoug Rabson char **name)
437c19800e8SDoug Rabson {
438c19800e8SDoug Rabson LDAPMessage *m, *m0;
439c19800e8SDoug Rabson char *attr[] = { "distinguishedName", NULL };
440c19800e8SDoug Rabson char *filter;
441c19800e8SDoug Rabson int ret;
442c19800e8SDoug Rabson
443c19800e8SDoug Rabson if (name)
444c19800e8SDoug Rabson *name = NULL;
445c19800e8SDoug Rabson
446c19800e8SDoug Rabson if (fqdn)
447c19800e8SDoug Rabson asprintf(&filter,
448c19800e8SDoug Rabson "(&(objectClass=computer)(|(dNSHostName=%s)(servicePrincipalName=%s)))",
449c19800e8SDoug Rabson fqdn, pn);
450c19800e8SDoug Rabson else if(pn)
451c19800e8SDoug Rabson asprintf(&filter, "(&(objectClass=account)(userPrincipalName=%s))", pn);
452c19800e8SDoug Rabson else
453c19800e8SDoug Rabson return KADM5_RPC_ERROR;
454c19800e8SDoug Rabson
455c19800e8SDoug Rabson ret = ldap_search_s(CTX2LP(context), CTX2BASE(context),
456c19800e8SDoug Rabson LDAP_SCOPE_SUBTREE,
457c19800e8SDoug Rabson filter, attr, 0, &m);
458c19800e8SDoug Rabson free(filter);
459c19800e8SDoug Rabson if (check_ldap(context, ret))
460c19800e8SDoug Rabson return KADM5_RPC_ERROR;
461c19800e8SDoug Rabson
462c19800e8SDoug Rabson if (ldap_count_entries(CTX2LP(context), m) > 0) {
463c19800e8SDoug Rabson char **vals;
464c19800e8SDoug Rabson m0 = ldap_first_entry(CTX2LP(context), m);
465c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "distinguishedName");
466c19800e8SDoug Rabson if (vals == NULL || vals[0] == NULL) {
467c19800e8SDoug Rabson ldap_msgfree(m);
468c19800e8SDoug Rabson return KADM5_RPC_ERROR;
469c19800e8SDoug Rabson }
470c19800e8SDoug Rabson if (name)
471c19800e8SDoug Rabson *name = strdup(vals[0]);
472c19800e8SDoug Rabson ldap_msgfree(m);
473c19800e8SDoug Rabson } else
474c19800e8SDoug Rabson return KADM5_UNK_PRINC;
475c19800e8SDoug Rabson
476c19800e8SDoug Rabson return 0;
477c19800e8SDoug Rabson }
478c19800e8SDoug Rabson
479c19800e8SDoug Rabson #endif /* OPENLDAP */
480c19800e8SDoug Rabson
481c19800e8SDoug Rabson static kadm5_ret_t
ad_get_cred(kadm5_ad_context * context,const char * password)482c19800e8SDoug Rabson ad_get_cred(kadm5_ad_context *context, const char *password)
483c19800e8SDoug Rabson {
484c19800e8SDoug Rabson kadm5_ret_t ret;
485c19800e8SDoug Rabson krb5_ccache cc;
486c19800e8SDoug Rabson char *service;
487c19800e8SDoug Rabson
488c19800e8SDoug Rabson if (context->ccache)
489c19800e8SDoug Rabson return 0;
490c19800e8SDoug Rabson
491c19800e8SDoug Rabson asprintf(&service, "%s/%s@%s", KRB5_TGS_NAME,
492c19800e8SDoug Rabson context->realm, context->realm);
493c19800e8SDoug Rabson if (service == NULL)
494c19800e8SDoug Rabson return ENOMEM;
495c19800e8SDoug Rabson
496c19800e8SDoug Rabson ret = _kadm5_c_get_cred_cache(context->context,
497c19800e8SDoug Rabson context->client_name,
498c19800e8SDoug Rabson service,
499c19800e8SDoug Rabson password, krb5_prompter_posix,
500c19800e8SDoug Rabson NULL, NULL, &cc);
501c19800e8SDoug Rabson free(service);
502c19800e8SDoug Rabson if(ret)
503c19800e8SDoug Rabson return ret; /* XXX */
504c19800e8SDoug Rabson context->ccache = cc;
505c19800e8SDoug Rabson return 0;
506c19800e8SDoug Rabson }
507c19800e8SDoug Rabson
508c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_chpass_principal(void * server_handle,krb5_principal principal,const char * password)509c19800e8SDoug Rabson kadm5_ad_chpass_principal(void *server_handle,
510c19800e8SDoug Rabson krb5_principal principal,
511c19800e8SDoug Rabson const char *password)
512c19800e8SDoug Rabson {
513c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
514c19800e8SDoug Rabson krb5_data result_code_string, result_string;
515c19800e8SDoug Rabson int result_code;
516c19800e8SDoug Rabson kadm5_ret_t ret;
517c19800e8SDoug Rabson
518c19800e8SDoug Rabson ret = ad_get_cred(context, NULL);
519c19800e8SDoug Rabson if (ret)
520c19800e8SDoug Rabson return ret;
521c19800e8SDoug Rabson
522c19800e8SDoug Rabson krb5_data_zero (&result_code_string);
523c19800e8SDoug Rabson krb5_data_zero (&result_string);
524c19800e8SDoug Rabson
525c19800e8SDoug Rabson ret = krb5_set_password_using_ccache (context->context,
526c19800e8SDoug Rabson context->ccache,
527c19800e8SDoug Rabson password,
528c19800e8SDoug Rabson principal,
529c19800e8SDoug Rabson &result_code,
530c19800e8SDoug Rabson &result_code_string,
531c19800e8SDoug Rabson &result_string);
532c19800e8SDoug Rabson
533c19800e8SDoug Rabson krb5_data_free (&result_code_string);
534c19800e8SDoug Rabson krb5_data_free (&result_string);
535c19800e8SDoug Rabson
536c19800e8SDoug Rabson /* XXX do mapping here on error codes */
537c19800e8SDoug Rabson
538c19800e8SDoug Rabson return ret;
539c19800e8SDoug Rabson }
540c19800e8SDoug Rabson
541c19800e8SDoug Rabson #ifdef OPENLDAP
542c19800e8SDoug Rabson static const char *
get_fqdn(krb5_context context,const krb5_principal p)543c19800e8SDoug Rabson get_fqdn(krb5_context context, const krb5_principal p)
544c19800e8SDoug Rabson {
545c19800e8SDoug Rabson const char *s, *hosttypes[] = { "host", "ldap", "gc", "cifs", "dns" };
546c19800e8SDoug Rabson int i;
547c19800e8SDoug Rabson
548c19800e8SDoug Rabson s = krb5_principal_get_comp_string(context, p, 0);
549c19800e8SDoug Rabson if (p == NULL)
550c19800e8SDoug Rabson return NULL;
551c19800e8SDoug Rabson
552c19800e8SDoug Rabson for (i = 0; i < sizeof(hosttypes)/sizeof(hosttypes[0]); i++) {
553c19800e8SDoug Rabson if (strcasecmp(s, hosttypes[i]) == 0)
554c19800e8SDoug Rabson return krb5_principal_get_comp_string(context, p, 1);
555c19800e8SDoug Rabson }
556c19800e8SDoug Rabson return 0;
557c19800e8SDoug Rabson }
558c19800e8SDoug Rabson #endif
559c19800e8SDoug Rabson
560c19800e8SDoug Rabson
561c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_create_principal(void * server_handle,kadm5_principal_ent_t entry,uint32_t mask,const char * password)562c19800e8SDoug Rabson kadm5_ad_create_principal(void *server_handle,
563c19800e8SDoug Rabson kadm5_principal_ent_t entry,
564c19800e8SDoug Rabson uint32_t mask,
565c19800e8SDoug Rabson const char *password)
566c19800e8SDoug Rabson {
567c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
568c19800e8SDoug Rabson
569c19800e8SDoug Rabson /*
570c19800e8SDoug Rabson * KADM5_PRINC_EXPIRE_TIME
571c19800e8SDoug Rabson *
572c19800e8SDoug Rabson * return 0 || KADM5_DUP;
573c19800e8SDoug Rabson */
574c19800e8SDoug Rabson
575c19800e8SDoug Rabson #ifdef OPENLDAP
576c19800e8SDoug Rabson LDAPMod *attrs[8], rattrs[7], *a;
577c19800e8SDoug Rabson char *useraccvals[2] = { NULL, NULL },
578c19800e8SDoug Rabson *samvals[2], *dnsvals[2], *spnvals[5], *upnvals[2], *tv[2];
579c19800e8SDoug Rabson char *ocvals_spn[] = { "top", "person", "organizationalPerson",
580c19800e8SDoug Rabson "user", "computer", NULL};
581c19800e8SDoug Rabson char *p, *realmless_p, *p_msrealm = NULL, *dn = NULL;
582c19800e8SDoug Rabson const char *fqdn;
583c19800e8SDoug Rabson char *s, *samname = NULL, *short_spn = NULL;
584c19800e8SDoug Rabson int ret, i;
585c19800e8SDoug Rabson int32_t uf_flags = 0;
586c19800e8SDoug Rabson
587c19800e8SDoug Rabson if ((mask & KADM5_PRINCIPAL) == 0)
588c19800e8SDoug Rabson return KADM5_BAD_MASK;
589c19800e8SDoug Rabson
590c19800e8SDoug Rabson for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++)
591c19800e8SDoug Rabson attrs[i] = &rattrs[i];
592c19800e8SDoug Rabson attrs[i] = NULL;
593c19800e8SDoug Rabson
594c19800e8SDoug Rabson ret = ad_get_cred(context, NULL);
595c19800e8SDoug Rabson if (ret)
596c19800e8SDoug Rabson return ret;
597c19800e8SDoug Rabson
598c19800e8SDoug Rabson ret = _kadm5_ad_connect(server_handle);
599c19800e8SDoug Rabson if (ret)
600c19800e8SDoug Rabson return ret;
601c19800e8SDoug Rabson
602c19800e8SDoug Rabson fqdn = get_fqdn(context->context, entry->principal);
603c19800e8SDoug Rabson
604c19800e8SDoug Rabson ret = krb5_unparse_name(context->context, entry->principal, &p);
605c19800e8SDoug Rabson if (ret)
606c19800e8SDoug Rabson return ret;
607c19800e8SDoug Rabson
608c19800e8SDoug Rabson if (ad_find_entry(context, fqdn, p, NULL) == 0) {
609c19800e8SDoug Rabson free(p);
610c19800e8SDoug Rabson return KADM5_DUP;
611c19800e8SDoug Rabson }
612c19800e8SDoug Rabson
613c19800e8SDoug Rabson if (mask & KADM5_ATTRIBUTES) {
614c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX)
615c19800e8SDoug Rabson uf_flags |= UF_ACCOUNTDISABLE|UF_LOCKOUT;
616c19800e8SDoug Rabson if ((entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH) == 0)
617c19800e8SDoug Rabson uf_flags |= UF_DONT_REQUIRE_PREAUTH;
618c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH)
619c19800e8SDoug Rabson uf_flags |= UF_SMARTCARD_REQUIRED;
620c19800e8SDoug Rabson }
621c19800e8SDoug Rabson
622c19800e8SDoug Rabson realmless_p = strdup(p);
623c19800e8SDoug Rabson if (realmless_p == NULL) {
624c19800e8SDoug Rabson ret = ENOMEM;
625c19800e8SDoug Rabson goto out;
626c19800e8SDoug Rabson }
627c19800e8SDoug Rabson s = strrchr(realmless_p, '@');
628c19800e8SDoug Rabson if (s)
629c19800e8SDoug Rabson *s = '\0';
630c19800e8SDoug Rabson
631c19800e8SDoug Rabson if (fqdn) {
632c19800e8SDoug Rabson /* create computer account */
633c19800e8SDoug Rabson asprintf(&samname, "%s$", fqdn);
634c19800e8SDoug Rabson if (samname == NULL) {
635c19800e8SDoug Rabson ret = ENOMEM;
636c19800e8SDoug Rabson goto out;
637c19800e8SDoug Rabson }
638c19800e8SDoug Rabson s = strchr(samname, '.');
639c19800e8SDoug Rabson if (s) {
640c19800e8SDoug Rabson s[0] = '$';
641c19800e8SDoug Rabson s[1] = '\0';
642c19800e8SDoug Rabson }
643c19800e8SDoug Rabson
644c19800e8SDoug Rabson short_spn = strdup(p);
645c19800e8SDoug Rabson if (short_spn == NULL) {
646c19800e8SDoug Rabson errno = ENOMEM;
647c19800e8SDoug Rabson goto out;
648c19800e8SDoug Rabson }
649c19800e8SDoug Rabson s = strchr(short_spn, '.');
650c19800e8SDoug Rabson if (s) {
651c19800e8SDoug Rabson *s = '\0';
652c19800e8SDoug Rabson } else {
653c19800e8SDoug Rabson free(short_spn);
654c19800e8SDoug Rabson short_spn = NULL;
655c19800e8SDoug Rabson }
656c19800e8SDoug Rabson
657c19800e8SDoug Rabson p_msrealm = strdup(p);
658c19800e8SDoug Rabson if (p_msrealm == NULL) {
659c19800e8SDoug Rabson errno = ENOMEM;
660c19800e8SDoug Rabson goto out;
661c19800e8SDoug Rabson }
662c19800e8SDoug Rabson s = strrchr(p_msrealm, '@');
663c19800e8SDoug Rabson if (s) {
664c19800e8SDoug Rabson *s = '/';
665c19800e8SDoug Rabson } else {
666c19800e8SDoug Rabson free(p_msrealm);
667c19800e8SDoug Rabson p_msrealm = NULL;
668c19800e8SDoug Rabson }
669c19800e8SDoug Rabson
670c19800e8SDoug Rabson asprintf(&dn, "cn=%s, cn=Computers, %s", fqdn, CTX2BASE(context));
671c19800e8SDoug Rabson if (dn == NULL) {
672c19800e8SDoug Rabson ret = ENOMEM;
673c19800e8SDoug Rabson goto out;
674c19800e8SDoug Rabson }
675c19800e8SDoug Rabson
676c19800e8SDoug Rabson a = &rattrs[0];
677c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
678c19800e8SDoug Rabson a->mod_type = "objectClass";
679c19800e8SDoug Rabson a->mod_values = ocvals_spn;
680c19800e8SDoug Rabson a++;
681c19800e8SDoug Rabson
682c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
683c19800e8SDoug Rabson a->mod_type = "userAccountControl";
684c19800e8SDoug Rabson a->mod_values = useraccvals;
685c19800e8SDoug Rabson asprintf(&useraccvals[0], "%d",
686c19800e8SDoug Rabson uf_flags |
687c19800e8SDoug Rabson UF_PASSWD_NOT_EXPIRE |
688c19800e8SDoug Rabson UF_WORKSTATION_TRUST_ACCOUNT);
689c19800e8SDoug Rabson useraccvals[1] = NULL;
690c19800e8SDoug Rabson a++;
691c19800e8SDoug Rabson
692c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
693c19800e8SDoug Rabson a->mod_type = "sAMAccountName";
694c19800e8SDoug Rabson a->mod_values = samvals;
695c19800e8SDoug Rabson samvals[0] = samname;
696c19800e8SDoug Rabson samvals[1] = NULL;
697c19800e8SDoug Rabson a++;
698c19800e8SDoug Rabson
699c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
700c19800e8SDoug Rabson a->mod_type = "dNSHostName";
701c19800e8SDoug Rabson a->mod_values = dnsvals;
702c19800e8SDoug Rabson dnsvals[0] = (char *)fqdn;
703c19800e8SDoug Rabson dnsvals[1] = NULL;
704c19800e8SDoug Rabson a++;
705c19800e8SDoug Rabson
706c19800e8SDoug Rabson /* XXX add even more spn's */
707c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
708c19800e8SDoug Rabson a->mod_type = "servicePrincipalName";
709c19800e8SDoug Rabson a->mod_values = spnvals;
710c19800e8SDoug Rabson i = 0;
711c19800e8SDoug Rabson spnvals[i++] = p;
712c19800e8SDoug Rabson spnvals[i++] = realmless_p;
713c19800e8SDoug Rabson if (short_spn)
714c19800e8SDoug Rabson spnvals[i++] = short_spn;
715c19800e8SDoug Rabson if (p_msrealm)
716c19800e8SDoug Rabson spnvals[i++] = p_msrealm;
717c19800e8SDoug Rabson spnvals[i++] = NULL;
718c19800e8SDoug Rabson a++;
719c19800e8SDoug Rabson
720c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
721c19800e8SDoug Rabson a->mod_type = "userPrincipalName";
722c19800e8SDoug Rabson a->mod_values = upnvals;
723c19800e8SDoug Rabson upnvals[0] = p;
724c19800e8SDoug Rabson upnvals[1] = NULL;
725c19800e8SDoug Rabson a++;
726c19800e8SDoug Rabson
727c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
728c19800e8SDoug Rabson a->mod_type = "accountExpires";
729c19800e8SDoug Rabson a->mod_values = tv;
730c19800e8SDoug Rabson tv[0] = "9223372036854775807"; /* "never" */
731c19800e8SDoug Rabson tv[1] = NULL;
732c19800e8SDoug Rabson a++;
733c19800e8SDoug Rabson
734c19800e8SDoug Rabson } else {
735c19800e8SDoug Rabson /* create user account */
736c19800e8SDoug Rabson
737c19800e8SDoug Rabson a = &rattrs[0];
738c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
739c19800e8SDoug Rabson a->mod_type = "userAccountControl";
740c19800e8SDoug Rabson a->mod_values = useraccvals;
741c19800e8SDoug Rabson asprintf(&useraccvals[0], "%d",
742c19800e8SDoug Rabson uf_flags |
743c19800e8SDoug Rabson UF_PASSWD_NOT_EXPIRE);
744c19800e8SDoug Rabson useraccvals[1] = NULL;
745c19800e8SDoug Rabson a++;
746c19800e8SDoug Rabson
747c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
748c19800e8SDoug Rabson a->mod_type = "sAMAccountName";
749c19800e8SDoug Rabson a->mod_values = samvals;
750c19800e8SDoug Rabson samvals[0] = realmless_p;
751c19800e8SDoug Rabson samvals[1] = NULL;
752c19800e8SDoug Rabson a++;
753c19800e8SDoug Rabson
754c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
755c19800e8SDoug Rabson a->mod_type = "userPrincipalName";
756c19800e8SDoug Rabson a->mod_values = upnvals;
757c19800e8SDoug Rabson upnvals[0] = p;
758c19800e8SDoug Rabson upnvals[1] = NULL;
759c19800e8SDoug Rabson a++;
760c19800e8SDoug Rabson
761c19800e8SDoug Rabson a->mod_op = LDAP_MOD_ADD;
762c19800e8SDoug Rabson a->mod_type = "accountExpires";
763c19800e8SDoug Rabson a->mod_values = tv;
764c19800e8SDoug Rabson tv[0] = "9223372036854775807"; /* "never" */
765c19800e8SDoug Rabson tv[1] = NULL;
766c19800e8SDoug Rabson a++;
767c19800e8SDoug Rabson }
768c19800e8SDoug Rabson
769c19800e8SDoug Rabson attrs[a - &rattrs[0]] = NULL;
770c19800e8SDoug Rabson
771c19800e8SDoug Rabson ret = ldap_add_s(CTX2LP(context), dn, attrs);
772c19800e8SDoug Rabson
773c19800e8SDoug Rabson out:
774c19800e8SDoug Rabson if (useraccvals[0])
775c19800e8SDoug Rabson free(useraccvals[0]);
776c19800e8SDoug Rabson if (realmless_p)
777c19800e8SDoug Rabson free(realmless_p);
778c19800e8SDoug Rabson if (samname)
779c19800e8SDoug Rabson free(samname);
780c19800e8SDoug Rabson if (short_spn)
781c19800e8SDoug Rabson free(short_spn);
782c19800e8SDoug Rabson if (p_msrealm)
783c19800e8SDoug Rabson free(p_msrealm);
784c19800e8SDoug Rabson free(p);
785c19800e8SDoug Rabson
786c19800e8SDoug Rabson if (check_ldap(context, ret))
787c19800e8SDoug Rabson return KADM5_RPC_ERROR;
788c19800e8SDoug Rabson
789c19800e8SDoug Rabson return 0;
790c19800e8SDoug Rabson #else
791*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
792c19800e8SDoug Rabson return KADM5_RPC_ERROR;
793c19800e8SDoug Rabson #endif
794c19800e8SDoug Rabson }
795c19800e8SDoug Rabson
796c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_delete_principal(void * server_handle,krb5_principal principal)797c19800e8SDoug Rabson kadm5_ad_delete_principal(void *server_handle, krb5_principal principal)
798c19800e8SDoug Rabson {
799c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
800c19800e8SDoug Rabson #ifdef OPENLDAP
801c19800e8SDoug Rabson char *p, *dn = NULL;
802c19800e8SDoug Rabson const char *fqdn;
803c19800e8SDoug Rabson int ret;
804c19800e8SDoug Rabson
805c19800e8SDoug Rabson ret = ad_get_cred(context, NULL);
806c19800e8SDoug Rabson if (ret)
807c19800e8SDoug Rabson return ret;
808c19800e8SDoug Rabson
809c19800e8SDoug Rabson ret = _kadm5_ad_connect(server_handle);
810c19800e8SDoug Rabson if (ret)
811c19800e8SDoug Rabson return ret;
812c19800e8SDoug Rabson
813c19800e8SDoug Rabson fqdn = get_fqdn(context->context, principal);
814c19800e8SDoug Rabson
815c19800e8SDoug Rabson ret = krb5_unparse_name(context->context, principal, &p);
816c19800e8SDoug Rabson if (ret)
817c19800e8SDoug Rabson return ret;
818c19800e8SDoug Rabson
819c19800e8SDoug Rabson if (ad_find_entry(context, fqdn, p, &dn) != 0) {
820c19800e8SDoug Rabson free(p);
821c19800e8SDoug Rabson return KADM5_UNK_PRINC;
822c19800e8SDoug Rabson }
823c19800e8SDoug Rabson
824c19800e8SDoug Rabson ret = ldap_delete_s(CTX2LP(context), dn);
825c19800e8SDoug Rabson
826c19800e8SDoug Rabson free(dn);
827c19800e8SDoug Rabson free(p);
828c19800e8SDoug Rabson
829c19800e8SDoug Rabson if (check_ldap(context, ret))
830c19800e8SDoug Rabson return KADM5_RPC_ERROR;
831c19800e8SDoug Rabson return 0;
832c19800e8SDoug Rabson #else
833*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
834c19800e8SDoug Rabson return KADM5_RPC_ERROR;
835c19800e8SDoug Rabson #endif
836c19800e8SDoug Rabson }
837c19800e8SDoug Rabson
838c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_destroy(void * server_handle)839c19800e8SDoug Rabson kadm5_ad_destroy(void *server_handle)
840c19800e8SDoug Rabson {
841c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
842c19800e8SDoug Rabson
843c19800e8SDoug Rabson if (context->ccache)
844c19800e8SDoug Rabson krb5_cc_destroy(context->context, context->ccache);
845c19800e8SDoug Rabson
846c19800e8SDoug Rabson #ifdef OPENLDAP
847c19800e8SDoug Rabson {
848c19800e8SDoug Rabson LDAP *lp = CTX2LP(context);
849c19800e8SDoug Rabson if (lp)
850c19800e8SDoug Rabson ldap_unbind(lp);
851c19800e8SDoug Rabson if (context->base_dn)
852c19800e8SDoug Rabson free(context->base_dn);
853c19800e8SDoug Rabson }
854c19800e8SDoug Rabson #endif
855c19800e8SDoug Rabson free(context->realm);
856c19800e8SDoug Rabson free(context->client_name);
857c19800e8SDoug Rabson krb5_free_principal(context->context, context->caller);
858c19800e8SDoug Rabson if(context->my_context)
859c19800e8SDoug Rabson krb5_free_context(context->context);
860c19800e8SDoug Rabson return 0;
861c19800e8SDoug Rabson }
862c19800e8SDoug Rabson
863c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_flush(void * server_handle)864c19800e8SDoug Rabson kadm5_ad_flush(void *server_handle)
865c19800e8SDoug Rabson {
866c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
867*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
868c19800e8SDoug Rabson return KADM5_RPC_ERROR;
869c19800e8SDoug Rabson }
870c19800e8SDoug Rabson
871c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_get_principal(void * server_handle,krb5_principal principal,kadm5_principal_ent_t entry,uint32_t mask)872c19800e8SDoug Rabson kadm5_ad_get_principal(void *server_handle,
873c19800e8SDoug Rabson krb5_principal principal,
874c19800e8SDoug Rabson kadm5_principal_ent_t entry,
875c19800e8SDoug Rabson uint32_t mask)
876c19800e8SDoug Rabson {
877c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
878c19800e8SDoug Rabson #ifdef OPENLDAP
879c19800e8SDoug Rabson LDAPMessage *m, *m0;
880c19800e8SDoug Rabson char **attr = NULL;
881c19800e8SDoug Rabson int attrlen = 0;
882c19800e8SDoug Rabson char *filter, *p, *q, *u;
883c19800e8SDoug Rabson int ret;
884c19800e8SDoug Rabson
885c19800e8SDoug Rabson /*
886c19800e8SDoug Rabson * principal
887c19800e8SDoug Rabson * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
888c19800e8SDoug Rabson */
889c19800e8SDoug Rabson
890c19800e8SDoug Rabson /*
891c19800e8SDoug Rabson * return 0 || KADM5_DUP;
892c19800e8SDoug Rabson */
893c19800e8SDoug Rabson
894c19800e8SDoug Rabson memset(entry, 0, sizeof(*entry));
895c19800e8SDoug Rabson
896c19800e8SDoug Rabson if (mask & KADM5_KVNO)
897c19800e8SDoug Rabson laddattr(&attr, &attrlen, "msDS-KeyVersionNumber");
898c19800e8SDoug Rabson
899c19800e8SDoug Rabson if (mask & KADM5_PRINCIPAL) {
900c19800e8SDoug Rabson laddattr(&attr, &attrlen, "userPrincipalName");
901c19800e8SDoug Rabson laddattr(&attr, &attrlen, "servicePrincipalName");
902c19800e8SDoug Rabson }
903c19800e8SDoug Rabson laddattr(&attr, &attrlen, "objectClass");
904c19800e8SDoug Rabson laddattr(&attr, &attrlen, "lastLogon");
905c19800e8SDoug Rabson laddattr(&attr, &attrlen, "badPwdCount");
906c19800e8SDoug Rabson laddattr(&attr, &attrlen, "badPasswordTime");
907c19800e8SDoug Rabson laddattr(&attr, &attrlen, "pwdLastSet");
908c19800e8SDoug Rabson laddattr(&attr, &attrlen, "accountExpires");
909c19800e8SDoug Rabson laddattr(&attr, &attrlen, "userAccountControl");
910c19800e8SDoug Rabson
911c19800e8SDoug Rabson krb5_unparse_name_short(context->context, principal, &p);
912c19800e8SDoug Rabson krb5_unparse_name(context->context, principal, &u);
913c19800e8SDoug Rabson
914c19800e8SDoug Rabson /* replace @ in domain part with a / */
915c19800e8SDoug Rabson q = strrchr(p, '@');
916c19800e8SDoug Rabson if (q && (p != q && *(q - 1) != '\\'))
917c19800e8SDoug Rabson *q = '/';
918c19800e8SDoug Rabson
919c19800e8SDoug Rabson asprintf(&filter,
920c19800e8SDoug Rabson "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
921c19800e8SDoug Rabson u, p, u);
922c19800e8SDoug Rabson free(p);
923c19800e8SDoug Rabson free(u);
924c19800e8SDoug Rabson
925c19800e8SDoug Rabson ret = ldap_search_s(CTX2LP(context), CTX2BASE(context),
926c19800e8SDoug Rabson LDAP_SCOPE_SUBTREE,
927c19800e8SDoug Rabson filter, attr, 0, &m);
928c19800e8SDoug Rabson free(attr);
929c19800e8SDoug Rabson if (check_ldap(context, ret))
930c19800e8SDoug Rabson return KADM5_RPC_ERROR;
931c19800e8SDoug Rabson
932c19800e8SDoug Rabson if (ldap_count_entries(CTX2LP(context), m) > 0) {
933c19800e8SDoug Rabson char **vals;
934c19800e8SDoug Rabson m0 = ldap_first_entry(CTX2LP(context), m);
935c19800e8SDoug Rabson if (m0 == NULL) {
936c19800e8SDoug Rabson ldap_msgfree(m);
937c19800e8SDoug Rabson goto fail;
938c19800e8SDoug Rabson }
939c19800e8SDoug Rabson #if 0
940c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "servicePrincipalName");
941c19800e8SDoug Rabson if (vals)
942c19800e8SDoug Rabson printf("servicePrincipalName %s\n", vals[0]);
943c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "userPrincipalName");
944c19800e8SDoug Rabson if (vals)
945c19800e8SDoug Rabson printf("userPrincipalName %s\n", vals[0]);
946c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
947c19800e8SDoug Rabson if (vals)
948c19800e8SDoug Rabson printf("userAccountControl %s\n", vals[0]);
949c19800e8SDoug Rabson #endif
950c19800e8SDoug Rabson entry->princ_expire_time = 0;
951c19800e8SDoug Rabson if (mask & KADM5_PRINC_EXPIRE_TIME) {
952c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "accountExpires");
953c19800e8SDoug Rabson if (vals)
954c19800e8SDoug Rabson entry->princ_expire_time = nt2unixtime(vals[0]);
955c19800e8SDoug Rabson }
956c19800e8SDoug Rabson entry->last_success = 0;
957c19800e8SDoug Rabson if (mask & KADM5_LAST_SUCCESS) {
958c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "lastLogon");
959c19800e8SDoug Rabson if (vals)
960c19800e8SDoug Rabson entry->last_success = nt2unixtime(vals[0]);
961c19800e8SDoug Rabson }
962c19800e8SDoug Rabson if (mask & KADM5_LAST_FAILED) {
963c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "badPasswordTime");
964c19800e8SDoug Rabson if (vals)
965c19800e8SDoug Rabson entry->last_failed = nt2unixtime(vals[0]);
966c19800e8SDoug Rabson }
967c19800e8SDoug Rabson if (mask & KADM5_LAST_PWD_CHANGE) {
968c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "pwdLastSet");
969c19800e8SDoug Rabson if (vals)
970c19800e8SDoug Rabson entry->last_pwd_change = nt2unixtime(vals[0]);
971c19800e8SDoug Rabson }
972c19800e8SDoug Rabson if (mask & KADM5_FAIL_AUTH_COUNT) {
973c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "badPwdCount");
974c19800e8SDoug Rabson if (vals)
975c19800e8SDoug Rabson entry->fail_auth_count = atoi(vals[0]);
976c19800e8SDoug Rabson }
977c19800e8SDoug Rabson if (mask & KADM5_ATTRIBUTES) {
978c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
979c19800e8SDoug Rabson if (vals) {
980c19800e8SDoug Rabson uint32_t i;
981c19800e8SDoug Rabson i = atoi(vals[0]);
982c19800e8SDoug Rabson if (i & (UF_ACCOUNTDISABLE|UF_LOCKOUT))
983c19800e8SDoug Rabson entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
984c19800e8SDoug Rabson if ((i & UF_DONT_REQUIRE_PREAUTH) == 0)
985c19800e8SDoug Rabson entry->attributes |= KRB5_KDB_REQUIRES_PRE_AUTH;
986c19800e8SDoug Rabson if (i & UF_SMARTCARD_REQUIRED)
987c19800e8SDoug Rabson entry->attributes |= KRB5_KDB_REQUIRES_HW_AUTH;
988c19800e8SDoug Rabson if ((i & UF_WORKSTATION_TRUST_ACCOUNT) == 0)
989c19800e8SDoug Rabson entry->attributes |= KRB5_KDB_DISALLOW_SVR;
990c19800e8SDoug Rabson }
991c19800e8SDoug Rabson }
992c19800e8SDoug Rabson if (mask & KADM5_KVNO) {
993c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0,
994c19800e8SDoug Rabson "msDS-KeyVersionNumber");
995c19800e8SDoug Rabson if (vals)
996c19800e8SDoug Rabson entry->kvno = atoi(vals[0]);
997c19800e8SDoug Rabson else
998c19800e8SDoug Rabson entry->kvno = 0;
999c19800e8SDoug Rabson }
1000c19800e8SDoug Rabson ldap_msgfree(m);
1001c19800e8SDoug Rabson } else {
1002c19800e8SDoug Rabson return KADM5_UNK_PRINC;
1003c19800e8SDoug Rabson }
1004c19800e8SDoug Rabson
1005c19800e8SDoug Rabson if (mask & KADM5_PRINCIPAL)
1006c19800e8SDoug Rabson krb5_copy_principal(context->context, principal, &entry->principal);
1007c19800e8SDoug Rabson
1008c19800e8SDoug Rabson return 0;
1009c19800e8SDoug Rabson fail:
1010c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1011c19800e8SDoug Rabson #else
1012*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1013c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1014c19800e8SDoug Rabson #endif
1015c19800e8SDoug Rabson }
1016c19800e8SDoug Rabson
1017c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_get_principals(void * server_handle,const char * expression,char *** principals,int * count)1018c19800e8SDoug Rabson kadm5_ad_get_principals(void *server_handle,
1019c19800e8SDoug Rabson const char *expression,
1020c19800e8SDoug Rabson char ***principals,
1021c19800e8SDoug Rabson int *count)
1022c19800e8SDoug Rabson {
1023c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1024c19800e8SDoug Rabson
1025c19800e8SDoug Rabson /*
1026c19800e8SDoug Rabson * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1027c19800e8SDoug Rabson */
1028c19800e8SDoug Rabson
1029c19800e8SDoug Rabson #ifdef OPENLDAP
1030c19800e8SDoug Rabson kadm5_ret_t ret;
1031c19800e8SDoug Rabson
1032c19800e8SDoug Rabson ret = ad_get_cred(context, NULL);
1033c19800e8SDoug Rabson if (ret)
1034c19800e8SDoug Rabson return ret;
1035c19800e8SDoug Rabson
1036c19800e8SDoug Rabson ret = _kadm5_ad_connect(server_handle);
1037c19800e8SDoug Rabson if (ret)
1038c19800e8SDoug Rabson return ret;
1039c19800e8SDoug Rabson
1040*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1041c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1042c19800e8SDoug Rabson #else
1043*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1044c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1045c19800e8SDoug Rabson #endif
1046c19800e8SDoug Rabson }
1047c19800e8SDoug Rabson
1048c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_get_privs(void * server_handle,uint32_t * privs)1049c19800e8SDoug Rabson kadm5_ad_get_privs(void *server_handle, uint32_t*privs)
1050c19800e8SDoug Rabson {
1051c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1052*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1053c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1054c19800e8SDoug Rabson }
1055c19800e8SDoug Rabson
1056c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_modify_principal(void * server_handle,kadm5_principal_ent_t entry,uint32_t mask)1057c19800e8SDoug Rabson kadm5_ad_modify_principal(void *server_handle,
1058c19800e8SDoug Rabson kadm5_principal_ent_t entry,
1059c19800e8SDoug Rabson uint32_t mask)
1060c19800e8SDoug Rabson {
1061c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1062c19800e8SDoug Rabson
1063c19800e8SDoug Rabson /*
1064c19800e8SDoug Rabson * KADM5_ATTRIBUTES
1065c19800e8SDoug Rabson * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1066c19800e8SDoug Rabson */
1067c19800e8SDoug Rabson
1068c19800e8SDoug Rabson #ifdef OPENLDAP
1069c19800e8SDoug Rabson LDAPMessage *m = NULL, *m0;
1070c19800e8SDoug Rabson kadm5_ret_t ret;
1071c19800e8SDoug Rabson char **attr = NULL;
1072c19800e8SDoug Rabson int attrlen = 0;
1073c19800e8SDoug Rabson char *p = NULL, *s = NULL, *q;
1074c19800e8SDoug Rabson char **vals;
1075c19800e8SDoug Rabson LDAPMod *attrs[4], rattrs[3], *a;
1076c19800e8SDoug Rabson char *uaf[2] = { NULL, NULL };
1077c19800e8SDoug Rabson char *kvno[2] = { NULL, NULL };
1078c19800e8SDoug Rabson char *tv[2] = { NULL, NULL };
1079c19800e8SDoug Rabson char *filter, *dn;
1080c19800e8SDoug Rabson int i;
1081c19800e8SDoug Rabson
1082c19800e8SDoug Rabson for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++)
1083c19800e8SDoug Rabson attrs[i] = &rattrs[i];
1084c19800e8SDoug Rabson attrs[i] = NULL;
1085c19800e8SDoug Rabson a = &rattrs[0];
1086c19800e8SDoug Rabson
1087c19800e8SDoug Rabson ret = _kadm5_ad_connect(server_handle);
1088c19800e8SDoug Rabson if (ret)
1089c19800e8SDoug Rabson return ret;
1090c19800e8SDoug Rabson
1091c19800e8SDoug Rabson if (mask & KADM5_KVNO)
1092c19800e8SDoug Rabson laddattr(&attr, &attrlen, "msDS-KeyVersionNumber");
1093c19800e8SDoug Rabson if (mask & KADM5_PRINC_EXPIRE_TIME)
1094c19800e8SDoug Rabson laddattr(&attr, &attrlen, "accountExpires");
1095c19800e8SDoug Rabson if (mask & KADM5_ATTRIBUTES)
1096c19800e8SDoug Rabson laddattr(&attr, &attrlen, "userAccountControl");
1097c19800e8SDoug Rabson laddattr(&attr, &attrlen, "distinguishedName");
1098c19800e8SDoug Rabson
1099c19800e8SDoug Rabson krb5_unparse_name(context->context, entry->principal, &p);
1100c19800e8SDoug Rabson
1101c19800e8SDoug Rabson s = strdup(p);
1102c19800e8SDoug Rabson
1103c19800e8SDoug Rabson q = strrchr(s, '@');
1104c19800e8SDoug Rabson if (q && (p != q && *(q - 1) != '\\'))
1105c19800e8SDoug Rabson *q = '\0';
1106c19800e8SDoug Rabson
1107c19800e8SDoug Rabson asprintf(&filter,
1108c19800e8SDoug Rabson "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1109c19800e8SDoug Rabson s, s);
1110c19800e8SDoug Rabson free(p);
1111c19800e8SDoug Rabson free(s);
1112c19800e8SDoug Rabson
1113c19800e8SDoug Rabson ret = ldap_search_s(CTX2LP(context), CTX2BASE(context),
1114c19800e8SDoug Rabson LDAP_SCOPE_SUBTREE,
1115c19800e8SDoug Rabson filter, attr, 0, &m);
1116c19800e8SDoug Rabson free(attr);
1117c19800e8SDoug Rabson free(filter);
1118c19800e8SDoug Rabson if (check_ldap(context, ret))
1119c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1120c19800e8SDoug Rabson
1121c19800e8SDoug Rabson if (ldap_count_entries(CTX2LP(context), m) <= 0) {
1122c19800e8SDoug Rabson ret = KADM5_RPC_ERROR;
1123c19800e8SDoug Rabson goto out;
1124c19800e8SDoug Rabson }
1125c19800e8SDoug Rabson
1126c19800e8SDoug Rabson m0 = ldap_first_entry(CTX2LP(context), m);
1127c19800e8SDoug Rabson
1128c19800e8SDoug Rabson if (mask & KADM5_ATTRIBUTES) {
1129c19800e8SDoug Rabson int32_t i;
1130c19800e8SDoug Rabson
1131c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
1132c19800e8SDoug Rabson if (vals == NULL) {
1133c19800e8SDoug Rabson ret = KADM5_RPC_ERROR;
1134c19800e8SDoug Rabson goto out;
1135c19800e8SDoug Rabson }
1136c19800e8SDoug Rabson
1137c19800e8SDoug Rabson i = atoi(vals[0]);
1138c19800e8SDoug Rabson if (i == 0)
1139c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1140c19800e8SDoug Rabson
1141c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX)
1142c19800e8SDoug Rabson i |= (UF_ACCOUNTDISABLE|UF_LOCKOUT);
1143c19800e8SDoug Rabson else
1144c19800e8SDoug Rabson i &= ~(UF_ACCOUNTDISABLE|UF_LOCKOUT);
1145c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH)
1146c19800e8SDoug Rabson i &= ~UF_DONT_REQUIRE_PREAUTH;
1147c19800e8SDoug Rabson else
1148c19800e8SDoug Rabson i |= UF_DONT_REQUIRE_PREAUTH;
1149c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH)
1150c19800e8SDoug Rabson i |= UF_SMARTCARD_REQUIRED;
1151c19800e8SDoug Rabson else
1152c19800e8SDoug Rabson i &= UF_SMARTCARD_REQUIRED;
1153c19800e8SDoug Rabson if (entry->attributes & KRB5_KDB_DISALLOW_SVR)
1154c19800e8SDoug Rabson i &= ~UF_WORKSTATION_TRUST_ACCOUNT;
1155c19800e8SDoug Rabson else
1156c19800e8SDoug Rabson i |= UF_WORKSTATION_TRUST_ACCOUNT;
1157c19800e8SDoug Rabson
1158c19800e8SDoug Rabson asprintf(&uaf[0], "%d", i);
1159c19800e8SDoug Rabson
1160c19800e8SDoug Rabson a->mod_op = LDAP_MOD_REPLACE;
1161c19800e8SDoug Rabson a->mod_type = "userAccountControl";
1162c19800e8SDoug Rabson a->mod_values = uaf;
1163c19800e8SDoug Rabson a++;
1164c19800e8SDoug Rabson }
1165c19800e8SDoug Rabson
1166c19800e8SDoug Rabson if (mask & KADM5_KVNO) {
1167c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "msDS-KeyVersionNumber");
1168c19800e8SDoug Rabson if (vals == NULL) {
1169c19800e8SDoug Rabson entry->kvno = 0;
1170c19800e8SDoug Rabson } else {
1171c19800e8SDoug Rabson asprintf(&kvno[0], "%d", entry->kvno);
1172c19800e8SDoug Rabson
1173c19800e8SDoug Rabson a->mod_op = LDAP_MOD_REPLACE;
1174c19800e8SDoug Rabson a->mod_type = "msDS-KeyVersionNumber";
1175c19800e8SDoug Rabson a->mod_values = kvno;
1176c19800e8SDoug Rabson a++;
1177c19800e8SDoug Rabson }
1178c19800e8SDoug Rabson }
1179c19800e8SDoug Rabson
1180c19800e8SDoug Rabson if (mask & KADM5_PRINC_EXPIRE_TIME) {
1181c19800e8SDoug Rabson long long wt;
1182c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "accountExpires");
1183c19800e8SDoug Rabson if (vals == NULL) {
1184c19800e8SDoug Rabson ret = KADM5_RPC_ERROR;
1185c19800e8SDoug Rabson goto out;
1186c19800e8SDoug Rabson }
1187c19800e8SDoug Rabson
1188c19800e8SDoug Rabson wt = unix2nttime(entry->princ_expire_time);
1189c19800e8SDoug Rabson
1190c19800e8SDoug Rabson asprintf(&tv[0], "%llu", wt);
1191c19800e8SDoug Rabson
1192c19800e8SDoug Rabson a->mod_op = LDAP_MOD_REPLACE;
1193c19800e8SDoug Rabson a->mod_type = "accountExpires";
1194c19800e8SDoug Rabson a->mod_values = tv;
1195c19800e8SDoug Rabson a++;
1196c19800e8SDoug Rabson }
1197c19800e8SDoug Rabson
1198c19800e8SDoug Rabson vals = ldap_get_values(CTX2LP(context), m0, "distinguishedName");
1199c19800e8SDoug Rabson if (vals == NULL) {
1200c19800e8SDoug Rabson ret = KADM5_RPC_ERROR;
1201c19800e8SDoug Rabson goto out;
1202c19800e8SDoug Rabson }
1203c19800e8SDoug Rabson dn = vals[0];
1204c19800e8SDoug Rabson
1205c19800e8SDoug Rabson attrs[a - &rattrs[0]] = NULL;
1206c19800e8SDoug Rabson
1207c19800e8SDoug Rabson ret = ldap_modify_s(CTX2LP(context), dn, attrs);
1208c19800e8SDoug Rabson if (check_ldap(context, ret))
1209c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1210c19800e8SDoug Rabson
1211c19800e8SDoug Rabson out:
1212c19800e8SDoug Rabson if (m)
1213c19800e8SDoug Rabson ldap_msgfree(m);
1214c19800e8SDoug Rabson if (uaf[0])
1215c19800e8SDoug Rabson free(uaf[0]);
1216c19800e8SDoug Rabson if (kvno[0])
1217c19800e8SDoug Rabson free(kvno[0]);
1218c19800e8SDoug Rabson if (tv[0])
1219c19800e8SDoug Rabson free(tv[0]);
1220c19800e8SDoug Rabson return ret;
1221c19800e8SDoug Rabson #else
1222*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1223c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1224c19800e8SDoug Rabson #endif
1225c19800e8SDoug Rabson }
1226c19800e8SDoug Rabson
1227c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_randkey_principal(void * server_handle,krb5_principal principal,krb5_keyblock ** keys,int * n_keys)1228c19800e8SDoug Rabson kadm5_ad_randkey_principal(void *server_handle,
1229c19800e8SDoug Rabson krb5_principal principal,
1230c19800e8SDoug Rabson krb5_keyblock **keys,
1231c19800e8SDoug Rabson int *n_keys)
1232c19800e8SDoug Rabson {
1233c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1234c19800e8SDoug Rabson
1235c19800e8SDoug Rabson /*
1236c19800e8SDoug Rabson * random key
1237c19800e8SDoug Rabson */
1238c19800e8SDoug Rabson
1239c19800e8SDoug Rabson #ifdef OPENLDAP
1240c19800e8SDoug Rabson krb5_data result_code_string, result_string;
1241c19800e8SDoug Rabson int result_code, plen;
1242c19800e8SDoug Rabson kadm5_ret_t ret;
1243c19800e8SDoug Rabson char *password;
1244c19800e8SDoug Rabson
1245c19800e8SDoug Rabson *keys = NULL;
1246c19800e8SDoug Rabson *n_keys = 0;
1247c19800e8SDoug Rabson
1248c19800e8SDoug Rabson {
1249c19800e8SDoug Rabson char p[64];
1250c19800e8SDoug Rabson krb5_generate_random_block(p, sizeof(p));
1251c19800e8SDoug Rabson plen = base64_encode(p, sizeof(p), &password);
1252c19800e8SDoug Rabson if (plen < 0)
1253c19800e8SDoug Rabson return ENOMEM;
1254c19800e8SDoug Rabson }
1255c19800e8SDoug Rabson
1256c19800e8SDoug Rabson ret = ad_get_cred(context, NULL);
1257c19800e8SDoug Rabson if (ret) {
1258c19800e8SDoug Rabson free(password);
1259c19800e8SDoug Rabson return ret;
1260c19800e8SDoug Rabson }
1261c19800e8SDoug Rabson
1262c19800e8SDoug Rabson krb5_data_zero (&result_code_string);
1263c19800e8SDoug Rabson krb5_data_zero (&result_string);
1264c19800e8SDoug Rabson
1265c19800e8SDoug Rabson ret = krb5_set_password_using_ccache (context->context,
1266c19800e8SDoug Rabson context->ccache,
1267c19800e8SDoug Rabson password,
1268c19800e8SDoug Rabson principal,
1269c19800e8SDoug Rabson &result_code,
1270c19800e8SDoug Rabson &result_code_string,
1271c19800e8SDoug Rabson &result_string);
1272c19800e8SDoug Rabson
1273c19800e8SDoug Rabson krb5_data_free (&result_code_string);
1274c19800e8SDoug Rabson krb5_data_free (&result_string);
1275c19800e8SDoug Rabson
1276c19800e8SDoug Rabson if (ret == 0) {
1277c19800e8SDoug Rabson
1278c19800e8SDoug Rabson *keys = malloc(sizeof(**keys) * 1);
1279c19800e8SDoug Rabson if (*keys == NULL) {
1280c19800e8SDoug Rabson ret = ENOMEM;
1281c19800e8SDoug Rabson goto out;
1282c19800e8SDoug Rabson }
1283c19800e8SDoug Rabson *n_keys = 1;
1284c19800e8SDoug Rabson
1285c19800e8SDoug Rabson ret = krb5_string_to_key(context->context,
1286c19800e8SDoug Rabson ENCTYPE_ARCFOUR_HMAC_MD5,
1287c19800e8SDoug Rabson password,
1288c19800e8SDoug Rabson principal,
1289c19800e8SDoug Rabson &(*keys)[0]);
1290c19800e8SDoug Rabson memset(password, 0, sizeof(password));
1291c19800e8SDoug Rabson if (ret) {
1292c19800e8SDoug Rabson free(*keys);
1293c19800e8SDoug Rabson *keys = NULL;
1294c19800e8SDoug Rabson *n_keys = 0;
1295c19800e8SDoug Rabson goto out;
1296c19800e8SDoug Rabson }
1297c19800e8SDoug Rabson }
1298c19800e8SDoug Rabson memset(password, 0, plen);
1299c19800e8SDoug Rabson free(password);
1300c19800e8SDoug Rabson out:
1301c19800e8SDoug Rabson return ret;
1302c19800e8SDoug Rabson #else
1303c19800e8SDoug Rabson *keys = NULL;
1304c19800e8SDoug Rabson *n_keys = 0;
1305c19800e8SDoug Rabson
1306*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1307c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1308c19800e8SDoug Rabson #endif
1309c19800e8SDoug Rabson }
1310c19800e8SDoug Rabson
1311c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_rename_principal(void * server_handle,krb5_principal from,krb5_principal to)1312c19800e8SDoug Rabson kadm5_ad_rename_principal(void *server_handle,
1313c19800e8SDoug Rabson krb5_principal from,
1314c19800e8SDoug Rabson krb5_principal to)
1315c19800e8SDoug Rabson {
1316c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1317*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1318c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1319c19800e8SDoug Rabson }
1320c19800e8SDoug Rabson
1321c19800e8SDoug Rabson static kadm5_ret_t
kadm5_ad_chpass_principal_with_key(void * server_handle,krb5_principal princ,int n_key_data,krb5_key_data * key_data)1322c19800e8SDoug Rabson kadm5_ad_chpass_principal_with_key(void *server_handle,
1323c19800e8SDoug Rabson krb5_principal princ,
1324c19800e8SDoug Rabson int n_key_data,
1325c19800e8SDoug Rabson krb5_key_data *key_data)
1326c19800e8SDoug Rabson {
1327c19800e8SDoug Rabson kadm5_ad_context *context = server_handle;
1328*ae771770SStanislav Sedov krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1329c19800e8SDoug Rabson return KADM5_RPC_ERROR;
1330c19800e8SDoug Rabson }
1331c19800e8SDoug Rabson
1332c19800e8SDoug Rabson static void
set_funcs(kadm5_ad_context * c)1333c19800e8SDoug Rabson set_funcs(kadm5_ad_context *c)
1334c19800e8SDoug Rabson {
1335c19800e8SDoug Rabson #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1336c19800e8SDoug Rabson SET(c, chpass_principal);
1337c19800e8SDoug Rabson SET(c, chpass_principal_with_key);
1338c19800e8SDoug Rabson SET(c, create_principal);
1339c19800e8SDoug Rabson SET(c, delete_principal);
1340c19800e8SDoug Rabson SET(c, destroy);
1341c19800e8SDoug Rabson SET(c, flush);
1342c19800e8SDoug Rabson SET(c, get_principal);
1343c19800e8SDoug Rabson SET(c, get_principals);
1344c19800e8SDoug Rabson SET(c, get_privs);
1345c19800e8SDoug Rabson SET(c, modify_principal);
1346c19800e8SDoug Rabson SET(c, randkey_principal);
1347c19800e8SDoug Rabson SET(c, rename_principal);
1348c19800e8SDoug Rabson }
1349c19800e8SDoug Rabson
1350c19800e8SDoug Rabson kadm5_ret_t
kadm5_ad_init_with_password_ctx(krb5_context context,const char * client_name,const char * password,const char * service_name,kadm5_config_params * realm_params,unsigned long struct_version,unsigned long api_version,void ** server_handle)1351c19800e8SDoug Rabson kadm5_ad_init_with_password_ctx(krb5_context context,
1352c19800e8SDoug Rabson const char *client_name,
1353c19800e8SDoug Rabson const char *password,
1354c19800e8SDoug Rabson const char *service_name,
1355c19800e8SDoug Rabson kadm5_config_params *realm_params,
1356c19800e8SDoug Rabson unsigned long struct_version,
1357c19800e8SDoug Rabson unsigned long api_version,
1358c19800e8SDoug Rabson void **server_handle)
1359c19800e8SDoug Rabson {
1360c19800e8SDoug Rabson kadm5_ret_t ret;
1361c19800e8SDoug Rabson kadm5_ad_context *ctx;
1362c19800e8SDoug Rabson
1363c19800e8SDoug Rabson ctx = malloc(sizeof(*ctx));
1364c19800e8SDoug Rabson if(ctx == NULL)
1365c19800e8SDoug Rabson return ENOMEM;
1366c19800e8SDoug Rabson memset(ctx, 0, sizeof(*ctx));
1367c19800e8SDoug Rabson set_funcs(ctx);
1368c19800e8SDoug Rabson
1369c19800e8SDoug Rabson ctx->context = context;
1370c19800e8SDoug Rabson krb5_add_et_list (context, initialize_kadm5_error_table_r);
1371c19800e8SDoug Rabson
1372c19800e8SDoug Rabson ret = krb5_parse_name(ctx->context, client_name, &ctx->caller);
1373c19800e8SDoug Rabson if(ret) {
1374c19800e8SDoug Rabson free(ctx);
1375c19800e8SDoug Rabson return ret;
1376c19800e8SDoug Rabson }
1377c19800e8SDoug Rabson
1378c19800e8SDoug Rabson if(realm_params->mask & KADM5_CONFIG_REALM) {
1379c19800e8SDoug Rabson ret = 0;
1380c19800e8SDoug Rabson ctx->realm = strdup(realm_params->realm);
1381c19800e8SDoug Rabson if (ctx->realm == NULL)
1382c19800e8SDoug Rabson ret = ENOMEM;
1383c19800e8SDoug Rabson } else
1384c19800e8SDoug Rabson ret = krb5_get_default_realm(ctx->context, &ctx->realm);
1385c19800e8SDoug Rabson if (ret) {
1386c19800e8SDoug Rabson free(ctx);
1387c19800e8SDoug Rabson return ret;
1388c19800e8SDoug Rabson }
1389c19800e8SDoug Rabson
1390c19800e8SDoug Rabson ctx->client_name = strdup(client_name);
1391c19800e8SDoug Rabson
1392c19800e8SDoug Rabson if(password != NULL && *password != '\0')
1393c19800e8SDoug Rabson ret = ad_get_cred(ctx, password);
1394c19800e8SDoug Rabson else
1395c19800e8SDoug Rabson ret = ad_get_cred(ctx, NULL);
1396c19800e8SDoug Rabson if(ret) {
1397c19800e8SDoug Rabson kadm5_ad_destroy(ctx);
1398c19800e8SDoug Rabson return ret;
1399c19800e8SDoug Rabson }
1400c19800e8SDoug Rabson
1401c19800e8SDoug Rabson #ifdef OPENLDAP
1402c19800e8SDoug Rabson ret = _kadm5_ad_connect(ctx);
1403c19800e8SDoug Rabson if (ret) {
1404c19800e8SDoug Rabson kadm5_ad_destroy(ctx);
1405c19800e8SDoug Rabson return ret;
1406c19800e8SDoug Rabson }
1407c19800e8SDoug Rabson #endif
1408c19800e8SDoug Rabson
1409c19800e8SDoug Rabson *server_handle = ctx;
1410c19800e8SDoug Rabson return 0;
1411c19800e8SDoug Rabson }
1412c19800e8SDoug Rabson
1413c19800e8SDoug Rabson kadm5_ret_t
kadm5_ad_init_with_password(const char * client_name,const char * password,const char * service_name,kadm5_config_params * realm_params,unsigned long struct_version,unsigned long api_version,void ** server_handle)1414c19800e8SDoug Rabson kadm5_ad_init_with_password(const char *client_name,
1415c19800e8SDoug Rabson const char *password,
1416c19800e8SDoug Rabson const char *service_name,
1417c19800e8SDoug Rabson kadm5_config_params *realm_params,
1418c19800e8SDoug Rabson unsigned long struct_version,
1419c19800e8SDoug Rabson unsigned long api_version,
1420c19800e8SDoug Rabson void **server_handle)
1421c19800e8SDoug Rabson {
1422c19800e8SDoug Rabson krb5_context context;
1423c19800e8SDoug Rabson kadm5_ret_t ret;
1424c19800e8SDoug Rabson kadm5_ad_context *ctx;
1425c19800e8SDoug Rabson
1426c19800e8SDoug Rabson ret = krb5_init_context(&context);
1427c19800e8SDoug Rabson if (ret)
1428c19800e8SDoug Rabson return ret;
1429c19800e8SDoug Rabson ret = kadm5_ad_init_with_password_ctx(context,
1430c19800e8SDoug Rabson client_name,
1431c19800e8SDoug Rabson password,
1432c19800e8SDoug Rabson service_name,
1433c19800e8SDoug Rabson realm_params,
1434c19800e8SDoug Rabson struct_version,
1435c19800e8SDoug Rabson api_version,
1436c19800e8SDoug Rabson server_handle);
1437c19800e8SDoug Rabson if(ret) {
1438c19800e8SDoug Rabson krb5_free_context(context);
1439c19800e8SDoug Rabson return ret;
1440c19800e8SDoug Rabson }
1441c19800e8SDoug Rabson ctx = *server_handle;
1442c19800e8SDoug Rabson ctx->my_context = 1;
1443c19800e8SDoug Rabson return 0;
1444c19800e8SDoug Rabson }
1445