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 2015 Gary Mills
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
27 * DESCRIPTION: Contains dit_access interface support functions.
29 #include <sys/systeminfo.h>
32 #include <sys/types.h>
34 #include <sys/systeminfo.h>
42 #include "../ldap_util.h"
43 #include "../ldap_map.h"
44 #include "../ldap_parse.h"
45 #include "../ldap_structs.h"
46 #include "../ldap_val.h"
47 #include "../ldap_ruleval.h"
48 #include "../ldap_op.h"
49 #include "../ldap_attr.h"
50 #include "../ldap_nisdbquery.h"
51 #include "../nisdb_mt.h"
54 #include "dit_access_utils.h"
56 #define YPMULTI "YP_MULTI_"
57 #define YPMULTISZ 9 /* == strlen(YPMULTI) */
60 * Returns 'map,domain.'
63 getFullMapName(char *map
, char *domain
) {
64 char *myself
= "getFullMapName";
66 if (map
== 0 || domain
== 0) {
69 objPath
= scat(myself
, T
, scat(myself
, F
, map
, ","),
70 scat(myself
, F
, domain
, "."));
76 * Convert string to __nis_value_t
78 __nis_value_t
*stringToValue(char *dptr
, int dsize
) {
79 char *myself
= "stringToValue";
83 if ((val
= am(myself
, sizeof (*val
))) == 0) {
87 val
->type
= vt_string
;
90 if ((val
->val
= am(myself
, sizeof (val
->val
[0]))) == 0) {
96 * Null strings or strings with length 0 are treated
97 * as empty strings with length 1
99 if (dptr
== 0 || dsize
<= 0) {
104 val
->val
->length
= dsize
;
105 if (dptr
[dsize
- 1] != '\0') {
106 val
->val
->length
= dsize
+ 1;
109 val
->val
->value
= am(myself
, val
->val
->length
);
110 if (val
->val
->value
== 0) {
114 (void) memcpy(val
->val
->value
, dptr
, dsize
);
120 * Returns an array of rule-values corresponding to the
124 processSplitField(__nis_table_mapping_t
*sf
, __nis_value_t
*inVal
,
125 int *nv
, int *statP
) {
128 __nis_rule_value_t
*rvq
;
129 __nis_value_t
**valA
, *tempVal
;
130 int i
, j
, res
, numVals
, oldlen
, count
;
133 /* sf will be non NULL */
135 if (inVal
== 0 || inVal
->type
!= vt_string
) {
136 *statP
= MAP_PARAM_ERROR
;
140 /* Get the separator list */
141 sepset
= sf
->separatorStr
;
143 /* Initialize rule-value */
147 if ((tempVal
= stringToValue(inVal
->val
->value
,
148 inVal
->val
->length
)) == 0) {
149 *statP
= MAP_NO_MEMORY
;
153 str
= oldstr
= tempVal
->val
->value
;
154 oldlen
= tempVal
->val
->length
;
157 tempVal
->val
->value
= str
;
158 tempVal
->val
->length
= strlen(str
) + 1;
160 /* Loop to check which format matches str */
161 for (i
= 0; i
<= sf
->numSplits
; i
++) {
162 valA
= matchMappingItem(sf
->e
[i
].element
.match
.fmt
,
163 tempVal
, &numVals
, sepset
, &str
);
165 /* The format didn't match. Try the next one */
170 * If we are here means we had a match.
171 * Each new set of values obtained from the match is
172 * added to a new rule-value. This is to preserve the
173 * the distinction between each set.
175 rvq
= growRuleValue(count
, count
+ 1, rvq
, 0);
177 *statP
= MAP_INTERNAL_ERROR
;
178 for (j
= 0; j
< numVals
; j
++)
179 freeValue(valA
[j
], 1);
181 tempVal
->val
->value
= oldstr
;
182 tempVal
->val
->length
= oldlen
;
183 freeValue(tempVal
, 1);
188 for (j
= 0; j
< numVals
; j
++) {
189 res
= addCol2RuleValue(vt_string
,
190 sf
->e
[i
].element
.match
.item
[j
].name
,
192 valA
[j
]->val
->length
,
195 *statP
= MAP_INTERNAL_ERROR
;
196 for (; j
< numVals
; j
++)
197 freeValue(valA
[j
], 1);
199 tempVal
->val
->value
= oldstr
;
200 tempVal
->val
->length
= oldlen
;
201 freeValue(tempVal
, 1);
202 freeRuleValue(rvq
, count
);
205 freeValue(valA
[j
], 1);
210 * Since we had a match, break out of this loop
211 * to parse remainder of str
216 /* Didn't find any match, so get out of the loop */
217 if (i
> sf
->numSplits
) {
222 /* Skip the separators before looping back */
224 str
= str
+ strspn(str
, sepset
);
230 tempVal
->val
->value
= oldstr
;
231 tempVal
->val
->length
= oldlen
;
232 freeValue(tempVal
, 1);
235 freeRuleValue(rvq
, count
);
246 * Convert the datum to an array of RuleValues
249 datumToRuleValue(datum
*key
, datum
*value
, __nis_table_mapping_t
*t
,
250 int *nv
, char *domain
, bool_t readonly
, int *statP
) {
252 __nis_rule_value_t
*rvq
, *subrvq
, *newrvq
;
254 __nis_value_t
**valA
;
255 __nis_table_mapping_t
*sf
;
256 int valueLen
, comLen
, numVals
, nr
, count
= 1;
258 char *ipaddr
, *ipvalue
;
260 /* At this point, 't' is always non NULL */
262 /* Initialize rule-value */
263 if ((rvq
= initRuleValue(1, 0)) == 0) {
264 *statP
= MAP_INTERNAL_ERROR
;
268 /* Add domainname to rule-value */
269 if (addCol2RuleValue(vt_string
, N2LDOMAIN
, domain
, strlen(domain
),
271 freeRuleValue(rvq
, 1);
272 *statP
= MAP_INTERNAL_ERROR
;
278 /* Add field=value pair for N2LKEY */
279 i
= addCol2RuleValue(vt_string
, N2LKEY
, key
->dptr
, key
->dsize
,
282 /* For readonly, add field=value pair for N2LSEARCHKEY */
283 if (readonly
== TRUE
&& i
== 0) {
284 i
= addCol2RuleValue(vt_string
, N2LSEARCHKEY
, key
->dptr
,
288 freeRuleValue(rvq
, 1);
289 *statP
= MAP_INTERNAL_ERROR
;
293 /* Add field=value pairs for IP addresses */
294 if (checkIPaddress(key
->dptr
, key
->dsize
, &ipaddr
) > 0) {
295 /* If key is IPaddress, use preferred format */
297 valueLen
= strlen(ipaddr
);
298 i
= addCol2RuleValue(vt_string
, N2LIPKEY
, ipvalue
,
301 /* If not, use original value for N2LSEARCHIPKEY */
304 valueLen
= key
->dsize
;
308 if (readonly
== TRUE
&& i
== 0) {
309 i
= addCol2RuleValue(vt_string
, N2LSEARCHIPKEY
, ipvalue
,
314 freeRuleValue(rvq
, 1);
315 *statP
= MAP_INTERNAL_ERROR
;
320 /* Handle datum value */
321 if (value
!= 0 && t
->e
) {
322 valueLen
= value
->dsize
;
324 * Extract the comment, if any, and add it to
327 if (t
->commentChar
!= '\0') {
329 * We loop on value->dsize because value->dptr
330 * may not be NULL-terminated.
332 for (i
= 0; i
< value
->dsize
; i
++) {
333 if (value
->dptr
[i
] == t
->commentChar
) {
335 comLen
= value
->dsize
- i
- 1;
338 if (addCol2RuleValue(vt_string
,
339 N2LCOMMENT
, value
->dptr
+ i
+ 1,
341 freeRuleValue(rvq
, 1);
342 *statP
= MAP_INTERNAL_ERROR
;
350 /* Skip trailing whitespaces */
351 for (; valueLen
> 0 && (value
->dptr
[valueLen
- 1] == ' ' ||
352 value
->dptr
[valueLen
- 1] == '\t'); valueLen
--);
355 * At this point valueLen is the effective length of
356 * the data. Convert value into __nis_value_t so that
357 * we can use the matchMappingItem function to break it
360 if ((val
= stringToValue(value
->dptr
, valueLen
)) == 0) {
361 freeRuleValue(rvq
, 1);
362 *statP
= MAP_NO_MEMORY
;
366 /* Perform namefield match */
367 valA
= matchMappingItem(t
->e
->element
.match
.fmt
, val
,
371 freeRuleValue(rvq
, 1);
372 *statP
= MAP_NAMEFIELD_MATCH_ERROR
;
376 /* We don't need val anymore, so free it */
380 * Since matchMappingItem only returns us an array of
381 * __nis_value_t's, we need to associate each value
382 * in the array with the corresponding item name.
383 * This code assumes that numVals will be less than or
384 * equal to the number of item names associated with
386 * These name=value pairs are added to rvq.
388 for (i
= 0, *statP
= SUCCESS
; i
< numVals
; i
++) {
389 for (j
= 0; j
< count
; j
++) {
390 if (addCol2RuleValue(vt_string
,
391 t
->e
->element
.match
.item
[i
].name
,
393 valA
[i
]->val
->length
, &rvq
[j
])) {
394 *statP
= MAP_INTERNAL_ERROR
;
398 if (*statP
== MAP_INTERNAL_ERROR
)
402 * Check if splitField exists for the field.
403 * Since splitfields are also stored as mapping
404 * structures, we need to get the hash table entry
405 * corresponding to the splitfield name
407 sf
= mappingFromMap(t
->e
->element
.match
.item
[i
].name
,
409 if (*statP
== MAP_NO_MEMORY
)
416 * Process and add splitFields to rule-value rvq
418 subrvq
= processSplitField(sf
, valA
[i
], &nr
, statP
);
421 /* statP would have been set */
426 * We merge 'count' rule-values in rvq with 'nr'
427 * rule-values from subrvq to give us a whopping
428 * 'count * nr' rule-values
431 /* Initialize the new rule-value array */
432 if ((newrvq
= initRuleValue(count
* nr
, 0)) == 0) {
433 *statP
= MAP_INTERNAL_ERROR
;
434 freeRuleValue(subrvq
, nr
);
438 for (j
= 0, l
= 0; j
< nr
; j
++) {
439 for (k
= 0; k
< count
; k
++, l
++) {
440 if ((mergeRuleValue(&newrvq
[l
],
444 &subrvq
[j
]) == -1)) {
445 *statP
= MAP_INTERNAL_ERROR
;
446 for (i
= 0; i
< numVals
; i
++)
447 freeValue(valA
[i
], 1);
449 freeRuleValue(rvq
, count
);
450 freeRuleValue(newrvq
,
452 freeRuleValue(subrvq
, nr
);
458 freeRuleValue(rvq
, count
);
461 freeRuleValue(subrvq
, nr
);
465 /* We don't need valA anymore, so free it */
466 for (i
= 0; i
< numVals
; i
++)
467 freeValue(valA
[i
], 1);
470 if (*statP
!= SUCCESS
) {
471 freeRuleValue(rvq
, count
);
484 * Generate name=values pairs for splitfield names
487 * nisLDAPnameFields club:
488 * ("%s %s %s", name, code, members)
489 * nisLDAPsplitField members:
490 * ("(%s,%s,%s)", host, user, domain),
493 * - rv is an array of numVals rule-values each containing
494 * name=value pairs for names occuring in nisLDAPsplitField.
495 * (i.e host, user, domain, group)
496 * - trv contains name=value pairs for names occuring in
497 * nisLDAPnameFields. (i.e name, code but not members)
499 * For every name in nisLDAPnamefields that is a splitfield,
500 * this function applies the data in rv to the corresponding
501 * splitfield formats (accessed thru t), to generate a single
502 * string value for the corresponding splitfield (members).
503 * This new name=value pair is then added to trv.
504 * Besides, any uninitialized namefield names are set to empty strings.
507 addSplitFieldValues(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
,
508 __nis_rule_value_t
*trv
, int numVals
, char *domain
) {
509 __nis_table_mapping_t
*sf
;
511 int i
, j
, k
, nitems
, res
, statP
;
513 char delim
[2] = {0, 0};
515 char *myself
= "addSplitFieldValues";
518 return (MAP_INTERNAL_ERROR
);
523 nitems
= t
->e
->element
.match
.numItems
;
527 * - Check each name in nisLDAPnamefield
528 * - if it's a splifield, construct its value and add it to trv
529 * - if not, check if it has a value
530 * - if not, add empty string
532 for (i
= 0, sf
= 0; i
< nitems
; i
++) {
535 * str will eventually contain the single string
536 * value for the corresponding splitfield.
537 * No point initializing str if rv == 0 because
538 * splitfield cannot be constructed without rv.
539 * So, only initialized here.
543 /* Check if it's a splitfield name */
544 sf
= mappingFromMap(t
->e
->element
.match
.item
[i
].name
,
548 * Return only incase of memory allocation failure.
549 * The other error case (MAP_NO_MAPPING_EXISTS),
550 * indicates that the item name is not a splitfieldname
551 * i.e it's a namefieldname. This case is handled by
552 * the following if (sf == 0)
554 if (statP
== MAP_NO_MEMORY
)
560 * Not a splitfield name. Verify if it has a value
562 if (findVal(t
->e
->element
.match
.item
[i
].name
,
563 trv
, mit_nisplus
) == 0) {
564 /* if not, use empty string */
565 res
= addCol2RuleValue(vt_string
,
566 t
->e
->element
.match
.item
[i
].name
,
569 return (MAP_INTERNAL_ERROR
);
573 * If rv == 0 then sf == 0 so we will continue here
574 * i.e. does not matter that str is not yet set up.
579 /* Code to construct a single value */
581 /* Use the first separator character as the delimiter */
582 delim
[0] = sf
->separatorStr
[0];
584 for (j
= 0; j
< numVals
; j
++) {
585 /* sf->numSplits is zero-based */
586 for (k
= 0; k
<= sf
->numSplits
; k
++) {
587 val
= getMappingFormatArray(
588 sf
->e
[k
].element
.match
.fmt
, &rv
[j
],
590 sf
->e
[k
].element
.match
.numItems
,
591 sf
->e
[k
].element
.match
.item
);
594 if (val
->numVals
> 0) {
596 tempstr
= scat(myself
,
603 return (MAP_NO_MEMORY
);
606 tempstr
= scat(myself
, 0, str
,
613 return (MAP_NO_MEMORY
);
622 res
= addCol2RuleValue(vt_string
,
623 t
->e
->element
.match
.item
[i
].name
,
624 str
, strlen(str
), trv
);
630 return (MAP_INTERNAL_ERROR
);
638 * Updates 'rv' with NIS name=value pairs suitable to
639 * construct datum from namefield information.
640 * Some part based on createNisPlusEntry (from ldap_nisdbquery.c)
641 * This code assumes that from a given LDAP entry, applying the
642 * mapping rules, would give us one or more NIS entries, differing
646 buildNISRuleValue(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
,
648 int r
, i
, j
, k
, l
, nrq
, res
, len
;
649 int numItems
, splitname
, count
, statP
;
651 __nis_mapping_item_t
*litem
;
652 __nis_mapping_rule_t
*rl
;
653 __nis_rule_value_t
*rvq
;
654 char *value
, *emptystr
= "";
658 /* Initialize default base */
659 __nisdb_get_tsd()->searchBase
= t
->objectDN
->read
.base
;
661 /* Initialize rule-value rvq */
665 /* Add domainname to rule-value */
666 if (addCol2RuleValue(vt_string
, N2LDOMAIN
, domain
, strlen(domain
),
668 return (MAP_INTERNAL_ERROR
);
671 for (r
= 0; r
< t
->numRulesFromLDAP
; r
++) {
672 rl
= t
->ruleFromLDAP
[r
];
674 /* Set escapeFlag if RHS is "dn" to remove escape chars */
675 if (rl
->rhs
.numElements
== 1 &&
676 rl
->rhs
.element
->type
== me_item
&&
677 rl
->rhs
.element
->element
.item
.type
== mit_ldap
&&
678 strcasecmp(rl
->rhs
.element
->element
.item
.name
, "dn")
680 __nisdb_get_tsd()->escapeFlag
= '2';
683 rval
= buildRvalue(&rl
->rhs
, mit_ldap
, rv
, NULL
);
685 /* Reset escapeFlag */
686 __nisdb_get_tsd()->escapeFlag
= '\0';
692 if (rval
->numVals
<= 0) {
693 /* Treat as invalid */
698 litem
= buildLvalue(&rl
->lhs
, &rval
, &numItems
);
700 /* This will take care of numItems == 0 */
705 if (rval
->numVals
> 1) {
706 if (numItems
== 1 && litem
->repeat
)
708 else if (numItems
> 1 && rval
->repeat
)
709 nrq
= 1 + ((rval
->numVals
-1)/numItems
);
715 /* Set splitname if splitfield names are specified */
716 for (i
= 0; i
< numItems
; i
++) {
717 if (strcasecmp(litem
[i
].name
, N2LKEY
) == 0 ||
718 strcasecmp(litem
[i
].name
, N2LIPKEY
) == 0 ||
719 strcasecmp(litem
[i
].name
, N2LCOMMENT
) == 0)
721 for (j
= 0; j
< t
->numColumns
; j
++) {
722 if (strcmp(litem
[i
].name
, t
->column
[j
]) == 0)
725 if (j
== t
->numColumns
)
729 splitname
= (i
< numItems
)?1:0;
731 for (j
= 0; j
< nrq
; j
++) {
732 if (splitname
== 1) {
734 * Put every value of splitfieldname in a new
735 * rule-value. Helps generating splitfields.
737 rvq
= growRuleValue(count
, count
+ 1, rvq
, 0);
739 freeRuleValue(rvq
, count
);
741 freeMappingItem(litem
, numItems
);
742 return (MAP_INTERNAL_ERROR
);
747 for (k
= j
% nrq
, l
= 0; l
< numItems
; k
+= nrq
, l
++) {
748 /* If we run out of values, use empty strings */
749 if (k
>= rval
->numVals
) {
753 value
= rval
->val
[k
].value
;
754 len
= rval
->val
[k
].length
;
756 res
= (splitname
== 1)?addCol2RuleValue(
757 vt_string
, litem
[l
].name
, value
,
758 len
, &rvq
[count
- 1]):0;
760 res
= addCol2RuleValue(vt_string
,
761 litem
[l
].name
, value
, len
, rv
);
763 freeRuleValue(rvq
, count
);
765 freeMappingItem(litem
, numItems
);
766 return (MAP_INTERNAL_ERROR
);
772 freeMappingItem(litem
, numItems
);
775 } /* for r < t->numRulesFromLDAP */
777 statP
= addSplitFieldValues(t
, rvq
, rv
, count
, domain
);
780 freeRuleValue(rvq
, count
);
782 if (verifyIndexMatch(t
, 0, rv
, 0, 0) == 0)
783 return (MAP_INDEXLIST_ERROR
);
786 } /* end of buildNISRuleValue */
789 * Convert rule-value to datum using namefield information
792 ruleValueToDatum(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
, int *statP
) {
795 char *str
, *cstr
, commentSep
[3] = {' ', 0, 0};
796 char *myself
= "ruleValueToDatum";
801 /* Return empty datum if no namefield information available */
803 if ((value
= am(myself
, sizeof (*value
))) == 0)
804 *statP
= MAP_NO_MEMORY
;
808 val
= getMappingFormatArray(t
->e
->element
.match
.fmt
, rv
,
809 fa_item
, t
->e
->element
.match
.numItems
,
810 t
->e
->element
.match
.item
);
812 if (val
&& val
->val
&& val
->val
->value
) {
813 if ((value
= am(myself
, sizeof (*value
))) == 0) {
814 *statP
= MAP_NO_MEMORY
;
819 /* Strip trailing whitespaces */
820 cstr
= (char *)val
->val
->value
+ val
->val
->length
;
821 for (; cstr
>= (char *)val
->val
->value
&&
822 (*cstr
== ' ' || *cstr
== '\t'); *cstr
-- = '\0');
824 if (t
->commentChar
!= '\0' &&
825 (str
= findVal(N2LCOMMENT
, rv
, mit_nisplus
)) != 0 &&
827 commentSep
[1] = t
->commentChar
;
828 cstr
= scat(myself
, F
, commentSep
, str
);
830 value
->dptr
= scat(myself
, F
,
831 val
->val
->value
, cstr
);
835 value
->dptr
= sdup(myself
, T
, val
->val
->value
);
839 value
->dsize
= strlen(value
->dptr
);
842 *statP
= MAP_NO_MEMORY
;
848 *statP
= MAP_NAMEFIELD_MATCH_ERROR
;
853 getKeyFromRuleValue(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
, int *nv
,
854 int *statP
, bool_t xlate_to_lcase
)
859 char *myself
= "getKeyFromRuleValue";
864 if (rv
== 0 || nv
== 0)
867 for (i
= 0; i
< rv
->numColumns
; i
++) {
868 if (rv
->colName
[i
] == 0)
870 if (strcasecmp(N2LKEY
, rv
->colName
[i
]) == 0 ||
871 strcasecmp(N2LIPKEY
, rv
->colName
[i
]) == 0) {
872 if ((*nv
= rv
->colVal
[i
].numVals
) == 0)
874 if ((key
= am(myself
, sizeof (key
[0]) * *nv
)) == 0) {
875 *statP
= MAP_NO_MEMORY
;
878 for (j
= 0; j
< *nv
; j
++) {
879 if ((str
= rv
->colVal
[i
].val
[j
].value
) == 0) {
883 if (verifyIndexMatch(t
, 0, 0,
884 rv
->colName
[i
], str
) == 0) {
890 key
[j
].dsize
= strlen(str
);
891 key
[j
].dptr
= am(myself
,
893 if (key
[j
].dptr
== 0) {
894 *statP
= MAP_NO_MEMORY
;
895 for (--j
; j
>= 0; j
--)
901 /* transliterate key to lowercase */
902 if (xlate_to_lcase
== TRUE
) {
907 * "YP_MULTI_" prefix.
910 if (strncmp(YPMULTI
, str
,
913 bcopy(str
, key
[j
].dptr
,
916 while (k
< key
[j
].dsize
) {
924 bcopy(str
, key
[j
].dptr
,
936 * Get the mapping structure corresponding to `map,domain.'
938 __nis_table_mapping_t
*
939 mappingFromMap(char *map
, char *domain
, int *statP
) {
941 __nis_table_mapping_t
*t
;
946 /* Construct map,domain. */
947 if ((mapPath
= getFullMapName(map
, domain
)) == 0) {
948 *statP
= MAP_NO_MEMORY
;
952 /* Get the hash table entry for the mapPath */
953 if ((t
= __nis_find_item_mt(mapPath
, &ldapMappingList
, 1, 0))
955 *statP
= MAP_NO_MAPPING_EXISTS
;
962 * Verify at least one key value obtained from DIT matches the search key
968 verifyKey(char *key
, __nis_rule_value_t
*rv
) {
972 for (i
= 0; i
< rv
->numColumns
; i
++) {
973 if (rv
->colName
[i
] == 0)
975 if (strcasecmp(N2LKEY
, rv
->colName
[i
]) == 0) {
976 if (rv
->colVal
[i
].val
== 0)
978 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++) {
979 str
= (char *)rv
->colVal
[i
].val
[j
].value
;
980 if (str
&& strcmp(str
, key
) == 0)
984 } else if (strcasecmp(N2LIPKEY
, rv
->colName
[i
]) == 0) {
985 if (checkIPaddress(key
, strlen(key
), &sipkey
) > 0) {
986 if (rv
->colVal
[i
].val
== 0)
988 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++) {
989 str
= rv
->colVal
[i
].val
[j
].value
;
990 if (str
&& strcmp(str
, sipkey
) == 0) {
1004 * Read (i.e get and map) a single NIS entry from the LDAP DIT
1007 singleReadFromDIT(char *map
, char *domain
, datum
*key
, datum
*value
,
1009 __nis_table_mapping_t
*t
;
1010 __nis_rule_value_t
*rv_request
= 0, *rv_result
= 0;
1011 __nis_ldap_search_t
*ls
;
1012 __nis_object_dn_t
*objectDN
= NULL
;
1016 char *myself
= "singleReadFromDIT";
1020 if (!map
|| !domain
|| !key
|| !value
) {
1021 *statP
= MAP_PARAM_ERROR
;
1026 /* Get the mapping information for the map */
1027 if ((t
= mappingFromMap(map
, domain
, statP
)) == 0) {
1029 * No problem. We don't handle this map and domain. Maybe it's
1030 * handled by a service other than NIS.
1035 /* NULL-terminated version of datum key for logging */
1036 if ((skey
= am(myself
, key
->dsize
+ 1)) == 0) {
1037 *statP
= MAP_NO_MEMORY
;
1040 (void) memcpy(skey
, key
->dptr
, key
->dsize
);
1042 if ((str
= getFullMapName(map
, domain
)) == 0) {
1043 *statP
= MAP_NO_MEMORY
;
1047 /* For each alternate mapping */
1048 for (; t
!= 0; t
= t
->next
) {
1049 /* Verify objName */
1050 if (strcmp(str
, t
->objName
) != 0) {
1054 /* Verify if key matches the index */
1055 if (verifyIndexMatch(t
, 0, 0, N2LKEY
, skey
) == 0 ||
1056 verifyIndexMatch(t
, 0, 0, N2LIPKEY
, skey
) == 0)
1059 /* Check if rulesFromLDAP are provided */
1060 if (t
->numRulesFromLDAP
== 0) {
1061 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1062 "%s: No rulesFromLDAP information available "
1063 "for %s (%s)", myself
, t
->dbId
, map
);
1067 /* Convert key into rule-value */
1068 if ((rv_request
= datumToRuleValue(key
, 0, t
, 0, domain
, TRUE
,
1070 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1071 "%s: Conversion error %d (NIS to name=value "
1072 "pairs) for NIS key (%s) for %s (%s)",
1073 myself
, *statP
, skey
, t
->dbId
, map
);
1076 /* Convert rule-value into ldap request */
1077 for (objectDN
= t
->objectDN
; objectDN
&&
1078 objectDN
->read
.base
;
1079 objectDN
= objectDN
->next
) {
1080 ls
= createLdapRequest(t
, rv_request
, 0, 1, NULL
,
1083 *statP
= MAP_CREATE_LDAP_REQUEST_ERROR
;
1084 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1085 "%s: Failed to create ldapSearch "
1087 "NIS key (%s) for %s (%s) "
1089 myself
, skey
, t
->dbId
, map
,
1090 objectDN
->read
.base
);
1093 ls
->timeout
.tv_sec
= SINGLE_ACCESS_TIMEOUT_SEC
;
1094 ls
->timeout
.tv_usec
= SINGLE_ACCESS_TIMEOUT_USEC
;
1096 nr
= (ls
->isDN
)?0:-1;
1097 rv_result
= ldapSearch(ls
, &nr
, 0, statP
);
1099 if (rv_result
== 0) {
1100 if (*statP
== LDAP_NO_SUCH_OBJECT
) {
1101 /* Entry does not exist in */
1102 /* the ldap server */
1106 freeRuleValue(rv_request
, 1);
1109 /* if result > 1, first match will be returned */
1111 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1112 "%s: %d ldapSearch results "
1114 "for %s (%s) for base %s. "
1115 "First match will be returned ",
1116 myself
, nr
, skey
, t
->dbId
, map
,
1117 objectDN
->read
.base
);
1120 for (i
= 0; i
< nr
; i
++) {
1121 /* Convert LDAP data to NIS equivalents */
1122 *statP
= buildNISRuleValue(t
, &rv_result
[i
],
1124 if (*statP
== MAP_INDEXLIST_ERROR
)
1127 if (*statP
!= SUCCESS
) {
1128 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1129 "%s: Conversion error %d (LDAP to "
1130 "name=value pairs) for NIS key (%s) "
1131 "for %s (%s) for base %s", myself
,
1133 t
->dbId
, map
, objectDN
->read
.base
);
1138 * Check if 'key' from the ldap result matches the key
1139 * provided by our caller
1141 if ((rc
= verifyKey(skey
, &rv_result
[i
]))
1143 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1144 "%s: Cannot verify key from ldap "
1145 "result for NIS key (%s) for %s (%s) "
1147 myself
, skey
, t
->dbId
, map
,
1148 objectDN
->read
.base
);
1153 datval
= ruleValueToDatum(t
,
1154 &rv_result
[i
], statP
);
1156 logmsg(MSG_NOTIMECHECK
,
1158 "%s: Conversion error %d "
1159 "(name=value pairs to NIS) "
1160 "for NIS key (%s) for %s (%s)"
1163 *statP
, skey
, t
->dbId
, map
,
1164 objectDN
->read
.base
);
1168 value
->dptr
= datval
->dptr
;
1169 value
->dsize
= datval
->dsize
;
1173 freeRuleValue(rv_result
, nr
);
1177 /* Free full map name */
1183 freeRuleValue(rv_result
, nr
);
1185 } /* end of for over objectDN */
1187 if (rv_request
!= 0) {
1188 freeRuleValue(rv_request
, 1);
1191 if (rv_result
!= 0) {
1192 freeRuleValue(rv_result
, nr
);
1197 *statP
= MAP_NO_MATCHING_KEY
;
1199 /* Free full map name */
1207 * Maps and writes a single NIS entry to the LDAP DIT
1210 singleWriteToDIT(char *map
, char *domain
, datum
*key
, datum
*value
,
1212 __nis_table_mapping_t
*t
;
1213 __nis_rule_value_t
*rv
, *frv
;
1214 __nis_ldap_search_t
*ls
;
1215 int statP
= SUCCESS
, flag
;
1216 int nv
, nr
, i
, rc
, collapse
;
1217 char *dn
= 0, *skey
, *svalue
, *str
;
1218 char *myself
= "singleWriteToDIT";
1220 if (!map
|| !domain
|| !key
|| !value
) {
1221 return (MAP_PARAM_ERROR
);
1224 /* Return SUCCESS for empty or whitespace key */
1225 for (i
= 0; i
< key
->dsize
&& (key
->dptr
[i
] == 0 ||
1226 key
->dptr
[i
] == ' ' || key
->dptr
[i
] == '\t'); i
++);
1227 if (i
>= key
->dsize
)
1230 /* Get the mapping information for the map */
1231 if ((t
= mappingFromMap(map
, domain
, &statP
)) == 0) {
1233 * No problem. We don't handle this map and domain. Maybe it's
1234 * handled by a service other than NIS.
1239 /* NULL-terminated version of key and value for logging */
1240 if ((skey
= am(myself
, key
->dsize
+ 1)) == 0)
1241 return (MAP_NO_MEMORY
);
1242 (void) memcpy(skey
, key
->dptr
, key
->dsize
);
1244 if ((svalue
= am(myself
, value
->dsize
+ 1)) == 0) {
1246 return (MAP_NO_MEMORY
);
1248 (void) memcpy(svalue
, value
->dptr
, value
->dsize
);
1250 if ((str
= getFullMapName(map
, domain
)) == 0) {
1253 return (MAP_NO_MEMORY
);
1256 /* For each alternate mapping */
1257 for (flag
= 0; t
!= 0; t
= t
->next
) {
1258 /* Verify objName */
1259 if (strcmp(str
, t
->objName
) != 0) {
1263 /* Verify if key matches the index */
1264 if (verifyIndexMatch(t
, 0, 0, N2LKEY
, skey
) == 0 ||
1265 verifyIndexMatch(t
, 0, 0, N2LIPKEY
, skey
) == 0)
1268 /* Check the writespecs */
1269 if (t
->objectDN
->write
.base
== 0) {
1270 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1271 "%s: No baseDN in writespec. Write disabled "
1272 "for %s (%s)", myself
, t
->dbId
, map
);
1276 /* Check if rulesToLDAP are provided */
1277 if (t
->numRulesToLDAP
== 0) {
1278 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1279 "%s: No rulesToLDAP. Write disabled for "
1280 "%s (%s)", myself
, t
->dbId
, map
);
1284 /* Set flag to indicate write is enabled */
1287 /* Convert key and value into an array of rule-values */
1288 if ((rv
= datumToRuleValue(key
, value
, t
, &nv
, domain
, FALSE
,
1290 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1291 "%s: Conversion error %d (NIS to name=value "
1292 "pairs) for NIS data (key=%s, value=%s) "
1294 myself
, statP
, skey
, svalue
, t
->dbId
, map
);
1298 /* Free full map name */
1304 /* Convert NIS data to LDAP equivalents for each rule-value */
1305 for (i
= 0; i
< nv
; i
++) {
1306 /* Verify indexlist with name=value pairs */
1307 if (verifyIndexMatch(t
, 0, &rv
[i
], 0, 0) == 0)
1310 /* Create LDAP request and LDAP name=value pairs */
1311 if ((ls
= createLdapRequest(t
, &rv
[i
],
1312 0, 0, NULL
, NULL
)) == 0) {
1313 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1314 "%s: Conversion error (name=value pairs"
1315 " to LDAP) for NIS data "
1316 "(key=%s, value=%s) for %s (%s)",
1317 myself
, skey
, svalue
, t
->dbId
, map
);
1318 freeRuleValue(rv
, nv
);
1322 /* Free full map name */
1325 return (MAP_CREATE_LDAP_REQUEST_ERROR
);
1328 /* printRuleValue(&rv[i]); */
1331 /* If i < nv then this alternate mapping isn't the one */
1336 * Merge rule-values with the same DN so that we have
1337 * one ldap write request for each DN
1340 frv
= mergeRuleValueWithSameDN(rv
, &nr
);
1341 freeRuleValue(rv
, nv
);
1344 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1345 "%s: Unable to merge LDAP write "
1346 "requests to same DN for NIS data "
1347 "(key=%s, value=%s) for %s (%s)",
1348 myself
, skey
, svalue
, t
->dbId
, map
);
1349 statP
= MAP_INTERNAL_ERROR
;
1350 } else if (nr
== 0) {
1351 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1352 "%s: Cannot generate write DN due to "
1353 "missing information for NIS data "
1354 "(key=%s, value=%s) for %s (%s)",
1355 myself
, skey
, svalue
, t
->dbId
, map
);
1361 /* Free full map name */
1367 /* Write to the LDAP server */
1368 for (collapse
= 0, i
= 0; i
< nr
; i
++) {
1369 if ((dn
= findVal("dn", &frv
[i
], mit_ldap
)) != 0) {
1370 if (replace
== FALSE
) {
1372 rc
= ldapAdd(dn
, &frv
[i
],
1373 t
->objectDN
->write
.attrs
, 0);
1375 /* ldap modify with addFirst set */
1376 rc
= ldapModify(dn
, &frv
[i
],
1377 t
->objectDN
->write
.attrs
, 1);
1380 /* if we get err=20, collapse and try again */
1382 (rc
== LDAP_TYPE_OR_VALUE_EXISTS
) &&
1383 (collapseRuleValue(&frv
[i
]) == 1)) {
1384 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1385 "%s: Ignoring values differing "
1386 "in case from NIS data (key=%s,"
1387 " value=%s) for (dn: %s) for "
1388 "%s (%s)", myself
, skey
,
1389 svalue
, dn
, t
->dbId
, map
);
1396 if (rc
!= LDAP_SUCCESS
) {
1398 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1399 "%s: %s error %d (%s) for "
1400 "(dn: %s) for NIS data "
1401 "(key=%s, value=%s) "
1403 myself
, (replace
== TRUE
) ?
1404 "ldapModify" : "ldapAdd", rc
,
1405 ldap_err2string(rc
), dn
, skey
,
1406 svalue
, t
->dbId
, map
);
1408 /* Dumping failed call may be useful */
1409 /* printRuleValue(&frv[i]); */
1412 * Return the error code and let wrapper
1413 * sort out if mapping should continue
1419 freeRuleValue(frv
, nr
);
1421 /* Free full map name */
1429 freeRuleValue(frv
, nr
);
1435 /* Free full map name */
1438 return ((flag
)?SUCCESS
:MAP_WRITE_DISABLED
);
1442 collapseRuleValue(__nis_rule_value_t
*rv
) {
1445 /* Using 'val' to appease cstyle's 80 chars/line limit */
1448 for (i
= 0, flag
= 0; i
< rv
->numAttrs
; i
++) {
1449 val
= &rv
->attrVal
[i
];
1450 for (j
= 1; j
< val
->numVals
; j
++) {
1451 for (k
= 0; k
< j
; k
++) {
1452 if (val
->val
[j
].length
!= val
->val
[k
].length
)
1454 if (val
->val
[k
].length
== 0)
1456 if (strncasecmp(val
->val
[j
].value
,
1458 val
->val
[j
].length
) != 0)
1461 sfree(val
->val
[j
].value
);
1463 #ifdef ORDER_NOT_IMPORTANT
1464 val
->val
[j
--] = val
->val
[--val
->numVals
];
1466 /* Order needs to be maintained */
1467 for (k
= j
+ 1; k
< val
->numVals
; k
++)
1468 val
->val
[k
- 1] = val
->val
[k
];
1479 /* ObjectClass lookup table */
1481 const char *attrType
;
1482 const char *objectClass
;
1484 { "o", "objectclass=organization"},
1485 { "organizationname", "objectclass=organization"},
1486 { "2.5.4.10", "objectclass=organization"},
1487 { "ou", "objectclass=organizationalunit"},
1488 { "organizationalunitname", "objectclass=organizationalunit"},
1489 { "2.5.4.11", "objectclass=organizationalunit"},
1490 { "c", "objectclass=country"},
1491 { "countryname", "objectclass=country"},
1492 { "2.5.4.6", "objectclass=country"},
1493 { "dc", "objectclass=domain"},
1494 { "domaincomponent", "objectclass=domain"},
1495 { "0.9.2342.19200300.100.1.25", "objectclass=domain"},
1496 { "nismapname", "objectclass=nismap"},
1497 { "1.3.6.1.1.1.1.26", "objectclass=nismap"},
1498 { "automountmapname", "objectclass=automountmap"},
1499 { "1.3.6.1.1.1.1.31", "objectclass=automountmap"},
1504 * Returns the name of the objectclass to which the object
1505 * represented by the given 'rdn' will most likely belong to.
1506 * The return value is in static memory so it should not be
1510 getObjectClass(char *rdn
) {
1515 /* Skip leading whitespaces */
1516 for (p
= rdn
; *p
== ' ' || *p
== '\t'; p
++);
1522 if ((p
= strchr(attrtype
, '=')) == 0 || p
== attrtype
||
1527 * Skip trailing whitespaces in attrtype
1528 * Don't worry, p won't decrease beyond attrtype
1530 for (--p
; *p
== ' ' || *p
== '\t'; p
--);
1531 len
= p
- attrtype
+ 1;
1533 for (i
= 0; oc_lookup
[i
].attrType
; i
++)
1534 if (!strncasecmp(oc_lookup
[i
].attrType
, attrtype
, len
))
1535 /* Check length is right */
1536 if (len
== strlen(oc_lookup
[i
].attrType
))
1537 return (oc_lookup
[i
].objectClass
);
1543 * Split 'dn' into rdn and parentdn based on the first
1544 * occurrence of unescaped 'comma' or 'semicolon'. rdn
1545 * lies on the LHS while parentdn lies on the RHS of the
1546 * split. If none found, then an empty string ("") is
1547 * assigned to parentdn
1550 splitDN(char *dn
, char **rdn
, char **parentdn
) {
1552 char *myself
= "splitDN";
1554 if ((name
= sdup(myself
, T
, dn
)) == 0)
1557 for (value
= name
; *value
!= '\0'; value
++) {
1558 if (*value
== ',' || *value
== ';')
1559 if (value
== name
|| *(value
- 1) != '\\')
1563 if (*value
!= '\0') {
1570 if ((*parentdn
= sdup(myself
, T
, value
)) == 0) {
1584 * FUNCTION : makeNISObject()
1586 * DESCRIPTION: Sets up a nis Object in the DIT.
1589 * Case 1: Both 'domain' and 'dn' are non-NULL
1590 * Create nisDomainObject with the given information
1591 * Case 2: Only 'domain' is non-NULL
1592 * Obtain the 'dn' from the nisLDAPdomainContext list
1593 * Create nisDomainObject with the above information
1594 * Case 3: Only 'dn' is non-NULL
1595 * Create an object with the 'dn'
1596 * Here we guess the objectclass attribute, based on
1598 * Case 4: Both 'domain' and 'dn' are NULL
1601 * RETURNS : SUCCESS = It worked
1602 * FAILURE = There was a problem.
1605 makeNISObject(char *domain
, char *dn
) {
1606 __nis_rule_value_t
*rv
;
1607 __nis_ldap_search_t
*ls
;
1608 int i
, rc
, nr
, add_rc
;
1610 char *myself
= "makeNISObject";
1616 * If only 'domain' name is provided, then
1617 * try to find dn from the nisLDAPdomainContext
1618 * list generated by the parser
1621 for (i
= 0; i
< ypDomains
.numDomains
; i
++) {
1622 if (ypDomains
.domainLabels
[i
] == 0)
1624 if (strcasecmp(domain
, ypDomains
.domainLabels
[i
])
1626 dn
= ypDomains
.domains
[i
];
1635 * If only 'dn' is given, then it means that the
1636 * caller simply wants to a create an entry for
1639 * If 'domain' is given, then check if the 'dn'
1640 * has already been set up as a nis domain object.
1641 * If not, see if we can make it become one.
1645 * Check to see if the nis domain object has
1646 * already been set up
1648 ls
= buildLdapSearch(dn
, LDAP_SCOPE_BASE
, 0, 0,
1649 "objectclass=*", 0, 0, 0);
1651 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1652 "%s: Unable to create ldapSearch "
1653 "request for dn: %s", myself
, dn
);
1657 rv
= ldapSearch(ls
, &nr
, 0, &rc
);
1659 if (rc
== LDAP_SUCCESS
) {
1660 val
= findVal("nisDomain", rv
, mit_ldap
);
1663 * Yes, nis domain object found. Check
1664 * to see if the domain names match.
1665 * If so, we are done. If not, log
1666 * a warning message, and return SUCCESS.
1668 if (strcasecmp(val
, domain
) == 0) {
1669 freeRuleValue(rv
, nr
);
1672 logmsg(MSG_NOTIMECHECK
,
1674 "%s: Entry (dn: %s) already "
1675 "contains a nis domain name "
1676 "(%s). The domain name (%s) "
1678 myself
, dn
, val
, domain
);
1679 freeRuleValue(rv
, nr
);
1683 freeRuleValue(rv
, nr
);
1685 * Entry for the 'dn' exists, but it
1686 * is not a nis domain object yet.
1687 * Add the nisDoamin attribute and
1688 * the nisDomainObject objectclass to
1691 if ((rv
= initRuleValue(1, 0)) == 0)
1694 if (addSAttr2RuleValue("nisDomain",
1695 domain
, rv
) == -1) {
1696 freeRuleValue(rv
, 1);
1699 rc
= ldapModify(dn
, rv
,
1700 "objectclass=nisDomainObject",
1702 freeRuleValue(rv
, 1);
1703 if (rc
== LDAP_SUCCESS
) {
1704 logmsg(MSG_NOTIMECHECK
,
1706 "%s: entry (dn: %s) "
1707 "modified to be an "
1708 "nis domain object",
1712 logmsg(MSG_NOTIMECHECK
,
1714 "%s: unable to modify "
1715 "entry (dn: %s) to be "
1716 "a nis domain object: "
1717 "ldapModify error %d (%s)",
1719 ldap_err2string(rc
));
1723 } else { /* search for 'dn' failed */
1724 freeRuleValue(rv
, nr
);
1727 * It is OK if no such object, otherwise
1730 if (rc
!= LDAP_NO_SUCH_OBJECT
) {
1731 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1732 "%s: unable to retrieve "
1734 "ldapSearch error %d (%s)",
1736 ldap_err2string(rc
));
1742 * If the 'dn' is actually the naming context of
1743 * the DIT, we should be able to make it a nis domain
1744 * object without worrying about missing parent
1745 * entries. If unable to add the entry for the 'dn'
1746 * due to missing parent entries, fall through
1747 * to create them and then add the nis domain object.
1749 if (addNISObject(domain
, dn
, &add_rc
) == SUCCESS
)
1751 else if (add_rc
!= LDAP_NO_SUCH_OBJECT
)
1756 if (addParent(dn
, NULL
) == FAILURE
)
1759 if (addNISObject(domain
, dn
, NULL
) == FAILURE
)
1766 addParent(char *dn
, char **attr
) {
1767 __nis_rule_value_t
*rv
;
1768 __nis_ldap_search_t
*ls
;
1770 char *parentdn
= 0, *rdn
= 0;
1771 char *myself
= "addParent";
1773 /* Obtain parentdn */
1774 if (splitDN(dn
, &rdn
, &parentdn
) == -1)
1781 /* Check if parentdn exists */
1782 ls
= buildLdapSearch(parentdn
, LDAP_SCOPE_BASE
, 0, 0,
1783 "objectclass=*", 0, 0, 0);
1785 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1786 "%s: Unable to create ldapSearch request for "
1787 "parent (dn: %s) of (dn: %s)",
1788 myself
, parentdn
, dn
);
1794 rv
= ldapSearch(ls
, &nr
, 0, &rc
);
1796 freeRuleValue(rv
, nr
);
1798 /* Create parent if it doesn't exists */
1799 if (rc
== LDAP_NO_SUCH_OBJECT
) {
1800 if (makeNISObject(0, parentdn
) == FAILURE
) {
1801 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1802 "%s: Unable to create parent (dn: %s) of "
1803 "(dn: %s) in the DIT", myself
, parentdn
, dn
);
1812 *attr
= (char *)getObjectClass(rdn
);
1821 * FUNCTION : is_fatal_error()
1823 * DESCRIPTION: Works out if a failed mapping operation should be retried.
1825 * INPUTS : Result code from operation
1827 * OUTPUTS : TRUE = Fatal error, don't retry.
1828 * FALSE = Temporary error, retry.
1831 is_fatal_error(int res
)
1835 /* An internal mapping error. Not going to go away. */
1839 case (LDAP_PROTOCOL_ERROR
):
1840 case (LDAP_TIMELIMIT_EXCEEDED
):
1841 case (LDAP_PARTIAL_RESULTS
):
1843 case (LDAP_UNAVAILABLE
):
1844 case (LDAP_UNWILLING_TO_PERFORM
):
1846 case (LDAP_SERVER_DOWN
):
1847 case (LDAP_LOCAL_ERROR
):
1848 case (LDAP_TIMEOUT
):
1849 case (LDAP_NO_MEMORY
):
1850 /* Probably worth a retry */
1859 * FUNCTION : addNISObject()
1861 * DESCRIPTION: Add a nis Object in the DIT.
1864 * Case 1: 'dn' is NULL
1866 * Case 2: 'domain' is non-NULL
1867 * Create nisDomainObject with the given information
1868 * Case 3: 'domain' is NULL
1869 * Create an object with the 'dn'
1870 * Here we guess the objectclass attribute, based on
1873 * RETURNS : SUCCESS = It worked
1874 * FAILURE = There was a problem. If the ldap add
1875 * operation failed, ldap_rc will be set
1876 * to the ldap error code.
1879 addNISObject(char *domain
, char *dn
, int *ldap_rc
) {
1880 __nis_rule_value_t
*rv
;
1882 char *objClassAttrs
= NULL
, *attrs
;
1883 char *value
, *svalue
, *rdn
= NULL
;
1884 char *myself
= "addNISObject";
1889 if ((rv
= initRuleValue(1, 0)) == 0)
1896 * Add name=value pairs from RDN. Although this is not required
1897 * for SunOne Directory Server, during openldap interoperabilty
1898 * tests, it was found out that openldap server returned object
1899 * class violation errors if MUST attributes were not specified
1902 if (splitDN(dn
, &rdn
, 0) == -1)
1905 objClassAttrs
= (char *)getObjectClass(rdn
);
1906 if (objClassAttrs
== NULL
) {
1912 * RDN can be composed of multiple name=value pairs
1913 * concatenated by '+'. Hence, we need to determine each
1914 * pair and add it to 'rv'
1916 for (value
= rdn
, svalue
= NULL
; *value
!= '\0'; value
++) {
1917 if (*value
== '+') {
1918 /* Make sure it's not escaped */
1919 if (value
== rdn
|| *(value
- 1) != '\\') {
1921 * We are at the start of the new
1922 * pair. 'svalue' now contains the
1923 * value for the previous pair. Add
1924 * the previous pair to 'rv'
1928 addSAttr2RuleValue(rdn
, svalue
, rv
)
1931 freeRuleValue(rv
, 1);
1940 if (*value
== '=') {
1941 if (value
== rdn
|| *(value
- 1) != '\\') {
1943 * 'rdn' now contains the name.
1944 * Whatever follows till the next
1945 * unescaped '+' or '\0' is the
1946 * value for this pair.
1956 * End of String. Add the previous name=value pair to 'rv'
1958 if (svalue
&& addSAttr2RuleValue(rdn
, svalue
, rv
) == -1) {
1960 freeRuleValue(rv
, 1);
1964 } else /* rdn == NULL */
1967 /* Create the entry */
1969 if (addSAttr2RuleValue("nisDomain", domain
, rv
) == -1) {
1970 freeRuleValue(rv
, 1);
1973 attrs
= scat(myself
, F
, "objectclass=nisdomainobject,",
1976 freeRuleValue(rv
, 1);
1979 rc
= ldapAdd(dn
, rv
, attrs
, 0);
1982 rc
= ldapAdd(dn
, rv
, objClassAttrs
, 0);
1985 if (rc
== LDAP_SUCCESS
)
1986 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1987 "%s: Entry (dn: %s) added to DIT",
1989 else if (rc
== LDAP_ALREADY_EXISTS
)
1990 /* Treat this as success */
1993 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1994 "%s: ldapAdd error %d (%s) for (dn: %s)",
1995 myself
, rc
, ldap_err2string(rc
), dn
);
1997 freeRuleValue(rv
, 1);
2000 return ((rc
== LDAP_SUCCESS
)?SUCCESS
:FAILURE
);