1/*
| 1/*
|
2 * Copyright (c) 2001-2004 Sendmail, Inc. and its suppliers.
| 2 * Copyright (c) 2001-2005 Sendmail, Inc. and its suppliers.
|
3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10#include <sm/gen.h>
| 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10#include <sm/gen.h>
|
11SM_RCSID("@(#)$Id: ldap.c,v 1.60 2004/08/03 20:42:21 ca Exp $")
| 11SM_RCSID("@(#)$Id: ldap.c,v 1.62 2005/02/24 00:30:01 ca Exp $")
|
12 13#if LDAPMAP 14# include <sys/types.h> 15# include <errno.h> 16# include <setjmp.h> 17# include <stdlib.h> 18# include <unistd.h> 19 20# include <sm/bitops.h> 21# include <sm/clock.h> 22# include <sm/conf.h> 23# include <sm/debug.h> 24# include <sm/errstring.h> 25# include <sm/ldap.h> 26# include <sm/string.h> 27# ifdef EX_OK 28# undef EX_OK /* for SVr4.2 SMP */ 29# endif /* EX_OK */ 30# include <sm/sysexits.h> 31 32SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", 33 "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); 34 35static void ldaptimeout __P((int)); 36static bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *)); 37static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *)); 38 39/* 40** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT 41** 42** Parameters: 43** lmap -- pointer to SM_LDAP_STRUCT to clear 44** 45** Returns: 46** None. 47** 48*/ 49 50void 51sm_ldap_clear(lmap) 52 SM_LDAP_STRUCT *lmap; 53{ 54 if (lmap == NULL) 55 return; 56 57 lmap->ldap_host = NULL; 58 lmap->ldap_port = LDAP_PORT; 59 lmap->ldap_uri = NULL; 60 lmap->ldap_version = 0; 61 lmap->ldap_deref = LDAP_DEREF_NEVER; 62 lmap->ldap_timelimit = LDAP_NO_LIMIT; 63 lmap->ldap_sizelimit = LDAP_NO_LIMIT; 64# ifdef LDAP_REFERRALS 65 lmap->ldap_options = LDAP_OPT_REFERRALS; 66# else /* LDAP_REFERRALS */ 67 lmap->ldap_options = 0; 68# endif /* LDAP_REFERRALS */ 69 lmap->ldap_attrsep = '\0'; 70 lmap->ldap_binddn = NULL; 71 lmap->ldap_secret = NULL; 72 lmap->ldap_method = LDAP_AUTH_SIMPLE; 73 lmap->ldap_base = NULL; 74 lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 75 lmap->ldap_attrsonly = LDAPMAP_FALSE; 76 lmap->ldap_timeout.tv_sec = 0; 77 lmap->ldap_timeout.tv_usec = 0; 78 lmap->ldap_ld = NULL; 79 lmap->ldap_filter = NULL; 80 lmap->ldap_attr[0] = NULL; 81 lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; 82 lmap->ldap_attr_needobjclass[0] = NULL; 83 lmap->ldap_res = NULL; 84 lmap->ldap_next = NULL; 85 lmap->ldap_pid = 0; 86} 87 88/* 89** SM_LDAP_START -- actually connect to an LDAP server 90** 91** Parameters: 92** name -- name of map for debug output. 93** lmap -- the LDAP map being opened. 94** 95** Returns: 96** true if connection is successful, false otherwise. 97** 98** Side Effects: 99** Populates lmap->ldap_ld. 100*/ 101 102static jmp_buf LDAPTimeout; 103 104#define SM_LDAP_SETTIMEOUT(to) \ 105do \ 106{ \ 107 if (to != 0) \ 108 { \ 109 if (setjmp(LDAPTimeout) != 0) \ 110 { \ 111 errno = ETIMEDOUT; \ 112 return false; \ 113 } \ 114 ev = sm_setevent(to, ldaptimeout, 0); \ 115 } \ 116} while (0) 117 118#define SM_LDAP_CLEARTIMEOUT() \ 119do \ 120{ \ 121 if (ev != NULL) \ 122 sm_clrevent(ev); \ 123} while (0) 124 125bool 126sm_ldap_start(name, lmap) 127 char *name; 128 SM_LDAP_STRUCT *lmap; 129{ 130 int bind_result; 131 int save_errno = 0; 132 char *id; 133 SM_EVENT *ev = NULL; 134 LDAP *ld = NULL; 135 136 if (sm_debug_active(&SmLDAPTrace, 2)) 137 sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 138 139 if (lmap->ldap_host != NULL) 140 id = lmap->ldap_host; 141 else if (lmap->ldap_uri != NULL) 142 id = lmap->ldap_uri; 143 else 144 id = "localhost"; 145 146 if (sm_debug_active(&SmLDAPTrace, 9)) 147 { 148 /* Don't print a port number for LDAP URIs */ 149 if (lmap->ldap_uri != NULL) 150 sm_dprintf("ldapmap_start(%s)\n", id); 151 else 152 sm_dprintf("ldapmap_start(%s, %d)\n", id, 153 lmap->ldap_port); 154 } 155 156 if (lmap->ldap_uri != NULL) 157 { 158#if SM_CONF_LDAP_INITIALIZE 159 /* LDAP server supports URIs so use them directly */ 160 save_errno = ldap_initialize(&ld, lmap->ldap_uri); 161#else /* SM_CONF_LDAP_INITIALIZE */ 162 int err; 163 LDAPURLDesc *ludp = NULL; 164 165 /* Blast apart URL and use the ldap_init/ldap_open below */ 166 err = ldap_url_parse(lmap->ldap_uri, &ludp); 167 if (err != 0) 168 { 169 errno = err + E_LDAPURLBASE; 170 return false; 171 } 172 lmap->ldap_host = sm_strdup_x(ludp->lud_host); 173 if (lmap->ldap_host == NULL) 174 { 175 save_errno = errno; 176 ldap_free_urldesc(ludp); 177 errno = save_errno; 178 return false; 179 } 180 lmap->ldap_port = ludp->lud_port; 181 ldap_free_urldesc(ludp); 182#endif /* SM_CONF_LDAP_INITIALIZE */ 183 } 184 185 if (ld == NULL) 186 { 187# if USE_LDAP_INIT 188 ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 189 save_errno = errno; 190# else /* USE_LDAP_INIT */ 191 /* 192 ** If using ldap_open(), the actual connection to the server 193 ** happens now so we need the timeout here. For ldap_init(), 194 ** the connection happens at bind time. 195 */ 196 197 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 198 ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 199 save_errno = errno; 200 201 /* clear the event if it has not sprung */ 202 SM_LDAP_CLEARTIMEOUT(); 203# endif /* USE_LDAP_INIT */ 204 } 205 206 errno = save_errno; 207 if (ld == NULL) 208 return false; 209 210 sm_ldap_setopts(ld, lmap); 211 212# if USE_LDAP_INIT 213 /* 214 ** If using ldap_init(), the actual connection to the server 215 ** happens at ldap_bind_s() so we need the timeout here. 216 */ 217 218 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 219# endif /* USE_LDAP_INIT */ 220 221# ifdef LDAP_AUTH_KRBV4 222 if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 223 lmap->ldap_secret != NULL) 224 { 225 /* 226 ** Need to put ticket in environment here instead of 227 ** during parseargs as there may be different tickets 228 ** for different LDAP connections. 229 */ 230 231 (void) putenv(lmap->ldap_secret); 232 } 233# endif /* LDAP_AUTH_KRBV4 */ 234 235 bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 236 lmap->ldap_secret, lmap->ldap_method); 237 238# if USE_LDAP_INIT 239 /* clear the event if it has not sprung */ 240 SM_LDAP_CLEARTIMEOUT(); 241# endif /* USE_LDAP_INIT */ 242 243 if (bind_result != LDAP_SUCCESS) 244 { 245 errno = bind_result + E_LDAPBASE; 246 return false; 247 } 248 249 /* Save PID to make sure only this PID closes the LDAP connection */ 250 lmap->ldap_pid = getpid(); 251 lmap->ldap_ld = ld; 252 return true; 253} 254 255/* ARGSUSED */ 256static void 257ldaptimeout(unused) 258 int unused; 259{ 260 /* 261 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 262 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 263 ** DOING. 264 */ 265 266 errno = ETIMEDOUT; 267 longjmp(LDAPTimeout, 1); 268} 269 270/* 271** SM_LDAP_SEARCH -- initiate LDAP search 272** 273** Initiate an LDAP search, return the msgid. 274** The calling function must collect the results. 275** 276** Parameters: 277** lmap -- LDAP map information 278** key -- key to substitute in LDAP filter 279** 280** Returns: 281** -1 on failure, msgid on success 282** 283*/ 284 285int 286sm_ldap_search(lmap, key) 287 SM_LDAP_STRUCT *lmap; 288 char *key; 289{ 290 int msgid; 291 char *fp, *p, *q; 292 char filter[LDAPMAP_MAX_FILTER + 1]; 293 294 /* substitute key into filter, perhaps multiple times */ 295 memset(filter, '\0', sizeof filter); 296 fp = filter; 297 p = lmap->ldap_filter; 298 while ((q = strchr(p, '%')) != NULL) 299 { 300 if (q[1] == 's') 301 { 302 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 303 "%.*s%s", (int) (q - p), p, key); 304 fp += strlen(fp); 305 p = q + 2; 306 } 307 else if (q[1] == '0') 308 { 309 char *k = key; 310 311 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 312 "%.*s", (int) (q - p), p); 313 fp += strlen(fp); 314 p = q + 2; 315 316 /* Properly escape LDAP special characters */ 317 while (SPACELEFT(filter, fp) > 0 && 318 *k != '\0') 319 { 320 if (*k == '*' || *k == '(' || 321 *k == ')' || *k == '\\') 322 { 323 (void) sm_strlcat(fp, 324 (*k == '*' ? "\\2A" : 325 (*k == '(' ? "\\28" : 326 (*k == ')' ? "\\29" : 327 (*k == '\\' ? "\\5C" : 328 "\00")))), 329 SPACELEFT(filter, fp)); 330 fp += strlen(fp); 331 k++; 332 } 333 else 334 *fp++ = *k++; 335 } 336 } 337 else 338 { 339 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 340 "%.*s", (int) (q - p + 1), p); 341 p = q + (q[1] == '%' ? 2 : 1); 342 fp += strlen(fp); 343 } 344 } 345 (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 346 if (sm_debug_active(&SmLDAPTrace, 20)) 347 sm_dprintf("ldap search filter=%s\n", filter); 348 349 lmap->ldap_res = NULL; 350 msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, 351 lmap->ldap_scope, filter, 352 (lmap->ldap_attr[0] == NULL ? NULL : 353 lmap->ldap_attr), 354 lmap->ldap_attrsonly); 355 return msgid; 356} 357 358/* 359** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a 360** particular objectClass 361** 362** Parameters: 363** lmap -- pointer to SM_LDAP_STRUCT in use 364** entry -- current LDAP entry struct 365** ocvalue -- particular objectclass in question. 366** may be of form (fee|foo|fum) meaning 367** any entry can be part of either fee, 368** foo or fum objectclass 369** 370** Returns: 371** true if item has that objectClass 372*/ 373 374static bool 375sm_ldap_has_objectclass(lmap, entry, ocvalue) 376 SM_LDAP_STRUCT *lmap; 377 LDAPMessage *entry; 378 char *ocvalue; 379{ 380 char **vals = NULL; 381 int i; 382 383 if (ocvalue == NULL) 384 return false; 385 386 vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); 387 if (vals == NULL) 388 return false; 389 390 for (i = 0; vals[i] != NULL; i++) 391 { 392 char *p; 393 char *q; 394 395 p = q = ocvalue; 396 while (*p != '\0') 397 { 398 while (*p != '\0' && *p != '|') 399 p++; 400 401 if ((p - q) == strlen(vals[i]) && 402 sm_strncasecmp(vals[i], q, p - q) == 0) 403 { 404 ldap_value_free(vals); 405 return true; 406 } 407 408 while (*p == '|') 409 p++; 410 q = p; 411 } 412 } 413 414 ldap_value_free(vals); 415 return false; 416} 417 418/* 419** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 420** 421** Parameters: 422** lmap -- pointer to SM_LDAP_STRUCT in use 423** msgid -- msgid returned by sm_ldap_search() 424** flags -- flags for the lookup 425** delim -- delimiter for result concatenation 426** rpool -- memory pool for storage 427** result -- return string 428** recurse -- recursion list 429** 430** Returns: 431** status (sysexit) 432*/ 433 434# define SM_LDAP_ERROR_CLEANUP() \ 435{ \ 436 if (lmap->ldap_res != NULL) \ 437 { \ 438 ldap_msgfree(lmap->ldap_res); \ 439 lmap->ldap_res = NULL; \ 440 } \ 441 (void) ldap_abandon(lmap->ldap_ld, msgid); \ 442} 443 444static SM_LDAP_RECURSE_ENTRY * 445sm_ldap_add_recurse(top, item, type, rpool) 446 SM_LDAP_RECURSE_LIST **top; 447 char *item; 448 int type; 449 SM_RPOOL_T *rpool; 450{ 451 int n; 452 int m; 453 int p; 454 int insertat; 455 int moveb; 456 int oldsizeb; 457 int rc; 458 SM_LDAP_RECURSE_ENTRY *newe; 459 SM_LDAP_RECURSE_ENTRY **olddata; 460 461 /* 462 ** This code will maintain a list of 463 ** SM_LDAP_RECURSE_ENTRY structures 464 ** in ascending order. 465 */ 466 467 if (*top == NULL) 468 { 469 /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ 470 *top = sm_rpool_malloc_x(rpool, sizeof **top); 471 (*top)->lr_cnt = 0; 472 (*top)->lr_size = 0; 473 (*top)->lr_data = NULL; 474 } 475 476 if ((*top)->lr_cnt >= (*top)->lr_size) 477 { 478 /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ 479 olddata = (*top)->lr_data; 480 if ((*top)->lr_size == 0) 481 { 482 oldsizeb = 0; 483 (*top)->lr_size = 256; 484 } 485 else 486 { 487 oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); 488 (*top)->lr_size *= 2; 489 } 490 (*top)->lr_data = sm_rpool_malloc_x(rpool, 491 (*top)->lr_size * sizeof *((*top)->lr_data)); 492 if (oldsizeb > 0) 493 memcpy((*top)->lr_data, olddata, oldsizeb); 494 } 495 496 /* 497 ** Binary search/insert item:type into list. 498 ** Return current entry pointer if already exists. 499 */ 500 501 n = 0; 502 m = (*top)->lr_cnt - 1; 503 if (m < 0) 504 insertat = 0; 505 else 506 insertat = -1; 507 508 while (insertat == -1) 509 { 510 p = (m + n) / 2; 511 512 rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); 513 if (rc == 0) 514 rc = type - (*top)->lr_data[p]->lr_type; 515 516 if (rc < 0) 517 m = p - 1; 518 else if (rc > 0) 519 n = p + 1; 520 else 521 return (*top)->lr_data[p]; 522 523 if (m == -1) 524 insertat = 0; 525 else if (n >= (*top)->lr_cnt) 526 insertat = (*top)->lr_cnt; 527 else if (m < n) 528 insertat = m + 1; 529 } 530 531 /* 532 ** Not found in list, make room 533 ** at insert point and add it. 534 */ 535 536 newe = sm_rpool_malloc_x(rpool, sizeof *newe); 537 if (newe != NULL) 538 { 539 moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); 540 if (moveb > 0) 541 memmove(&((*top)->lr_data[insertat + 1]), 542 &((*top)->lr_data[insertat]), 543 moveb); 544 545 newe->lr_search = sm_rpool_strdup_x(rpool, item); 546 newe->lr_type = type; 547 newe->lr_ludp = NULL; 548 newe->lr_attrs = NULL; 549 newe->lr_done = false; 550 551 ((*top)->lr_data)[insertat] = newe; 552 (*top)->lr_cnt++; 553 } 554 return newe; 555} 556 557int 558sm_ldap_results(lmap, msgid, flags, delim, rpool, result, 559 resultln, resultsz, recurse) 560 SM_LDAP_STRUCT *lmap; 561 int msgid; 562 int flags; 563 int delim; 564 SM_RPOOL_T *rpool; 565 char **result; 566 int *resultln; 567 int *resultsz; 568 SM_LDAP_RECURSE_LIST *recurse; 569{ 570 bool toplevel; 571 int i; 572 int statp; 573 int vsize; 574 int ret; 575 int save_errno; 576 char *p; 577 SM_LDAP_RECURSE_ENTRY *rl; 578 579 /* Are we the top top level of the search? */ 580 toplevel = (recurse == NULL); 581 582 /* Get results */ 583 statp = EX_NOTFOUND; 584 while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 585 (lmap->ldap_timeout.tv_sec == 0 ? NULL : 586 &(lmap->ldap_timeout)), 587 &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 588 { 589 LDAPMessage *entry; 590 591 /* If we don't want multiple values and we have one, break */
| 12 13#if LDAPMAP 14# include <sys/types.h> 15# include <errno.h> 16# include <setjmp.h> 17# include <stdlib.h> 18# include <unistd.h> 19 20# include <sm/bitops.h> 21# include <sm/clock.h> 22# include <sm/conf.h> 23# include <sm/debug.h> 24# include <sm/errstring.h> 25# include <sm/ldap.h> 26# include <sm/string.h> 27# ifdef EX_OK 28# undef EX_OK /* for SVr4.2 SMP */ 29# endif /* EX_OK */ 30# include <sm/sysexits.h> 31 32SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", 33 "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); 34 35static void ldaptimeout __P((int)); 36static bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *)); 37static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *)); 38 39/* 40** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT 41** 42** Parameters: 43** lmap -- pointer to SM_LDAP_STRUCT to clear 44** 45** Returns: 46** None. 47** 48*/ 49 50void 51sm_ldap_clear(lmap) 52 SM_LDAP_STRUCT *lmap; 53{ 54 if (lmap == NULL) 55 return; 56 57 lmap->ldap_host = NULL; 58 lmap->ldap_port = LDAP_PORT; 59 lmap->ldap_uri = NULL; 60 lmap->ldap_version = 0; 61 lmap->ldap_deref = LDAP_DEREF_NEVER; 62 lmap->ldap_timelimit = LDAP_NO_LIMIT; 63 lmap->ldap_sizelimit = LDAP_NO_LIMIT; 64# ifdef LDAP_REFERRALS 65 lmap->ldap_options = LDAP_OPT_REFERRALS; 66# else /* LDAP_REFERRALS */ 67 lmap->ldap_options = 0; 68# endif /* LDAP_REFERRALS */ 69 lmap->ldap_attrsep = '\0'; 70 lmap->ldap_binddn = NULL; 71 lmap->ldap_secret = NULL; 72 lmap->ldap_method = LDAP_AUTH_SIMPLE; 73 lmap->ldap_base = NULL; 74 lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 75 lmap->ldap_attrsonly = LDAPMAP_FALSE; 76 lmap->ldap_timeout.tv_sec = 0; 77 lmap->ldap_timeout.tv_usec = 0; 78 lmap->ldap_ld = NULL; 79 lmap->ldap_filter = NULL; 80 lmap->ldap_attr[0] = NULL; 81 lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; 82 lmap->ldap_attr_needobjclass[0] = NULL; 83 lmap->ldap_res = NULL; 84 lmap->ldap_next = NULL; 85 lmap->ldap_pid = 0; 86} 87 88/* 89** SM_LDAP_START -- actually connect to an LDAP server 90** 91** Parameters: 92** name -- name of map for debug output. 93** lmap -- the LDAP map being opened. 94** 95** Returns: 96** true if connection is successful, false otherwise. 97** 98** Side Effects: 99** Populates lmap->ldap_ld. 100*/ 101 102static jmp_buf LDAPTimeout; 103 104#define SM_LDAP_SETTIMEOUT(to) \ 105do \ 106{ \ 107 if (to != 0) \ 108 { \ 109 if (setjmp(LDAPTimeout) != 0) \ 110 { \ 111 errno = ETIMEDOUT; \ 112 return false; \ 113 } \ 114 ev = sm_setevent(to, ldaptimeout, 0); \ 115 } \ 116} while (0) 117 118#define SM_LDAP_CLEARTIMEOUT() \ 119do \ 120{ \ 121 if (ev != NULL) \ 122 sm_clrevent(ev); \ 123} while (0) 124 125bool 126sm_ldap_start(name, lmap) 127 char *name; 128 SM_LDAP_STRUCT *lmap; 129{ 130 int bind_result; 131 int save_errno = 0; 132 char *id; 133 SM_EVENT *ev = NULL; 134 LDAP *ld = NULL; 135 136 if (sm_debug_active(&SmLDAPTrace, 2)) 137 sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 138 139 if (lmap->ldap_host != NULL) 140 id = lmap->ldap_host; 141 else if (lmap->ldap_uri != NULL) 142 id = lmap->ldap_uri; 143 else 144 id = "localhost"; 145 146 if (sm_debug_active(&SmLDAPTrace, 9)) 147 { 148 /* Don't print a port number for LDAP URIs */ 149 if (lmap->ldap_uri != NULL) 150 sm_dprintf("ldapmap_start(%s)\n", id); 151 else 152 sm_dprintf("ldapmap_start(%s, %d)\n", id, 153 lmap->ldap_port); 154 } 155 156 if (lmap->ldap_uri != NULL) 157 { 158#if SM_CONF_LDAP_INITIALIZE 159 /* LDAP server supports URIs so use them directly */ 160 save_errno = ldap_initialize(&ld, lmap->ldap_uri); 161#else /* SM_CONF_LDAP_INITIALIZE */ 162 int err; 163 LDAPURLDesc *ludp = NULL; 164 165 /* Blast apart URL and use the ldap_init/ldap_open below */ 166 err = ldap_url_parse(lmap->ldap_uri, &ludp); 167 if (err != 0) 168 { 169 errno = err + E_LDAPURLBASE; 170 return false; 171 } 172 lmap->ldap_host = sm_strdup_x(ludp->lud_host); 173 if (lmap->ldap_host == NULL) 174 { 175 save_errno = errno; 176 ldap_free_urldesc(ludp); 177 errno = save_errno; 178 return false; 179 } 180 lmap->ldap_port = ludp->lud_port; 181 ldap_free_urldesc(ludp); 182#endif /* SM_CONF_LDAP_INITIALIZE */ 183 } 184 185 if (ld == NULL) 186 { 187# if USE_LDAP_INIT 188 ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 189 save_errno = errno; 190# else /* USE_LDAP_INIT */ 191 /* 192 ** If using ldap_open(), the actual connection to the server 193 ** happens now so we need the timeout here. For ldap_init(), 194 ** the connection happens at bind time. 195 */ 196 197 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 198 ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 199 save_errno = errno; 200 201 /* clear the event if it has not sprung */ 202 SM_LDAP_CLEARTIMEOUT(); 203# endif /* USE_LDAP_INIT */ 204 } 205 206 errno = save_errno; 207 if (ld == NULL) 208 return false; 209 210 sm_ldap_setopts(ld, lmap); 211 212# if USE_LDAP_INIT 213 /* 214 ** If using ldap_init(), the actual connection to the server 215 ** happens at ldap_bind_s() so we need the timeout here. 216 */ 217 218 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 219# endif /* USE_LDAP_INIT */ 220 221# ifdef LDAP_AUTH_KRBV4 222 if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 223 lmap->ldap_secret != NULL) 224 { 225 /* 226 ** Need to put ticket in environment here instead of 227 ** during parseargs as there may be different tickets 228 ** for different LDAP connections. 229 */ 230 231 (void) putenv(lmap->ldap_secret); 232 } 233# endif /* LDAP_AUTH_KRBV4 */ 234 235 bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 236 lmap->ldap_secret, lmap->ldap_method); 237 238# if USE_LDAP_INIT 239 /* clear the event if it has not sprung */ 240 SM_LDAP_CLEARTIMEOUT(); 241# endif /* USE_LDAP_INIT */ 242 243 if (bind_result != LDAP_SUCCESS) 244 { 245 errno = bind_result + E_LDAPBASE; 246 return false; 247 } 248 249 /* Save PID to make sure only this PID closes the LDAP connection */ 250 lmap->ldap_pid = getpid(); 251 lmap->ldap_ld = ld; 252 return true; 253} 254 255/* ARGSUSED */ 256static void 257ldaptimeout(unused) 258 int unused; 259{ 260 /* 261 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 262 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 263 ** DOING. 264 */ 265 266 errno = ETIMEDOUT; 267 longjmp(LDAPTimeout, 1); 268} 269 270/* 271** SM_LDAP_SEARCH -- initiate LDAP search 272** 273** Initiate an LDAP search, return the msgid. 274** The calling function must collect the results. 275** 276** Parameters: 277** lmap -- LDAP map information 278** key -- key to substitute in LDAP filter 279** 280** Returns: 281** -1 on failure, msgid on success 282** 283*/ 284 285int 286sm_ldap_search(lmap, key) 287 SM_LDAP_STRUCT *lmap; 288 char *key; 289{ 290 int msgid; 291 char *fp, *p, *q; 292 char filter[LDAPMAP_MAX_FILTER + 1]; 293 294 /* substitute key into filter, perhaps multiple times */ 295 memset(filter, '\0', sizeof filter); 296 fp = filter; 297 p = lmap->ldap_filter; 298 while ((q = strchr(p, '%')) != NULL) 299 { 300 if (q[1] == 's') 301 { 302 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 303 "%.*s%s", (int) (q - p), p, key); 304 fp += strlen(fp); 305 p = q + 2; 306 } 307 else if (q[1] == '0') 308 { 309 char *k = key; 310 311 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 312 "%.*s", (int) (q - p), p); 313 fp += strlen(fp); 314 p = q + 2; 315 316 /* Properly escape LDAP special characters */ 317 while (SPACELEFT(filter, fp) > 0 && 318 *k != '\0') 319 { 320 if (*k == '*' || *k == '(' || 321 *k == ')' || *k == '\\') 322 { 323 (void) sm_strlcat(fp, 324 (*k == '*' ? "\\2A" : 325 (*k == '(' ? "\\28" : 326 (*k == ')' ? "\\29" : 327 (*k == '\\' ? "\\5C" : 328 "\00")))), 329 SPACELEFT(filter, fp)); 330 fp += strlen(fp); 331 k++; 332 } 333 else 334 *fp++ = *k++; 335 } 336 } 337 else 338 { 339 (void) sm_snprintf(fp, SPACELEFT(filter, fp), 340 "%.*s", (int) (q - p + 1), p); 341 p = q + (q[1] == '%' ? 2 : 1); 342 fp += strlen(fp); 343 } 344 } 345 (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 346 if (sm_debug_active(&SmLDAPTrace, 20)) 347 sm_dprintf("ldap search filter=%s\n", filter); 348 349 lmap->ldap_res = NULL; 350 msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, 351 lmap->ldap_scope, filter, 352 (lmap->ldap_attr[0] == NULL ? NULL : 353 lmap->ldap_attr), 354 lmap->ldap_attrsonly); 355 return msgid; 356} 357 358/* 359** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a 360** particular objectClass 361** 362** Parameters: 363** lmap -- pointer to SM_LDAP_STRUCT in use 364** entry -- current LDAP entry struct 365** ocvalue -- particular objectclass in question. 366** may be of form (fee|foo|fum) meaning 367** any entry can be part of either fee, 368** foo or fum objectclass 369** 370** Returns: 371** true if item has that objectClass 372*/ 373 374static bool 375sm_ldap_has_objectclass(lmap, entry, ocvalue) 376 SM_LDAP_STRUCT *lmap; 377 LDAPMessage *entry; 378 char *ocvalue; 379{ 380 char **vals = NULL; 381 int i; 382 383 if (ocvalue == NULL) 384 return false; 385 386 vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); 387 if (vals == NULL) 388 return false; 389 390 for (i = 0; vals[i] != NULL; i++) 391 { 392 char *p; 393 char *q; 394 395 p = q = ocvalue; 396 while (*p != '\0') 397 { 398 while (*p != '\0' && *p != '|') 399 p++; 400 401 if ((p - q) == strlen(vals[i]) && 402 sm_strncasecmp(vals[i], q, p - q) == 0) 403 { 404 ldap_value_free(vals); 405 return true; 406 } 407 408 while (*p == '|') 409 p++; 410 q = p; 411 } 412 } 413 414 ldap_value_free(vals); 415 return false; 416} 417 418/* 419** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 420** 421** Parameters: 422** lmap -- pointer to SM_LDAP_STRUCT in use 423** msgid -- msgid returned by sm_ldap_search() 424** flags -- flags for the lookup 425** delim -- delimiter for result concatenation 426** rpool -- memory pool for storage 427** result -- return string 428** recurse -- recursion list 429** 430** Returns: 431** status (sysexit) 432*/ 433 434# define SM_LDAP_ERROR_CLEANUP() \ 435{ \ 436 if (lmap->ldap_res != NULL) \ 437 { \ 438 ldap_msgfree(lmap->ldap_res); \ 439 lmap->ldap_res = NULL; \ 440 } \ 441 (void) ldap_abandon(lmap->ldap_ld, msgid); \ 442} 443 444static SM_LDAP_RECURSE_ENTRY * 445sm_ldap_add_recurse(top, item, type, rpool) 446 SM_LDAP_RECURSE_LIST **top; 447 char *item; 448 int type; 449 SM_RPOOL_T *rpool; 450{ 451 int n; 452 int m; 453 int p; 454 int insertat; 455 int moveb; 456 int oldsizeb; 457 int rc; 458 SM_LDAP_RECURSE_ENTRY *newe; 459 SM_LDAP_RECURSE_ENTRY **olddata; 460 461 /* 462 ** This code will maintain a list of 463 ** SM_LDAP_RECURSE_ENTRY structures 464 ** in ascending order. 465 */ 466 467 if (*top == NULL) 468 { 469 /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ 470 *top = sm_rpool_malloc_x(rpool, sizeof **top); 471 (*top)->lr_cnt = 0; 472 (*top)->lr_size = 0; 473 (*top)->lr_data = NULL; 474 } 475 476 if ((*top)->lr_cnt >= (*top)->lr_size) 477 { 478 /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ 479 olddata = (*top)->lr_data; 480 if ((*top)->lr_size == 0) 481 { 482 oldsizeb = 0; 483 (*top)->lr_size = 256; 484 } 485 else 486 { 487 oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); 488 (*top)->lr_size *= 2; 489 } 490 (*top)->lr_data = sm_rpool_malloc_x(rpool, 491 (*top)->lr_size * sizeof *((*top)->lr_data)); 492 if (oldsizeb > 0) 493 memcpy((*top)->lr_data, olddata, oldsizeb); 494 } 495 496 /* 497 ** Binary search/insert item:type into list. 498 ** Return current entry pointer if already exists. 499 */ 500 501 n = 0; 502 m = (*top)->lr_cnt - 1; 503 if (m < 0) 504 insertat = 0; 505 else 506 insertat = -1; 507 508 while (insertat == -1) 509 { 510 p = (m + n) / 2; 511 512 rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); 513 if (rc == 0) 514 rc = type - (*top)->lr_data[p]->lr_type; 515 516 if (rc < 0) 517 m = p - 1; 518 else if (rc > 0) 519 n = p + 1; 520 else 521 return (*top)->lr_data[p]; 522 523 if (m == -1) 524 insertat = 0; 525 else if (n >= (*top)->lr_cnt) 526 insertat = (*top)->lr_cnt; 527 else if (m < n) 528 insertat = m + 1; 529 } 530 531 /* 532 ** Not found in list, make room 533 ** at insert point and add it. 534 */ 535 536 newe = sm_rpool_malloc_x(rpool, sizeof *newe); 537 if (newe != NULL) 538 { 539 moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); 540 if (moveb > 0) 541 memmove(&((*top)->lr_data[insertat + 1]), 542 &((*top)->lr_data[insertat]), 543 moveb); 544 545 newe->lr_search = sm_rpool_strdup_x(rpool, item); 546 newe->lr_type = type; 547 newe->lr_ludp = NULL; 548 newe->lr_attrs = NULL; 549 newe->lr_done = false; 550 551 ((*top)->lr_data)[insertat] = newe; 552 (*top)->lr_cnt++; 553 } 554 return newe; 555} 556 557int 558sm_ldap_results(lmap, msgid, flags, delim, rpool, result, 559 resultln, resultsz, recurse) 560 SM_LDAP_STRUCT *lmap; 561 int msgid; 562 int flags; 563 int delim; 564 SM_RPOOL_T *rpool; 565 char **result; 566 int *resultln; 567 int *resultsz; 568 SM_LDAP_RECURSE_LIST *recurse; 569{ 570 bool toplevel; 571 int i; 572 int statp; 573 int vsize; 574 int ret; 575 int save_errno; 576 char *p; 577 SM_LDAP_RECURSE_ENTRY *rl; 578 579 /* Are we the top top level of the search? */ 580 toplevel = (recurse == NULL); 581 582 /* Get results */ 583 statp = EX_NOTFOUND; 584 while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 585 (lmap->ldap_timeout.tv_sec == 0 ? NULL : 586 &(lmap->ldap_timeout)), 587 &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 588 { 589 LDAPMessage *entry; 590 591 /* If we don't want multiple values and we have one, break */
|
592 if ((char) delim == '\0' && *result != NULL)
| 592 if ((char) delim == '\0' && 593 !bitset(SM_LDAP_SINGLEMATCH, flags) && 594 *result != NULL)
|
593 break; 594 595 /* Cycle through all entries */ 596 for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 597 entry != NULL; 598 entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 599 { 600 BerElement *ber; 601 char *attr; 602 char **vals = NULL; 603 char *dn; 604 605 /* 606 ** If matching only and found an entry, 607 ** no need to spin through attributes 608 */ 609 610 if (bitset(SM_LDAP_MATCHONLY, flags)) 611 { 612 statp = EX_OK; 613 continue; 614 } 615 616 /* record completed DN's to prevent loops */ 617 dn = ldap_get_dn(lmap->ldap_ld, entry); 618 if (dn == NULL) 619 { 620 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 621 save_errno += E_LDAPBASE; 622 SM_LDAP_ERROR_CLEANUP(); 623 errno = save_errno; 624 return EX_TEMPFAIL; 625 } 626 627 rl = sm_ldap_add_recurse(&recurse, dn, 628 SM_LDAP_ATTR_DN, 629 rpool); 630 631 if (rl == NULL) 632 { 633 ldap_memfree(dn); 634 SM_LDAP_ERROR_CLEANUP(); 635 errno = ENOMEM; 636 return EX_OSERR; 637 } 638 else if (rl->lr_done) 639 { 640 /* already on list, skip it */ 641 ldap_memfree(dn); 642 continue; 643 } 644 ldap_memfree(dn); 645 646# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 647 /* 648 ** Reset value to prevent lingering 649 ** LDAP_DECODING_ERROR due to 650 ** OpenLDAP 1.X's hack (see below) 651 */ 652 653 lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 654# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 655 656 for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 657 &ber); 658 attr != NULL; 659 attr = ldap_next_attribute(lmap->ldap_ld, entry, 660 ber)) 661 { 662 char *tmp, *vp_tmp; 663 int type; 664 char *needobjclass = NULL; 665 666 type = SM_LDAP_ATTR_NONE; 667 for (i = 0; lmap->ldap_attr[i] != NULL; i++) 668 { 669 if (sm_strcasecmp(lmap->ldap_attr[i], 670 attr) == 0) 671 { 672 type = lmap->ldap_attr_type[i]; 673 needobjclass = lmap->ldap_attr_needobjclass[i]; 674 break; 675 } 676 } 677 678 if (bitset(SM_LDAP_USE_ALLATTR, flags) && 679 type == SM_LDAP_ATTR_NONE) 680 { 681 /* URL lookups specify attrs to use */ 682 type = SM_LDAP_ATTR_NORMAL; 683 needobjclass = NULL; 684 } 685 686 if (type == SM_LDAP_ATTR_NONE) 687 { 688 /* attribute not requested */ 689 ldap_memfree(attr); 690 SM_LDAP_ERROR_CLEANUP(); 691 errno = EFAULT; 692 return EX_SOFTWARE; 693 } 694 695 /* 696 ** For recursion on a particular attribute, 697 ** we may need to see if this entry is 698 ** part of a particular objectclass. 699 ** Also, ignore objectClass attribute. 700 ** Otherwise we just ignore this attribute. 701 */ 702 703 if (type == SM_LDAP_ATTR_OBJCLASS || 704 (needobjclass != NULL && 705 !sm_ldap_has_objectclass(lmap, entry, 706 needobjclass))) 707 { 708 ldap_memfree(attr); 709 continue; 710 } 711 712 if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 713 { 714 vals = ldap_get_values(lmap->ldap_ld, 715 entry, 716 attr); 717 if (vals == NULL) 718 { 719 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 720 if (save_errno == LDAP_SUCCESS) 721 { 722 ldap_memfree(attr); 723 continue; 724 } 725 726 /* Must be an error */ 727 save_errno += E_LDAPBASE; 728 ldap_memfree(attr); 729 SM_LDAP_ERROR_CLEANUP(); 730 errno = save_errno; 731 return EX_TEMPFAIL; 732 } 733 } 734 735 statp = EX_OK; 736 737# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 738 /* 739 ** Reset value to prevent lingering 740 ** LDAP_DECODING_ERROR due to 741 ** OpenLDAP 1.X's hack (see below) 742 */ 743 744 lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 745# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 746 747 /* 748 ** If matching only, 749 ** no need to spin through entries 750 */ 751 752 if (bitset(SM_LDAP_MATCHONLY, flags)) 753 { 754 if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 755 ldap_value_free(vals); 756 ldap_memfree(attr); 757 continue; 758 } 759 760 /* 761 ** If we don't want multiple values, 762 ** return first found. 763 */ 764 765 if ((char) delim == '\0') 766 { 767 if (*result != NULL) 768 { 769 /* already have a value */
| 595 break; 596 597 /* Cycle through all entries */ 598 for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 599 entry != NULL; 600 entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 601 { 602 BerElement *ber; 603 char *attr; 604 char **vals = NULL; 605 char *dn; 606 607 /* 608 ** If matching only and found an entry, 609 ** no need to spin through attributes 610 */ 611 612 if (bitset(SM_LDAP_MATCHONLY, flags)) 613 { 614 statp = EX_OK; 615 continue; 616 } 617 618 /* record completed DN's to prevent loops */ 619 dn = ldap_get_dn(lmap->ldap_ld, entry); 620 if (dn == NULL) 621 { 622 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 623 save_errno += E_LDAPBASE; 624 SM_LDAP_ERROR_CLEANUP(); 625 errno = save_errno; 626 return EX_TEMPFAIL; 627 } 628 629 rl = sm_ldap_add_recurse(&recurse, dn, 630 SM_LDAP_ATTR_DN, 631 rpool); 632 633 if (rl == NULL) 634 { 635 ldap_memfree(dn); 636 SM_LDAP_ERROR_CLEANUP(); 637 errno = ENOMEM; 638 return EX_OSERR; 639 } 640 else if (rl->lr_done) 641 { 642 /* already on list, skip it */ 643 ldap_memfree(dn); 644 continue; 645 } 646 ldap_memfree(dn); 647 648# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 649 /* 650 ** Reset value to prevent lingering 651 ** LDAP_DECODING_ERROR due to 652 ** OpenLDAP 1.X's hack (see below) 653 */ 654 655 lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 656# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 657 658 for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 659 &ber); 660 attr != NULL; 661 attr = ldap_next_attribute(lmap->ldap_ld, entry, 662 ber)) 663 { 664 char *tmp, *vp_tmp; 665 int type; 666 char *needobjclass = NULL; 667 668 type = SM_LDAP_ATTR_NONE; 669 for (i = 0; lmap->ldap_attr[i] != NULL; i++) 670 { 671 if (sm_strcasecmp(lmap->ldap_attr[i], 672 attr) == 0) 673 { 674 type = lmap->ldap_attr_type[i]; 675 needobjclass = lmap->ldap_attr_needobjclass[i]; 676 break; 677 } 678 } 679 680 if (bitset(SM_LDAP_USE_ALLATTR, flags) && 681 type == SM_LDAP_ATTR_NONE) 682 { 683 /* URL lookups specify attrs to use */ 684 type = SM_LDAP_ATTR_NORMAL; 685 needobjclass = NULL; 686 } 687 688 if (type == SM_LDAP_ATTR_NONE) 689 { 690 /* attribute not requested */ 691 ldap_memfree(attr); 692 SM_LDAP_ERROR_CLEANUP(); 693 errno = EFAULT; 694 return EX_SOFTWARE; 695 } 696 697 /* 698 ** For recursion on a particular attribute, 699 ** we may need to see if this entry is 700 ** part of a particular objectclass. 701 ** Also, ignore objectClass attribute. 702 ** Otherwise we just ignore this attribute. 703 */ 704 705 if (type == SM_LDAP_ATTR_OBJCLASS || 706 (needobjclass != NULL && 707 !sm_ldap_has_objectclass(lmap, entry, 708 needobjclass))) 709 { 710 ldap_memfree(attr); 711 continue; 712 } 713 714 if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 715 { 716 vals = ldap_get_values(lmap->ldap_ld, 717 entry, 718 attr); 719 if (vals == NULL) 720 { 721 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 722 if (save_errno == LDAP_SUCCESS) 723 { 724 ldap_memfree(attr); 725 continue; 726 } 727 728 /* Must be an error */ 729 save_errno += E_LDAPBASE; 730 ldap_memfree(attr); 731 SM_LDAP_ERROR_CLEANUP(); 732 errno = save_errno; 733 return EX_TEMPFAIL; 734 } 735 } 736 737 statp = EX_OK; 738 739# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 740 /* 741 ** Reset value to prevent lingering 742 ** LDAP_DECODING_ERROR due to 743 ** OpenLDAP 1.X's hack (see below) 744 */ 745 746 lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 747# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 748 749 /* 750 ** If matching only, 751 ** no need to spin through entries 752 */ 753 754 if (bitset(SM_LDAP_MATCHONLY, flags)) 755 { 756 if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 757 ldap_value_free(vals); 758 ldap_memfree(attr); 759 continue; 760 } 761 762 /* 763 ** If we don't want multiple values, 764 ** return first found. 765 */ 766 767 if ((char) delim == '\0') 768 { 769 if (*result != NULL) 770 { 771 /* already have a value */
|
| 772 if (bitset(SM_LDAP_SINGLEMATCH, 773 flags)) 774 { 775 /* only wanted one match */ 776 SM_LDAP_ERROR_CLEANUP(); 777 errno = ENOENT; 778 return EX_NOTFOUND; 779 }
|
770 break; 771 } 772
| 780 break; 781 } 782
|
773 if (bitset(SM_LDAP_SINGLEMATCH, 774 flags) && 775 *result != NULL) 776 { 777 /* only wanted one match */ 778 SM_LDAP_ERROR_CLEANUP(); 779 errno = ENOENT; 780 return EX_NOTFOUND; 781 } 782
| |
783 if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 784 { 785 *result = sm_rpool_strdup_x(rpool, 786 attr); 787 ldap_memfree(attr); 788 break; 789 } 790 791 if (vals[0] == NULL) 792 { 793 ldap_value_free(vals); 794 ldap_memfree(attr); 795 continue; 796 } 797 798 vsize = strlen(vals[0]) + 1; 799 if (lmap->ldap_attrsep != '\0') 800 vsize += strlen(attr) + 1; 801 *result = sm_rpool_malloc_x(rpool, 802 vsize); 803 if (lmap->ldap_attrsep != '\0') 804 sm_snprintf(*result, vsize, 805 "%s%c%s", 806 attr, 807 lmap->ldap_attrsep, 808 vals[0]); 809 else 810 sm_strlcpy(*result, vals[0], 811 vsize); 812 ldap_value_free(vals); 813 ldap_memfree(attr); 814 break; 815 } 816 817 /* attributes only */ 818 if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 819 { 820 if (*result == NULL) 821 *result = sm_rpool_strdup_x(rpool, 822 attr); 823 else 824 { 825 if (bitset(SM_LDAP_SINGLEMATCH, 826 flags) && 827 *result != NULL) 828 { 829 /* only wanted one match */ 830 SM_LDAP_ERROR_CLEANUP(); 831 errno = ENOENT; 832 return EX_NOTFOUND; 833 } 834 835 vsize = strlen(*result) + 836 strlen(attr) + 2; 837 tmp = sm_rpool_malloc_x(rpool, 838 vsize); 839 (void) sm_snprintf(tmp, 840 vsize, "%s%c%s", 841 *result, (char) delim, 842 attr); 843 *result = tmp; 844 } 845 ldap_memfree(attr); 846 continue; 847 } 848 849 /* 850 ** If there is more than one, munge then 851 ** into a map_coldelim separated string. 852 ** If we are recursing we may have an entry 853 ** with no 'normal' values to put in the 854 ** string. 855 ** This is not an error. 856 */ 857 858 if (type == SM_LDAP_ATTR_NORMAL && 859 bitset(SM_LDAP_SINGLEMATCH, flags) && 860 *result != NULL) 861 { 862 /* only wanted one match */ 863 SM_LDAP_ERROR_CLEANUP(); 864 errno = ENOENT; 865 return EX_NOTFOUND; 866 } 867 868 vsize = 0; 869 for (i = 0; vals[i] != NULL; i++) 870 { 871 if (type == SM_LDAP_ATTR_DN || 872 type == SM_LDAP_ATTR_FILTER || 873 type == SM_LDAP_ATTR_URL) 874 { 875 /* add to recursion */ 876 if (sm_ldap_add_recurse(&recurse, 877 vals[i], 878 type, 879 rpool) == NULL) 880 { 881 SM_LDAP_ERROR_CLEANUP(); 882 errno = ENOMEM; 883 return EX_OSERR; 884 } 885 continue; 886 } 887 888 vsize += strlen(vals[i]) + 1; 889 if (lmap->ldap_attrsep != '\0') 890 vsize += strlen(attr) + 1; 891 } 892 893 /* 894 ** Create/Append to string any normal 895 ** attribute values. Otherwise, just free 896 ** memory and move on to the next 897 ** attribute in this entry. 898 */ 899 900 if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) 901 { 902 char *pe; 903 904 /* Grow result string if needed */ 905 if ((*resultln + vsize) >= *resultsz) 906 { 907 while ((*resultln + vsize) >= *resultsz) 908 { 909 if (*resultsz == 0) 910 *resultsz = 1024; 911 else 912 *resultsz *= 2; 913 } 914 915 vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); 916 *vp_tmp = '\0'; 917 918 if (*result != NULL) 919 sm_strlcpy(vp_tmp, 920 *result, 921 *resultsz); 922 *result = vp_tmp; 923 } 924 925 p = *result + *resultln; 926 pe = *result + *resultsz; 927 928 for (i = 0; vals[i] != NULL; i++) 929 { 930 if (*resultln > 0 && 931 p < pe) 932 *p++ = (char) delim; 933 934 if (lmap->ldap_attrsep != '\0') 935 { 936 p += sm_strlcpy(p, attr, 937 pe - p); 938 if (p < pe) 939 *p++ = lmap->ldap_attrsep; 940 } 941 942 p += sm_strlcpy(p, vals[i], 943 pe - p); 944 *resultln = p - (*result); 945 if (p >= pe) 946 { 947 /* Internal error: buffer too small for LDAP values */ 948 SM_LDAP_ERROR_CLEANUP(); 949 errno = ENOMEM; 950 return EX_OSERR; 951 } 952 } 953 } 954 955 ldap_value_free(vals); 956 ldap_memfree(attr); 957 } 958 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 959 960 /* 961 ** We check save_errno != LDAP_DECODING_ERROR since 962 ** OpenLDAP 1.X has a very ugly *undocumented* 963 ** hack of returning this error code from 964 ** ldap_next_attribute() if the library freed the 965 ** ber attribute. See: 966 ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 967 */ 968 969 if (save_errno != LDAP_SUCCESS && 970 save_errno != LDAP_DECODING_ERROR) 971 { 972 /* Must be an error */ 973 save_errno += E_LDAPBASE; 974 SM_LDAP_ERROR_CLEANUP(); 975 errno = save_errno; 976 return EX_TEMPFAIL; 977 } 978 979 /* mark this DN as done */ 980 rl->lr_done = true; 981 if (rl->lr_ludp != NULL) 982 { 983 ldap_free_urldesc(rl->lr_ludp); 984 rl->lr_ludp = NULL; 985 } 986 if (rl->lr_attrs != NULL) 987 { 988 free(rl->lr_attrs); 989 rl->lr_attrs = NULL; 990 } 991 992 /* We don't want multiple values and we have one */
| 783 if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 784 { 785 *result = sm_rpool_strdup_x(rpool, 786 attr); 787 ldap_memfree(attr); 788 break; 789 } 790 791 if (vals[0] == NULL) 792 { 793 ldap_value_free(vals); 794 ldap_memfree(attr); 795 continue; 796 } 797 798 vsize = strlen(vals[0]) + 1; 799 if (lmap->ldap_attrsep != '\0') 800 vsize += strlen(attr) + 1; 801 *result = sm_rpool_malloc_x(rpool, 802 vsize); 803 if (lmap->ldap_attrsep != '\0') 804 sm_snprintf(*result, vsize, 805 "%s%c%s", 806 attr, 807 lmap->ldap_attrsep, 808 vals[0]); 809 else 810 sm_strlcpy(*result, vals[0], 811 vsize); 812 ldap_value_free(vals); 813 ldap_memfree(attr); 814 break; 815 } 816 817 /* attributes only */ 818 if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 819 { 820 if (*result == NULL) 821 *result = sm_rpool_strdup_x(rpool, 822 attr); 823 else 824 { 825 if (bitset(SM_LDAP_SINGLEMATCH, 826 flags) && 827 *result != NULL) 828 { 829 /* only wanted one match */ 830 SM_LDAP_ERROR_CLEANUP(); 831 errno = ENOENT; 832 return EX_NOTFOUND; 833 } 834 835 vsize = strlen(*result) + 836 strlen(attr) + 2; 837 tmp = sm_rpool_malloc_x(rpool, 838 vsize); 839 (void) sm_snprintf(tmp, 840 vsize, "%s%c%s", 841 *result, (char) delim, 842 attr); 843 *result = tmp; 844 } 845 ldap_memfree(attr); 846 continue; 847 } 848 849 /* 850 ** If there is more than one, munge then 851 ** into a map_coldelim separated string. 852 ** If we are recursing we may have an entry 853 ** with no 'normal' values to put in the 854 ** string. 855 ** This is not an error. 856 */ 857 858 if (type == SM_LDAP_ATTR_NORMAL && 859 bitset(SM_LDAP_SINGLEMATCH, flags) && 860 *result != NULL) 861 { 862 /* only wanted one match */ 863 SM_LDAP_ERROR_CLEANUP(); 864 errno = ENOENT; 865 return EX_NOTFOUND; 866 } 867 868 vsize = 0; 869 for (i = 0; vals[i] != NULL; i++) 870 { 871 if (type == SM_LDAP_ATTR_DN || 872 type == SM_LDAP_ATTR_FILTER || 873 type == SM_LDAP_ATTR_URL) 874 { 875 /* add to recursion */ 876 if (sm_ldap_add_recurse(&recurse, 877 vals[i], 878 type, 879 rpool) == NULL) 880 { 881 SM_LDAP_ERROR_CLEANUP(); 882 errno = ENOMEM; 883 return EX_OSERR; 884 } 885 continue; 886 } 887 888 vsize += strlen(vals[i]) + 1; 889 if (lmap->ldap_attrsep != '\0') 890 vsize += strlen(attr) + 1; 891 } 892 893 /* 894 ** Create/Append to string any normal 895 ** attribute values. Otherwise, just free 896 ** memory and move on to the next 897 ** attribute in this entry. 898 */ 899 900 if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) 901 { 902 char *pe; 903 904 /* Grow result string if needed */ 905 if ((*resultln + vsize) >= *resultsz) 906 { 907 while ((*resultln + vsize) >= *resultsz) 908 { 909 if (*resultsz == 0) 910 *resultsz = 1024; 911 else 912 *resultsz *= 2; 913 } 914 915 vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); 916 *vp_tmp = '\0'; 917 918 if (*result != NULL) 919 sm_strlcpy(vp_tmp, 920 *result, 921 *resultsz); 922 *result = vp_tmp; 923 } 924 925 p = *result + *resultln; 926 pe = *result + *resultsz; 927 928 for (i = 0; vals[i] != NULL; i++) 929 { 930 if (*resultln > 0 && 931 p < pe) 932 *p++ = (char) delim; 933 934 if (lmap->ldap_attrsep != '\0') 935 { 936 p += sm_strlcpy(p, attr, 937 pe - p); 938 if (p < pe) 939 *p++ = lmap->ldap_attrsep; 940 } 941 942 p += sm_strlcpy(p, vals[i], 943 pe - p); 944 *resultln = p - (*result); 945 if (p >= pe) 946 { 947 /* Internal error: buffer too small for LDAP values */ 948 SM_LDAP_ERROR_CLEANUP(); 949 errno = ENOMEM; 950 return EX_OSERR; 951 } 952 } 953 } 954 955 ldap_value_free(vals); 956 ldap_memfree(attr); 957 } 958 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 959 960 /* 961 ** We check save_errno != LDAP_DECODING_ERROR since 962 ** OpenLDAP 1.X has a very ugly *undocumented* 963 ** hack of returning this error code from 964 ** ldap_next_attribute() if the library freed the 965 ** ber attribute. See: 966 ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 967 */ 968 969 if (save_errno != LDAP_SUCCESS && 970 save_errno != LDAP_DECODING_ERROR) 971 { 972 /* Must be an error */ 973 save_errno += E_LDAPBASE; 974 SM_LDAP_ERROR_CLEANUP(); 975 errno = save_errno; 976 return EX_TEMPFAIL; 977 } 978 979 /* mark this DN as done */ 980 rl->lr_done = true; 981 if (rl->lr_ludp != NULL) 982 { 983 ldap_free_urldesc(rl->lr_ludp); 984 rl->lr_ludp = NULL; 985 } 986 if (rl->lr_attrs != NULL) 987 { 988 free(rl->lr_attrs); 989 rl->lr_attrs = NULL; 990 } 991 992 /* We don't want multiple values and we have one */
|
993 if ((char) delim == '\0' && *result != NULL)
| 993 if ((char) delim == '\0' && 994 !bitset(SM_LDAP_SINGLEMATCH, flags) && 995 *result != NULL)
|
994 break; 995 } 996 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 997 if (save_errno != LDAP_SUCCESS && 998 save_errno != LDAP_DECODING_ERROR) 999 { 1000 /* Must be an error */ 1001 save_errno += E_LDAPBASE; 1002 SM_LDAP_ERROR_CLEANUP(); 1003 errno = save_errno; 1004 return EX_TEMPFAIL; 1005 } 1006 ldap_msgfree(lmap->ldap_res); 1007 lmap->ldap_res = NULL; 1008 } 1009 1010 if (ret == 0) 1011 save_errno = ETIMEDOUT; 1012 else 1013 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 1014 if (save_errno != LDAP_SUCCESS) 1015 { 1016 statp = EX_TEMPFAIL; 1017 if (ret != 0) 1018 { 1019 switch (save_errno) 1020 { 1021#ifdef LDAP_SERVER_DOWN 1022 case LDAP_SERVER_DOWN: 1023#endif /* LDAP_SERVER_DOWN */ 1024 case LDAP_TIMEOUT: 1025 case LDAP_UNAVAILABLE: 1026 1027 /* 1028 ** server disappeared, 1029 ** try reopen on next search 1030 */ 1031 1032 statp = EX_RESTART; 1033 break; 1034 } 1035 save_errno += E_LDAPBASE; 1036 } 1037 SM_LDAP_ERROR_CLEANUP(); 1038 errno = save_errno; 1039 return statp; 1040 } 1041 1042 if (lmap->ldap_res != NULL) 1043 { 1044 ldap_msgfree(lmap->ldap_res); 1045 lmap->ldap_res = NULL; 1046 } 1047 1048 if (toplevel) 1049 { 1050 int rlidx; 1051 1052 /* 1053 ** Spin through the built-up recurse list at the top 1054 ** of the recursion. Since new items are added at the 1055 ** end of the shared list, we actually only ever get 1056 ** one level of recursion before things pop back to the 1057 ** top. Any items added to the list during that recursion 1058 ** will be expanded by the top level. 1059 */ 1060 1061 for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++) 1062 { 1063 int newflags; 1064 int sid; 1065 int status; 1066 1067 rl = recurse->lr_data[rlidx]; 1068 1069 newflags = flags; 1070 if (rl->lr_done) 1071 { 1072 /* already expanded */ 1073 continue; 1074 } 1075 1076 if (rl->lr_type == SM_LDAP_ATTR_DN) 1077 { 1078 /* do DN search */ 1079 sid = ldap_search(lmap->ldap_ld, 1080 rl->lr_search, 1081 lmap->ldap_scope, 1082 "(objectClass=*)", 1083 (lmap->ldap_attr[0] == NULL ? 1084 NULL : lmap->ldap_attr), 1085 lmap->ldap_attrsonly); 1086 } 1087 else if (rl->lr_type == SM_LDAP_ATTR_FILTER) 1088 { 1089 /* do new search */ 1090 sid = ldap_search(lmap->ldap_ld, 1091 lmap->ldap_base, 1092 lmap->ldap_scope, 1093 rl->lr_search, 1094 (lmap->ldap_attr[0] == NULL ? 1095 NULL : lmap->ldap_attr), 1096 lmap->ldap_attrsonly); 1097 } 1098 else if (rl->lr_type == SM_LDAP_ATTR_URL) 1099 { 1100 /* Parse URL */ 1101 sid = ldap_url_parse(rl->lr_search, 1102 &rl->lr_ludp); 1103 1104 if (sid != 0) 1105 { 1106 errno = sid + E_LDAPURLBASE; 1107 return EX_TEMPFAIL; 1108 } 1109 1110 /* We need to add objectClass */ 1111 if (rl->lr_ludp->lud_attrs != NULL) 1112 { 1113 int attrnum = 0; 1114 1115 while (rl->lr_ludp->lud_attrs[attrnum] != NULL) 1116 { 1117 if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum], 1118 "objectClass") == 0) 1119 { 1120 /* already requested */ 1121 attrnum = -1; 1122 break; 1123 } 1124 attrnum++; 1125 } 1126 1127 if (attrnum >= 0) 1128 { 1129 int i; 1130 1131 rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2)); 1132 if (rl->lr_attrs == NULL) 1133 { 1134 save_errno = errno; 1135 ldap_free_urldesc(rl->lr_ludp); 1136 errno = save_errno; 1137 return EX_TEMPFAIL; 1138 } 1139 for (i = 0 ; i < attrnum; i++) 1140 { 1141 rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i]; 1142 } 1143 rl->lr_attrs[i++] = "objectClass"; 1144 rl->lr_attrs[i++] = NULL; 1145 } 1146 } 1147 1148 /* 1149 ** Use the existing connection 1150 ** for this search. It really 1151 ** should use lud_scheme://lud_host:lud_port/ 1152 ** instead but that would require 1153 ** opening a new connection. 1154 ** This should be fixed ASAP. 1155 */ 1156 1157 sid = ldap_search(lmap->ldap_ld, 1158 rl->lr_ludp->lud_dn, 1159 rl->lr_ludp->lud_scope, 1160 rl->lr_ludp->lud_filter, 1161 rl->lr_attrs, 1162 lmap->ldap_attrsonly); 1163 1164 /* Use the attributes specified by URL */ 1165 newflags |= SM_LDAP_USE_ALLATTR; 1166 } 1167 else 1168 { 1169 /* unknown or illegal attribute type */ 1170 errno = EFAULT; 1171 return EX_SOFTWARE; 1172 } 1173 1174 /* Collect results */ 1175 if (sid == -1) 1176 { 1177 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 1178 statp = EX_TEMPFAIL; 1179 switch (save_errno) 1180 { 1181#ifdef LDAP_SERVER_DOWN 1182 case LDAP_SERVER_DOWN: 1183#endif /* LDAP_SERVER_DOWN */ 1184 case LDAP_TIMEOUT: 1185 case LDAP_UNAVAILABLE: 1186 1187 /* 1188 ** server disappeared, 1189 ** try reopen on next search 1190 */ 1191 1192 statp = EX_RESTART; 1193 break; 1194 } 1195 errno = save_errno + E_LDAPBASE; 1196 return statp; 1197 } 1198 1199 status = sm_ldap_results(lmap, sid, newflags, delim, 1200 rpool, result, resultln, 1201 resultsz, recurse); 1202 save_errno = errno; 1203 if (status != EX_OK && status != EX_NOTFOUND) 1204 { 1205 errno = save_errno; 1206 return status; 1207 } 1208 1209 /* Mark as done */ 1210 rl->lr_done = true; 1211 if (rl->lr_ludp != NULL) 1212 { 1213 ldap_free_urldesc(rl->lr_ludp); 1214 rl->lr_ludp = NULL; 1215 } 1216 if (rl->lr_attrs != NULL) 1217 { 1218 free(rl->lr_attrs); 1219 rl->lr_attrs = NULL; 1220 } 1221 1222 /* Reset rlidx as new items may have been added */ 1223 rlidx = -1; 1224 } 1225 } 1226 return statp; 1227} 1228 1229/* 1230** SM_LDAP_CLOSE -- close LDAP connection 1231** 1232** Parameters: 1233** lmap -- LDAP map information 1234** 1235** Returns: 1236** None. 1237** 1238*/ 1239 1240void 1241sm_ldap_close(lmap) 1242 SM_LDAP_STRUCT *lmap; 1243{ 1244 if (lmap->ldap_ld == NULL) 1245 return; 1246 1247 if (lmap->ldap_pid == getpid()) 1248 ldap_unbind(lmap->ldap_ld); 1249 lmap->ldap_ld = NULL; 1250 lmap->ldap_pid = 0; 1251} 1252 1253/* 1254** SM_LDAP_SETOPTS -- set LDAP options 1255** 1256** Parameters: 1257** ld -- LDAP session handle 1258** lmap -- LDAP map information 1259** 1260** Returns: 1261** None. 1262** 1263*/ 1264 1265void 1266sm_ldap_setopts(ld, lmap) 1267 LDAP *ld; 1268 SM_LDAP_STRUCT *lmap; 1269{ 1270# if USE_LDAP_SET_OPTION 1271 if (lmap->ldap_version != 0) 1272 { 1273 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 1274 &lmap->ldap_version); 1275 } 1276 ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 1277 if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 1278 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 1279 else 1280 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1281 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 1282 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 1283# ifdef LDAP_OPT_RESTART 1284 ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1285# endif /* LDAP_OPT_RESTART */ 1286# else /* USE_LDAP_SET_OPTION */ 1287 /* From here on in we can use ldap internal timelimits */ 1288 ld->ld_deref = lmap->ldap_deref; 1289 ld->ld_options = lmap->ldap_options; 1290 ld->ld_sizelimit = lmap->ldap_sizelimit; 1291 ld->ld_timelimit = lmap->ldap_timelimit; 1292# endif /* USE_LDAP_SET_OPTION */ 1293} 1294 1295/* 1296** SM_LDAP_GETERRNO -- get ldap errno value 1297** 1298** Parameters: 1299** ld -- LDAP session handle 1300** 1301** Returns: 1302** LDAP errno. 1303** 1304*/ 1305 1306int 1307sm_ldap_geterrno(ld) 1308 LDAP *ld; 1309{ 1310 int err = LDAP_SUCCESS; 1311 1312# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 1313 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 1314# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 1315# ifdef LDAP_OPT_SIZELIMIT 1316 err = ldap_get_lderrno(ld, NULL, NULL); 1317# else /* LDAP_OPT_SIZELIMIT */ 1318 err = ld->ld_errno; 1319 1320 /* 1321 ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 1322 ** OpenLDAP 1.X's hack (see above) 1323 */ 1324 1325 ld->ld_errno = LDAP_SUCCESS; 1326# endif /* LDAP_OPT_SIZELIMIT */ 1327# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 1328 return err; 1329} 1330# endif /* LDAPMAP */
| 996 break; 997 } 998 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 999 if (save_errno != LDAP_SUCCESS && 1000 save_errno != LDAP_DECODING_ERROR) 1001 { 1002 /* Must be an error */ 1003 save_errno += E_LDAPBASE; 1004 SM_LDAP_ERROR_CLEANUP(); 1005 errno = save_errno; 1006 return EX_TEMPFAIL; 1007 } 1008 ldap_msgfree(lmap->ldap_res); 1009 lmap->ldap_res = NULL; 1010 } 1011 1012 if (ret == 0) 1013 save_errno = ETIMEDOUT; 1014 else 1015 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 1016 if (save_errno != LDAP_SUCCESS) 1017 { 1018 statp = EX_TEMPFAIL; 1019 if (ret != 0) 1020 { 1021 switch (save_errno) 1022 { 1023#ifdef LDAP_SERVER_DOWN 1024 case LDAP_SERVER_DOWN: 1025#endif /* LDAP_SERVER_DOWN */ 1026 case LDAP_TIMEOUT: 1027 case LDAP_UNAVAILABLE: 1028 1029 /* 1030 ** server disappeared, 1031 ** try reopen on next search 1032 */ 1033 1034 statp = EX_RESTART; 1035 break; 1036 } 1037 save_errno += E_LDAPBASE; 1038 } 1039 SM_LDAP_ERROR_CLEANUP(); 1040 errno = save_errno; 1041 return statp; 1042 } 1043 1044 if (lmap->ldap_res != NULL) 1045 { 1046 ldap_msgfree(lmap->ldap_res); 1047 lmap->ldap_res = NULL; 1048 } 1049 1050 if (toplevel) 1051 { 1052 int rlidx; 1053 1054 /* 1055 ** Spin through the built-up recurse list at the top 1056 ** of the recursion. Since new items are added at the 1057 ** end of the shared list, we actually only ever get 1058 ** one level of recursion before things pop back to the 1059 ** top. Any items added to the list during that recursion 1060 ** will be expanded by the top level. 1061 */ 1062 1063 for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++) 1064 { 1065 int newflags; 1066 int sid; 1067 int status; 1068 1069 rl = recurse->lr_data[rlidx]; 1070 1071 newflags = flags; 1072 if (rl->lr_done) 1073 { 1074 /* already expanded */ 1075 continue; 1076 } 1077 1078 if (rl->lr_type == SM_LDAP_ATTR_DN) 1079 { 1080 /* do DN search */ 1081 sid = ldap_search(lmap->ldap_ld, 1082 rl->lr_search, 1083 lmap->ldap_scope, 1084 "(objectClass=*)", 1085 (lmap->ldap_attr[0] == NULL ? 1086 NULL : lmap->ldap_attr), 1087 lmap->ldap_attrsonly); 1088 } 1089 else if (rl->lr_type == SM_LDAP_ATTR_FILTER) 1090 { 1091 /* do new search */ 1092 sid = ldap_search(lmap->ldap_ld, 1093 lmap->ldap_base, 1094 lmap->ldap_scope, 1095 rl->lr_search, 1096 (lmap->ldap_attr[0] == NULL ? 1097 NULL : lmap->ldap_attr), 1098 lmap->ldap_attrsonly); 1099 } 1100 else if (rl->lr_type == SM_LDAP_ATTR_URL) 1101 { 1102 /* Parse URL */ 1103 sid = ldap_url_parse(rl->lr_search, 1104 &rl->lr_ludp); 1105 1106 if (sid != 0) 1107 { 1108 errno = sid + E_LDAPURLBASE; 1109 return EX_TEMPFAIL; 1110 } 1111 1112 /* We need to add objectClass */ 1113 if (rl->lr_ludp->lud_attrs != NULL) 1114 { 1115 int attrnum = 0; 1116 1117 while (rl->lr_ludp->lud_attrs[attrnum] != NULL) 1118 { 1119 if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum], 1120 "objectClass") == 0) 1121 { 1122 /* already requested */ 1123 attrnum = -1; 1124 break; 1125 } 1126 attrnum++; 1127 } 1128 1129 if (attrnum >= 0) 1130 { 1131 int i; 1132 1133 rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2)); 1134 if (rl->lr_attrs == NULL) 1135 { 1136 save_errno = errno; 1137 ldap_free_urldesc(rl->lr_ludp); 1138 errno = save_errno; 1139 return EX_TEMPFAIL; 1140 } 1141 for (i = 0 ; i < attrnum; i++) 1142 { 1143 rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i]; 1144 } 1145 rl->lr_attrs[i++] = "objectClass"; 1146 rl->lr_attrs[i++] = NULL; 1147 } 1148 } 1149 1150 /* 1151 ** Use the existing connection 1152 ** for this search. It really 1153 ** should use lud_scheme://lud_host:lud_port/ 1154 ** instead but that would require 1155 ** opening a new connection. 1156 ** This should be fixed ASAP. 1157 */ 1158 1159 sid = ldap_search(lmap->ldap_ld, 1160 rl->lr_ludp->lud_dn, 1161 rl->lr_ludp->lud_scope, 1162 rl->lr_ludp->lud_filter, 1163 rl->lr_attrs, 1164 lmap->ldap_attrsonly); 1165 1166 /* Use the attributes specified by URL */ 1167 newflags |= SM_LDAP_USE_ALLATTR; 1168 } 1169 else 1170 { 1171 /* unknown or illegal attribute type */ 1172 errno = EFAULT; 1173 return EX_SOFTWARE; 1174 } 1175 1176 /* Collect results */ 1177 if (sid == -1) 1178 { 1179 save_errno = sm_ldap_geterrno(lmap->ldap_ld); 1180 statp = EX_TEMPFAIL; 1181 switch (save_errno) 1182 { 1183#ifdef LDAP_SERVER_DOWN 1184 case LDAP_SERVER_DOWN: 1185#endif /* LDAP_SERVER_DOWN */ 1186 case LDAP_TIMEOUT: 1187 case LDAP_UNAVAILABLE: 1188 1189 /* 1190 ** server disappeared, 1191 ** try reopen on next search 1192 */ 1193 1194 statp = EX_RESTART; 1195 break; 1196 } 1197 errno = save_errno + E_LDAPBASE; 1198 return statp; 1199 } 1200 1201 status = sm_ldap_results(lmap, sid, newflags, delim, 1202 rpool, result, resultln, 1203 resultsz, recurse); 1204 save_errno = errno; 1205 if (status != EX_OK && status != EX_NOTFOUND) 1206 { 1207 errno = save_errno; 1208 return status; 1209 } 1210 1211 /* Mark as done */ 1212 rl->lr_done = true; 1213 if (rl->lr_ludp != NULL) 1214 { 1215 ldap_free_urldesc(rl->lr_ludp); 1216 rl->lr_ludp = NULL; 1217 } 1218 if (rl->lr_attrs != NULL) 1219 { 1220 free(rl->lr_attrs); 1221 rl->lr_attrs = NULL; 1222 } 1223 1224 /* Reset rlidx as new items may have been added */ 1225 rlidx = -1; 1226 } 1227 } 1228 return statp; 1229} 1230 1231/* 1232** SM_LDAP_CLOSE -- close LDAP connection 1233** 1234** Parameters: 1235** lmap -- LDAP map information 1236** 1237** Returns: 1238** None. 1239** 1240*/ 1241 1242void 1243sm_ldap_close(lmap) 1244 SM_LDAP_STRUCT *lmap; 1245{ 1246 if (lmap->ldap_ld == NULL) 1247 return; 1248 1249 if (lmap->ldap_pid == getpid()) 1250 ldap_unbind(lmap->ldap_ld); 1251 lmap->ldap_ld = NULL; 1252 lmap->ldap_pid = 0; 1253} 1254 1255/* 1256** SM_LDAP_SETOPTS -- set LDAP options 1257** 1258** Parameters: 1259** ld -- LDAP session handle 1260** lmap -- LDAP map information 1261** 1262** Returns: 1263** None. 1264** 1265*/ 1266 1267void 1268sm_ldap_setopts(ld, lmap) 1269 LDAP *ld; 1270 SM_LDAP_STRUCT *lmap; 1271{ 1272# if USE_LDAP_SET_OPTION 1273 if (lmap->ldap_version != 0) 1274 { 1275 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 1276 &lmap->ldap_version); 1277 } 1278 ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 1279 if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 1280 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 1281 else 1282 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1283 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 1284 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 1285# ifdef LDAP_OPT_RESTART 1286 ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1287# endif /* LDAP_OPT_RESTART */ 1288# else /* USE_LDAP_SET_OPTION */ 1289 /* From here on in we can use ldap internal timelimits */ 1290 ld->ld_deref = lmap->ldap_deref; 1291 ld->ld_options = lmap->ldap_options; 1292 ld->ld_sizelimit = lmap->ldap_sizelimit; 1293 ld->ld_timelimit = lmap->ldap_timelimit; 1294# endif /* USE_LDAP_SET_OPTION */ 1295} 1296 1297/* 1298** SM_LDAP_GETERRNO -- get ldap errno value 1299** 1300** Parameters: 1301** ld -- LDAP session handle 1302** 1303** Returns: 1304** LDAP errno. 1305** 1306*/ 1307 1308int 1309sm_ldap_geterrno(ld) 1310 LDAP *ld; 1311{ 1312 int err = LDAP_SUCCESS; 1313 1314# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 1315 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 1316# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 1317# ifdef LDAP_OPT_SIZELIMIT 1318 err = ldap_get_lderrno(ld, NULL, NULL); 1319# else /* LDAP_OPT_SIZELIMIT */ 1320 err = ld->ld_errno; 1321 1322 /* 1323 ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 1324 ** OpenLDAP 1.X's hack (see above) 1325 */ 1326 1327 ld->ld_errno = LDAP_SUCCESS; 1328# endif /* LDAP_OPT_SIZELIMIT */ 1329# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 1330 return err; 1331} 1332# endif /* LDAPMAP */
|