dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libsldap / common / ns_common.c
blob6f1a0a0048eb0bc6ac105c4511da6ef820a6b1ff
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <stdlib.h>
29 #include <libintl.h>
30 #include <ctype.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <syslog.h>
38 #include <sys/socket.h>
39 #include <sys/sockio.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <net/if.h>
43 #include <netdir.h>
44 #include <lber.h>
45 #include <ldap.h>
47 #include "ns_sldap.h"
48 #include "ns_internal.h"
49 #include "ns_cache_door.h"
51 #define UDP "/dev/udp"
52 #define MAXIFS 32
54 struct ifinfo {
55 struct in_addr addr, netmask;
58 static ns_service_map ns_def_map[] = {
59 { "passwd", "ou=people,", NULL },
60 { "shadow", "ou=people,", "passwd" },
61 { "user_attr", "ou=people,", "passwd" },
62 { "audit_user", "ou=people,", "passwd" },
63 { "group", "ou=group,", NULL },
64 { "rpc", "ou=rpc,", NULL },
65 { "project", "ou=projects,", NULL },
66 { "protocols", "ou=protocols,", NULL },
67 { "networks", "ou=networks,", NULL },
68 { "netmasks", "ou=networks,", "networks" },
69 { "netgroup", "ou=netgroup,", NULL },
70 { "aliases", "ou=aliases,", NULL },
71 { "Hosts", "ou=Hosts,", NULL },
72 { "ipnodes", "ou=Hosts,", "hosts" },
73 { "Services", "ou=Services,", NULL },
74 { "bootparams", "ou=ethers,", "ethers" },
75 { "ethers", "ou=ethers,", NULL },
76 { "auth_attr", "ou=SolarisAuthAttr,", NULL },
77 { "prof_attr", "ou=SolarisProfAttr,", NULL },
78 { "exec_attr", "ou=SolarisProfAttr,", "prof_attr" },
79 { "profile", "ou=profile,", NULL },
80 { "printers", "ou=printers,", NULL },
81 { "automount", "", NULL },
82 { NULL, NULL, NULL }
86 static char ** parseDN(const char *val, const char *service);
87 static char ** sortServerNet(char **srvlist);
88 static char ** sortServerPref(char **srvlist, char **preflist,
89 boolean_t flag, int version, int *error);
92 * FUNCTION: s_api_printResult
93 * Given a ns_ldap_result structure print it.
95 int
96 __s_api_printResult(ns_ldap_result_t *result)
99 ns_ldap_entry_t *curEntry;
100 int i, j, k = 0;
102 #ifdef DEBUG
103 (void) fprintf(stderr, "__s_api_printResult START\n");
104 #endif
105 (void) printf("--------------------------------------\n");
106 if (result == NULL) {
107 (void) printf("No result\n");
108 return (0);
110 (void) printf("entries_count %d\n", result->entries_count);
111 curEntry = result->entry;
112 for (i = 0; i < result->entries_count; i++) {
114 (void) printf("entry %d has attr_count = %d \n", i,
115 curEntry->attr_count);
116 for (j = 0; j < curEntry->attr_count; j++) {
117 (void) printf("entry %d has attr_pair[%d] = %s \n",
118 i, j, curEntry->attr_pair[j]->attrname);
119 for (k = 0; k < 20 &&
120 curEntry->attr_pair[j]->attrvalue[k]; k++)
121 (void) printf("entry %d has attr_pair[%d]->"
122 "attrvalue[%d] = %s \n", i, j, k,
123 curEntry->attr_pair[j]->attrvalue[k]);
125 (void) printf("\n--------------------------------------\n");
126 curEntry = curEntry->next;
128 return (1);
132 * FUNCTION: __s_api_getSearchScope
134 * Retrieve the search scope for ldap search from the config module.
136 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_CONFIG
137 * INPUT: NONE
138 * OUTPUT: searchScope, errorp
141 __s_api_getSearchScope(
142 int *searchScope,
143 ns_ldap_error_t **errorp)
146 char errmsg[MAXERROR];
147 void **paramVal = NULL;
148 int rc = 0;
149 int scope = 0;
151 #ifdef DEBUG
152 (void) fprintf(stderr, "__s_api_getSearchScope START\n");
153 #endif
154 if (*searchScope == 0) {
155 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
156 &paramVal, errorp)) != NS_LDAP_SUCCESS) {
157 return (rc);
159 if (paramVal && *paramVal)
160 scope = * (int *)(*paramVal);
161 else
162 scope = NS_LDAP_SCOPE_ONELEVEL;
163 (void) __ns_ldap_freeParam(&paramVal);
164 } else {
165 scope = *searchScope;
168 switch (scope) {
170 case NS_LDAP_SCOPE_ONELEVEL:
171 *searchScope = LDAP_SCOPE_ONELEVEL;
172 break;
173 case NS_LDAP_SCOPE_BASE:
174 *searchScope = LDAP_SCOPE_BASE;
175 break;
176 case NS_LDAP_SCOPE_SUBTREE:
177 *searchScope = LDAP_SCOPE_SUBTREE;
178 break;
179 default:
180 (void) snprintf(errmsg, sizeof (errmsg),
181 gettext("Invalid search scope!"));
182 MKERROR(LOG_ERR, *errorp, NS_CONFIG_FILE,
183 strdup(errmsg), NS_LDAP_CONFIG);
184 return (NS_LDAP_CONFIG);
187 return (NS_LDAP_SUCCESS);
191 * FUNCTION: __ns_ldap_dupAuth
193 * Duplicates an authentication structure.
195 * RETURN VALUES: copy of authp or NULL on error
196 * INPUT: authp
198 ns_cred_t *
199 __ns_ldap_dupAuth(const ns_cred_t *authp)
201 ns_cred_t *ap;
203 #ifdef DEBUG
204 (void) fprintf(stderr, "__ns_ldap_dupAuth START\n");
205 #endif
206 if (authp == NULL)
207 return (NULL);
209 ap = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
210 if (ap == NULL)
211 return (NULL);
213 if (authp->hostcertpath) {
214 ap->hostcertpath = strdup(authp->hostcertpath);
215 if (ap->hostcertpath == NULL) {
216 free(ap);
217 return (NULL);
220 if (authp->cred.unix_cred.userID) {
221 ap->cred.unix_cred.userID =
222 strdup(authp->cred.unix_cred.userID);
223 if (ap->cred.unix_cred.userID == NULL) {
224 (void) __ns_ldap_freeCred(&ap);
225 return (NULL);
228 if (authp->cred.unix_cred.passwd) {
229 ap->cred.unix_cred.passwd =
230 strdup(authp->cred.unix_cred.passwd);
231 if (ap->cred.unix_cred.passwd == NULL) {
232 (void) __ns_ldap_freeCred(&ap);
233 return (NULL);
236 if (authp->cred.cert_cred.nickname) {
237 ap->cred.cert_cred.nickname =
238 strdup(authp->cred.cert_cred.nickname);
239 if (ap->cred.cert_cred.nickname == NULL) {
240 (void) __ns_ldap_freeCred(&ap);
241 return (NULL);
244 ap->auth.type = authp->auth.type;
245 ap->auth.tlstype = authp->auth.tlstype;
246 ap->auth.saslmech = authp->auth.saslmech;
247 ap->auth.saslopt = authp->auth.saslopt;
248 return (ap);
252 * FUNCTION: __ns_ldap_freeUnixCred
254 * Frees all the memory associated with a UnixCred_t structure.
256 * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS
257 * INPUT: UnixCred
260 __ns_ldap_freeUnixCred(UnixCred_t ** credp)
262 UnixCred_t *ap;
264 #ifdef DEBUG
265 (void) fprintf(stderr, "__ns_ldap_freeUnixCred START\n");
266 #endif
267 if (credp == NULL || *credp == NULL)
268 return (NS_LDAP_INVALID_PARAM);
270 ap = *credp;
271 if (ap->userID) {
272 (void) memset(ap->userID, 0, strlen(ap->userID));
273 free(ap->userID);
276 if (ap->passwd) {
277 (void) memset(ap->passwd, 0, strlen(ap->passwd));
278 free(ap->passwd);
281 free(ap);
282 *credp = NULL;
283 return (NS_LDAP_SUCCESS);
287 * FUNCTION: __ns_ldap_freeCred
289 * Frees all the memory associated with a ns_cred_t structure.
291 * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS
292 * INPUT: ns_cred_t
295 __ns_ldap_freeCred(ns_cred_t ** credp)
297 ns_cred_t *ap;
299 #ifdef DEBUG
300 (void) fprintf(stderr, "__ns_ldap_freeCred START\n");
301 #endif
302 if (credp == NULL || *credp == NULL)
303 return (NS_LDAP_INVALID_PARAM);
305 ap = *credp;
306 if (ap->hostcertpath) {
307 (void) memset(ap->hostcertpath, 0,
308 strlen(ap->hostcertpath));
309 free(ap->hostcertpath);
312 if (ap->cred.unix_cred.userID) {
313 (void) memset(ap->cred.unix_cred.userID, 0,
314 strlen(ap->cred.unix_cred.userID));
315 free(ap->cred.unix_cred.userID);
318 if (ap->cred.unix_cred.passwd) {
319 (void) memset(ap->cred.unix_cred.passwd, 0,
320 strlen(ap->cred.unix_cred.passwd));
321 free(ap->cred.unix_cred.passwd);
324 if (ap->cred.cert_cred.nickname) {
325 (void) memset(ap->cred.cert_cred.nickname, 0,
326 strlen(ap->cred.cert_cred.nickname));
327 free(ap->cred.cert_cred.nickname);
330 free(ap);
331 *credp = NULL;
332 return (NS_LDAP_SUCCESS);
336 * FUNCTION: __s_api_is_auth_matched
338 * Compare an authentication structure.
340 * RETURN VALUES: B_TRUE if matched, B_FALSE otherwise.
341 * INPUT: auth1, auth2
343 boolean_t
344 __s_api_is_auth_matched(const ns_cred_t *auth1,
345 const ns_cred_t *auth2)
347 if ((auth1->auth.type != auth2->auth.type) ||
348 (auth1->auth.tlstype != auth2->auth.tlstype) ||
349 (auth1->auth.saslmech != auth2->auth.saslmech) ||
350 (auth1->auth.saslopt != auth2->auth.saslopt))
351 return (B_FALSE);
353 if ((((auth1->auth.type == NS_LDAP_AUTH_SASL) &&
354 ((auth1->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) ||
355 (auth1->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) ||
356 (auth1->auth.type == NS_LDAP_AUTH_SIMPLE)) &&
357 ((auth1->cred.unix_cred.userID == NULL) ||
358 (auth1->cred.unix_cred.passwd == NULL) ||
359 ((strcasecmp(auth1->cred.unix_cred.userID,
360 auth2->cred.unix_cred.userID) != 0)) ||
361 ((strcmp(auth1->cred.unix_cred.passwd,
362 auth2->cred.unix_cred.passwd) != 0))))
363 return (B_FALSE);
365 return (B_TRUE);
369 * FUNCTION: __s_api_getDNs
371 * Retrieves the default base dn for the given
372 * service.
374 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
375 * INPUT: service
376 * OUTPUT: DN, error
378 typedef int (*pf)(const char *, char **, ns_ldap_error_t **);
380 __s_api_getDNs(
381 char *** DN,
382 const char *service,
383 ns_ldap_error_t ** error)
386 void **paramVal = NULL;
387 char **dns = NULL;
388 int rc = 0;
389 int i, len;
390 pf prepend_auto2dn = __s_api_prepend_automountmapname_to_dn;
392 #ifdef DEBUG
393 (void) fprintf(stderr, "__s_api_getDNs START\n");
394 #endif
395 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
396 &paramVal, error)) != NS_LDAP_SUCCESS) {
397 return (rc);
399 if (!paramVal) {
400 char errmsg[MAXERROR];
402 (void) snprintf(errmsg, sizeof (errmsg),
403 gettext("BaseDN not defined"));
404 MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errmsg),
405 NS_LDAP_CONFIG);
406 return (NS_LDAP_CONFIG);
409 dns = (char **)calloc(2, sizeof (char *));
410 if (dns == NULL) {
411 (void) __ns_ldap_freeParam(&paramVal);
412 return (NS_LDAP_MEMORY);
415 if (service == NULL) {
416 dns[0] = strdup((char *)*paramVal);
417 if (dns[0] == NULL) {
418 (void) __ns_ldap_freeParam(&paramVal);
419 free(dns);
420 return (NS_LDAP_MEMORY);
422 } else {
423 for (i = 0; ns_def_map[i].service != NULL; i++) {
424 if (strcasecmp(service,
425 ns_def_map[i].service) == 0) {
427 len = strlen((char *)*paramVal) +
428 strlen(ns_def_map[i].rdn) + 1;
429 dns[0] = (char *)
430 calloc(len, sizeof (char));
431 if (dns[0] == NULL) {
432 (void) __ns_ldap_freeParam(
433 &paramVal);
434 free(dns);
435 return (NS_LDAP_MEMORY);
437 (void) strcpy(dns[0],
438 ns_def_map[i].rdn);
439 (void) strcat(dns[0],
440 (char *)*paramVal);
441 break;
444 if (ns_def_map[i].service == NULL) {
445 char *p = (char *)*paramVal;
446 char *buffer = NULL;
447 int buflen = 0;
449 if (strchr(service, '=') == NULL) {
450 /* automount entries */
451 if (strncasecmp(service, "auto_", 5) == 0) {
452 buffer = strdup(p);
453 if (!buffer) {
454 free(dns);
455 (void) __ns_ldap_freeParam(
456 &paramVal);
457 return (NS_LDAP_MEMORY);
459 /* shorten name to avoid cstyle error */
460 rc = prepend_auto2dn(
461 service, &buffer, error);
462 if (rc != NS_LDAP_SUCCESS) {
463 free(dns);
464 free(buffer);
465 (void) __ns_ldap_freeParam(
466 &paramVal);
467 return (rc);
469 } else {
470 /* strlen("nisMapName")+"="+","+'\0' = 13 */
471 buflen = strlen(service) + strlen(p) +
473 buffer = (char *)malloc(buflen);
474 if (buffer == NULL) {
475 free(dns);
476 (void) __ns_ldap_freeParam(
477 &paramVal);
478 return (NS_LDAP_MEMORY);
480 (void) snprintf(buffer, buflen,
481 "nisMapName=%s,%s", service, p);
483 } else {
484 buflen = strlen(service) + strlen(p) + 2;
485 buffer = (char *)malloc(buflen);
486 if (buffer == NULL) {
487 free(dns);
488 (void) __ns_ldap_freeParam(&paramVal);
489 return (NS_LDAP_MEMORY);
491 (void) snprintf(buffer, buflen,
492 "%s,%s", service, p);
494 dns[0] = buffer;
498 (void) __ns_ldap_freeParam(&paramVal);
499 *DN = dns;
500 return (NS_LDAP_SUCCESS);
503 * FUNCTION: __s_api_get_search_DNs_v1
505 * Retrieves the list of search DNS from the V1 profile for the given
506 * service.
508 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
509 * INPUT: service
510 * OUTPUT: DN, error
513 __s_api_get_search_DNs_v1(
514 char *** DN,
515 const char *service,
516 ns_ldap_error_t ** error)
519 void **paramVal = NULL;
520 void **temptr = NULL;
521 char **dns = NULL;
522 int rc = 0;
524 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_DN_P,
525 &paramVal, error)) != NS_LDAP_SUCCESS) {
526 return (rc);
529 if (service && paramVal) {
530 for (temptr = paramVal; *temptr != NULL; temptr++) {
531 dns = parseDN((const char *)(*temptr),
532 (const char *)service);
533 if (dns != NULL)
534 break;
538 (void) __ns_ldap_freeParam(&paramVal);
539 *DN = dns;
540 return (NS_LDAP_SUCCESS);
544 * FUNCTION: parseDN
546 * Parse a special formated list(val) into an array of char *.
548 * RETURN VALUE: A char * pointer to the new list of dns.
549 * INPUT: val, service
551 static char **
552 parseDN(
553 const char *val,
554 const char *service)
557 size_t len = 0;
558 size_t slen = 0;
559 char **retVal = NULL;
560 const char *temptr;
561 char *temptr2;
562 const char *valend;
563 int valNo = 0;
564 int valSize = 0;
565 int i;
566 char *SSD_service = NULL;
568 #ifdef DEBUG
569 (void) fprintf(stderr, "parseDN START\n");
570 #endif
571 if (val == NULL || *val == '\0')
572 return (NULL);
573 if (service == NULL || *service == '\0')
574 return (NULL);
576 len = strlen(val);
577 slen = strlen(service);
578 if (strncasecmp(val, service, slen) != 0) {
580 * This routine is only called
581 * to process V1 profile and
582 * for V1 profile, map service
583 * to the corresponding SSD_service
584 * which is associated with a
585 * real container in the LDAP directory
586 * tree, e.g., map "shadow" to
587 * "password". See function
588 * __s_api_get_SSD_from_SSDtoUse_service
589 * for similar service to SSD_service
590 * mapping handling for V2 profile.
592 for (i = 0; ns_def_map[i].service != NULL; i++) {
593 if (ns_def_map[i].SSDtoUse_service &&
594 strcasecmp(service,
595 ns_def_map[i].service) == 0) {
596 SSD_service =
597 ns_def_map[i].SSDtoUse_service;
598 break;
602 if (SSD_service == NULL)
603 return (NULL);
605 slen = strlen(SSD_service);
606 if (strncasecmp(val, SSD_service, slen) != 0)
607 return (NULL);
610 temptr = val + slen;
611 while (*temptr == SPACETOK || *temptr == TABTOK)
612 temptr++;
613 if (*temptr != COLONTOK)
614 return (NULL);
616 while (*temptr) {
617 temptr2 = strchr(temptr, OPARATOK);
618 if (temptr2 == NULL)
619 break;
620 temptr2++;
621 temptr2 = strchr(temptr2, CPARATOK);
622 if (temptr2 == NULL)
623 break;
624 valNo++;
625 temptr = temptr2+1;
628 retVal = (char **)calloc(valNo +1, sizeof (char *));
629 if (retVal == NULL)
630 return (NULL);
632 temptr = val;
633 valend = val+len;
635 for (i = 0; (i < valNo) && (temptr < valend); i++) {
636 temptr = strchr(temptr, OPARATOK);
637 if (temptr == NULL) {
638 __s_api_free2dArray(retVal);
639 return (NULL);
641 temptr++;
642 temptr2 = strchr(temptr, CPARATOK);
643 if (temptr2 == NULL) {
644 __s_api_free2dArray(retVal);
645 return (NULL);
647 valSize = temptr2 - temptr;
649 retVal[i] = (char *)calloc(valSize + 1, sizeof (char));
650 if (retVal[i] == NULL) {
651 __s_api_free2dArray(retVal);
652 return (NULL);
654 (void) strncpy(retVal[i], temptr, valSize);
655 retVal[i][valSize] = '\0';
656 temptr = temptr2 + 1;
659 return (retVal);
664 * __s_api_get_local_interfaces
666 * Returns a pointer to an array of addresses and netmasks of all interfaces
667 * configured on the system.
669 * NOTE: This function is very IPv4 centric.
671 static struct ifinfo *
672 __s_api_get_local_interfaces()
674 struct ifconf ifc;
675 struct ifreq ifreq, *ifr;
676 struct ifinfo *localinfo;
677 struct in_addr netmask;
678 struct sockaddr_in *sin;
679 void *buf = NULL;
680 int fd = 0;
681 int numifs = 0;
682 int i, n = 0;
684 if ((fd = open(UDP, O_RDONLY)) < 0)
685 return (NULL);
687 if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
688 numifs = MAXIFS;
691 buf = malloc(numifs * sizeof (struct ifreq));
692 if (buf == NULL) {
693 (void) close(fd);
694 return (NULL);
696 ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
697 ifc.ifc_buf = buf;
698 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
699 (void) close(fd);
700 free(buf);
701 buf = NULL;
702 return (NULL);
704 ifr = (struct ifreq *)buf;
705 numifs = ifc.ifc_len/(int)sizeof (struct ifreq);
706 localinfo = (struct ifinfo *)malloc((numifs + 1) *
707 sizeof (struct ifinfo));
708 if (localinfo == NULL) {
709 (void) close(fd);
710 free(buf);
711 buf = NULL;
712 return (NULL);
715 for (i = 0, n = numifs; n > 0; n--, ifr++) {
716 uint_t ifrflags;
718 ifreq = *ifr;
719 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0)
720 continue;
722 ifrflags = ifreq.ifr_flags;
723 if (((ifrflags & IFF_UP) == 0) ||
724 (ifr->ifr_addr.sa_family != AF_INET))
725 continue;
727 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifreq) < 0)
728 continue;
729 netmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
731 if (ioctl(fd, SIOCGIFADDR, (char *)&ifreq) < 0)
732 continue;
734 sin = (struct sockaddr_in *)&ifreq.ifr_addr;
736 localinfo[i].addr = sin->sin_addr;
737 localinfo[i].netmask = netmask;
738 i++;
740 localinfo[i].addr.s_addr = 0;
742 free(buf);
743 buf = NULL;
744 (void) close(fd);
745 return (localinfo);
750 * __s_api_samenet(char *, struct ifinfo *)
752 * Returns 1 if address is on the same subnet of the array of addresses
753 * passed in.
755 * NOTE: This function is only valid for IPv4 addresses.
757 static int
758 __s_api_IPv4sameNet(char *addr, struct ifinfo *ifs)
760 int answer = 0;
762 if (addr && ifs) {
763 char *addr_raw;
764 unsigned long iaddr;
765 int i;
767 if ((addr_raw = strdup(addr)) != NULL) {
768 char *s;
770 /* Remove port number. */
771 if ((s = strchr(addr_raw, ':')) != NULL)
772 *s = '\0';
774 iaddr = inet_addr(addr_raw);
776 /* Loop through interface list to find match. */
777 for (i = 0; ifs[i].addr.s_addr != 0; i++) {
778 if ((iaddr & ifs[i].netmask.s_addr) ==
779 (ifs[i].addr.s_addr &
780 ifs[i].netmask.s_addr))
781 answer++;
783 free(addr_raw);
787 return (answer);
791 * FUNCTION: __s_api_getServers
793 * Retrieve a list of ldap servers from the config module.
795 * RETURN VALUE: NS_LDAP_SUCCESS, NS_LDAP_CONFIG, NS_LDAP_MEMORY
796 * INPUT: NONE
797 * OUTPUT: servers, error
800 __s_api_getServers(
801 char *** servers,
802 ns_ldap_error_t ** error)
804 void **paramVal = NULL;
805 char errmsg[MAXERROR];
806 char **sortServers = NULL;
807 char **netservers = NULL;
808 int rc = 0, err = NS_LDAP_CONFIG, version = 1;
809 const char *str, *str1;
811 #ifdef DEBUG
812 (void) fprintf(stderr, "__s_api_getServers START\n");
813 #endif
814 *servers = NULL;
815 /* get profile version number */
816 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
817 &paramVal, error)) != NS_LDAP_SUCCESS)
818 return (rc);
820 if (paramVal == NULL || *paramVal == NULL) {
821 (void) snprintf(errmsg, sizeof (errmsg),
822 gettext("No file version"));
823 MKERROR(LOG_INFO, *error, NS_CONFIG_FILE, strdup(errmsg),
824 NS_LDAP_CONFIG);
825 return (NS_LDAP_CONFIG);
828 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
829 version = 1;
830 else if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_2) == 0)
831 version = 2;
833 (void) __ns_ldap_freeParam(&paramVal);
834 paramVal = NULL;
836 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVERS_P,
837 &paramVal, error)) != NS_LDAP_SUCCESS)
838 return (rc);
841 * For version 2, default server list could be
842 * empty.
844 if ((paramVal == NULL || (char *)*paramVal == NULL) &&
845 version == 1) {
846 str = NULL_OR_STR(__s_api_get_configname(NS_LDAP_SERVERS_P));
847 (void) snprintf(errmsg, sizeof (errmsg),
848 gettext("Unable to retrieve the '%s' list"), str);
849 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE, strdup(errmsg),
850 NS_LDAP_CONFIG);
851 return (NS_LDAP_CONFIG);
855 * Get server address(es) and go through them.
857 *servers = (char **)paramVal;
858 paramVal = NULL;
860 /* Sort servers based on network. */
861 if (*servers) {
862 netservers = sortServerNet(*servers);
863 if (netservers) {
864 free(*servers);
865 *servers = netservers;
866 } else {
867 return (NS_LDAP_MEMORY);
871 /* Get preferred server list and sort servers based on that. */
872 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P,
873 &paramVal, error)) != NS_LDAP_SUCCESS) {
874 if (*servers)
875 __s_api_free2dArray(*servers);
876 *servers = NULL;
877 return (rc);
880 if (paramVal != NULL) {
881 char **prefServers;
882 void **val = NULL;
884 if ((rc = __ns_ldap_getParam(NS_LDAP_PREF_ONLY_P,
885 &val, error)) != NS_LDAP_SUCCESS) {
886 if (*servers)
887 __s_api_free2dArray(*servers);
888 *servers = NULL;
889 (void) __ns_ldap_freeParam(&paramVal);
890 return (rc);
893 prefServers = (char **)paramVal;
894 paramVal = NULL;
895 if (prefServers) {
896 if (val != NULL && (*val) != NULL &&
897 *(int *)val[0] == 1)
898 sortServers = sortServerPref(*servers,
899 prefServers, B_FALSE, version,
900 &err);
901 else
902 sortServers = sortServerPref(*servers,
903 prefServers, B_TRUE, version,
904 &err);
905 if (sortServers) {
906 free(*servers);
907 *servers = NULL;
908 free(prefServers);
909 prefServers = NULL;
910 *servers = sortServers;
911 } else {
912 if (*servers)
913 __s_api_free2dArray(*servers);
914 *servers = NULL;
915 __s_api_free2dArray(prefServers);
916 prefServers = NULL;
919 (void) __ns_ldap_freeParam(&val);
921 (void) __ns_ldap_freeParam(&paramVal);
923 if (*servers == NULL) {
924 if (err == NS_LDAP_CONFIG) {
925 str = NULL_OR_STR(__s_api_get_configname(
926 NS_LDAP_SERVERS_P));
927 str1 = NULL_OR_STR(__s_api_get_configname(
928 NS_LDAP_SERVER_PREF_P));
929 (void) snprintf(errmsg, sizeof (errmsg),
930 gettext("Unable to generate a new server list "
931 "based on '%s' and/or '%s'"), str, str1);
932 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE,
933 strdup(errmsg), err);
934 return (err);
936 return (NS_LDAP_MEMORY);
939 return (NS_LDAP_SUCCESS);
944 * FUNCTION: sortServerNet
945 * Sort the serverlist based on the distance from client as long
946 * as the list only contains IPv4 addresses. Otherwise do nothing.
948 static char **
949 sortServerNet(char **srvlist)
951 int count = 0;
952 int all = 0;
953 int ipv4only = 1;
954 struct ifinfo *ifs = __s_api_get_local_interfaces();
955 char **tsrvs;
956 char **psrvs, **retsrvs;
958 /* Sanity check. */
959 if (srvlist == NULL || srvlist[0] == NULL)
960 return (NULL);
962 /* Count the number of servers to sort. */
963 for (count = 0; srvlist[count] != NULL; count++) {
964 if (!__s_api_isipv4(srvlist[count]))
965 ipv4only = 0;
967 count++;
969 /* Make room for the returned list of servers. */
970 retsrvs = (char **)calloc(count, sizeof (char *));
971 if (retsrvs == NULL) {
972 free(ifs);
973 ifs = NULL;
974 return (NULL);
977 retsrvs[count - 1] = NULL;
979 /* Make a temporary list of servers. */
980 psrvs = (char **)calloc(count, sizeof (char *));
981 if (psrvs == NULL) {
982 free(ifs);
983 ifs = NULL;
984 free(retsrvs);
985 retsrvs = NULL;
986 return (NULL);
989 /* Filter servers on the same subnet */
990 tsrvs = srvlist;
991 while (*tsrvs) {
992 if (ipv4only && __s_api_IPv4sameNet(*tsrvs, ifs)) {
993 psrvs[all] = *tsrvs;
994 retsrvs[all++] = *(tsrvs);
996 tsrvs++;
999 /* Filter remaining servers. */
1000 tsrvs = srvlist;
1001 while (*tsrvs) {
1002 char **ttsrvs = psrvs;
1004 while (*ttsrvs) {
1005 if (strcmp(*tsrvs, *ttsrvs) == 0)
1006 break;
1007 ttsrvs++;
1010 if (*ttsrvs == NULL)
1011 retsrvs[all++] = *(tsrvs);
1012 tsrvs++;
1015 free(ifs);
1016 ifs = NULL;
1017 free(psrvs);
1018 psrvs = NULL;
1020 return (retsrvs);
1024 * FUNCTION: sortServerPref
1025 * Sort the serverlist based on the preferred server list.
1027 * The sorting algorithm works as follows:
1029 * If version 1, if flag is TRUE, find all the servers in both preflist
1030 * and srvlist, then append other servers in srvlist to this list
1031 * and return the list.
1032 * If flag is FALSE, just return srvlist.
1033 * srvlist can not be empty.
1035 * If version 2, append all the servers in srvlist
1036 * but not in preflist to preflist, and return the merged list.
1037 * If srvlist is empty, just return preflist.
1038 * If preflist is empty, just return srvlist.
1040 static char **
1041 sortServerPref(char **srvlist, char **preflist,
1042 boolean_t flag, int version, int *error)
1044 int i, scount = 0, pcount = 0;
1045 int all = 0, dup = 0;
1046 char **tsrvs;
1047 char **retsrvs;
1048 char **dupsrvs;
1050 /* Count the number of servers to sort. */
1051 if (srvlist && srvlist[0])
1052 for (i = 0; srvlist[i] != NULL; i++)
1053 scount++;
1055 /* Sanity check. */
1056 if (scount == 0 && version == 1) {
1057 *error = NS_LDAP_CONFIG;
1058 return (NULL);
1061 /* Count the number of preferred servers */
1062 if (preflist && preflist[0])
1063 for (i = 0; preflist[i] != NULL; i++)
1064 pcount++;
1066 /* Sanity check. */
1067 if (scount == 0 && pcount == 0) {
1068 *error = NS_LDAP_CONFIG;
1069 return (NULL);
1072 /* Make room for the returned list of servers */
1073 retsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1074 if (retsrvs == NULL) {
1075 *error = NS_LDAP_MEMORY;
1076 return (NULL);
1080 * if the preferred server list is empty,
1081 * just return a copy of the server list
1083 if (pcount == 0) {
1084 tsrvs = srvlist;
1085 while (*tsrvs)
1086 retsrvs[all++] = *(tsrvs++);
1087 return (retsrvs);
1089 all = 0;
1092 * if the server list is empty,
1093 * just return a copy of the preferred server list
1095 if (scount == 0) {
1096 tsrvs = preflist;
1097 while (*tsrvs)
1098 retsrvs[all++] = *(tsrvs++);
1099 return (retsrvs);
1101 all = 0;
1103 /* Make room for the servers whose memory needs to be freed */
1104 dupsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1105 if (dupsrvs == NULL) {
1106 free(retsrvs);
1107 *error = NS_LDAP_MEMORY;
1108 return (NULL);
1112 * If version 1,
1113 * throw out preferred servers not on server list.
1114 * If version 2, make a copy of the preferred server list.
1116 if (version == 1) {
1117 tsrvs = preflist;
1118 while (*tsrvs) {
1119 char **ttsrvs = srvlist;
1121 while (*ttsrvs) {
1122 if (strcmp(*tsrvs, *(ttsrvs)) == 0)
1123 break;
1124 ttsrvs++;
1126 if (*ttsrvs != NULL)
1127 retsrvs[all++] = *tsrvs;
1128 else
1129 dupsrvs[dup++] = *tsrvs;
1130 tsrvs++;
1132 } else {
1133 tsrvs = preflist;
1134 while (*tsrvs)
1135 retsrvs[all++] = *(tsrvs++);
1138 * If version 1,
1139 * if PREF_ONLY is false, we append the non-preferred servers
1140 * to bottom of list.
1141 * For version 2, always append.
1143 if (flag == B_TRUE || version != 1) {
1145 tsrvs = srvlist;
1146 while (*tsrvs) {
1147 char **ttsrvs = preflist;
1149 while (*ttsrvs) {
1150 if (strcmp(*tsrvs, *ttsrvs) == 0) {
1151 break;
1153 ttsrvs++;
1155 if (*ttsrvs == NULL)
1156 retsrvs[all++] = *tsrvs;
1157 else
1158 dupsrvs[dup++] = *tsrvs;
1159 tsrvs++;
1163 /* free memory for duplicate servers */
1164 if (dup) {
1165 for (tsrvs = dupsrvs; *tsrvs; tsrvs++)
1166 free(*tsrvs);
1168 free(dupsrvs);
1170 return (retsrvs);
1174 * FUNCTION: __s_api_removeBadServers
1175 * Contacts the ldap cache manager for marking the
1176 * problem servers as down, so that the server is
1177 * not contacted until the TTL expires.
1179 void
1180 __s_api_removeBadServers(char ** Servers)
1183 char **host;
1185 if (Servers == NULL)
1186 return;
1188 for (host = Servers; *host != NULL; host++) {
1189 if (__s_api_removeServer(*host) < 0) {
1191 * Couldn't remove server from
1192 * server list. Log a warning.
1194 syslog(LOG_WARNING, "libsldap: could "
1195 "not remove %s from servers list", *host);
1201 * FUNCTION: __s_api_free2dArray
1203 void
1204 __s_api_free2dArray(char ** inarray)
1207 char **temptr;
1209 if (inarray == NULL)
1210 return;
1212 for (temptr = inarray; *temptr != NULL; temptr++) {
1213 free(*temptr);
1215 free(inarray);
1219 * FUNCTION: __s_api_cp2dArray
1221 char **
1222 __s_api_cp2dArray(char **inarray)
1224 char **newarray;
1225 char **ttarray, *ret;
1226 int count;
1228 if (inarray == NULL)
1229 return (NULL);
1231 for (count = 0; inarray[count] != NULL; count++)
1234 newarray = (char **)calloc(count + 1, sizeof (char *));
1235 if (newarray == NULL)
1236 return (NULL);
1238 ttarray = newarray;
1239 for (; *inarray; inarray++) {
1240 *(ttarray++) = ret = strdup(*inarray);
1241 if (ret == NULL) {
1242 __s_api_free2dArray(newarray);
1243 return (NULL);
1246 return (newarray);
1250 * FUNCTION: __s_api_isCtrlSupported
1251 * Determines if the passed control is supported by the LDAP sever.
1252 * RETURNS: NS_LDAP_SUCCESS if yes, NS_LDAP_OP_FAIL if not.
1255 __s_api_isCtrlSupported(Connection *con, char *ctrlString)
1257 char **ctrl;
1258 int len;
1260 len = strlen(ctrlString);
1261 for (ctrl = con->controls; ctrl && *ctrl; ctrl++) {
1262 if (strncasecmp(*ctrl, ctrlString, len) == 0)
1263 return (NS_LDAP_SUCCESS);
1265 return (NS_LDAP_OP_FAILED);
1269 * FUNCTION: __s_api_toFollowReferrals
1270 * Determines if need to follow referral for an SLDAP API.
1271 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_INVALID_PARAM, or
1272 * other rc from __ns_ldap_getParam()
1273 * INPUT: flags
1274 * OUTPUT: toFollow, errorp
1277 __s_api_toFollowReferrals(const int flags,
1278 int *toFollow,
1279 ns_ldap_error_t **errorp)
1281 void **paramVal = NULL;
1282 int rc = 0;
1283 int iflags = 0;
1285 #ifdef DEBUG
1286 (void) fprintf(stderr, "__s_api_toFollowReferrals START\n");
1287 #endif
1289 /* Either NS_LDAP_NOREF or NS_LDAP_FOLLOWREF not both */
1290 if ((flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) ==
1291 (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1292 return (NS_LDAP_INVALID_PARAM);
1296 * if the NS_LDAP_NOREF or NS_LDAP_FOLLOWREF is set
1297 * this will take precendence over the values specified
1298 * in the configuration file
1300 if (flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1301 iflags = flags;
1302 } else {
1303 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_REF_P,
1304 &paramVal, errorp);
1305 if (rc != NS_LDAP_SUCCESS)
1306 return (rc);
1307 if (paramVal == NULL || *paramVal == NULL) {
1308 (void) __ns_ldap_freeParam(&paramVal);
1309 if (*errorp)
1310 (void) __ns_ldap_freeError(errorp);
1311 *toFollow = TRUE;
1312 return (NS_LDAP_SUCCESS);
1314 iflags = (* (int *)(*paramVal));
1315 (void) __ns_ldap_freeParam(&paramVal);
1318 if (iflags & NS_LDAP_NOREF)
1319 *toFollow = FALSE;
1320 else
1321 *toFollow = TRUE;
1323 return (NS_LDAP_SUCCESS);
1327 * FUNCTION: __s_api_addRefInfo
1328 * Insert a referral info into a referral info list.
1329 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_OP_FAILED
1330 * INPUT: LDAP URL, pointer to the referral info list,
1331 * search baseDN, search scope, search filter,
1332 * previous connection
1335 __s_api_addRefInfo(ns_referral_info_t **head, char *url,
1336 char *baseDN, int *scope,
1337 char *filter, LDAP *ld)
1339 char errmsg[MAXERROR], *tmp;
1340 ns_referral_info_t *ref, *tmpref;
1341 LDAPURLDesc *ludp = NULL;
1342 int hostlen;
1343 char *ld_defhost = NULL;
1345 #ifdef DEBUG
1346 (void) fprintf(stderr, "__s_api_addRefInfo START\n");
1347 #endif
1349 /* sanity check */
1350 if (head == NULL)
1351 return (NS_LDAP_OP_FAILED);
1354 * log error and return NS_LDAP_SUCCESS
1355 * if one of the following:
1356 * 1. non-LDAP URL
1357 * 2. LDAP URL which can not be parsed
1359 if (!ldap_is_ldap_url(url) ||
1360 ldap_url_parse_nodn(url, &ludp) != 0) {
1361 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1362 gettext("Invalid or non-LDAP URL when"
1363 " processing referrals URL"),
1364 url);
1365 syslog(LOG_ERR, "libsldap: %s", errmsg);
1366 if (ludp)
1367 ldap_free_urldesc(ludp);
1368 return (NS_LDAP_SUCCESS);
1371 ref = (ns_referral_info_t *)calloc(1,
1372 sizeof (ns_referral_info_t));
1373 if (ref == NULL) {
1374 ldap_free_urldesc(ludp);
1375 return (NS_LDAP_MEMORY);
1379 * we do have a valid URL and we were able to parse it
1380 * however, we still need to find out what hostport to
1381 * use if none were provided in the LDAP URL
1382 * (e.g., ldap:///...)
1384 if ((ludp->lud_port == 0) && (ludp->lud_host == NULL)) {
1385 if (ld == NULL) {
1386 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1387 gettext("no LDAP handle when"
1388 " processing referrals URL"),
1389 url);
1390 syslog(LOG_WARNING, "libsldap: %s", errmsg);
1391 ldap_free_urldesc(ludp);
1392 free(ref);
1393 return (NS_LDAP_SUCCESS);
1394 } else {
1395 (void) ldap_get_option(ld, LDAP_OPT_HOST_NAME,
1396 &ld_defhost);
1397 if (ld_defhost == NULL) {
1398 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1399 gettext("not able to retrieve default "
1400 "host when processing "
1401 "referrals URL"),
1402 url);
1403 syslog(LOG_WARNING, "libsldap: %s", errmsg);
1404 ldap_free_urldesc(ludp);
1405 free(ref);
1406 return (NS_LDAP_SUCCESS);
1407 } else {
1408 ref->refHost = strdup(ld_defhost);
1409 if (ref->refHost == NULL) {
1410 ldap_free_urldesc(ludp);
1411 free(ref);
1412 return (NS_LDAP_MEMORY);
1416 } else {
1418 * add 4 here:
1419 * 1 for the last '\0'.
1420 * 1 for host and prot separator ":"
1421 * and "[" & "]" for possible ipV6 addressing
1423 hostlen = strlen(ludp->lud_host) +
1424 sizeof (MAXPORTNUMBER_STR) + 4;
1425 ref->refHost = (char *)malloc(hostlen);
1426 if (ref->refHost == NULL) {
1427 ldap_free_urldesc(ludp);
1428 free(ref);
1429 return (NS_LDAP_MEMORY);
1432 if (ludp->lud_port != 0) {
1434 * serverAddr = host:port
1435 * or
1436 * if host is an IPV6 address
1437 * [host]:port
1439 tmp = strstr(url, ludp->lud_host);
1440 if (tmp && (tmp > url) && *(tmp - 1) == '[') {
1441 (void) snprintf(ref->refHost, hostlen,
1442 "[%s]:%d",
1443 ludp->lud_host,
1444 ludp->lud_port);
1445 } else {
1446 (void) snprintf(ref->refHost, hostlen,
1447 "%s:%d",
1448 ludp->lud_host,
1449 ludp->lud_port);
1451 } else {
1452 /* serverAddr = host */
1453 (void) snprintf(ref->refHost, hostlen, "%s",
1454 ludp->lud_host);
1458 if (ludp->lud_dn) {
1459 ref->refDN = strdup(ludp->lud_dn);
1460 if (ref->refDN == NULL) {
1461 ldap_free_urldesc(ludp);
1462 free(ref->refHost);
1463 free(ref);
1464 return (NS_LDAP_MEMORY);
1466 } else {
1467 if (baseDN) {
1468 ref->refDN = strdup(baseDN);
1469 if (ref->refDN == NULL) {
1470 ldap_free_urldesc(ludp);
1471 free(ref->refHost);
1472 free(ref);
1473 return (NS_LDAP_MEMORY);
1478 if (filter)
1479 ref->refFilter = strdup(filter);
1480 else if (ludp->lud_filter)
1481 ref->refFilter = strdup(ludp->lud_filter);
1482 else
1483 ref->refFilter = strdup("");
1485 if (ref->refFilter == NULL) {
1486 ldap_free_urldesc(ludp);
1487 free(ref->refHost);
1488 free(ref->refDN);
1489 free(ref);
1490 return (NS_LDAP_MEMORY);
1494 * If the scope is specified in the URL use it.
1495 * Note if the scope is missing in the URL, ldap_url_parse_nodn()
1496 * returns the scope BASE. We need to check that the scope of BASE
1497 * is actually present in the URL.
1498 * If the scope is missing in the URL then use the passed-in
1499 * scope.
1500 * If there is no passed-in scope, then use the scope SUBTREE.
1502 if (ludp->lud_dn && ludp->lud_scope != LDAP_SCOPE_BASE)
1503 ref->refScope = ludp->lud_scope;
1504 else if (ludp->lud_dn && strstr(url, "?base"))
1505 ref->refScope = LDAP_SCOPE_BASE;
1506 else if (scope)
1507 ref->refScope = *scope;
1508 else
1509 ref->refScope = LDAP_SCOPE_SUBTREE;
1511 ref->next = NULL;
1513 ldap_free_urldesc(ludp);
1515 /* insert the referral info */
1516 if (*head) {
1517 for (tmpref = *head; tmpref->next; tmpref = tmpref->next)
1519 tmpref->next = ref;
1520 } else
1521 *head = ref;
1523 return (NS_LDAP_SUCCESS);
1527 * FUNCTION: __s_api_deleteRefInfo
1528 * Delete a referral info list.
1529 * INPUT: pointer to the referral info list
1531 void
1532 __s_api_deleteRefInfo(ns_referral_info_t *head)
1534 ns_referral_info_t *ref, *tmp;
1536 #ifdef DEBUG
1537 (void) fprintf(stderr, "__s_api_deleteRefInfo START\n");
1538 #endif
1540 for (ref = head; ref; ) {
1541 free(ref->refHost);
1542 free(ref->refDN);
1543 free(ref->refFilter);
1544 tmp = ref->next;
1545 free(ref);
1546 ref = tmp;
1552 * FUNCTION: __s_api_get_SSD_from_SSDtoUse_service
1554 * Retrieves the Service Search Descriptors which should be used for
1555 * the given service. For example, return all the "passwd" SSDs for
1556 * service "shadow" if no SSD is defined for service "shadow" and
1557 * no filter component is defined in all the "passwd" SSDs. This idea
1558 * of sharing the SSDs defined for some other service is to reduce the
1559 * configuration complexity. For a service, which does not have its own
1560 * entries in the LDAP directory, SSD for it is useless, and should not
1561 * be set. But since this service must share the container with at least
1562 * one other service which does have it own entries, the SSD for
1563 * this other service will be shared by this service.
1564 * This other service is called the SSD-to-use service.
1565 * The static data structure, ns_def_map[], in this file
1566 * defines the SSD-to-use service for all the services supported.
1568 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_INVALID_PARAM
1569 * INPUT: service
1570 * OUTPUT: *SSDlist, *errorp if error
1573 __s_api_get_SSD_from_SSDtoUse_service(const char *service,
1574 ns_ldap_search_desc_t ***SSDlist,
1575 ns_ldap_error_t **errorp)
1577 int i, rc;
1578 int found = FALSE;
1579 int filter_found = FALSE;
1580 char *SSD_service = NULL;
1581 char errmsg[MAXERROR];
1582 ns_ldap_search_desc_t **sdlist;
1583 int auto_service = FALSE;
1585 #ifdef DEBUG
1586 (void) fprintf(stderr,
1587 "__s_api_get_SSD_from_SSDtoUse_service START\n");
1588 #endif
1590 if (SSDlist == NULL || errorp == NULL)
1591 return (NS_LDAP_INVALID_PARAM);
1593 *SSDlist = NULL;
1594 *errorp = NULL;
1596 if (service == NULL)
1597 return (NS_LDAP_SUCCESS);
1599 if (strncasecmp(service, "auto_", 5) == 0)
1600 auto_service = TRUE;
1603 * First try to return the configured SSDs for the input server
1605 rc = __ns_ldap_getSearchDescriptors(service, SSDlist, errorp);
1606 if (rc != NS_LDAP_SUCCESS)
1607 return (rc);
1608 else {
1609 if (*SSDlist != NULL)
1610 return (NS_LDAP_SUCCESS);
1614 * If service == auto_* and SSD is not found,
1615 * then try automount to see if there is an SSD
1616 * for automount.
1619 if (auto_service) {
1620 rc = __ns_ldap_getSearchDescriptors(
1621 "automount", SSDlist, errorp);
1622 if (rc != NS_LDAP_SUCCESS)
1623 return (rc);
1624 else {
1625 if (*SSDlist != NULL) {
1627 * If SSDlist is found,
1628 * prepend automountMapName to the basedn
1629 * in the SSDlist
1632 rc = __s_api_prepend_automountmapname(
1633 service,
1634 SSDlist,
1635 errorp);
1637 if (rc != NS_LDAP_SUCCESS) {
1638 (void) __ns_ldap_freeSearchDescriptors(
1639 SSDlist);
1640 *SSDlist = NULL;
1643 return (rc);
1649 * Find the SSDtoUse service.
1650 * If none found, flag "found" remains FALSE.
1652 for (i = 0; ns_def_map[i].service != NULL; i++) {
1653 if (ns_def_map[i].SSDtoUse_service &&
1654 strcasecmp(service,
1655 ns_def_map[i].service) == 0) {
1656 found = TRUE;
1657 SSD_service = ns_def_map[i].SSDtoUse_service;
1658 break;
1662 if (!found)
1663 return (NS_LDAP_SUCCESS);
1666 * return the SSDs for SSD_service only if no optional filter
1667 * component is defined in the SSDs
1669 rc = __ns_ldap_getSearchDescriptors(SSD_service,
1670 SSDlist, errorp);
1671 if (rc != NS_LDAP_SUCCESS) {
1672 return (rc);
1673 } else {
1674 if (*SSDlist == NULL)
1675 return (NS_LDAP_SUCCESS);
1677 /* check to see if filter defined in SSD */
1678 for (sdlist = *SSDlist; *sdlist; sdlist++) {
1679 if ((*sdlist)->filter &&
1680 strlen((*sdlist)->filter) > 0) {
1681 filter_found = TRUE;
1682 break;
1685 if (filter_found) {
1686 (void) __ns_ldap_freeSearchDescriptors(SSDlist);
1687 *SSDlist = NULL;
1688 (void) snprintf(errmsg, sizeof (errmsg),
1689 gettext("Service search descriptor for "
1690 "service '%s' contains filter, "
1691 "which can not be used for "
1692 "service '%s'."),
1693 SSD_service, service);
1694 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE,
1695 strdup(errmsg), NS_LDAP_CONFIG);
1696 return (NS_LDAP_CONFIG);
1700 return (NS_LDAP_SUCCESS);
1705 * verify addr is an IPv4 address with the optional [:portno]
1706 * RFC2373 & RFC2732 & RFC2396
1709 __s_api_isipv4(char *addr)
1711 int i, seg, digit, port;
1713 if (!addr)
1714 return (0);
1716 digit = seg = port = 0;
1718 for (i = 0; i < strlen(addr); i++) {
1719 if (isdigit(addr[i])) {
1720 digit++;
1721 continue;
1723 if (addr[i] == '.') {
1724 if (digit > 3 || digit == 0)
1725 return (0);
1726 digit = 0;
1727 seg++;
1728 continue;
1730 if (addr[i] == ':') {
1731 if (digit > 3)
1732 return (0);
1733 port++;
1734 digit = 0;
1735 seg++;
1736 continue;
1738 return (0);
1741 if ((seg == 3 && port == 0 && digit > 0 && digit < 4) ||
1742 (seg == 4 && port == 1 && digit > 0))
1743 return (1);
1745 return (0);
1750 * verify addr is an IPv6 address with the optional [IPv6]:portno
1751 * RFC2373 & RFC2732 & RFC2396
1754 __s_api_isipv6(char *addr)
1756 int i, col, digit, port, dc, tc;
1757 char *laddr, *c1, *s;
1759 if (!addr)
1760 return (0);
1762 s = addr;
1763 laddr = NULL;
1764 digit = col = port = 0;
1765 if (addr[0] == '[') {
1766 laddr = strdup(addr);
1767 if (!laddr)
1768 return (0);
1769 c1 = strchr(laddr, ']');
1770 /* only 1 ']' should be in an addr */
1771 if (!c1 || (strchr(c1+1, ']')))
1772 goto bad;
1773 switch (c1[1]) {
1774 case ':':
1775 port++;
1776 for (i = 2; i < strlen(c1); i++) {
1777 if (!isdigit(c1[i]))
1778 goto bad;
1779 digit++;
1781 if (!digit)
1782 goto bad;
1783 c1[0] = '\0';
1784 break;
1785 case '\0':
1786 c1[0] = '\0';
1787 break;
1788 default:
1789 goto bad;
1791 s = &laddr[1];
1794 digit = dc = tc = 0;
1795 for (i = 0; i < strlen(s); i++) {
1796 if (isxdigit(s[i])) {
1797 if (digit == 0)
1798 dc = i;
1799 digit++;
1800 col = 0;
1801 continue;
1803 if (s[i] == ':') {
1804 tc++;
1805 if ((col > 1) || (i && !col && !digit))
1806 goto bad;
1807 digit = 0;
1808 col++;
1809 continue;
1811 if (s[i] == '.') {
1812 if (__s_api_isipv4(&s[dc]) && tc)
1813 goto good;
1814 else
1815 goto bad;
1817 goto bad;
1820 good:
1821 free(laddr);
1822 return (1);
1823 bad:
1824 free(laddr);
1825 return (0);
1830 * verify addr is a valid hostname with the optional [:portno]
1831 * RFC2373 & RFC2732 & RFC2396
1834 __s_api_ishost(char *addr)
1836 int i, seg, alpha, digit, port;
1838 if (!addr)
1839 return (0);
1841 alpha = digit = seg = port = 0;
1843 /* must start with alpha character */
1844 if (!isalpha(addr[0]))
1845 return (0);
1847 for (i = 0; i < strlen(addr); i++) {
1848 if (isalpha(addr[i]) || (i && addr[i] == '-')) {
1849 alpha++;
1850 continue;
1852 if (isdigit(addr[i])) {
1853 digit++;
1854 continue;
1856 if (addr[i] == '.') {
1857 if (!alpha && !digit)
1858 return (0);
1859 alpha = digit = 0;
1860 seg++;
1861 continue;
1863 if (addr[i] == ':') {
1864 if (!alpha && !digit)
1865 return (0);
1866 alpha = digit = 0;
1867 port++;
1868 seg++;
1869 continue;
1871 return (0);
1874 if ((port == 0 && (seg || alpha || digit)) ||
1875 (port == 1 && alpha == 0 && digit))
1876 return (1);
1878 return (0);
1883 * Prepend automountMapName=auto_xxx to the basedn
1884 * in the SSDlist
1887 int __s_api_prepend_automountmapname(
1888 const char *service,
1889 ns_ldap_search_desc_t ***SSDlist,
1890 ns_ldap_error_t **errorp)
1892 int i, rc;
1893 ns_ldap_search_desc_t ** ssdlist = NULL;
1895 if (service == NULL || SSDlist == NULL || *SSDlist == NULL)
1896 return (NS_LDAP_INVALID_PARAM);
1898 ssdlist = *SSDlist;
1900 for (i = 0; ssdlist[i] != NULL; i++) {
1901 rc = __s_api_prepend_automountmapname_to_dn(
1902 service, &ssdlist[i]->basedn, errorp);
1904 if (rc != NS_LDAP_SUCCESS)
1905 return (rc);
1908 return (NS_LDAP_SUCCESS);
1913 * Prepend automountMapName=auto_xxx to the DN
1914 * Construct a string of
1915 * "automountMapName=auto_xxx,dn"
1917 * If automountMapName is mapped to some other attribute,
1918 * then use the mapping in the setup.
1920 * If a version 1 profile is in use, use nisMapName for
1921 * backward compatibility (i.e. "nisMapName=auto_xxx,dn").
1925 __s_api_prepend_automountmapname_to_dn(
1926 const char *service,
1927 char **dn,
1928 ns_ldap_error_t **errorp)
1930 int rc, len_s = 0, len_d = 0, len = 0;
1931 char *buffer = NULL;
1932 char *default_automountmapname = "automountMapName";
1933 char *automountmapname = NULL;
1934 char **mappedattrs = NULL;
1935 char errstr[MAXERROR];
1936 void **paramVal = NULL;
1938 if (service == NULL || dn == NULL || *dn == NULL)
1939 return (NS_LDAP_INVALID_PARAM);
1941 rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
1942 if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
1943 if (paramVal)
1944 (void) __ns_ldap_freeParam(&paramVal);
1945 return (rc);
1947 if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) {
1948 automountmapname = strdup("nisMapName");
1949 (void) __ns_ldap_freeParam(&paramVal);
1950 if (automountmapname == NULL) {
1951 return (NS_LDAP_MEMORY);
1953 } else {
1954 (void) __ns_ldap_freeParam(&paramVal);
1956 /* Find mapped attribute name of auto_xxx first */
1957 mappedattrs = __ns_ldap_getMappedAttributes(
1958 service, default_automountmapname);
1960 * if mapped attribute name of auto_xxx is not found,
1961 * find the mapped attribute name of automount
1964 if (mappedattrs == NULL)
1965 mappedattrs = __ns_ldap_getMappedAttributes(
1966 "automount", default_automountmapname);
1969 * if mapped attr is not found, use the default automountmapname
1972 if (mappedattrs == NULL) {
1973 automountmapname = strdup(default_automountmapname);
1974 if (automountmapname == NULL)
1975 return (NS_LDAP_MEMORY);
1976 } else {
1977 if (mappedattrs[0] != NULL) {
1979 * Copy it from the mapped attr list
1980 * Assume it's 1 to 1 mapping
1981 * 1 to n does not make sense
1983 automountmapname = strdup(mappedattrs[0]);
1984 __s_api_free2dArray(mappedattrs);
1985 if (automountmapname == NULL) {
1986 return (NS_LDAP_MEMORY);
1988 } else {
1991 * automountmapname is mapped to an empty string
1994 __s_api_free2dArray(mappedattrs);
1996 (void) sprintf(errstr,
1997 gettext(
1998 "Attribute automountMapName is "
1999 "mapped to an empty string.\n"));
2001 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
2002 strdup(errstr), NS_LDAP_MEMORY);
2004 return (NS_LDAP_CONFIG);
2009 len_s = strlen(service);
2010 len_d = strlen(*dn);
2011 /* automountMapName + "=" + service + "," + dn + '\0' */
2012 len = strlen(automountmapname) + 1 + len_s + 1 + len_d + 1;
2013 buffer = (char *)malloc(len);
2014 if (buffer == NULL) {
2015 free(automountmapname);
2016 return (NS_LDAP_MEMORY);
2019 (void) snprintf(buffer, len, "%s=%s,%s",
2020 automountmapname, service, *dn);
2022 buffer[len-1] = '\0';
2024 free(automountmapname);
2026 /* free the original dn */
2027 (void) free(*dn);
2029 *dn = buffer;
2031 return (NS_LDAP_SUCCESS);
2035 * Map the LDAP error code and error message from LDAP server
2036 * to a password status used for password aging/management.
2038 ns_ldap_passwd_status_t
2039 __s_api_set_passwd_status(int errnum, char *errmsg)
2041 syslog(LOG_DEBUG, "libsldap: got LDAP errnum %d & message: %s ", errnum,
2042 (errmsg != NULL) ? errmsg : "error msg not available");
2043 if (errmsg) {
2044 if (errnum ==
2045 LDAP_INVALID_CREDENTIALS) {
2047 * case 1 (Bind):
2048 * password expired
2050 if (strstr(errmsg,
2051 NS_PWDERR_EXPIRED))
2052 return (NS_PASSWD_EXPIRED);
2055 if (errnum ==
2056 LDAP_UNWILLING_TO_PERFORM) {
2058 * case 1.1 (Bind):
2059 * password expired
2061 if (strstr(errmsg,
2062 NS_PWDERR_EXPIRED))
2063 return (NS_PASSWD_EXPIRED);
2066 * case 2 (Bind):
2067 * Account inactivated
2069 if (strstr(errmsg,
2070 NS_PWDERR_ACCT_INACTIVATED))
2071 return (NS_PASSWD_EXPIRED);
2075 * case 3 (Modify passwd):
2076 * the user is not allow to change
2077 * password; only admin can change it
2079 if (strstr(errmsg,
2080 NS_PWDERR_CHANGE_NOT_ALLOW))
2081 return (NS_PASSWD_CHANGE_NOT_ALLOWED);
2084 if (errnum ==
2085 LDAP_CONSTRAINT_VIOLATION) {
2087 * case 4 (Bind):
2088 * the user account is locked due to
2089 * too many login failures.
2091 if (strstr(errmsg,
2092 NS_PWDERR_MAXTRIES))
2093 return (NS_PASSWD_RETRY_EXCEEDED);
2095 * case 5 (Modify passwd):
2096 * syntax error: the new password
2097 * has length less than defined
2098 * minimum
2099 * Not true anymore with strong password
2100 * policies on LDAP server: errmsg that
2101 * contain NS_PWDERR_INVALID_SYNTAX may
2102 * have different meanings.
2103 * To keep compatibility with older password
2104 * policy, check if errmsg is strictly equal
2105 * to NS_PWDERR_INVALID_SYNTAX and if yes only,
2106 * return NS_PASSWD_TOO_SHORT.
2108 if (strcmp(errmsg,
2109 NS_PWDERR_INVALID_SYNTAX) == 0)
2110 return (NS_PASSWD_TOO_SHORT);
2111 if (strstr(errmsg,
2112 NS_PWDERR_INVALID_SYNTAX))
2113 return (NS_PASSWD_INVALID_SYNTAX);
2115 * case 6 (Modify passwd):
2116 * trivial password: same value as
2117 * that of attribute cn, sn, or uid ...
2119 if (strstr(errmsg,
2120 NS_PWDERR_TRIVIAL_PASSWD))
2121 return (NS_PASSWD_INVALID_SYNTAX);
2123 * case 7 (Modify passwd):
2124 * re-use one of the old passwords
2125 * in history list
2127 if (strstr(errmsg,
2128 NS_PWDERR_IN_HISTORY))
2129 return (NS_PASSWD_IN_HISTORY);
2131 * case 8 (Modify passwd):
2132 * password not allowed to be
2133 * changed yet; within minimum
2134 * age
2136 if (strstr(errmsg,
2137 NS_PWDERR_WITHIN_MIN_AGE))
2138 return (NS_PASSWD_WITHIN_MIN_AGE);
2143 return (NS_PASSWD_GOOD);
2147 * Determine if the input OID list contains
2148 * one of the password control OIDs, which are:
2149 * LDAP_CONTROL_PWEXPIRED: 2.16.840.1.113730.3.4.4
2150 * LDAP_CONTROL_PWEXPIRING: 2.16.840.1.113730.3.4.5.
2151 * If yes, return 1, if no, 0.
2154 __s_api_contain_passwd_control_oid(char **oids)
2156 char **oid;
2158 if (oids == NULL)
2159 return (0);
2161 for (oid = oids; *oid; oid++) {
2162 if (strcmp(*oid, LDAP_CONTROL_PWEXPIRED) == 0 ||
2163 strcmp(*oid, LDAP_CONTROL_PWEXPIRING) == 0) {
2164 return (1);
2168 return (0);
2172 * Determine if the input OID list contains LDAP V3 password less
2173 * account management control OID, which is:
2174 * NS_LDAP_ACCOUNT_USABLE_CONTROL:1.3.6.1.4.1.42.2.27.9.5.8
2175 * If yes, return 1, if no, 0.
2178 __s_api_contain_account_usable_control_oid(char **oids)
2180 char **oid;
2182 if (oids == NULL)
2183 return (0);
2185 for (oid = oids; *oid; oid++) {
2186 if (strcmp(*oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) == 0) {
2187 return (1);
2191 return (0);
2195 * For some databases in name switch, the name and aliases are saved
2196 * as "cn". When the "cn" valuse are retrieved, there is no distinction
2197 * which is the name and which is(are) aliase(s).
2198 * This function is to parse RDN and find the value of the "cn" and
2199 * then find the matching value in "cn" attribute.
2200 * Also see RFC 2307 section 5.6.
2202 * Input -
2203 * entry: An LDAP entry
2204 * attrptr: A attribute which value appears in RDN
2205 * This should be "cn" for the name switch for now.
2206 * case_ignore: 0 Case sensitive comparison on the attribute value
2207 * 1 Case insensitive comparison
2209 * Return -
2210 * The value of an attrbute which is used as canonical name
2211 * This is read only and the caller should not try to free it.
2212 * If it's a NULL, it could be either an RDN parsing error
2213 * or RDN value does not match any existing "cn" values.
2214 * e.g.
2215 * dn: cn=xx+ipserviceprotocol=udp,......
2216 * cn: aa
2217 * cn: bb
2219 * Note:
2220 * Although the name switch/ldap's rdn is in "cn=xx" or "cn=xx+..."
2221 * format, this function makes no such assumption. If the DN
2222 * is saved as "dn: yy=...+sn=my_canocical_name, ..", then it can still work.
2223 * The comments use "cn" as an example only.
2226 typedef int (*cmpfunc)(const char *, const char *);
2228 char *
2229 __s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr,
2230 int case_ignore) {
2231 uint_t i;
2232 char *token, *lasts, *value = NULL;
2233 char **rdn = NULL, **attrs = NULL, **values = NULL;
2234 char *rdn_attr_value = NULL;
2235 cmpfunc cmp;
2237 if (entry == NULL || attrptr == NULL)
2238 return (NULL);
2240 /* "values" is read-only */
2241 if ((values = __ns_ldap_getAttr(entry, "dn")) == NULL ||
2242 values[0] == NULL)
2243 return (NULL);
2245 if ((rdn = ldap_explode_dn(values[0], 0)) == NULL ||
2246 rdn[0] == NULL)
2247 return (NULL);
2249 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) {
2250 ldap_value_free(rdn);
2251 return (NULL);
2253 /* Assume the rdn is normalized */
2254 for (i = 0; attrs[i] != NULL; i++) {
2255 /* parse attribute name and value, get attribute name first */
2256 if ((token = strtok_r(attrs[i], "=", &lasts)) == NULL) {
2257 goto cleanup;
2259 if (strcasecmp(token, attrptr->attrname) == 0) {
2260 /* get value */
2261 rdn_attr_value = lasts;
2262 break;
2265 if (rdn_attr_value) {
2266 if (case_ignore)
2267 cmp = strcasecmp;
2268 else
2269 cmp = strcmp;
2271 * After parsing RDN and find the matching attribute in RDN,
2272 * match rdn value with values in "cn".
2274 for (i = 0; i < attrptr->value_count; i++) {
2275 if (attrptr->attrvalue[i] &&
2276 (*cmp)(rdn_attr_value,
2277 attrptr->attrvalue[i]) == 0) {
2278 /* RDN "cn" value matches the "cn" value */
2279 value = attrptr->attrvalue[i];
2280 break;
2284 cleanup:
2285 ldap_value_free(rdn);
2286 ldap_value_free(attrs);
2288 return (value);
2292 * This function requests a server to be removed from
2293 * the cache manager maintained server list. This is
2294 * done via the door functionality.
2295 * Returns 0 if OK, else a negative value.
2299 __s_api_removeServer(const char *server)
2301 union {
2302 ldap_data_t s_d;
2303 char s_b[DOORBUFFERSIZE];
2304 } space;
2306 ns_server_info_t r, *ret = &r;
2307 const char *ireq;
2308 ldap_data_t *sptr;
2309 int ndata;
2310 int adata;
2311 int len;
2312 int rc;
2313 ns_ldap_error_t *error = NULL;
2315 if (server == NULL)
2316 return (-1);
2318 ireq = NS_CACHE_NORESP;
2320 if (__s_api_isStandalone()) {
2322 * Remove 'server' from the standalone server list.
2323 * __s_api_findRootDSE() is the standalone version
2324 * of getldap_get_serverInfo() used in ldap_cachemgr.
2325 * Request NS_CACHE_NORESP indicates 'server' should
2326 * be removed.
2328 if (__s_api_findRootDSE(ireq,
2329 server,
2330 NS_CACHE_ADDR_IP,
2331 NULL,
2332 &error) != NS_LDAP_SUCCESS) {
2333 syslog(LOG_WARNING,
2334 "libsldap (\"standalone\" mode): "
2335 " Unable to remove %s - %s",
2336 server,
2337 error != NULL && error->message != NULL ?
2338 error->message : " no error info");
2339 if (error != NULL) {
2340 (void) __ns_ldap_freeError(&error);
2343 return (NS_CACHE_NOSERVER);
2346 return (0);
2349 (void) memset(ret, 0, sizeof (ns_server_info_t));
2350 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2352 adata = (sizeof (ldap_call_t) + strlen(ireq) +
2353 strlen(NS_CACHE_ADDR_IP) + 1);
2354 adata += strlen(DOORLINESEP) + 1;
2355 adata += strlen(server) + 1;
2357 ndata = sizeof (space);
2358 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2359 len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2360 if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
2361 return (-1);
2362 if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
2363 NS_CACHE_ADDR_IP, len) >= len)
2364 return (-1);
2365 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len) >=
2366 len)
2367 return (-1);
2368 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len) >= len)
2369 return (-1);
2370 sptr = &space.s_d;
2372 /* try to remove the server via the door interface */
2373 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2375 /* clean up the door call */
2376 if (sptr != &space.s_d) {
2377 (void) munmap((char *)sptr, ndata);
2380 return (rc);
2383 void
2384 __s_api_free_server_info(ns_server_info_t *sinfo) {
2385 if (sinfo->server) {
2386 free(sinfo->server);
2387 sinfo->server = NULL;
2389 if (sinfo->serverFQDN) {
2390 free(sinfo->serverFQDN);
2391 sinfo->serverFQDN = NULL;
2393 __s_api_free2dArray(sinfo->saslMechanisms);
2394 sinfo->saslMechanisms = NULL;
2395 __s_api_free2dArray(sinfo->controls);
2396 sinfo->controls = NULL;
2400 * Create an ns_ldap_error structure, set status to 'rc',
2401 * and copy in the error message 'msg'.
2403 ns_ldap_error_t *
2404 __s_api_make_error(int rc, char *msg) {
2405 ns_ldap_error_t *ep;
2407 ep = (ns_ldap_error_t *)calloc(1, sizeof (*ep));
2408 if (ep == NULL)
2409 return (NULL);
2411 ep->status = rc;
2412 if (msg != NULL)
2413 ep->message = strdup(msg); /* OK if ep->message is NULL */
2415 return (ep);
2419 * Make a copy of the input ns_ldap_error.
2421 ns_ldap_error_t *
2422 __s_api_copy_error(ns_ldap_error_t *errorp) {
2423 ns_ldap_error_t *ep;
2424 char *msg;
2426 if (errorp == NULL)
2427 return (NULL);
2429 ep = (ns_ldap_error_t *)malloc(sizeof (*ep));
2430 if (ep != NULL) {
2431 *ep = *errorp;
2432 if (ep->message != NULL) {
2433 msg = strdup(ep->message);
2434 if (msg == NULL) {
2435 free(ep);
2436 ep = NULL;
2437 } else
2438 ep->message = msg;
2441 return (ep);