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 char *valstr
= value
->dptr
;
323 valueLen
= value
->dsize
;
325 * Extract the comment, if any, and add it to
328 if (t
->commentChar
!= '\0') {
330 * We loop on value->dsize because valstr
331 * may not be NULL-terminated.
333 for (i
= 0; i
< value
->dsize
; i
++) {
334 if (valstr
[i
] == t
->commentChar
) {
336 comLen
= value
->dsize
- i
- 1;
339 if (addCol2RuleValue(vt_string
,
340 N2LCOMMENT
, valstr
+ i
+ 1,
342 freeRuleValue(rvq
, 1);
343 *statP
= MAP_INTERNAL_ERROR
;
351 /* Skip trailing whitespaces */
352 for (; valueLen
> 0 && (valstr
[valueLen
- 1] == ' ' ||
353 valstr
[valueLen
- 1] == '\t'); valueLen
--);
356 * At this point valueLen is the effective length of
357 * the data. Convert value into __nis_value_t so that
358 * we can use the matchMappingItem function to break it
361 if ((val
= stringToValue(valstr
, valueLen
)) == 0) {
362 freeRuleValue(rvq
, 1);
363 *statP
= MAP_NO_MEMORY
;
367 /* Perform namefield match */
368 valA
= matchMappingItem(t
->e
->element
.match
.fmt
, val
,
372 freeRuleValue(rvq
, 1);
373 *statP
= MAP_NAMEFIELD_MATCH_ERROR
;
377 /* We don't need val anymore, so free it */
381 * Since matchMappingItem only returns us an array of
382 * __nis_value_t's, we need to associate each value
383 * in the array with the corresponding item name.
384 * This code assumes that numVals will be less than or
385 * equal to the number of item names associated with
387 * These name=value pairs are added to rvq.
389 for (i
= 0, *statP
= SUCCESS
; i
< numVals
; i
++) {
390 for (j
= 0; j
< count
; j
++) {
391 if (addCol2RuleValue(vt_string
,
392 t
->e
->element
.match
.item
[i
].name
,
394 valA
[i
]->val
->length
, &rvq
[j
])) {
395 *statP
= MAP_INTERNAL_ERROR
;
399 if (*statP
== MAP_INTERNAL_ERROR
)
403 * Check if splitField exists for the field.
404 * Since splitfields are also stored as mapping
405 * structures, we need to get the hash table entry
406 * corresponding to the splitfield name
408 sf
= mappingFromMap(t
->e
->element
.match
.item
[i
].name
,
410 if (*statP
== MAP_NO_MEMORY
)
417 * Process and add splitFields to rule-value rvq
419 subrvq
= processSplitField(sf
, valA
[i
], &nr
, statP
);
422 /* statP would have been set */
427 * We merge 'count' rule-values in rvq with 'nr'
428 * rule-values from subrvq to give us a whopping
429 * 'count * nr' rule-values
432 /* Initialize the new rule-value array */
433 if ((newrvq
= initRuleValue(count
* nr
, 0)) == 0) {
434 *statP
= MAP_INTERNAL_ERROR
;
435 freeRuleValue(subrvq
, nr
);
439 for (j
= 0, l
= 0; j
< nr
; j
++) {
440 for (k
= 0; k
< count
; k
++, l
++) {
441 if ((mergeRuleValue(&newrvq
[l
],
445 &subrvq
[j
]) == -1)) {
446 *statP
= MAP_INTERNAL_ERROR
;
447 for (i
= 0; i
< numVals
; i
++)
448 freeValue(valA
[i
], 1);
450 freeRuleValue(rvq
, count
);
451 freeRuleValue(newrvq
,
453 freeRuleValue(subrvq
, nr
);
459 freeRuleValue(rvq
, count
);
462 freeRuleValue(subrvq
, nr
);
466 /* We don't need valA anymore, so free it */
467 for (i
= 0; i
< numVals
; i
++)
468 freeValue(valA
[i
], 1);
471 if (*statP
!= SUCCESS
) {
472 freeRuleValue(rvq
, count
);
485 * Generate name=values pairs for splitfield names
488 * nisLDAPnameFields club:
489 * ("%s %s %s", name, code, members)
490 * nisLDAPsplitField members:
491 * ("(%s,%s,%s)", host, user, domain),
494 * - rv is an array of numVals rule-values each containing
495 * name=value pairs for names occuring in nisLDAPsplitField.
496 * (i.e host, user, domain, group)
497 * - trv contains name=value pairs for names occuring in
498 * nisLDAPnameFields. (i.e name, code but not members)
500 * For every name in nisLDAPnamefields that is a splitfield,
501 * this function applies the data in rv to the corresponding
502 * splitfield formats (accessed thru t), to generate a single
503 * string value for the corresponding splitfield (members).
504 * This new name=value pair is then added to trv.
505 * Besides, any uninitialized namefield names are set to empty strings.
508 addSplitFieldValues(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
,
509 __nis_rule_value_t
*trv
, int numVals
, char *domain
) {
510 __nis_table_mapping_t
*sf
;
512 int i
, j
, k
, nitems
, res
, statP
;
514 char delim
[2] = {0, 0};
516 char *myself
= "addSplitFieldValues";
519 return (MAP_INTERNAL_ERROR
);
524 nitems
= t
->e
->element
.match
.numItems
;
528 * - Check each name in nisLDAPnamefield
529 * - if it's a splifield, construct its value and add it to trv
530 * - if not, check if it has a value
531 * - if not, add empty string
533 for (i
= 0, sf
= 0; i
< nitems
; i
++) {
536 * str will eventually contain the single string
537 * value for the corresponding splitfield.
538 * No point initializing str if rv == 0 because
539 * splitfield cannot be constructed without rv.
540 * So, only initialized here.
544 /* Check if it's a splitfield name */
545 sf
= mappingFromMap(t
->e
->element
.match
.item
[i
].name
,
549 * Return only incase of memory allocation failure.
550 * The other error case (MAP_NO_MAPPING_EXISTS),
551 * indicates that the item name is not a splitfieldname
552 * i.e it's a namefieldname. This case is handled by
553 * the following if (sf == 0)
555 if (statP
== MAP_NO_MEMORY
)
561 * Not a splitfield name. Verify if it has a value
563 if (findVal(t
->e
->element
.match
.item
[i
].name
,
564 trv
, mit_nisplus
) == 0) {
565 /* if not, use empty string */
566 res
= addCol2RuleValue(vt_string
,
567 t
->e
->element
.match
.item
[i
].name
,
570 return (MAP_INTERNAL_ERROR
);
574 * If rv == 0 then sf == 0 so we will continue here
575 * i.e. does not matter that str is not yet set up.
580 /* Code to construct a single value */
582 /* Use the first separator character as the delimiter */
583 delim
[0] = sf
->separatorStr
[0];
585 for (j
= 0; j
< numVals
; j
++) {
586 /* sf->numSplits is zero-based */
587 for (k
= 0; k
<= sf
->numSplits
; k
++) {
588 val
= getMappingFormatArray(
589 sf
->e
[k
].element
.match
.fmt
, &rv
[j
],
591 sf
->e
[k
].element
.match
.numItems
,
592 sf
->e
[k
].element
.match
.item
);
595 if (val
->numVals
> 0) {
597 tempstr
= scat(myself
,
604 return (MAP_NO_MEMORY
);
607 tempstr
= scat(myself
, 0, str
,
614 return (MAP_NO_MEMORY
);
623 res
= addCol2RuleValue(vt_string
,
624 t
->e
->element
.match
.item
[i
].name
,
625 str
, strlen(str
), trv
);
631 return (MAP_INTERNAL_ERROR
);
639 * Updates 'rv' with NIS name=value pairs suitable to
640 * construct datum from namefield information.
641 * Some part based on createNisPlusEntry (from ldap_nisdbquery.c)
642 * This code assumes that from a given LDAP entry, applying the
643 * mapping rules, would give us one or more NIS entries, differing
647 buildNISRuleValue(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
,
649 int r
, i
, j
, k
, l
, nrq
, res
, len
;
650 int numItems
, splitname
, count
, statP
;
652 __nis_mapping_item_t
*litem
;
653 __nis_mapping_rule_t
*rl
;
654 __nis_rule_value_t
*rvq
;
655 char *value
, *emptystr
= "";
659 /* Initialize default base */
660 __nisdb_get_tsd()->searchBase
= t
->objectDN
->read
.base
;
662 /* Initialize rule-value rvq */
666 /* Add domainname to rule-value */
667 if (addCol2RuleValue(vt_string
, N2LDOMAIN
, domain
, strlen(domain
),
669 return (MAP_INTERNAL_ERROR
);
672 for (r
= 0; r
< t
->numRulesFromLDAP
; r
++) {
673 rl
= t
->ruleFromLDAP
[r
];
675 /* Set escapeFlag if RHS is "dn" to remove escape chars */
676 if (rl
->rhs
.numElements
== 1 &&
677 rl
->rhs
.element
->type
== me_item
&&
678 rl
->rhs
.element
->element
.item
.type
== mit_ldap
&&
679 strcasecmp(rl
->rhs
.element
->element
.item
.name
, "dn")
681 __nisdb_get_tsd()->escapeFlag
= '2';
684 rval
= buildRvalue(&rl
->rhs
, mit_ldap
, rv
, NULL
);
686 /* Reset escapeFlag */
687 __nisdb_get_tsd()->escapeFlag
= '\0';
693 if (rval
->numVals
<= 0) {
694 /* Treat as invalid */
699 litem
= buildLvalue(&rl
->lhs
, &rval
, &numItems
);
701 /* This will take care of numItems == 0 */
706 if (rval
->numVals
> 1) {
707 if (numItems
== 1 && litem
->repeat
)
709 else if (numItems
> 1 && rval
->repeat
)
710 nrq
= 1 + ((rval
->numVals
-1)/numItems
);
716 /* Set splitname if splitfield names are specified */
717 for (i
= 0; i
< numItems
; i
++) {
718 if (strcasecmp(litem
[i
].name
, N2LKEY
) == 0 ||
719 strcasecmp(litem
[i
].name
, N2LIPKEY
) == 0 ||
720 strcasecmp(litem
[i
].name
, N2LCOMMENT
) == 0)
722 for (j
= 0; j
< t
->numColumns
; j
++) {
723 if (strcmp(litem
[i
].name
, t
->column
[j
]) == 0)
726 if (j
== t
->numColumns
)
730 splitname
= (i
< numItems
)?1:0;
732 for (j
= 0; j
< nrq
; j
++) {
733 if (splitname
== 1) {
735 * Put every value of splitfieldname in a new
736 * rule-value. Helps generating splitfields.
738 rvq
= growRuleValue(count
, count
+ 1, rvq
, 0);
740 freeRuleValue(rvq
, count
);
742 freeMappingItem(litem
, numItems
);
743 return (MAP_INTERNAL_ERROR
);
748 for (k
= j
% nrq
, l
= 0; l
< numItems
; k
+= nrq
, l
++) {
749 /* If we run out of values, use empty strings */
750 if (k
>= rval
->numVals
) {
754 value
= rval
->val
[k
].value
;
755 len
= rval
->val
[k
].length
;
757 res
= (splitname
== 1)?addCol2RuleValue(
758 vt_string
, litem
[l
].name
, value
,
759 len
, &rvq
[count
- 1]):0;
761 res
= addCol2RuleValue(vt_string
,
762 litem
[l
].name
, value
, len
, rv
);
764 freeRuleValue(rvq
, count
);
766 freeMappingItem(litem
, numItems
);
767 return (MAP_INTERNAL_ERROR
);
773 freeMappingItem(litem
, numItems
);
776 } /* for r < t->numRulesFromLDAP */
778 statP
= addSplitFieldValues(t
, rvq
, rv
, count
, domain
);
781 freeRuleValue(rvq
, count
);
783 if (verifyIndexMatch(t
, 0, rv
, 0, 0) == 0)
784 return (MAP_INDEXLIST_ERROR
);
787 } /* end of buildNISRuleValue */
790 * Convert rule-value to datum using namefield information
793 ruleValueToDatum(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
, int *statP
) {
796 char *str
, *cstr
, commentSep
[3] = {' ', 0, 0};
797 char *myself
= "ruleValueToDatum";
802 /* Return empty datum if no namefield information available */
804 if ((value
= am(myself
, sizeof (*value
))) == 0)
805 *statP
= MAP_NO_MEMORY
;
809 val
= getMappingFormatArray(t
->e
->element
.match
.fmt
, rv
,
810 fa_item
, t
->e
->element
.match
.numItems
,
811 t
->e
->element
.match
.item
);
813 if (val
&& val
->val
&& val
->val
->value
) {
814 if ((value
= am(myself
, sizeof (*value
))) == 0) {
815 *statP
= MAP_NO_MEMORY
;
820 /* Strip trailing whitespaces */
821 cstr
= (char *)val
->val
->value
+ val
->val
->length
;
822 for (; cstr
>= (char *)val
->val
->value
&&
823 (*cstr
== ' ' || *cstr
== '\t'); *cstr
-- = '\0');
825 if (t
->commentChar
!= '\0' &&
826 (str
= findVal(N2LCOMMENT
, rv
, mit_nisplus
)) != 0 &&
828 commentSep
[1] = t
->commentChar
;
829 cstr
= scat(myself
, F
, commentSep
, str
);
831 value
->dptr
= scat(myself
, F
,
832 val
->val
->value
, cstr
);
836 value
->dptr
= sdup(myself
, T
, val
->val
->value
);
840 value
->dsize
= strlen(value
->dptr
);
843 *statP
= MAP_NO_MEMORY
;
849 *statP
= MAP_NAMEFIELD_MATCH_ERROR
;
854 getKeyFromRuleValue(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
, int *nv
,
855 int *statP
, bool_t xlate_to_lcase
)
860 char *myself
= "getKeyFromRuleValue";
865 if (rv
== 0 || nv
== 0)
868 for (i
= 0; i
< rv
->numColumns
; i
++) {
869 if (rv
->colName
[i
] == 0)
871 if (strcasecmp(N2LKEY
, rv
->colName
[i
]) == 0 ||
872 strcasecmp(N2LIPKEY
, rv
->colName
[i
]) == 0) {
873 if ((*nv
= rv
->colVal
[i
].numVals
) == 0)
875 if ((key
= am(myself
, sizeof (key
[0]) * *nv
)) == 0) {
876 *statP
= MAP_NO_MEMORY
;
879 for (j
= 0; j
< *nv
; j
++) {
880 if ((str
= rv
->colVal
[i
].val
[j
].value
) == 0) {
884 if (verifyIndexMatch(t
, 0, 0,
885 rv
->colName
[i
], str
) == 0) {
891 key
[j
].dsize
= strlen(str
);
892 key
[j
].dptr
= am(myself
,
894 if (key
[j
].dptr
== 0) {
895 *statP
= MAP_NO_MEMORY
;
896 for (--j
; j
>= 0; j
--)
902 /* transliterate key to lowercase */
903 if (xlate_to_lcase
== TRUE
) {
908 * "YP_MULTI_" prefix.
911 if (strncmp(YPMULTI
, str
,
914 bcopy(str
, key
[j
].dptr
,
917 while (k
< key
[j
].dsize
) {
918 char *d
= key
[j
].dptr
;
926 bcopy(str
, key
[j
].dptr
,
938 * Get the mapping structure corresponding to `map,domain.'
940 __nis_table_mapping_t
*
941 mappingFromMap(char *map
, char *domain
, int *statP
) {
943 __nis_table_mapping_t
*t
;
948 /* Construct map,domain. */
949 if ((mapPath
= getFullMapName(map
, domain
)) == 0) {
950 *statP
= MAP_NO_MEMORY
;
954 /* Get the hash table entry for the mapPath */
955 if ((t
= __nis_find_item_mt(mapPath
, &ldapMappingList
, 1, 0))
957 *statP
= MAP_NO_MAPPING_EXISTS
;
964 * Verify at least one key value obtained from DIT matches the search key
970 verifyKey(char *key
, __nis_rule_value_t
*rv
) {
974 for (i
= 0; i
< rv
->numColumns
; i
++) {
975 if (rv
->colName
[i
] == 0)
977 if (strcasecmp(N2LKEY
, rv
->colName
[i
]) == 0) {
978 if (rv
->colVal
[i
].val
== 0)
980 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++) {
981 str
= (char *)rv
->colVal
[i
].val
[j
].value
;
982 if (str
&& strcmp(str
, key
) == 0)
986 } else if (strcasecmp(N2LIPKEY
, rv
->colName
[i
]) == 0) {
987 if (checkIPaddress(key
, strlen(key
), &sipkey
) > 0) {
988 if (rv
->colVal
[i
].val
== 0)
990 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++) {
991 str
= rv
->colVal
[i
].val
[j
].value
;
992 if (str
&& strcmp(str
, sipkey
) == 0) {
1006 * Read (i.e get and map) a single NIS entry from the LDAP DIT
1009 singleReadFromDIT(char *map
, char *domain
, datum
*key
, datum
*value
,
1011 __nis_table_mapping_t
*t
;
1012 __nis_rule_value_t
*rv_request
= 0, *rv_result
= 0;
1013 __nis_ldap_search_t
*ls
;
1014 __nis_object_dn_t
*objectDN
= NULL
;
1018 char *myself
= "singleReadFromDIT";
1022 if (!map
|| !domain
|| !key
|| !value
) {
1023 *statP
= MAP_PARAM_ERROR
;
1028 /* Get the mapping information for the map */
1029 if ((t
= mappingFromMap(map
, domain
, statP
)) == 0) {
1031 * No problem. We don't handle this map and domain. Maybe it's
1032 * handled by a service other than NIS.
1037 /* NULL-terminated version of datum key for logging */
1038 if ((skey
= am(myself
, key
->dsize
+ 1)) == 0) {
1039 *statP
= MAP_NO_MEMORY
;
1042 (void) memcpy(skey
, key
->dptr
, key
->dsize
);
1044 if ((str
= getFullMapName(map
, domain
)) == 0) {
1045 *statP
= MAP_NO_MEMORY
;
1049 /* For each alternate mapping */
1050 for (; t
!= 0; t
= t
->next
) {
1051 /* Verify objName */
1052 if (strcmp(str
, t
->objName
) != 0) {
1056 /* Verify if key matches the index */
1057 if (verifyIndexMatch(t
, 0, 0, N2LKEY
, skey
) == 0 ||
1058 verifyIndexMatch(t
, 0, 0, N2LIPKEY
, skey
) == 0)
1061 /* Check if rulesFromLDAP are provided */
1062 if (t
->numRulesFromLDAP
== 0) {
1063 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1064 "%s: No rulesFromLDAP information available "
1065 "for %s (%s)", myself
, t
->dbId
, map
);
1069 /* Convert key into rule-value */
1070 if ((rv_request
= datumToRuleValue(key
, 0, t
, 0, domain
, TRUE
,
1072 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1073 "%s: Conversion error %d (NIS to name=value "
1074 "pairs) for NIS key (%s) for %s (%s)",
1075 myself
, *statP
, skey
, t
->dbId
, map
);
1078 /* Convert rule-value into ldap request */
1079 for (objectDN
= t
->objectDN
; objectDN
&&
1080 objectDN
->read
.base
;
1081 objectDN
= objectDN
->next
) {
1082 ls
= createLdapRequest(t
, rv_request
, 0, 1, NULL
,
1085 *statP
= MAP_CREATE_LDAP_REQUEST_ERROR
;
1086 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1087 "%s: Failed to create ldapSearch "
1089 "NIS key (%s) for %s (%s) "
1091 myself
, skey
, t
->dbId
, map
,
1092 objectDN
->read
.base
);
1095 ls
->timeout
.tv_sec
= SINGLE_ACCESS_TIMEOUT_SEC
;
1096 ls
->timeout
.tv_usec
= SINGLE_ACCESS_TIMEOUT_USEC
;
1098 nr
= (ls
->isDN
)?0:-1;
1099 rv_result
= ldapSearch(ls
, &nr
, 0, statP
);
1101 if (rv_result
== 0) {
1102 if (*statP
== LDAP_NO_SUCH_OBJECT
) {
1103 /* Entry does not exist in */
1104 /* the ldap server */
1108 freeRuleValue(rv_request
, 1);
1111 /* if result > 1, first match will be returned */
1113 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1114 "%s: %d ldapSearch results "
1116 "for %s (%s) for base %s. "
1117 "First match will be returned ",
1118 myself
, nr
, skey
, t
->dbId
, map
,
1119 objectDN
->read
.base
);
1122 for (i
= 0; i
< nr
; i
++) {
1123 /* Convert LDAP data to NIS equivalents */
1124 *statP
= buildNISRuleValue(t
, &rv_result
[i
],
1126 if (*statP
== MAP_INDEXLIST_ERROR
)
1129 if (*statP
!= SUCCESS
) {
1130 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1131 "%s: Conversion error %d (LDAP to "
1132 "name=value pairs) for NIS key (%s) "
1133 "for %s (%s) for base %s", myself
,
1135 t
->dbId
, map
, objectDN
->read
.base
);
1140 * Check if 'key' from the ldap result matches the key
1141 * provided by our caller
1143 if ((rc
= verifyKey(skey
, &rv_result
[i
]))
1145 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1146 "%s: Cannot verify key from ldap "
1147 "result for NIS key (%s) for %s (%s) "
1149 myself
, skey
, t
->dbId
, map
,
1150 objectDN
->read
.base
);
1155 datval
= ruleValueToDatum(t
,
1156 &rv_result
[i
], statP
);
1158 logmsg(MSG_NOTIMECHECK
,
1160 "%s: Conversion error %d "
1161 "(name=value pairs to NIS) "
1162 "for NIS key (%s) for %s (%s)"
1165 *statP
, skey
, t
->dbId
, map
,
1166 objectDN
->read
.base
);
1170 value
->dptr
= datval
->dptr
;
1171 value
->dsize
= datval
->dsize
;
1175 freeRuleValue(rv_result
, nr
);
1179 /* Free full map name */
1185 freeRuleValue(rv_result
, nr
);
1187 } /* end of for over objectDN */
1189 if (rv_request
!= 0) {
1190 freeRuleValue(rv_request
, 1);
1193 if (rv_result
!= 0) {
1194 freeRuleValue(rv_result
, nr
);
1199 *statP
= MAP_NO_MATCHING_KEY
;
1201 /* Free full map name */
1209 * Maps and writes a single NIS entry to the LDAP DIT
1212 singleWriteToDIT(char *map
, char *domain
, datum
*key
, datum
*value
,
1214 __nis_table_mapping_t
*t
;
1215 __nis_rule_value_t
*rv
, *frv
;
1216 __nis_ldap_search_t
*ls
;
1217 int statP
= SUCCESS
, flag
;
1218 int nv
, nr
, i
, rc
, collapse
;
1219 char *dn
= 0, *skey
, *svalue
, *str
;
1220 char *myself
= "singleWriteToDIT";
1223 if (!map
|| !domain
|| !key
|| !value
) {
1224 return (MAP_PARAM_ERROR
);
1228 /* Return SUCCESS for empty or whitespace key */
1229 for (i
= 0; i
< key
->dsize
&& (keystr
[i
] == 0 ||
1230 keystr
[i
] == ' ' || keystr
[i
] == '\t'); i
++);
1231 if (i
>= key
->dsize
)
1234 /* Get the mapping information for the map */
1235 if ((t
= mappingFromMap(map
, domain
, &statP
)) == 0) {
1237 * No problem. We don't handle this map and domain. Maybe it's
1238 * handled by a service other than NIS.
1243 /* NULL-terminated version of key and value for logging */
1244 if ((skey
= am(myself
, key
->dsize
+ 1)) == 0)
1245 return (MAP_NO_MEMORY
);
1246 (void) memcpy(skey
, key
->dptr
, key
->dsize
);
1248 if ((svalue
= am(myself
, value
->dsize
+ 1)) == 0) {
1250 return (MAP_NO_MEMORY
);
1252 (void) memcpy(svalue
, value
->dptr
, value
->dsize
);
1254 if ((str
= getFullMapName(map
, domain
)) == 0) {
1257 return (MAP_NO_MEMORY
);
1260 /* For each alternate mapping */
1261 for (flag
= 0; t
!= 0; t
= t
->next
) {
1262 /* Verify objName */
1263 if (strcmp(str
, t
->objName
) != 0) {
1267 /* Verify if key matches the index */
1268 if (verifyIndexMatch(t
, 0, 0, N2LKEY
, skey
) == 0 ||
1269 verifyIndexMatch(t
, 0, 0, N2LIPKEY
, skey
) == 0)
1272 /* Check the writespecs */
1273 if (t
->objectDN
->write
.base
== 0) {
1274 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1275 "%s: No baseDN in writespec. Write disabled "
1276 "for %s (%s)", myself
, t
->dbId
, map
);
1280 /* Check if rulesToLDAP are provided */
1281 if (t
->numRulesToLDAP
== 0) {
1282 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1283 "%s: No rulesToLDAP. Write disabled for "
1284 "%s (%s)", myself
, t
->dbId
, map
);
1288 /* Set flag to indicate write is enabled */
1291 /* Convert key and value into an array of rule-values */
1292 if ((rv
= datumToRuleValue(key
, value
, t
, &nv
, domain
, FALSE
,
1294 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1295 "%s: Conversion error %d (NIS to name=value "
1296 "pairs) for NIS data (key=%s, value=%s) "
1298 myself
, statP
, skey
, svalue
, t
->dbId
, map
);
1302 /* Free full map name */
1308 /* Convert NIS data to LDAP equivalents for each rule-value */
1309 for (i
= 0; i
< nv
; i
++) {
1310 /* Verify indexlist with name=value pairs */
1311 if (verifyIndexMatch(t
, 0, &rv
[i
], 0, 0) == 0)
1314 /* Create LDAP request and LDAP name=value pairs */
1315 if ((ls
= createLdapRequest(t
, &rv
[i
],
1316 0, 0, NULL
, NULL
)) == 0) {
1317 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1318 "%s: Conversion error (name=value pairs"
1319 " to LDAP) for NIS data "
1320 "(key=%s, value=%s) for %s (%s)",
1321 myself
, skey
, svalue
, t
->dbId
, map
);
1322 freeRuleValue(rv
, nv
);
1326 /* Free full map name */
1329 return (MAP_CREATE_LDAP_REQUEST_ERROR
);
1332 /* printRuleValue(&rv[i]); */
1335 /* If i < nv then this alternate mapping isn't the one */
1340 * Merge rule-values with the same DN so that we have
1341 * one ldap write request for each DN
1344 frv
= mergeRuleValueWithSameDN(rv
, &nr
);
1345 freeRuleValue(rv
, nv
);
1348 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1349 "%s: Unable to merge LDAP write "
1350 "requests to same DN for NIS data "
1351 "(key=%s, value=%s) for %s (%s)",
1352 myself
, skey
, svalue
, t
->dbId
, map
);
1353 statP
= MAP_INTERNAL_ERROR
;
1354 } else if (nr
== 0) {
1355 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1356 "%s: Cannot generate write DN due to "
1357 "missing information for NIS data "
1358 "(key=%s, value=%s) for %s (%s)",
1359 myself
, skey
, svalue
, t
->dbId
, map
);
1365 /* Free full map name */
1371 /* Write to the LDAP server */
1372 for (collapse
= 0, i
= 0; i
< nr
; i
++) {
1373 if ((dn
= findVal("dn", &frv
[i
], mit_ldap
)) != 0) {
1374 if (replace
== FALSE
) {
1376 rc
= ldapAdd(dn
, &frv
[i
],
1377 t
->objectDN
->write
.attrs
, 0);
1379 /* ldap modify with addFirst set */
1380 rc
= ldapModify(dn
, &frv
[i
],
1381 t
->objectDN
->write
.attrs
, 1);
1384 /* if we get err=20, collapse and try again */
1386 (rc
== LDAP_TYPE_OR_VALUE_EXISTS
) &&
1387 (collapseRuleValue(&frv
[i
]) == 1)) {
1388 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1389 "%s: Ignoring values differing "
1390 "in case from NIS data (key=%s,"
1391 " value=%s) for (dn: %s) for "
1392 "%s (%s)", myself
, skey
,
1393 svalue
, dn
, t
->dbId
, map
);
1400 if (rc
!= LDAP_SUCCESS
) {
1402 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1403 "%s: %s error %d (%s) for "
1404 "(dn: %s) for NIS data "
1405 "(key=%s, value=%s) "
1407 myself
, (replace
== TRUE
) ?
1408 "ldapModify" : "ldapAdd", rc
,
1409 ldap_err2string(rc
), dn
, skey
,
1410 svalue
, t
->dbId
, map
);
1412 /* Dumping failed call may be useful */
1413 /* printRuleValue(&frv[i]); */
1416 * Return the error code and let wrapper
1417 * sort out if mapping should continue
1423 freeRuleValue(frv
, nr
);
1425 /* Free full map name */
1433 freeRuleValue(frv
, nr
);
1439 /* Free full map name */
1442 return ((flag
)?SUCCESS
:MAP_WRITE_DISABLED
);
1446 collapseRuleValue(__nis_rule_value_t
*rv
) {
1449 /* Using 'val' to appease cstyle's 80 chars/line limit */
1452 for (i
= 0, flag
= 0; i
< rv
->numAttrs
; i
++) {
1453 val
= &rv
->attrVal
[i
];
1454 for (j
= 1; j
< val
->numVals
; j
++) {
1455 for (k
= 0; k
< j
; k
++) {
1456 if (val
->val
[j
].length
!= val
->val
[k
].length
)
1458 if (val
->val
[k
].length
== 0)
1460 if (strncasecmp(val
->val
[j
].value
,
1462 val
->val
[j
].length
) != 0)
1465 sfree(val
->val
[j
].value
);
1467 #ifdef ORDER_NOT_IMPORTANT
1468 val
->val
[j
--] = val
->val
[--val
->numVals
];
1470 /* Order needs to be maintained */
1471 for (k
= j
+ 1; k
< val
->numVals
; k
++)
1472 val
->val
[k
- 1] = val
->val
[k
];
1483 /* ObjectClass lookup table */
1485 const char *attrType
;
1486 const char *objectClass
;
1488 { "o", "objectclass=organization"},
1489 { "organizationname", "objectclass=organization"},
1490 { "2.5.4.10", "objectclass=organization"},
1491 { "ou", "objectclass=organizationalunit"},
1492 { "organizationalunitname", "objectclass=organizationalunit"},
1493 { "2.5.4.11", "objectclass=organizationalunit"},
1494 { "c", "objectclass=country"},
1495 { "countryname", "objectclass=country"},
1496 { "2.5.4.6", "objectclass=country"},
1497 { "dc", "objectclass=domain"},
1498 { "domaincomponent", "objectclass=domain"},
1499 { "0.9.2342.19200300.100.1.25", "objectclass=domain"},
1500 { "nismapname", "objectclass=nismap"},
1501 { "1.3.6.1.1.1.1.26", "objectclass=nismap"},
1502 { "automountmapname", "objectclass=automountmap"},
1503 { "1.3.6.1.1.1.1.31", "objectclass=automountmap"},
1508 * Returns the name of the objectclass to which the object
1509 * represented by the given 'rdn' will most likely belong to.
1510 * The return value is in static memory so it should not be
1514 getObjectClass(char *rdn
) {
1519 /* Skip leading whitespaces */
1520 for (p
= rdn
; *p
== ' ' || *p
== '\t'; p
++);
1526 if ((p
= strchr(attrtype
, '=')) == 0 || p
== attrtype
||
1531 * Skip trailing whitespaces in attrtype
1532 * Don't worry, p won't decrease beyond attrtype
1534 for (--p
; *p
== ' ' || *p
== '\t'; p
--);
1535 len
= p
- attrtype
+ 1;
1537 for (i
= 0; oc_lookup
[i
].attrType
; i
++)
1538 if (!strncasecmp(oc_lookup
[i
].attrType
, attrtype
, len
))
1539 /* Check length is right */
1540 if (len
== strlen(oc_lookup
[i
].attrType
))
1541 return (oc_lookup
[i
].objectClass
);
1547 * Split 'dn' into rdn and parentdn based on the first
1548 * occurrence of unescaped 'comma' or 'semicolon'. rdn
1549 * lies on the LHS while parentdn lies on the RHS of the
1550 * split. If none found, then an empty string ("") is
1551 * assigned to parentdn
1554 splitDN(char *dn
, char **rdn
, char **parentdn
) {
1556 char *myself
= "splitDN";
1558 if ((name
= sdup(myself
, T
, dn
)) == 0)
1561 for (value
= name
; *value
!= '\0'; value
++) {
1562 if (*value
== ',' || *value
== ';')
1563 if (value
== name
|| *(value
- 1) != '\\')
1567 if (*value
!= '\0') {
1574 if ((*parentdn
= sdup(myself
, T
, value
)) == 0) {
1588 * FUNCTION : makeNISObject()
1590 * DESCRIPTION: Sets up a nis Object in the DIT.
1593 * Case 1: Both 'domain' and 'dn' are non-NULL
1594 * Create nisDomainObject with the given information
1595 * Case 2: Only 'domain' is non-NULL
1596 * Obtain the 'dn' from the nisLDAPdomainContext list
1597 * Create nisDomainObject with the above information
1598 * Case 3: Only 'dn' is non-NULL
1599 * Create an object with the 'dn'
1600 * Here we guess the objectclass attribute, based on
1602 * Case 4: Both 'domain' and 'dn' are NULL
1605 * RETURNS : SUCCESS = It worked
1606 * FAILURE = There was a problem.
1609 makeNISObject(char *domain
, char *dn
) {
1610 __nis_rule_value_t
*rv
;
1611 __nis_ldap_search_t
*ls
;
1612 int i
, rc
, nr
, add_rc
;
1614 char *myself
= "makeNISObject";
1620 * If only 'domain' name is provided, then
1621 * try to find dn from the nisLDAPdomainContext
1622 * list generated by the parser
1625 for (i
= 0; i
< ypDomains
.numDomains
; i
++) {
1626 if (ypDomains
.domainLabels
[i
] == 0)
1628 if (strcasecmp(domain
, ypDomains
.domainLabels
[i
])
1630 dn
= ypDomains
.domains
[i
];
1639 * If only 'dn' is given, then it means that the
1640 * caller simply wants to a create an entry for
1643 * If 'domain' is given, then check if the 'dn'
1644 * has already been set up as a nis domain object.
1645 * If not, see if we can make it become one.
1649 * Check to see if the nis domain object has
1650 * already been set up
1652 ls
= buildLdapSearch(dn
, LDAP_SCOPE_BASE
, 0, 0,
1653 "objectclass=*", 0, 0, 0);
1655 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1656 "%s: Unable to create ldapSearch "
1657 "request for dn: %s", myself
, dn
);
1661 rv
= ldapSearch(ls
, &nr
, 0, &rc
);
1663 if (rc
== LDAP_SUCCESS
) {
1664 val
= findVal("nisDomain", rv
, mit_ldap
);
1667 * Yes, nis domain object found. Check
1668 * to see if the domain names match.
1669 * If so, we are done. If not, log
1670 * a warning message, and return SUCCESS.
1672 if (strcasecmp(val
, domain
) == 0) {
1673 freeRuleValue(rv
, nr
);
1676 logmsg(MSG_NOTIMECHECK
,
1678 "%s: Entry (dn: %s) already "
1679 "contains a nis domain name "
1680 "(%s). The domain name (%s) "
1682 myself
, dn
, val
, domain
);
1683 freeRuleValue(rv
, nr
);
1687 freeRuleValue(rv
, nr
);
1689 * Entry for the 'dn' exists, but it
1690 * is not a nis domain object yet.
1691 * Add the nisDoamin attribute and
1692 * the nisDomainObject objectclass to
1695 if ((rv
= initRuleValue(1, 0)) == 0)
1698 if (addSAttr2RuleValue("nisDomain",
1699 domain
, rv
) == -1) {
1700 freeRuleValue(rv
, 1);
1703 rc
= ldapModify(dn
, rv
,
1704 "objectclass=nisDomainObject",
1706 freeRuleValue(rv
, 1);
1707 if (rc
== LDAP_SUCCESS
) {
1708 logmsg(MSG_NOTIMECHECK
,
1710 "%s: entry (dn: %s) "
1711 "modified to be an "
1712 "nis domain object",
1716 logmsg(MSG_NOTIMECHECK
,
1718 "%s: unable to modify "
1719 "entry (dn: %s) to be "
1720 "a nis domain object: "
1721 "ldapModify error %d (%s)",
1723 ldap_err2string(rc
));
1727 } else { /* search for 'dn' failed */
1728 freeRuleValue(rv
, nr
);
1731 * It is OK if no such object, otherwise
1734 if (rc
!= LDAP_NO_SUCH_OBJECT
) {
1735 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1736 "%s: unable to retrieve "
1738 "ldapSearch error %d (%s)",
1740 ldap_err2string(rc
));
1746 * If the 'dn' is actually the naming context of
1747 * the DIT, we should be able to make it a nis domain
1748 * object without worrying about missing parent
1749 * entries. If unable to add the entry for the 'dn'
1750 * due to missing parent entries, fall through
1751 * to create them and then add the nis domain object.
1753 if (addNISObject(domain
, dn
, &add_rc
) == SUCCESS
)
1755 else if (add_rc
!= LDAP_NO_SUCH_OBJECT
)
1760 if (addParent(dn
, NULL
) == FAILURE
)
1763 if (addNISObject(domain
, dn
, NULL
) == FAILURE
)
1770 addParent(char *dn
, char **attr
) {
1771 __nis_rule_value_t
*rv
;
1772 __nis_ldap_search_t
*ls
;
1774 char *parentdn
= 0, *rdn
= 0;
1775 char *myself
= "addParent";
1777 /* Obtain parentdn */
1778 if (splitDN(dn
, &rdn
, &parentdn
) == -1)
1785 /* Check if parentdn exists */
1786 ls
= buildLdapSearch(parentdn
, LDAP_SCOPE_BASE
, 0, 0,
1787 "objectclass=*", 0, 0, 0);
1789 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1790 "%s: Unable to create ldapSearch request for "
1791 "parent (dn: %s) of (dn: %s)",
1792 myself
, parentdn
, dn
);
1798 rv
= ldapSearch(ls
, &nr
, 0, &rc
);
1800 freeRuleValue(rv
, nr
);
1802 /* Create parent if it doesn't exists */
1803 if (rc
== LDAP_NO_SUCH_OBJECT
) {
1804 if (makeNISObject(0, parentdn
) == FAILURE
) {
1805 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1806 "%s: Unable to create parent (dn: %s) of "
1807 "(dn: %s) in the DIT", myself
, parentdn
, dn
);
1816 *attr
= (char *)getObjectClass(rdn
);
1825 * FUNCTION : is_fatal_error()
1827 * DESCRIPTION: Works out if a failed mapping operation should be retried.
1829 * INPUTS : Result code from operation
1831 * OUTPUTS : TRUE = Fatal error, don't retry.
1832 * FALSE = Temporary error, retry.
1835 is_fatal_error(int res
)
1839 /* An internal mapping error. Not going to go away. */
1843 case (LDAP_PROTOCOL_ERROR
):
1844 case (LDAP_TIMELIMIT_EXCEEDED
):
1845 case (LDAP_PARTIAL_RESULTS
):
1847 case (LDAP_UNAVAILABLE
):
1848 case (LDAP_UNWILLING_TO_PERFORM
):
1850 case (LDAP_SERVER_DOWN
):
1851 case (LDAP_LOCAL_ERROR
):
1852 case (LDAP_TIMEOUT
):
1853 case (LDAP_NO_MEMORY
):
1854 /* Probably worth a retry */
1863 * FUNCTION : addNISObject()
1865 * DESCRIPTION: Add a nis Object in the DIT.
1868 * Case 1: 'dn' is NULL
1870 * Case 2: 'domain' is non-NULL
1871 * Create nisDomainObject with the given information
1872 * Case 3: 'domain' is NULL
1873 * Create an object with the 'dn'
1874 * Here we guess the objectclass attribute, based on
1877 * RETURNS : SUCCESS = It worked
1878 * FAILURE = There was a problem. If the ldap add
1879 * operation failed, ldap_rc will be set
1880 * to the ldap error code.
1883 addNISObject(char *domain
, char *dn
, int *ldap_rc
) {
1884 __nis_rule_value_t
*rv
;
1886 char *objClassAttrs
= NULL
, *attrs
;
1887 char *value
, *svalue
, *rdn
= NULL
;
1888 char *myself
= "addNISObject";
1893 if ((rv
= initRuleValue(1, 0)) == 0)
1900 * Add name=value pairs from RDN. Although this is not required
1901 * for SunOne Directory Server, during openldap interoperabilty
1902 * tests, it was found out that openldap server returned object
1903 * class violation errors if MUST attributes were not specified
1906 if (splitDN(dn
, &rdn
, 0) == -1)
1909 objClassAttrs
= (char *)getObjectClass(rdn
);
1910 if (objClassAttrs
== NULL
) {
1916 * RDN can be composed of multiple name=value pairs
1917 * concatenated by '+'. Hence, we need to determine each
1918 * pair and add it to 'rv'
1920 for (value
= rdn
, svalue
= NULL
; *value
!= '\0'; value
++) {
1921 if (*value
== '+') {
1922 /* Make sure it's not escaped */
1923 if (value
== rdn
|| *(value
- 1) != '\\') {
1925 * We are at the start of the new
1926 * pair. 'svalue' now contains the
1927 * value for the previous pair. Add
1928 * the previous pair to 'rv'
1932 addSAttr2RuleValue(rdn
, svalue
, rv
)
1935 freeRuleValue(rv
, 1);
1944 if (*value
== '=') {
1945 if (value
== rdn
|| *(value
- 1) != '\\') {
1947 * 'rdn' now contains the name.
1948 * Whatever follows till the next
1949 * unescaped '+' or '\0' is the
1950 * value for this pair.
1960 * End of String. Add the previous name=value pair to 'rv'
1962 if (svalue
&& addSAttr2RuleValue(rdn
, svalue
, rv
) == -1) {
1964 freeRuleValue(rv
, 1);
1968 } else /* rdn == NULL */
1971 /* Create the entry */
1973 if (addSAttr2RuleValue("nisDomain", domain
, rv
) == -1) {
1974 freeRuleValue(rv
, 1);
1977 attrs
= scat(myself
, F
, "objectclass=nisdomainobject,",
1980 freeRuleValue(rv
, 1);
1983 rc
= ldapAdd(dn
, rv
, attrs
, 0);
1986 rc
= ldapAdd(dn
, rv
, objClassAttrs
, 0);
1989 if (rc
== LDAP_SUCCESS
)
1990 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1991 "%s: Entry (dn: %s) added to DIT",
1993 else if (rc
== LDAP_ALREADY_EXISTS
)
1994 /* Treat this as success */
1997 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1998 "%s: ldapAdd error %d (%s) for (dn: %s)",
1999 myself
, rc
, ldap_err2string(rc
), dn
);
2001 freeRuleValue(rv
, 1);
2004 return ((rc
== LDAP_SUCCESS
)?SUCCESS
:FAILURE
);