xref: /onnv-gate/usr/src/lib/nsswitch/ldap/common/getservent.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <ctype.h>
30*0Sstevel@tonic-gate #include <netdb.h>
31*0Sstevel@tonic-gate #include "ns_internal.h"
32*0Sstevel@tonic-gate #include "ldap_common.h"
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate /* services attributes filters */
35*0Sstevel@tonic-gate #define	_S_NAME			"cn"
36*0Sstevel@tonic-gate #define	_S_PORT			"ipserviceport"
37*0Sstevel@tonic-gate #define	_S_PROTOCOL		"ipserviceprotocol"
38*0Sstevel@tonic-gate #define	_F_GETSERVBYNAME	"(&(objectClass=ipService)(cn=%s))"
39*0Sstevel@tonic-gate #define	_F_GETSERVBYNAME_SSD	"(&(%%s)(cn=%s))"
40*0Sstevel@tonic-gate #define	_F_GETSERVBYNAMEPROTO	\
41*0Sstevel@tonic-gate 	"(&(objectClass=ipService)(cn=%s)(ipServiceProtocol=%s))"
42*0Sstevel@tonic-gate #define	_F_GETSERVBYNAMEPROTO_SSD	\
43*0Sstevel@tonic-gate 	"(&(%%s)(cn=%s)(ipServiceProtocol=%s))"
44*0Sstevel@tonic-gate #define	_F_GETSERVBYPORT	"(&(objectClass=ipService)(ipServicePort=%ld))"
45*0Sstevel@tonic-gate #define	_F_GETSERVBYPORT_SSD	"(&(%%s)(ipServicePort=%ld))"
46*0Sstevel@tonic-gate #define	_F_GETSERVBYPORTPROTO	\
47*0Sstevel@tonic-gate 	"(&(objectClass=ipService)(ipServicePort=%ld)(ipServiceProtocol=%s))"
48*0Sstevel@tonic-gate #define	_F_GETSERVBYPORTPROTO_SSD	\
49*0Sstevel@tonic-gate 	"(&(%%s)(ipServicePort=%ld)(ipServiceProtocol=%s))"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate typedef struct _nss_services_cookie {
52*0Sstevel@tonic-gate 	int			index;	/* index of ipserviceprotocol */
53*0Sstevel@tonic-gate 	char			*cname;	/* canonical name, don't free it */
54*0Sstevel@tonic-gate 	ns_ldap_result_t	*result;
55*0Sstevel@tonic-gate } _nss_services_cookie_t;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static const char *services_attrs[] = {
58*0Sstevel@tonic-gate 	_S_NAME,
59*0Sstevel@tonic-gate 	_S_PORT,
60*0Sstevel@tonic-gate 	_S_PROTOCOL,
61*0Sstevel@tonic-gate 	(char *)NULL
62*0Sstevel@tonic-gate };
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate void
65*0Sstevel@tonic-gate _nss_services_cookie_free(void **ckP) {
66*0Sstevel@tonic-gate 	_nss_services_cookie_t **cookieP = (_nss_services_cookie_t **)ckP;
67*0Sstevel@tonic-gate 	if (cookieP && *cookieP) {
68*0Sstevel@tonic-gate 		if ((*cookieP)->result)
69*0Sstevel@tonic-gate 			(void) __ns_ldap_freeResult(&(*cookieP)->result);
70*0Sstevel@tonic-gate 		free(*cookieP);
71*0Sstevel@tonic-gate 		*cookieP = NULL;
72*0Sstevel@tonic-gate 	}
73*0Sstevel@tonic-gate }
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static _nss_services_cookie_t *
76*0Sstevel@tonic-gate _nss_services_cookie_new(ns_ldap_result_t *result, int index, char *cname) {
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	_nss_services_cookie_t	*cookie;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	if ((cookie = calloc(1, sizeof (*cookie))) == NULL)
81*0Sstevel@tonic-gate 		return (NULL);
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	/*
84*0Sstevel@tonic-gate 	 * result has been allocated either by __ns_ldap_firstEntry
85*0Sstevel@tonic-gate 	 * or __ns_ldap_nextEntry.
86*0Sstevel@tonic-gate 	 */
87*0Sstevel@tonic-gate 	cookie->result = result;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	cookie->index = index;
90*0Sstevel@tonic-gate 	cookie->cname = cname;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	return (cookie);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * _nss_ldap_services2ent is the data marshaling method for the services
97*0Sstevel@tonic-gate  * getXbyY * (e.g., getbyname(), getbyport(), getent()) backend processes.
98*0Sstevel@tonic-gate  * This method is called after a successful ldap search has been performed.
99*0Sstevel@tonic-gate  * This method will parse the ldap search values into *serv = (struct
100*0Sstevel@tonic-gate  * servent *)argp->buf.result which the frontend process expects. Three error
101*0Sstevel@tonic-gate  * conditions are expected and returned to nsswitch.
102*0Sstevel@tonic-gate  *
103*0Sstevel@tonic-gate  * In section 5.5 of RFC 2307, it specifies that a "services" LDAP entry
104*0Sstevel@tonic-gate  * containing multiple ipserviceprotocol values should be able to be mapped
105*0Sstevel@tonic-gate  * to multiple "services" entities. Code has been added to support
106*0Sstevel@tonic-gate  * this one to many mapping feature.
107*0Sstevel@tonic-gate  */
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate static int
110*0Sstevel@tonic-gate _nss_ldap_services2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
111*0Sstevel@tonic-gate {
112*0Sstevel@tonic-gate 	int		i, j, k;
113*0Sstevel@tonic-gate 	int		nss_result;
114*0Sstevel@tonic-gate 	int		buflen = (int)0;
115*0Sstevel@tonic-gate 	int		firstime = (int)1;
116*0Sstevel@tonic-gate 	unsigned long	len = 0L;
117*0Sstevel@tonic-gate 	char		**mp, *cname = NULL, *protoval = NULL;
118*0Sstevel@tonic-gate 	char		*buffer = (char *)NULL;
119*0Sstevel@tonic-gate 	char		*ceiling = (char *)NULL;
120*0Sstevel@tonic-gate 	struct servent *serv = (struct servent *)NULL;
121*0Sstevel@tonic-gate 	ns_ldap_result_t	*result;
122*0Sstevel@tonic-gate 	ns_ldap_attr_t	*attrptr, *protocol = NULL;
123*0Sstevel@tonic-gate 	_nss_services_cookie_t	*cookie = (_nss_services_cookie_t *)
124*0Sstevel@tonic-gate 						be->services_cookie;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	buffer = (char *)argp->buf.buffer;
127*0Sstevel@tonic-gate 	buflen = (size_t)argp->buf.buflen;
128*0Sstevel@tonic-gate 	serv = (struct servent *)argp->buf.result;
129*0Sstevel@tonic-gate 	ceiling = buffer + buflen;
130*0Sstevel@tonic-gate #ifdef DEBUG
131*0Sstevel@tonic-gate 	(void) fprintf(stderr, "[getservent.c: _nss_ldap_services2ent]\n");
132*0Sstevel@tonic-gate #endif /* DEBUG */
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	if (cookie) {
135*0Sstevel@tonic-gate 		/*
136*0Sstevel@tonic-gate 		 * getservent_r with multiple protocol values and the entry
137*0Sstevel@tonic-gate 		 * is enumerated 2nd time or beyond
138*0Sstevel@tonic-gate 		 */
139*0Sstevel@tonic-gate 		result =  cookie->result;
140*0Sstevel@tonic-gate 		cname = cookie->cname;
141*0Sstevel@tonic-gate 	} else {
142*0Sstevel@tonic-gate 		/*
143*0Sstevel@tonic-gate 		 * getservbyname_r, getservbyport_r or
144*0Sstevel@tonic-gate 		 * getservent_r with single protocol value or multiple values
145*0Sstevel@tonic-gate 		 * and the entry is enumerated 1st time
146*0Sstevel@tonic-gate 		 */
147*0Sstevel@tonic-gate 		result = be->result;
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
151*0Sstevel@tonic-gate 	(void) memset(argp->buf.buffer, 0, buflen);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	attrptr = getattr(result, 0);
154*0Sstevel@tonic-gate 	if (attrptr == NULL) {
155*0Sstevel@tonic-gate 		nss_result = (int)NSS_STR_PARSE_PARSE;
156*0Sstevel@tonic-gate 		goto result_srvs2ent;
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 	for (i = 0; i < result->entry->attr_count; i++) {
159*0Sstevel@tonic-gate 		attrptr = getattr(result, i);
160*0Sstevel@tonic-gate 		if (attrptr == NULL) {
161*0Sstevel@tonic-gate 			nss_result = (int)NSS_STR_PARSE_PARSE;
162*0Sstevel@tonic-gate 			goto result_srvs2ent;
163*0Sstevel@tonic-gate 		}
164*0Sstevel@tonic-gate 		if (strcasecmp(attrptr->attrname, _S_NAME) == 0) {
165*0Sstevel@tonic-gate 			for (j = 0; j < attrptr->value_count; j++) {
166*0Sstevel@tonic-gate 				if (firstime) {
167*0Sstevel@tonic-gate 					/* service name */
168*0Sstevel@tonic-gate 					if (cname == NULL) {
169*0Sstevel@tonic-gate 					    cname = __s_api_get_canonical_name(
170*0Sstevel@tonic-gate 					    result->entry, attrptr, 1);
171*0Sstevel@tonic-gate 					}
172*0Sstevel@tonic-gate 					if (cname == NULL ||
173*0Sstevel@tonic-gate 						(len = strlen(cname)) < 1) {
174*0Sstevel@tonic-gate 						nss_result =
175*0Sstevel@tonic-gate 							NSS_STR_PARSE_PARSE;
176*0Sstevel@tonic-gate 						goto result_srvs2ent;
177*0Sstevel@tonic-gate 					}
178*0Sstevel@tonic-gate 					serv->s_name = buffer;
179*0Sstevel@tonic-gate 					buffer += len + 1;
180*0Sstevel@tonic-gate 					if (buffer >= ceiling) {
181*0Sstevel@tonic-gate 						nss_result =
182*0Sstevel@tonic-gate 						    (int)NSS_STR_PARSE_ERANGE;
183*0Sstevel@tonic-gate 						goto result_srvs2ent;
184*0Sstevel@tonic-gate 					}
185*0Sstevel@tonic-gate 					(void) strcpy(serv->s_name, cname);
186*0Sstevel@tonic-gate 					/* alias list */
187*0Sstevel@tonic-gate 					mp = serv->s_aliases =
188*0Sstevel@tonic-gate 						(char **)ROUND_UP(buffer,
189*0Sstevel@tonic-gate 						sizeof (char **));
190*0Sstevel@tonic-gate 					buffer = (char *)serv->s_aliases +
191*0Sstevel@tonic-gate 						sizeof (char *) *
192*0Sstevel@tonic-gate 						(attrptr->value_count + 1);
193*0Sstevel@tonic-gate 					buffer = (char *)ROUND_UP(buffer,
194*0Sstevel@tonic-gate 						sizeof (char **));
195*0Sstevel@tonic-gate 					if (buffer >= ceiling) {
196*0Sstevel@tonic-gate 						nss_result =
197*0Sstevel@tonic-gate 						    (int)NSS_STR_PARSE_ERANGE;
198*0Sstevel@tonic-gate 						goto result_srvs2ent;
199*0Sstevel@tonic-gate 					}
200*0Sstevel@tonic-gate 					firstime = (int)0;
201*0Sstevel@tonic-gate 				}
202*0Sstevel@tonic-gate 				/* alias list */
203*0Sstevel@tonic-gate 				if ((attrptr->attrvalue[j] == NULL) ||
204*0Sstevel@tonic-gate 				    (len = strlen(attrptr->attrvalue[j])) < 1) {
205*0Sstevel@tonic-gate 					nss_result = (int)NSS_STR_PARSE_PARSE;
206*0Sstevel@tonic-gate 					goto result_srvs2ent;
207*0Sstevel@tonic-gate 				}
208*0Sstevel@tonic-gate 				/* skip canonical name */
209*0Sstevel@tonic-gate 				if (strcmp(cname, attrptr->attrvalue[j]) == 0)
210*0Sstevel@tonic-gate 					continue;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 				*mp = buffer;
213*0Sstevel@tonic-gate 				buffer += len + 1;
214*0Sstevel@tonic-gate 				if (buffer >= ceiling) {
215*0Sstevel@tonic-gate 					nss_result = (int)NSS_STR_PARSE_ERANGE;
216*0Sstevel@tonic-gate 					goto result_srvs2ent;
217*0Sstevel@tonic-gate 				}
218*0Sstevel@tonic-gate 				(void) strcpy(*mp++, attrptr->attrvalue[j]);
219*0Sstevel@tonic-gate 				continue;
220*0Sstevel@tonic-gate 			}
221*0Sstevel@tonic-gate 		}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		if (strcasecmp(attrptr->attrname, _S_PORT) == 0) {
224*0Sstevel@tonic-gate 			if ((attrptr->attrvalue[0] == NULL) ||
225*0Sstevel@tonic-gate 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
226*0Sstevel@tonic-gate 				nss_result = (int)NSS_STR_PARSE_PARSE;
227*0Sstevel@tonic-gate 				goto result_srvs2ent;
228*0Sstevel@tonic-gate 			}
229*0Sstevel@tonic-gate 			serv->s_port =
230*0Sstevel@tonic-gate 			    htons((ushort_t)atoi(attrptr->attrvalue[0]));
231*0Sstevel@tonic-gate 			continue;
232*0Sstevel@tonic-gate 		}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		if (strcasecmp(attrptr->attrname, _S_PROTOCOL) == 0) {
235*0Sstevel@tonic-gate 			/* protocol name */
236*0Sstevel@tonic-gate 			if (attrptr->attrvalue == NULL) {
237*0Sstevel@tonic-gate 				nss_result = (int)NSS_STR_PARSE_PARSE;
238*0Sstevel@tonic-gate 				goto result_srvs2ent;
239*0Sstevel@tonic-gate 			}
240*0Sstevel@tonic-gate 			protocol = attrptr;
241*0Sstevel@tonic-gate 			if (cookie) {
242*0Sstevel@tonic-gate 				/*
243*0Sstevel@tonic-gate 				 * getservent_r
244*0Sstevel@tonic-gate 				 * Get current value then increment index
245*0Sstevel@tonic-gate 				 */
246*0Sstevel@tonic-gate 				protoval = attrptr->attrvalue[cookie->index++];
247*0Sstevel@tonic-gate 			} else if (attrptr->value_count > 1 &&
248*0Sstevel@tonic-gate 						argp->key.serv.proto) {
249*0Sstevel@tonic-gate 				/*
250*0Sstevel@tonic-gate 				 * getserverbyname_r and getservbyport_r
251*0Sstevel@tonic-gate 				 *
252*0Sstevel@tonic-gate 				 * If there are more than one value and
253*0Sstevel@tonic-gate 				 * it needs to match protocol too,
254*0Sstevel@tonic-gate 				 * iterate each value to find matching one.
255*0Sstevel@tonic-gate 				 * getservent_r sets key.serv.proto to NULL,
256*0Sstevel@tonic-gate 				 * so it wouldn't run this part of code.
257*0Sstevel@tonic-gate 				 */
258*0Sstevel@tonic-gate 				for (k = 0; k < attrptr->value_count; k++) {
259*0Sstevel@tonic-gate 					if (attrptr->attrvalue[k] == NULL) {
260*0Sstevel@tonic-gate 						nss_result =
261*0Sstevel@tonic-gate 							NSS_STR_PARSE_PARSE;
262*0Sstevel@tonic-gate 						goto result_srvs2ent;
263*0Sstevel@tonic-gate 					}
264*0Sstevel@tonic-gate 					if (strcmp(attrptr->attrvalue[k],
265*0Sstevel@tonic-gate 						argp->key.serv.proto) == 0) {
266*0Sstevel@tonic-gate 						protoval =
267*0Sstevel@tonic-gate 							attrptr->attrvalue[k];
268*0Sstevel@tonic-gate 						break;
269*0Sstevel@tonic-gate 					}
270*0Sstevel@tonic-gate 				}
271*0Sstevel@tonic-gate 			} else {
272*0Sstevel@tonic-gate 				/*
273*0Sstevel@tonic-gate 				 * 1. getserverbyname_r and getservbyport_r
274*0Sstevel@tonic-gate 				 *
275*0Sstevel@tonic-gate 				 * It does not need to match protocol or
276*0Sstevel@tonic-gate 				 * ipserviceprotocol has single value,
277*0Sstevel@tonic-gate 				 * return the first one
278*0Sstevel@tonic-gate 				 *
279*0Sstevel@tonic-gate 				 * 2. getservent_r with single value
280*0Sstevel@tonic-gate 				 * or multiple values and the entry is
281*0Sstevel@tonic-gate 				 * enumerated 1st time,
282*0Sstevel@tonic-gate 				 * return the first one
283*0Sstevel@tonic-gate 				 *
284*0Sstevel@tonic-gate 				 */
285*0Sstevel@tonic-gate 				protoval = attrptr->attrvalue[0];
286*0Sstevel@tonic-gate 			}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 			if (protoval == NULL || (len = strlen(protoval)) < 1) {
289*0Sstevel@tonic-gate 				nss_result = (int)NSS_STR_PARSE_PARSE;
290*0Sstevel@tonic-gate 				goto result_srvs2ent;
291*0Sstevel@tonic-gate 			}
292*0Sstevel@tonic-gate 			serv->s_proto = buffer;
293*0Sstevel@tonic-gate 			buffer += len + 1;
294*0Sstevel@tonic-gate 			if (buffer >= ceiling) {
295*0Sstevel@tonic-gate 				nss_result = (int)NSS_STR_PARSE_ERANGE;
296*0Sstevel@tonic-gate 				goto result_srvs2ent;
297*0Sstevel@tonic-gate 			}
298*0Sstevel@tonic-gate 			(void) strcpy(serv->s_proto, protoval);
299*0Sstevel@tonic-gate 			continue;
300*0Sstevel@tonic-gate 		}
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if (be->enumcookie != NULL && cookie == NULL &&
304*0Sstevel@tonic-gate 			protocol->value_count > 1) {
305*0Sstevel@tonic-gate 		/*
306*0Sstevel@tonic-gate 		 * getservent_r with multiple ipserviceprotocol values
307*0Sstevel@tonic-gate 		 * and the entry is enumerated 1st time
308*0Sstevel@tonic-gate 		 *
309*0Sstevel@tonic-gate 		 * Create cookie and save result in the cookie
310*0Sstevel@tonic-gate 		 * "attrvalue[0]" of ipserviceprotocol is returned,
311*0Sstevel@tonic-gate 		 * so it starts with index 1. Also save the canonical name.
312*0Sstevel@tonic-gate 		 */
313*0Sstevel@tonic-gate 		be->services_cookie =
314*0Sstevel@tonic-gate 			(void *)_nss_services_cookie_new(be->result, 1, cname);
315*0Sstevel@tonic-gate 		if (be->services_cookie == NULL) {
316*0Sstevel@tonic-gate 			nss_result = NSS_STR_PARSE_PARSE;
317*0Sstevel@tonic-gate 			goto result_srvs2ent;
318*0Sstevel@tonic-gate 		}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 		/* reset be->result so it won't get freed later */
321*0Sstevel@tonic-gate 		be->result = NULL;
322*0Sstevel@tonic-gate 	}
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate #ifdef DEBUG
325*0Sstevel@tonic-gate 	(void) fprintf(stdout, "\n[getservent.c: _nss_ldap_services2ent]\n");
326*0Sstevel@tonic-gate 	(void) fprintf(stdout, "        s_name: [%s]\n", serv->s_name);
327*0Sstevel@tonic-gate 	if (mp != NULL) {
328*0Sstevel@tonic-gate 		for (mp = serv->s_aliases; *mp != NULL; mp++)
329*0Sstevel@tonic-gate 			(void) fprintf(stdout, "     s_aliases: [%s]\n", *mp);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 	(void) fprintf(stdout, "        s_port: [%d]\n", serv->s_port);
332*0Sstevel@tonic-gate 	(void) fprintf(stdout, "    s_protocol: [%s]\n", serv->s_proto);
333*0Sstevel@tonic-gate #endif /* DEBUG */
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate result_srvs2ent:
336*0Sstevel@tonic-gate 	if (cookie) {
337*0Sstevel@tonic-gate 		/*
338*0Sstevel@tonic-gate 		 * getservent_r with multiple ipserviceprotocol values and
339*0Sstevel@tonic-gate 		 * the entry is enumerated 2nd time or beyond
340*0Sstevel@tonic-gate 		 */
341*0Sstevel@tonic-gate 		if (nss_result != NSS_STR_PARSE_SUCCESS ||
342*0Sstevel@tonic-gate 			cookie->index >= protocol->value_count) {
343*0Sstevel@tonic-gate 			/*
344*0Sstevel@tonic-gate 			 * If it's an error case or it has iterated all
345*0Sstevel@tonic-gate 			 * ipservicesprotocol value(s) then free cookie and
346*0Sstevel@tonic-gate 			 * set it to NULL
347*0Sstevel@tonic-gate 			 *
348*0Sstevel@tonic-gate 			 */
349*0Sstevel@tonic-gate 			_nss_services_cookie_free(
350*0Sstevel@tonic-gate 				(void **)&be->services_cookie);
351*0Sstevel@tonic-gate 		}
352*0Sstevel@tonic-gate 	} else {
353*0Sstevel@tonic-gate 		/*
354*0Sstevel@tonic-gate 		 * getservbyname_r, getservbyport_r, or
355*0Sstevel@tonic-gate 		 * getservent_r with single value or can't create cookie
356*0Sstevel@tonic-gate 		 */
357*0Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&be->result);
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 	return ((int)nss_result);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate /*
364*0Sstevel@tonic-gate  * getbyname gets struct servent values by service name. This
365*0Sstevel@tonic-gate  * function constructs an ldap search filter using the service
366*0Sstevel@tonic-gate  * name invocation parameter and the getservbyname search filter
367*0Sstevel@tonic-gate  * defined. Once the filter is constructed, we search for a matching
368*0Sstevel@tonic-gate  * entry and marshal the data results into *serv = (struct servent *)
369*0Sstevel@tonic-gate  * argp->buf.result. The function _nss_ldap_services2ent performs
370*0Sstevel@tonic-gate  * the data marshaling.
371*0Sstevel@tonic-gate  */
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate static nss_status_t
374*0Sstevel@tonic-gate getbyname(ldap_backend_ptr be, void *a)
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
377*0Sstevel@tonic-gate 	const char	*proto = argp->key.serv.proto;
378*0Sstevel@tonic-gate 	char		searchfilter[SEARCHFILTERLEN];
379*0Sstevel@tonic-gate 	char		userdata[SEARCHFILTERLEN];
380*0Sstevel@tonic-gate 	char		name[SEARCHFILTERLEN];
381*0Sstevel@tonic-gate 	char		protocol[SEARCHFILTERLEN];
382*0Sstevel@tonic-gate 	int		ret;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (_ldap_filter_name(name, argp->key.serv.serv.name, sizeof (name))
385*0Sstevel@tonic-gate 			!= 0)
386*0Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if (proto == NULL) {
389*0Sstevel@tonic-gate 		ret = snprintf(searchfilter, sizeof (searchfilter),
390*0Sstevel@tonic-gate 		    _F_GETSERVBYNAME, name);
391*0Sstevel@tonic-gate 		if (ret >= sizeof (searchfilter) || ret < 0)
392*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 		ret = snprintf(userdata, sizeof (userdata),
395*0Sstevel@tonic-gate 		    _F_GETSERVBYNAME_SSD, name);
396*0Sstevel@tonic-gate 		if (ret >= sizeof (userdata) || ret < 0)
397*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
398*0Sstevel@tonic-gate 	} else {
399*0Sstevel@tonic-gate 		if (_ldap_filter_name(protocol, proto, sizeof (protocol)) != 0)
400*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 		ret = snprintf(searchfilter, sizeof (searchfilter),
403*0Sstevel@tonic-gate 		    _F_GETSERVBYNAMEPROTO, name, protocol);
404*0Sstevel@tonic-gate 		if (ret >= sizeof (searchfilter) || ret < 0)
405*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 		ret = snprintf(userdata, sizeof (userdata),
408*0Sstevel@tonic-gate 		    _F_GETSERVBYNAMEPROTO_SSD, name, protocol);
409*0Sstevel@tonic-gate 		if (ret >= sizeof (userdata) || ret < 0)
410*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
411*0Sstevel@tonic-gate 	}
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
414*0Sstevel@tonic-gate 		_SERVICES, searchfilter, NULL,
415*0Sstevel@tonic-gate 		_merge_SSD_filter, userdata));
416*0Sstevel@tonic-gate }
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate /*
420*0Sstevel@tonic-gate  * getbyport gets struct servent values by service port. This
421*0Sstevel@tonic-gate  * function constructs an ldap search filter using the service
422*0Sstevel@tonic-gate  * name invocation parameter and the getservbyport search filter
423*0Sstevel@tonic-gate  * defined. Once the filter is constructed, we search for a matching
424*0Sstevel@tonic-gate  * entry and marshal the data results into *serv = (struct servent *)
425*0Sstevel@tonic-gate  * argp->buf.result. The function _nss_ldap_services2ent performs
426*0Sstevel@tonic-gate  * the data marshaling.
427*0Sstevel@tonic-gate  */
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate static nss_status_t
430*0Sstevel@tonic-gate getbyport(ldap_backend_ptr be, void *a)
431*0Sstevel@tonic-gate {
432*0Sstevel@tonic-gate 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
433*0Sstevel@tonic-gate 	const char	*proto = argp->key.serv.proto;
434*0Sstevel@tonic-gate 	char		portstr[12];
435*0Sstevel@tonic-gate 	char		searchfilter[SEARCHFILTERLEN];
436*0Sstevel@tonic-gate 	char		userdata[SEARCHFILTERLEN];
437*0Sstevel@tonic-gate 	char		protocol[SEARCHFILTERLEN];
438*0Sstevel@tonic-gate 	int		ret;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	ret = snprintf(portstr, sizeof (portstr), " %d",
441*0Sstevel@tonic-gate 	    ntohs((ushort_t)argp->key.serv.serv.port));
442*0Sstevel@tonic-gate 	if (ret >= sizeof (portstr) || ret < 0)
443*0Sstevel@tonic-gate 		return ((nss_status_t)NSS_NOTFOUND);
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (proto == NULL) {
446*0Sstevel@tonic-gate 		ret = snprintf(searchfilter, sizeof (searchfilter),
447*0Sstevel@tonic-gate 		    _F_GETSERVBYPORT, strtol(portstr, (char **)NULL, 10));
448*0Sstevel@tonic-gate 		if (ret >= sizeof (searchfilter) || ret < 0)
449*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 		ret = snprintf(userdata, sizeof (userdata),
452*0Sstevel@tonic-gate 		    _F_GETSERVBYPORT_SSD, strtol(portstr, (char **)NULL, 10));
453*0Sstevel@tonic-gate 		if (ret >= sizeof (userdata) || ret < 0)
454*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
455*0Sstevel@tonic-gate 	} else {
456*0Sstevel@tonic-gate 		if (_ldap_filter_name(protocol, proto, sizeof (protocol)) != 0)
457*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		ret = snprintf(searchfilter, sizeof (searchfilter),
460*0Sstevel@tonic-gate 		    _F_GETSERVBYPORTPROTO,
461*0Sstevel@tonic-gate 		    strtol(portstr, (char **)NULL, 10), protocol);
462*0Sstevel@tonic-gate 		if (ret >= sizeof (searchfilter) || ret < 0)
463*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		ret = snprintf(userdata, sizeof (userdata),
466*0Sstevel@tonic-gate 		    _F_GETSERVBYPORTPROTO_SSD,
467*0Sstevel@tonic-gate 		    strtol(portstr, (char **)NULL, 10), protocol);
468*0Sstevel@tonic-gate 		if (ret >= sizeof (userdata) || ret < 0)
469*0Sstevel@tonic-gate 			return ((nss_status_t)NSS_NOTFOUND);
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
473*0Sstevel@tonic-gate 		_SERVICES, searchfilter, NULL,
474*0Sstevel@tonic-gate 		_merge_SSD_filter, userdata));
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate static ldap_backend_op_t serv_ops[] = {
478*0Sstevel@tonic-gate     _nss_ldap_destr,
479*0Sstevel@tonic-gate     _nss_ldap_endent,
480*0Sstevel@tonic-gate     _nss_ldap_setent,
481*0Sstevel@tonic-gate     _nss_ldap_getent,
482*0Sstevel@tonic-gate     getbyname,
483*0Sstevel@tonic-gate     getbyport
484*0Sstevel@tonic-gate };
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate /*
488*0Sstevel@tonic-gate  * _nss_ldap_services_constr is where life begins. This function calls
489*0Sstevel@tonic-gate  * the generic ldap constructor function to define and build the
490*0Sstevel@tonic-gate  * abstract data types required to support ldap operations.
491*0Sstevel@tonic-gate  */
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate /*ARGSUSED0*/
494*0Sstevel@tonic-gate nss_backend_t *
495*0Sstevel@tonic-gate _nss_ldap_services_constr(const char *dummy1, const char *dummy2,
496*0Sstevel@tonic-gate 			const char *dummy3)
497*0Sstevel@tonic-gate {
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	return ((nss_backend_t *)_nss_ldap_constr(serv_ops,
500*0Sstevel@tonic-gate 		sizeof (serv_ops)/sizeof (serv_ops[0]), _SERVICES,
501*0Sstevel@tonic-gate 		services_attrs, _nss_ldap_services2ent));
502*0Sstevel@tonic-gate }
503