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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include "ldap_common.h"
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/yp_prot.h>
37 /* getent attributes filters */
38 #define _F_GETALIASENT "(objectClass=rfc822MailGroup)"
39 #define _F_GETAUTHNAME "(objectClass=SolarisAuthAttr)"
40 #define _F_GETAUUSERNAME "(objectClass=SolarisAuditUser)"
41 #define _F_GETEXECNAME "(objectClass=SolarisExecAttr)"
42 #define _F_GETGRENT "(objectClass=posixGroup)"
43 #define _F_GETHOSTENT "(objectClass=ipHost)"
44 #define _F_GETNETENT "(objectClass=ipNetwork)"
45 #define _F_GETPROFNAME \
46 "(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))"
47 #define _F_GETPROTOENT "(objectClass=ipProtocol)"
48 #define _F_GETPWENT "(objectClass=posixAccount)"
49 #define _F_GETPRINTERENT "(objectClass=sunPrinter)"
50 #define _F_GETRPCENT "(objectClass=oncRpc)"
51 #define _F_GETSERVENT "(objectClass=ipService)"
52 #define _F_GETSPENT "(objectclass=shadowAccount)"
53 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)"
54 #define _F_GETPROJENT "(objectClass=SolarisProject)"
55 #define _F_GETENT_SSD "(%s)"
57 /* getent sort attributes */
59 #define _A_GIDNUMBER "gidnumber"
61 #define _A_IPNETWORKNUM "ipnetworknumber"
62 #define _A_PROJECTNAM "SolarisProjectName"
64 static struct gettablefilter
{
68 } gettablefilterent
[] = {
69 {(char *)_PASSWD
, (char *)_F_GETPWENT
, (char *)_A_UID
},
70 {(char *)_SHADOW
, (char *)_F_GETSPENT
, (char *)_A_UID
},
71 {(char *)_GROUP
, (char *)_F_GETGRENT
, (char *)_A_GIDNUMBER
},
72 {(char *)_HOSTS
, (char *)_F_GETHOSTENT
, (char *)_A_CN
},
73 {(char *)_NETWORKS
, (char *)_F_GETNETENT
,
74 (char *)_A_IPNETWORKNUM
},
75 {(char *)_PROTOCOLS
, (char *)_F_GETPROTOENT
, (char *)_A_CN
},
76 {(char *)_RPC
, (char *)_F_GETRPCENT
, (char *)_A_CN
},
77 {(char *)_ALIASES
, (char *)_F_GETALIASENT
, (char *)_A_CN
},
78 {(char *)_SERVICES
, (char *)_F_GETSERVENT
, (char *)_A_CN
},
79 {(char *)_AUUSER
, (char *)_F_GETAUUSERNAME
,
81 {(char *)_AUTHATTR
, (char *)_F_GETAUTHNAME
, (char *)_A_CN
},
82 {(char *)_EXECATTR
, (char *)_F_GETEXECNAME
, (char *)_A_CN
},
83 {(char *)_PROFATTR
, (char *)_F_GETPROFNAME
, (char *)_A_CN
},
84 {(char *)_USERATTR
, (char *)_F_GETUSERNAME
, (char *)_A_UID
},
85 {(char *)_PROJECT
, (char *)_F_GETPROJENT
, (char *)_A_PROJECTNAM
},
86 {(char *)_PRINTERS
, (char *)_F_GETPRINTERENT
, (char *)_A_CN
},
87 {(char *)NULL
, (char *)NULL
, (char *)NULL
}
92 switch_err(int rc
, ns_ldap_error_t
*error
)
98 case NS_LDAP_NOTFOUND
:
99 return (NSS_NOTFOUND
);
101 case NS_LDAP_PARTIAL
:
102 return (NSS_TRYAGAIN
);
104 case NS_LDAP_INTERNAL
:
105 if (error
&& (error
->status
== LDAP_SERVER_DOWN
||
106 error
->status
== LDAP_TIMEOUT
))
107 return (NSS_TRYAGAIN
);
109 return (NSS_UNAVAIL
);
112 return (NSS_UNAVAIL
);
117 _nss_ldap_lookup(ldap_backend_ptr be
, nss_XbyY_args_t
*argp
,
118 char *database
, char *searchfilter
, char *domain
,
119 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
120 char **realfilter
, const void *userdata
),
121 const void *userdata
)
123 int callbackstat
= 0;
124 ns_ldap_error_t
*error
= NULL
;
128 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_lookup]\n");
129 (void) fprintf(stdout
, "\tsearchfilter: %s\n", searchfilter
);
130 (void) fprintf(stdout
,
131 "\tuserdata: %s\n", userdata
? userdata
: "NULL");
132 (void) fprintf(stdout
, "\tdatabase: %s\n", database
);
135 (void) __ns_ldap_freeResult(&be
->result
);
137 if ((rc
= __ns_ldap_list(database
, searchfilter
, init_filter_cb
,
138 be
->attrs
, NULL
, 0, &be
->result
, &error
, NULL
,
139 userdata
)) != NS_LDAP_SUCCESS
) {
141 rc
= switch_err(rc
, error
);
142 (void) __ns_ldap_freeError(&error
);
146 (void) __ns_ldap_freeError(&error
);
147 /* callback function */
149 be
->ldapobj2str(be
, argp
)) != NSS_STR_PARSE_SUCCESS
) {
154 * publickey does not have a front end marshaller and expects
155 * a string to be returned in NSS.
156 * No need to convert file format -> struct.
159 if (be
->db_type
== NSS_LDAP_DB_PUBLICKEY
) {
160 argp
->returnval
= argp
->buf
.buffer
;
161 argp
->returnlen
= strlen(argp
->buf
.buffer
);
162 be
->db_type
= NSS_LDAP_DB_NONE
;
163 return (NSS_SUCCESS
);
166 * Assume the switch engine wants the returned data in the file
167 * format when argp->buf.result == NULL.
168 * The front-end marshaller str2ether(ethers) uses
169 * ent (argp->buf.result) and buffer (argp->buf.buffer)
170 * for different purpose so ethers has to be treated differently.
172 if (argp
->buf
.result
!= NULL
||
173 be
->db_type
== NSS_LDAP_DB_ETHERS
) {
174 /* file format -> struct */
175 if (argp
->str2ent
== NULL
) {
176 callbackstat
= NSS_STR_PARSE_PARSE
;
180 callbackstat
= (*argp
->str2ent
)(be
->buffer
,
185 if (callbackstat
== NSS_STR_PARSE_SUCCESS
) {
186 if (be
->db_type
== NSS_LDAP_DB_ETHERS
&&
187 argp
->buf
.buffer
!= NULL
) {
188 argp
->returnval
= argp
->buf
.buffer
;
189 argp
->returnlen
= strlen(argp
->buf
.buffer
);
191 argp
->returnval
= argp
->buf
.result
;
192 argp
->returnlen
= 1; /* irrelevant */
194 if (be
->buffer
!= NULL
) {
198 be
->db_type
= NSS_LDAP_DB_NONE
;
200 return ((nss_status_t
)NSS_SUCCESS
);
203 /* return file format in argp->buf.buffer */
204 argp
->returnval
= argp
->buf
.buffer
;
205 argp
->returnlen
= strlen(argp
->buf
.buffer
);
206 return ((nss_status_t
)NSS_SUCCESS
);
210 if (be
->buffer
!= NULL
) {
214 be
->db_type
= NSS_LDAP_DB_NONE
;
217 if (callbackstat
== NSS_STR_PARSE_PARSE
) {
219 return ((nss_status_t
)NSS_NOTFOUND
);
221 if (callbackstat
== NSS_STR_PARSE_ERANGE
) {
223 return ((nss_status_t
)NSS_NOTFOUND
);
225 if (callbackstat
== NSS_STR_PARSE_NO_ADDR
) {
226 /* No IPV4 address is found */
227 argp
->h_errno
= HOST_NOT_FOUND
;
228 return ((nss_status_t
)NSS_NOTFOUND
);
230 return ((nss_status_t
)NSS_UNAVAIL
);
234 * This function is similar to _nss_ldap_lookup except it does not
235 * do a callback. It is only used by getnetgrent.c
240 _nss_ldap_nocb_lookup(ldap_backend_ptr be
, nss_XbyY_args_t
*argp
,
241 char *database
, char *searchfilter
, char *domain
,
242 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
243 char **realfilter
, const void *userdata
),
244 const void *userdata
)
246 ns_ldap_error_t
*error
= NULL
;
250 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n");
251 (void) fprintf(stdout
, "\tsearchfilter: %s\n", searchfilter
);
252 (void) fprintf(stdout
, "\tdatabase: %s\n", database
);
253 (void) fprintf(stdout
,
254 "\tuserdata: %s\n", userdata
? userdata
: "NULL");
257 (void) __ns_ldap_freeResult(&be
->result
);
259 if ((rc
= __ns_ldap_list(database
, searchfilter
, init_filter_cb
,
260 be
->attrs
, NULL
, 0, &be
->result
, &error
, NULL
,
261 userdata
)) != NS_LDAP_SUCCESS
) {
264 rc
= switch_err(rc
, error
);
265 (void) __ns_ldap_freeError(&error
);
269 return ((nss_status_t
)NSS_SUCCESS
);
278 _clean_ldap_backend(ldap_backend_ptr be
)
280 ns_ldap_error_t
*error
;
283 (void) fprintf(stdout
, "\n[ldap_common.c: _clean_ldap_backend]\n");
287 if (be
->result
!= NULL
)
288 (void) __ns_ldap_freeResult(&be
->result
);
289 if (be
->enumcookie
!= NULL
)
290 (void) __ns_ldap_endEntry(&be
->enumcookie
, &error
);
291 if (be
->services_cookie
!= NULL
)
292 _nss_services_cookie_free((void **)&be
->services_cookie
);
293 if (be
->toglue
!= NULL
) {
297 if (be
->buffer
!= NULL
) {
306 * _nss_ldap_destr will free all smalloc'ed variable strings and structures
307 * before exiting this nsswitch shared backend library. This function is
308 * called before returning control back to nsswitch.
313 _nss_ldap_destr(ldap_backend_ptr be
, void *a
)
317 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_destr]\n");
320 (void) _clean_ldap_backend(be
);
322 return ((nss_status_t
)NSS_SUCCESS
);
327 * _nss_ldap_setent called before _nss_ldap_getent. This function is
332 _nss_ldap_setent(ldap_backend_ptr be
, void *a
)
334 struct gettablefilter
*gtf
;
337 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_setent]\n");
340 if (be
->setcalled
== 1)
341 (void) _nss_ldap_endent(be
, a
);
344 for (gtf
= gettablefilterent
; gtf
->tablename
!= (char *)NULL
; gtf
++) {
345 if (strcmp(gtf
->tablename
, be
->tablename
))
347 be
->filter
= (char *)gtf
->tablefilter
;
348 be
->sortattr
= (char *)gtf
->sortattr
;
353 be
->enumcookie
= NULL
;
355 be
->services_cookie
= NULL
;
357 return ((nss_status_t
)NSS_SUCCESS
);
362 * _nss_ldap_endent called after _nss_ldap_getent. This function is
368 _nss_ldap_endent(ldap_backend_ptr be
, void *a
)
370 ns_ldap_error_t
*error
= NULL
;
373 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_endent]\n");
379 if (be
->enumcookie
!= NULL
) {
380 (void) __ns_ldap_endEntry(&be
->enumcookie
, &error
);
381 (void) __ns_ldap_freeError(&error
);
383 if (be
->result
!= NULL
) {
384 (void) __ns_ldap_freeResult(&be
->result
);
386 if (be
->services_cookie
!= NULL
) {
387 _nss_services_cookie_free((void **)&be
->services_cookie
);
389 if (be
->buffer
!= NULL
) {
394 return ((nss_status_t
)NSS_SUCCESS
);
403 _nss_ldap_getent(ldap_backend_ptr be
, void *a
)
405 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)a
;
406 ns_ldap_error_t
*error
= NULL
;
411 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_getent]\n");
414 if (be
->setcalled
== 0)
415 (void) _nss_ldap_setent(be
, a
);
418 if (be
->enumcookie
== NULL
) {
419 retcode
= __ns_ldap_firstEntry(be
->tablename
,
420 be
->filter
, be
->sortattr
, _merge_SSD_filter
, be
->attrs
,
421 NULL
, 0, &be
->enumcookie
,
422 &be
->result
, &error
, _F_GETENT_SSD
);
424 if (be
->services_cookie
== NULL
) {
425 retcode
= __ns_ldap_nextEntry(be
->enumcookie
,
426 &be
->result
, &error
);
429 if (retcode
!= NS_LDAP_SUCCESS
) {
430 retcode
= switch_err(retcode
, error
);
431 (void) __ns_ldap_freeError(&error
);
432 (void) _nss_ldap_endent(be
, a
);
436 if (be
->result
== NULL
) {
437 parsestat
= NSS_STR_PARSE_NO_RESULT
;
440 /* ns_ldap_entry_t -> file format */
441 if ((parsestat
= be
->ldapobj2str(be
, argp
))
442 == NSS_STR_PARSE_SUCCESS
) {
443 if (argp
->buf
.result
!= NULL
) {
444 /* file format -> struct */
445 if (argp
->str2ent
== NULL
) {
446 parsestat
= NSS_STR_PARSE_NO_RESULT
;
449 parsestat
= (*argp
->str2ent
)(be
->buffer
,
454 if (parsestat
== NSS_STR_PARSE_SUCCESS
) {
455 if (be
->buffer
!= NULL
) {
461 argp
->returnval
= argp
->buf
.result
;
462 argp
->returnlen
= 1; /* irrevelant */
463 return ((nss_status_t
)NSS_SUCCESS
);
467 * nscd is not caching the enumerated
468 * entries. This code path would be dormant.
469 * Keep this path for the future references.
471 argp
->returnval
= argp
->buf
.buffer
;
473 strlen(argp
->buf
.buffer
) + 1;
477 if (be
->buffer
!= NULL
) {
483 if (parsestat
== NSS_STR_PARSE_NO_RESULT
) {
485 (void) _nss_ldap_endent(be
, a
);
486 return ((nss_status_t
)NSS_NOTFOUND
);
489 if (parsestat
== NSS_STR_PARSE_ERANGE
) {
491 (void) _nss_ldap_endent(be
, a
);
492 return ((nss_status_t
)NSS_NOTFOUND
);
494 if (parsestat
== NSS_STR_PARSE_NO_ADDR
)
496 * No IPV4 address is found in the current entry.
497 * It indicates that the entry contains IPV6 addresses
498 * only. Instead of calling _nss_ldap_endent to
499 * terminate, get next entry to continue enumeration.
500 * If it returned NSS_NOTFOUND here,
501 * gethostent() would return NULL
502 * and the enumeration would stop prematurely.
506 if (parsestat
== NSS_STR_PARSE_PARSE
)
508 * There has been a parse error. Most likely some
509 * mandatory attributes are missing. Ignore the error
510 * and get the next entry. If we returned an error the
511 * enumeration would stop prematurely.
515 return ((nss_status_t
)NSS_SUCCESS
);
524 _nss_ldap_constr(ldap_backend_op_t ops
[], int nops
, char *tablename
,
525 const char **attrs
, fnf ldapobj2str
)
530 (void) fprintf(stdout
, "\n[ldap_common.c: _nss_ldap_constr]\n");
533 if ((be
= (ldap_backend_ptr
) calloc(1, sizeof (*be
))) == 0)
536 be
->nops
= (nss_dbop_t
)nops
;
537 be
->tablename
= (char *)strdup(tablename
);
539 be
->ldapobj2str
= ldapobj2str
;
541 return ((nss_backend_t
*)be
);
549 chophostdomain(char *string
, char *host
, char *domain
)
556 if ((dot
= strchr(string
, '.')) == NULL
) {
560 (void) strcpy(host
, string
);
561 (void) strcpy(domain
, ++dot
);
571 propersubdomain(char *domain
, char *subdomain
)
573 int domainlen
, subdomainlen
;
576 if (domain
== NULL
|| subdomain
== NULL
)
579 domainlen
= strlen(domain
);
580 subdomainlen
= strlen(subdomain
);
582 /* is afterdot a substring of domain? */
583 if ((strncasecmp(domain
, subdomain
, subdomainlen
)) != 0)
586 if (domainlen
== subdomainlen
)
589 if (subdomainlen
> domainlen
)
592 if (*(domain
+ subdomainlen
) != '.')