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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 1362 kadm5_ad_lock(void *server_handle) 1363 { 1364 return ENOTSUP; 1365 } 1366 1367 static kadm5_ret_t 1368 kadm5_ad_unlock(void *server_handle) 1369 { 1370 return ENOTSUP; 1371 } 1372 1373 static void 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 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 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