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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include "ns_internal.h"
31 #include "ldap_common.h"
33 /* services attributes filters */
35 #define _S_PORT "ipserviceport"
36 #define _S_PROTOCOL "ipserviceprotocol"
37 #define _F_GETSERVBYNAME "(&(objectClass=ipService)(cn=%s))"
38 #define _F_GETSERVBYNAME_SSD "(&(%%s)(cn=%s))"
39 #define _F_GETSERVBYNAMEPROTO \
40 "(&(objectClass=ipService)(cn=%s)(ipServiceProtocol=%s))"
41 #define _F_GETSERVBYNAMEPROTO_SSD \
42 "(&(%%s)(cn=%s)(ipServiceProtocol=%s))"
43 #define _F_GETSERVBYPORT "(&(objectClass=ipService)(ipServicePort=%ld))"
44 #define _F_GETSERVBYPORT_SSD "(&(%%s)(ipServicePort=%ld))"
45 #define _F_GETSERVBYPORTPROTO \
46 "(&(objectClass=ipService)(ipServicePort=%ld)(ipServiceProtocol=%s))"
47 #define _F_GETSERVBYPORTPROTO_SSD \
48 "(&(%%s)(ipServicePort=%ld)(ipServiceProtocol=%s))"
50 typedef struct _nss_services_cookie
{
51 int index
; /* index of ipserviceprotocol */
52 char *cname
; /* canonical name, don't free it */
53 ns_ldap_result_t
*result
;
54 } _nss_services_cookie_t
;
56 static const char *services_attrs
[] = {
64 _nss_services_cookie_free(void **ckP
) {
65 _nss_services_cookie_t
**cookieP
= (_nss_services_cookie_t
**)ckP
;
66 if (cookieP
&& *cookieP
) {
67 if ((*cookieP
)->result
)
68 (void) __ns_ldap_freeResult(&(*cookieP
)->result
);
74 static _nss_services_cookie_t
*
75 _nss_services_cookie_new(ns_ldap_result_t
*result
, int index
, char *cname
) {
77 _nss_services_cookie_t
*cookie
;
79 if ((cookie
= calloc(1, sizeof (*cookie
))) == NULL
)
83 * result has been allocated either by __ns_ldap_firstEntry
84 * or __ns_ldap_nextEntry.
86 cookie
->result
= result
;
88 cookie
->index
= index
;
89 cookie
->cname
= cname
;
94 * _nss_ldap_services2str is the data marshaling method for the services
95 * getXbyY * (e.g., getbyname(), getbyport(), getent()) backend processes.
96 * This method is called after a successful ldap search has been performed.
97 * This method will parse the ldap search values into the file format.
103 * In section 5.5 of RFC 2307, it specifies that a "services" LDAP entry
104 * containing multiple ipserviceprotocol values should be able to be mapped
105 * to multiple "services" entities. Code has been added to support
106 * this one to many mapping feature.
110 _nss_ldap_services2str(ldap_backend_ptr be
, nss_XbyY_args_t
*argp
)
115 char **ipport
, *cname
= NULL
, *protoval
= NULL
;
117 ns_ldap_result_t
*result
;
118 ns_ldap_attr_t
*names
= NULL
, *protocol
= NULL
;
119 _nss_services_cookie_t
*cookie
= (_nss_services_cookie_t
*)
124 * getservent_r with multiple protocol values and the entry
125 * is enumerated 2nd time or beyond
127 result
= cookie
->result
;
128 cname
= cookie
->cname
;
131 * getservbyname_r, getservbyport_r or
132 * getservent_r with single protocol value or multiple values
133 * and the entry is enumerated 1st time
137 if (result
== NULL
) {
138 nss_result
= NSS_STR_PARSE_PARSE
;
139 goto result_srvs2str
;
142 buflen
= argp
->buf
.buflen
;
143 if (argp
->buf
.result
!= NULL
) {
144 if ((be
->buffer
= calloc(1, buflen
)) == NULL
) {
145 nss_result
= NSS_STR_PARSE_PARSE
;
146 goto result_srvs2str
;
150 buffer
= argp
->buf
.buffer
;
153 nss_result
= NSS_STR_PARSE_SUCCESS
;
154 (void) memset(argp
->buf
.buffer
, 0, buflen
);
156 /* Get services names */
157 names
= __ns_ldap_getAttrStruct(result
->entry
, _S_NAME
);
158 if (names
== NULL
|| names
->attrvalue
== NULL
) {
159 nss_result
= NSS_STR_PARSE_PARSE
;
160 goto result_srvs2str
;
162 /* Get canonical services name */
164 cname
= __s_api_get_canonical_name(result
->entry
, names
, 1);
165 if (cname
== NULL
|| (len
= strlen(cname
)) < 1) {
166 nss_result
= NSS_STR_PARSE_PARSE
;
167 goto result_srvs2str
;
171 ipport
= __ns_ldap_getAttr(result
->entry
, _S_PORT
);
172 if (ipport
== NULL
|| ipport
[0] == NULL
||
173 (len
= strlen(cname
)) < 1) {
174 nss_result
= NSS_STR_PARSE_PARSE
;
175 goto result_srvs2str
;
177 /* Set services name and port and '/' */
178 len
= snprintf(buffer
, buflen
, "%s %s/", cname
, ipport
[0]);
179 TEST_AND_ADJUST(len
, buffer
, buflen
, result_srvs2str
);
182 protocol
= __ns_ldap_getAttrStruct(result
->entry
, _S_PROTOCOL
);
183 if (protocol
== NULL
|| protocol
->attrvalue
== NULL
) {
184 nss_result
= NSS_STR_PARSE_PARSE
;
185 goto result_srvs2str
;
191 * Get current value then increment index
193 protoval
= protocol
->attrvalue
[cookie
->index
++];
194 } else if (protocol
->value_count
> 1 && be
->setcalled
== 0 &&
195 argp
->key
.serv
.proto
) {
197 * getserverbyname_r and getservbyport_r
199 * If there are more than one value and
200 * it needs to match protocol too,
201 * iterate each value to find matching one.
203 for (k
= 0; k
< protocol
->value_count
; k
++) {
204 if (protocol
->attrvalue
[k
] == NULL
) {
205 nss_result
= NSS_STR_PARSE_PARSE
;
206 goto result_srvs2str
;
208 if (strcmp(protocol
->attrvalue
[k
],
209 argp
->key
.serv
.proto
) == 0) {
210 protoval
= protocol
->attrvalue
[k
];
216 * 1. getserverbyname_r and getservbyport_r
218 * It does not need to match protocol or
219 * ipserviceprotocol has single value,
220 * return the first one.
222 * 2. getservent_r with single ipserviceprotocol value
223 * or multiple values and the entry is
224 * enumerated 1st time, return the first one.
227 protoval
= protocol
->attrvalue
[0];
230 if (protoval
== NULL
|| (len
= strlen(protoval
)) < 1) {
231 nss_result
= NSS_STR_PARSE_PARSE
;
232 goto result_srvs2str
;
236 len
= snprintf(buffer
, buflen
, "%s", protoval
);
237 TEST_AND_ADJUST(len
, buffer
, buflen
, result_srvs2str
);
240 for (i
= 0; i
< names
->value_count
; i
++) {
241 if (names
->attrvalue
[i
] == NULL
) {
242 nss_result
= NSS_STR_PARSE_PARSE
;
243 goto result_srvs2str
;
245 /* Skip the canonical name */
246 if (strcmp(cname
, names
->attrvalue
[i
]) != 0) {
247 len
= snprintf(buffer
, buflen
, " %s",
248 names
->attrvalue
[i
]);
249 TEST_AND_ADJUST(len
, buffer
, buflen
, result_srvs2str
);
254 if (be
->enumcookie
!= NULL
&& cookie
== NULL
&&
255 protocol
->value_count
> 1) {
257 * getservent_r with multiple ipserviceprotocol values
258 * and the entry is enumerated 1st time
260 * Create cookie and save result in the cookie
261 * "attrvalue[0]" of ipserviceprotocol is returned,
262 * so it starts with index 1. Also save the canonical name.
264 be
->services_cookie
=
265 (void *)_nss_services_cookie_new(be
->result
, 1, cname
);
266 if (be
->services_cookie
== NULL
) {
267 nss_result
= NSS_STR_PARSE_PARSE
;
268 goto result_srvs2str
;
271 /* reset be->result so it won't get freed later */
275 /* The front end marshaller doesn't need to copy trailing nulls */
276 if (argp
->buf
.result
!= NULL
)
277 be
->buflen
= strlen(be
->buffer
);
282 * getservent_r with multiple ipserviceprotocol values and
283 * the entry is enumerated 2nd time or beyond
285 if (nss_result
!= NSS_STR_PARSE_SUCCESS
||
286 cookie
->index
>= protocol
->value_count
) {
288 * If it's an error case or it has iterated all
289 * ipservicesprotocol value(s) then free cookie and
293 _nss_services_cookie_free(
294 (void **)&be
->services_cookie
);
298 * getservbyname_r, getservbyport_r, or
299 * getservent_r with single value or can't create cookie
301 (void) __ns_ldap_freeResult(&be
->result
);
307 * getbyname gets struct servent values by service name. This
308 * function constructs an ldap search filter using the service
309 * name invocation parameter and the getservbyname search filter
310 * defined. Once the filter is constructed, we search for a matching
311 * entry and marshal the data results into *serv = (struct servent *)
312 * argp->buf.result. The function _nss_ldap_services2ent performs
313 * the data marshaling.
317 getbyname(ldap_backend_ptr be
, void *a
)
319 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)a
;
320 const char *proto
= argp
->key
.serv
.proto
;
321 char searchfilter
[SEARCHFILTERLEN
];
322 char userdata
[SEARCHFILTERLEN
];
323 char name
[SEARCHFILTERLEN
];
324 char protocol
[SEARCHFILTERLEN
];
327 if (_ldap_filter_name(name
, argp
->key
.serv
.serv
.name
, sizeof (name
))
329 return ((nss_status_t
)NSS_NOTFOUND
);
332 ret
= snprintf(searchfilter
, sizeof (searchfilter
),
333 _F_GETSERVBYNAME
, name
);
334 if (ret
>= sizeof (searchfilter
) || ret
< 0)
335 return ((nss_status_t
)NSS_NOTFOUND
);
337 ret
= snprintf(userdata
, sizeof (userdata
),
338 _F_GETSERVBYNAME_SSD
, name
);
339 if (ret
>= sizeof (userdata
) || ret
< 0)
340 return ((nss_status_t
)NSS_NOTFOUND
);
342 if (_ldap_filter_name(protocol
, proto
, sizeof (protocol
)) != 0)
343 return ((nss_status_t
)NSS_NOTFOUND
);
345 ret
= snprintf(searchfilter
, sizeof (searchfilter
),
346 _F_GETSERVBYNAMEPROTO
, name
, protocol
);
347 if (ret
>= sizeof (searchfilter
) || ret
< 0)
348 return ((nss_status_t
)NSS_NOTFOUND
);
350 ret
= snprintf(userdata
, sizeof (userdata
),
351 _F_GETSERVBYNAMEPROTO_SSD
, name
, protocol
);
352 if (ret
>= sizeof (userdata
) || ret
< 0)
353 return ((nss_status_t
)NSS_NOTFOUND
);
356 return ((nss_status_t
)_nss_ldap_lookup(be
, argp
,
357 _SERVICES
, searchfilter
, NULL
,
358 _merge_SSD_filter
, userdata
));
363 * getbyport gets struct servent values by service port. This
364 * function constructs an ldap search filter using the service
365 * name invocation parameter and the getservbyport search filter
366 * defined. Once the filter is constructed, we search for a matching
367 * entry and marshal the data results into *serv = (struct servent *)
368 * argp->buf.result. The function _nss_ldap_services2ent performs
369 * the data marshaling.
373 getbyport(ldap_backend_ptr be
, void *a
)
375 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)a
;
376 const char *proto
= argp
->key
.serv
.proto
;
378 char searchfilter
[SEARCHFILTERLEN
];
379 char userdata
[SEARCHFILTERLEN
];
380 char protocol
[SEARCHFILTERLEN
];
383 ret
= snprintf(portstr
, sizeof (portstr
), " %d",
384 ntohs((ushort_t
)argp
->key
.serv
.serv
.port
));
385 if (ret
>= sizeof (portstr
) || ret
< 0)
386 return ((nss_status_t
)NSS_NOTFOUND
);
389 ret
= snprintf(searchfilter
, sizeof (searchfilter
),
390 _F_GETSERVBYPORT
, strtol(portstr
, (char **)NULL
, 10));
391 if (ret
>= sizeof (searchfilter
) || ret
< 0)
392 return ((nss_status_t
)NSS_NOTFOUND
);
394 ret
= snprintf(userdata
, sizeof (userdata
),
395 _F_GETSERVBYPORT_SSD
, strtol(portstr
, (char **)NULL
, 10));
396 if (ret
>= sizeof (userdata
) || ret
< 0)
397 return ((nss_status_t
)NSS_NOTFOUND
);
399 if (_ldap_filter_name(protocol
, proto
, sizeof (protocol
)) != 0)
400 return ((nss_status_t
)NSS_NOTFOUND
);
402 ret
= snprintf(searchfilter
, sizeof (searchfilter
),
403 _F_GETSERVBYPORTPROTO
,
404 strtol(portstr
, (char **)NULL
, 10), protocol
);
405 if (ret
>= sizeof (searchfilter
) || ret
< 0)
406 return ((nss_status_t
)NSS_NOTFOUND
);
408 ret
= snprintf(userdata
, sizeof (userdata
),
409 _F_GETSERVBYPORTPROTO_SSD
,
410 strtol(portstr
, (char **)NULL
, 10), protocol
);
411 if (ret
>= sizeof (userdata
) || ret
< 0)
412 return ((nss_status_t
)NSS_NOTFOUND
);
415 return ((nss_status_t
)_nss_ldap_lookup(be
, argp
,
416 _SERVICES
, searchfilter
, NULL
,
417 _merge_SSD_filter
, userdata
));
420 static ldap_backend_op_t serv_ops
[] = {
431 * _nss_ldap_services_constr is where life begins. This function calls
432 * the generic ldap constructor function to define and build the
433 * abstract data types required to support ldap operations.
438 _nss_ldap_services_constr(const char *dummy1
, const char *dummy2
,
442 return ((nss_backend_t
*)_nss_ldap_constr(serv_ops
,
443 sizeof (serv_ops
)/sizeof (serv_ops
[0]), _SERVICES
,
444 services_attrs
, _nss_ldap_services2str
));