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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/param.h>
39 #include "ldap_parse.h"
40 #include "ldap_glob.h"
41 #include "ldap_attr.h"
42 #include "ldap_util.h"
44 #include "ldap_ruleval.h"
45 #include "nis_parse_ldap_conf.h"
49 * List of mapping structures in original (i.e., as in config file) order.
50 * Lined on the 'seqNext' field.
52 __nis_table_mapping_t
*ldapMappingSeq
= 0;
55 * Call the parser for the config file 'ldapConfFile', and command line
56 * attribute settings per 'ldapCLA'.
60 * -1 Config file stat/open or parse error
61 * 1 No mapping should be used.
64 parseConfig(char **ldapCLA
, char *ldapConfFile
) {
68 * Establish defaults for ldapDBTableMapping, so that we have
69 * valid values even if there's no mapping config to parse.
71 ldapDBTableMapping
.initTtlLo
= (3600-1800);
72 ldapDBTableMapping
.initTtlHi
= (3600+1800);
73 ldapDBTableMapping
.ttl
= 3600;
74 ldapDBTableMapping
.enumExpire
= 0;
75 ldapDBTableMapping
.fromLDAP
= FALSE
;
76 ldapDBTableMapping
.toLDAP
= FALSE
;
77 ldapDBTableMapping
.expire
= 0;
79 ret
= parse_ldap_migration((const char **)ldapCLA
, ldapConfFile
);
85 * Convert the linked list of __nis_table_mapping_t's (produced by the
86 * attribute parser) to the 'ldapMappingList', keyed on the objPath.
88 * Once this function has returned, the 'tlist' is invalid, and must
89 * not be used in any way.
92 linked2hash(__nis_table_mapping_t
*tlist
) {
93 __nis_hash_table_mt dbids
;
94 __nis_table_mapping_t
*t
, *told
, *x
, **seqNext
;
95 __nis_object_dn_t
*o
, *to
;
96 char *myself
= "linked2hash";
97 #ifdef NISDB_LDAP_DEBUG
98 char *selectDbid
= getenv("NISLDAPSELECTDBID");
101 #endif /* NISDB_LDAP_DEBUG */
107 /* proxyInfo.default_nis_domain must end in a dot */
109 int len
= slen(proxyInfo
.default_nis_domain
);
111 if (len
> 0 && proxyInfo
.default_nis_domain
[len
-1] != '.') {
112 char *domain
= am(myself
, len
+2);
114 (void) memcpy(domain
, proxyInfo
.default_nis_domain
,
117 domain
[len
+1] = '\0';
118 sfree(proxyInfo
.default_nis_domain
);
119 proxyInfo
.default_nis_domain
= domain
;
123 #ifdef NISDB_LDAP_DEBUG
124 for (nsdi
= 0, s
= selectDbid
; s
!= 0 && *s
!= '\0'; s
++) {
127 while (*s
!= ' ' && *s
!= '\0')
134 sdi
= am(myself
, nsdi
* sizeof (sdi
[0]));
136 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
137 "%s: Memory alloc failure for dbId selection",
140 for (i
= 0, s
= selectDbid
; *s
!= '\0'; s
++) {
142 sdi
[i
++] = selectDbid
;
143 while (*s
!= ' ' && *s
!= '\0')
155 #endif /* NISDB_LDAP_DEBUG */
157 __nis_init_hash_table(&dbids
, 0);
159 seqNext
= &ldapMappingSeq
;
160 for (t
= tlist
; t
!= 0; t
= told
) {
163 #ifdef NISDB_LDAP_DEBUG
165 * If the dbId doesn't match 'selectDbid', skip this
166 * mapping. Re-insert on 'tlist', in order to keep memory
167 * leak checking happy. Note that 'tlist' may end up pointing
168 * into the real mapping list, so it shouldn't be used once
169 * this routine has been called.
172 for (i
= 0; i
< nsdi
; i
++) {
173 if (strcmp(sdi
[i
], t
->dbId
) == 0)
186 #endif /* NISDB_LDAP_DEBUG */
191 /* Make sure t->item.name is set correctly */
192 if (t
->item
.name
== 0)
193 t
->item
.name
= t
->dbId
;
195 /* Remove leading dot in object name, if any */
196 len
= slen(t
->objName
);
197 while (len
> 0 && t
->objName
[0] == '.') {
198 (void) memmove(t
->objName
, &t
->objName
[1], len
);
203 * Initialize the object path, which is what we'll
207 t
->objPath
= internal_table_name(t
->objName
,
210 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
211 "%s: Failed to obtain internal table name for \"%s\"",
216 t
->objPath
= am(myself
, len
+ MAXPATHLEN
+ 1);
219 if (internal_table_name(t
->objName
,
221 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
222 "%s: Failed to obtain internal table name for \"%s\"",
229 * Initialize the column name array.
232 if (setColumnsDuringConfig
&& setColumnNames(t
)) {
233 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
234 "%s: Unable to find column names for \"%s\"",
235 myself
, NIL(t
->objName
));
241 * If there are multiple mapping target containers, make
242 * each one into it's own mapping structure. They can all
243 * be minimal copies (i.e., share pointers to sub-structures
244 * other than the objectDN).
246 * If objectDN is NULL, we will never use this structure.
247 * In order to allow the rest of the mapping code to assume
248 * objectDN != NULL, skip the mapping (even if x == t).
250 for (o
= to
= t
->objectDN
; o
!= 0; o
= o
->next
) {
251 __nis_table_mapping_t
*p
;
256 * Only insert the first mapping for an
257 * object on the sequential list.
261 seqNext
= (__nis_table_mapping_t
**)&t
->seqNext
;
263 x
= am(myself
, sizeof (*x
));
266 * This happens during rpc.nisd
267 * initialization, and it's an
268 * unrecoverable disaster, so don't
269 * bother cleaning up.
273 memcpy(x
, t
, sizeof (*x
));
279 * If x->objectDN->write.base is NULL, clone it from
280 * x->objectDN->read.base.
282 if (x
->objectDN
->write
.scope
!= LDAP_SCOPE_UNKNOWN
) {
283 if (x
->objectDN
->write
.base
== 0 &&
284 x
->objectDN
->read
.base
!= 0) {
285 x
->objectDN
->write
.base
=
287 x
->objectDN
->read
.base
);
288 if (x
->objectDN
->write
.base
== 0)
291 if (x
->objectDN
->write
.attrs
== 0 &&
292 x
->objectDN
->read
.attrs
!= 0) {
293 x
->objectDN
->write
.attrs
=
295 x
->objectDN
->read
.attrs
);
296 if (x
->objectDN
->write
.attrs
== 0)
302 /* Insert last on the 't->next' list */
303 for (p
= t
; p
->next
!= 0; p
= p
->next
);
308 /* Insert on dbid hash list */
309 if (t
->objectDN
!= 0 && !__nis_insert_item_mt(t
, &dbids
, 0)) {
310 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
311 "%s: Error inserting mapping for \"%s\" on hash list",
312 myself
, NIL(t
->objName
));
313 #ifdef NISDB_LDAP_DEBUG
315 #endif /* NISDB_LDAP_DEBUG */
321 * dbids2objs() will remove the entries on 'dbids', so no need
322 * to clean up that list from this function.
324 return (dbids2objs(&dbids
, &ldapMappingList
));
328 dbids2objs(__nis_hash_table_mt
*dbids
, __nis_hash_table_mt
*objs
) {
329 __nis_table_mapping_t
*t
, *o
;
330 char *myself
= "dbids2objs";
333 while ((t
= __nis_pop_item_mt(dbids
)) != 0) {
334 /* Previous entry for this object ? */
335 o
= __nis_find_item_mt(t
->objPath
, objs
, -1, 0);
337 __nis_table_mapping_t
*p
= o
;
339 * Mapping already exists, so this is an alternate.
340 * Find the end of the list of any previous alt's,
343 while (p
->next
!= 0) {
347 if (!__nis_release_item(o
, objs
, -1)) {
348 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
349 "%s: __nis_release_item error",
354 t
->item
.name
= t
->objPath
;
355 if (!__nis_insert_item_mt(t
, objs
, 0)) {
356 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
357 "%s: __nis_insert_item error",
368 * internal_table_name()
370 * Removes the local domain part from a fully qualified name
371 * to create the internal table name for an object. These tables are
372 * stored in /var/nis/<hostname>
374 * Imported from rpc.nisd/nisdb.c.
377 internal_table_name(nis_name name
, char *res
)
385 res
= s_strndup(name
, strlen(name
));
393 /* pointer at the first character of the table name */
394 s
= relative_name(name
);
397 * If s == NULL then either this is a request for a lookup
398 * in our parents namespace (ILLEGAL), or we're the root
399 * server and this is a lookup in our namespace.
405 t
= strrchr(res
, '/');
407 t
++; /* Point past the slash */
408 /* Strip off the quotes if they were used here. */
410 /* Check for simply a quoted quote. */
413 /* shift string left by one */
414 for (i
= 0; i
< j
; i
++)
416 t
[j
-2] = '\0'; /* Trounce trailing dquote */
420 * OK so now we have the unique name for the table.
421 * At this point we can fix it up to match local
422 * file system conventions if we so desire. Since it
423 * is only used in this form by _this_ server we can
424 * mangle it any way we want, as long as we are consistent
434 * This function makes the table name "legal" for the underlying file system.
436 * Imported from rpc.nisd/nisdb.c.
439 __make_legal(char *s
)
450 * This internal function will remove from the NIS name, the domain
451 * name of the current server, this will leave the unique part in
452 * the name this becomes the "internal" version of the name. If this
453 * function returns NULL then the name we were given to resolve is
456 * A dynamically-allocated string is returned.
458 * Imported from rpc.nisd/nis_log_common.c
463 char *s
; /* string with the name in it. */
473 d
= __nis_rpc_domain();
476 dl
= strlen(d
); /* _always dot terminated_ */
481 strcpy(buf
, s
); /* Make a private copy of 's' */
484 if (dl
== 1) { /* We're the '.' directory */
485 buf
[sl
-1] = '\0'; /* Lose the 'dot' */
489 p
= nis_dir_cmp(buf
, d
);
491 /* 's' is above 'd' in the tree */
492 if ((p
== HIGHER_NAME
) || (p
== NOT_SEQUENTIAL
) || (p
== SAME_NAME
)) {
497 /* Insert a NUL where the domain name starts in the string */
498 buf
[(sl
- dl
) - 1] = '\0';
500 /* Don't return a zero length name */
501 if (buf
[0] == '\0') {
510 * Wrapper for internal_table_name() that allocates a large enough
511 * buffer for the internal name. Return value must be freed by caller.
512 * If the input 'name' is NULL, the name of the root directory table
516 internalTableName(char *name
) {
518 char *myself
= "internalTableName";
520 buf
= (char *)am(myself
, MAXPATHLEN
+ NIS_MAXNAMELEN
+ 1);
525 (void) memcpy(buf
, ROOTDIRFILE
, slen(ROOTDIRFILE
));
529 res
= internal_table_name(name
, buf
);
539 * Return the object mapping for the object indicated either by the
540 * internal DB name ('intNameArg'; preferred), or the FQ object name
541 * 'name'. If 'asObj' is non-zero, the caller is interested in the
542 * object mapping proper, not a mapping of table entries. Optionally,
543 * also indicate if the object is mapped from (read) or to (write) LDAP.
545 * Note that there may be more than one mapping of the appropriate type.
546 * Use the selectTableMapping() function in ldap_map.c to get all
547 * alternatives. However, the function below works as a short-cut if:
549 * You only want an indication that _a_ mapping of the desired
552 * You want the non-objectDN information for an object-mapping
553 * proper (i.e., _not_ the mapping for entries in a table).
555 __nis_table_mapping_t
*
556 getObjMapping(char *name
, char *intNameArg
, int asObj
,
557 int *doRead
, int *doWrite
) {
558 __nis_table_mapping_t
*t
, *x
;
560 int freeIntName
= 0, rd
, wr
;
567 if (intNameArg
== 0) {
570 intName
= internalTableName(name
);
575 intName
= intNameArg
;
578 t
= __nis_find_item_mt(intName
, &ldapMappingList
, 0, 0);
586 for (x
= t
; x
!= 0; x
= x
->next
) {
588 * If we're looking for an object mapping, and this
589 * one's for entries in a table, skip it.
591 if (asObj
&& x
->objType
== NIS_TABLE_OBJ
&&
594 /* Check if we should read/write */
595 if (x
->objectDN
->read
.scope
!= LDAP_SCOPE_UNKNOWN
)
597 if (x
->objectDN
->write
.scope
!= LDAP_SCOPE_UNKNOWN
)
602 *doRead
= (rd
> 0) ? 1 : 0;
604 *doWrite
= (wr
> 0) ? 1 : 0;