xref: /minix/crypto/external/bsd/heimdal/dist/lib/kadm5/ad.c (revision 0a6a1f1d)
1 /*	$NetBSD: ad.c,v 1.3 2014/04/24 13:45:34 pettai 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");
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 
490     if (context->ccache)
491 	return 0;
492 
493     asprintf(&service, "%s/%s@%s", KRB5_TGS_NAME,
494 	     context->realm, context->realm);
495     if (service == NULL)
496 	return ENOMEM;
497 
498     ret = _kadm5_c_get_cred_cache(context->context,
499 				  context->client_name,
500 				  service,
501 				  password, krb5_prompter_posix,
502 				  NULL, NULL, &cc);
503     free(service);
504     if(ret)
505 	return ret; /* XXX */
506     context->ccache = cc;
507     return 0;
508 }
509 
510 static kadm5_ret_t
kadm5_ad_chpass_principal(void * server_handle,krb5_principal principal,const char * password)511 kadm5_ad_chpass_principal(void *server_handle,
512 			  krb5_principal principal,
513 			  const char *password)
514 {
515     kadm5_ad_context *context = server_handle;
516     krb5_data result_code_string, result_string;
517     int result_code;
518     kadm5_ret_t ret;
519 
520     ret = ad_get_cred(context, NULL);
521     if (ret)
522 	return ret;
523 
524     krb5_data_zero (&result_code_string);
525     krb5_data_zero (&result_string);
526 
527     ret = krb5_set_password_using_ccache (context->context,
528 					  context->ccache,
529 					  password,
530 					  principal,
531 					  &result_code,
532 					  &result_code_string,
533 					  &result_string);
534 
535     krb5_data_free (&result_code_string);
536     krb5_data_free (&result_string);
537 
538     /* XXX do mapping here on error codes */
539 
540     return ret;
541 }
542 
543 #ifdef OPENLDAP
544 static const char *
get_fqdn(krb5_context context,const krb5_principal p)545 get_fqdn(krb5_context context, const krb5_principal p)
546 {
547     const char *s, *hosttypes[] = { "host", "ldap", "gc", "cifs", "dns" };
548     int i;
549 
550     s = krb5_principal_get_comp_string(context, p, 0);
551     if (p == NULL)
552 	return NULL;
553 
554     for (i = 0; i < sizeof(hosttypes)/sizeof(hosttypes[0]); i++) {
555 	if (strcasecmp(s, hosttypes[i]) == 0)
556 	    return krb5_principal_get_comp_string(context, p, 1);
557     }
558     return 0;
559 }
560 #endif
561 
562 
563 static kadm5_ret_t
kadm5_ad_create_principal(void * server_handle,kadm5_principal_ent_t entry,uint32_t mask,const char * password)564 kadm5_ad_create_principal(void *server_handle,
565 			  kadm5_principal_ent_t entry,
566 			  uint32_t mask,
567 			  const char *password)
568 {
569     kadm5_ad_context *context = server_handle;
570 
571     /*
572      * KADM5_PRINC_EXPIRE_TIME
573      *
574      * return 0 || KADM5_DUP;
575      */
576 
577 #ifdef OPENLDAP
578     LDAPMod *attrs[8], rattrs[7], *a;
579     char *useraccvals[2] = { NULL, NULL },
580 	*samvals[2], *dnsvals[2], *spnvals[5], *upnvals[2], *tv[2];
581     char *ocvals_spn[] = { "top", "person", "organizationalPerson",
582 			   "user", "computer", NULL};
583     char *p, *realmless_p, *p_msrealm = NULL, *dn = NULL;
584     const char *fqdn;
585     char *s, *samname = NULL, *short_spn = NULL;
586     int ret, i;
587     int32_t uf_flags = 0;
588 
589     if ((mask & KADM5_PRINCIPAL) == 0)
590 	return KADM5_BAD_MASK;
591 
592     for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++)
593 	attrs[i] = &rattrs[i];
594     attrs[i] = NULL;
595 
596     ret = ad_get_cred(context, NULL);
597     if (ret)
598 	return ret;
599 
600     ret = _kadm5_ad_connect(server_handle);
601     if (ret)
602 	return ret;
603 
604     fqdn = get_fqdn(context->context, entry->principal);
605 
606     ret = krb5_unparse_name(context->context, entry->principal, &p);
607     if (ret)
608 	return ret;
609 
610     if (ad_find_entry(context, fqdn, p, NULL) == 0) {
611 	free(p);
612 	return KADM5_DUP;
613     }
614 
615     if (mask & KADM5_ATTRIBUTES) {
616 	if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX)
617 	    uf_flags |= UF_ACCOUNTDISABLE|UF_LOCKOUT;
618 	if ((entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH) == 0)
619 	    uf_flags |= UF_DONT_REQUIRE_PREAUTH;
620 	if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH)
621 	    uf_flags |= UF_SMARTCARD_REQUIRED;
622     }
623 
624     realmless_p = strdup(p);
625     if (realmless_p == NULL) {
626 	ret = ENOMEM;
627 	goto out;
628     }
629     s = strrchr(realmless_p, '@');
630     if (s)
631 	*s = '\0';
632 
633     if (fqdn) {
634 	/* create computer account */
635 	asprintf(&samname, "%s$", fqdn);
636 	if (samname == NULL) {
637 	    ret = ENOMEM;
638 	    goto out;
639 	}
640 	s = strchr(samname, '.');
641 	if (s) {
642 	    s[0] = '$';
643 	    s[1] = '\0';
644 	}
645 
646 	short_spn = strdup(p);
647 	if (short_spn == NULL) {
648 	    errno = ENOMEM;
649 	    goto out;
650 	}
651 	s = strchr(short_spn, '.');
652 	if (s) {
653 	    *s = '\0';
654 	} else {
655 	    free(short_spn);
656 	    short_spn = NULL;
657 	}
658 
659 	p_msrealm = strdup(p);
660 	if (p_msrealm == NULL) {
661 	    errno = ENOMEM;
662 	    goto out;
663 	}
664 	s = strrchr(p_msrealm, '@');
665 	if (s) {
666 	    *s = '/';
667 	} else {
668 	    free(p_msrealm);
669 	    p_msrealm = NULL;
670 	}
671 
672 	asprintf(&dn, "cn=%s, cn=Computers, %s", fqdn, CTX2BASE(context));
673 	if (dn == NULL) {
674 	    ret = ENOMEM;
675 	    goto out;
676 	}
677 
678 	a = &rattrs[0];
679 	a->mod_op = LDAP_MOD_ADD;
680 	a->mod_type = "objectClass";
681 	a->mod_values = ocvals_spn;
682 	a++;
683 
684 	a->mod_op = LDAP_MOD_ADD;
685 	a->mod_type = "userAccountControl";
686 	a->mod_values = useraccvals;
687 	asprintf(&useraccvals[0], "%d",
688 		 uf_flags |
689 		 UF_PASSWD_NOT_EXPIRE |
690 		 UF_WORKSTATION_TRUST_ACCOUNT);
691 	useraccvals[1] = NULL;
692 	a++;
693 
694 	a->mod_op = LDAP_MOD_ADD;
695 	a->mod_type = "sAMAccountName";
696 	a->mod_values = samvals;
697 	samvals[0] = samname;
698 	samvals[1] = NULL;
699 	a++;
700 
701 	a->mod_op = LDAP_MOD_ADD;
702 	a->mod_type = "dNSHostName";
703 	a->mod_values = dnsvals;
704 	dnsvals[0] = (char *)fqdn;
705 	dnsvals[1] = NULL;
706 	a++;
707 
708 	/* XXX  add even more spn's */
709 	a->mod_op = LDAP_MOD_ADD;
710 	a->mod_type = "servicePrincipalName";
711 	a->mod_values = spnvals;
712 	i = 0;
713 	spnvals[i++] = p;
714 	spnvals[i++] = realmless_p;
715 	if (short_spn)
716 	    spnvals[i++] = short_spn;
717 	if (p_msrealm)
718 	    spnvals[i++] = p_msrealm;
719 	spnvals[i++] = NULL;
720 	a++;
721 
722 	a->mod_op = LDAP_MOD_ADD;
723 	a->mod_type = "userPrincipalName";
724 	a->mod_values = upnvals;
725 	upnvals[0] = p;
726 	upnvals[1] = NULL;
727 	a++;
728 
729 	a->mod_op = LDAP_MOD_ADD;
730 	a->mod_type = "accountExpires";
731 	a->mod_values = tv;
732 	tv[0] = "9223372036854775807"; /* "never" */
733 	tv[1] = NULL;
734 	a++;
735 
736     } else {
737 	/* create user account */
738 
739 	a = &rattrs[0];
740 	a->mod_op = LDAP_MOD_ADD;
741 	a->mod_type = "userAccountControl";
742 	a->mod_values = useraccvals;
743 	asprintf(&useraccvals[0], "%d",
744 		 uf_flags |
745 		 UF_PASSWD_NOT_EXPIRE);
746 	useraccvals[1] = NULL;
747 	a++;
748 
749 	a->mod_op = LDAP_MOD_ADD;
750 	a->mod_type = "sAMAccountName";
751 	a->mod_values = samvals;
752 	samvals[0] = realmless_p;
753 	samvals[1] = NULL;
754 	a++;
755 
756 	a->mod_op = LDAP_MOD_ADD;
757 	a->mod_type = "userPrincipalName";
758 	a->mod_values = upnvals;
759 	upnvals[0] = p;
760 	upnvals[1] = NULL;
761 	a++;
762 
763 	a->mod_op = LDAP_MOD_ADD;
764 	a->mod_type = "accountExpires";
765 	a->mod_values = tv;
766 	tv[0] = "9223372036854775807"; /* "never" */
767 	tv[1] = NULL;
768 	a++;
769     }
770 
771     attrs[a - &rattrs[0]] = NULL;
772 
773     ret = ldap_add_s(CTX2LP(context), dn, attrs);
774 
775  out:
776     if (useraccvals[0])
777 	free(useraccvals[0]);
778     if (realmless_p)
779 	free(realmless_p);
780     if (samname)
781 	free(samname);
782     if (short_spn)
783 	free(short_spn);
784     if (p_msrealm)
785 	free(p_msrealm);
786     free(p);
787 
788     if (check_ldap(context, ret))
789 	return KADM5_RPC_ERROR;
790 
791     return 0;
792 #else
793     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
794     return KADM5_RPC_ERROR;
795 #endif
796 }
797 
798 static kadm5_ret_t
kadm5_ad_delete_principal(void * server_handle,krb5_principal principal)799 kadm5_ad_delete_principal(void *server_handle, krb5_principal principal)
800 {
801     kadm5_ad_context *context = server_handle;
802 #ifdef OPENLDAP
803     char *p, *dn = NULL;
804     const char *fqdn;
805     int ret;
806 
807     ret = ad_get_cred(context, NULL);
808     if (ret)
809 	return ret;
810 
811     ret = _kadm5_ad_connect(server_handle);
812     if (ret)
813 	return ret;
814 
815     fqdn = get_fqdn(context->context, principal);
816 
817     ret = krb5_unparse_name(context->context, principal, &p);
818     if (ret)
819 	return ret;
820 
821     if (ad_find_entry(context, fqdn, p, &dn) != 0) {
822 	free(p);
823 	return KADM5_UNK_PRINC;
824     }
825 
826     ret = ldap_delete_s(CTX2LP(context), dn);
827 
828     free(dn);
829     free(p);
830 
831     if (check_ldap(context, ret))
832 	return KADM5_RPC_ERROR;
833     return 0;
834 #else
835     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
836     return KADM5_RPC_ERROR;
837 #endif
838 }
839 
840 static kadm5_ret_t
kadm5_ad_destroy(void * server_handle)841 kadm5_ad_destroy(void *server_handle)
842 {
843     kadm5_ad_context *context = server_handle;
844 
845     if (context->ccache)
846 	krb5_cc_destroy(context->context, context->ccache);
847 
848 #ifdef OPENLDAP
849     {
850 	LDAP *lp = CTX2LP(context);
851 	if (lp)
852 	    ldap_unbind(lp);
853 	if (context->base_dn)
854 	    free(context->base_dn);
855     }
856 #endif
857     free(context->realm);
858     free(context->client_name);
859     krb5_free_principal(context->context, context->caller);
860     if(context->my_context)
861 	krb5_free_context(context->context);
862     return 0;
863 }
864 
865 static kadm5_ret_t
kadm5_ad_flush(void * server_handle)866 kadm5_ad_flush(void *server_handle)
867 {
868     kadm5_ad_context *context = server_handle;
869     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
870     return KADM5_RPC_ERROR;
871 }
872 
873 static kadm5_ret_t
kadm5_ad_get_principal(void * server_handle,krb5_principal principal,kadm5_principal_ent_t entry,uint32_t mask)874 kadm5_ad_get_principal(void *server_handle,
875 		       krb5_principal principal,
876 		       kadm5_principal_ent_t entry,
877 		       uint32_t mask)
878 {
879     kadm5_ad_context *context = server_handle;
880 #ifdef OPENLDAP
881     LDAPMessage *m, *m0;
882     char **attr = NULL;
883     int attrlen = 0;
884     char *filter, *p, *q, *u;
885     int ret;
886 
887     /*
888      * principal
889      * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
890      */
891 
892     /*
893      * return 0 || KADM5_DUP;
894      */
895 
896     memset(entry, 0, sizeof(*entry));
897 
898     if (mask & KADM5_KVNO)
899 	laddattr(&attr, &attrlen, "msDS-KeyVersionNumber");
900 
901     if (mask & KADM5_PRINCIPAL) {
902 	laddattr(&attr, &attrlen, "userPrincipalName");
903 	laddattr(&attr, &attrlen, "servicePrincipalName");
904     }
905     laddattr(&attr, &attrlen, "objectClass");
906     laddattr(&attr, &attrlen, "lastLogon");
907     laddattr(&attr, &attrlen, "badPwdCount");
908     laddattr(&attr, &attrlen, "badPasswordTime");
909     laddattr(&attr, &attrlen, "pwdLastSet");
910     laddattr(&attr, &attrlen, "accountExpires");
911     laddattr(&attr, &attrlen, "userAccountControl");
912 
913     krb5_unparse_name_short(context->context, principal, &p);
914     krb5_unparse_name(context->context, principal, &u);
915 
916     /* replace @ in domain part with a / */
917     q = strrchr(p, '@');
918     if (q && (p != q && *(q - 1) != '\\'))
919 	*q = '/';
920 
921     asprintf(&filter,
922 	     "(|(userPrincipalName=%s)(servicePrincipalName=%s)(servicePrincipalName=%s))",
923 	     u, p, u);
924     free(p);
925     free(u);
926 
927     ret = ldap_search_s(CTX2LP(context), CTX2BASE(context),
928 			LDAP_SCOPE_SUBTREE,
929 			filter, attr, 0, &m);
930     free(attr);
931     if (check_ldap(context, ret))
932 	return KADM5_RPC_ERROR;
933 
934     if (ldap_count_entries(CTX2LP(context), m) > 0) {
935 	char **vals;
936 	m0 = ldap_first_entry(CTX2LP(context), m);
937 	if (m0 == NULL) {
938 	    ldap_msgfree(m);
939 	    goto fail;
940 	}
941 #if 0
942 	vals = ldap_get_values(CTX2LP(context), m0, "servicePrincipalName");
943 	if (vals)
944 	    printf("servicePrincipalName %s\n", vals[0]);
945 	vals = ldap_get_values(CTX2LP(context), m0, "userPrincipalName");
946 	if (vals)
947 	    printf("userPrincipalName %s\n", vals[0]);
948 	vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
949 	if (vals)
950 	    printf("userAccountControl %s\n", vals[0]);
951 #endif
952 	entry->princ_expire_time = 0;
953 	if (mask & KADM5_PRINC_EXPIRE_TIME) {
954 	    vals = ldap_get_values(CTX2LP(context), m0, "accountExpires");
955 	    if (vals)
956 		entry->princ_expire_time = nt2unixtime(vals[0]);
957 	}
958 	entry->last_success = 0;
959 	if (mask & KADM5_LAST_SUCCESS) {
960 	    vals = ldap_get_values(CTX2LP(context), m0, "lastLogon");
961 	    if (vals)
962 		entry->last_success = nt2unixtime(vals[0]);
963 	}
964 	if (mask & KADM5_LAST_FAILED) {
965 	    vals = ldap_get_values(CTX2LP(context), m0, "badPasswordTime");
966 	    if (vals)
967 		entry->last_failed = nt2unixtime(vals[0]);
968 	}
969 	if (mask & KADM5_LAST_PWD_CHANGE) {
970 	    vals = ldap_get_values(CTX2LP(context), m0, "pwdLastSet");
971 	    if (vals)
972 		entry->last_pwd_change = nt2unixtime(vals[0]);
973 	}
974 	if (mask & KADM5_FAIL_AUTH_COUNT) {
975 	    vals = ldap_get_values(CTX2LP(context), m0, "badPwdCount");
976 	    if (vals)
977 		entry->fail_auth_count = atoi(vals[0]);
978 	}
979  	if (mask & KADM5_ATTRIBUTES) {
980 	    vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
981 	    if (vals) {
982 		uint32_t i;
983 		i = atoi(vals[0]);
984 		if (i & (UF_ACCOUNTDISABLE|UF_LOCKOUT))
985 		    entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
986 		if ((i & UF_DONT_REQUIRE_PREAUTH) == 0)
987 		    entry->attributes |= KRB5_KDB_REQUIRES_PRE_AUTH;
988 		if (i & UF_SMARTCARD_REQUIRED)
989 		    entry->attributes |= KRB5_KDB_REQUIRES_HW_AUTH;
990 		if ((i & UF_WORKSTATION_TRUST_ACCOUNT) == 0)
991 		    entry->attributes |= KRB5_KDB_DISALLOW_SVR;
992 	    }
993 	}
994 	if (mask & KADM5_KVNO) {
995 	    vals = ldap_get_values(CTX2LP(context), m0,
996 				   "msDS-KeyVersionNumber");
997 	    if (vals)
998 		entry->kvno = atoi(vals[0]);
999 	    else
1000 		entry->kvno = 0;
1001 	}
1002 	ldap_msgfree(m);
1003     } else {
1004 	return KADM5_UNK_PRINC;
1005     }
1006 
1007     if (mask & KADM5_PRINCIPAL)
1008 	krb5_copy_principal(context->context, principal, &entry->principal);
1009 
1010     return 0;
1011  fail:
1012     return KADM5_RPC_ERROR;
1013 #else
1014     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1015     return KADM5_RPC_ERROR;
1016 #endif
1017 }
1018 
1019 static kadm5_ret_t
kadm5_ad_get_principals(void * server_handle,const char * expression,char *** principals,int * count)1020 kadm5_ad_get_principals(void *server_handle,
1021 			const char *expression,
1022 			char ***principals,
1023 			int *count)
1024 {
1025     kadm5_ad_context *context = server_handle;
1026 
1027     /*
1028      * KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES
1029      */
1030 
1031 #ifdef OPENLDAP
1032     kadm5_ret_t ret;
1033 
1034     ret = ad_get_cred(context, NULL);
1035     if (ret)
1036 	return ret;
1037 
1038     ret = _kadm5_ad_connect(server_handle);
1039     if (ret)
1040 	return ret;
1041 
1042     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1043     return KADM5_RPC_ERROR;
1044 #else
1045     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1046     return KADM5_RPC_ERROR;
1047 #endif
1048 }
1049 
1050 static kadm5_ret_t
kadm5_ad_get_privs(void * server_handle,uint32_t * privs)1051 kadm5_ad_get_privs(void *server_handle, uint32_t*privs)
1052 {
1053     kadm5_ad_context *context = server_handle;
1054     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1055     return KADM5_RPC_ERROR;
1056 }
1057 
1058 static kadm5_ret_t
kadm5_ad_modify_principal(void * server_handle,kadm5_principal_ent_t entry,uint32_t mask)1059 kadm5_ad_modify_principal(void *server_handle,
1060 			  kadm5_principal_ent_t entry,
1061 			  uint32_t mask)
1062 {
1063     kadm5_ad_context *context = server_handle;
1064 
1065     /*
1066      * KADM5_ATTRIBUTES
1067      * KRB5_KDB_DISALLOW_ALL_TIX (| KADM5_KVNO)
1068      */
1069 
1070 #ifdef OPENLDAP
1071     LDAPMessage *m = NULL, *m0;
1072     kadm5_ret_t ret;
1073     char **attr = NULL;
1074     int attrlen = 0;
1075     char *p = NULL, *s = NULL, *q;
1076     char **vals;
1077     LDAPMod *attrs[4], rattrs[3], *a;
1078     char *uaf[2] = { NULL, NULL };
1079     char *kvno[2] = { NULL, NULL };
1080     char *tv[2] = { NULL, NULL };
1081     char *filter, *dn;
1082     int i;
1083 
1084     for (i = 0; i < sizeof(rattrs)/sizeof(rattrs[0]); i++)
1085 	attrs[i] = &rattrs[i];
1086     attrs[i] = NULL;
1087     a = &rattrs[0];
1088 
1089     ret = _kadm5_ad_connect(server_handle);
1090     if (ret)
1091 	return ret;
1092 
1093     if (mask & KADM5_KVNO)
1094 	laddattr(&attr, &attrlen, "msDS-KeyVersionNumber");
1095     if (mask & KADM5_PRINC_EXPIRE_TIME)
1096 	laddattr(&attr, &attrlen, "accountExpires");
1097     if (mask & KADM5_ATTRIBUTES)
1098 	laddattr(&attr, &attrlen, "userAccountControl");
1099     laddattr(&attr, &attrlen, "distinguishedName");
1100 
1101     krb5_unparse_name(context->context, entry->principal, &p);
1102 
1103     s = strdup(p);
1104 
1105     q = strrchr(s, '@');
1106     if (q && (p != q && *(q - 1) != '\\'))
1107 	*q = '\0';
1108 
1109     asprintf(&filter,
1110 	     "(|(userPrincipalName=%s)(servicePrincipalName=%s))",
1111 	     s, s);
1112     free(p);
1113     free(s);
1114 
1115     ret = ldap_search_s(CTX2LP(context), CTX2BASE(context),
1116 			LDAP_SCOPE_SUBTREE,
1117 			filter, attr, 0, &m);
1118     free(attr);
1119     free(filter);
1120     if (check_ldap(context, ret))
1121 	return KADM5_RPC_ERROR;
1122 
1123     if (ldap_count_entries(CTX2LP(context), m) <= 0) {
1124 	ret = KADM5_RPC_ERROR;
1125 	goto out;
1126     }
1127 
1128     m0 = ldap_first_entry(CTX2LP(context), m);
1129 
1130     if (mask & KADM5_ATTRIBUTES) {
1131 	int32_t i;
1132 
1133 	vals = ldap_get_values(CTX2LP(context), m0, "userAccountControl");
1134 	if (vals == NULL) {
1135 	    ret = KADM5_RPC_ERROR;
1136 	    goto out;
1137 	}
1138 
1139 	i = atoi(vals[0]);
1140 	if (i == 0)
1141 	    return KADM5_RPC_ERROR;
1142 
1143 	if (entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX)
1144 	    i |= (UF_ACCOUNTDISABLE|UF_LOCKOUT);
1145 	else
1146 	    i &= ~(UF_ACCOUNTDISABLE|UF_LOCKOUT);
1147 	if (entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH)
1148 	    i &= ~UF_DONT_REQUIRE_PREAUTH;
1149 	else
1150 	    i |= UF_DONT_REQUIRE_PREAUTH;
1151 	if (entry->attributes & KRB5_KDB_REQUIRES_HW_AUTH)
1152 	    i |= UF_SMARTCARD_REQUIRED;
1153 	else
1154 	    i &= UF_SMARTCARD_REQUIRED;
1155 	if (entry->attributes & KRB5_KDB_DISALLOW_SVR)
1156 	    i &= ~UF_WORKSTATION_TRUST_ACCOUNT;
1157 	else
1158 	    i |= UF_WORKSTATION_TRUST_ACCOUNT;
1159 
1160 	asprintf(&uaf[0], "%d", i);
1161 
1162 	a->mod_op = LDAP_MOD_REPLACE;
1163 	a->mod_type = "userAccountControl";
1164 	a->mod_values = uaf;
1165 	a++;
1166     }
1167 
1168     if (mask & KADM5_KVNO) {
1169 	vals = ldap_get_values(CTX2LP(context), m0, "msDS-KeyVersionNumber");
1170 	if (vals == NULL) {
1171 	    entry->kvno = 0;
1172 	} else {
1173 	    asprintf(&kvno[0], "%d", entry->kvno);
1174 
1175 	    a->mod_op = LDAP_MOD_REPLACE;
1176 	    a->mod_type = "msDS-KeyVersionNumber";
1177 	    a->mod_values = kvno;
1178 	    a++;
1179 	}
1180     }
1181 
1182     if (mask & KADM5_PRINC_EXPIRE_TIME) {
1183 	long long wt;
1184 	vals = ldap_get_values(CTX2LP(context), m0, "accountExpires");
1185 	if (vals == NULL) {
1186 	    ret = KADM5_RPC_ERROR;
1187 	    goto out;
1188 	}
1189 
1190 	wt = unix2nttime(entry->princ_expire_time);
1191 
1192 	asprintf(&tv[0], "%llu", wt);
1193 
1194 	a->mod_op = LDAP_MOD_REPLACE;
1195 	a->mod_type = "accountExpires";
1196 	a->mod_values = tv;
1197 	a++;
1198     }
1199 
1200     vals = ldap_get_values(CTX2LP(context), m0, "distinguishedName");
1201     if (vals == NULL) {
1202 	ret = KADM5_RPC_ERROR;
1203 	goto out;
1204     }
1205     dn = vals[0];
1206 
1207     attrs[a - &rattrs[0]] = NULL;
1208 
1209     ret = ldap_modify_s(CTX2LP(context), dn, attrs);
1210     if (check_ldap(context, ret))
1211 	return KADM5_RPC_ERROR;
1212 
1213  out:
1214     if (m)
1215 	ldap_msgfree(m);
1216     if (uaf[0])
1217 	free(uaf[0]);
1218     if (kvno[0])
1219 	free(kvno[0]);
1220     if (tv[0])
1221 	free(tv[0]);
1222     return ret;
1223 #else
1224     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1225     return KADM5_RPC_ERROR;
1226 #endif
1227 }
1228 
1229 static kadm5_ret_t
kadm5_ad_randkey_principal(void * server_handle,krb5_principal principal,krb5_keyblock ** keys,int * n_keys)1230 kadm5_ad_randkey_principal(void *server_handle,
1231 			   krb5_principal principal,
1232 			   krb5_keyblock **keys,
1233 			   int *n_keys)
1234 {
1235     kadm5_ad_context *context = server_handle;
1236 
1237     /*
1238      * random key
1239      */
1240 
1241 #ifdef OPENLDAP
1242     krb5_data result_code_string, result_string;
1243     int result_code, plen;
1244     kadm5_ret_t ret;
1245     char *password;
1246 
1247     *keys = NULL;
1248     *n_keys = 0;
1249 
1250     {
1251 	char p[64];
1252 	krb5_generate_random_block(p, sizeof(p));
1253 	plen = base64_encode(p, sizeof(p), &password);
1254 	if (plen < 0)
1255 	    return ENOMEM;
1256     }
1257 
1258     ret = ad_get_cred(context, NULL);
1259     if (ret) {
1260 	free(password);
1261 	return ret;
1262     }
1263 
1264     krb5_data_zero (&result_code_string);
1265     krb5_data_zero (&result_string);
1266 
1267     ret = krb5_set_password_using_ccache (context->context,
1268 					  context->ccache,
1269 					  password,
1270 					  principal,
1271 					  &result_code,
1272 					  &result_code_string,
1273 					  &result_string);
1274 
1275     krb5_data_free (&result_code_string);
1276     krb5_data_free (&result_string);
1277 
1278     if (ret == 0) {
1279 
1280 	*keys = malloc(sizeof(**keys) * 1);
1281 	if (*keys == NULL) {
1282 	    ret = ENOMEM;
1283 	    goto out;
1284 	}
1285 	*n_keys = 1;
1286 
1287 	ret = krb5_string_to_key(context->context,
1288 				 ENCTYPE_ARCFOUR_HMAC_MD5,
1289 				 password,
1290 				 principal,
1291 				 &(*keys)[0]);
1292 	memset(password, 0, plen);
1293 	if (ret) {
1294 	    free(*keys);
1295 	    *keys = NULL;
1296 	    *n_keys = 0;
1297 	    goto out;
1298 	}
1299     }
1300     memset(password, 0, plen);
1301     free(password);
1302  out:
1303     return ret;
1304 #else
1305     *keys = NULL;
1306     *n_keys = 0;
1307 
1308     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1309     return KADM5_RPC_ERROR;
1310 #endif
1311 }
1312 
1313 static kadm5_ret_t
kadm5_ad_rename_principal(void * server_handle,krb5_principal from,krb5_principal to)1314 kadm5_ad_rename_principal(void *server_handle,
1315 			  krb5_principal from,
1316 			  krb5_principal to)
1317 {
1318     kadm5_ad_context *context = server_handle;
1319     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1320     return KADM5_RPC_ERROR;
1321 }
1322 
1323 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)1324 kadm5_ad_chpass_principal_with_key(void *server_handle,
1325 				   krb5_principal princ,
1326 				   int n_key_data,
1327 				   krb5_key_data *key_data)
1328 {
1329     kadm5_ad_context *context = server_handle;
1330     krb5_set_error_message(context->context, KADM5_RPC_ERROR, "Function not implemented");
1331     return KADM5_RPC_ERROR;
1332 }
1333 
1334 static void
set_funcs(kadm5_ad_context * c)1335 set_funcs(kadm5_ad_context *c)
1336 {
1337 #define SET(C, F) (C)->funcs.F = kadm5_ad_ ## F
1338     SET(c, chpass_principal);
1339     SET(c, chpass_principal_with_key);
1340     SET(c, create_principal);
1341     SET(c, delete_principal);
1342     SET(c, destroy);
1343     SET(c, flush);
1344     SET(c, get_principal);
1345     SET(c, get_principals);
1346     SET(c, get_privs);
1347     SET(c, modify_principal);
1348     SET(c, randkey_principal);
1349     SET(c, rename_principal);
1350 }
1351 
1352 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)1353 kadm5_ad_init_with_password_ctx(krb5_context context,
1354 				const char *client_name,
1355 				const char *password,
1356 				const char *service_name,
1357 				kadm5_config_params *realm_params,
1358 				unsigned long struct_version,
1359 				unsigned long api_version,
1360 				void **server_handle)
1361 {
1362     kadm5_ret_t ret;
1363     kadm5_ad_context *ctx;
1364 
1365     ctx = malloc(sizeof(*ctx));
1366     if(ctx == NULL)
1367 	return ENOMEM;
1368     memset(ctx, 0, sizeof(*ctx));
1369     set_funcs(ctx);
1370 
1371     ctx->context = context;
1372     krb5_add_et_list (context, initialize_kadm5_error_table_r);
1373 
1374     ret = krb5_parse_name(ctx->context, client_name, &ctx->caller);
1375     if(ret) {
1376 	free(ctx);
1377 	return ret;
1378     }
1379 
1380     if(realm_params->mask & KADM5_CONFIG_REALM) {
1381 	ret = 0;
1382 	ctx->realm = strdup(realm_params->realm);
1383 	if (ctx->realm == NULL)
1384 	    ret = ENOMEM;
1385     } else
1386 	ret = krb5_get_default_realm(ctx->context, &ctx->realm);
1387     if (ret) {
1388 	free(ctx);
1389 	return ret;
1390     }
1391 
1392     ctx->client_name = strdup(client_name);
1393 
1394     if(password != NULL && *password != '\0')
1395 	ret = ad_get_cred(ctx, password);
1396     else
1397 	ret = ad_get_cred(ctx, NULL);
1398     if(ret) {
1399 	kadm5_ad_destroy(ctx);
1400 	return ret;
1401     }
1402 
1403 #ifdef OPENLDAP
1404     ret = _kadm5_ad_connect(ctx);
1405     if (ret) {
1406 	kadm5_ad_destroy(ctx);
1407 	return ret;
1408     }
1409 #endif
1410 
1411     *server_handle = ctx;
1412     return 0;
1413 }
1414 
1415 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)1416 kadm5_ad_init_with_password(const char *client_name,
1417 			    const char *password,
1418 			    const char *service_name,
1419 			    kadm5_config_params *realm_params,
1420 			    unsigned long struct_version,
1421 			    unsigned long api_version,
1422 			    void **server_handle)
1423 {
1424     krb5_context context;
1425     kadm5_ret_t ret;
1426     kadm5_ad_context *ctx;
1427 
1428     ret = krb5_init_context(&context);
1429     if (ret)
1430 	return ret;
1431     ret = kadm5_ad_init_with_password_ctx(context,
1432 					  client_name,
1433 					  password,
1434 					  service_name,
1435 					  realm_params,
1436 					  struct_version,
1437 					  api_version,
1438 					  server_handle);
1439     if(ret) {
1440 	krb5_free_context(context);
1441 	return ret;
1442     }
1443     ctx = *server_handle;
1444     ctx->my_context = 1;
1445     return 0;
1446 }
1447