1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * lib/kdb/kdb_ldap/ldap_misc.c
5 * Copyright (c) 2004-2005, Novell, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * The copyright holder's name is not used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
33 * Use is subject to license terms.
38 #include "ldap_misc.h"
39 #include "ldap_handle.h"
41 #include "ldap_principal.h"
42 #include "princ_xdr.h"
43 #include "ldap_pwd_policy.h"
45 #ifdef NEED_STRPTIME_PROTO
46 extern char *strptime (const char *, const char *, struct tm *);
49 static krb5_error_code
50 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount,
53 /* Linux (GNU Libc) provides a length-limited variant of strdup.
54 But all the world's not Linux. */
56 #define strndup my_strndup
57 #ifdef HAVE_LDAP_STR2DN
59 my_strndup(const char *input, size_t limit)
61 size_t len = strlen(input);
64 result = malloc(1 + limit);
66 memcpy(result, input, limit);
75 /* Get integer or string values from the config section, falling back
76 to the default section, then to hard-coded values. */
78 prof_get_integer_def(krb5_context ctx, const char *conf_section,
79 const char *name, int dfl, krb5_ui_4 *out)
84 err = profile_get_integer (ctx->profile,
85 KDB_MODULE_SECTION, conf_section, name,
88 krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
89 name, error_message(err));
96 err = profile_get_integer (ctx->profile,
97 KDB_MODULE_DEF_SECTION, name, 0,
100 krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
101 name, error_message(err));
108 /* Get integer or string values from the config section, falling back
109 to the default section, then to hard-coded values. */
111 prof_get_boolean_def(krb5_context ctx, const char *conf_section,
112 const char *name, krb5_boolean dfl, krb5_boolean *out)
117 err = profile_get_boolean(ctx->profile, KDB_MODULE_SECTION, conf_section,
118 name, -1, &out_temp);
120 krb5_set_error_message(ctx, err, "Error reading '%s' attribute: %s",
121 name, error_message(err));
124 if (out_temp != -1) {
128 err = profile_get_boolean(ctx->profile, KDB_MODULE_DEF_SECTION, name, 0,
131 krb5_set_error_message(ctx, err, "Error reading '%s' attribute: %s",
132 name, error_message(err));
139 /* We don't have non-null defaults in any of our calls, so don't
140 bother with the extra argument. */
142 prof_get_string_def(krb5_context ctx, const char *conf_section,
143 const char *name, char **out)
147 err = profile_get_string (ctx->profile,
148 KDB_MODULE_SECTION, conf_section, name,
151 krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
152 name, error_message(err));
157 err = profile_get_string (ctx->profile,
158 KDB_MODULE_DEF_SECTION, name, 0,
161 krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
162 name, error_message(err));
171 * This function reads the parameters from the krb5.conf file. The
172 * parameters read here are DAL-LDAP specific attributes. Some of
173 * these are ldap_server ....
176 krb5_ldap_read_server_params(krb5_context context, char *conf_section,
179 char *tempval=NULL, *save_ptr=NULL;
180 const char *delims="\t\n\f\v\r ,";
181 krb5_error_code st=0;
182 kdb5_dal_handle *dal_handle=NULL;
183 krb5_ldap_context *ldap_context=NULL;
184 krb5_ldap_server_info ***server_info=NULL;
186 dal_handle = context->dal_handle;
187 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
189 /* copy the conf_section into ldap_context for later use */
191 ldap_context->conf_section = strdup (conf_section);
192 if (ldap_context->conf_section == NULL) {
198 /* initialize the mutexs and condition variable */
199 /* this portion logically doesn't fit here should be moved appropriately */
201 /* this mutex is used in ldap reconnection pool */
202 if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) {
203 st = KRB5_KDB_SERVER_INTERNAL_ERR;
206 krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st,
207 "k5_mutex_init failed");
213 * If max_server_conns is not set read it from database module
214 * section of conf file this parameter defines maximum ldap
215 * connections per ldap server.
217 if (ldap_context->max_server_conns == 0) {
218 st = prof_get_integer_def (context, conf_section,
219 KRB5_CONF_LDAP_CONNS_PER_SERVER,
220 DEFAULT_CONNS_PER_SERVER,
221 &ldap_context->max_server_conns);
226 if (ldap_context->max_server_conns < 2) {
228 krb5_set_error_message (context, st,
229 "Minimum connections required per server is 2");
234 * If the bind dn is not set read it from the database module
235 * section of conf file this paramter is populated by one of the
236 * KDC, ADMIN or PASSWD dn to be used to connect to LDAP
237 * server. The srv_type decides which dn to read.
239 if (ldap_context->bind_dn == NULL) {
241 if (srv_type == KRB5_KDB_SRV_TYPE_KDC)
242 name = KRB5_CONF_LDAP_KDC_DN;
243 else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN)
244 name = KRB5_CONF_LDAP_KADMIN_DN;
245 else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD)
246 name = "ldap_kpasswdd_dn";
249 st = prof_get_string_def (context, conf_section, name,
250 &ldap_context->bind_dn);
257 * Read service_password_file parameter from database module
258 * section of conf file this file contains stashed passwords of
259 * the KDC, ADMIN and PASSWD dns.
261 if (ldap_context->service_password_file == NULL) {
262 st = prof_get_string_def (context, conf_section,
263 KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE,
264 &ldap_context->service_password_file);
269 #ifdef HAVE_EDIRECTORY
271 * If root certificate file is not set read it from database
272 * module section of conf file this is the trusted root
273 * certificate of the Directory.
275 if (ldap_context->root_certificate_file == NULL) {
276 st = prof_get_string_def (context, conf_section,
277 KRB5_CONF_LDAP_ROOT_CERTIFICATE_FILE,
278 &ldap_context->root_certificate_file);
285 * If the ldap server parameter is not set read the list of ldap
286 * servers from the database module section of the conf file.
289 if (ldap_context->server_info_list == NULL) {
292 server_info = &(ldap_context->server_info_list);
293 *server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1,
294 sizeof (krb5_ldap_server_info *));
296 if (*server_info == NULL) {
301 if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section,
302 KRB5_CONF_LDAP_SERVERS, NULL, &tempval)) != 0) {
303 krb5_set_error_message (context, st, "Error reading 'ldap_servers' attribute");
307 if (tempval == NULL) {
309 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
310 sizeof(krb5_ldap_server_info));
312 (*server_info)[ele]->server_name = strdup("ldapi://");
313 if ((*server_info)[ele]->server_name == NULL) {
317 (*server_info)[ele]->server_status = NOTSET;
321 item = strtok_r(tempval,delims,&save_ptr);
322 while (item != NULL && ele<SERV_COUNT) {
323 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
324 sizeof(krb5_ldap_server_info));
325 if ((*server_info)[ele] == NULL) {
329 (*server_info)[ele]->server_name = strdup(item);
330 if ((*server_info)[ele]->server_name == NULL) {
335 (*server_info)[ele]->server_status = NOTSET;
336 item = strtok_r(NULL,delims,&save_ptr);
339 profile_release_string(tempval);
343 if ((st = prof_get_boolean_def(context, conf_section,
344 KRB5_CONF_DISABLE_LAST_SUCCESS, FALSE,
345 &ldap_context->disable_last_success)))
348 if ((st = prof_get_boolean_def(context, conf_section,
349 KRB5_CONF_DISABLE_LOCKOUT, FALSE,
350 &ldap_context->disable_lockout)))
358 * This function frees the krb5_ldap_context structure members.
362 krb5_ldap_free_server_context_params(krb5_ldap_context *ldap_context)
365 krb5_ldap_server_handle *ldap_server_handle=NULL, *next_ldap_server_handle=NULL;
367 if (ldap_context == NULL)
370 /* Free all ldap servers list and the ldap handles associated with
372 if (ldap_context->server_info_list) {
373 while (ldap_context->server_info_list[i]) {
374 if (ldap_context->server_info_list[i]->server_name) {
375 free (ldap_context->server_info_list[i]->server_name);
377 #ifdef HAVE_EDIRECTORY
378 if (ldap_context->server_info_list[i]->root_certificate_file) {
379 free (ldap_context->server_info_list[i]->root_certificate_file);
382 if (ldap_context->server_info_list[i]->ldap_server_handles) {
383 ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles;
384 while (ldap_server_handle) {
385 ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL);
386 ldap_server_handle->ldap_handle = NULL;
387 next_ldap_server_handle = ldap_server_handle->next;
388 krb5_xfree(ldap_server_handle);
389 ldap_server_handle = next_ldap_server_handle;
392 krb5_xfree(ldap_context->server_info_list[i]);
395 krb5_xfree(ldap_context->server_info_list);
398 if (ldap_context->conf_section != NULL) {
399 krb5_xfree(ldap_context->conf_section);
400 ldap_context->conf_section = NULL;
403 if (ldap_context->bind_dn != NULL) {
404 krb5_xfree(ldap_context->bind_dn);
405 ldap_context->bind_dn = NULL;
408 if (ldap_context->bind_pwd != NULL) {
409 memset(ldap_context->bind_pwd, 0, strlen(ldap_context->bind_pwd));
410 krb5_xfree(ldap_context->bind_pwd);
411 ldap_context->bind_pwd = NULL;
414 if (ldap_context->service_password_file != NULL) {
415 krb5_xfree(ldap_context->service_password_file);
416 ldap_context->service_password_file = NULL;
419 #ifdef HAVE_EDIRECTORY
420 if (ldap_context->root_certificate_file != NULL) {
421 krb5_xfree(ldap_context->root_certificate_file);
422 ldap_context->root_certificate_file = NULL;
426 if (ldap_context->service_cert_path != NULL) {
427 krb5_xfree(ldap_context->service_cert_path);
428 ldap_context->service_cert_path = NULL;
431 if (ldap_context->service_cert_pass != NULL) {
432 krb5_xfree(ldap_context->service_cert_pass);
433 ldap_context->service_cert_pass = NULL;
436 if (ldap_context->certificates) {
438 while (ldap_context->certificates[i] != NULL) {
439 krb5_xfree(ldap_context->certificates[i]->certificate);
440 krb5_xfree(ldap_context->certificates[i]);
443 krb5_xfree(ldap_context->certificates);
450 krb5_ldap_free_server_params(krb5_ldap_context *ldap_context)
452 if (ldap_context == NULL)
455 krb5_ldap_free_server_context_params(ldap_context);
457 k5_mutex_destroy(&ldap_context->hndl_lock);
458 krb5_xfree(ldap_context);
463 * check to see if the principal belongs to the default realm.
464 * The default realm is present in the krb5_ldap_context structure.
465 * The principal has a realm portion. This realm portion is compared with the default realm
466 * to check whether the principal belong to the default realm.
467 * Return 0 if principal belongs to default realm else 1.
471 is_principal_in_realm(krb5_ldap_context *ldap_context,
472 krb5_const_principal searchfor)
474 size_t defrealmlen=0;
477 #define FIND_MAX(a,b) ((a) > (b) ? (a) : (b))
479 defrealmlen = strlen(ldap_context->lrparams->realm_name);
480 defrealm = ldap_context->lrparams->realm_name;
483 * Care should be taken for inter-realm principals as the default
484 * realm can exist in the realm part of the principal name or can
485 * also exist in the second portion of the name part. However, if
486 * the default realm exist in the second part of the principal
487 * portion, then the first portion of the principal name SHOULD be
488 * "krbtgt". All this check is done in the immediate block.
490 if (searchfor->length == 2)
491 if ((strncasecmp(searchfor->data[0].data, "krbtgt",
492 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) &&
493 (strncasecmp(searchfor->data[1].data, defrealm,
494 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0))
497 /* first check the length, if they are not equal, then they are not same */
498 if (strlen(defrealm) != searchfor->realm.length)
501 /* if the length is equal, check for the contents */
502 if (strncmp(defrealm, searchfor->realm.data,
503 searchfor->realm.length) != 0)
505 /* if we are here, then the realm portions match, return 0 */
511 * Deduce the subtree information from the context. A realm can have
513 * 1. the Realm container
514 * 2. the actual subtrees associated with the Realm
516 * However, there are some conditions to be considered to deduce the
517 * actual subtree/s associated with the realm. The conditions are as
519 * 1. If the subtree information of the Realm is [Root] or NULL (that
520 * is internal a [Root]) then the realm has only one subtree
521 * i.e [Root], i.e. whole of the tree.
522 * 2. If the subtree information of the Realm is missing/absent, then the
523 * realm has only one, i.e., the Realm container. NOTE: In all cases
524 * Realm container SHOULD be the one among the subtrees or the only
526 * 3. The subtree information of the realm is overlapping the realm
527 * container of the realm, then the realm has only one subtree and
528 * it is the subtree information associated with the realm.
531 krb5_get_subtree_info(krb5_ldap_context *ldap_context, char ***subtreearr,
534 int st=0, i=0, subtreecount=0;
535 int ncount=0, search_scope=0;
536 char **subtree=NULL, *realm_cont_dn=NULL;
538 char *containerref=NULL;
539 char **newsubtree=NULL;
541 containerref = ldap_context->lrparams->containerref;
542 subtree = ldap_context->lrparams->subtree;
543 realm_cont_dn = ldap_context->lrparams->realmdn;
544 subtreecount = ldap_context->lrparams->subtreecount;
545 search_scope = ldap_context->lrparams->search_scope;
547 subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1));
548 if (subtarr == NULL) {
552 memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1)));
554 /* get the complete subtree list */
555 for (i=0; i<subtreecount && subtree[i]!=NULL; i++) {
556 subtarr[i] = strdup(subtree[i]);
557 if (subtarr[i] == NULL) {
563 subtarr[i] = strdup(realm_cont_dn);
564 if (subtarr[i++] == NULL) {
569 if (containerref != NULL) {
570 subtarr[i] = strdup(containerref);
571 if (subtarr[i++] == NULL) {
578 newsubtree = (char **) malloc(sizeof(char *) * (ncount + 1));
579 if (newsubtree == NULL) {
583 memset(newsubtree, 0, (sizeof(char *) * (ncount+1)));
584 if ((st = remove_overlapping_subtrees(subtarr, newsubtree, &ncount,
585 search_scope)) != 0) {
590 *subtreearr = newsubtree;
593 if (subtarr != NULL) {
594 for (i=0; subtarr[i] != NULL; i++)
600 if (newsubtree != NULL) {
601 for (i=0; newsubtree[i] != NULL; i++)
610 * This function appends the content with a type into the tl_data
611 * structure. Based on the type the length of the content is either
612 * pre-defined or computed from the content. Returns 0 in case of
613 * success and 1 if the type associated with the content is undefined.
617 store_tl_data(krb5_tl_data *tl_data, int tl_type, void *value)
619 unsigned int currlen=0, tldatalen=0;
620 unsigned char *curr=NULL;
621 void *reallocptr=NULL;
623 tl_data->tl_data_type = KDB_TL_USER_INFO;
625 case KDB_TL_PRINCCOUNT:
626 case KDB_TL_PRINCTYPE:
629 int *iptr = (int *)value;
632 currlen = tl_data->tl_data_length;
633 tl_data->tl_data_length += 1 + 2 + 2;
634 /* allocate required memory */
635 reallocptr = tl_data->tl_data_contents;
636 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
637 tl_data->tl_data_length);
638 if (tl_data->tl_data_contents == NULL) {
643 curr = (tl_data->tl_data_contents + currlen);
645 /* store the tl_type value */
646 memset(curr, tl_type, 1);
648 /* store the content length */
650 STORE16_INT(curr, tldatalen);
652 /* store the content */
653 STORE16_INT(curr, ivalue);
661 char *cptr = (char *)value;
663 currlen = tl_data->tl_data_length;
664 tl_data->tl_data_length += 1 + 2 + strlen(cptr);
665 /* allocate required memory */
666 reallocptr = tl_data->tl_data_contents;
667 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
668 tl_data->tl_data_length);
669 if (tl_data->tl_data_contents == NULL) {
674 curr = (tl_data->tl_data_contents + currlen);
676 /* store the tl_type value */
677 memset(curr, tl_type, 1);
679 /* store the content length */
680 tldatalen = strlen(cptr);
681 STORE16_INT(curr, tldatalen);
683 /* store the content */
684 memcpy(curr, cptr, tldatalen);
697 * This function scans the tl_data structure to get the value of a
698 * type defined by the tl_type (second parameter). The tl_data
699 * structure has all the data in the tl_data_contents member. The
700 * format of the tl_data_contents is as follows. The first byte
701 * defines the type of the content that follows. The next 2 bytes
702 * define the size n (in terms of bytes) of the content that
703 * follows. The next n bytes define the content itself.
707 decode_tl_data(krb5_tl_data *tl_data, int tl_type, void **data)
709 int subtype=0, i=0, limit=10;
710 unsigned int sublen=0;
711 unsigned char *curr=NULL;
714 char *DN=NULL, **DNarr=NULL;
715 krb5_error_code st=-1;
719 curr = tl_data->tl_data_contents;
720 while (curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) {
722 /* get the type of the content */
723 subtype = (int) curr[0];
724 /* forward by 1 byte*/
727 if (subtype == tl_type) {
730 case KDB_TL_PRINCCOUNT:
731 case KDB_TL_PRINCTYPE:
733 /* get the length of the content */
734 UNSTORE16_INT(curr, sublen);
735 /* forward by 2 bytes */
737 /* get the actual content */
739 /* intptr = malloc(sublen); */
740 intptr = malloc(sizeof(krb5_int32));
743 memset(intptr, 0, sublen);
744 UNSTORE16_INT(curr, (*intptr));
747 longptr = malloc(sublen);
750 memset(longptr, 0, sublen);
751 UNSTORE32_INT(curr, (*longptr));
759 case KDB_TL_CONTAINERDN:
761 /* get the length of the content */
762 UNSTORE16_INT(curr, sublen);
763 /* forward by 2 bytes */
765 DN = malloc (sublen + 1);
768 memcpy(DN, curr, sublen);
778 DNarr = calloc(limit, sizeof(char *));
784 DNarr = realloc(DNarr, sizeof(char *) * (limit));
789 /* get the length of the content */
790 UNSTORE16_INT(curr, sublen);
791 /* forward by 2 bytes */
793 DNarr[i] = malloc (sublen + 1);
794 if (DNarr[i] == NULL)
796 memcpy(DNarr[i], curr, sublen);
797 DNarr[i][sublen] = 0;
805 /* move to the current content block */
806 UNSTORE16_INT(curr, sublen);
814 * wrapper routines for decode_tl_data
816 static krb5_error_code
817 krb5_get_int_from_tl_data(krb5_context context, krb5_db_entry *entries,
818 int type, int *intval)
820 krb5_error_code st=0;
821 krb5_tl_data tl_data;
825 tl_data.tl_data_type = KDB_TL_USER_INFO;
826 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
829 if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
830 intptr = (int *) voidptr;
840 * Get the mask representing the attributes set on the directory
841 * object (user, policy ...).
844 krb5_get_attributes_mask(krb5_context context, krb5_db_entry *entries,
847 return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK, mask);
851 krb5_get_princ_type(krb5_context context, krb5_db_entry *entries, int *ptype)
853 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype);
857 krb5_get_princ_count(krb5_context context, krb5_db_entry *entries, int *pcount)
859 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount);
863 krb5_get_linkdn(krb5_context context, krb5_db_entry *entries, char ***link_dn)
865 krb5_error_code st=0;
866 krb5_tl_data tl_data;
870 tl_data.tl_data_type = KDB_TL_USER_INFO;
871 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
874 if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) {
875 *link_dn = (char **) voidptr;
882 static krb5_error_code
883 krb5_get_str_from_tl_data(krb5_context context, krb5_db_entry *entries,
884 int type, char **strval)
886 krb5_error_code st=0;
887 krb5_tl_data tl_data;
890 if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) {
895 tl_data.tl_data_type = KDB_TL_USER_INFO;
896 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
899 if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
900 *strval = (char *) voidptr;
908 krb5_get_userdn(krb5_context context, krb5_db_entry *entries, char **userdn)
911 return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn);
915 krb5_get_containerdn(krb5_context context, krb5_db_entry *entries,
919 return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn);
923 * This function reads the attribute values (if the attribute is
924 * non-null) from the dn. The read attribute values is compared
925 * aganist the attrvalues passed to the function and a bit mask is set
926 * for all the matching attributes (attributes existing in both list).
927 * The bit to be set is selected such that the index of the attribute
928 * in the attrvalues parameter is the position of the bit. For ex:
929 * the first element in the attrvalues is present in both list shall
930 * set the LSB of the bit mask.
932 * In case if either the attribute or the attrvalues parameter to the
933 * function is NULL, then the existence of the object is considered
934 * and appropriate status is returned back.
938 checkattributevalue(LDAP *ld, char *dn, char *attribute, char **attrvalues,
942 char **values=NULL, *attributes[2] = {NULL};
943 LDAPMessage *result=NULL, *entry=NULL;
945 if (strlen(dn) == 0) {
946 st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
950 attributes[0] = attribute;
952 /* read the attribute values from the dn */
953 if ((st = ldap_search_ext_s(ld,
963 &result)) != LDAP_SUCCESS) {
964 st = set_ldap_error(0, st, OP_SEARCH);
969 * If the attribute/attrvalues is NULL, then check for the
970 * existence of the object alone.
972 if (attribute == NULL || attrvalues == NULL)
975 /* reset the bit mask */
978 if ((entry=ldap_first_entry(ld, result)) != NULL) {
979 /* read the attribute values */
980 if ((values=ldap_get_values(ld, entry, attribute)) != NULL) {
984 * Compare the read attribute values with the attrvalues
985 * array and set the appropriate bit mask.
987 for (j=0; attrvalues[j]; ++j) {
988 for (i=0; values[i]; ++i) {
989 if (strcasecmp(values[i], attrvalues[j]) == 0) {
995 ldap_value_free(values);
1000 ldap_msgfree(result);
1006 * This function updates a single attribute with a single value of a
1007 * specified dn. This function is mainly used to update
1008 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
1009 * ADMIN, PASSWD servers are associated with some realms or vice
1014 updateAttribute(LDAP *ld, char *dn, char *attribute, char *value)
1017 LDAPMod modAttr, *mods[2]={NULL};
1018 char *values[2]={NULL};
1022 /* data to update the {attr,attrval} combination */
1023 memset(&modAttr, 0, sizeof(modAttr));
1024 modAttr.mod_type = attribute;
1025 modAttr.mod_op = LDAP_MOD_ADD;
1026 modAttr.mod_values = values;
1029 /* ldap modify operation */
1030 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1032 /* if the {attr,attrval} combination is already present return a success
1033 * LDAP_ALREADY_EXISTS is for single-valued attribute
1034 * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute
1036 if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS)
1040 st = set_ldap_error (0, st, OP_MOD);
1047 * This function deletes a single attribute with a single value of a
1048 * specified dn. This function is mainly used to delete
1049 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
1050 * ADMIN, PASSWD servers are disassociated with some realms or vice
1055 deleteAttribute(LDAP *ld, char *dn, char *attribute, char *value)
1057 krb5_error_code st=0;
1058 LDAPMod modAttr, *mods[2]={NULL};
1059 char *values[2]={NULL};
1063 /* data to delete the {attr,attrval} combination */
1064 memset(&modAttr, 0, sizeof(modAttr));
1065 modAttr.mod_type = attribute;
1066 modAttr.mod_op = LDAP_MOD_DELETE;
1067 modAttr.mod_values = values;
1070 /* ldap modify operation */
1071 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1073 /* if either the attribute or the attribute value is missing return a success */
1074 if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE)
1078 st = set_ldap_error (0, st, OP_MOD);
1086 * This function takes in 2 string arrays, compares them to remove the
1087 * matching entries. The first array is the original list and the
1088 * second array is the modified list. Removing the matching entries
1089 * will result in a reduced array, where the left over first array
1090 * elements are the deleted entries and the left over second array
1091 * elements are the added entries. These additions and deletions has
1092 * resulted in the modified second array.
1096 disjoint_members(char **src, char **dest)
1098 int i=0, j=0, slen=0, dlen=0;
1100 /* validate the input parameters */
1101 if (src == NULL || dest == NULL)
1104 /* compute the first array length */
1105 for (i=0;src[i]; ++i)
1108 /* return if the length is 0 */
1112 /* index of the last element and also the length of the array */
1115 /* compute the second array length */
1116 for (i=0;dest[i]; ++i)
1119 /* return if the length is 0 */
1123 /* index of the last element and also the length of the array */
1126 /* check for the similar elements and delete them from both the arrays */
1127 for (i=0; src[i]; ++i) {
1129 for (j=0; dest[j]; ++j) {
1131 /* if the element are same */
1132 if (strcasecmp(src[i], dest[j]) == 0) {
1134 * If the matched element is in the middle, then copy
1135 * the last element to the matched index.
1143 * If the matched element is the last, free it and
1149 /* reduce the array length by 1 */
1152 /* repeat the same processing for the second array too */
1155 dest[j] = dest[dlen];
1164 * The source array is reduced by 1, so reduce the
1165 * index variable used for source array by 1. No need
1166 * to adjust the second array index variable as it is
1167 * reset while entering the inner loop.
1178 * This function replicates the contents of the src array for later
1179 * use. Mostly the contents of the src array is obtained from a
1180 * ldap_search operation and the contents are required for later use.
1184 copy_arrays(char **src, char ***dest, int count)
1186 krb5_error_code st=0;
1189 /* validate the input parameters */
1190 if (src == NULL || dest == NULL)
1193 /* allocate memory for the dest array */
1194 *dest = (char **) calloc((unsigned) count+1, sizeof(char *));
1195 if (*dest == NULL) {
1200 /* copy the members from src to dest array. */
1201 for (i=0; i < count && src[i] != NULL; ++i) {
1202 (*dest)[i] = strdup(src[i]);
1203 if ((*dest)[i] == NULL) {
1210 /* in case of error free up everything and return */
1212 if (*dest != NULL) {
1213 for (i=0; (*dest)[i]; ++i) {
1224 static krb5_error_code
1225 getepochtime(char *strtime, krb5_timestamp *epochtime)
1229 memset(&tme, 0, sizeof(tme));
1230 if (strptime(strtime,"%Y%m%d%H%M%SZ", &tme) == NULL) {
1234 *epochtime = krb5int_gmt_mktime(&tme);
1239 * krb5_ldap_get_value() - get the integer value of the attribute
1240 * Returns, 0 if the attribute is present, 1 if the attribute is missing.
1241 * The retval is 0 if the attribute is missing.
1245 krb5_ldap_get_value(LDAP *ld, LDAPMessage *ent, char *attribute, int *retval)
1250 values=ldap_get_values(ld, ent, attribute);
1251 if (values != NULL) {
1252 if (values[0] != NULL)
1253 *retval = atoi(values[0]);
1254 ldap_value_free(values);
1261 * krb5_ldap_get_string() - Returns the first string of the
1262 * attribute. Intended to
1267 krb5_ldap_get_string(LDAP *ld, LDAPMessage *ent, char *attribute,
1268 char **retstr, krb5_boolean *attr_present)
1271 krb5_error_code st=0;
1274 if (attr_present != NULL)
1275 *attr_present = FALSE;
1277 values=ldap_get_values(ld, ent, attribute);
1278 if (values != NULL) {
1279 if (values[0] != NULL) {
1280 if (attr_present!= NULL)
1281 *attr_present = TRUE;
1282 *retstr = strdup(values[0]);
1283 if (*retstr == NULL)
1286 ldap_value_free(values);
1292 * krb5_ldap_get_strings() - Returns all the values
1296 krb5_ldap_get_strings(LDAP *ld, LDAPMessage *ent, char *attribute,
1297 char ***retarr, krb5_boolean *attr_present)
1300 krb5_error_code st=0;
1301 unsigned int i=0, count=0;
1304 if (attr_present != NULL)
1305 *attr_present = FALSE;
1307 values=ldap_get_values(ld, ent, attribute);
1308 if (values != NULL) {
1309 if (attr_present != NULL)
1310 *attr_present = TRUE;
1312 count = ldap_count_values(values);
1313 *retarr = (char **) calloc(count+1, sizeof(char *));
1314 if (*retarr == NULL) {
1318 for (i=0; i< count; ++i) {
1319 (*retarr)[i] = strdup(values[i]);
1320 if ((*retarr)[i] == NULL) {
1325 ldap_value_free(values);
1330 if (*retarr != NULL) {
1331 for (i=0; i< count; ++i)
1332 if ((*retarr)[i] != NULL)
1333 free ((*retarr)[i]);
1341 krb5_ldap_get_time(LDAP *ld, LDAPMessage *ent, char *attribute,
1342 krb5_timestamp *rettime, krb5_boolean *attr_present)
1345 krb5_error_code st=0;
1348 *attr_present = FALSE;
1350 values=ldap_get_values(ld, ent, attribute);
1351 if (values != NULL) {
1352 if (values[0] != NULL) {
1353 *attr_present = TRUE;
1354 st = getepochtime(values[0], rettime);
1356 ldap_value_free(values);
1362 * Function to allocate, set the values of LDAPMod structure. The
1363 * LDAPMod structure is then added to the array at the ind
1367 krb5_add_member(LDAPMod ***mods, int *count)
1370 LDAPMod **lmods=NULL;
1372 if ((*mods) != NULL) {
1373 for (;(*mods)[i] != NULL; ++i)
1376 lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *));
1381 (*mods)[i+1] = NULL;
1382 (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod));
1383 if ((*mods)[i] == NULL)
1390 krb5_add_str_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op,
1394 krb5_error_code st=0;
1396 if ((st=krb5_add_member(mods, &i)) != 0)
1399 (*mods)[i]->mod_type = strdup(attribute);
1400 if ((*mods)[i]->mod_type == NULL)
1402 (*mods)[i]->mod_op = op;
1404 (*mods)[i]->mod_values = NULL;
1406 if (values != NULL) {
1407 for (j=0; values[j] != NULL; ++j)
1409 (*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1));
1410 if ((*mods)[i]->mod_values == NULL)
1413 for (j=0; values[j] != NULL; ++j) {
1414 (*mods)[i]->mod_values[j] = strdup(values[j]);
1415 if ((*mods)[i]->mod_values[j] == NULL)
1418 (*mods)[i]->mod_values[j] = NULL;
1424 krb5_add_ber_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op,
1425 struct berval **ber_values)
1428 krb5_error_code st=0;
1430 if ((st=krb5_add_member(mods, &i)) != 0)
1433 (*mods)[i]->mod_type = strdup(attribute);
1434 if ((*mods)[i]->mod_type == NULL)
1436 (*mods)[i]->mod_op = op;
1438 for (j=0; ber_values[j] != NULL; ++j)
1440 (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1));
1441 if ((*mods)[i]->mod_bvalues == NULL)
1444 for (j=0; ber_values[j] != NULL; ++j) {
1445 (*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval));
1446 if ((*mods)[i]->mod_bvalues[j] == NULL)
1449 (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len;
1450 (*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len);
1451 if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL)
1454 memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val,
1455 ber_values[j]->bv_len);
1457 (*mods)[i]->mod_bvalues[j] = NULL;
1461 static inline char *
1464 char tmpbuf[2+3*sizeof(val)];
1465 snprintf(tmpbuf, sizeof(tmpbuf), "%d", val);
1466 return strdup(tmpbuf);
1470 krb5_add_int_arr_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op,
1474 krb5_error_code st=0;
1476 if ((st=krb5_add_member(mods, &i)) != 0)
1479 (*mods)[i]->mod_type = strdup(attribute);
1480 if ((*mods)[i]->mod_type == NULL)
1482 (*mods)[i]->mod_op = op;
1484 for (j=0; value[j] != -1; ++j)
1487 (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1));
1489 for (j=0; value[j] != -1; ++j) {
1490 if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL)
1493 (*mods)[i]->mod_values[j] = NULL;
1498 krb5_add_int_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op, int value)
1501 krb5_error_code st=0;
1503 if ((st=krb5_add_member(mods, &i)) != 0)
1506 (*mods)[i]->mod_type = strdup(attribute);
1507 if ((*mods)[i]->mod_type == NULL)
1510 (*mods)[i]->mod_op = op;
1511 (*mods)[i]->mod_values = calloc (2, sizeof(char *));
1512 if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL)
1518 krb5_ldap_lock(krb5_context kcontext, int mode)
1520 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1521 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1526 krb5_ldap_unlock(krb5_context kcontext)
1528 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1529 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1534 krb5_ldap_supported_realms(krb5_context kcontext, char **realms)
1536 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1537 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1542 krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms)
1544 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1545 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1550 krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code)
1552 return krb5_get_error_message(kcontext, err_code);
1556 krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg)
1558 krb5_free_error_message(kcontext, msg);
1563 * Get the number of times an object has been referred to in a realm. this is
1564 * needed to find out if deleting the attribute will cause dangling links.
1566 * An LDAP handle may be optionally specified to prevent race condition - there
1567 * are a limited number of LDAP handles.
1570 krb5_ldap_get_reference_count(krb5_context context, char *dn, char *refattr,
1571 int *count, LDAP *ld)
1573 int st = 0, tempst = 0, gothandle = 0;
1574 unsigned int i, ntrees;
1575 char *refcntattr[2];
1576 char *filter = NULL;
1577 char **subtree = NULL, *ptr = NULL;
1578 kdb5_dal_handle *dal_handle = NULL;
1579 krb5_ldap_context *ldap_context = NULL;
1580 krb5_ldap_server_handle *ldap_server_handle = NULL;
1581 LDAPMessage *result = NULL;
1584 if (dn == NULL || refattr == NULL) {
1595 refcntattr [0] = refattr;
1596 refcntattr [1] = NULL;
1598 ptr = ldap_filter_correct (dn);
1604 if (asprintf (&filter, "%s=%s", refattr, ptr) < 0) {
1610 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
1613 for (i = 0, *count = 0; i < ntrees; i++) {
1616 LDAP_SEARCH(subtree[i],
1620 n = ldap_count_entries (ld, result);
1622 int ret, errcode = 0;
1623 ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0);
1624 if (ret != LDAP_SUCCESS)
1626 st = translate_ldap_error (errcode, OP_SEARCH);
1630 ldap_msgfree(result);
1641 ldap_msgfree (result);
1643 if (subtree != NULL) {
1644 for (i = 0; i < ntrees; i++)
1653 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1659 * For now, policy objects are expected to be directly under the realm
1663 krb5_ldap_policydn_to_name(krb5_context context, char *policy_dn, char **name)
1666 krb5_error_code st = 0;
1667 kdb5_dal_handle *dal_handle=NULL;
1668 krb5_ldap_context *ldap_context=NULL;
1672 if (ldap_context->lrparams->realmdn == NULL) {
1677 len1 = strlen (ldap_context->lrparams->realmdn);
1678 len2 = strlen (policy_dn);
1679 if (len1 == 0 || len2 == 0 || len1 > len2) {
1684 if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) {
1689 #if defined HAVE_LDAP_STR2DN
1693 rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */
1695 if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) {
1699 if (dn[0] == NULL || dn[1] != NULL)
1701 else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0)
1704 *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len);
1711 #elif defined HAVE_LDAP_EXPLODE_DN
1715 /* 1 = return DN components without type prefix */
1716 parsed_dn = ldap_explode_dn(policy_dn, 1);
1717 if (parsed_dn == NULL) {
1720 *name = strdup(parsed_dn[0]);
1724 ldap_value_free(parsed_dn);
1736 krb5_ldap_name_to_policydn(krb5_context context, char *name, char **policy_dn)
1740 krb5_error_code st = 0;
1741 kdb5_dal_handle *dal_handle=NULL;
1742 krb5_ldap_context *ldap_context=NULL;
1746 /* validate the input parameters */
1752 /* Used for removing policy reference from an object */
1753 if (name[0] == '\0') {
1754 if ((*policy_dn = strdup ("")) == NULL)
1761 if (ldap_context->lrparams->realmdn == NULL) {
1765 len = strlen (ldap_context->lrparams->realmdn);
1767 ptr = ldap_filter_correct (name);
1772 len += strlen (ptr);
1774 len += sizeof ("cn=") + 3;
1776 *policy_dn = (char *) malloc (len);
1777 if (*policy_dn == NULL) {
1782 sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn);
1790 /* remove overlapping and repeated subtree entries from the list of subtrees */
1791 static krb5_error_code
1792 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount,
1795 int slen=0, k=0, j=0, lendiff=0;
1796 int count = *subtcount;
1797 char **subtree = listop;
1800 for (k=0; k<=slen && listin[k]!=NULL ; k++) {
1801 for (j=k+1; j<=slen && listin[j]!=NULL ;j++) {
1802 lendiff = strlen(listin[k]) - strlen(listin[j]);
1804 if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) {
1807 listin[k] = listin[slen];
1808 listin[slen] = NULL;
1816 } else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) {
1819 listin[j] = listin[slen];
1829 if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) {
1832 listin[j] = listin[slen];
1844 for (k=0; k<*subtcount && listin[k]!=NULL; k++) {
1845 subtree[k] = strdup(listin[k]);
1846 if (subtree[k] == NULL) {
1854 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing
1855 * the results of a principal search of the directory.
1858 populate_krb5_db_entry(krb5_context context, krb5_ldap_context *ldap_context,
1859 LDAP *ld, LDAPMessage *ent, krb5_const_principal princ,
1860 krb5_db_entry *entry)
1862 krb5_error_code st = 0;
1863 unsigned int mask = 0;
1864 krb5_boolean attr_present = FALSE;
1865 char **values = NULL, *policydn = NULL, *pwdpolicydn = NULL;
1866 char *polname = NULL, *tktpolname = NULL;
1867 struct berval **bvalues = NULL;
1868 krb5_tl_data userinfo_tl_data = {0};
1869 char **link_references = NULL;
1872 if (princ == NULL) {
1873 /* XXX WAF probably should just extract princ from ldap result */
1877 if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0)
1880 /* get the associated directory user information */
1881 if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
1882 int i, pcount=0, kerberos_principal_object_type=0;
1885 if ((st=krb5_unparse_name(context, princ, &user)) != 0)
1888 for (i=0; values[i] != NULL; ++i) {
1889 if (strcasecmp(values[i], user) == 0) {
1890 pcount = ldap_count_values(values);
1894 ldap_value_free(values);
1897 if ((DN = ldap_get_dn(ld, ent)) == NULL) {
1898 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st);
1899 st = set_ldap_error(context, st, 0);
1903 if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) {
1904 for (i=0; values[i] != NULL; ++i)
1905 if (strcasecmp(values[i], "krbprincipal") == 0) {
1906 kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT;
1907 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
1908 &kerberos_principal_object_type)) != 0)
1912 ldap_value_free(values);
1915 /* add principalcount, DN and principaltype user information to tl_data */
1916 if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) ||
1917 ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0))
1921 /* read all the kerberos attributes */
1923 /* KRBLASTSUCCESSFULAUTH */
1924 if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth",
1925 &(entry->last_success), &attr_present)) != 0)
1927 if (attr_present == TRUE)
1928 mask |= KDB_LAST_SUCCESS_ATTR;
1930 /* KRBLASTFAILEDAUTH */
1931 if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth",
1932 &(entry->last_failed), &attr_present)) != 0)
1934 if (attr_present == TRUE)
1935 mask |= KDB_LAST_FAILED_ATTR;
1937 /* KRBLOGINFAILEDCOUNT */
1938 if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount",
1939 &(entry->fail_auth_count)) == 0)
1940 mask |= KDB_FAIL_AUTH_COUNT_ATTR;
1942 /* KRBMAXTICKETLIFE */
1943 if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0)
1944 mask |= KDB_MAX_LIFE_ATTR;
1946 /* KRBMAXRENEWABLEAGE */
1947 if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage",
1948 &(entry->max_renewable_life)) == 0)
1949 mask |= KDB_MAX_RLIFE_ATTR;
1951 /* KRBTICKETFLAGS */
1952 if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0)
1953 mask |= KDB_TKT_FLAGS_ATTR;
1955 /* PRINCIPAL EXPIRATION TIME */
1956 if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration),
1957 &attr_present)) != 0)
1959 if (attr_present == TRUE)
1960 mask |= KDB_PRINC_EXPIRE_TIME_ATTR;
1962 /* PASSWORD EXPIRATION TIME */
1963 if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration),
1964 &attr_present)) != 0)
1966 if (attr_present == TRUE)
1967 mask |= KDB_PWD_EXPIRE_TIME_ATTR;
1969 /* KRBPOLICYREFERENCE */
1971 if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
1972 &attr_present)) != 0)
1974 if (attr_present == TRUE) {
1975 mask |= KDB_POL_REF_ATTR;
1976 /* Ensure that the policy is inside the realm container */
1977 if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0)
1981 /* KRBPWDPOLICYREFERENCE */
1982 if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
1983 &attr_present)) != 0)
1985 if (attr_present == TRUE) {
1986 krb5_tl_data kadm_tl_data;
1988 mask |= KDB_PWD_POL_REF_ATTR;
1990 /* Ensure that the policy is inside the realm container */
1991 if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0)
1994 if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data)) != 0) {
1997 krb5_dbe_update_tl_data(context, entry, &kadm_tl_data);
2001 if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) {
2002 krb5_kvno mkvno = 0;
2004 mask |= KDB_SECRET_KEY_ATTR;
2005 if ((st=krb5_decode_krbsecretkey(context, entry, bvalues, &userinfo_tl_data, &mkvno)) != 0)
2008 /* don't add the tl data if mkvno == 0 */
2009 if ((st=krb5_dbe_update_mkvno(context, entry, mkvno)) != 0)
2014 /* LAST PASSWORD CHANGE */
2016 krb5_timestamp lstpwdchng=0;
2017 if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange",
2018 &lstpwdchng, &attr_present)) != 0)
2020 if (attr_present == TRUE) {
2021 if ((st=krb5_dbe_update_last_pwd_change(context, entry,
2024 mask |= KDB_LAST_PWD_CHANGE_ATTR;
2028 /* ALLOWED TO DELEGATE TO */
2034 st = krb5_ldap_get_strings(ld, ent, "krbAllowedToDelegateTo",
2035 &a2d2, &attr_present);
2039 if (attr_present == TRUE) {
2040 for (tlp = &entry->tl_data; *tlp; tlp = &(*tlp)->tl_data_next)
2042 for (i = 0; a2d2[i] != NULL; i++) {
2043 krb5_tl_data *tl = k5alloc(sizeof(*tl), &st);
2045 ldap_value_free(a2d2);
2048 tl->tl_data_type = KRB5_TL_CONSTRAINED_DELEGATION_ACL;
2049 tl->tl_data_length = strlen(a2d2[i]);
2050 tl->tl_data_contents = (krb5_octet *)strdup(a2d2[i]);
2051 if (tl->tl_data_contents == NULL) {
2053 ldap_value_free(a2d2);
2057 tl->tl_data_next = NULL;
2059 tlp = &tl->tl_data_next;
2061 ldap_value_free(a2d2);
2065 /* KRBOBJECTREFERENCES */
2069 if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences",
2070 &link_references, &attr_present)) != 0)
2072 if (link_references != NULL) {
2073 for (i=0; link_references[i] != NULL; ++i) {
2074 if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
2075 link_references[i])) != 0)
2084 struct berval **ber_tl_data = NULL;
2085 krb5_tl_data *ptr = NULL;
2087 if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) {
2088 for (i = 0; ber_tl_data[i] != NULL; i++) {
2089 if ((st = berval2tl_data (ber_tl_data[i] , &ptr)) != 0)
2091 if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0)
2094 ldap_value_free_len (ber_tl_data);
2097 mask |= KDB_EXTRA_DATA_ATTR;
2101 /* update the mask of attributes present on the directory object to the tl_data */
2102 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0)
2104 if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0)
2107 #ifdef HAVE_EDIRECTORY
2109 krb5_timestamp expiretime=0;
2110 char *is_login_disabled=NULL;
2112 /* LOGIN EXPIRATION TIME */
2113 if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime,
2114 &attr_present)) != 0)
2117 if (attr_present == TRUE) {
2118 if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) {
2119 if (expiretime < entry->expiration)
2120 entry->expiration = expiretime;
2122 entry->expiration = expiretime;
2126 /* LOGIN DISABLED */
2127 if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled,
2128 &attr_present)) != 0)
2130 if (attr_present == TRUE) {
2131 if (strcasecmp(is_login_disabled, "TRUE")== 0)
2132 entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
2133 free (is_login_disabled);
2138 if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0)
2141 /* We already know that the policy is inside the realm container. */
2143 osa_policy_ent_t pwdpol;
2145 krb5_timestamp last_pw_changed;
2146 krb5_ui_4 pw_max_life;
2148 memset(&pwdpol, 0, sizeof(pwdpol));
2150 if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0)
2152 pw_max_life = pwdpol->pw_max_life;
2155 if (pw_max_life > 0) {
2156 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0)
2159 if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) {
2160 if ((last_pw_changed + pw_max_life) < entry->pw_expiration)
2161 entry->pw_expiration = last_pw_changed + pw_max_life;
2163 entry->pw_expiration = last_pw_changed + pw_max_life;
2166 /* XXX so krb5_encode_princ_contents() will be happy */
2167 entry->len = KRB5_KDB_V1_BASE_LENGTH;
2174 if (userinfo_tl_data.tl_data_contents != NULL)
2175 free(userinfo_tl_data.tl_data_contents);
2177 if (pwdpolicydn != NULL)
2180 if (polname != NULL)
2183 if (tktpolname != NULL)
2186 if (policydn != NULL)
2189 if (link_references) {
2191 for (i=0; link_references[i] != NULL; ++i)
2192 free (link_references[i]);
2193 free (link_references);
2200 * Solaris libldap does not provide the following functions which are in
2203 #ifndef HAVE_LDAP_INITIALIZE
2205 ldap_initialize(LDAP **ldp, char *url)
2209 LDAPURLDesc *ludp = NULL;
2211 /* For now, we don't use any DN that may be provided. And on
2212 Solaris (based on Mozilla's LDAP client code), we need the
2213 _nodn form to parse "ldap://host" without a trailing slash.
2215 Also, this version won't handle an input string which contains
2216 multiple URLs, unlike the OpenLDAP ldap_initialize. See
2217 https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 . */
2218 #ifdef HAVE_LDAP_URL_PARSE_NODN
2219 rc = ldap_url_parse_nodn(url, &ludp);
2221 rc = ldap_url_parse(url, &ludp);
2225 ld = ldap_init(ludp->lud_host, ludp->lud_port);
2229 printf("lud_host %s lud_port %d\n", ludp->lud_host,
2234 rc = KRB5_KDB_ACCESS_ERROR;
2236 ldap_free_urldesc(ludp);
2240 #endif /* HAVE_LDAP_INITIALIZE */
2242 #ifndef HAVE_LDAP_UNBIND_EXT_S
2244 ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls)
2246 return ldap_unbind_ext(ld, sctrls, cctrls);
2248 #endif /* HAVE_LDAP_UNBIND_EXT_S */