8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libsldap / common / ns_common.c
blobcd5de8d25778c8c9fd250115cec4e5514f8dbe2f
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 { "tnrhtp", "ou=ipTnet,", NULL },
83 { "tnrhdb", "ou=ipTnet,", "tnrhtp" },
84 { NULL, NULL, NULL }
88 static char ** parseDN(const char *val, const char *service);
89 static char ** sortServerNet(char **srvlist);
90 static char ** sortServerPref(char **srvlist, char **preflist,
91 boolean_t flag, int version, int *error);
94 * FUNCTION: s_api_printResult
95 * Given a ns_ldap_result structure print it.
97 int
98 __s_api_printResult(ns_ldap_result_t *result)
101 ns_ldap_entry_t *curEntry;
102 int i, j, k = 0;
104 #ifdef DEBUG
105 (void) fprintf(stderr, "__s_api_printResult START\n");
106 #endif
107 (void) printf("--------------------------------------\n");
108 if (result == NULL) {
109 (void) printf("No result\n");
110 return (0);
112 (void) printf("entries_count %d\n", result->entries_count);
113 curEntry = result->entry;
114 for (i = 0; i < result->entries_count; i++) {
116 (void) printf("entry %d has attr_count = %d \n", i,
117 curEntry->attr_count);
118 for (j = 0; j < curEntry->attr_count; j++) {
119 (void) printf("entry %d has attr_pair[%d] = %s \n",
120 i, j, curEntry->attr_pair[j]->attrname);
121 for (k = 0; k < 20 &&
122 curEntry->attr_pair[j]->attrvalue[k]; k++)
123 (void) printf("entry %d has attr_pair[%d]->"
124 "attrvalue[%d] = %s \n", i, j, k,
125 curEntry->attr_pair[j]->attrvalue[k]);
127 (void) printf("\n--------------------------------------\n");
128 curEntry = curEntry->next;
130 return (1);
134 * FUNCTION: __s_api_getSearchScope
136 * Retrieve the search scope for ldap search from the config module.
138 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_CONFIG
139 * INPUT: NONE
140 * OUTPUT: searchScope, errorp
143 __s_api_getSearchScope(
144 int *searchScope,
145 ns_ldap_error_t **errorp)
148 char errmsg[MAXERROR];
149 void **paramVal = NULL;
150 int rc = 0;
151 int scope = 0;
153 #ifdef DEBUG
154 (void) fprintf(stderr, "__s_api_getSearchScope START\n");
155 #endif
156 if (*searchScope == 0) {
157 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
158 &paramVal, errorp)) != NS_LDAP_SUCCESS) {
159 return (rc);
161 if (paramVal && *paramVal)
162 scope = * (int *)(*paramVal);
163 else
164 scope = NS_LDAP_SCOPE_ONELEVEL;
165 (void) __ns_ldap_freeParam(&paramVal);
166 } else {
167 scope = *searchScope;
170 switch (scope) {
172 case NS_LDAP_SCOPE_ONELEVEL:
173 *searchScope = LDAP_SCOPE_ONELEVEL;
174 break;
175 case NS_LDAP_SCOPE_BASE:
176 *searchScope = LDAP_SCOPE_BASE;
177 break;
178 case NS_LDAP_SCOPE_SUBTREE:
179 *searchScope = LDAP_SCOPE_SUBTREE;
180 break;
181 default:
182 (void) snprintf(errmsg, sizeof (errmsg),
183 gettext("Invalid search scope!"));
184 MKERROR(LOG_ERR, *errorp, NS_CONFIG_FILE,
185 strdup(errmsg), NS_LDAP_CONFIG);
186 return (NS_LDAP_CONFIG);
189 return (NS_LDAP_SUCCESS);
193 * FUNCTION: __ns_ldap_dupAuth
195 * Duplicates an authentication structure.
197 * RETURN VALUES: copy of authp or NULL on error
198 * INPUT: authp
200 ns_cred_t *
201 __ns_ldap_dupAuth(const ns_cred_t *authp)
203 ns_cred_t *ap;
205 #ifdef DEBUG
206 (void) fprintf(stderr, "__ns_ldap_dupAuth START\n");
207 #endif
208 if (authp == NULL)
209 return (NULL);
211 ap = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
212 if (ap == NULL)
213 return (NULL);
215 if (authp->hostcertpath) {
216 ap->hostcertpath = strdup(authp->hostcertpath);
217 if (ap->hostcertpath == NULL) {
218 free(ap);
219 return (NULL);
222 if (authp->cred.unix_cred.userID) {
223 ap->cred.unix_cred.userID =
224 strdup(authp->cred.unix_cred.userID);
225 if (ap->cred.unix_cred.userID == NULL) {
226 (void) __ns_ldap_freeCred(&ap);
227 return (NULL);
230 if (authp->cred.unix_cred.passwd) {
231 ap->cred.unix_cred.passwd =
232 strdup(authp->cred.unix_cred.passwd);
233 if (ap->cred.unix_cred.passwd == NULL) {
234 (void) __ns_ldap_freeCred(&ap);
235 return (NULL);
238 if (authp->cred.cert_cred.nickname) {
239 ap->cred.cert_cred.nickname =
240 strdup(authp->cred.cert_cred.nickname);
241 if (ap->cred.cert_cred.nickname == NULL) {
242 (void) __ns_ldap_freeCred(&ap);
243 return (NULL);
246 ap->auth.type = authp->auth.type;
247 ap->auth.tlstype = authp->auth.tlstype;
248 ap->auth.saslmech = authp->auth.saslmech;
249 ap->auth.saslopt = authp->auth.saslopt;
250 return (ap);
254 * FUNCTION: __ns_ldap_freeUnixCred
256 * Frees all the memory associated with a UnixCred_t structure.
258 * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS
259 * INPUT: UnixCred
262 __ns_ldap_freeUnixCred(UnixCred_t ** credp)
264 UnixCred_t *ap;
266 #ifdef DEBUG
267 (void) fprintf(stderr, "__ns_ldap_freeUnixCred START\n");
268 #endif
269 if (credp == NULL || *credp == NULL)
270 return (NS_LDAP_INVALID_PARAM);
272 ap = *credp;
273 if (ap->userID) {
274 (void) memset(ap->userID, 0, strlen(ap->userID));
275 free(ap->userID);
278 if (ap->passwd) {
279 (void) memset(ap->passwd, 0, strlen(ap->passwd));
280 free(ap->passwd);
283 free(ap);
284 *credp = NULL;
285 return (NS_LDAP_SUCCESS);
289 * FUNCTION: __ns_ldap_freeCred
291 * Frees all the memory associated with a ns_cred_t structure.
293 * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS
294 * INPUT: ns_cred_t
297 __ns_ldap_freeCred(ns_cred_t ** credp)
299 ns_cred_t *ap;
301 #ifdef DEBUG
302 (void) fprintf(stderr, "__ns_ldap_freeCred START\n");
303 #endif
304 if (credp == NULL || *credp == NULL)
305 return (NS_LDAP_INVALID_PARAM);
307 ap = *credp;
308 if (ap->hostcertpath) {
309 (void) memset(ap->hostcertpath, 0,
310 strlen(ap->hostcertpath));
311 free(ap->hostcertpath);
314 if (ap->cred.unix_cred.userID) {
315 (void) memset(ap->cred.unix_cred.userID, 0,
316 strlen(ap->cred.unix_cred.userID));
317 free(ap->cred.unix_cred.userID);
320 if (ap->cred.unix_cred.passwd) {
321 (void) memset(ap->cred.unix_cred.passwd, 0,
322 strlen(ap->cred.unix_cred.passwd));
323 free(ap->cred.unix_cred.passwd);
326 if (ap->cred.cert_cred.nickname) {
327 (void) memset(ap->cred.cert_cred.nickname, 0,
328 strlen(ap->cred.cert_cred.nickname));
329 free(ap->cred.cert_cred.nickname);
332 free(ap);
333 *credp = NULL;
334 return (NS_LDAP_SUCCESS);
338 * FUNCTION: __s_api_is_auth_matched
340 * Compare an authentication structure.
342 * RETURN VALUES: B_TRUE if matched, B_FALSE otherwise.
343 * INPUT: auth1, auth2
345 boolean_t
346 __s_api_is_auth_matched(const ns_cred_t *auth1,
347 const ns_cred_t *auth2)
349 if ((auth1->auth.type != auth2->auth.type) ||
350 (auth1->auth.tlstype != auth2->auth.tlstype) ||
351 (auth1->auth.saslmech != auth2->auth.saslmech) ||
352 (auth1->auth.saslopt != auth2->auth.saslopt))
353 return (B_FALSE);
355 if ((((auth1->auth.type == NS_LDAP_AUTH_SASL) &&
356 ((auth1->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) ||
357 (auth1->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) ||
358 (auth1->auth.type == NS_LDAP_AUTH_SIMPLE)) &&
359 ((auth1->cred.unix_cred.userID == NULL) ||
360 (auth1->cred.unix_cred.passwd == NULL) ||
361 ((strcasecmp(auth1->cred.unix_cred.userID,
362 auth2->cred.unix_cred.userID) != 0)) ||
363 ((strcmp(auth1->cred.unix_cred.passwd,
364 auth2->cred.unix_cred.passwd) != 0))))
365 return (B_FALSE);
367 return (B_TRUE);
371 * FUNCTION: __s_api_getDNs
373 * Retrieves the default base dn for the given
374 * service.
376 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
377 * INPUT: service
378 * OUTPUT: DN, error
380 typedef int (*pf)(const char *, char **, ns_ldap_error_t **);
382 __s_api_getDNs(
383 char *** DN,
384 const char *service,
385 ns_ldap_error_t ** error)
388 void **paramVal = NULL;
389 char **dns = NULL;
390 int rc = 0;
391 int i, len;
392 pf prepend_auto2dn = __s_api_prepend_automountmapname_to_dn;
394 #ifdef DEBUG
395 (void) fprintf(stderr, "__s_api_getDNs START\n");
396 #endif
397 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
398 &paramVal, error)) != NS_LDAP_SUCCESS) {
399 return (rc);
401 if (!paramVal) {
402 char errmsg[MAXERROR];
404 (void) snprintf(errmsg, sizeof (errmsg),
405 gettext("BaseDN not defined"));
406 MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errmsg),
407 NS_LDAP_CONFIG);
408 return (NS_LDAP_CONFIG);
411 dns = (char **)calloc(2, sizeof (char *));
412 if (dns == NULL) {
413 (void) __ns_ldap_freeParam(&paramVal);
414 return (NS_LDAP_MEMORY);
417 if (service == NULL) {
418 dns[0] = strdup((char *)*paramVal);
419 if (dns[0] == NULL) {
420 (void) __ns_ldap_freeParam(&paramVal);
421 free(dns);
422 return (NS_LDAP_MEMORY);
424 } else {
425 for (i = 0; ns_def_map[i].service != NULL; i++) {
426 if (strcasecmp(service,
427 ns_def_map[i].service) == 0) {
429 len = strlen((char *)*paramVal) +
430 strlen(ns_def_map[i].rdn) + 1;
431 dns[0] = (char *)
432 calloc(len, sizeof (char));
433 if (dns[0] == NULL) {
434 (void) __ns_ldap_freeParam(
435 &paramVal);
436 free(dns);
437 return (NS_LDAP_MEMORY);
439 (void) strcpy(dns[0],
440 ns_def_map[i].rdn);
441 (void) strcat(dns[0],
442 (char *)*paramVal);
443 break;
446 if (ns_def_map[i].service == NULL) {
447 char *p = (char *)*paramVal;
448 char *buffer = NULL;
449 int buflen = 0;
451 if (strchr(service, '=') == NULL) {
452 /* automount entries */
453 if (strncasecmp(service, "auto_", 5) == 0) {
454 buffer = strdup(p);
455 if (!buffer) {
456 free(dns);
457 (void) __ns_ldap_freeParam(
458 &paramVal);
459 return (NS_LDAP_MEMORY);
461 /* shorten name to avoid cstyle error */
462 rc = prepend_auto2dn(
463 service, &buffer, error);
464 if (rc != NS_LDAP_SUCCESS) {
465 free(dns);
466 free(buffer);
467 (void) __ns_ldap_freeParam(
468 &paramVal);
469 return (rc);
471 } else {
472 /* strlen("nisMapName")+"="+","+'\0' = 13 */
473 buflen = strlen(service) + strlen(p) +
475 buffer = (char *)malloc(buflen);
476 if (buffer == NULL) {
477 free(dns);
478 (void) __ns_ldap_freeParam(
479 &paramVal);
480 return (NS_LDAP_MEMORY);
482 (void) snprintf(buffer, buflen,
483 "nisMapName=%s,%s", service, p);
485 } else {
486 buflen = strlen(service) + strlen(p) + 2;
487 buffer = (char *)malloc(buflen);
488 if (buffer == NULL) {
489 free(dns);
490 (void) __ns_ldap_freeParam(&paramVal);
491 return (NS_LDAP_MEMORY);
493 (void) snprintf(buffer, buflen,
494 "%s,%s", service, p);
496 dns[0] = buffer;
500 (void) __ns_ldap_freeParam(&paramVal);
501 *DN = dns;
502 return (NS_LDAP_SUCCESS);
505 * FUNCTION: __s_api_get_search_DNs_v1
507 * Retrieves the list of search DNS from the V1 profile for the given
508 * service.
510 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
511 * INPUT: service
512 * OUTPUT: DN, error
515 __s_api_get_search_DNs_v1(
516 char *** DN,
517 const char *service,
518 ns_ldap_error_t ** error)
521 void **paramVal = NULL;
522 void **temptr = NULL;
523 char **dns = NULL;
524 int rc = 0;
526 if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_DN_P,
527 &paramVal, error)) != NS_LDAP_SUCCESS) {
528 return (rc);
531 if (service && paramVal) {
532 for (temptr = paramVal; *temptr != NULL; temptr++) {
533 dns = parseDN((const char *)(*temptr),
534 (const char *)service);
535 if (dns != NULL)
536 break;
540 (void) __ns_ldap_freeParam(&paramVal);
541 *DN = dns;
542 return (NS_LDAP_SUCCESS);
546 * FUNCTION: parseDN
548 * Parse a special formated list(val) into an array of char *.
550 * RETURN VALUE: A char * pointer to the new list of dns.
551 * INPUT: val, service
553 static char **
554 parseDN(
555 const char *val,
556 const char *service)
559 size_t len = 0;
560 size_t slen = 0;
561 char **retVal = NULL;
562 const char *temptr;
563 char *temptr2;
564 const char *valend;
565 int valNo = 0;
566 int valSize = 0;
567 int i;
568 char *SSD_service = NULL;
570 #ifdef DEBUG
571 (void) fprintf(stderr, "parseDN START\n");
572 #endif
573 if (val == NULL || *val == '\0')
574 return (NULL);
575 if (service == NULL || *service == '\0')
576 return (NULL);
578 len = strlen(val);
579 slen = strlen(service);
580 if (strncasecmp(val, service, slen) != 0) {
582 * This routine is only called
583 * to process V1 profile and
584 * for V1 profile, map service
585 * to the corresponding SSD_service
586 * which is associated with a
587 * real container in the LDAP directory
588 * tree, e.g., map "shadow" to
589 * "password". See function
590 * __s_api_get_SSD_from_SSDtoUse_service
591 * for similar service to SSD_service
592 * mapping handling for V2 profile.
594 for (i = 0; ns_def_map[i].service != NULL; i++) {
595 if (ns_def_map[i].SSDtoUse_service &&
596 strcasecmp(service,
597 ns_def_map[i].service) == 0) {
598 SSD_service =
599 ns_def_map[i].SSDtoUse_service;
600 break;
604 if (SSD_service == NULL)
605 return (NULL);
607 slen = strlen(SSD_service);
608 if (strncasecmp(val, SSD_service, slen) != 0)
609 return (NULL);
612 temptr = val + slen;
613 while (*temptr == SPACETOK || *temptr == TABTOK)
614 temptr++;
615 if (*temptr != COLONTOK)
616 return (NULL);
618 while (*temptr) {
619 temptr2 = strchr(temptr, OPARATOK);
620 if (temptr2 == NULL)
621 break;
622 temptr2++;
623 temptr2 = strchr(temptr2, CPARATOK);
624 if (temptr2 == NULL)
625 break;
626 valNo++;
627 temptr = temptr2+1;
630 retVal = (char **)calloc(valNo +1, sizeof (char *));
631 if (retVal == NULL)
632 return (NULL);
634 temptr = val;
635 valend = val+len;
637 for (i = 0; (i < valNo) && (temptr < valend); i++) {
638 temptr = strchr(temptr, OPARATOK);
639 if (temptr == NULL) {
640 __s_api_free2dArray(retVal);
641 return (NULL);
643 temptr++;
644 temptr2 = strchr(temptr, CPARATOK);
645 if (temptr2 == NULL) {
646 __s_api_free2dArray(retVal);
647 return (NULL);
649 valSize = temptr2 - temptr;
651 retVal[i] = (char *)calloc(valSize + 1, sizeof (char));
652 if (retVal[i] == NULL) {
653 __s_api_free2dArray(retVal);
654 return (NULL);
656 (void) strncpy(retVal[i], temptr, valSize);
657 retVal[i][valSize] = '\0';
658 temptr = temptr2 + 1;
661 return (retVal);
666 * __s_api_get_local_interfaces
668 * Returns a pointer to an array of addresses and netmasks of all interfaces
669 * configured on the system.
671 * NOTE: This function is very IPv4 centric.
673 static struct ifinfo *
674 __s_api_get_local_interfaces()
676 struct ifconf ifc;
677 struct ifreq ifreq, *ifr;
678 struct ifinfo *localinfo;
679 struct in_addr netmask;
680 struct sockaddr_in *sin;
681 void *buf = NULL;
682 int fd = 0;
683 int numifs = 0;
684 int i, n = 0;
686 if ((fd = open(UDP, O_RDONLY)) < 0)
687 return ((struct ifinfo *)NULL);
689 if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
690 numifs = MAXIFS;
693 buf = malloc(numifs * sizeof (struct ifreq));
694 if (buf == NULL) {
695 (void) close(fd);
696 return ((struct ifinfo *)NULL);
698 ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
699 ifc.ifc_buf = buf;
700 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
701 (void) close(fd);
702 free(buf);
703 buf = NULL;
704 return ((struct ifinfo *)NULL);
706 ifr = (struct ifreq *)buf;
707 numifs = ifc.ifc_len/(int)sizeof (struct ifreq);
708 localinfo = (struct ifinfo *)malloc((numifs + 1) *
709 sizeof (struct ifinfo));
710 if (localinfo == NULL) {
711 (void) close(fd);
712 free(buf);
713 buf = NULL;
714 return ((struct ifinfo *)NULL);
717 for (i = 0, n = numifs; n > 0; n--, ifr++) {
718 uint_t ifrflags;
720 ifreq = *ifr;
721 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0)
722 continue;
724 ifrflags = ifreq.ifr_flags;
725 if (((ifrflags & IFF_UP) == 0) ||
726 (ifr->ifr_addr.sa_family != AF_INET))
727 continue;
729 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifreq) < 0)
730 continue;
731 netmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
733 if (ioctl(fd, SIOCGIFADDR, (char *)&ifreq) < 0)
734 continue;
736 sin = (struct sockaddr_in *)&ifreq.ifr_addr;
738 localinfo[i].addr = sin->sin_addr;
739 localinfo[i].netmask = netmask;
740 i++;
742 localinfo[i].addr.s_addr = 0;
744 free(buf);
745 buf = NULL;
746 (void) close(fd);
747 return (localinfo);
752 * __s_api_samenet(char *, struct ifinfo *)
754 * Returns 1 if address is on the same subnet of the array of addresses
755 * passed in.
757 * NOTE: This function is only valid for IPv4 addresses.
759 static int
760 __s_api_IPv4sameNet(char *addr, struct ifinfo *ifs)
762 int answer = 0;
764 if (addr && ifs) {
765 char *addr_raw;
766 unsigned long iaddr;
767 int i;
769 if ((addr_raw = strdup(addr)) != NULL) {
770 char *s;
772 /* Remove port number. */
773 if ((s = strchr(addr_raw, ':')) != NULL)
774 *s = '\0';
776 iaddr = inet_addr(addr_raw);
778 /* Loop through interface list to find match. */
779 for (i = 0; ifs[i].addr.s_addr != 0; i++) {
780 if ((iaddr & ifs[i].netmask.s_addr) ==
781 (ifs[i].addr.s_addr &
782 ifs[i].netmask.s_addr))
783 answer++;
785 free(addr_raw);
789 return (answer);
793 * FUNCTION: __s_api_getServers
795 * Retrieve a list of ldap servers from the config module.
797 * RETURN VALUE: NS_LDAP_SUCCESS, NS_LDAP_CONFIG, NS_LDAP_MEMORY
798 * INPUT: NONE
799 * OUTPUT: servers, error
802 __s_api_getServers(
803 char *** servers,
804 ns_ldap_error_t ** error)
806 void **paramVal = NULL;
807 char errmsg[MAXERROR];
808 char **sortServers = NULL;
809 char **netservers = NULL;
810 int rc = 0, err = NS_LDAP_CONFIG, version = 1;
811 const char *str, *str1;
813 #ifdef DEBUG
814 (void) fprintf(stderr, "__s_api_getServers START\n");
815 #endif
816 *servers = NULL;
817 /* get profile version number */
818 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
819 &paramVal, error)) != NS_LDAP_SUCCESS)
820 return (rc);
822 if (paramVal == NULL || *paramVal == NULL) {
823 (void) snprintf(errmsg, sizeof (errmsg),
824 gettext("No file version"));
825 MKERROR(LOG_INFO, *error, NS_CONFIG_FILE, strdup(errmsg),
826 NS_LDAP_CONFIG);
827 return (NS_LDAP_CONFIG);
830 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
831 version = 1;
832 else if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_2) == 0)
833 version = 2;
835 (void) __ns_ldap_freeParam(&paramVal);
836 paramVal = NULL;
838 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVERS_P,
839 &paramVal, error)) != NS_LDAP_SUCCESS)
840 return (rc);
843 * For version 2, default server list could be
844 * empty.
846 if ((paramVal == NULL || (char *)*paramVal == NULL) &&
847 version == 1) {
848 str = NULL_OR_STR(__s_api_get_configname(NS_LDAP_SERVERS_P));
849 (void) snprintf(errmsg, sizeof (errmsg),
850 gettext("Unable to retrieve the '%s' list"), str);
851 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE, strdup(errmsg),
852 NS_LDAP_CONFIG);
853 return (NS_LDAP_CONFIG);
857 * Get server address(es) and go through them.
859 *servers = (char **)paramVal;
860 paramVal = NULL;
862 /* Sort servers based on network. */
863 if (*servers) {
864 netservers = sortServerNet(*servers);
865 if (netservers) {
866 free(*servers);
867 *servers = netservers;
868 } else {
869 return (NS_LDAP_MEMORY);
873 /* Get preferred server list and sort servers based on that. */
874 if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P,
875 &paramVal, error)) != NS_LDAP_SUCCESS) {
876 if (*servers)
877 __s_api_free2dArray(*servers);
878 *servers = NULL;
879 return (rc);
882 if (paramVal != NULL) {
883 char **prefServers;
884 void **val = NULL;
886 if ((rc = __ns_ldap_getParam(NS_LDAP_PREF_ONLY_P,
887 &val, error)) != NS_LDAP_SUCCESS) {
888 if (*servers)
889 __s_api_free2dArray(*servers);
890 *servers = NULL;
891 (void) __ns_ldap_freeParam(&paramVal);
892 return (rc);
895 prefServers = (char **)paramVal;
896 paramVal = NULL;
897 if (prefServers) {
898 if (val != NULL && (*val) != NULL &&
899 *(int *)val[0] == 1)
900 sortServers = sortServerPref(*servers,
901 prefServers, B_FALSE, version,
902 &err);
903 else
904 sortServers = sortServerPref(*servers,
905 prefServers, B_TRUE, version,
906 &err);
907 if (sortServers) {
908 if (*servers)
909 free(*servers);
910 *servers = NULL;
911 free(prefServers);
912 prefServers = NULL;
913 *servers = sortServers;
914 } else {
915 if (*servers)
916 __s_api_free2dArray(*servers);
917 *servers = NULL;
918 __s_api_free2dArray(prefServers);
919 prefServers = NULL;
922 (void) __ns_ldap_freeParam(&val);
924 (void) __ns_ldap_freeParam(&paramVal);
926 if (*servers == NULL) {
927 if (err == NS_LDAP_CONFIG) {
928 str = NULL_OR_STR(__s_api_get_configname(
929 NS_LDAP_SERVERS_P));
930 str1 = NULL_OR_STR(__s_api_get_configname(
931 NS_LDAP_SERVER_PREF_P));
932 (void) snprintf(errmsg, sizeof (errmsg),
933 gettext("Unable to generate a new server list "
934 "based on '%s' and/or '%s'"), str, str1);
935 MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE,
936 strdup(errmsg), err);
937 return (err);
939 return (NS_LDAP_MEMORY);
942 return (NS_LDAP_SUCCESS);
947 * FUNCTION: sortServerNet
948 * Sort the serverlist based on the distance from client as long
949 * as the list only contains IPv4 addresses. Otherwise do nothing.
951 static char **
952 sortServerNet(char **srvlist)
954 int count = 0;
955 int all = 0;
956 int ipv4only = 1;
957 struct ifinfo *ifs = __s_api_get_local_interfaces();
958 char **tsrvs;
959 char **psrvs, **retsrvs;
961 /* Sanity check. */
962 if (srvlist == NULL || srvlist[0] == NULL)
963 return (NULL);
965 /* Count the number of servers to sort. */
966 for (count = 0; srvlist[count] != NULL; count++) {
967 if (!__s_api_isipv4(srvlist[count]))
968 ipv4only = 0;
970 count++;
972 /* Make room for the returned list of servers. */
973 retsrvs = (char **)calloc(count, sizeof (char *));
974 if (retsrvs == NULL) {
975 free(ifs);
976 ifs = NULL;
977 return (NULL);
980 retsrvs[count - 1] = NULL;
982 /* Make a temporary list of servers. */
983 psrvs = (char **)calloc(count, sizeof (char *));
984 if (psrvs == NULL) {
985 free(ifs);
986 ifs = NULL;
987 free(retsrvs);
988 retsrvs = NULL;
989 return (NULL);
992 /* Filter servers on the same subnet */
993 tsrvs = srvlist;
994 while (*tsrvs) {
995 if (ipv4only && __s_api_IPv4sameNet(*tsrvs, ifs)) {
996 psrvs[all] = *tsrvs;
997 retsrvs[all++] = *(tsrvs);
999 tsrvs++;
1002 /* Filter remaining servers. */
1003 tsrvs = srvlist;
1004 while (*tsrvs) {
1005 char **ttsrvs = psrvs;
1007 while (*ttsrvs) {
1008 if (strcmp(*tsrvs, *ttsrvs) == 0)
1009 break;
1010 ttsrvs++;
1013 if (*ttsrvs == NULL)
1014 retsrvs[all++] = *(tsrvs);
1015 tsrvs++;
1018 free(ifs);
1019 ifs = NULL;
1020 free(psrvs);
1021 psrvs = NULL;
1023 return (retsrvs);
1027 * FUNCTION: sortServerPref
1028 * Sort the serverlist based on the preferred server list.
1030 * The sorting algorithm works as follows:
1032 * If version 1, if flag is TRUE, find all the servers in both preflist
1033 * and srvlist, then append other servers in srvlist to this list
1034 * and return the list.
1035 * If flag is FALSE, just return srvlist.
1036 * srvlist can not be empty.
1038 * If version 2, append all the servers in srvlist
1039 * but not in preflist to preflist, and return the merged list.
1040 * If srvlist is empty, just return preflist.
1041 * If preflist is empty, just return srvlist.
1043 static char **
1044 sortServerPref(char **srvlist, char **preflist,
1045 boolean_t flag, int version, int *error)
1047 int i, scount = 0, pcount = 0;
1048 int all = 0, dup = 0;
1049 char **tsrvs;
1050 char **retsrvs;
1051 char **dupsrvs;
1053 /* Count the number of servers to sort. */
1054 if (srvlist && srvlist[0])
1055 for (i = 0; srvlist[i] != NULL; i++)
1056 scount++;
1058 /* Sanity check. */
1059 if (scount == 0 && version == 1) {
1060 *error = NS_LDAP_CONFIG;
1061 return (NULL);
1064 /* Count the number of preferred servers */
1065 if (preflist && preflist[0])
1066 for (i = 0; preflist[i] != NULL; i++)
1067 pcount++;
1069 /* Sanity check. */
1070 if (scount == 0 && pcount == 0) {
1071 *error = NS_LDAP_CONFIG;
1072 return (NULL);
1075 /* Make room for the returned list of servers */
1076 retsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1077 if (retsrvs == NULL) {
1078 *error = NS_LDAP_MEMORY;
1079 return (NULL);
1083 * if the preferred server list is empty,
1084 * just return a copy of the server list
1086 if (pcount == 0) {
1087 tsrvs = srvlist;
1088 while (*tsrvs)
1089 retsrvs[all++] = *(tsrvs++);
1090 return (retsrvs);
1092 all = 0;
1095 * if the server list is empty,
1096 * just return a copy of the preferred server list
1098 if (scount == 0) {
1099 tsrvs = preflist;
1100 while (*tsrvs)
1101 retsrvs[all++] = *(tsrvs++);
1102 return (retsrvs);
1104 all = 0;
1106 /* Make room for the servers whose memory needs to be freed */
1107 dupsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1108 if (dupsrvs == NULL) {
1109 free(retsrvs);
1110 *error = NS_LDAP_MEMORY;
1111 return (NULL);
1115 * If version 1,
1116 * throw out preferred servers not on server list.
1117 * If version 2, make a copy of the preferred server list.
1119 if (version == 1) {
1120 tsrvs = preflist;
1121 while (*tsrvs) {
1122 char **ttsrvs = srvlist;
1124 while (*ttsrvs) {
1125 if (strcmp(*tsrvs, *(ttsrvs)) == 0)
1126 break;
1127 ttsrvs++;
1129 if (*ttsrvs != NULL)
1130 retsrvs[all++] = *tsrvs;
1131 else
1132 dupsrvs[dup++] = *tsrvs;
1133 tsrvs++;
1135 } else {
1136 tsrvs = preflist;
1137 while (*tsrvs)
1138 retsrvs[all++] = *(tsrvs++);
1141 * If version 1,
1142 * if PREF_ONLY is false, we append the non-preferred servers
1143 * to bottom of list.
1144 * For version 2, always append.
1146 if (flag == B_TRUE || version != 1) {
1148 tsrvs = srvlist;
1149 while (*tsrvs) {
1150 char **ttsrvs = preflist;
1152 while (*ttsrvs) {
1153 if (strcmp(*tsrvs, *ttsrvs) == 0) {
1154 break;
1156 ttsrvs++;
1158 if (*ttsrvs == NULL)
1159 retsrvs[all++] = *tsrvs;
1160 else
1161 dupsrvs[dup++] = *tsrvs;
1162 tsrvs++;
1166 /* free memory for duplicate servers */
1167 if (dup) {
1168 for (tsrvs = dupsrvs; *tsrvs; tsrvs++)
1169 free(*tsrvs);
1171 free(dupsrvs);
1173 return (retsrvs);
1177 * FUNCTION: __s_api_removeBadServers
1178 * Contacts the ldap cache manager for marking the
1179 * problem servers as down, so that the server is
1180 * not contacted until the TTL expires.
1182 void
1183 __s_api_removeBadServers(char ** Servers)
1186 char **host;
1188 if (Servers == NULL)
1189 return;
1191 for (host = Servers; *host != NULL; host++) {
1192 if (__s_api_removeServer(*host) < 0) {
1194 * Couldn't remove server from
1195 * server list. Log a warning.
1197 syslog(LOG_WARNING, "libsldap: could "
1198 "not remove %s from servers list", *host);
1204 * FUNCTION: __s_api_free2dArray
1206 void
1207 __s_api_free2dArray(char ** inarray)
1210 char **temptr;
1212 if (inarray == NULL)
1213 return;
1215 for (temptr = inarray; *temptr != NULL; temptr++) {
1216 free(*temptr);
1218 free(inarray);
1222 * FUNCTION: __s_api_cp2dArray
1224 char **
1225 __s_api_cp2dArray(char **inarray)
1227 char **newarray;
1228 char **ttarray, *ret;
1229 int count;
1231 if (inarray == NULL)
1232 return (NULL);
1234 for (count = 0; inarray[count] != NULL; count++)
1237 newarray = (char **)calloc(count + 1, sizeof (char *));
1238 if (newarray == NULL)
1239 return (NULL);
1241 ttarray = newarray;
1242 for (; *inarray; inarray++) {
1243 *(ttarray++) = ret = strdup(*inarray);
1244 if (ret == NULL) {
1245 __s_api_free2dArray(newarray);
1246 return (NULL);
1249 return (newarray);
1253 * FUNCTION: __s_api_isCtrlSupported
1254 * Determines if the passed control is supported by the LDAP sever.
1255 * RETURNS: NS_LDAP_SUCCESS if yes, NS_LDAP_OP_FAIL if not.
1258 __s_api_isCtrlSupported(Connection *con, char *ctrlString)
1260 char **ctrl;
1261 int len;
1263 len = strlen(ctrlString);
1264 for (ctrl = con->controls; ctrl && *ctrl; ctrl++) {
1265 if (strncasecmp(*ctrl, ctrlString, len) == 0)
1266 return (NS_LDAP_SUCCESS);
1268 return (NS_LDAP_OP_FAILED);
1272 * FUNCTION: __s_api_toFollowReferrals
1273 * Determines if need to follow referral for an SLDAP API.
1274 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_INVALID_PARAM, or
1275 * other rc from __ns_ldap_getParam()
1276 * INPUT: flags
1277 * OUTPUT: toFollow, errorp
1280 __s_api_toFollowReferrals(const int flags,
1281 int *toFollow,
1282 ns_ldap_error_t **errorp)
1284 void **paramVal = NULL;
1285 int rc = 0;
1286 int iflags = 0;
1288 #ifdef DEBUG
1289 (void) fprintf(stderr, "__s_api_toFollowReferrals START\n");
1290 #endif
1292 /* Either NS_LDAP_NOREF or NS_LDAP_FOLLOWREF not both */
1293 if ((flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) ==
1294 (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1295 return (NS_LDAP_INVALID_PARAM);
1299 * if the NS_LDAP_NOREF or NS_LDAP_FOLLOWREF is set
1300 * this will take precendence over the values specified
1301 * in the configuration file
1303 if (flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1304 iflags = flags;
1305 } else {
1306 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_REF_P,
1307 &paramVal, errorp);
1308 if (rc != NS_LDAP_SUCCESS)
1309 return (rc);
1310 if (paramVal == NULL || *paramVal == NULL) {
1311 (void) __ns_ldap_freeParam(&paramVal);
1312 if (*errorp)
1313 (void) __ns_ldap_freeError(errorp);
1314 *toFollow = TRUE;
1315 return (NS_LDAP_SUCCESS);
1317 iflags = (* (int *)(*paramVal));
1318 (void) __ns_ldap_freeParam(&paramVal);
1321 if (iflags & NS_LDAP_NOREF)
1322 *toFollow = FALSE;
1323 else
1324 *toFollow = TRUE;
1326 return (NS_LDAP_SUCCESS);
1330 * FUNCTION: __s_api_addRefInfo
1331 * Insert a referral info into a referral info list.
1332 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_OP_FAILED
1333 * INPUT: LDAP URL, pointer to the referral info list,
1334 * search baseDN, search scope, search filter,
1335 * previous connection
1338 __s_api_addRefInfo(ns_referral_info_t **head, char *url,
1339 char *baseDN, int *scope,
1340 char *filter, LDAP *ld)
1342 char errmsg[MAXERROR], *tmp;
1343 ns_referral_info_t *ref, *tmpref;
1344 LDAPURLDesc *ludp = NULL;
1345 int hostlen;
1346 char *ld_defhost = NULL;
1348 #ifdef DEBUG
1349 (void) fprintf(stderr, "__s_api_addRefInfo START\n");
1350 #endif
1352 /* sanity check */
1353 if (head == NULL)
1354 return (NS_LDAP_OP_FAILED);
1357 * log error and return NS_LDAP_SUCCESS
1358 * if one of the following:
1359 * 1. non-LDAP URL
1360 * 2. LDAP URL which can not be parsed
1362 if (!ldap_is_ldap_url(url) ||
1363 ldap_url_parse_nodn(url, &ludp) != 0) {
1364 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1365 gettext("Invalid or non-LDAP URL when"
1366 " processing referrals URL"),
1367 url);
1368 syslog(LOG_ERR, "libsldap: %s", errmsg);
1369 if (ludp)
1370 ldap_free_urldesc(ludp);
1371 return (NS_LDAP_SUCCESS);
1374 ref = (ns_referral_info_t *)calloc(1,
1375 sizeof (ns_referral_info_t));
1376 if (ref == NULL) {
1377 ldap_free_urldesc(ludp);
1378 return (NS_LDAP_MEMORY);
1382 * we do have a valid URL and we were able to parse it
1383 * however, we still need to find out what hostport to
1384 * use if none were provided in the LDAP URL
1385 * (e.g., ldap:///...)
1387 if ((ludp->lud_port == 0) && (ludp->lud_host == NULL)) {
1388 if (ld == NULL) {
1389 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1390 gettext("no LDAP handle when"
1391 " processing referrals URL"),
1392 url);
1393 syslog(LOG_WARNING, "libsldap: %s", errmsg);
1394 ldap_free_urldesc(ludp);
1395 free(ref);
1396 return (NS_LDAP_SUCCESS);
1397 } else {
1398 (void) ldap_get_option(ld, LDAP_OPT_HOST_NAME,
1399 &ld_defhost);
1400 if (ld_defhost == NULL) {
1401 (void) snprintf(errmsg, MAXERROR, "%s: %s",
1402 gettext("not able to retrieve default "
1403 "host when processing "
1404 "referrals URL"),
1405 url);
1406 syslog(LOG_WARNING, "libsldap: %s", errmsg);
1407 ldap_free_urldesc(ludp);
1408 free(ref);
1409 return (NS_LDAP_SUCCESS);
1410 } else {
1411 ref->refHost = strdup(ld_defhost);
1412 if (ref->refHost == NULL) {
1413 ldap_free_urldesc(ludp);
1414 free(ref);
1415 return (NS_LDAP_MEMORY);
1419 } else {
1421 * add 4 here:
1422 * 1 for the last '\0'.
1423 * 1 for host and prot separator ":"
1424 * and "[" & "]" for possible ipV6 addressing
1426 hostlen = strlen(ludp->lud_host) +
1427 sizeof (MAXPORTNUMBER_STR) + 4;
1428 ref->refHost = (char *)malloc(hostlen);
1429 if (ref->refHost == NULL) {
1430 ldap_free_urldesc(ludp);
1431 free(ref);
1432 return (NS_LDAP_MEMORY);
1435 if (ludp->lud_port != 0) {
1437 * serverAddr = host:port
1438 * or
1439 * if host is an IPV6 address
1440 * [host]:port
1442 tmp = strstr(url, ludp->lud_host);
1443 if (tmp && (tmp > url) && *(tmp - 1) == '[') {
1444 (void) snprintf(ref->refHost, hostlen,
1445 "[%s]:%d",
1446 ludp->lud_host,
1447 ludp->lud_port);
1448 } else {
1449 (void) snprintf(ref->refHost, hostlen,
1450 "%s:%d",
1451 ludp->lud_host,
1452 ludp->lud_port);
1454 } else {
1455 /* serverAddr = host */
1456 (void) snprintf(ref->refHost, hostlen, "%s",
1457 ludp->lud_host);
1461 if (ludp->lud_dn) {
1462 ref->refDN = strdup(ludp->lud_dn);
1463 if (ref->refDN == NULL) {
1464 ldap_free_urldesc(ludp);
1465 free(ref->refHost);
1466 free(ref);
1467 return (NS_LDAP_MEMORY);
1469 } else {
1470 if (baseDN) {
1471 ref->refDN = strdup(baseDN);
1472 if (ref->refDN == NULL) {
1473 ldap_free_urldesc(ludp);
1474 free(ref->refHost);
1475 free(ref);
1476 return (NS_LDAP_MEMORY);
1481 if (filter)
1482 ref->refFilter = strdup(filter);
1483 else if (ludp->lud_filter)
1484 ref->refFilter = strdup(ludp->lud_filter);
1485 else
1486 ref->refFilter = strdup("");
1488 if (ref->refFilter == NULL) {
1489 ldap_free_urldesc(ludp);
1490 free(ref->refHost);
1491 if (ref->refDN)
1492 free(ref->refDN);
1493 free(ref);
1494 return (NS_LDAP_MEMORY);
1498 * If the scope is specified in the URL use it.
1499 * Note if the scope is missing in the URL, ldap_url_parse_nodn()
1500 * returns the scope BASE. We need to check that the scope of BASE
1501 * is actually present in the URL.
1502 * If the scope is missing in the URL then use the passed-in
1503 * scope.
1504 * If there is no passed-in scope, then use the scope SUBTREE.
1506 if (ludp->lud_dn && ludp->lud_scope != LDAP_SCOPE_BASE)
1507 ref->refScope = ludp->lud_scope;
1508 else if (ludp->lud_dn && strstr(url, "?base"))
1509 ref->refScope = LDAP_SCOPE_BASE;
1510 else if (scope)
1511 ref->refScope = *scope;
1512 else
1513 ref->refScope = LDAP_SCOPE_SUBTREE;
1515 ref->next = NULL;
1517 ldap_free_urldesc(ludp);
1519 /* insert the referral info */
1520 if (*head) {
1521 for (tmpref = *head; tmpref->next; tmpref = tmpref->next)
1523 tmpref->next = ref;
1524 } else
1525 *head = ref;
1527 return (NS_LDAP_SUCCESS);
1531 * FUNCTION: __s_api_deleteRefInfo
1532 * Delete a referral info list.
1533 * INPUT: pointer to the referral info list
1535 void
1536 __s_api_deleteRefInfo(ns_referral_info_t *head)
1538 ns_referral_info_t *ref, *tmp;
1540 #ifdef DEBUG
1541 (void) fprintf(stderr, "__s_api_deleteRefInfo START\n");
1542 #endif
1544 for (ref = head; ref; ) {
1545 if (ref->refHost)
1546 free(ref->refHost);
1547 if (ref->refDN)
1548 free(ref->refDN);
1549 if (ref->refFilter)
1550 free(ref->refFilter);
1551 tmp = ref->next;
1552 free(ref);
1553 ref = tmp;
1559 * FUNCTION: __s_api_get_SSD_from_SSDtoUse_service
1561 * Retrieves the Service Search Descriptors which should be used for
1562 * the given service. For example, return all the "passwd" SSDs for
1563 * service "shadow" if no SSD is defined for service "shadow" and
1564 * no filter component is defined in all the "passwd" SSDs. This idea
1565 * of sharing the SSDs defined for some other service is to reduce the
1566 * configuration complexity. For a service, which does not have its own
1567 * entries in the LDAP directory, SSD for it is useless, and should not
1568 * be set. But since this service must share the container with at least
1569 * one other service which does have it own entries, the SSD for
1570 * this other service will be shared by this service.
1571 * This other service is called the SSD-to-use service.
1572 * The static data structure, ns_def_map[], in this file
1573 * defines the SSD-to-use service for all the services supported.
1575 * RETURN VALUES: NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_INVALID_PARAM
1576 * INPUT: service
1577 * OUTPUT: *SSDlist, *errorp if error
1580 __s_api_get_SSD_from_SSDtoUse_service(const char *service,
1581 ns_ldap_search_desc_t ***SSDlist,
1582 ns_ldap_error_t **errorp)
1584 int i, rc;
1585 int found = FALSE;
1586 int filter_found = FALSE;
1587 char *SSD_service = NULL;
1588 char errmsg[MAXERROR];
1589 ns_ldap_search_desc_t **sdlist;
1590 int auto_service = FALSE;
1592 #ifdef DEBUG
1593 (void) fprintf(stderr,
1594 "__s_api_get_SSD_from_SSDtoUse_service START\n");
1595 #endif
1597 if (SSDlist == NULL || errorp == NULL)
1598 return (NS_LDAP_INVALID_PARAM);
1600 *SSDlist = NULL;
1601 *errorp = NULL;
1603 if (service == NULL)
1604 return (NS_LDAP_SUCCESS);
1606 if (strncasecmp(service, "auto_", 5) == 0)
1607 auto_service = TRUE;
1610 * First try to return the configured SSDs for the input server
1612 rc = __ns_ldap_getSearchDescriptors(service, SSDlist, errorp);
1613 if (rc != NS_LDAP_SUCCESS)
1614 return (rc);
1615 else {
1616 if (*SSDlist != NULL)
1617 return (NS_LDAP_SUCCESS);
1621 * If service == auto_* and SSD is not found,
1622 * then try automount to see if there is an SSD
1623 * for automount.
1626 if (auto_service) {
1627 rc = __ns_ldap_getSearchDescriptors(
1628 "automount", SSDlist, errorp);
1629 if (rc != NS_LDAP_SUCCESS)
1630 return (rc);
1631 else {
1632 if (*SSDlist != NULL) {
1634 * If SSDlist is found,
1635 * prepend automountMapName to the basedn
1636 * in the SSDlist
1639 rc = __s_api_prepend_automountmapname(
1640 service,
1641 SSDlist,
1642 errorp);
1644 if (rc != NS_LDAP_SUCCESS) {
1645 (void) __ns_ldap_freeSearchDescriptors(
1646 SSDlist);
1647 *SSDlist = NULL;
1650 return (rc);
1656 * Find the SSDtoUse service.
1657 * If none found, flag "found" remains FALSE.
1659 for (i = 0; ns_def_map[i].service != NULL; i++) {
1660 if (ns_def_map[i].SSDtoUse_service &&
1661 strcasecmp(service,
1662 ns_def_map[i].service) == 0) {
1663 found = TRUE;
1664 SSD_service = ns_def_map[i].SSDtoUse_service;
1665 break;
1669 if (!found)
1670 return (NS_LDAP_SUCCESS);
1673 * return the SSDs for SSD_service only if no optional filter
1674 * component is defined in the SSDs
1676 rc = __ns_ldap_getSearchDescriptors(SSD_service,
1677 SSDlist, errorp);
1678 if (rc != NS_LDAP_SUCCESS) {
1679 return (rc);
1680 } else {
1681 if (*SSDlist == NULL)
1682 return (NS_LDAP_SUCCESS);
1684 /* check to see if filter defined in SSD */
1685 for (sdlist = *SSDlist; *sdlist; sdlist++) {
1686 if ((*sdlist)->filter &&
1687 strlen((*sdlist)->filter) > 0) {
1688 filter_found = TRUE;
1689 break;
1692 if (filter_found) {
1693 (void) __ns_ldap_freeSearchDescriptors(SSDlist);
1694 *SSDlist = NULL;
1695 (void) snprintf(errmsg, sizeof (errmsg),
1696 gettext("Service search descriptor for "
1697 "service '%s' contains filter, "
1698 "which can not be used for "
1699 "service '%s'."),
1700 SSD_service, service);
1701 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE,
1702 strdup(errmsg), NS_LDAP_CONFIG);
1703 return (NS_LDAP_CONFIG);
1707 return (NS_LDAP_SUCCESS);
1712 * verify addr is an IPv4 address with the optional [:portno]
1713 * RFC2373 & RFC2732 & RFC2396
1716 __s_api_isipv4(char *addr)
1718 int i, seg, digit, port;
1720 if (!addr)
1721 return (0);
1723 digit = seg = port = 0;
1725 for (i = 0; i < strlen(addr); i++) {
1726 if (isdigit(addr[i])) {
1727 digit++;
1728 continue;
1730 if (addr[i] == '.') {
1731 if (digit > 3 || digit == 0)
1732 return (0);
1733 digit = 0;
1734 seg++;
1735 continue;
1737 if (addr[i] == ':') {
1738 if (digit > 3)
1739 return (0);
1740 port++;
1741 digit = 0;
1742 seg++;
1743 continue;
1745 return (0);
1748 if ((seg == 3 && port == 0 && digit > 0 && digit < 4) ||
1749 (seg == 4 && port == 1 && digit > 0))
1750 return (1);
1752 return (0);
1757 * verify addr is an IPv6 address with the optional [IPv6]:portno
1758 * RFC2373 & RFC2732 & RFC2396
1761 __s_api_isipv6(char *addr)
1763 int i, col, digit, port, dc, tc;
1764 char *laddr, *c1, *s;
1766 if (!addr)
1767 return (0);
1769 s = addr;
1770 laddr = NULL;
1771 digit = col = port = 0;
1772 if (addr[0] == '[') {
1773 laddr = strdup(addr);
1774 if (!laddr)
1775 return (0);
1776 c1 = strchr(laddr, ']');
1777 /* only 1 ']' should be in an addr */
1778 if (!c1 || (strchr(c1+1, ']')))
1779 goto bad;
1780 switch (c1[1]) {
1781 case ':':
1782 port++;
1783 for (i = 2; i < strlen(c1); i++) {
1784 if (!isdigit(c1[i]))
1785 goto bad;
1786 digit++;
1788 if (!digit)
1789 goto bad;
1790 c1[0] = '\0';
1791 break;
1792 case '\0':
1793 c1[0] = '\0';
1794 break;
1795 default:
1796 goto bad;
1798 s = &laddr[1];
1801 digit = dc = tc = 0;
1802 for (i = 0; i < strlen(s); i++) {
1803 if (isxdigit(s[i])) {
1804 if (digit == 0)
1805 dc = i;
1806 digit++;
1807 col = 0;
1808 continue;
1810 if (s[i] == ':') {
1811 tc++;
1812 if ((col > 1) || (i && !col && !digit))
1813 goto bad;
1814 digit = 0;
1815 col++;
1816 continue;
1818 if (s[i] == '.') {
1819 if (__s_api_isipv4(&s[dc]) && tc)
1820 goto good;
1821 else
1822 goto bad;
1824 goto bad;
1827 good:
1828 free(laddr);
1829 return (1);
1830 bad:
1831 free(laddr);
1832 return (0);
1837 * verify addr is a valid hostname with the optional [:portno]
1838 * RFC2373 & RFC2732 & RFC2396
1841 __s_api_ishost(char *addr)
1843 int i, seg, alpha, digit, port;
1845 if (!addr)
1846 return (0);
1848 alpha = digit = seg = port = 0;
1850 /* must start with alpha character */
1851 if (!isalpha(addr[0]))
1852 return (0);
1854 for (i = 0; i < strlen(addr); i++) {
1855 if (isalpha(addr[i]) || (i && addr[i] == '-')) {
1856 alpha++;
1857 continue;
1859 if (isdigit(addr[i])) {
1860 digit++;
1861 continue;
1863 if (addr[i] == '.') {
1864 if (!alpha && !digit)
1865 return (0);
1866 alpha = digit = 0;
1867 seg++;
1868 continue;
1870 if (addr[i] == ':') {
1871 if (!alpha && !digit)
1872 return (0);
1873 alpha = digit = 0;
1874 port++;
1875 seg++;
1876 continue;
1878 return (0);
1881 if ((port == 0 && (seg || alpha || digit)) ||
1882 (port == 1 && alpha == 0 && digit))
1883 return (1);
1885 return (0);
1890 * Prepend automountMapName=auto_xxx to the basedn
1891 * in the SSDlist
1894 int __s_api_prepend_automountmapname(
1895 const char *service,
1896 ns_ldap_search_desc_t ***SSDlist,
1897 ns_ldap_error_t **errorp)
1899 int i, rc;
1900 ns_ldap_search_desc_t ** ssdlist = NULL;
1902 if (service == NULL || SSDlist == NULL || *SSDlist == NULL)
1903 return (NS_LDAP_INVALID_PARAM);
1905 ssdlist = *SSDlist;
1907 for (i = 0; ssdlist[i] != NULL; i++) {
1908 rc = __s_api_prepend_automountmapname_to_dn(
1909 service, &ssdlist[i]->basedn, errorp);
1911 if (rc != NS_LDAP_SUCCESS)
1912 return (rc);
1915 return (NS_LDAP_SUCCESS);
1920 * Prepend automountMapName=auto_xxx to the DN
1921 * Construct a string of
1922 * "automountMapName=auto_xxx,dn"
1924 * If automountMapName is mapped to some other attribute,
1925 * then use the mapping in the setup.
1927 * If a version 1 profile is in use, use nisMapName for
1928 * backward compatibility (i.e. "nisMapName=auto_xxx,dn").
1932 __s_api_prepend_automountmapname_to_dn(
1933 const char *service,
1934 char **dn,
1935 ns_ldap_error_t **errorp)
1937 int rc, len_s = 0, len_d = 0, len = 0;
1938 char *buffer = NULL;
1939 char *default_automountmapname = "automountMapName";
1940 char *automountmapname = NULL;
1941 char **mappedattrs = NULL;
1942 char errstr[MAXERROR];
1943 void **paramVal = NULL;
1945 if (service == NULL || dn == NULL || *dn == NULL)
1946 return (NS_LDAP_INVALID_PARAM);
1948 rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
1949 if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
1950 if (paramVal)
1951 (void) __ns_ldap_freeParam(&paramVal);
1952 return (rc);
1954 if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) {
1955 automountmapname = strdup("nisMapName");
1956 (void) __ns_ldap_freeParam(&paramVal);
1957 if (automountmapname == NULL) {
1958 return (NS_LDAP_MEMORY);
1960 } else {
1961 (void) __ns_ldap_freeParam(&paramVal);
1963 /* Find mapped attribute name of auto_xxx first */
1964 mappedattrs = __ns_ldap_getMappedAttributes(
1965 service, default_automountmapname);
1967 * if mapped attribute name of auto_xxx is not found,
1968 * find the mapped attribute name of automount
1971 if (mappedattrs == NULL)
1972 mappedattrs = __ns_ldap_getMappedAttributes(
1973 "automount", default_automountmapname);
1976 * if mapped attr is not found, use the default automountmapname
1979 if (mappedattrs == NULL) {
1980 automountmapname = strdup(default_automountmapname);
1981 if (automountmapname == NULL)
1982 return (NS_LDAP_MEMORY);
1983 } else {
1984 if (mappedattrs[0] != NULL) {
1986 * Copy it from the mapped attr list
1987 * Assume it's 1 to 1 mapping
1988 * 1 to n does not make sense
1990 automountmapname = strdup(mappedattrs[0]);
1991 __s_api_free2dArray(mappedattrs);
1992 if (automountmapname == NULL) {
1993 return (NS_LDAP_MEMORY);
1995 } else {
1998 * automountmapname is mapped to an empty string
2001 __s_api_free2dArray(mappedattrs);
2003 (void) sprintf(errstr,
2004 gettext(
2005 "Attribute automountMapName is "
2006 "mapped to an empty string.\n"));
2008 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
2009 strdup(errstr), NS_LDAP_MEMORY);
2011 return (NS_LDAP_CONFIG);
2016 len_s = strlen(service);
2017 len_d = strlen(*dn);
2018 /* automountMapName + "=" + service + "," + dn + '\0' */
2019 len = strlen(automountmapname) + 1 + len_s + 1 + len_d + 1;
2020 buffer = (char *)malloc(len);
2021 if (buffer == NULL) {
2022 free(automountmapname);
2023 return (NS_LDAP_MEMORY);
2026 (void) snprintf(buffer, len, "%s=%s,%s",
2027 automountmapname, service, *dn);
2029 buffer[len-1] = '\0';
2031 free(automountmapname);
2033 /* free the original dn */
2034 (void) free(*dn);
2036 *dn = buffer;
2038 return (NS_LDAP_SUCCESS);
2042 * Map the LDAP error code and error message from LDAP server
2043 * to a password status used for password aging/management.
2045 ns_ldap_passwd_status_t
2046 __s_api_set_passwd_status(int errnum, char *errmsg)
2048 syslog(LOG_DEBUG, "libsldap: got LDAP errnum %d & message: %s ", errnum,
2049 (errmsg != NULL) ? errmsg : "error msg not available");
2050 if (errmsg) {
2051 if (errnum ==
2052 LDAP_INVALID_CREDENTIALS) {
2054 * case 1 (Bind):
2055 * password expired
2057 if (strstr(errmsg,
2058 NS_PWDERR_EXPIRED))
2059 return (NS_PASSWD_EXPIRED);
2062 if (errnum ==
2063 LDAP_UNWILLING_TO_PERFORM) {
2065 * case 1.1 (Bind):
2066 * password expired
2068 if (strstr(errmsg,
2069 NS_PWDERR_EXPIRED))
2070 return (NS_PASSWD_EXPIRED);
2073 * case 2 (Bind):
2074 * Account inactivated
2076 if (strstr(errmsg,
2077 NS_PWDERR_ACCT_INACTIVATED))
2078 return (NS_PASSWD_EXPIRED);
2082 * case 3 (Modify passwd):
2083 * the user is not allow to change
2084 * password; only admin can change it
2086 if (strstr(errmsg,
2087 NS_PWDERR_CHANGE_NOT_ALLOW))
2088 return (NS_PASSWD_CHANGE_NOT_ALLOWED);
2091 if (errnum ==
2092 LDAP_CONSTRAINT_VIOLATION) {
2094 * case 4 (Bind):
2095 * the user account is locked due to
2096 * too many login failures.
2098 if (strstr(errmsg,
2099 NS_PWDERR_MAXTRIES))
2100 return (NS_PASSWD_RETRY_EXCEEDED);
2102 * case 5 (Modify passwd):
2103 * syntax error: the new password
2104 * has length less than defined
2105 * minimum
2106 * Not true anymore with strong password
2107 * policies on LDAP server: errmsg that
2108 * contain NS_PWDERR_INVALID_SYNTAX may
2109 * have different meanings.
2110 * To keep compatibility with older password
2111 * policy, check if errmsg is strictly equal
2112 * to NS_PWDERR_INVALID_SYNTAX and if yes only,
2113 * return NS_PASSWD_TOO_SHORT.
2115 if (strcmp(errmsg,
2116 NS_PWDERR_INVALID_SYNTAX) == 0)
2117 return (NS_PASSWD_TOO_SHORT);
2118 if (strstr(errmsg,
2119 NS_PWDERR_INVALID_SYNTAX))
2120 return (NS_PASSWD_INVALID_SYNTAX);
2122 * case 6 (Modify passwd):
2123 * trivial password: same value as
2124 * that of attribute cn, sn, or uid ...
2126 if (strstr(errmsg,
2127 NS_PWDERR_TRIVIAL_PASSWD))
2128 return (NS_PASSWD_INVALID_SYNTAX);
2130 * case 7 (Modify passwd):
2131 * re-use one of the old passwords
2132 * in history list
2134 if (strstr(errmsg,
2135 NS_PWDERR_IN_HISTORY))
2136 return (NS_PASSWD_IN_HISTORY);
2138 * case 8 (Modify passwd):
2139 * password not allowed to be
2140 * changed yet; within minimum
2141 * age
2143 if (strstr(errmsg,
2144 NS_PWDERR_WITHIN_MIN_AGE))
2145 return (NS_PASSWD_WITHIN_MIN_AGE);
2150 return (NS_PASSWD_GOOD);
2154 * Determine if the input OID list contains
2155 * one of the password control OIDs, which are:
2156 * LDAP_CONTROL_PWEXPIRED: 2.16.840.1.113730.3.4.4
2157 * LDAP_CONTROL_PWEXPIRING: 2.16.840.1.113730.3.4.5.
2158 * If yes, return 1, if no, 0.
2161 __s_api_contain_passwd_control_oid(char **oids)
2163 char **oid;
2165 if (oids == NULL)
2166 return (0);
2168 for (oid = oids; *oid; oid++) {
2169 if (strcmp(*oid, LDAP_CONTROL_PWEXPIRED) == 0 ||
2170 strcmp(*oid, LDAP_CONTROL_PWEXPIRING) == 0) {
2171 return (1);
2175 return (0);
2179 * Determine if the input OID list contains LDAP V3 password less
2180 * account management control OID, which is:
2181 * NS_LDAP_ACCOUNT_USABLE_CONTROL:1.3.6.1.4.1.42.2.27.9.5.8
2182 * If yes, return 1, if no, 0.
2185 __s_api_contain_account_usable_control_oid(char **oids)
2187 char **oid;
2189 if (oids == NULL)
2190 return (0);
2192 for (oid = oids; *oid; oid++) {
2193 if (strcmp(*oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) == 0) {
2194 return (1);
2198 return (0);
2202 * For some databases in name switch, the name and aliases are saved
2203 * as "cn". When the "cn" valuse are retrieved, there is no distinction
2204 * which is the name and which is(are) aliase(s).
2205 * This function is to parse RDN and find the value of the "cn" and
2206 * then find the matching value in "cn" attribute.
2207 * Also see RFC 2307 section 5.6.
2209 * Input -
2210 * entry: An LDAP entry
2211 * attrptr: A attribute which value appears in RDN
2212 * This should be "cn" for the name switch for now.
2213 * case_ignore: 0 Case sensitive comparison on the attribute value
2214 * 1 Case insensitive comparison
2216 * Return -
2217 * The value of an attrbute which is used as canonical name
2218 * This is read only and the caller should not try to free it.
2219 * If it's a NULL, it could be either an RDN parsing error
2220 * or RDN value does not match any existing "cn" values.
2221 * e.g.
2222 * dn: cn=xx+ipserviceprotocol=udp,......
2223 * cn: aa
2224 * cn: bb
2226 * Note:
2227 * Although the name switch/ldap's rdn is in "cn=xx" or "cn=xx+..."
2228 * format, this function makes no such assumption. If the DN
2229 * is saved as "dn: yy=...+sn=my_canocical_name, ..", then it can still work.
2230 * The comments use "cn" as an example only.
2233 typedef int (*cmpfunc)(const char *, const char *);
2235 char *
2236 __s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr,
2237 int case_ignore) {
2238 uint_t i;
2239 char *token, *lasts, *value = NULL;
2240 char **rdn = NULL, **attrs = NULL, **values = NULL;
2241 char *rdn_attr_value = NULL;
2242 cmpfunc cmp;
2244 if (entry == NULL || attrptr == NULL)
2245 return (NULL);
2247 /* "values" is read-only */
2248 if ((values = __ns_ldap_getAttr(entry, "dn")) == NULL ||
2249 values[0] == NULL)
2250 return (NULL);
2252 if ((rdn = ldap_explode_dn(values[0], 0)) == NULL ||
2253 rdn[0] == NULL)
2254 return (NULL);
2256 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) {
2257 ldap_value_free(rdn);
2258 return (NULL);
2260 /* Assume the rdn is normalized */
2261 for (i = 0; attrs[i] != NULL; i++) {
2262 /* parse attribute name and value, get attribute name first */
2263 if ((token = strtok_r(attrs[i], "=", &lasts)) == NULL) {
2264 goto cleanup;
2266 if (strcasecmp(token, attrptr->attrname) == 0) {
2267 /* get value */
2268 rdn_attr_value = lasts;
2269 break;
2272 if (rdn_attr_value) {
2273 if (case_ignore)
2274 cmp = strcasecmp;
2275 else
2276 cmp = strcmp;
2278 * After parsing RDN and find the matching attribute in RDN,
2279 * match rdn value with values in "cn".
2281 for (i = 0; i < attrptr->value_count; i++) {
2282 if (attrptr->attrvalue[i] &&
2283 (*cmp)(rdn_attr_value,
2284 attrptr->attrvalue[i]) == 0) {
2285 /* RDN "cn" value matches the "cn" value */
2286 value = attrptr->attrvalue[i];
2287 break;
2291 cleanup:
2292 ldap_value_free(rdn);
2293 ldap_value_free(attrs);
2295 return (value);
2299 * This function requests a server to be removed from
2300 * the cache manager maintained server list. This is
2301 * done via the door functionality.
2302 * Returns 0 if OK, else a negative value.
2306 __s_api_removeServer(const char *server)
2308 union {
2309 ldap_data_t s_d;
2310 char s_b[DOORBUFFERSIZE];
2311 } space;
2313 ns_server_info_t r, *ret = &r;
2314 const char *ireq;
2315 ldap_data_t *sptr;
2316 int ndata;
2317 int adata;
2318 int len;
2319 int rc;
2320 ns_ldap_error_t *error = NULL;
2322 if (server == NULL)
2323 return (-1);
2325 ireq = NS_CACHE_NORESP;
2327 if (__s_api_isStandalone()) {
2329 * Remove 'server' from the standalone server list.
2330 * __s_api_findRootDSE() is the standalone version
2331 * of getldap_get_serverInfo() used in ldap_cachemgr.
2332 * Request NS_CACHE_NORESP indicates 'server' should
2333 * be removed.
2335 if (__s_api_findRootDSE(ireq,
2336 server,
2337 NS_CACHE_ADDR_IP,
2338 NULL,
2339 &error) != NS_LDAP_SUCCESS) {
2340 syslog(LOG_WARNING,
2341 "libsldap (\"standalone\" mode): "
2342 " Unable to remove %s - %s",
2343 server,
2344 error != NULL && error->message != NULL ?
2345 error->message : " no error info");
2346 if (error != NULL) {
2347 (void) __ns_ldap_freeError(&error);
2350 return (NS_CACHE_NOSERVER);
2353 return (0);
2356 (void) memset(ret, 0, sizeof (ns_server_info_t));
2357 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2359 adata = (sizeof (ldap_call_t) + strlen(ireq) +
2360 strlen(NS_CACHE_ADDR_IP) + 1);
2361 adata += strlen(DOORLINESEP) + 1;
2362 adata += strlen(server) + 1;
2364 ndata = sizeof (space);
2365 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2366 len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2367 if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
2368 return (-1);
2369 if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
2370 NS_CACHE_ADDR_IP, len) >= len)
2371 return (-1);
2372 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len) >=
2373 len)
2374 return (-1);
2375 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len) >= len)
2376 return (-1);
2377 sptr = &space.s_d;
2379 /* try to remove the server via the door interface */
2380 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2382 /* clean up the door call */
2383 if (sptr != &space.s_d) {
2384 (void) munmap((char *)sptr, ndata);
2387 return (rc);
2390 void
2391 __s_api_free_server_info(ns_server_info_t *sinfo) {
2392 if (sinfo->server) {
2393 free(sinfo->server);
2394 sinfo->server = NULL;
2396 if (sinfo->serverFQDN) {
2397 free(sinfo->serverFQDN);
2398 sinfo->serverFQDN = NULL;
2400 __s_api_free2dArray(sinfo->saslMechanisms);
2401 sinfo->saslMechanisms = NULL;
2402 __s_api_free2dArray(sinfo->controls);
2403 sinfo->controls = NULL;
2407 * Create an ns_ldap_error structure, set status to 'rc',
2408 * and copy in the error message 'msg'.
2410 ns_ldap_error_t *
2411 __s_api_make_error(int rc, char *msg) {
2412 ns_ldap_error_t *ep;
2414 ep = (ns_ldap_error_t *)calloc(1, sizeof (*ep));
2415 if (ep == NULL)
2416 return (NULL);
2418 ep->status = rc;
2419 if (msg != NULL)
2420 ep->message = strdup(msg); /* OK if ep->message is NULL */
2422 return (ep);
2426 * Make a copy of the input ns_ldap_error.
2428 ns_ldap_error_t *
2429 __s_api_copy_error(ns_ldap_error_t *errorp) {
2430 ns_ldap_error_t *ep;
2431 char *msg;
2433 if (errorp == NULL)
2434 return (NULL);
2436 ep = (ns_ldap_error_t *)malloc(sizeof (*ep));
2437 if (ep != NULL) {
2438 *ep = *errorp;
2439 if (ep->message != NULL) {
2440 msg = strdup(ep->message);
2441 if (msg == NULL) {
2442 free(ep);
2443 ep = NULL;
2444 } else
2445 ep->message = msg;
2448 return (ep);