1 /*
2 * lib/kdb/kdb_ldap/ldap_misc.c
3 *
4 * Copyright (c) 2004-2005, Novell, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * The copyright holder's name is not used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30 /*
31 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
32 * Use is subject to license terms.
33 */
34 #include <string.h>
35 #include <time.h>
36 #include <k5-platform.h>
37 #include "ldap_main.h"
38 #include "ldap_err.h"
39 #include "ldap_principal.h"
40 #include "princ_xdr.h"
41 #include "ldap_pwd_policy.h"
42 #include <libintl.h>
43
44 #ifdef NEED_STRPTIME_PROTO
45 extern char *strptime (const char *, const char *, struct tm *);
46 #endif
47
48 static krb5_error_code
49 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount,
50 int sscope);
51
52 /* Linux (GNU Libc) provides a length-limited variant of strdup.
53 But all the world's not Linux. */
54 #undef strndup
55 #define strndup my_strndup
56 #ifdef HAVE_LDAP_STR2DN
my_strndup(const char * input,size_t limit)57 static char *my_strndup (const char *input, size_t limit)
58 {
59 size_t len = strlen(input);
60 char *result;
61 if (len > limit) {
62 result = malloc(1 + limit);
63 if (result != NULL) {
64 memcpy(result, input, limit);
65 result[limit] = 0;
66 }
67 return result;
68 } else
69 return strdup(input);
70 }
71 #endif
72
73 /* Get integer or string values from the config section, falling back
74 to the default section, then to hard-coded values. */
75 static errcode_t
prof_get_integer_def(krb5_context ctx,const char * conf_section,const char * name,int dfl,krb5_ui_4 * out)76 prof_get_integer_def(krb5_context ctx, const char *conf_section,
77 const char *name, int dfl, krb5_ui_4 *out)
78 {
79 errcode_t err;
80 int out_temp = 0;
81
82 err = profile_get_integer (ctx->profile,
83 KDB_MODULE_SECTION, conf_section, name,
84 0, &out_temp);
85 if (err) {
86 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
87 name, error_message(err));
88 return err;
89 }
90 if (out_temp != 0) {
91 *out = out_temp;
92 return 0;
93 }
94 err = profile_get_integer (ctx->profile,
95 KDB_MODULE_DEF_SECTION, name, 0,
96 dfl, &out_temp);
97 if (err) {
98 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
99 name, error_message(err));
100 return err;
101 }
102 *out = out_temp;
103 return 0;
104 }
105
106 /* We don't have non-null defaults in any of our calls, so don't
107 bother with the extra argument. */
108 static errcode_t
prof_get_string_def(krb5_context ctx,const char * conf_section,const char * name,char ** out)109 prof_get_string_def(krb5_context ctx, const char *conf_section,
110 const char *name, char **out)
111 {
112 errcode_t err;
113
114 err = profile_get_string (ctx->profile,
115 KDB_MODULE_SECTION, conf_section, name,
116 0, out);
117 if (err) {
118 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
119 name, error_message(err));
120 return err;
121 }
122 if (*out != 0)
123 return 0;
124 err = profile_get_string (ctx->profile,
125 KDB_MODULE_DEF_SECTION, name, 0,
126 0, out);
127 if (err) {
128 krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
129 name, error_message(err));
130 return err;
131 }
132 return 0;
133 }
134
135
136
137 /*
138 * This function reads the parameters from the krb5.conf file. The
139 * parameters read here are DAL-LDAP specific attributes. Some of
140 * these are ldap_server ....
141 */
142 krb5_error_code
krb5_ldap_read_server_params(context,conf_section,srv_type)143 krb5_ldap_read_server_params(context, conf_section, srv_type)
144 krb5_context context;
145 char *conf_section;
146 int srv_type;
147 {
148 char *tempval=NULL, *save_ptr=NULL;
149 const char *delims="\t\n\f\v\r ,";
150 krb5_error_code st=0;
151 kdb5_dal_handle *dal_handle=NULL;
152 krb5_ldap_context *ldap_context=NULL;
153 krb5_ldap_server_info ***server_info=NULL;
154
155 dal_handle = (kdb5_dal_handle *) context->db_context;
156 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
157
158 /* copy the conf_section into ldap_context for later use */
159 if (conf_section) {
160 ldap_context->conf_section = strdup (conf_section);
161 if (ldap_context->conf_section == NULL) {
162 st = ENOMEM;
163 goto cleanup;
164 }
165 }
166
167 /* initialize the mutexs and condition variable */
168 /* this portion logically doesn't fit here should be moved appropriately */
169
170 /* this mutex is used in ldap reconnection pool */
171 if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) {
172 st = KRB5_KDB_SERVER_INTERNAL_ERR;
173 #if 0
174 st = -1;
175 krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st,
176 "k5_mutex_init failed");
177 #endif
178 goto cleanup;
179 }
180
181 /*
182 * If max_server_conns is not set read it from database module
183 * section of conf file this parameter defines maximum ldap
184 * connections per ldap server.
185 */
186 if (ldap_context->max_server_conns == 0) {
187 st = prof_get_integer_def (context, conf_section,
188 "ldap_conns_per_server",
189 DEFAULT_CONNS_PER_SERVER,
190 &ldap_context->max_server_conns);
191 if (st)
192 goto cleanup;
193 }
194
195 if (ldap_context->max_server_conns < 2) {
196 st = EINVAL;
197 krb5_set_error_message (context, st,
198 gettext("Minimum connections required per server is 2"));
199 goto cleanup;
200 }
201
202 /*
203 * If the bind dn is not set read it from the database module
204 * section of conf file this paramter is populated by one of the
205 * KDC, ADMIN or PASSWD dn to be used to connect to LDAP
206 * server. The srv_type decides which dn to read.
207 */
208 if (ldap_context->bind_dn == NULL) {
209 char *name = 0;
210 if (srv_type == KRB5_KDB_SRV_TYPE_KDC)
211 name = "ldap_kdc_dn";
212 else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN)
213 name = "ldap_kadmind_dn";
214 else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD)
215 name = "ldap_kpasswdd_dn";
216
217 if (name) {
218 st = prof_get_string_def (context, conf_section, name,
219 &ldap_context->bind_dn);
220 if (st)
221 goto cleanup;
222 }
223 }
224
225 /*
226 * Read service_password_file parameter from database module
227 * section of conf file this file contains stashed passwords of
228 * the KDC, ADMIN and PASSWD dns.
229 */
230 if (ldap_context->service_password_file == NULL) {
231 /*
232 * Solaris Kerberos: providing a default.
233 */
234 st = profile_get_string (context->profile, KDB_MODULE_SECTION,
235 conf_section,
236 "ldap_service_password_file",
237 NULL,
238 &ldap_context->service_password_file);
239
240 if (st)
241 goto cleanup;
242
243 if (ldap_context->service_password_file == NULL) {
244 st = profile_get_string (context->profile, KDB_MODULE_DEF_SECTION,
245 "ldap_service_password_file",
246 NULL,
247 DEF_SERVICE_PASSWD_FILE,
248 &ldap_context->service_password_file);
249 if (st)
250 goto cleanup;
251 }
252 }
253
254 /*
255 * Solaris Kerberos: we must use root_certificate_file
256 *
257 * Note, I've changed the ldap_root_certificate_file config parameter to
258 * ldap_cert_path which is more appropriate for that parameter.
259 */
260 /* #ifdef HAVE_EDIRECTORY */
261 /*
262 * If root certificate file is not set read it from database
263 * module section of conf file this is the trusted root
264 * certificate of the Directory.
265 */
266 if (ldap_context->root_certificate_file == NULL) {
267 st = prof_get_string_def (context, conf_section,
268 "ldap_cert_path",
269 &ldap_context->root_certificate_file);
270 if (st)
271 goto cleanup;
272 }
273 /* #endif */
274
275 /*
276 * If the ldap server parameter is not set read the list of ldap
277 * servers from the database module section of the conf file.
278 */
279
280 if (ldap_context->server_info_list == NULL) {
281 unsigned int ele=0;
282
283 server_info = &(ldap_context->server_info_list);
284 *server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1,
285 sizeof (krb5_ldap_server_info *));
286
287 if (*server_info == NULL) {
288 st = ENOMEM;
289 goto cleanup;
290 }
291
292 if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section,
293 "ldap_servers", NULL, &tempval)) != 0) {
294 krb5_set_error_message (context, st, gettext("Error reading 'ldap_servers' attribute"));
295 goto cleanup;
296 }
297
298 if (tempval == NULL) {
299
300 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
301 sizeof(krb5_ldap_server_info));
302
303 if ((*server_info)[ele] == NULL) {
304 st = ENOMEM;
305 goto cleanup;
306 }
307 (*server_info)[ele]->server_name = strdup("ldapi://");
308 if ((*server_info)[ele]->server_name == NULL) {
309 st = ENOMEM;
310 goto cleanup;
311 }
312 (*server_info)[ele]->server_status = NOTSET;
313 } else {
314 char *item=NULL;
315
316 item = strtok_r(tempval,delims,&save_ptr);
317 while (item != NULL && ele<SERV_COUNT) {
318 (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
319 sizeof(krb5_ldap_server_info));
320 if ((*server_info)[ele] == NULL) {
321 st = ENOMEM;
322 goto cleanup;
323 }
324 (*server_info)[ele]->server_name = strdup(item);
325 if ((*server_info)[ele]->server_name == NULL) {
326 st = ENOMEM;
327 goto cleanup;
328 }
329
330 (*server_info)[ele]->server_status = NOTSET;
331 item = strtok_r(NULL,delims,&save_ptr);
332 ++ele;
333 }
334 profile_release_string(tempval);
335 }
336 }
337
338 cleanup:
339 return(st);
340 }
341
342 /*
343 * This function frees the krb5_ldap_context structure members.
344 */
345
346 krb5_error_code
krb5_ldap_free_server_params(ldap_context)347 krb5_ldap_free_server_params(ldap_context)
348 krb5_ldap_context *ldap_context;
349 {
350 int i=0;
351 krb5_ldap_server_handle *ldap_server_handle=NULL, *next_ldap_server_handle=NULL;
352
353 if (ldap_context == NULL)
354 return 0;
355
356 /* Free all ldap servers list and the ldap handles associated with
357 the ldap server. */
358 if (ldap_context->server_info_list) {
359 while (ldap_context->server_info_list[i]) {
360 if (ldap_context->server_info_list[i]->server_name) {
361 free (ldap_context->server_info_list[i]->server_name);
362 }
363 #ifdef HAVE_EDIRECTORY
364 if (ldap_context->server_info_list[i]->root_certificate_file) {
365 free (ldap_context->server_info_list[i]->root_certificate_file);
366 }
367 #endif
368 if (ldap_context->server_info_list[i]->ldap_server_handles) {
369 ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles;
370 while (ldap_server_handle) {
371 ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL);
372 ldap_server_handle->ldap_handle = NULL;
373 next_ldap_server_handle = ldap_server_handle->next;
374 krb5_xfree(ldap_server_handle);
375 ldap_server_handle = next_ldap_server_handle;
376 }
377 }
378 krb5_xfree(ldap_context->server_info_list[i]);
379 i++;
380 }
381 krb5_xfree(ldap_context->server_info_list);
382 }
383
384 if (ldap_context->conf_section != NULL) {
385 krb5_xfree(ldap_context->conf_section);
386 ldap_context->conf_section = NULL;
387 }
388
389 if (ldap_context->bind_dn != NULL) {
390 krb5_xfree(ldap_context->bind_dn);
391 ldap_context->bind_dn = NULL;
392 }
393
394 if (ldap_context->bind_pwd != NULL) {
395 krb5_xfree(ldap_context->bind_pwd);
396 ldap_context->bind_pwd = NULL;
397 }
398
399 if (ldap_context->service_password_file != NULL) {
400 krb5_xfree(ldap_context->service_password_file);
401 ldap_context->service_password_file = NULL;
402 }
403
404 /* Solaris Kerberos */
405 /* #ifdef HAVE_EDIRECTORY */
406 if (ldap_context->root_certificate_file != NULL) {
407 krb5_xfree(ldap_context->root_certificate_file);
408 ldap_context->root_certificate_file = NULL;
409 }
410 /* #endif */
411
412 if (ldap_context->service_cert_path != NULL) {
413 krb5_xfree(ldap_context->service_cert_path);
414 ldap_context->service_cert_path = NULL;
415 }
416
417 if (ldap_context->service_cert_pass != NULL) {
418 krb5_xfree(ldap_context->service_cert_pass);
419 ldap_context->service_cert_pass = NULL;
420 }
421
422 if (ldap_context->certificates) {
423 i=0;
424 while (ldap_context->certificates[i] != NULL) {
425 krb5_xfree(ldap_context->certificates[i]->certificate);
426 krb5_xfree(ldap_context->certificates[i]);
427 ++i;
428 }
429 krb5_xfree(ldap_context->certificates);
430 }
431
432 k5_mutex_destroy(&ldap_context->hndl_lock);
433
434 krb5_xfree(ldap_context);
435 return(0);
436 }
437
438
439 /*
440 * check to see if the principal belongs to the default realm.
441 * The default realm is present in the krb5_ldap_context structure.
442 * The principal has a realm portion. This realm portion is compared with the default realm
443 * to check whether the principal belong to the default realm.
444 * Return 0 if principal belongs to default realm else 1.
445 */
446
447 krb5_error_code
is_principal_in_realm(ldap_context,searchfor)448 is_principal_in_realm(ldap_context, searchfor)
449 krb5_ldap_context *ldap_context;
450 krb5_const_principal searchfor;
451 {
452 size_t defrealmlen=0;
453 char *defrealm=NULL;
454
455 #define FIND_MAX(a,b) ((a) > (b) ? (a) : (b))
456
457 defrealmlen = strlen(ldap_context->lrparams->realm_name);
458 defrealm = ldap_context->lrparams->realm_name;
459
460 /*
461 * Care should be taken for inter-realm principals as the default
462 * realm can exist in the realm part of the principal name or can
463 * also exist in the second portion of the name part. However, if
464 * the default realm exist in the second part of the principal
465 * portion, then the first portion of the principal name SHOULD be
466 * "krbtgt". All this check is done in the immediate block.
467 */
468 if (searchfor->length == 2)
469 if ((strncasecmp(searchfor->data[0].data, "krbtgt",
470 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) &&
471 (strncasecmp(searchfor->data[1].data, defrealm,
472 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0))
473 return 0;
474
475 /* first check the length, if they are not equal, then they are not same */
476 if (strlen(defrealm) != searchfor->realm.length)
477 return 1;
478
479 /* if the length is equal, check for the contents */
480 if (strncmp(defrealm, searchfor->realm.data,
481 searchfor->realm.length) != 0)
482 return 1;
483 /* if we are here, then the realm portions match, return 0 */
484 return 0;
485 }
486
487
488 /*
489 * Deduce the subtree information from the context. A realm can have
490 * multiple subtrees.
491 * 1. the Realm container
492 * 2. the actual subtrees associated with the Realm
493 *
494 * However, there are some conditions to be considered to deduce the
495 * actual subtree/s associated with the realm. The conditions are as
496 * follows:
497 * 1. If the subtree information of the Realm is [Root] or NULL (that
498 * is internal a [Root]) then the realm has only one subtree
499 * i.e [Root], i.e. whole of the tree.
500 * 2. If the subtree information of the Realm is missing/absent, then the
501 * realm has only one, i.e., the Realm container. NOTE: In all cases
502 * Realm container SHOULD be the one among the subtrees or the only
503 * one subtree.
504 * 3. The subtree information of the realm is overlapping the realm
505 * container of the realm, then the realm has only one subtree and
506 * it is the subtree information associated with the realm.
507 */
508 krb5_error_code
krb5_get_subtree_info(ldap_context,subtreearr,ntree)509 krb5_get_subtree_info(ldap_context, subtreearr, ntree)
510 krb5_ldap_context *ldap_context;
511 char ***subtreearr;
512 unsigned int *ntree;
513 {
514 int st=0, i=0, subtreecount=0;
515 int ncount=0, search_scope=0;
516 char **subtree=NULL, *realm_cont_dn=NULL;
517 char **subtarr=NULL;
518 char *containerref=NULL;
519 char **newsubtree=NULL;
520
521 containerref = ldap_context->lrparams->containerref;
522 subtree = ldap_context->lrparams->subtree;
523 realm_cont_dn = ldap_context->lrparams->realmdn;
524 subtreecount = ldap_context->lrparams->subtreecount;
525 search_scope = ldap_context->lrparams->search_scope;
526
527 subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1));
528 if (subtarr == NULL) {
529 st = ENOMEM;
530 goto cleanup;
531 }
532 memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1)));
533
534 /* get the complete subtree list */
535 for (i=0; i<subtreecount && subtree[i]!=NULL; i++) {
536 subtarr[i] = strdup(subtree[i]);
537 if (subtarr[i] == NULL) {
538 st = ENOMEM;
539 goto cleanup;
540 }
541 }
542
543 subtarr[i] = strdup(realm_cont_dn);
544 if (subtarr[i++] == NULL) {
545 st = ENOMEM;
546 goto cleanup;
547 }
548
549 if (containerref != NULL) {
550 subtarr[i] = strdup(containerref);
551 if (subtarr[i++] == NULL) {
552 st = ENOMEM;
553 goto cleanup;
554 }
555 }
556
557 ncount = i;
558 newsubtree = (char **) malloc(sizeof(char *) * (ncount + 1));
559 if (newsubtree == NULL) {
560 st = ENOMEM;
561 goto cleanup;
562 }
563 memset(newsubtree, 0, (sizeof(char *) * (ncount+1)));
564 if ((st = remove_overlapping_subtrees(subtarr, newsubtree, &ncount,
565 search_scope)) != 0) {
566 goto cleanup;
567 }
568
569 *ntree = ncount;
570 *subtreearr = newsubtree;
571
572 cleanup:
573 if (subtarr != NULL) {
574 for (i=0; subtarr[i] != NULL; i++)
575 free(subtarr[i]);
576 free(subtarr);
577 }
578
579 if (st != 0) {
580 if (newsubtree != NULL) {
581 for (i=0; newsubtree[i] != NULL; i++)
582 free(newsubtree[i]);
583 free(newsubtree);
584 }
585 }
586 return st;
587 }
588
589 /*
590 * This function appends the content with a type into the tl_data
591 * structure. Based on the type the length of the content is either
592 * pre-defined or computed from the content. Returns 0 in case of
593 * success and 1 if the type associated with the content is undefined.
594 */
595
596 krb5_error_code
store_tl_data(tl_data,tl_type,value)597 store_tl_data(tl_data, tl_type, value)
598 krb5_tl_data *tl_data;
599 int tl_type;
600 void *value;
601 {
602 unsigned int currlen=0, tldatalen=0;
603 unsigned char *curr=NULL;
604 void *reallocptr=NULL;
605
606 tl_data->tl_data_type = KDB_TL_USER_INFO;
607 switch (tl_type) {
608 case KDB_TL_PRINCCOUNT:
609 case KDB_TL_PRINCTYPE:
610 case KDB_TL_MASK:
611 {
612 int *iptr = (int *)value;
613 int ivalue = *iptr;
614
615 currlen = tl_data->tl_data_length;
616 tl_data->tl_data_length += 1 + 2 + 2;
617 /* allocate required memory */
618 reallocptr = tl_data->tl_data_contents;
619 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
620 tl_data->tl_data_length);
621 if (tl_data->tl_data_contents == NULL) {
622 if (reallocptr)
623 free (reallocptr);
624 return ENOMEM;
625 }
626 curr = (tl_data->tl_data_contents + currlen);
627
628 /* store the tl_type value */
629 memset(curr, tl_type, 1);
630 curr += 1;
631 /* store the content length */
632 tldatalen = 2;
633 STORE16_INT(curr, tldatalen);
634 curr += 2;
635 /* store the content */
636 STORE16_INT(curr, ivalue);
637 curr += 2;
638 break;
639 }
640
641 case KDB_TL_USERDN:
642 case KDB_TL_LINKDN:
643 {
644 char *cptr = (char *)value;
645
646 currlen = tl_data->tl_data_length;
647 tl_data->tl_data_length += 1 + 2 + strlen(cptr);
648 /* allocate required memory */
649 reallocptr = tl_data->tl_data_contents;
650 tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
651 tl_data->tl_data_length);
652 if (tl_data->tl_data_contents == NULL) {
653 if (reallocptr)
654 free (reallocptr);
655 return ENOMEM;
656 }
657 curr = (tl_data->tl_data_contents + currlen);
658
659 /* store the tl_type value */
660 memset(curr, tl_type, 1);
661 curr += 1;
662 /* store the content length */
663 tldatalen = strlen(cptr);
664 STORE16_INT(curr, tldatalen);
665 curr += 2;
666 /* store the content */
667 memcpy(curr, cptr, tldatalen);
668 curr += tldatalen;
669 break;
670 }
671
672 default:
673 return 1;
674
675 }
676 return 0;
677 }
678
679 /*
680 * This function scans the tl_data structure to get the value of a
681 * type defined by the tl_type (second parameter). The tl_data
682 * structure has all the data in the tl_data_contents member. The
683 * format of the tl_data_contents is as follows. The first byte
684 * defines the type of the content that follows. The next 2 bytes
685 * define the size n (in terms of bytes) of the content that
686 * follows. The next n bytes define the content itself.
687 */
688
689 krb5_error_code
decode_tl_data(tl_data,tl_type,data)690 decode_tl_data(tl_data, tl_type, data)
691 krb5_tl_data *tl_data;
692 int tl_type;
693 void **data;
694 {
695 int subtype=0, i=0, limit=10;
696 unsigned int sublen=0;
697 unsigned char *curr=NULL;
698 int *intptr=NULL;
699 long *longptr=NULL;
700 char *DN=NULL, **DNarr=NULL;
701 krb5_error_code st=-1;
702
703 *data = NULL;
704
705 curr = tl_data->tl_data_contents;
706 while (curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) {
707
708 /* get the type of the content */
709 subtype = (int) curr[0];
710 /* forward by 1 byte*/
711 curr += 1;
712
713 if (subtype == tl_type) {
714 switch (subtype) {
715
716 case KDB_TL_PRINCCOUNT:
717 case KDB_TL_PRINCTYPE:
718 case KDB_TL_MASK:
719 /* get the length of the content */
720 UNSTORE16_INT(curr, sublen);
721 /* forward by 2 bytes */
722 curr += 2;
723 /* get the actual content */
724 if (sublen == 2) {
725 /* intptr = malloc(sublen); */
726 intptr = malloc(sizeof(krb5_int32));
727 if (intptr == NULL)
728 return ENOMEM;
729 memset(intptr, 0, sublen);
730 UNSTORE16_INT(curr, (*intptr));
731 *data = intptr;
732 } else {
733 longptr = malloc(sublen);
734 if (longptr == NULL)
735 return ENOMEM;
736 memset(longptr, 0, sublen);
737 UNSTORE32_INT(curr, (*longptr));
738 *data = longptr;
739 }
740 curr += sublen;
741 st = 0;
742 return st;
743 /*LINTED*/
744 break;
745
746 case KDB_TL_CONTAINERDN:
747 case KDB_TL_USERDN:
748 /* get the length of the content */
749 UNSTORE16_INT(curr, sublen);
750 /* forward by 2 bytes */
751 curr += 2;
752 DN = malloc (sublen + 1);
753 if (DN == NULL)
754 return ENOMEM;
755 memcpy(DN, curr, sublen);
756 DN[sublen] = 0;
757 *data = DN;
758 curr += sublen;
759 st = 0;
760 return st;
761 /*LINTED*/
762 break;
763
764 case KDB_TL_LINKDN:
765 if (DNarr == NULL) {
766 DNarr = calloc(limit, sizeof(char *));
767 if (DNarr == NULL)
768 return ENOMEM;
769 }
770 if (i == limit-1) {
771 limit *= 2;
772 DNarr = realloc(DNarr, sizeof(char *) * (limit));
773 if (DNarr == NULL)
774 return ENOMEM;
775 }
776
777 /* get the length of the content */
778 UNSTORE16_INT(curr, sublen);
779 /* forward by 2 bytes */
780 curr += 2;
781 DNarr[i] = malloc (sublen + 1);
782 if (DNarr[i] == NULL) {
783 int j=0;
784 for (; j<i; j++)
785 free(DNarr[j]);
786 free(DNarr);
787 return ENOMEM;
788 }
789 memcpy(DNarr[i], curr, sublen);
790 DNarr[i][sublen] = 0;
791 ++i;
792 curr += sublen;
793 *data = DNarr;
794 st=0;
795 break;
796 }
797 } else {
798 /* move to the current content block */
799 UNSTORE16_INT(curr, sublen);
800 curr += 2 + sublen;
801 }
802 }
803 return st;
804 }
805
806 /*
807 * wrapper routines for decode_tl_data
808 */
809 static krb5_error_code
krb5_get_int_from_tl_data(context,entries,type,intval)810 krb5_get_int_from_tl_data(context, entries, type, intval)
811 krb5_context context;
812 krb5_db_entry *entries;
813 int type;
814 int *intval;
815 {
816 krb5_error_code st=0;
817 krb5_tl_data tl_data;
818 void *voidptr=NULL;
819 int *intptr=NULL;
820
821 tl_data.tl_data_type = KDB_TL_USER_INFO;
822 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
823 goto cleanup;
824
825 if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
826 intptr = (int *) voidptr;
827 *intval = *intptr;
828 free(intptr);
829 }
830
831 cleanup:
832 return st;
833 }
834
835 /*
836 * Get the mask representing the attributes set on the directory
837 * object (user, policy ...).
838 */
839 krb5_error_code
krb5_get_attributes_mask(context,entries,mask)840 krb5_get_attributes_mask(context, entries, mask)
841 krb5_context context;
842 krb5_db_entry *entries;
843 unsigned int *mask;
844 {
845 return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK,
846 (int *)mask);
847 }
848
849 krb5_error_code
krb5_get_princ_type(context,entries,ptype)850 krb5_get_princ_type(context, entries, ptype)
851 krb5_context context;
852 krb5_db_entry *entries;
853 int *ptype;
854 {
855 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype);
856 }
857
858 krb5_error_code
krb5_get_princ_count(context,entries,pcount)859 krb5_get_princ_count(context, entries, pcount)
860 krb5_context context;
861 krb5_db_entry *entries;
862 int *pcount;
863 {
864 return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount);
865 }
866
867 krb5_error_code
krb5_get_linkdn(context,entries,link_dn)868 krb5_get_linkdn(context, entries, link_dn)
869 krb5_context context;
870 krb5_db_entry *entries;
871 char ***link_dn;
872 {
873 krb5_error_code st=0;
874 krb5_tl_data tl_data;
875 void *voidptr=NULL;
876
877 *link_dn = NULL;
878 tl_data.tl_data_type = KDB_TL_USER_INFO;
879 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
880 goto cleanup;
881
882 if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) {
883 *link_dn = (char **) voidptr;
884 }
885
886 cleanup:
887 return st;
888 }
889
890 static krb5_error_code
krb5_get_str_from_tl_data(context,entries,type,strval)891 krb5_get_str_from_tl_data(context, entries, type, strval)
892 krb5_context context;
893 krb5_db_entry *entries;
894 int type;
895 char **strval;
896 {
897 krb5_error_code st=0;
898 krb5_tl_data tl_data;
899 void *voidptr=NULL;
900
901 if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) {
902 st = EINVAL;
903 goto cleanup;
904 }
905
906 tl_data.tl_data_type = KDB_TL_USER_INFO;
907 if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
908 goto cleanup;
909
910 if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
911 *strval = (char *) voidptr;
912 }
913
914 cleanup:
915 return st;
916 }
917
918 krb5_error_code
krb5_get_userdn(context,entries,userdn)919 krb5_get_userdn(context, entries, userdn)
920 krb5_context context;
921 krb5_db_entry *entries;
922 char **userdn;
923 {
924 *userdn = NULL;
925 return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn);
926 }
927
928 krb5_error_code
krb5_get_containerdn(context,entries,containerdn)929 krb5_get_containerdn(context, entries, containerdn)
930 krb5_context context;
931 krb5_db_entry *entries;
932 char **containerdn;
933 {
934 *containerdn = NULL;
935 return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn);
936 }
937
938 /*
939 * This function reads the attribute values (if the attribute is
940 * non-null) from the dn. The read attribute values is compared
941 * aganist the attrvalues passed to the function and a bit mask is set
942 * for all the matching attributes (attributes existing in both list).
943 * The bit to be set is selected such that the index of the attribute
944 * in the attrvalues parameter is the position of the bit. For ex:
945 * the first element in the attrvalues is present in both list shall
946 * set the LSB of the bit mask.
947 *
948 * In case if either the attribute or the attrvalues parameter to the
949 * function is NULL, then the existence of the object is considered
950 * and appropriate status is returned back.
951 */
952
953 krb5_error_code
checkattributevalue(ld,dn,attribute,attrvalues,mask)954 checkattributevalue (ld, dn, attribute, attrvalues, mask)
955 LDAP *ld;
956 char *dn;
957 char *attribute;
958 char **attrvalues;
959 int *mask;
960 {
961 int st=0, one=1;
962 char **values=NULL, *attributes[2] = {NULL};
963 LDAPMessage *result=NULL, *entry=NULL;
964
965 if (strlen(dn) == 0) {
966 st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
967 return st;
968 }
969
970 attributes[0] = attribute;
971
972 /* read the attribute values from the dn */
973 if ((st = ldap_search_ext_s(ld,
974 dn,
975 LDAP_SCOPE_BASE,
976 0,
977 attributes,
978 0,
979 NULL,
980 NULL,
981 &timelimit,
982 LDAP_NO_LIMIT,
983 &result)) != LDAP_SUCCESS) {
984 st = set_ldap_error(0, st, OP_SEARCH);
985 return st;
986 }
987
988 /*
989 * If the attribute/attrvalues is NULL, then check for the
990 * existence of the object alone.
991 */
992 if (attribute == NULL || attrvalues == NULL)
993 goto cleanup;
994
995 /* reset the bit mask */
996 *mask = 0;
997
998 if ((entry=ldap_first_entry(ld, result)) != NULL) {
999 /* read the attribute values */
1000 if ((values=ldap_get_values(ld, entry, attribute)) != NULL) {
1001 int i,j;
1002
1003 /*
1004 * Compare the read attribute values with the attrvalues
1005 * array and set the appropriate bit mask.
1006 */
1007 for (j=0; attrvalues[j]; ++j) {
1008 for (i=0; values[i]; ++i) {
1009 if (strcasecmp(values[i], attrvalues[j]) == 0) {
1010 *mask |= (one<<j);
1011 break;
1012 }
1013 }
1014 }
1015 ldap_value_free(values);
1016 }
1017 }
1018
1019 cleanup:
1020 ldap_msgfree(result);
1021 return st;
1022 }
1023
1024
1025 /*
1026 * This function updates a single attribute with a single value of a
1027 * specified dn. This function is mainly used to update
1028 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
1029 * ADMIN, PASSWD servers are associated with some realms or vice
1030 * versa.
1031 */
1032
1033 krb5_error_code
updateAttribute(ld,dn,attribute,value)1034 updateAttribute (ld, dn, attribute, value)
1035 LDAP *ld;
1036 char *dn;
1037 char *attribute;
1038 char *value;
1039 {
1040 int st=0;
1041 LDAPMod modAttr, *mods[2]={NULL};
1042 char *values[2]={NULL};
1043
1044 values[0] = value;
1045
1046 /* data to update the {attr,attrval} combination */
1047 memset(&modAttr, 0, sizeof(modAttr));
1048 modAttr.mod_type = attribute;
1049 modAttr.mod_op = LDAP_MOD_ADD;
1050 modAttr.mod_values = values;
1051 mods[0] = &modAttr;
1052
1053 /* ldap modify operation */
1054 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1055
1056 /* if the {attr,attrval} combination is already present return a success
1057 * LDAP_ALREADY_EXISTS is for single-valued attribute
1058 * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute
1059 */
1060 if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS)
1061 st = 0;
1062
1063 if (st != 0) {
1064 st = set_ldap_error (0, st, OP_MOD);
1065 }
1066
1067 return st;
1068 }
1069
1070 /*
1071 * This function deletes a single attribute with a single value of a
1072 * specified dn. This function is mainly used to delete
1073 * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
1074 * ADMIN, PASSWD servers are disassociated with some realms or vice
1075 * versa.
1076 */
1077
1078 krb5_error_code
deleteAttribute(ld,dn,attribute,value)1079 deleteAttribute (ld, dn, attribute, value)
1080 LDAP *ld;
1081 char *dn;
1082 char *attribute;
1083 char *value;
1084 {
1085 krb5_error_code st=0;
1086 LDAPMod modAttr, *mods[2]={NULL};
1087 char *values[2]={NULL};
1088
1089 values[0] = value;
1090
1091 /* data to delete the {attr,attrval} combination */
1092 memset(&modAttr, 0, sizeof(modAttr));
1093 modAttr.mod_type = attribute;
1094 modAttr.mod_op = LDAP_MOD_DELETE;
1095 modAttr.mod_values = values;
1096 mods[0] = &modAttr;
1097
1098 /* ldap modify operation */
1099 st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1100
1101 /* if either the attribute or the attribute value is missing return a success */
1102 if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE)
1103 st = 0;
1104
1105 if (st != 0) {
1106 st = set_ldap_error (0, st, OP_MOD);
1107 }
1108
1109 return st;
1110 }
1111
1112
1113 /*
1114 * This function takes in 2 string arrays, compares them to remove the
1115 * matching entries. The first array is the original list and the
1116 * second array is the modified list. Removing the matching entries
1117 * will result in a reduced array, where the left over first array
1118 * elements are the deleted entries and the left over second array
1119 * elements are the added entries. These additions and deletions has
1120 * resulted in the modified second array.
1121 */
1122
1123 krb5_error_code
disjoint_members(src,dest)1124 disjoint_members(src, dest)
1125 char **src;
1126 char **dest;
1127 {
1128 int i=0, j=0, slen=0, dlen=0;
1129
1130 /* validate the input parameters */
1131 if (src == NULL || dest == NULL)
1132 return 0;
1133
1134 /* compute the first array length */
1135 for (i=0;src[i]; ++i)
1136 ;
1137
1138 /* return if the length is 0 */
1139 if (i==0)
1140 return 0;
1141
1142 /* index of the last element and also the length of the array */
1143 slen = i-1;
1144
1145 /* compute the second array length */
1146 for (i=0;dest[i]; ++i)
1147 ;
1148
1149 /* return if the length is 0 */
1150 if (i==0)
1151 return 0;
1152
1153 /* index of the last element and also the length of the array */
1154 dlen = i-1;
1155
1156 /* check for the similar elements and delete them from both the arrays */
1157 for (i=0; src[i]; ++i) {
1158
1159 for (j=0; dest[j]; ++j) {
1160
1161 /* if the element are same */
1162 if (strcasecmp(src[i], dest[j]) == 0) {
1163 /*
1164 * If the matched element is in the middle, then copy
1165 * the last element to the matched index.
1166 */
1167 if (i != slen) {
1168 free (src[i]);
1169 src[i] = src[slen];
1170 src[slen] = NULL;
1171 } else {
1172 /*
1173 * If the matched element is the last, free it and
1174 * set it to NULL.
1175 */
1176 free (src[i]);
1177 src[i] = NULL;
1178 }
1179 /* reduce the array length by 1 */
1180 slen -= 1;
1181
1182 /* repeat the same processing for the second array too */
1183 if (j != dlen) {
1184 free(dest[j]);
1185 dest[j] = dest[dlen];
1186 dest[dlen] = NULL;
1187 } else {
1188 free(dest[j]);
1189 dest[j] = NULL;
1190 }
1191 dlen -=1;
1192
1193 /*
1194 * The source array is reduced by 1, so reduce the
1195 * index variable used for source array by 1. No need
1196 * to adjust the second array index variable as it is
1197 * reset while entering the inner loop.
1198 */
1199 i -= 1;
1200 break;
1201 }
1202 }
1203 }
1204 return 0;
1205 }
1206
1207 /*
1208 * This function replicates the contents of the src array for later
1209 * use. Mostly the contents of the src array is obtained from a
1210 * ldap_search operation and the contents are required for later use.
1211 */
1212
1213 krb5_error_code
copy_arrays(src,dest,count)1214 copy_arrays(src, dest, count)
1215 char **src;
1216 char ***dest;
1217 int count;
1218 {
1219 krb5_error_code st=0;
1220 int i=0;
1221
1222 /* validate the input parameters */
1223 if (src == NULL || dest == NULL)
1224 return 0;
1225
1226 /* allocate memory for the dest array */
1227 *dest = (char **) calloc((unsigned) count+1, sizeof(char *));
1228 if (*dest == NULL) {
1229 st = ENOMEM;
1230 goto cleanup;
1231 }
1232
1233 /* copy the members from src to dest array. */
1234 for (i=0; i < count && src[i] != NULL; ++i) {
1235 (*dest)[i] = strdup(src[i]);
1236 if ((*dest)[i] == NULL) {
1237 st = ENOMEM;
1238 goto cleanup;
1239 }
1240 }
1241
1242 cleanup:
1243 /* in case of error free up everything and return */
1244 if (st != 0) {
1245 if (*dest != NULL) {
1246 for (i=0; (*dest)[i]; ++i) {
1247 free ((*dest)[i]);
1248 (*dest)[i] = NULL;
1249 }
1250 free (*dest);
1251 *dest = NULL;
1252 }
1253 }
1254 return st;
1255 }
1256
1257 static krb5_error_code
getepochtime(strtime,epochtime)1258 getepochtime(strtime, epochtime)
1259 char *strtime;
1260 krb5_timestamp *epochtime;
1261 {
1262 struct tm tme;
1263
1264 memset(&tme, 0, sizeof(tme));
1265 if (strptime(strtime, DATE_FORMAT, &tme) == NULL) {
1266 *epochtime = 0;
1267 return EINVAL;
1268 }
1269
1270 *epochtime = krb5int_gmt_mktime(&tme);
1271
1272 return 0;
1273 }
1274
1275 /*
1276 * krb5_ldap_get_value() - get the integer value of the attribute
1277 * Returns, 0 if the attribute is present, 1 if the attribute is missing.
1278 * The retval is 0 if the attribute is missing.
1279 */
1280
1281 krb5_error_code
krb5_ldap_get_value(ld,ent,attribute,retval)1282 krb5_ldap_get_value(ld, ent, attribute, retval)
1283 LDAP *ld;
1284 LDAPMessage *ent;
1285 char *attribute;
1286 int *retval;
1287 {
1288 char **values=NULL;
1289
1290 *retval = 0;
1291 values=ldap_get_values(ld, ent, attribute);
1292 if (values != NULL) {
1293 if (values[0] != NULL)
1294 *retval = atoi(values[0]);
1295 ldap_value_free(values);
1296 return 0;
1297 }
1298 return 1;
1299 }
1300
1301 /*
1302 * krb5_ldap_get_string() - Returns the first string of the
1303 * attribute. Intended to
1304 *
1305 *
1306 */
1307 krb5_error_code
krb5_ldap_get_string(ld,ent,attribute,retstr,attr_present)1308 krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present)
1309 LDAP *ld;
1310 LDAPMessage *ent;
1311 char *attribute;
1312 char **retstr;
1313 krb5_boolean *attr_present;
1314 {
1315 char **values=NULL;
1316 krb5_error_code st=0;
1317
1318 *retstr = NULL;
1319 if (attr_present != NULL)
1320 *attr_present = FALSE;
1321
1322 values=ldap_get_values(ld, ent, attribute);
1323 if (values != NULL) {
1324 if (values[0] != NULL) {
1325 if (attr_present!= NULL)
1326 *attr_present = TRUE;
1327 *retstr = strdup(values[0]);
1328 if (*retstr == NULL)
1329 st = ENOMEM;
1330 }
1331 ldap_value_free(values);
1332 }
1333 return st;
1334 }
1335
1336 /*
1337 * krb5_ldap_get_strings() - Returns all the values
1338 * of the attribute.
1339 */
1340 krb5_error_code
krb5_ldap_get_strings(ld,ent,attribute,retarr,attr_present)1341 krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present)
1342 LDAP *ld;
1343 LDAPMessage *ent;
1344 char *attribute;
1345 char ***retarr;
1346 krb5_boolean *attr_present;
1347 {
1348 char **values=NULL;
1349 krb5_error_code st=0;
1350 unsigned int i=0, count=0;
1351
1352 *retarr = NULL;
1353 if (attr_present != NULL)
1354 *attr_present = FALSE;
1355
1356 values=ldap_get_values(ld, ent, attribute);
1357 if (values != NULL) {
1358 if (attr_present != NULL)
1359 *attr_present = TRUE;
1360
1361 count = ldap_count_values(values);
1362 *retarr = (char **) calloc(count+1, sizeof(char *));
1363 if (*retarr == NULL) {
1364 st = ENOMEM;
1365 return st;
1366 }
1367 for (i=0; i< count; ++i) {
1368 (*retarr)[i] = strdup(values[i]);
1369 if ((*retarr)[i] == NULL) {
1370 st = ENOMEM;
1371 goto cleanup;
1372 }
1373 }
1374 ldap_value_free(values);
1375 }
1376
1377 cleanup:
1378 if (st != 0) {
1379 if (*retarr != NULL) {
1380 for (i=0; i< count; ++i)
1381 if ((*retarr)[i] != NULL)
1382 free ((*retarr)[i]);
1383 free (*retarr);
1384 }
1385 }
1386 return st;
1387 }
1388
1389 krb5_error_code
krb5_ldap_get_time(ld,ent,attribute,rettime,attr_present)1390 krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present)
1391 LDAP *ld;
1392 LDAPMessage *ent;
1393 char *attribute;
1394 krb5_timestamp *rettime;
1395 krb5_boolean *attr_present;
1396 {
1397 char **values=NULL;
1398 krb5_error_code st=0;
1399
1400 *rettime = 0;
1401 *attr_present = FALSE;
1402
1403 values=ldap_get_values(ld, ent, attribute);
1404 if (values != NULL) {
1405 if (values[0] != NULL) {
1406 *attr_present = TRUE;
1407 st = getepochtime(values[0], rettime);
1408 }
1409 ldap_value_free(values);
1410 }
1411 return st;
1412 }
1413
1414 /*
1415 * Function to allocate, set the values of LDAPMod structure. The
1416 * LDAPMod structure is then added to the array at the ind
1417 */
1418
1419 krb5_error_code
krb5_add_member(mods,count)1420 krb5_add_member(mods, count)
1421 LDAPMod ***mods;
1422 int *count;
1423 {
1424 int i=0;
1425 LDAPMod **lmods=NULL;
1426
1427 if ((*mods) != NULL) {
1428 for (;(*mods)[i] != NULL; ++i)
1429 ;
1430 }
1431 lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *));
1432 if (lmods == NULL)
1433 return ENOMEM;
1434
1435 *mods = lmods;
1436 (*mods)[i+1] = NULL;
1437 (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod));
1438 if ((*mods)[i] == NULL) {
1439 free(lmods);
1440 *mods = NULL;
1441 return ENOMEM;
1442 }
1443 *count = i;
1444 return 0;
1445 }
1446
1447 krb5_error_code
krb5_add_str_mem_ldap_mod(mods,attribute,op,values)1448 krb5_add_str_mem_ldap_mod(mods, attribute, op, values)
1449 LDAPMod ***mods;
1450 char *attribute;
1451 int op;
1452 char **values;
1453
1454 {
1455 int i=0, j=0;
1456 krb5_error_code st=0;
1457
1458 if ((st=krb5_add_member(mods, &i)) != 0)
1459 return st;
1460
1461 (*mods)[i]->mod_type = strdup(attribute);
1462 if ((*mods)[i]->mod_type == NULL)
1463 return ENOMEM;
1464 (*mods)[i]->mod_op = op;
1465
1466 (*mods)[i]->mod_values = NULL;
1467
1468 if (values != NULL) {
1469 for (j=0; values[j] != NULL; ++j)
1470 ;
1471 (*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1));
1472 if ((*mods)[i]->mod_values == NULL) {
1473 free((*mods)[i]->mod_type);
1474 (*mods)[i]->mod_type = NULL;
1475 return ENOMEM;
1476 }
1477
1478 for (j=0; values[j] != NULL; ++j) {
1479 (*mods)[i]->mod_values[j] = strdup(values[j]);
1480 if ((*mods)[i]->mod_values[j] == NULL){
1481 int k=0;
1482 for (; k<j; k++) {
1483 free((*mods)[i]->mod_values[k]);
1484 (*mods)[i]->mod_values[k] = NULL;
1485 }
1486 return ENOMEM;
1487 }
1488 }
1489 (*mods)[i]->mod_values[j] = NULL;
1490 }
1491 return 0;
1492 }
1493
1494 krb5_error_code
krb5_add_ber_mem_ldap_mod(mods,attribute,op,ber_values)1495 krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values)
1496 LDAPMod ***mods;
1497 char *attribute;
1498 int op;
1499 struct berval **ber_values;
1500
1501 {
1502 int i=0, j=0;
1503 krb5_error_code st=0;
1504
1505 if ((st=krb5_add_member(mods, &i)) != 0)
1506 return st;
1507
1508 (*mods)[i]->mod_type = strdup(attribute);
1509 if ((*mods)[i]->mod_type == NULL)
1510 return ENOMEM;
1511 (*mods)[i]->mod_op = op;
1512
1513 for (j=0; ber_values[j] != NULL; ++j)
1514 ;
1515 (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1));
1516 if ((*mods)[i]->mod_bvalues == NULL)
1517 return ENOMEM;
1518
1519 for (j=0; ber_values[j] != NULL; ++j) {
1520 (*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval));
1521 if ((*mods)[i]->mod_bvalues[j] == NULL)
1522 return ENOMEM;
1523
1524 (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len;
1525 (*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len);
1526 if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL)
1527 return ENOMEM;
1528
1529 memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val,
1530 ber_values[j]->bv_len);
1531 }
1532 (*mods)[i]->mod_bvalues[j] = NULL;
1533 return 0;
1534 }
1535
1536 static inline char *
format_d(int val)1537 format_d (int val)
1538 {
1539 char tmpbuf[2+3*sizeof(val)];
1540 sprintf(tmpbuf, "%d", val);
1541 return strdup(tmpbuf);
1542 }
1543
1544 krb5_error_code
krb5_add_int_arr_mem_ldap_mod(mods,attribute,op,value)1545 krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value)
1546 LDAPMod ***mods;
1547 char *attribute;
1548 int op;
1549 int *value;
1550
1551 {
1552 int i=0, j=0;
1553 krb5_error_code st=0;
1554
1555 if ((st=krb5_add_member(mods, &i)) != 0)
1556 return st;
1557
1558 (*mods)[i]->mod_type = strdup(attribute);
1559 if ((*mods)[i]->mod_type == NULL)
1560 return ENOMEM;
1561 (*mods)[i]->mod_op = op;
1562
1563 for (j=0; value[j] != -1; ++j)
1564 ;
1565
1566 (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1));
1567
1568 for (j=0; value[j] != -1; ++j) {
1569 if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL)
1570 return ENOMEM;
1571 }
1572 (*mods)[i]->mod_values[j] = NULL;
1573 return 0;
1574 }
1575
1576 krb5_error_code
krb5_add_int_mem_ldap_mod(mods,attribute,op,value)1577 krb5_add_int_mem_ldap_mod(mods, attribute, op, value)
1578 LDAPMod ***mods;
1579 char *attribute;
1580 int op;
1581 int value;
1582
1583 {
1584 int i=0;
1585 krb5_error_code st=0;
1586
1587 if ((st=krb5_add_member(mods, &i)) != 0)
1588 return st;
1589
1590 (*mods)[i]->mod_type = strdup(attribute);
1591 if ((*mods)[i]->mod_type == NULL)
1592 return ENOMEM;
1593
1594 (*mods)[i]->mod_op = op;
1595 (*mods)[i]->mod_values = calloc (2, sizeof(char *));
1596 if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL)
1597 return ENOMEM;
1598 return 0;
1599 }
1600
1601 /*ARGSUSED*/
1602 krb5_error_code
krb5_ldap_set_option(krb5_context kcontext,int option,void * value)1603 krb5_ldap_set_option(krb5_context kcontext, int option, void *value)
1604 {
1605 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1606 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1607 return status;
1608 }
1609
1610 /*ARGSUSED*/
1611 krb5_error_code
krb5_ldap_lock(krb5_context kcontext,int mode)1612 krb5_ldap_lock(krb5_context kcontext, int mode)
1613 {
1614 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1615 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1616 return status;
1617 }
1618
1619 krb5_error_code
krb5_ldap_unlock(krb5_context kcontext)1620 krb5_ldap_unlock(krb5_context kcontext)
1621 {
1622 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1623 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1624 return status;
1625 }
1626
1627 /*ARGSUSED*/
1628 krb5_error_code
krb5_ldap_supported_realms(krb5_context kcontext,char ** realms)1629 krb5_ldap_supported_realms(krb5_context kcontext, char **realms)
1630 {
1631 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1632 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1633 return status;
1634 }
1635
1636 /*ARGSUSED*/
1637 krb5_error_code
krb5_ldap_free_supported_realms(krb5_context kcontext,char ** realms)1638 krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms)
1639 {
1640 krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
1641 krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
1642 return status;
1643 }
1644
1645 const char *
krb5_ldap_errcode_2_string(krb5_context kcontext,long err_code)1646 krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code)
1647 {
1648 return krb5_get_error_message(kcontext, err_code);
1649 }
1650
1651 void
krb5_ldap_release_errcode_string(krb5_context kcontext,const char * msg)1652 krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg)
1653 {
1654 krb5_free_error_message(kcontext, msg);
1655 }
1656
1657
1658 /*
1659 * Get the number of times an object has been referred to in a realm. this is
1660 * needed to find out if deleting the attribute will cause dangling links.
1661 *
1662 * An LDAP handle may be optionally specified to prevent race condition - there
1663 * are a limited number of LDAP handles.
1664 */
1665 krb5_error_code
krb5_ldap_get_reference_count(krb5_context context,char * dn,char * refattr,int * count,LDAP * ld)1666 krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr,
1667 int *count, LDAP *ld)
1668 {
1669 int st = 0, tempst = 0, gothandle = 0;
1670 unsigned int i, ntrees;
1671 char *refcntattr[2];
1672 char *filter = NULL;
1673 char **subtree = NULL, *ptr = NULL;
1674 kdb5_dal_handle *dal_handle = NULL;
1675 krb5_ldap_context *ldap_context = NULL;
1676 krb5_ldap_server_handle *ldap_server_handle = NULL;
1677 LDAPMessage *result = NULL;
1678
1679
1680 if (dn == NULL || refattr == NULL) {
1681 st = EINVAL;
1682 goto cleanup;
1683 }
1684
1685 SETUP_CONTEXT();
1686 if (ld == NULL) {
1687 GET_HANDLE();
1688 gothandle = 1;
1689 }
1690
1691 refcntattr [0] = refattr;
1692 refcntattr [1] = NULL;
1693
1694 ptr = ldap_filter_correct (dn);
1695 if (ptr == NULL) {
1696 st = ENOMEM;
1697 goto cleanup;
1698 }
1699
1700 filter = (char *) malloc (strlen (refattr) + strlen (ptr) + 2);
1701 if (filter == NULL) {
1702 st = ENOMEM;
1703 goto cleanup;
1704 }
1705
1706 /*LINTED*/
1707 sprintf (filter, "%s=%s", refattr, ptr);
1708
1709 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
1710 goto cleanup;
1711
1712 for (i = 0, *count = 0; i < ntrees; i++) {
1713 int n;
1714
1715 LDAP_SEARCH(subtree[i],
1716 LDAP_SCOPE_SUBTREE,
1717 filter,
1718 refcntattr);
1719 n = ldap_count_entries (ld, result);
1720 if (n == -1) {
1721 int ret, errcode = 0;
1722 ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0);
1723 if (ret != LDAP_SUCCESS)
1724 errcode = ret;
1725 st = translate_ldap_error (errcode, OP_SEARCH);
1726 goto cleanup;
1727 }
1728
1729 ldap_msgfree(result);
1730 result = NULL;
1731
1732 *count += n;
1733 }
1734
1735 cleanup:
1736 if (filter != NULL)
1737 free (filter);
1738
1739 if (result != NULL)
1740 ldap_msgfree (result);
1741
1742 if (subtree != NULL) {
1743 for (i = 0; i < ntrees; i++)
1744 free (subtree[i]);
1745 free (subtree);
1746 }
1747
1748 if (ptr != NULL)
1749 free (ptr);
1750
1751 if (gothandle == 1)
1752 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1753
1754 return st;
1755 }
1756
1757 /*
1758 * For now, policy objects are expected to be directly under the realm
1759 * container.
1760 */
krb5_ldap_policydn_to_name(context,policy_dn,name)1761 krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name)
1762 krb5_context context;
1763 char *policy_dn;
1764 char **name;
1765 {
1766 int len1, len2;
1767 krb5_error_code st = 0;
1768 kdb5_dal_handle *dal_handle=NULL;
1769 krb5_ldap_context *ldap_context=NULL;
1770
1771 SETUP_CONTEXT();
1772
1773 if (ldap_context->lrparams->realmdn == NULL) {
1774 st = EINVAL;
1775 goto cleanup;
1776 }
1777
1778 len1 = strlen (ldap_context->lrparams->realmdn);
1779 len2 = strlen (policy_dn);
1780 if (len1 == 0 || len2 == 0 || len1 > len2) {
1781 st = EINVAL;
1782 goto cleanup;
1783 }
1784
1785 if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) {
1786 st = EINVAL;
1787 goto cleanup;
1788 }
1789
1790 #if defined HAVE_LDAP_STR2DN
1791 {
1792 char *rdn;
1793 LDAPDN dn;
1794 rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */
1795
1796 if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) {
1797 st = EINVAL;
1798 goto cleanup;
1799 }
1800 if (dn[0] == NULL || dn[1] != NULL)
1801 st = EINVAL;
1802 else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0)
1803 st = EINVAL;
1804 else {
1805 *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len);
1806 if (*name == NULL)
1807 st = EINVAL;
1808 }
1809
1810 ldap_memfree (dn);
1811 }
1812 #elif defined HAVE_LDAP_EXPLODE_DN
1813 {
1814 char **parsed_dn;
1815
1816 /* 1 = return DN components without type prefix */
1817 parsed_dn = ldap_explode_dn(policy_dn, 1);
1818 if (parsed_dn == NULL) {
1819 st = EINVAL;
1820 } else {
1821 *name = strdup(parsed_dn[0]);
1822 if (*name == NULL)
1823 st = EINVAL;
1824
1825 ldap_value_free(parsed_dn);
1826 }
1827 }
1828 #else
1829 st = EINVAL;
1830 #endif
1831
1832 cleanup:
1833 return st;
1834 }
1835
krb5_ldap_name_to_policydn(context,name,policy_dn)1836 krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn)
1837 krb5_context context;
1838 char *name;
1839 char **policy_dn;
1840 {
1841 int len;
1842 char *ptr = NULL;
1843 krb5_error_code st = 0;
1844 kdb5_dal_handle *dal_handle=NULL;
1845 krb5_ldap_context *ldap_context=NULL;
1846
1847 *policy_dn = NULL;
1848
1849 /* validate the input parameters */
1850 if (name == NULL) {
1851 st = EINVAL;
1852 goto cleanup;
1853 }
1854
1855 /* Used for removing policy reference from an object */
1856 if (name[0] == '\0') {
1857 if ((*policy_dn = strdup ("")) == NULL)
1858 st = ENOMEM;
1859 goto cleanup;
1860 }
1861
1862 SETUP_CONTEXT();
1863
1864 if (ldap_context->lrparams->realmdn == NULL) {
1865 st = EINVAL;
1866 goto cleanup;
1867 }
1868 len = strlen (ldap_context->lrparams->realmdn);
1869
1870 ptr = ldap_filter_correct (name);
1871 if (ptr == NULL) {
1872 st = ENOMEM;
1873 goto cleanup;
1874 }
1875 len += strlen (ptr);
1876
1877 len += sizeof ("cn=") + 3;
1878
1879 *policy_dn = (char *) malloc (len);
1880 if (*policy_dn == NULL) {
1881 st = ENOMEM;
1882 goto cleanup;
1883 }
1884
1885 /*LINTED*/
1886 sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn);
1887
1888 cleanup:
1889 if (ptr != NULL)
1890 free (ptr);
1891 return st;
1892 }
1893
1894 /* remove overlapping and repeated subtree entries from the list of subtrees */
1895 static krb5_error_code
remove_overlapping_subtrees(char ** listin,char ** listop,int * subtcount,int sscope)1896 remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, int sscope)
1897 {
1898 int slen=0, k=0, j=0, lendiff=0;
1899 int count = *subtcount;
1900 char **subtree = listop;
1901
1902 slen = count-1;
1903 for (k=0; k<=slen && listin[k]!=NULL ; k++) {
1904 for (j=k+1; j<=slen && listin[j]!=NULL ;j++) {
1905 lendiff = strlen(listin[k]) - strlen(listin[j]);
1906 if (sscope == 2) {
1907 if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) {
1908 if (k != slen) {
1909 free(listin[k]);
1910 listin[k] = listin[slen];
1911 listin[slen] = NULL;
1912 } else {
1913 free(listin[k]);
1914 listin[k] = NULL;
1915 }
1916 slen-=1;
1917 k-=1;
1918 break;
1919 } else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) {
1920 if (j != slen) {
1921 free(listin[j]);
1922 listin[j] = listin[slen];
1923 listin[slen]=NULL;
1924 } else {
1925 free(listin[j]);
1926 listin[j] = NULL;
1927 }
1928 slen-=1;
1929 j-=1;
1930 }
1931 }
1932 if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) {
1933 if (j != slen) {
1934 free(listin[j]);
1935 listin[j] = listin[slen];
1936 listin[slen]=NULL;
1937 } else {
1938 free(listin[j]);
1939 listin[j] = NULL;
1940 }
1941 slen -=1;
1942 j-=1;
1943 }
1944 }
1945 }
1946 *subtcount=slen+1;
1947 for (k=0; k<*subtcount && listin[k]!=NULL; k++) {
1948 subtree[k] = strdup(listin[k]);
1949 if (subtree[k] == NULL) {
1950 return ENOMEM;
1951 }
1952 }
1953 return 0;
1954 }
1955
1956 /*
1957 * Fill out a krb5_db_entry princ entry struct given a LDAP message containing
1958 * the results of a principal search of the directory.
1959 */
1960 krb5_error_code
populate_krb5_db_entry(krb5_context context,krb5_ldap_context * ldap_context,LDAP * ld,LDAPMessage * ent,krb5_const_principal princ,krb5_db_entry * entry)1961 populate_krb5_db_entry (krb5_context context,
1962 krb5_ldap_context *ldap_context,
1963 LDAP *ld,
1964 LDAPMessage *ent,
1965 krb5_const_principal princ,
1966 krb5_db_entry *entry)
1967 {
1968 krb5_error_code st = 0;
1969 unsigned int mask = 0;
1970 krb5_boolean attr_present = FALSE;
1971 char **values = NULL, *policydn = NULL, *pwdpolicydn = NULL;
1972 char *polname = NULL, *tktpolname = NULL;
1973 struct berval **bvalues = NULL;
1974 krb5_tl_data userinfo_tl_data = {0};
1975 /* Solaris Kerberos: added next line to fix memleak */
1976 krb5_tl_data kadm_tl_data = {NULL};
1977 char **link_references = NULL;
1978 char *DN = NULL;
1979
1980 if (princ == NULL) {
1981 st = EINVAL;
1982 goto cleanup;
1983 } else {
1984 if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0)
1985 goto cleanup;
1986 }
1987 /* get the associated directory user information */
1988 if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
1989 int i, pcount=0, kerberos_principal_object_type=0;
1990 char *user;
1991
1992 if ((st=krb5_unparse_name(context, princ, &user)) != 0)
1993 goto cleanup;
1994
1995 for (i=0; values[i] != NULL; ++i) {
1996 if (strcasecmp(values[i], user) == 0) {
1997 pcount = ldap_count_values(values);
1998 break;
1999 }
2000 }
2001 ldap_value_free(values);
2002 free(user);
2003
2004 if ((DN = ldap_get_dn(ld, ent)) == NULL) {
2005 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st);
2006 st = set_ldap_error(context, st, 0);
2007 goto cleanup;
2008 }
2009
2010 if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) {
2011 for (i=0; values[i] != NULL; ++i)
2012 if (strcasecmp(values[i], "krbprincipal") == 0) {
2013 kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT;
2014 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
2015 &kerberos_principal_object_type)) != 0)
2016 goto cleanup;
2017 break;
2018 }
2019 ldap_value_free(values);
2020 }
2021
2022 /* add principalcount, DN and principaltype user information to tl_data */
2023 if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) ||
2024 ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0))
2025 goto cleanup;
2026 }
2027
2028 /* read all the kerberos attributes */
2029
2030 /* KRBLASTSUCCESSFULAUTH */
2031 if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth",
2032 &(entry->last_success), &attr_present)) != 0)
2033 goto cleanup;
2034 if (attr_present == TRUE)
2035 mask |= KDB_LAST_SUCCESS_ATTR;
2036
2037 /* KRBLASTFAILEDAUTH */
2038 if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth",
2039 &(entry->last_failed), &attr_present)) != 0)
2040 goto cleanup;
2041 if (attr_present == TRUE)
2042 mask |= KDB_LAST_FAILED_ATTR;
2043
2044 /* KRBLOGINFAILEDCOUNT */
2045 if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount",
2046 /* Solaris kerberos: need the cast */
2047 (int *)&(entry->fail_auth_count)) == 0)
2048 mask |= KDB_FAIL_AUTH_COUNT_ATTR;
2049
2050 /* KRBMAXTICKETLIFE */
2051 if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0)
2052 mask |= KDB_MAX_LIFE_ATTR;
2053
2054 /* KRBMAXRENEWABLEAGE */
2055 if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage",
2056 &(entry->max_renewable_life)) == 0)
2057 mask |= KDB_MAX_RLIFE_ATTR;
2058
2059 /* KRBTICKETFLAGS */
2060 if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0)
2061 mask |= KDB_TKT_FLAGS_ATTR;
2062
2063 /* PRINCIPAL EXPIRATION TIME */
2064 if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration),
2065 &attr_present)) != 0)
2066 goto cleanup;
2067 if (attr_present == TRUE)
2068 mask |= KDB_PRINC_EXPIRE_TIME_ATTR;
2069
2070 /* PASSWORD EXPIRATION TIME */
2071 if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration),
2072 &attr_present)) != 0)
2073 goto cleanup;
2074 if (attr_present == TRUE)
2075 mask |= KDB_PWD_EXPIRE_TIME_ATTR;
2076
2077 /* KRBPOLICYREFERENCE */
2078
2079 if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
2080 &attr_present)) != 0)
2081 goto cleanup;
2082 if (attr_present == TRUE) {
2083 mask |= KDB_POL_REF_ATTR;
2084 /* Ensure that the policy is inside the realm container */
2085 if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0)
2086 goto cleanup;
2087 }
2088
2089 /* KRBPWDPOLICYREFERENCE */
2090 if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
2091 &attr_present)) != 0)
2092 goto cleanup;
2093 if (attr_present == TRUE) {
2094 /* Solaris Kerberos: changed this to fix memleak */
2095 /* krb5_tl_data kadm_tl_data; */
2096
2097 mask |= KDB_PWD_POL_REF_ATTR;
2098
2099 /* Ensure that the policy is inside the realm container */
2100 if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0)
2101 goto cleanup;
2102
2103 /* Solaris Kerberos: adding support for key history in LDAP KDB */
2104 if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data, entry->tl_data)) != 0) {
2105 goto cleanup;
2106 }
2107 krb5_dbe_update_tl_data(context, entry, &kadm_tl_data);
2108 }
2109
2110 /* KRBSECRETKEY */
2111 if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) {
2112 mask |= KDB_SECRET_KEY_ATTR;
2113 if ((st=krb5_decode_krbsecretkey(context, entry, bvalues)) != 0)
2114 goto cleanup;
2115 }
2116
2117 /* LAST PASSWORD CHANGE */
2118 {
2119 krb5_timestamp lstpwdchng=0;
2120 if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange",
2121 &lstpwdchng, &attr_present)) != 0)
2122 goto cleanup;
2123 if (attr_present == TRUE) {
2124 if ((st=krb5_dbe_update_last_pwd_change(context, entry,
2125 lstpwdchng)))
2126 goto cleanup;
2127 mask |= KDB_LAST_PWD_CHANGE_ATTR;
2128 }
2129 }
2130
2131 /* KRBOBJECTREFERENCES */
2132 {
2133 int i=0;
2134
2135 if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences",
2136 &link_references, &attr_present)) != 0)
2137 goto cleanup;
2138 if (link_references != NULL) {
2139 for (i=0; link_references[i] != NULL; ++i) {
2140 if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
2141 link_references[i])) != 0)
2142 goto cleanup;
2143 }
2144 }
2145 }
2146
2147 /* Set tl_data */
2148 {
2149 int i;
2150 struct berval **ber_tl_data = NULL;
2151 krb5_tl_data *ptr = NULL;
2152
2153 if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) {
2154 for (i = 0; ber_tl_data[i] != NULL; i++) {
2155 if ((st = berval2tl_data (ber_tl_data[i], &ptr)) != 0)
2156 break;
2157 if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0)
2158 break;
2159 /* Solaris kerberos: fix memory leak */
2160 if (ptr) {
2161 if (ptr->tl_data_contents)
2162 free(ptr->tl_data_contents);
2163 free(ptr);
2164 ptr = NULL;
2165 }
2166 }
2167 ldap_value_free_len (ber_tl_data);
2168 if (st != 0)
2169 goto cleanup;
2170 mask |= KDB_EXTRA_DATA_ATTR;
2171 }
2172 }
2173
2174 /* update the mask of attributes present on the directory object to the tl_data */
2175 if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0)
2176 goto cleanup;
2177 if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0)
2178 goto cleanup;
2179
2180 #ifdef HAVE_EDIRECTORY
2181 {
2182 krb5_timestamp expiretime=0;
2183 char *is_login_disabled=NULL;
2184
2185 /* LOGIN EXPIRATION TIME */
2186 if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime,
2187 &attr_present)) != 0)
2188 goto cleanup;
2189
2190 if (attr_present == TRUE) {
2191 if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) {
2192 if (expiretime < entry->expiration)
2193 entry->expiration = expiretime;
2194 } else {
2195 entry->expiration = expiretime;
2196 }
2197 }
2198
2199 /* LOGIN DISABLED */
2200 if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled,
2201 &attr_present)) != 0)
2202 goto cleanup;
2203 if (attr_present == TRUE) {
2204 if (strcasecmp(is_login_disabled, "TRUE")== 0)
2205 entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
2206 free (is_login_disabled);
2207 }
2208 }
2209 #endif
2210
2211 if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0)
2212 goto cleanup;
2213
2214 /* We already know that the policy is inside the realm container. */
2215 if (polname) {
2216 osa_policy_ent_t pwdpol;
2217 int cnt=0;
2218 krb5_timestamp last_pw_changed;
2219 krb5_ui_4 pw_max_life;
2220
2221 memset(&pwdpol, 0, sizeof(pwdpol));
2222
2223 if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0)
2224 goto cleanup;
2225 pw_max_life = pwdpol->pw_max_life;
2226 /* Solaris Kerberos: fix memory leak */
2227 krb5_ldap_free_password_policy(context, pwdpol);
2228
2229 if (pw_max_life > 0) {
2230 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0)
2231 goto cleanup;
2232
2233 if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == KDB_PWD_EXPIRE_TIME_ATTR) {
2234 if ((last_pw_changed + pw_max_life) < entry->pw_expiration)
2235 entry->pw_expiration = last_pw_changed + pw_max_life;
2236 } else
2237 entry->pw_expiration = last_pw_changed + pw_max_life;
2238 }
2239 }
2240 /* XXX so krb5_encode_princ_contents() will be happy */
2241 entry->len = KRB5_KDB_V1_BASE_LENGTH;
2242
2243 cleanup:
2244
2245 if (DN != NULL)
2246 ldap_memfree(DN);
2247
2248 if (userinfo_tl_data.tl_data_contents != NULL)
2249 free(userinfo_tl_data.tl_data_contents);
2250
2251 /* Solaris Kerberos: added this to fix memleak */
2252 if (kadm_tl_data.tl_data_contents != NULL)
2253 free(kadm_tl_data.tl_data_contents);
2254
2255 if (pwdpolicydn != NULL)
2256 free(pwdpolicydn);
2257
2258 if (polname != NULL)
2259 free(polname);
2260
2261 if (tktpolname != NULL)
2262 free (tktpolname);
2263
2264 if (policydn != NULL)
2265 free(policydn);
2266
2267 if (link_references) {
2268 int i;
2269 for (i=0; link_references[i] != NULL; ++i)
2270 free (link_references[i]);
2271 free (link_references);
2272 }
2273
2274 return (st);
2275 }
2276
2277 /*
2278 * Solaris libldap does not provide the following functions which are in
2279 * OpenLDAP. Note, Solaris Kerberos added the use_SSL to do a SSL init. Also
2280 * added errstr to return specific error if it isn't NULL. Yes, this is ugly
2281 * and no, the errstr should not be free()'ed.
2282 */
2283 #ifndef HAVE_LDAP_INITIALIZE
2284 int
ldap_initialize(LDAP ** ldp,char * url,int use_SSL,char ** errstr)2285 ldap_initialize(LDAP **ldp, char *url, int use_SSL, char **errstr)
2286 {
2287 int rc = LDAP_SUCCESS;
2288 LDAP *ld = NULL;
2289 LDAPURLDesc *ludp = NULL;
2290
2291 /* For now, we don't use any DN that may be provided. And on
2292 Solaris (based on Mozilla's LDAP client code), we need the
2293 _nodn form to parse "ldap://host" without a trailing slash.
2294
2295 Also, this version won't handle an input string which contains
2296 multiple URLs, unlike the OpenLDAP ldap_initialize. See
2297 https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 . */
2298
2299 /* to avoid reinit and leaking handles, *ldp must be NULL */
2300 if (*ldp != NULL)
2301 return LDAP_SUCCESS;
2302
2303 #ifdef HAVE_LDAP_URL_PARSE_NODN
2304 rc = ldap_url_parse_nodn(url, &ludp);
2305 #else
2306 rc = ldap_url_parse(url, &ludp);
2307 #endif
2308 if (rc == 0) {
2309 if (use_SSL == SSL_ON)
2310 ld = ldapssl_init(ludp->lud_host, ludp->lud_port, 1);
2311 else
2312 ld = ldap_init(ludp->lud_host, ludp->lud_port);
2313
2314 if (ld != NULL)
2315 *ldp = ld;
2316 else {
2317 if (errstr != NULL)
2318 *errstr = strerror(errno);
2319 rc = LDAP_OPERATIONS_ERROR;
2320 }
2321
2322 ldap_free_urldesc(ludp);
2323 } else {
2324 /* report error from ldap url parsing */
2325 if (errstr != NULL)
2326 *errstr = ldap_err2string(rc);
2327 /* convert to generic LDAP error */
2328 rc = LDAP_OPERATIONS_ERROR;
2329 }
2330 return rc;
2331 }
2332 #endif /* HAVE_LDAP_INITIALIZE */
2333
2334 #ifndef HAVE_LDAP_UNBIND_EXT_S
2335 int
ldap_unbind_ext_s(LDAP * ld,LDAPControl ** sctrls,LDAPControl ** cctrls)2336 ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls)
2337 {
2338 return ldap_unbind_ext(ld, sctrls, cctrls);
2339 }
2340 #endif /* HAVE_LDAP_UNBIND_EXT_S */
2341