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