1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <stdlib.h> 31 #include <libintl.h> 32 #include <ctype.h> 33 34 #include <sys/stat.h> 35 #include <sys/mman.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <syslog.h> 40 #include <sys/socket.h> 41 #include <sys/sockio.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <net/if.h> 45 #include <netdir.h> 46 #include <lber.h> 47 #include <ldap.h> 48 49 #include "ns_sldap.h" 50 #include "ns_internal.h" 51 #include "ns_cache_door.h" 52 53 #define UDP "/dev/udp" 54 #define MAXIFS 32 55 56 struct ifinfo { 57 struct in_addr addr, netmask; 58 }; 59 60 static ns_service_map ns_def_map[] = { 61 { "passwd", "ou=people,", NULL }, 62 { "shadow", "ou=people,", "passwd" }, 63 { "user_attr", "ou=people,", "passwd" }, 64 { "audit_user", "ou=people,", "passwd" }, 65 { "group", "ou=group,", NULL }, 66 { "rpc", "ou=rpc,", NULL }, 67 { "project", "ou=projects,", NULL }, 68 { "protocols", "ou=protocols,", NULL }, 69 { "networks", "ou=networks,", NULL }, 70 { "netmasks", "ou=networks,", "networks" }, 71 { "netgroup", "ou=netgroup,", NULL }, 72 { "aliases", "ou=aliases,", NULL }, 73 { "Hosts", "ou=Hosts,", NULL }, 74 { "ipnodes", "ou=Hosts,", "hosts" }, 75 { "Services", "ou=Services,", NULL }, 76 { "bootparams", "ou=ethers,", "ethers" }, 77 { "ethers", "ou=ethers,", NULL }, 78 { "auth_attr", "ou=SolarisAuthAttr,", NULL }, 79 { "prof_attr", "ou=SolarisProfAttr,", NULL }, 80 { "exec_attr", "ou=SolarisProfAttr,", "prof_attr" }, 81 { "profile", "ou=profile,", NULL }, 82 { "printers", "ou=printers,", NULL }, 83 { "automount", "", NULL }, 84 { "tnrhtp", "ou=ipTnet,", NULL }, 85 { "tnrhdb", "ou=ipTnet,", "tnrhtp" }, 86 { NULL, NULL, NULL } 87 }; 88 89 90 static char ** parseDN(const char *val, const char *service); 91 static char ** sortServerNet(char **srvlist); 92 static char ** sortServerPref(char **srvlist, char **preflist, 93 boolean_t flag, int version, int *error); 94 95 /* 96 * FUNCTION: s_api_printResult 97 * Given a ns_ldap_result structure print it. 98 */ 99 int 100 __s_api_printResult(ns_ldap_result_t *result) 101 { 102 103 ns_ldap_entry_t *curEntry; 104 int i, j, k = 0; 105 106 #ifdef DEBUG 107 (void) fprintf(stderr, "__s_api_printResult START\n"); 108 #endif 109 (void) printf("--------------------------------------\n"); 110 if (result == NULL) { 111 (void) printf("No result\n"); 112 return (0); 113 } 114 (void) printf("entries_count %d\n", result->entries_count); 115 curEntry = result->entry; 116 for (i = 0; i < result->entries_count; i++) { 117 118 (void) printf("entry %d has attr_count = %d \n", i, 119 curEntry->attr_count); 120 for (j = 0; j < curEntry->attr_count; j++) { 121 (void) printf("entry %d has attr_pair[%d] = %s \n", i, j, 122 curEntry->attr_pair[j]->attrname); 123 for (k = 0; k < 20 && curEntry->attr_pair[j]->attrvalue[k]; k++) 124 (void) printf( 125 "entry %d has attr_pair[%d]->attrvalue[%d] = %s \n", 126 i, j, k, curEntry->attr_pair[j]->attrvalue[k]); 127 } 128 (void) printf("\n--------------------------------------\n"); 129 curEntry = curEntry->next; 130 } 131 return (1); 132 } 133 134 /* 135 * FUNCTION: __s_api_getSearchScope 136 * 137 * Retrieve the search scope for ldap search from the config module. 138 * 139 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_CONFIG 140 * INPUT: NONE 141 * OUTPUT: searchScope, errorp 142 */ 143 int 144 __s_api_getSearchScope( 145 int *searchScope, 146 ns_ldap_error_t **errorp) 147 { 148 149 char errmsg[MAXERROR]; 150 void **paramVal = NULL; 151 int rc = 0; 152 int scope = 0; 153 154 #ifdef DEBUG 155 (void) fprintf(stderr, "__s_api_getSearchScope START\n"); 156 #endif 157 if (*searchScope == 0) { 158 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P, 159 ¶mVal, errorp)) != NS_LDAP_SUCCESS) { 160 return (rc); 161 } 162 if (paramVal && *paramVal) 163 scope = * (int *)(*paramVal); 164 else 165 scope = NS_LDAP_SCOPE_ONELEVEL; 166 (void) __ns_ldap_freeParam(¶mVal); 167 } else { 168 scope = *searchScope; 169 } 170 171 switch (scope) { 172 173 case NS_LDAP_SCOPE_ONELEVEL: 174 *searchScope = LDAP_SCOPE_ONELEVEL; 175 break; 176 case NS_LDAP_SCOPE_BASE: 177 *searchScope = LDAP_SCOPE_BASE; 178 break; 179 case NS_LDAP_SCOPE_SUBTREE: 180 *searchScope = LDAP_SCOPE_SUBTREE; 181 break; 182 default: 183 (void) snprintf(errmsg, sizeof (errmsg), 184 gettext("Invalid search scope!")); 185 MKERROR(LOG_ERR, *errorp, NS_CONFIG_FILE, 186 strdup(errmsg), NS_LDAP_CONFIG); 187 return (NS_LDAP_CONFIG); 188 } 189 190 return (NS_LDAP_SUCCESS); 191 } 192 193 /* 194 * FUNCTION: __ns_ldap_dupAuth 195 * 196 * Duplicates an authentication structure. 197 * 198 * RETURN VALUES: copy of authp or NULL on error 199 * INPUT: authp 200 */ 201 ns_cred_t * 202 __ns_ldap_dupAuth(const ns_cred_t *authp) 203 { 204 ns_cred_t *ap; 205 206 #ifdef DEBUG 207 (void) fprintf(stderr, "__ns_ldap_dupAuth START\n"); 208 #endif 209 if (authp == NULL) 210 return (NULL); 211 212 ap = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 213 if (ap == NULL) 214 return (NULL); 215 216 if (authp->hostcertpath) { 217 ap->hostcertpath = strdup(authp->hostcertpath); 218 if (ap->hostcertpath == NULL) { 219 free(ap); 220 return (NULL); 221 } 222 } 223 if (authp->cred.unix_cred.userID) { 224 ap->cred.unix_cred.userID = 225 strdup(authp->cred.unix_cred.userID); 226 if (ap->cred.unix_cred.userID == NULL) { 227 (void) __ns_ldap_freeCred(&ap); 228 return (NULL); 229 } 230 } 231 if (authp->cred.unix_cred.passwd) { 232 ap->cred.unix_cred.passwd = 233 strdup(authp->cred.unix_cred.passwd); 234 if (ap->cred.unix_cred.passwd == NULL) { 235 (void) __ns_ldap_freeCred(&ap); 236 return (NULL); 237 } 238 } 239 if (authp->cred.cert_cred.nickname) { 240 ap->cred.cert_cred.nickname = 241 strdup(authp->cred.cert_cred.nickname); 242 if (ap->cred.cert_cred.nickname == NULL) { 243 (void) __ns_ldap_freeCred(&ap); 244 return (NULL); 245 } 246 } 247 ap->auth.type = authp->auth.type; 248 ap->auth.tlstype = authp->auth.tlstype; 249 ap->auth.saslmech = authp->auth.saslmech; 250 ap->auth.saslopt = authp->auth.saslopt; 251 return (ap); 252 } 253 254 /* 255 * FUNCTION: __ns_ldap_freeCred 256 * 257 * Frees all the memory associated with a ns_cred_t structure. 258 * 259 * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS, NS_LDAP_CONFIG 260 * INPUT: ns_cred_t 261 */ 262 int 263 __ns_ldap_freeCred(ns_cred_t ** credp) 264 { 265 ns_cred_t *ap; 266 267 #ifdef DEBUG 268 (void) fprintf(stderr, "__ns_ldap_freeCred START\n"); 269 #endif 270 if (credp == NULL || *credp == NULL) 271 return (NS_LDAP_INVALID_PARAM); 272 273 ap = *credp; 274 if (ap->hostcertpath) { 275 (void) memset(ap->hostcertpath, 0, 276 strlen(ap->hostcertpath)); 277 free(ap->hostcertpath); 278 } 279 280 if (ap->cred.unix_cred.userID) { 281 (void) memset(ap->cred.unix_cred.userID, 0, 282 strlen(ap->cred.unix_cred.userID)); 283 free(ap->cred.unix_cred.userID); 284 } 285 286 if (ap->cred.unix_cred.passwd) { 287 (void) memset(ap->cred.unix_cred.passwd, 0, 288 strlen(ap->cred.unix_cred.passwd)); 289 free(ap->cred.unix_cred.passwd); 290 } 291 292 if (ap->cred.cert_cred.nickname) { 293 (void) memset(ap->cred.cert_cred.nickname, 0, 294 strlen(ap->cred.cert_cred.nickname)); 295 free(ap->cred.cert_cred.nickname); 296 } 297 298 free(ap); 299 *credp = NULL; 300 return (NS_LDAP_SUCCESS); 301 } 302 303 /* 304 * FUNCTION: __s_api_getDNs 305 * 306 * Retrieves the default base dn for the given 307 * service. 308 * 309 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG 310 * INPUT: service 311 * OUTPUT: DN, error 312 */ 313 int 314 __s_api_getDNs( 315 char *** DN, 316 const char *service, 317 ns_ldap_error_t ** error) 318 { 319 320 void **paramVal = NULL; 321 char **dns = NULL; 322 int rc = 0; 323 int i, len; 324 325 #ifdef DEBUG 326 (void) fprintf(stderr, "__s_api_getDNs START\n"); 327 #endif 328 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P, 329 ¶mVal, error)) != NS_LDAP_SUCCESS) { 330 return (rc); 331 } 332 if (!paramVal) { 333 char errmsg[MAXERROR]; 334 335 (void) snprintf(errmsg, sizeof (errmsg), 336 gettext("BaseDN not defined")); 337 MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errmsg), 338 NS_LDAP_CONFIG); 339 return (NS_LDAP_CONFIG); 340 } 341 342 dns = (char **)calloc(2, sizeof (char *)); 343 if (dns == NULL) { 344 (void) __ns_ldap_freeParam(¶mVal); 345 return (NS_LDAP_MEMORY); 346 } 347 348 if (service == NULL) { 349 dns[0] = strdup((char *)*paramVal); 350 if (dns[0] == NULL) { 351 (void) __ns_ldap_freeParam(¶mVal); 352 free(dns); 353 return (NS_LDAP_MEMORY); 354 } 355 } else { 356 for (i = 0; ns_def_map[i].service != NULL; i++) { 357 if (strcasecmp(service, 358 ns_def_map[i].service) == 0) { 359 360 len = strlen((char *)*paramVal) + 361 strlen(ns_def_map[i].rdn) + 1; 362 dns[0] = (char *) 363 calloc(len, sizeof (char)); 364 if (dns[0] == NULL) { 365 (void) __ns_ldap_freeParam( 366 ¶mVal); 367 free(dns); 368 return (NS_LDAP_MEMORY); 369 } 370 (void) strcpy(dns[0], 371 ns_def_map[i].rdn); 372 (void) strcat(dns[0], 373 (char *)*paramVal); 374 break; 375 } 376 } 377 if (ns_def_map[i].service == NULL) { 378 char *p = (char *)*paramVal; 379 char *buffer = NULL; 380 int buflen = 0; 381 382 if (strchr(service, '=') == NULL) { 383 /* automount entries */ 384 if (strncasecmp(service, "auto_", 5) == 0) { 385 buffer = strdup(p); 386 if (!buffer) { 387 free(dns); 388 (void) __ns_ldap_freeParam(¶mVal); 389 return (NS_LDAP_MEMORY); 390 } 391 rc = __s_api_prepend_automountmapname_to_dn( 392 service, &buffer, error); 393 if (rc != NS_LDAP_SUCCESS) { 394 free(dns); 395 free(buffer); 396 (void) __ns_ldap_freeParam(¶mVal); 397 return (rc); 398 } 399 } else { 400 /* strlen("nisMapName")+"="+","+'\0' = 13 */ 401 buflen = strlen(service) + strlen(p) + 13; 402 buffer = (char *)malloc(buflen); 403 if (buffer == NULL) { 404 free(dns); 405 (void) __ns_ldap_freeParam(¶mVal); 406 return (NS_LDAP_MEMORY); 407 } 408 (void) snprintf(buffer, buflen, 409 "nisMapName=%s,%s", service, p); 410 } 411 } else { 412 buflen = strlen(service) + strlen(p) + 2; 413 buffer = (char *)malloc(buflen); 414 if (buffer == NULL) { 415 free(dns); 416 (void) __ns_ldap_freeParam(¶mVal); 417 return (NS_LDAP_MEMORY); 418 } 419 (void) snprintf(buffer, buflen, 420 "%s,%s", service, p); 421 } 422 dns[0] = buffer; 423 } 424 } 425 426 (void) __ns_ldap_freeParam(¶mVal); 427 *DN = dns; 428 return (NS_LDAP_SUCCESS); 429 } 430 /* 431 * FUNCTION: __s_api_get_search_DNs_v1 432 * 433 * Retrieves the list of search DNS from the V1 profile for the given 434 * service. 435 * 436 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG 437 * INPUT: service 438 * OUTPUT: DN, error 439 */ 440 int 441 __s_api_get_search_DNs_v1( 442 char *** DN, 443 const char *service, 444 ns_ldap_error_t ** error) 445 { 446 447 void **paramVal = NULL; 448 void **temptr = NULL; 449 char **dns = NULL; 450 int rc = 0; 451 452 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_DN_P, 453 ¶mVal, error)) != NS_LDAP_SUCCESS) { 454 return (rc); 455 } 456 457 if (service && paramVal) { 458 for (temptr = paramVal; *temptr != NULL; temptr++) { 459 dns = parseDN((const char *)(*temptr), 460 (const char *)service); 461 if (dns != NULL) 462 break; 463 } 464 } 465 466 (void) __ns_ldap_freeParam(¶mVal); 467 *DN = dns; 468 return (NS_LDAP_SUCCESS); 469 470 } 471 /* 472 * FUNCTION: parseDN 473 * 474 * Parse a special formated list(val) into an array of char *. 475 * 476 * RETURN VALUE: A char * pointer to the new list of dns. 477 * INPUT: val, service 478 */ 479 static char ** 480 parseDN( 481 const char *val, 482 const char *service) 483 { 484 485 size_t len = 0; 486 size_t slen = 0; 487 char **retVal = NULL; 488 const char *temptr; 489 char *temptr2; 490 const char *valend; 491 int valNo = 0; 492 int valSize = 0; 493 int i; 494 char *SSD_service = NULL; 495 496 #ifdef DEBUG 497 (void) fprintf(stderr, "parseDN START\n"); 498 #endif 499 if (val == NULL || *val == '\0') 500 return (NULL); 501 if (service == NULL || *service == '\0') 502 return (NULL); 503 504 len = strlen(val); 505 slen = strlen(service); 506 if (strncasecmp(val, service, slen) != 0) { 507 /* 508 * This routine is only called 509 * to process V1 profile and 510 * for V1 profile, map service 511 * to the corresponding SSD_service 512 * which is associated with a 513 * real container in the LDAP directory 514 * tree, e.g., map "shadow" to 515 * "password". See function 516 * __s_api_get_SSD_from_SSDtoUse_service 517 * for similar service to SSD_service 518 * mapping handling for V2 profile. 519 */ 520 for (i = 0; ns_def_map[i].service != NULL; i++) { 521 if (ns_def_map[i].SSDtoUse_service && 522 strcasecmp(service, 523 ns_def_map[i].service) == 0) { 524 SSD_service = 525 ns_def_map[i].SSDtoUse_service; 526 break; 527 } 528 } 529 530 if (SSD_service == NULL) 531 return (NULL); 532 533 slen = strlen(SSD_service); 534 if (strncasecmp(val, SSD_service, slen) != 0) 535 return (NULL); 536 } 537 538 temptr = val + slen; 539 while (*temptr == SPACETOK || *temptr == TABTOK) 540 temptr++; 541 if (*temptr != COLONTOK) 542 return (NULL); 543 544 while (*temptr) { 545 temptr2 = strchr(temptr, OPARATOK); 546 if (temptr2 == NULL) 547 break; 548 temptr2++; 549 temptr2 = strchr(temptr2, CPARATOK); 550 if (temptr2 == NULL) 551 break; 552 valNo++; 553 temptr = temptr2+1; 554 } 555 556 retVal = (char **)calloc(valNo +1, sizeof (char *)); 557 if (retVal == NULL) 558 return (NULL); 559 560 temptr = val; 561 valend = val+len; 562 563 for (i = 0; (i < valNo) && (temptr < valend); i++) { 564 temptr = strchr(temptr, OPARATOK); 565 if (temptr == NULL) { 566 __s_api_free2dArray(retVal); 567 return (NULL); 568 } 569 temptr++; 570 temptr2 = strchr(temptr, CPARATOK); 571 if (temptr2 == NULL) { 572 __s_api_free2dArray(retVal); 573 return (NULL); 574 } 575 valSize = temptr2 - temptr; 576 577 retVal[i] = (char *)calloc(valSize + 1, sizeof (char)); 578 if (retVal[i] == NULL) { 579 __s_api_free2dArray(retVal); 580 return (NULL); 581 } 582 (void) strncpy(retVal[i], temptr, valSize); 583 retVal[i][valSize] = '\0'; 584 temptr = temptr2 + 1; 585 } 586 587 return (retVal); 588 } 589 590 591 /* 592 * __s_api_get_local_interfaces 593 * 594 * Returns a pointer to an array of addresses and netmasks of all interfaces 595 * configured on the system. 596 * 597 * NOTE: This function is very IPv4 centric. 598 */ 599 static struct ifinfo * 600 __s_api_get_local_interfaces() 601 { 602 struct ifconf ifc; 603 struct ifreq ifreq, *ifr; 604 struct ifinfo *localinfo; 605 struct in_addr netmask; 606 struct sockaddr_in *sin; 607 void *buf = NULL; 608 int fd = 0; 609 int numifs = 0; 610 int i, n = 0; 611 612 if ((fd = open(UDP, O_RDONLY)) < 0) 613 return ((struct ifinfo *)NULL); 614 615 if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) { 616 numifs = MAXIFS; 617 } 618 619 buf = malloc(numifs * sizeof (struct ifreq)); 620 if (buf == NULL) { 621 (void) close(fd); 622 return ((struct ifinfo *)NULL); 623 } 624 ifc.ifc_len = numifs * (int)sizeof (struct ifreq); 625 ifc.ifc_buf = buf; 626 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) { 627 (void) close(fd); 628 free(buf); 629 buf = NULL; 630 return ((struct ifinfo *)NULL); 631 } 632 ifr = (struct ifreq *)buf; 633 numifs = ifc.ifc_len/(int)sizeof (struct ifreq); 634 localinfo = (struct ifinfo *)malloc((numifs + 1) * 635 sizeof (struct ifinfo)); 636 if (localinfo == NULL) { 637 (void) close(fd); 638 free(buf); 639 buf = NULL; 640 return ((struct ifinfo *)NULL); 641 } 642 643 for (i = 0, n = numifs; n > 0; n--, ifr++) { 644 uint_t ifrflags; 645 646 ifreq = *ifr; 647 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0) 648 continue; 649 650 ifrflags = ifreq.ifr_flags; 651 if (((ifrflags & IFF_UP) == 0) || 652 (ifr->ifr_addr.sa_family != AF_INET)) 653 continue; 654 655 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifreq) < 0) 656 continue; 657 netmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; 658 659 if (ioctl(fd, SIOCGIFADDR, (char *)&ifreq) < 0) 660 continue; 661 662 sin = (struct sockaddr_in *)&ifreq.ifr_addr; 663 664 localinfo[i].addr = sin->sin_addr; 665 localinfo[i].netmask = netmask; 666 i++; 667 } 668 localinfo[i].addr.s_addr = 0; 669 670 free(buf); 671 buf = NULL; 672 (void) close(fd); 673 return (localinfo); 674 } 675 676 677 /* 678 * __s_api_samenet(char *, struct ifinfo *) 679 * 680 * Returns 1 if address is on the same subnet of the array of addresses 681 * passed in. 682 * 683 * NOTE: This function is only valid for IPv4 addresses. 684 */ 685 static int 686 __s_api_IPv4sameNet(char *addr, struct ifinfo *ifs) 687 { 688 int answer = 0; 689 690 if (addr && ifs) { 691 char *addr_raw; 692 unsigned long iaddr; 693 int i; 694 695 if ((addr_raw = strdup(addr)) != NULL) { 696 char *s; 697 698 /* Remove port number. */ 699 if ((s = strchr(addr_raw, ':')) != NULL) 700 *s = '\0'; 701 702 iaddr = inet_addr(addr_raw); 703 704 /* Loop through interface list to find match. */ 705 for (i = 0; ifs[i].addr.s_addr != 0; i++) { 706 if ((iaddr & ifs[i].netmask.s_addr) == 707 (ifs[i].addr.s_addr & 708 ifs[i].netmask.s_addr)) 709 answer++; 710 } 711 free(addr_raw); 712 } 713 } 714 715 return (answer); 716 } 717 718 /* 719 * FUNCTION: __s_api_getServers 720 * 721 * Retrieve a list of ldap servers from the config module. 722 * 723 * RETURN VALUE: NS_LDAP_SUCCESS, NS_LDAP_CONFIG, NS_LDAP_MEMORY 724 * INPUT: NONE 725 * OUTPUT: servers, error 726 */ 727 int 728 __s_api_getServers( 729 char *** servers, 730 ns_ldap_error_t ** error) 731 { 732 void **paramVal = NULL; 733 char errmsg[MAXERROR]; 734 char **sortServers = NULL; 735 char **netservers = NULL; 736 int rc = 0, err = NS_LDAP_CONFIG, version = 1; 737 const char *str, *str1; 738 739 #ifdef DEBUG 740 (void) fprintf(stderr, "__s_api_getServers START\n"); 741 #endif 742 *servers = NULL; 743 /* get profile version number */ 744 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 745 ¶mVal, error)) != NS_LDAP_SUCCESS) 746 return (rc); 747 748 if (paramVal == NULL || *paramVal == NULL) { 749 (void) snprintf(errmsg, sizeof (errmsg), 750 gettext("No file version")); 751 MKERROR(LOG_INFO, *error, NS_CONFIG_FILE, strdup(errmsg), 752 NS_LDAP_CONFIG); 753 return (NS_LDAP_CONFIG); 754 } 755 756 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 757 version = 1; 758 else if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_2) == 0) 759 version = 2; 760 761 (void) __ns_ldap_freeParam(¶mVal); 762 paramVal = NULL; 763 764 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVERS_P, 765 ¶mVal, error)) != NS_LDAP_SUCCESS) 766 return (rc); 767 768 /* 769 * For version 2, default server list could be 770 * empty. 771 */ 772 if ((paramVal == NULL || (char *)*paramVal == NULL) && 773 version == 1) { 774 str = NULL_OR_STR(__s_api_get_configname(NS_LDAP_SERVERS_P)); 775 (void) snprintf(errmsg, sizeof (errmsg), 776 gettext("Unable to retrieve the '%s' list"), str); 777 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE, strdup(errmsg), 778 NS_LDAP_CONFIG); 779 return (NS_LDAP_CONFIG); 780 } 781 782 /* 783 * Get server address(es) and go through them. 784 */ 785 *servers = (char **)paramVal; 786 paramVal = NULL; 787 788 /* Sort servers based on network. */ 789 if (*servers) { 790 netservers = sortServerNet(*servers); 791 if (netservers) { 792 free(*servers); 793 *servers = netservers; 794 } else { 795 return (NS_LDAP_MEMORY); 796 } 797 } 798 799 /* Get preferred server list and sort servers based on that. */ 800 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P, 801 ¶mVal, error)) != NS_LDAP_SUCCESS) { 802 if (*servers) 803 __s_api_free2dArray(*servers); 804 *servers = NULL; 805 return (rc); 806 } 807 808 if (paramVal != NULL) { 809 char **prefServers; 810 void **val = NULL; 811 812 if ((rc = __ns_ldap_getParam(NS_LDAP_PREF_ONLY_P, 813 &val, error)) != NS_LDAP_SUCCESS) { 814 if (*servers) 815 __s_api_free2dArray(*servers); 816 *servers = NULL; 817 (void) __ns_ldap_freeParam(¶mVal); 818 return (rc); 819 } 820 821 prefServers = (char **)paramVal; 822 paramVal = NULL; 823 if (prefServers) { 824 if (val != NULL && (*val) != NULL && 825 *(int *)val[0] == 1) 826 sortServers = sortServerPref(*servers, 827 prefServers, B_FALSE, version, 828 &err); 829 else 830 sortServers = sortServerPref(*servers, 831 prefServers, B_TRUE, version, 832 &err); 833 if (sortServers) { 834 if (*servers) 835 free(*servers); 836 *servers = NULL; 837 free(prefServers); 838 prefServers = NULL; 839 *servers = sortServers; 840 } else { 841 if (*servers) 842 __s_api_free2dArray(*servers); 843 *servers = NULL; 844 __s_api_free2dArray(prefServers); 845 prefServers = NULL; 846 } 847 } 848 (void) __ns_ldap_freeParam(&val); 849 } 850 (void) __ns_ldap_freeParam(¶mVal); 851 852 if (*servers == NULL) { 853 if (err == NS_LDAP_CONFIG) { 854 str = NULL_OR_STR(__s_api_get_configname( 855 NS_LDAP_SERVERS_P)); 856 str1 = NULL_OR_STR(__s_api_get_configname( 857 NS_LDAP_SERVER_PREF_P)); 858 (void) snprintf(errmsg, sizeof (errmsg), 859 gettext("Unable to generate a new server list " 860 "based on '%s' and/or '%s'"), str, str1); 861 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE, 862 strdup(errmsg), err); 863 return (err); 864 } 865 return (NS_LDAP_MEMORY); 866 } 867 868 return (NS_LDAP_SUCCESS); 869 870 } 871 872 /* 873 * FUNCTION: sortServerNet 874 * Sort the serverlist based on the distance from client as long 875 * as the list only contains IPv4 addresses. Otherwise do nothing. 876 */ 877 static char ** 878 sortServerNet(char **srvlist) 879 { 880 int count = 0; 881 int all = 0; 882 int ipv4only = 1; 883 struct ifinfo *ifs = __s_api_get_local_interfaces(); 884 char **tsrvs; 885 char **psrvs, **retsrvs; 886 887 /* Sanity check. */ 888 if (srvlist == NULL || srvlist[0] == NULL) 889 return (NULL); 890 891 /* Count the number of servers to sort. */ 892 for (count = 0; srvlist[count] != NULL; count++) { 893 if (!__s_api_isipv4(srvlist[count])) 894 ipv4only = 0; 895 } 896 count++; 897 898 /* Make room for the returned list of servers. */ 899 retsrvs = (char **)calloc(count, sizeof (char *)); 900 if (retsrvs == NULL) { 901 free(ifs); 902 ifs = NULL; 903 return (NULL); 904 } 905 906 retsrvs[count - 1] = NULL; 907 908 /* Make a temporary list of servers. */ 909 psrvs = (char **)calloc(count, sizeof (char *)); 910 if (psrvs == NULL) { 911 free(ifs); 912 ifs = NULL; 913 free(retsrvs); 914 retsrvs = NULL; 915 return (NULL); 916 } 917 918 /* Filter servers on the same subnet */ 919 tsrvs = srvlist; 920 while (*tsrvs) { 921 if (ipv4only && __s_api_IPv4sameNet(*tsrvs, ifs)) { 922 psrvs[all] = *tsrvs; 923 retsrvs[all++] = *(tsrvs); 924 } 925 tsrvs++; 926 } 927 928 /* Filter remaining servers. */ 929 tsrvs = srvlist; 930 while (*tsrvs) { 931 char **ttsrvs = psrvs; 932 933 while (*ttsrvs) { 934 if (strcmp(*tsrvs, *ttsrvs) == 0) 935 break; 936 ttsrvs++; 937 } 938 939 if (*ttsrvs == NULL) 940 retsrvs[all++] = *(tsrvs); 941 tsrvs++; 942 } 943 944 free(ifs); 945 ifs = NULL; 946 free(psrvs); 947 psrvs = NULL; 948 949 return (retsrvs); 950 } 951 952 /* 953 * FUNCTION: sortServerPref 954 * Sort the serverlist based on the preferred server list. 955 * 956 * The sorting algorithm works as follows: 957 * 958 * If version 1, if flag is TRUE, find all the servers in both preflist 959 * and srvlist, then append other servers in srvlist to this list 960 * and return the list. 961 * If flag is FALSE, just return srvlist. 962 * srvlist can not be empty. 963 * 964 * If version 2, append all the servers in srvlist 965 * but not in preflist to preflist, and return the merged list. 966 * If srvlist is empty, just return preflist. 967 * If preflist is empty, just return srvlist. 968 */ 969 static char ** 970 sortServerPref(char **srvlist, char **preflist, 971 boolean_t flag, int version, int *error) 972 { 973 int i, scount = 0, pcount = 0; 974 int all = 0, dup = 0; 975 char **tsrvs; 976 char **retsrvs; 977 char **dupsrvs; 978 979 /* Count the number of servers to sort. */ 980 if (srvlist && srvlist[0]) 981 for (i = 0; srvlist[i] != NULL; i++) 982 scount++; 983 984 /* Sanity check. */ 985 if (scount == 0 && version == 1) { 986 *error = NS_LDAP_CONFIG; 987 return (NULL); 988 } 989 990 /* Count the number of preferred servers */ 991 if (preflist && preflist[0]) 992 for (i = 0; preflist[i] != NULL; i++) 993 pcount++; 994 995 /* Sanity check. */ 996 if (scount == 0 && pcount == 0) { 997 *error = NS_LDAP_CONFIG; 998 return (NULL); 999 } 1000 1001 /* Make room for the returned list of servers */ 1002 retsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *)); 1003 if (retsrvs == NULL) { 1004 *error = NS_LDAP_MEMORY; 1005 return (NULL); 1006 } 1007 1008 /* 1009 * if the preferred server list is empty, 1010 * just return a copy of the server list 1011 */ 1012 if (pcount == 0) { 1013 tsrvs = srvlist; 1014 while (*tsrvs) 1015 retsrvs[all++] = *(tsrvs++); 1016 return (retsrvs); 1017 } 1018 all = 0; 1019 1020 /* 1021 * if the server list is empty, 1022 * just return a copy of the preferred server list 1023 */ 1024 if (scount == 0) { 1025 tsrvs = preflist; 1026 while (*tsrvs) 1027 retsrvs[all++] = *(tsrvs++); 1028 return (retsrvs); 1029 } 1030 all = 0; 1031 1032 /* Make room for the servers whose memory needs to be freed */ 1033 dupsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *)); 1034 if (dupsrvs == NULL) { 1035 free(retsrvs); 1036 *error = NS_LDAP_MEMORY; 1037 return (NULL); 1038 } 1039 1040 /* 1041 * If version 1, 1042 * throw out preferred servers not on server list. 1043 * If version 2, make a copy of the preferred server list. 1044 */ 1045 if (version == 1) { 1046 tsrvs = preflist; 1047 while (*tsrvs) { 1048 char **ttsrvs = srvlist; 1049 1050 while (*ttsrvs) { 1051 if (strcmp(*tsrvs, *(ttsrvs)) == 0) 1052 break; 1053 ttsrvs++; 1054 } 1055 if (*ttsrvs != NULL) 1056 retsrvs[all++] = *tsrvs; 1057 else 1058 dupsrvs[dup++] = *tsrvs; 1059 tsrvs++; 1060 } 1061 } else { 1062 tsrvs = preflist; 1063 while (*tsrvs) 1064 retsrvs[all++] = *(tsrvs++); 1065 } 1066 /* 1067 * If version 1, 1068 * if PREF_ONLY is false, we append the non-preferred servers 1069 * to bottom of list. 1070 * For version 2, always append. 1071 */ 1072 if (flag == B_TRUE || version != 1) { 1073 1074 tsrvs = srvlist; 1075 while (*tsrvs) { 1076 char **ttsrvs = preflist; 1077 1078 while (*ttsrvs) { 1079 if (strcmp(*tsrvs, *ttsrvs) == 0) { 1080 break; 1081 } 1082 ttsrvs++; 1083 } 1084 if (*ttsrvs == NULL) 1085 retsrvs[all++] = *tsrvs; 1086 else 1087 dupsrvs[dup++] = *tsrvs; 1088 tsrvs++; 1089 } 1090 } 1091 1092 /* free memory for duplicate servers */ 1093 if (dup) { 1094 for (tsrvs = dupsrvs; *tsrvs; tsrvs++) 1095 free(*tsrvs); 1096 } 1097 free(dupsrvs); 1098 1099 return (retsrvs); 1100 } 1101 1102 /* 1103 * FUNCTION: __s_api_removeBadServers 1104 * Contacts the ldap cache manager for marking the 1105 * problem servers as down, so that the server is 1106 * not contacted until the TTL expires. 1107 */ 1108 void 1109 __s_api_removeBadServers(char ** Servers) 1110 { 1111 1112 char **host; 1113 1114 if (Servers == NULL) 1115 return; 1116 1117 for (host = Servers; *host != NULL; host++) { 1118 if (__s_api_removeServer(*host) < 0) { 1119 /* 1120 * Couldn't remove server from 1121 * server list. Log a warning. 1122 */ 1123 syslog(LOG_WARNING, "libsldap: could " 1124 "not remove %s from servers list", *host); 1125 } 1126 } 1127 } 1128 1129 /* 1130 * FUNCTION: __s_api_free2dArray 1131 */ 1132 void 1133 __s_api_free2dArray(char ** inarray) 1134 { 1135 1136 char **temptr; 1137 1138 if (inarray == NULL) 1139 return; 1140 1141 for (temptr = inarray; *temptr != NULL; temptr++) { 1142 free(*temptr); 1143 } 1144 free(inarray); 1145 } 1146 1147 /* 1148 * FUNCTION: __s_api_cp2dArray 1149 */ 1150 char ** 1151 __s_api_cp2dArray(char **inarray) 1152 { 1153 char **newarray; 1154 char **ttarray, *ret; 1155 int count; 1156 1157 if (inarray == NULL) 1158 return (NULL); 1159 1160 for (count = 0; inarray[count] != NULL; count++); 1161 1162 newarray = (char **)calloc(count + 1, sizeof (char *)); 1163 if (newarray == NULL) 1164 return (NULL); 1165 1166 ttarray = newarray; 1167 for (; *inarray; inarray++) { 1168 *(ttarray++) = ret = strdup(*inarray); 1169 if (ret == NULL) { 1170 __s_api_free2dArray(newarray); 1171 return (NULL); 1172 } 1173 } 1174 return (newarray); 1175 } 1176 1177 /* 1178 * FUNCTION: __s_api_isCtrlSupported 1179 * Determines if the passed control is supported by the LDAP sever. 1180 * RETURNS: NS_LDAP_SUCCESS if yes, NS_LDAP_OP_FAIL if not. 1181 */ 1182 int 1183 __s_api_isCtrlSupported(Connection *con, char *ctrlString) 1184 { 1185 char **ctrl; 1186 int len; 1187 1188 len = strlen(ctrlString); 1189 for (ctrl = con->controls; ctrl && *ctrl; ctrl++) { 1190 if (strncasecmp(*ctrl, ctrlString, len) == 0) 1191 return (NS_LDAP_SUCCESS); 1192 } 1193 return (NS_LDAP_OP_FAILED); 1194 } 1195 1196 /* 1197 * FUNCTION: __s_api_toFollowReferrals 1198 * Determines if need to follow referral for an SLDAP API. 1199 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_INVALID_PARAM, or 1200 * other rc from __ns_ldap_getParam() 1201 * INPUT: flags 1202 * OUTPUT: toFollow, errorp 1203 */ 1204 int 1205 __s_api_toFollowReferrals(const int flags, 1206 int *toFollow, 1207 ns_ldap_error_t **errorp) 1208 { 1209 void **paramVal = NULL; 1210 int rc = 0; 1211 int iflags = 0; 1212 1213 #ifdef DEBUG 1214 (void) fprintf(stderr, "__s_api_toFollowReferrals START\n"); 1215 #endif 1216 1217 /* Either NS_LDAP_NOREF or NS_LDAP_FOLLOWREF not both */ 1218 if ((flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) == 1219 (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) { 1220 return (NS_LDAP_INVALID_PARAM); 1221 } 1222 1223 /* 1224 * if the NS_LDAP_NOREF or NS_LDAP_FOLLOWREF is set 1225 * this will take precendence over the values specified 1226 * in the configuration file 1227 */ 1228 if (flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) { 1229 iflags = flags; 1230 } else { 1231 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_REF_P, 1232 ¶mVal, errorp); 1233 if (rc != NS_LDAP_SUCCESS) 1234 return (rc); 1235 if (paramVal == NULL || *paramVal == NULL) { 1236 (void) __ns_ldap_freeParam(¶mVal); 1237 if (*errorp) 1238 (void) __ns_ldap_freeError(errorp); 1239 *toFollow = TRUE; 1240 return (NS_LDAP_SUCCESS); 1241 } 1242 iflags = (* (int *)(*paramVal)); 1243 (void) __ns_ldap_freeParam(¶mVal); 1244 } 1245 1246 if (iflags & NS_LDAP_NOREF) 1247 *toFollow = FALSE; 1248 else 1249 *toFollow = TRUE; 1250 1251 return (NS_LDAP_SUCCESS); 1252 } 1253 1254 /* 1255 * FUNCTION: __s_api_addRefInfo 1256 * Insert a referral info into a referral info list. 1257 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_OP_FAILED 1258 * INPUT: LDAP URL, pointer to the referral info list, 1259 * search baseDN, search scope, search filter, 1260 * previous connection 1261 */ 1262 int 1263 __s_api_addRefInfo(ns_referral_info_t **head, char *url, 1264 char *baseDN, int *scope, 1265 char *filter, LDAP *ld) 1266 { 1267 char errmsg[MAXERROR], *tmp; 1268 ns_referral_info_t *ref, *tmpref; 1269 LDAPURLDesc *ludp = NULL; 1270 int hostlen; 1271 char *ld_defhost = NULL; 1272 1273 #ifdef DEBUG 1274 (void) fprintf(stderr, "__s_api_addRefInfo START\n"); 1275 #endif 1276 1277 /* sanity check */ 1278 if (head == NULL) 1279 return (NS_LDAP_OP_FAILED); 1280 1281 /* 1282 * log error and return NS_LDAP_SUCCESS 1283 * if one of the following: 1284 * 1. non-LDAP URL 1285 * 2. LDAP URL which can not be parsed 1286 */ 1287 if (!ldap_is_ldap_url(url) || 1288 ldap_url_parse_nodn(url, &ludp) != 0) { 1289 (void) snprintf(errmsg, MAXERROR, "%s: %s", 1290 gettext("Invalid or non-LDAP URL when" 1291 " processing referrals URL"), 1292 url); 1293 syslog(LOG_ERR, "libsldap: %s", errmsg); 1294 if (ludp) 1295 ldap_free_urldesc(ludp); 1296 return (NS_LDAP_SUCCESS); 1297 } 1298 1299 ref = (ns_referral_info_t *)calloc(1, 1300 sizeof (ns_referral_info_t)); 1301 if (ref == NULL) { 1302 ldap_free_urldesc(ludp); 1303 return (NS_LDAP_MEMORY); 1304 } 1305 1306 /* 1307 * we do have a valid URL and we were able to parse it 1308 * however, we still need to find out what hostport to 1309 * use if none were provided in the LDAP URL 1310 * (e.g., ldap:///...) 1311 */ 1312 if ((ludp->lud_port == 0) && (ludp->lud_host == NULL)) { 1313 if (ld == NULL) { 1314 (void) snprintf(errmsg, MAXERROR, "%s: %s", 1315 gettext("no LDAP handle when" 1316 " processing referrals URL"), 1317 url); 1318 syslog(LOG_WARNING, "libsldap: %s", errmsg); 1319 ldap_free_urldesc(ludp); 1320 free(ref); 1321 return (NS_LDAP_SUCCESS); 1322 } else { 1323 (void) ldap_get_option(ld, LDAP_OPT_HOST_NAME, 1324 &ld_defhost); 1325 if (ld_defhost == NULL) { 1326 (void) snprintf(errmsg, MAXERROR, "%s: %s", 1327 gettext("not able to retrieve default " 1328 "host when processing " 1329 "referrals URL"), 1330 url); 1331 syslog(LOG_WARNING, "libsldap: %s", errmsg); 1332 ldap_free_urldesc(ludp); 1333 free(ref); 1334 return (NS_LDAP_SUCCESS); 1335 } else { 1336 ref->refHost = strdup(ld_defhost); 1337 if (ref->refHost == NULL) { 1338 ldap_free_urldesc(ludp); 1339 free(ref); 1340 return (NS_LDAP_MEMORY); 1341 } 1342 } 1343 } 1344 } else { 1345 /* 1346 * add 4 here: 1347 * 1 for the last '\0'. 1348 * 1 for host and prot separator ":" 1349 * and "[" & "]" for possible ipV6 addressing 1350 */ 1351 hostlen = strlen(ludp->lud_host) + 1352 sizeof (MAXPORTNUMBER_STR) + 4; 1353 ref->refHost = (char *)malloc(hostlen); 1354 if (ref->refHost == NULL) { 1355 ldap_free_urldesc(ludp); 1356 free(ref); 1357 return (NS_LDAP_MEMORY); 1358 } 1359 1360 if (ludp->lud_port != 0) { 1361 /* 1362 * serverAddr = host:port 1363 * or 1364 * if host is an IPV6 address 1365 * [host]:port 1366 */ 1367 tmp = strstr(url, ludp->lud_host); 1368 if (tmp && (tmp > url) && *(tmp - 1) == '[') { 1369 (void) snprintf(ref->refHost, hostlen, 1370 "[%s]:%d", 1371 ludp->lud_host, 1372 ludp->lud_port); 1373 } else { 1374 (void) snprintf(ref->refHost, hostlen, 1375 "%s:%d", 1376 ludp->lud_host, 1377 ludp->lud_port); 1378 } 1379 } else { 1380 /* serverAddr = host */ 1381 (void) snprintf(ref->refHost, hostlen, "%s", 1382 ludp->lud_host); 1383 } 1384 } 1385 1386 if (ludp->lud_dn) { 1387 ref->refDN = strdup(ludp->lud_dn); 1388 if (ref->refDN == NULL) { 1389 ldap_free_urldesc(ludp); 1390 free(ref->refHost); 1391 free(ref); 1392 return (NS_LDAP_MEMORY); 1393 } 1394 } else { 1395 if (baseDN) { 1396 ref->refDN = strdup(baseDN); 1397 if (ref->refDN == NULL) { 1398 ldap_free_urldesc(ludp); 1399 free(ref->refHost); 1400 free(ref); 1401 return (NS_LDAP_MEMORY); 1402 } 1403 } 1404 } 1405 1406 if (filter) 1407 ref->refFilter = strdup(filter); 1408 else if (ludp->lud_filter) 1409 ref->refFilter = strdup(ludp->lud_filter); 1410 else 1411 ref->refFilter = strdup(""); 1412 1413 if (ref->refFilter == NULL) { 1414 ldap_free_urldesc(ludp); 1415 free(ref->refHost); 1416 if (ref->refDN) 1417 free(ref->refDN); 1418 free(ref); 1419 return (NS_LDAP_MEMORY); 1420 } 1421 1422 if (scope) 1423 ref->refScope = *scope; 1424 1425 ref->next = NULL; 1426 1427 ldap_free_urldesc(ludp); 1428 1429 /* insert the referral info */ 1430 if (*head) { 1431 for (tmpref = *head; tmpref->next; 1432 tmpref = tmpref->next); 1433 tmpref->next = ref; 1434 } else 1435 *head = ref; 1436 1437 return (NS_LDAP_SUCCESS); 1438 } 1439 1440 /* 1441 * FUNCTION: __s_api_deleteRefInfo 1442 * Delete a referral info list. 1443 * INPUT: pointer to the referral info list 1444 */ 1445 void 1446 __s_api_deleteRefInfo(ns_referral_info_t *head) 1447 { 1448 ns_referral_info_t *ref, *tmp; 1449 1450 #ifdef DEBUG 1451 (void) fprintf(stderr, "__s_api_deleteRefInfo START\n"); 1452 #endif 1453 1454 for (ref = head; ref; ) { 1455 if (ref->refHost) 1456 free(ref->refHost); 1457 if (ref->refDN) 1458 free(ref->refDN); 1459 if (ref->refFilter) 1460 free(ref->refFilter); 1461 tmp = ref->next; 1462 free(ref); 1463 ref = tmp; 1464 } 1465 1466 } 1467 1468 /* 1469 * FUNCTION: __s_api_get_SSD_from_SSDtoUse_service 1470 * 1471 * Retrieves the Service Search Descriptors which should be used for 1472 * the given service. For example, return all the "passwd" SSDs for 1473 * service "shadow" if no SSD is defined for service "shadow" and 1474 * no filter component is defined in all the "passwd" SSDs. This idea 1475 * of sharing the SSDs defined for some other service is to reduce the 1476 * configuration complexity. For a service, which does not have its own 1477 * entries in the LDAP directory, SSD for it is useless, and should not 1478 * be set. But since this service must share the container with at least 1479 * one other service which does have it own entries, the SSD for 1480 * this other service will be shared by this service. 1481 * This other service is called the SSD-to-use service. 1482 * The static data structure, ns_def_map[], in this file 1483 * defines the SSD-to-use service for all the services supported. 1484 * 1485 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_INVALID_PARAM 1486 * INPUT: service 1487 * OUTPUT: *SSDlist, *errorp if error 1488 */ 1489 int 1490 __s_api_get_SSD_from_SSDtoUse_service(const char *service, 1491 ns_ldap_search_desc_t ***SSDlist, 1492 ns_ldap_error_t **errorp) 1493 { 1494 int i, rc; 1495 int found = FALSE; 1496 int filter_found = FALSE; 1497 char *SSD_service = NULL; 1498 char errmsg[MAXERROR]; 1499 ns_ldap_search_desc_t **sdlist; 1500 int auto_service = FALSE; 1501 1502 #ifdef DEBUG 1503 (void) fprintf(stderr, 1504 "__s_api_get_SSD_from_SSDtoUse_service START\n"); 1505 #endif 1506 1507 if (SSDlist == NULL || errorp == NULL) 1508 return (NS_LDAP_INVALID_PARAM); 1509 1510 *SSDlist = NULL; 1511 *errorp = NULL; 1512 1513 if (service == NULL) 1514 return (NS_LDAP_SUCCESS); 1515 1516 if (strncasecmp(service, "auto_", 5) == 0) 1517 auto_service = TRUE; 1518 1519 /* 1520 * First try to return the configured SSDs for the input server 1521 */ 1522 rc = __ns_ldap_getSearchDescriptors(service, SSDlist, errorp); 1523 if (rc != NS_LDAP_SUCCESS) 1524 return (rc); 1525 else { 1526 if (*SSDlist != NULL) 1527 return (NS_LDAP_SUCCESS); 1528 } 1529 1530 /* 1531 * If service == auto_* and SSD is not found, 1532 * then try automount to see if there is an SSD 1533 * for automount. 1534 */ 1535 1536 if (auto_service) { 1537 rc = __ns_ldap_getSearchDescriptors( 1538 "automount", SSDlist, errorp); 1539 if (rc != NS_LDAP_SUCCESS) 1540 return (rc); 1541 else { 1542 if (*SSDlist != NULL) { 1543 /* 1544 * If SSDlist is found, 1545 * prepend automountMapName to the basedn 1546 * in the SSDlist 1547 * 1548 */ 1549 rc = __s_api_prepend_automountmapname( 1550 service, 1551 SSDlist, 1552 errorp); 1553 1554 if (rc != NS_LDAP_SUCCESS) { 1555 (void) __ns_ldap_freeSearchDescriptors( 1556 SSDlist); 1557 *SSDlist = NULL; 1558 } 1559 1560 return (rc); 1561 } 1562 } 1563 } 1564 1565 /* 1566 * Find the SSDtoUse service. 1567 * If none found, flag "found" remains FALSE. 1568 */ 1569 for (i = 0; ns_def_map[i].service != NULL; i++) { 1570 if (ns_def_map[i].SSDtoUse_service && 1571 strcasecmp(service, 1572 ns_def_map[i].service) == 0) { 1573 found = TRUE; 1574 SSD_service = ns_def_map[i].SSDtoUse_service; 1575 break; 1576 } 1577 } 1578 1579 if (!found) 1580 return (NS_LDAP_SUCCESS); 1581 1582 /* 1583 * return the SSDs for SSD_service only if no optional filter 1584 * component is defined in the SSDs 1585 */ 1586 rc = __ns_ldap_getSearchDescriptors(SSD_service, 1587 SSDlist, errorp); 1588 if (rc != NS_LDAP_SUCCESS) { 1589 return (rc); 1590 } else { 1591 if (*SSDlist == NULL) 1592 return (NS_LDAP_SUCCESS); 1593 1594 /* check to see if filter defined in SSD */ 1595 for (sdlist = *SSDlist; *sdlist; sdlist++) { 1596 if ((*sdlist)->filter && 1597 strlen((*sdlist)->filter) > 0) { 1598 filter_found = TRUE; 1599 break; 1600 } 1601 } 1602 if (filter_found) { 1603 (void) __ns_ldap_freeSearchDescriptors(SSDlist); 1604 *SSDlist = NULL; 1605 (void) snprintf(errmsg, sizeof (errmsg), 1606 gettext("Service search descriptor for " 1607 "service '%s' contains filter, " 1608 "which can not be used for " 1609 "service '%s'."), 1610 SSD_service, service); 1611 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, 1612 strdup(errmsg), NS_LDAP_CONFIG); 1613 return (NS_LDAP_CONFIG); 1614 } 1615 1616 } 1617 return (NS_LDAP_SUCCESS); 1618 } 1619 1620 1621 /* 1622 * verify addr is an IPv4 address with the optional [:portno] 1623 * RFC2373 & RFC2732 & RFC2396 1624 */ 1625 int 1626 __s_api_isipv4(char *addr) 1627 { 1628 int i, seg, digit, port; 1629 1630 if (!addr) 1631 return (0); 1632 1633 digit = seg = port = 0; 1634 1635 for (i = 0; i < strlen(addr); i++) { 1636 if (isdigit(addr[i])) { 1637 digit++; 1638 continue; 1639 } 1640 if (addr[i] == '.') { 1641 if (digit > 3 || digit == 0) 1642 return (0); 1643 digit = 0; 1644 seg++; 1645 continue; 1646 } 1647 if (addr[i] == ':') { 1648 if (digit > 3) 1649 return (0); 1650 port++; 1651 digit = 0; 1652 seg++; 1653 continue; 1654 } 1655 return (0); 1656 } 1657 1658 if ((seg == 3 && port == 0 && digit > 0 && digit < 4) || 1659 (seg == 4 && port == 1 && digit > 0)) 1660 return (1); 1661 1662 return (0); 1663 } 1664 1665 1666 /* 1667 * verify addr is an IPv6 address with the optional [IPv6]:portno 1668 * RFC2373 & RFC2732 & RFC2396 1669 */ 1670 int 1671 __s_api_isipv6(char *addr) 1672 { 1673 int i, col, digit, port, dc, tc; 1674 char *laddr, *c1, *s; 1675 1676 if (!addr) 1677 return (0); 1678 1679 s = addr; 1680 laddr = NULL; 1681 digit = col = port = 0; 1682 if (addr[0] == '[') { 1683 laddr = strdup(addr); 1684 if (!laddr) 1685 return (0); 1686 c1 = strchr(laddr, ']'); 1687 /* only 1 ']' should be in an addr */ 1688 if (!c1 || (strchr(c1+1, ']'))) 1689 goto bad; 1690 switch (c1[1]) { 1691 case ':': 1692 port++; 1693 for (i = 2; i < strlen(c1); i++) { 1694 if (!isdigit(c1[i])) 1695 goto bad; 1696 digit++; 1697 } 1698 if (!digit) 1699 goto bad; 1700 c1[0] = '\0'; 1701 break; 1702 case '\0': 1703 c1[0] = '\0'; 1704 break; 1705 default: 1706 goto bad; 1707 } 1708 s = &laddr[1]; 1709 } 1710 1711 digit = dc = tc = 0; 1712 for (i = 0; i < strlen(s); i++) { 1713 if (isxdigit(s[i])) { 1714 if (digit == 0) 1715 dc = i; 1716 digit++; 1717 col = 0; 1718 continue; 1719 } 1720 if (s[i] == ':') { 1721 tc++; 1722 if ((col > 1) || (i && !col && !digit)) 1723 goto bad; 1724 digit = 0; 1725 col++; 1726 continue; 1727 } 1728 if (s[i] == '.') { 1729 if (__s_api_isipv4(&s[dc]) && tc) 1730 goto good; 1731 else 1732 goto bad; 1733 } 1734 goto bad; 1735 } 1736 1737 good: 1738 free(laddr); 1739 return (1); 1740 bad: 1741 free(laddr); 1742 return (0); 1743 } 1744 1745 1746 /* 1747 * verify addr is a valid hostname with the optional [:portno] 1748 * RFC2373 & RFC2732 & RFC2396 1749 */ 1750 int 1751 __s_api_ishost(char *addr) 1752 { 1753 int i, seg, alpha, digit, port; 1754 1755 if (!addr) 1756 return (0); 1757 1758 alpha = digit = seg = port = 0; 1759 1760 /* must start with alpha character */ 1761 if (!isalpha(addr[0])) 1762 return (0); 1763 1764 for (i = 0; i < strlen(addr); i++) { 1765 if (isalpha(addr[i]) || (i && addr[i] == '-')) { 1766 alpha++; 1767 continue; 1768 } 1769 if (isdigit(addr[i])) { 1770 digit++; 1771 continue; 1772 } 1773 if (addr[i] == '.') { 1774 if (!alpha && !digit) 1775 return (0); 1776 alpha = digit = 0; 1777 seg++; 1778 continue; 1779 } 1780 if (addr[i] == ':') { 1781 if (!alpha && !digit) 1782 return (0); 1783 alpha = digit = 0; 1784 port++; 1785 seg++; 1786 continue; 1787 } 1788 return (0); 1789 } 1790 1791 if ((port == 0 && (seg || alpha || digit)) || 1792 (port == 1 && alpha == 0 && digit)) 1793 return (1); 1794 1795 return (0); 1796 } 1797 1798 1799 /* 1800 * Prepend automountMapName=auto_xxx to the basedn 1801 * in the SSDlist 1802 */ 1803 1804 int __s_api_prepend_automountmapname( 1805 const char *service, 1806 ns_ldap_search_desc_t ***SSDlist, 1807 ns_ldap_error_t **errorp) 1808 { 1809 int i, rc; 1810 ns_ldap_search_desc_t ** ssdlist = NULL; 1811 1812 if (service == NULL || SSDlist == NULL || *SSDlist == NULL) 1813 return (NS_LDAP_INVALID_PARAM); 1814 1815 ssdlist = *SSDlist; 1816 1817 for (i = 0; ssdlist[i] != NULL; i++) { 1818 rc = __s_api_prepend_automountmapname_to_dn( 1819 service, &ssdlist[i]->basedn, errorp); 1820 1821 if (rc != NS_LDAP_SUCCESS) 1822 return (rc); 1823 } 1824 1825 return (NS_LDAP_SUCCESS); 1826 } 1827 1828 1829 /* 1830 * Prepend automountMapName=auto_xxx to the DN 1831 * Construct a string of 1832 * "automountMapName=auto_xxx,dn" 1833 * 1834 * If automountMapName is mapped to some other attribute, 1835 * then use the mapping in the setup. 1836 * 1837 * If a version 1 profile is in use, use nisMapName for 1838 * backward compatibility (i.e. "nisMapName=auto_xxx,dn"). 1839 */ 1840 1841 int 1842 __s_api_prepend_automountmapname_to_dn( 1843 const char *service, 1844 char **dn, 1845 ns_ldap_error_t **errorp) 1846 { 1847 int rc, len_s = 0, len_d = 0, len = 0; 1848 char *buffer = NULL; 1849 char *default_automountmapname = "automountMapName"; 1850 char *automountmapname = NULL; 1851 char **mappedattrs = NULL; 1852 char errstr[MAXERROR]; 1853 void **paramVal = NULL; 1854 1855 if (service == NULL || dn == NULL || *dn == NULL) 1856 return (NS_LDAP_INVALID_PARAM); 1857 1858 rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, ¶mVal, errorp); 1859 if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) { 1860 if (paramVal) 1861 (void) __ns_ldap_freeParam(¶mVal); 1862 return (rc); 1863 } 1864 if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) { 1865 automountmapname = strdup("nisMapName"); 1866 (void) __ns_ldap_freeParam(¶mVal); 1867 if (automountmapname == NULL) { 1868 return (NS_LDAP_MEMORY); 1869 } 1870 } else { 1871 (void) __ns_ldap_freeParam(¶mVal); 1872 1873 /* Find mapped attribute name of auto_xxx first */ 1874 mappedattrs = __ns_ldap_getMappedAttributes( 1875 service, default_automountmapname); 1876 /* 1877 * if mapped attribute name of auto_xxx is not found, 1878 * find the mapped attribute name of automount 1879 */ 1880 1881 if (mappedattrs == NULL) 1882 mappedattrs = __ns_ldap_getMappedAttributes( 1883 "automount", default_automountmapname); 1884 1885 /* 1886 * if mapped attr is not found, use the default automountmapname 1887 */ 1888 1889 if (mappedattrs == NULL) { 1890 automountmapname = strdup(default_automountmapname); 1891 if (automountmapname == NULL) 1892 return (NS_LDAP_MEMORY); 1893 } else { 1894 if (mappedattrs[0] != NULL) { 1895 /* 1896 * Copy it from the mapped attr list 1897 * Assume it's 1 to 1 mapping 1898 * 1 to n does not make sense 1899 */ 1900 automountmapname = strdup(mappedattrs[0]); 1901 __s_api_free2dArray(mappedattrs); 1902 if (automountmapname == NULL) { 1903 return (NS_LDAP_MEMORY); 1904 } 1905 } else { 1906 1907 /* 1908 * automountmapname is mapped to an empty string 1909 */ 1910 1911 __s_api_free2dArray(mappedattrs); 1912 1913 (void) sprintf(errstr, 1914 gettext( 1915 "Attribute automountMapName is " 1916 "mapped to an empty string.\n")); 1917 1918 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX, 1919 strdup(errstr), NULL); 1920 1921 return (NS_LDAP_CONFIG); 1922 } 1923 } 1924 } 1925 1926 len_s = strlen(service); 1927 len_d = strlen(*dn); 1928 /* automountMapName + "=" + service + "," + dn + '\0' */ 1929 len = strlen(automountmapname) + 1 + len_s + 1 + len_d + 1; 1930 buffer = (char *)malloc(len); 1931 if (buffer == NULL) { 1932 free(automountmapname); 1933 return (NS_LDAP_MEMORY); 1934 } 1935 1936 (void) snprintf(buffer, len, "%s=%s,%s", 1937 automountmapname, service, *dn); 1938 1939 buffer[len-1] = '\0'; 1940 1941 free(automountmapname); 1942 1943 /* free the original dn */ 1944 (void) free(*dn); 1945 1946 *dn = buffer; 1947 1948 return (NS_LDAP_SUCCESS); 1949 } 1950 1951 /* 1952 * Map the LDAP error code and error message from LDAP server 1953 * to a password status used for password aging/management. 1954 */ 1955 ns_ldap_passwd_status_t 1956 __s_api_set_passwd_status(int errnum, char *errmsg) 1957 { 1958 if (errmsg) { 1959 if (errnum == 1960 LDAP_INVALID_CREDENTIALS) { 1961 /* 1962 * case 1 (Bind): 1963 * password expired 1964 */ 1965 if (strstr(errmsg, 1966 NS_PWDERR_EXPIRED)) 1967 return (NS_PASSWD_EXPIRED); 1968 } 1969 1970 if (errnum == 1971 LDAP_UNWILLING_TO_PERFORM) { 1972 /* 1973 * case 1.1 (Bind): 1974 * password expired 1975 */ 1976 if (strstr(errmsg, 1977 NS_PWDERR_EXPIRED)) 1978 return (NS_PASSWD_EXPIRED); 1979 1980 /* 1981 * case 2 (Bind): 1982 * Account inactivated 1983 */ 1984 if (strstr(errmsg, 1985 NS_PWDERR_ACCT_INACTIVATED)) 1986 return (NS_PASSWD_EXPIRED); 1987 1988 1989 /* 1990 * case 3 (Modify passwd): 1991 * the user is not allow to change 1992 * password; only admin can change it 1993 */ 1994 if (strstr(errmsg, 1995 NS_PWDERR_CHANGE_NOT_ALLOW)) 1996 return (NS_PASSWD_CHANGE_NOT_ALLOWED); 1997 } 1998 1999 if (errnum == 2000 LDAP_CONSTRAINT_VIOLATION) { 2001 /* 2002 * case 4 (Bind): 2003 * the user account is locked due to 2004 * too many login failures. 2005 */ 2006 if (strstr(errmsg, 2007 NS_PWDERR_MAXTRIES)) 2008 return (NS_PASSWD_RETRY_EXCEEDED); 2009 /* 2010 * case 5 (Modify passwd): 2011 * syntax error: the new password 2012 * has length less than defined 2013 * minimum 2014 */ 2015 if (strstr(errmsg, 2016 NS_PWDERR_INVALID_SYNTAX)) 2017 return (NS_PASSWD_TOO_SHORT); 2018 /* 2019 * case 6 (Modify passwd): 2020 * trivial password: same valule as 2021 * that of attribute cn, sn, or uid ... 2022 */ 2023 if (strstr(errmsg, 2024 NS_PWDERR_TRIVIAL_PASSWD)) 2025 return (NS_PASSWD_INVALID_SYNTAX); 2026 /* 2027 * case 7 (Modify passwd): 2028 * re-use one of the old passwords 2029 * in history list 2030 */ 2031 if (strstr(errmsg, 2032 NS_PWDERR_IN_HISTORY)) 2033 return (NS_PASSWD_IN_HISTORY); 2034 /* 2035 * case 8 (Modify passwd): 2036 * password not allowed to be 2037 * changed yet; within minimum 2038 * age 2039 */ 2040 if (strstr(errmsg, 2041 NS_PWDERR_WITHIN_MIN_AGE)) 2042 return (NS_PASSWD_WITHIN_MIN_AGE); 2043 } 2044 2045 } 2046 2047 return (NS_PASSWD_GOOD); 2048 } 2049 2050 /* 2051 * Determine if the input OID list contains 2052 * one of the password control OIDs, which are: 2053 * LDAP_CONTROL_PWEXPIRED: 2.16.840.1.113730.3.4.4 2054 * LDAP_CONTROL_PWEXPIRING: 2.16.840.1.113730.3.4.5. 2055 * If yes, return 1, if no, 0. 2056 */ 2057 int 2058 __s_api_contain_passwd_control_oid(char **oids) 2059 { 2060 char **oid; 2061 2062 if (oids == NULL) 2063 return (0); 2064 2065 for (oid = oids; *oid; oid++) { 2066 if (strcmp(*oid, LDAP_CONTROL_PWEXPIRED) == 0 || 2067 strcmp(*oid, LDAP_CONTROL_PWEXPIRING) == 0) { 2068 return (1); 2069 } 2070 } 2071 2072 return (0); 2073 } 2074 2075 /* 2076 * Determine if the input OID list contains LDAP V3 password less 2077 * account management control OID, which is: 2078 * NS_LDAP_ACCOUNT_USABLE_CONTROL:1.3.6.1.4.1.42.2.27.9.5.8 2079 * If yes, return 1, if no, 0. 2080 */ 2081 int 2082 __s_api_contain_account_usable_control_oid(char **oids) 2083 { 2084 char **oid; 2085 2086 if (oids == NULL) 2087 return (0); 2088 2089 for (oid = oids; *oid; oid++) { 2090 if (strcmp(*oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) == 0) { 2091 return (1); 2092 } 2093 } 2094 2095 return (0); 2096 } 2097 2098 /* 2099 * For some databases in name switch, the name and aliases are saved 2100 * as "cn". When the "cn" valuse are retrieved, there is no distinction 2101 * which is the name and which is(are) aliase(s). 2102 * This function is to parse RDN and find the value of the "cn" and 2103 * then find the matching value in "cn" attribute. 2104 * Also see RFC 2307 section 5.6. 2105 * 2106 * Input - 2107 * entry: An LDAP entry 2108 * attrptr: A attribute which value appears in RDN 2109 * This should be "cn" for the name switch for now. 2110 * case_ignore: 0 Case sensitive comparison on the attribute value 2111 * 1 Case insensitive comparison 2112 * 2113 * Return - 2114 * The value of an attrbute which is used as canonical name 2115 * This is read only and the caller should not try to free it. 2116 * If it's a NULL, it could be either an RDN parsing error 2117 * or RDN value does not match any existing "cn" values. 2118 * e.g. 2119 * dn: cn=xx+ipserviceprotocol=udp,...... 2120 * cn: aa 2121 * cn: bb 2122 * 2123 * Note: 2124 * Although the name switch/ldap's rdn is in "cn=xx" or "cn=xx+..." 2125 * format, this function makes no such assumption. If the DN 2126 * is saved as "dn: yy=...+sn=my_canocical_name, ..", then it can still work. 2127 * The comments use "cn" as an example only. 2128 * 2129 */ 2130 typedef int (*cmpfunc)(const char *, const char *); 2131 2132 char * 2133 __s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr, 2134 int case_ignore) { 2135 uint_t i; 2136 char *token, *lasts, *value = NULL; 2137 char **rdn = NULL, **attrs = NULL, **values = NULL; 2138 char *rdn_attr_value = NULL; 2139 cmpfunc cmp; 2140 2141 if (entry == NULL || attrptr == NULL) 2142 return (NULL); 2143 2144 /* "values" is read-only */ 2145 if ((values = __ns_ldap_getAttr(entry, "dn")) == NULL || 2146 values[0] == NULL) 2147 return (NULL); 2148 2149 if ((rdn = ldap_explode_dn(values[0], 0)) == NULL || 2150 rdn[0] == NULL) 2151 return (NULL); 2152 2153 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) { 2154 ldap_value_free(rdn); 2155 return (NULL); 2156 } 2157 /* Assume the rdn is normalized */ 2158 for (i = 0; attrs[i] != NULL; i++) { 2159 /* parse attribute name and value, get attribute name first */ 2160 if ((token = strtok_r(attrs[i], "=", &lasts)) == NULL) { 2161 goto cleanup; 2162 } 2163 if (strcasecmp(token, attrptr->attrname) == 0) { 2164 /* get value */ 2165 rdn_attr_value = lasts; 2166 break; 2167 } 2168 } 2169 if (rdn_attr_value) { 2170 if (case_ignore) 2171 cmp = strcasecmp; 2172 else 2173 cmp = strcmp; 2174 /* 2175 * After parsing RDN and find the matching attribute in RDN, 2176 * match rdn value with values in "cn". 2177 */ 2178 for (i = 0; i < attrptr->value_count; i++) { 2179 if (attrptr->attrvalue[i] && 2180 (*cmp)(rdn_attr_value, 2181 attrptr->attrvalue[i]) == 0) { 2182 /* RDN "cn" value matches the "cn" value */ 2183 value = attrptr->attrvalue[i]; 2184 break; 2185 } 2186 } 2187 } 2188 cleanup: 2189 ldap_value_free(rdn); 2190 ldap_value_free(attrs); 2191 2192 return (value); 2193 } 2194 2195 /* 2196 * This function requests a server to be removed from 2197 * the cache manager maintained server list. This is 2198 * done via the door functionality. 2199 * Returns 0 if OK, else a negative value. 2200 */ 2201 2202 int 2203 __s_api_removeServer(const char *server) 2204 { 2205 union { 2206 ldap_data_t s_d; 2207 char s_b[DOORBUFFERSIZE]; 2208 } space; 2209 2210 ns_server_info_t r, *ret = &r; 2211 const char *ireq; 2212 ldap_data_t *sptr; 2213 int ndata; 2214 int adata; 2215 int len; 2216 int rc; 2217 2218 if (server == NULL) 2219 return (-1); 2220 2221 ireq = NS_CACHE_NORESP; 2222 2223 (void) memset(ret, 0, sizeof (ns_server_info_t)); 2224 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 2225 2226 adata = (sizeof (ldap_call_t) + strlen(ireq) +1); 2227 adata += strlen(DOORLINESEP) + 1; 2228 adata += strlen(server) + 1; 2229 2230 ndata = sizeof (space); 2231 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 2232 len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); 2233 (void) strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len); 2234 (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len); 2235 (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len); 2236 sptr = &space.s_d; 2237 2238 /* try to remove the server via the door interface */ 2239 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata); 2240 2241 /* clean up the door call */ 2242 if (sptr != &space.s_d) { 2243 (void) munmap((char *)sptr, ndata); 2244 } 2245 2246 return (rc); 2247 } 2248