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