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