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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
35 #include "ldap_util.h"
37 #include "ldap_ruleval.h"
38 #include "ldap_attr.h"
40 #include "ldap_ldap.h"
45 __nis_mapping_format_t
*
46 cloneMappingFormat(__nis_mapping_format_t
*m
) {
47 __nis_mapping_format_t
*new;
49 char *myself
= "cloneMappingFormat";
54 for (nf
= 0; m
[nf
].type
!= mmt_end
; nf
++);
57 new = am(myself
, nf
* sizeof (new[0]));
61 /* Copy the whole array */
62 memcpy(new, m
, nf
* sizeof (new[0]));
64 /* Make copies of allocated stuff */
65 for (i
= 0, err
= 0; i
< nf
; i
++) {
68 new[i
].match
.string
= sdup(myself
, T
,
70 if (new[i
].match
.string
== 0 && m
[i
].match
.string
!= 0)
74 new[i
].match
.single
.lo
=
75 am(myself
, m
[i
].match
.single
.numRange
*
76 sizeof (new[i
].match
.single
.lo
[0]));
77 new[i
].match
.single
.hi
=
78 am(myself
, m
[i
].match
.single
.numRange
*
79 sizeof (new[i
].match
.single
.hi
[0]));
80 if (new[i
].match
.single
.lo
!= 0)
81 memcpy(new[i
].match
.single
.lo
,
83 m
[i
].match
.single
.numRange
);
84 else if (m
[i
].match
.single
.lo
!= 0)
86 if (new[i
].match
.single
.hi
!= 0)
87 memcpy(new[i
].match
.single
.hi
,
89 m
[i
].match
.single
.numRange
);
90 else if (m
[i
].match
.single
.hi
!= 0)
94 new[i
].match
.berString
= sdup(myself
, T
,
95 m
[i
].match
.berString
);
96 if (new[i
].match
.berString
== 0 &&
97 m
[i
].match
.berString
!= 0)
110 /* If there were memory allocation errors, free the copy */
112 freeMappingFormat(new);
120 freeMappingFormat(__nis_mapping_format_t
*m
) {
126 for (i
= 0; m
[i
].type
!= mmt_end
; i
++) {
129 sfree(m
[i
].match
.string
);
132 sfree(m
[i
].match
.single
.lo
);
133 sfree(m
[i
].match
.single
.hi
);
136 sfree(m
[i
].match
.berString
);
153 copyIndex(__nis_index_t
*old
, __nis_index_t
*new, int *err
) {
155 char *myself
= "copyIndex";
157 if (old
== 0 || new == 0) {
162 for (i
= 0; i
< old
->numIndexes
; i
++) {
163 new->name
[i
] = sdup(myself
, T
, old
->name
[i
]);
164 if (new->name
[i
] == 0 && old
->name
[i
] != 0) {
168 new->value
[i
] = cloneMappingFormat(old
->value
[i
]);
169 if (new->value
[i
] == 0 && old
->value
[i
] != 0) {
175 new->numIndexes
= old
->numIndexes
;
179 cloneIndex(__nis_index_t
*old
) {
180 char *myself
= "cloneIndex";
182 __nis_index_t
*new = am(myself
, sizeof (*new));
188 copyIndex(old
, new, &err
);
199 freeIndex(__nis_index_t
*old
, bool_t doFree
) {
205 for (i
= 0; i
< old
->numIndexes
; i
++) {
207 freeMappingFormat(old
->value
[i
]);
215 cloneName(char **name
, int numNames
) {
218 char *myself
= "cloneName";
220 if (name
== 0 || numNames
<= 0)
223 new = am(myself
, numNames
* sizeof (new[0]));
227 for (i
= 0; i
< numNames
; i
++) {
229 new[i
] = sdup(myself
, T
, name
[i
]);
231 for (i
--; i
>= 0; i
--) {
246 freeValue(__nis_value_t
*val
, int count
) {
252 for (c
= 0; c
< count
; c
++) {
253 if (val
[c
].val
!= 0) {
254 for (i
= 0; i
< val
[c
].numVals
; i
++) {
255 sfree(val
[c
].val
[i
].value
);
265 cloneValue(__nis_value_t
*val
, int count
) {
268 char *myself
= "cloneValue";
270 if (count
<= 0 || val
== 0)
273 n
= am(myself
, count
* sizeof (*n
));
277 for (c
= 0; c
< count
; c
++) {
278 n
[c
].type
= val
[c
].type
;
279 n
[c
].repeat
= val
[c
].repeat
;
280 n
[c
].numVals
= val
[c
].numVals
;
281 if (n
[c
].numVals
> 0) {
282 n
[c
].val
= am(myself
, n
[c
].numVals
*
283 sizeof (n
[c
].val
[0]));
291 for (i
= 0; i
< n
[c
].numVals
; i
++) {
292 int amlen
= val
[c
].val
[i
].length
;
295 * The functions that create string values try to
296 * make sure that there's a NUL at the end. However,
297 * both NIS+ and LDAP have a tendency to store strings
298 * without a NUL, so the value length may not include
299 * the NUL (even though it's there). In order to
300 * preserve that NUL, we add a byte to the length if
301 * the type is vt_string, and there isn't already a
302 * NUL at the end. The memory allocation function
303 * (am()) will take care of actually putting the NUL
304 * in place, since it allocates zero-initialized
307 n
[c
].val
[i
].length
= val
[c
].val
[i
].length
;
308 if (n
[c
].type
== vt_string
&& amlen
> 0 &&
309 ((char *)val
[c
].val
[i
].value
)[amlen
-1] !=
313 n
[c
].val
[i
].value
= am(myself
, amlen
);
314 if (amlen
> 0 && n
[c
].val
[i
].value
== 0) {
318 memcpy(n
[c
].val
[i
].value
, val
[c
].val
[i
].value
,
326 /* Define LBER_USE_DER per ber_decode(3LDAP) */
328 #define LBER_USE_DER 0x01
329 #endif /* LBER_USE_DER */
332 * Return a copy of 'valIn' where each value has been replaced by the
333 * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged.
336 berEncode(__nis_value_t
*valIn
, char *berstring
) {
337 char *myself
= "berEncode";
341 if (valIn
== 0 || berstring
== 0)
344 val
= cloneValue(valIn
, 1);
348 for (i
= 0; i
< val
->numVals
; i
++) {
349 BerElement
*ber
= ber_alloc();
350 struct berval
*bv
= 0;
354 logmsg(MSG_NOMEM
, LOG_ERR
, "%s: ber_alloc() => NULL",
360 if ((strcmp("b", berstring
) == 0 ||
361 strcmp("i", berstring
) == 0)) {
362 if (val
->val
[i
].length
>= sizeof (int)) {
363 ret
= ber_printf(ber
, berstring
,
364 *((int *)(val
->val
[i
].value
)));
368 } else if (strcmp("B", berstring
) == 0) {
369 ret
= ber_printf(ber
, berstring
,
371 val
->val
[i
].length
* 8);
372 } else if (strcmp("n", berstring
) == 0) {
373 ret
= ber_printf(ber
, berstring
);
374 } else if (strcmp("o", berstring
) == 0) {
375 ret
= ber_printf(ber
, berstring
,
376 val
->val
[i
].value
, val
->val
[i
].length
);
377 } else if (strcmp("s", berstring
) == 0) {
378 char *str
= am(myself
, val
->val
[i
].length
+ 1);
381 ret
= ber_printf(ber
, berstring
, str
);
391 reportError(NPL_BERENCODE
, "%s: BER encoding error",
398 if (ber_flatten(ber
, &bv
) != 0 || bv
== 0) {
399 reportError(NPL_BERENCODE
, "%s: ber_flatten() error",
406 sfree(val
->val
[i
].value
);
407 val
->val
[i
].length
= bv
->bv_len
;
408 val
->val
[i
].value
= bv
->bv_val
;
419 berDecode(__nis_value_t
*valIn
, char *berstring
) {
422 char *myself
= "berDecode";
424 if (valIn
== 0 || berstring
== 0)
427 val
= cloneValue(valIn
, 1);
431 for (i
= 0; i
< val
->numVals
; i
++) {
437 if (val
->val
[i
].value
== 0 || val
->val
[i
].length
<= 0)
440 bv
.bv_val
= val
->val
[i
].value
;
441 bv
.bv_len
= val
->val
[i
].length
;
444 reportError(NPL_BERDECODE
, "%s: ber_init() error",
450 if ((strcmp("b", berstring
) == 0 ||
451 strcmp("i", berstring
) == 0)) {
455 ret
= ber_scanf(ber
, berstring
, v
);
459 } else if (strcmp("B", berstring
) == 0) {
462 ret
= ber_scanf(ber
, berstring
, &v
, &llen
);
466 } else if (strcmp("n", berstring
) == 0) {
468 } else if (strcmp("o", berstring
) == 0) {
469 struct berval
*bv
= am(myself
, sizeof (*bv
));
472 ret
= ber_scanf(ber
, "O", &bv
);
473 if (ret
!= -1 && bv
!= 0) {
479 /* Only free 'bv' itself */
484 } else if (strcmp("s", berstring
) == 0) {
485 ret
= ber_scanf(ber
, "a", &v
);
494 reportError(NPL_BERDECODE
, "%s: BER decoding error",
500 /* Free the old value, and replace it with the decoded one */
501 sfree(val
->val
[i
].value
);
502 val
->val
[i
].value
= v
;
503 val
->val
[i
].length
= len
;
510 * Return the value of the specified item.
513 getMappingItemVal(__nis_mapping_item_t
*item
, __nis_mapping_item_type_t native
,
514 __nis_rule_value_t
*rv
, char *berstring
, int *np_ldap_stat
) {
515 __nis_value_t
*val
= 0, *nameVal
, *exVal
= 0;
516 int numName
, caseInsens
, cmp
;
519 enum {rvOnly
, rvThenLookup
, lookupOnly
} check
;
520 unsigned char fromldap
= '\0';
526 * First, we decide if we should look for the value in 'rv',
527 * directly from NIS+/LDAP, or both.
529 switch (item
->type
) {
531 /* Do we have a valid index/object spec ? */
532 if (item
->searchSpec
.obj
.index
.numIndexes
<= 0 &&
533 item
->searchSpec
.obj
.name
== 0) {
535 * No valid index/object. If we have a rule-value,
536 * use it. Otherwise, return error.
540 nameVal
= rv
->colVal
;
541 numName
= rv
->numColumns
;
549 * Valid index, so skip the rule-value and do
550 * a direct NIS+ lookup.
558 nameVal
= rv
->attrVal
;
559 numName
= rv
->numAttrs
;
563 /* Do we have a valid triple ? */
564 if (item
->searchSpec
.triple
.scope
== LDAP_SCOPE_UNKNOWN
) {
566 * No valid triple. If we have a rule-value, use it.
567 * Otherwise, return error.
574 } else if (item
->searchSpec
.triple
.base
== 0 &&
575 item
->searchSpec
.triple
.scope
==
576 LDAP_SCOPE_ONELEVEL
&&
577 item
->searchSpec
.triple
.attrs
== 0 &&
578 item
->searchSpec
.triple
.element
== 0) {
580 * We have a valid triple, but it points to the
581 * current LDAP container. Thus, first look in
582 * the rule-value; if that fails, perform a direct
586 check
= rvThenLookup
;
592 * Valid triple, and it's not the current container
593 * (at least not in the trivial sense). Hence, do
594 * a direct LDAP lookup.
603 /* Check the rule-value */
604 if (check
== rvOnly
|| check
== rvThenLookup
) {
605 for (i
= 0; i
< numName
; i
++) {
607 cmp
= strcasecmp(item
->name
, name
[i
]);
609 cmp
= strcmp(item
->name
, name
[i
]);
611 if (nameVal
[i
].numVals
<= 0)
613 if (berstring
== 0) {
614 val
= cloneValue(&nameVal
[i
], 1);
615 } else if (yp2ldap
&& berstring
[0] == 'a') {
616 val
= cloneValue(&nameVal
[i
], 1);
618 val
= berDecode(&nameVal
[i
],
622 val
->repeat
= item
->repeat
;
624 * If value for nis+ column is
625 * passed with value, val is
626 * manipulated in cloneValue().
627 * To decide whether there are
628 * enough nis+ column values
629 * for rule to produce a value,
630 * we need nis+ column values
631 * as well as nis_mapping_element
632 * from the rule. If we are here,
633 * it indicates that the 'val has
634 * an valid value for the column
635 * item-> name. So set
636 * NP_LDAP_MAP_SUCCESS
640 if (np_ldap_stat
!= NULL
)
649 /* Do a direct lookup ? */
650 if (val
== 0 && (check
== rvThenLookup
|| check
== lookupOnly
)) {
651 if (item
->type
== mit_ldap
) {
653 __nis_search_triple_t triple
;
657 * If item->searchSpec.triple.base is NULL, or ends
658 * in a comma, append the current search base from
659 * the TSD (put there by an upper layer).
661 * Special case for N2L mode:
662 * if item->searchSpec.triple.base ends in a comma,
663 * the current domain Context is used.
665 if (yp2ldap
&& item
->searchSpec
.triple
.base
&&
666 strlen(item
->searchSpec
.triple
.base
) > 0) {
667 baseDN
= __nisdb_get_tsd()->domainContext
;
669 baseDN
= __nisdb_get_tsd()->searchBase
;
671 triple
.base
= appendBase(item
->searchSpec
.triple
.base
,
674 triple
.scope
= item
->searchSpec
.triple
.scope
;
675 triple
.attrs
= item
->searchSpec
.triple
.attrs
;
677 item
->searchSpec
.triple
.element
;
678 val
= lookupLDAP(&triple
, item
->name
, rv
, 0,
689 /* Special processing for NIS to LDAP mode */
690 if (yp2ldap
&& val
!= 0) {
693 * Escape special chars from dn before sending to DIT,
694 * provided val is not ldap-based
696 if (fromldap
== '\0' && __nisdb_get_tsd()->escapeFlag
== '1') {
697 if (escapeSpecialChars(val
) < 0) {
701 } else if (__nisdb_get_tsd()->escapeFlag
== '2') {
702 /* Remove escape chars from data received from DIT */
703 (void) removeEscapeChars(val
);
707 * Remove from 'val', any values obtained using
708 * the 'removespec' syntax
713 exVal
= getMappingItemVal(item
->exItem
, native
, rv
,
718 for (i
= 0; i
< val
->numVals
; ) {
719 for (j
= 0; j
< exVal
->numVals
; j
++) {
720 if (sstrncmp(val
->val
[i
].value
,
722 MAX(val
->val
[i
].length
,
723 exVal
->val
[j
].length
))
727 if (j
< exVal
->numVals
) {
728 sfree(val
->val
[i
].value
);
729 val
->val
[i
].value
= 0;
730 val
->val
[i
].length
= 0;
731 for (k
= i
; k
< val
->numVals
- 1; k
++) {
732 val
->val
[k
] = val
->val
[k
+ 1];
733 val
->val
[k
+ 1].value
= 0;
734 val
->val
[k
+ 1].length
= 0;
744 * If val->numVals <= 0, then we have no val to
745 * return. So free up stuff.
747 if (val
->numVals
<= 0) {
760 getMappingFormat(__nis_mapping_format_t
*f
, __nis_rule_value_t
*rv
,
761 __nis_format_arg_t at
, void *a
, int *numArg
) {
762 char *myself
= "getMappingFormat";
763 __nis_value_t
*val
= 0;
764 __nis_buffer_t b
= {0, 0};
771 val
= am(myself
, sizeof (*val
));
777 bp2buf(myself
, &b
, "%%s");
780 bp2buf(myself
, &b
, "%s", NIL(f
->match
.string
));
783 bp2buf(myself
, &b
, "[");
784 for (i
= 0; i
< f
->match
.single
.numRange
; i
++) {
785 if (f
->match
.single
.lo
[i
] ==
786 f
->match
.single
.hi
[i
])
787 bp2buf(myself
, &b
, "%c",
788 f
->match
.single
.lo
[i
]);
790 bp2buf(myself
, &b
, "%c-%c",
791 f
->match
.single
.lo
[i
],
792 f
->match
.single
.hi
[i
]);
794 bp2buf(myself
, &b
, "]");
799 bp2buf(myself
, &b
, "*");
802 bp2buf(myself
, &b
, "%s", NIL(f
->match
.berString
));
806 bp2buf(myself
, &b
, "\"");
809 bp2buf(myself
, &b
, "<unknown>");
811 val
->type
= vt_string
;
813 val
->val
= am(myself
, sizeof (val
->val
[0]));
818 val
->val
[0].value
= b
.buf
;
819 val
->val
[0].length
= b
.len
;
826 val
= getMappingItemVal(
827 (__nis_mapping_item_t
*)a
,
829 (f
->type
== mmt_berstring
) ? f
->match
.berString
: 0, NULL
);
834 (__nis_value_t
*)a
, 1);
841 val
= am(myself
, sizeof (*val
));
844 val
->type
= vt_string
;
846 val
->val
= am(myself
, sizeof (val
->val
[0]));
851 val
->val
[0].value
= sdup(myself
, T
, f
->match
.string
);
852 val
->val
[0].length
= strlen(val
->val
[0].value
);
859 /* Not an error, so return an empty value */
860 val
= am(myself
, sizeof (*val
));
863 val
->type
= vt_string
;
877 * Used when evaluating an expression. Typically, the value of the
878 * expression so far will be kept in 'v1', and 'v2' is the value
879 * of the current component of the expression. In the general case,
880 * both will be multi-valued, and the result is an "explosion"
881 * resulting in N*M new values (if 'v1' had N values, and 'v2'
884 * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"},
885 * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl",
886 * "efgh", "efij", "efkl"}.
888 * There are special cases when v1->repeat and/or v2->repeat are set.
889 * Repeat mostly makes sense with single values; for example, if
890 * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result
891 * is {"x=1", "x=2", "x=3"}.
893 * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's
894 * not clear if there's a useful application for this, but the code's
895 * there for the sake of orthogonality.
898 explodeValues(__nis_value_t
*v1
, __nis_value_t
*v2
) {
901 __nis_buffer_t b
= {0, 0};
902 char *myself
= "explodeValues";
904 if (v1
== 0 || v1
->numVals
<= 0)
905 return (cloneValue(v2
, 1));
906 if (v2
== 0 || v2
->numVals
<= 0)
907 return (cloneValue(v1
, 1));
910 * XXX What should we do if (v1->type != v2->type) ?
911 * Policy: Just explode anyway, even though the result is
912 * unlikely to be very useful.
915 v
= am(myself
, sizeof (*v
));
919 if (!v1
->repeat
&& !v2
->repeat
)
920 nv
= v1
->numVals
* v2
->numVals
;
921 else if (v1
->repeat
&& !v2
->repeat
)
923 else if (!v1
->repeat
&& v2
->repeat
)
925 else /* v1->repeat && v2->repeat */
928 v
->val
= am(myself
, nv
* sizeof (v
->val
[0]));
935 * Four different cases, depending on the 'repeat' flags.
937 if (!v1
->repeat
&& !v2
->repeat
) {
938 for (i1
= 0, n
= 0; i1
< v1
->numVals
; i1
++) {
939 for (i2
= 0; i2
< v2
->numVals
; i2
++) {
940 if (v1
->type
== vt_string
)
941 sbc2buf(myself
, v1
->val
[i1
].value
,
945 bc2buf(myself
, v1
->val
[i1
].value
,
948 if (v2
->type
== vt_string
)
949 sbc2buf(myself
, v2
->val
[i2
].value
,
953 bc2buf(myself
, v2
->val
[i2
].value
,
956 v
->val
[n
].value
= b
.buf
;
957 v
->val
[n
].length
= b
.len
;
963 } else if (v1
->repeat
&& !v2
->repeat
) {
964 for (i2
= 0; i2
< v2
->numVals
; i2
++) {
965 for (i1
= 0, n
= 0; i1
< v1
->numVals
; i1
++) {
966 if (v1
->type
== vt_string
)
967 sbc2buf(myself
, v1
->val
[i1
].value
,
971 bc2buf(myself
, v1
->val
[i1
].value
,
974 if (v2
->type
== vt_string
)
975 sbc2buf(myself
, v2
->val
[i2
].value
,
979 bc2buf(myself
, v2
->val
[i2
].value
,
983 v
->val
[n
].value
= b
.buf
;
984 v
->val
[n
].length
= b
.len
;
989 } else if (!v1
->repeat
&& v2
->repeat
) {
990 for (i1
= 0, n
= 0; i1
< v1
->numVals
; i1
++) {
991 for (i2
= 0; i2
< v2
->numVals
; i2
++) {
992 if (v1
->type
== vt_string
)
993 sbc2buf(myself
, v1
->val
[i1
].value
,
997 bc2buf(myself
, v1
->val
[i1
].value
,
1000 if (v2
->type
== vt_string
)
1001 sbc2buf(myself
, v2
->val
[i2
].value
,
1005 bc2buf(myself
, v2
->val
[i2
].value
,
1009 v
->val
[n
].value
= b
.buf
;
1010 v
->val
[n
].length
= b
.len
;
1015 } else { /* v1->repeat && v2->repeat */
1016 for (i1
= 0, n
= 0; i1
< v1
->numVals
; i1
++) {
1017 for (i2
= 0; i2
< v2
->numVals
; i2
++) {
1018 if (v1
->type
== vt_string
)
1019 sbc2buf(myself
, v1
->val
[i1
].value
,
1023 bc2buf(myself
, v1
->val
[i1
].value
,
1026 if (v2
->type
== vt_string
)
1027 sbc2buf(myself
, v2
->val
[i2
].value
,
1031 bc2buf(myself
, v2
->val
[i2
].value
,
1036 v
->val
[n
].value
= b
.buf
;
1037 v
->val
[n
].length
= b
.len
;
1043 #ifdef NISDB_LDAP_DEBUG
1047 #endif /* NISD__LDAP_DEBUG */
1049 v
->type
= (v1
->type
== vt_string
) ?
1050 ((v2
->type
== vt_string
) ?
1051 vt_string
: vt_ber
) : vt_ber
;
1059 getMappingFormatArray(__nis_mapping_format_t
*a
, __nis_rule_value_t
*rv
,
1060 __nis_format_arg_t at
, int numArgs
, void *arg
) {
1062 __nis_value_t
*val
, *v
= 0;
1063 bool_t moreFormat
= (a
!= 0);
1064 bool_t moreArgs
= (numArgs
> 0);
1066 while (moreFormat
&& (arg
== 0 || ia
< numArgs
)) {
1067 for (i
= 0; moreFormat
; i
++) {
1068 moreFormat
= (a
[i
].type
!= mmt_end
);
1069 if (at
== fa_item
) {
1070 __nis_mapping_item_t
*item
= arg
;
1071 val
= getMappingFormat(&a
[i
], rv
, at
,
1072 ((item
!= 0) ? &item
[ia
] : 0), &ia
);
1074 __nis_value_t
**ival
= arg
;
1075 val
= getMappingFormat(&a
[i
], rv
, at
,
1076 ((ival
!= 0) ? ival
[ia
] : 0), &ia
);
1079 __nis_value_t
*new = explodeValues(v
, val
);
1092 * If we run out of arguments, but still have format
1093 * remaining, repeat the last argument. Keep track of
1094 * the fact that we've really consumed all arguments.
1096 if (moreFormat
&& ia
>= numArgs
) {
1097 ia
= (numArgs
> 0) ? numArgs
- 1 : 0;
1102 * We've run out of format, so if we still have arguments
1103 * left, start over on the format.
1105 if (ia
< numArgs
&& moreArgs
) {
1107 * However, if we didn't consume any arguments going
1108 * through the format once, abort to avoid an infinite
1111 if (numArgs
> 0 && ia
<= 0) {
1123 * Returns a string representation (such as "[name=foo, value=bar]")
1127 getIndex(__nis_index_t
*i
, int *len
) {
1129 __nis_buffer_t b
= {0, 0};
1130 char *myself
= "getIndex";
1135 if (i
->numIndexes
> 0) {
1136 bp2buf(myself
, &b
, "[");
1137 for (n
= 0; n
< i
->numIndexes
; n
++) {
1141 val
= getMappingFormatArray(i
->value
[n
],
1144 bp2buf(myself
, &b
, ", ");
1145 bp2buf(myself
, &b
, "%s=", i
->name
[n
]);
1147 for (j
= 0; j
< val
->numVals
; j
++) {
1148 bc2buf(myself
, val
->val
[j
].value
,
1149 val
->val
[j
].length
, &b
);
1152 bp2buf(myself
, &b
, "<no-vals>");
1156 bp2buf(myself
, &b
, "]");
1164 getObjSpec(__nis_obj_spec_t
*o
, int *len
) {
1165 __nis_buffer_t b
= {0, 0};
1166 char *myself
= "getObjSpec";
1171 b
.buf
= getIndex(&o
->index
, &b
.len
);
1172 sbc2buf(myself
, o
->name
, slen(o
->name
), &b
);
1179 * Returns a string representation of the LDAP scope. Note that the
1180 * returned value is a static entity, and must be copied by the
1181 * caller (but, obviously, must not be freed).
1184 getScope(int scope
) {
1186 case LDAP_SCOPE_BASE
:
1188 case LDAP_SCOPE_ONELEVEL
:
1190 case LDAP_SCOPE_SUBTREE
:
1198 * Return a string representation of an LDAP search triple (such as
1199 * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1202 getSearchTriple(__nis_search_triple_t
*s
, int *len
) {
1203 __nis_buffer_t b
= {0, 0};
1206 char *myself
= "getSearchTriple";
1208 /* If the scope is LDAP_SCOPE_UNKNOWN, the search triple is unused */
1209 if (s
== 0 || s
->scope
== LDAP_SCOPE_UNKNOWN
) {
1216 sbc2buf(myself
, s
->base
, slen(s
->base
), &b
);
1217 if (!(s
->scope
== LDAP_SCOPE_ONELEVEL
&&
1218 (s
->base
== 0 || s
->base
[0] == '\0'))) {
1219 bp2buf(myself
, &b
, "?%s?", getScope(s
->scope
));
1221 if ((l
= slen(s
->attrs
)) > 0) {
1223 * Remove white space from the filter/attribute list.
1224 * The parser usually keeps any white space from the
1225 * config file (or LDAP/command line), but we don't
1228 a
= am(myself
, l
+1);
1232 for (i
= 0, la
= 0; i
< l
; i
++) {
1233 if (s
->attrs
[i
] != ' ' &&
1234 s
->attrs
[i
] != '\t')
1235 a
[la
++] = s
->attrs
[i
];
1237 sbc2buf(myself
, a
, la
, &b
);
1240 sbc2buf(myself
, s
->attrs
, slen(s
->attrs
), &b
);
1250 getMappingItem(__nis_mapping_item_t
*i
, __nis_mapping_item_type_t native
,
1251 __nis_rule_value_t
*rv
, char *berstring
, int *np_ldap_stat
) {
1252 char *myself
= "getMappingItem";
1253 __nis_value_t
*val
= 0;
1254 __nis_buffer_t b
= {0, 0};
1262 return (getMappingItemVal(i
, native
, rv
, berstring
,
1265 val
= am(myself
, sizeof (*val
));
1271 if (native
!= mit_nisplus
)
1272 bp2buf(myself
, &b
, "nis+:");
1273 bp2buf(myself
, &b
, "%s", NIL(i
->name
));
1274 buf
= getObjSpec(&i
->searchSpec
.obj
, &len
);
1275 if (buf
!= 0 && len
> 0) {
1276 bc2buf(myself
, ":", 1, &b
);
1277 sbc2buf(myself
, buf
, len
, &b
);
1280 val
->type
= vt_string
;
1281 val
->repeat
= i
->repeat
;
1283 val
->val
= am(myself
, sizeof (val
->val
[0]));
1284 if (val
->val
== 0) {
1289 val
->val
[0].value
= b
.buf
;
1290 val
->val
[0].length
= b
.len
;
1293 if (native
!= mit_ldap
)
1294 bp2buf(myself
, &b
, "ldap:");
1295 bp2buf(myself
, &b
, "%s", NIL(i
->name
));
1296 buf
= getSearchTriple(&i
->searchSpec
.triple
, &len
);
1297 if (buf
!= 0 && len
> 0) {
1298 bc2buf(myself
, ":", 1, &b
);
1299 sbc2buf(myself
, buf
, len
, &b
);
1302 val
->type
= vt_string
;
1303 val
->repeat
= i
->repeat
;
1305 val
->val
= am(myself
, sizeof (val
->val
[0]));
1306 if (val
->val
== 0) {
1311 val
->val
[0].value
= b
.buf
;
1312 val
->val
[0].length
= b
.len
;
1315 p2buf(myself
, "<unknown>:");
1316 p2buf(myself
, "%s", NIL(i
->name
));
1324 copyObjSpec(__nis_obj_spec_t
*old
, __nis_obj_spec_t
*new, int *err
) {
1325 char *myself
= "copyObjSpec";
1327 if (old
== 0 || new == 0) {
1332 if (new->index
.name
== 0) {
1333 new->index
.name
= am(myself
, old
->index
.numIndexes
*
1334 sizeof (new->index
.name
[0]));
1335 if (old
->index
.numIndexes
> 0 && new->index
.name
== 0) {
1339 new->index
.value
= am(myself
, old
->index
.numIndexes
*
1340 sizeof (new->index
.value
[0]));
1341 if (old
->index
.numIndexes
> 0 && new->index
.value
== 0) {
1346 new->name
= sdup(myself
, T
, old
->name
);
1347 if (new->name
== 0 && old
->name
!= 0) {
1351 copyIndex(&old
->index
, &new->index
, err
);
1355 cloneObjSpec(__nis_obj_spec_t
*old
) {
1356 char *myself
= "cloneObjSpec";
1358 __nis_obj_spec_t
*new = am(myself
, sizeof (*new));
1361 copyObjSpec(old
, new, &err
);
1363 freeObjSpec(new, 1);
1372 freeObjSpec(__nis_obj_spec_t
*old
, bool_t doFree
) {
1378 freeIndex(&old
->index
, FALSE
);
1384 copySearchTriple(__nis_search_triple_t
*old
, __nis_search_triple_t
*new,
1386 char *myself
= "copySearchTriple";
1390 if (old
== 0 || new == 0) {
1395 if (old
->base
!= NULL
)
1396 new->base
= sdup(myself
, T
, old
->base
);
1399 if (old
->attrs
!= NULL
)
1400 new->attrs
= sdup(myself
, T
, old
->attrs
);
1403 if ((new->base
== 0 && old
->base
!= 0) ||
1404 (new->attrs
== 0 && old
->attrs
!= 0)) {
1412 new->scope
= old
->scope
;
1414 * XXX Really should have a cloneMappingElement() function.
1415 * However, since whatever the 'element' field points to
1416 * is allocated at parse time, and never is freed or modified,
1417 * it's sufficient to copy the pointer value.
1419 new->element
= old
->element
;
1422 __nis_search_triple_t
*
1423 cloneSearchTriple(__nis_search_triple_t
*old
) {
1424 char *myself
= "cloneSearchTriple";
1426 __nis_search_triple_t
*new = am(myself
, sizeof (*new));
1429 copySearchTriple(old
, new, &err
);
1431 freeSearchTriple(new, 1);
1440 freeSearchTriple(__nis_search_triple_t
*old
, bool_t doFree
) {
1448 * Since we only copied the element pointer when this structure
1449 * was created, we don't free old->element.
1456 copyTripleOrObj(__nis_mapping_item_type_t type
,
1457 __nis_triple_or_obj_t
*old
, __nis_triple_or_obj_t
*new,
1462 if (old
== 0 || new == 0) {
1467 if (type
== mit_nisplus
) {
1468 copyObjSpec(&old
->obj
, &new->obj
, err
);
1469 } else if (type
== mit_ldap
) {
1470 copySearchTriple(&old
->triple
, &new->triple
, err
);
1474 __nis_triple_or_obj_t
*
1475 cloneTripleOrObj(__nis_mapping_item_type_t type
, __nis_triple_or_obj_t
*old
) {
1476 char *myself
= "cloneTripleOrObj";
1478 __nis_triple_or_obj_t
*new = am(myself
, sizeof (*new));
1481 copyTripleOrObj(type
, old
, new, &err
);
1483 freeTripleOrObj(type
, new, 1);
1492 freeTripleOrObj(__nis_mapping_item_type_t type
, __nis_triple_or_obj_t
*old
,
1498 if (type
== mit_nisplus
)
1499 freeObjSpec(&old
->obj
, doFree
);
1500 else if (type
== mit_ldap
)
1501 freeSearchTriple(&old
->triple
, doFree
);
1508 copyItem(__nis_mapping_item_t
*old
, __nis_mapping_item_t
*new, int *err
) {
1512 if (old
== 0 || new == 0) {
1517 new->type
= old
->type
;
1518 new->repeat
= old
->repeat
;
1519 if (old
->name
!= 0) {
1520 new->name
= strdup(old
->name
);
1521 if (new->name
== 0) {
1528 if (old
->type
== mit_nisplus
|| old
->type
== mit_ldap
)
1529 copyTripleOrObj(old
->type
, &old
->searchSpec
, &new->searchSpec
,
1532 memset(&new->searchSpec
, 0, sizeof (new->searchSpec
));
1535 __nis_mapping_item_t
*
1536 cloneItem(__nis_mapping_item_t
*old
) {
1537 __nis_mapping_item_t
*new;
1539 char *myself
= "cloneItem";
1544 new = am(myself
, sizeof (*new));
1548 copyItem(old
, new, &err
);
1550 freeMappingItem(new, 1);
1558 freeMappingItem(__nis_mapping_item_t
*item
, int numItems
) {
1564 for (i
= 0; i
< numItems
; i
++) {
1565 sfree(item
[i
].name
);
1566 freeTripleOrObj(item
[i
].type
, &item
[i
].searchSpec
, FALSE
);
1571 __nis_mapping_item_t
*
1572 concatenateMappingItem(__nis_mapping_item_t
*old
, int numItems
,
1573 __nis_mapping_item_t
*cat
) {
1574 __nis_mapping_item_t
*new;
1576 char *myself
= "concatenateMappingItem";
1578 if (old
== 0 || numItems
< 1)
1579 return (cloneItem(cat
));
1581 new = am(myself
, (numItems
+ 1) * sizeof (*new));
1585 for (i
= 0; i
< numItems
; i
++) {
1586 copyItem(&old
[i
], &new[i
], &err
);
1588 freeMappingItem(new, i
);
1592 copyItem(cat
, &new[numItems
], &err
);
1594 freeMappingItem(new, numItems
);
1602 concatenateValues(__nis_value_t
*v1
, __nis_value_t
*v2
) {
1605 char *myself
= "concatenateValues";
1607 if (v1
== 0 || v1
->numVals
<= 0)
1608 return (cloneValue(v2
, 1));
1609 if (v2
== 0 || v2
->numVals
<= 0)
1610 return (cloneValue(v1
, 1));
1612 if (v1
->type
!= v2
->type
)
1615 n
= v1
->numVals
+ v2
->numVals
;
1616 v
= am(myself
, sizeof (*v
));
1619 v
->val
= am(myself
, n
* sizeof (v
->val
[0]));
1627 for (a
= 0; a
< 2; a
++) {
1628 __nis_single_value_t
*val
= (a
== 0) ? v1
->val
: v2
->val
;
1629 int numv
= (a
== 0) ? v1
->numVals
:
1631 for (i
= 0; i
< numv
; i
++) {
1632 int clen
, alen
= val
[i
].length
;
1637 * Make sure there's a NUL at the end of a string,
1638 * but avoid adding to the allocated length if there's
1639 * already a NUL at the end.
1641 if (alen
> 0 && v
->type
== vt_string
&&
1642 ((char *)val
[i
].value
)[alen
-1] != '\0')
1644 v
->val
[v
->numVals
].value
= am(myself
, alen
);
1645 if (v
->val
[v
->numVals
].value
== 0) {
1649 memcpy(v
->val
[v
->numVals
].value
, val
[i
].value
, clen
);
1650 v
->val
[v
->numVals
].length
= val
[i
].length
;
1659 splitMappingItem(__nis_mapping_item_t
*item
, char delim
,
1660 __nis_rule_value_t
*rv
) {
1661 __nis_value_t
*val
= getMappingItem(item
, mit_any
,
1663 __nis_single_value_t
*nval
;
1668 else if (delim
== 0 || val
->val
== 0 || val
->numVals
<= 0 ||
1669 val
->type
!= vt_string
) {
1676 val
->repeat
= FALSE
;
1680 /* In N2L, space and tab delimiters are treated the same */
1681 if (yp2ldap
&& delim
== '\t')
1684 /* If the item has multiple values, we split each one independently */
1685 for (i
= 0; i
< nv
; i
++) {
1689 __nis_single_value_t
*newval
;
1691 if (yp2ldap
&& delim
== ' ')
1692 nval
[i
].value
= trimWhiteSpaces(nval
[i
].value
,
1693 &nval
[i
].length
, 1);
1695 str
= nval
[i
].value
;
1697 if (nval
[i
].value
== 0)
1700 for (s
= 0; s
< nval
[i
].length
; s
= e
+1) {
1701 /* Find the next delimiter, or end-of-string */
1702 for (e
= s
; str
[e
] != '\0' && str
[e
] != delim
; e
++);
1704 * 'str[e]' is either a delimiter, or the concluding
1705 * NUL. Make sure it's NUL.
1708 /* Add to val->val */
1709 newstr
= strdup(&str
[s
]);
1710 newval
= realloc(val
->val
,
1712 sizeof (val
->val
[0]));
1715 if (newstr
== 0 || newval
== 0) {
1717 for (n
= i
; n
< nv
; n
++) {
1718 sfree(nval
[n
].value
);
1724 val
->val
[val
->numVals
].value
= newstr
;
1725 val
->val
[val
->numVals
].length
= strlen(newstr
) + 1;
1728 free(nval
[i
].value
);
1731 /* Already freed the nval[i].value's as we traversed nval */
1738 * Match the format spec 'f[curf]' to the input value string 'str'.
1740 * If successful, returns the updated position in the value string 'str'.
1741 * Otherwise, NULL is returned.
1743 * curf Current index (i.e., the one we should look at) in 'f'
1744 * nf Number of elements in 'f', including 'mmt_end'
1745 * str The value string we're scanning
1746 * val Pointer to where an item value (if any) should be returned
1747 * Set to NULL if not an 'mmt_item'.
1748 * fmtstart If non-zero on entry, skip characters in 'str' until we find
1749 * the f[curf].type data, if doing so makes any sense. On exit,
1750 * set to the start of the fmt element data (which will be 'str',
1751 * unless we did skip characters)
1752 * sepset List of separators
1755 scanMappingFormat(__nis_mapping_format_t
*f
, int curf
, int nf
, char *str
,
1756 char **val
, char **fmtstart
, char *sepset
) {
1757 char *mstr
, *next
, *start
= 0, *tmpstr
;
1760 char *myself
= "scanMappingFormat";
1762 int af
, skipspaces
= 0;
1763 bool_t ipaddr
= FALSE
;
1764 char *spacestr
= " ", *emptystr
= "";
1767 if (f
== 0 || curf
< 0 || nf
<= 0 || str
== 0)
1771 * If separator list is NULL (which will be the case for
1772 * nis+2ldap), then simply use empty string
1778 /* OK if the string also is exhausted */
1779 if (strchr(sepset
, *str
) != 0)
1785 switch (f
[curf
].type
) {
1787 if (f
[curf
].match
.berString
[0] != 'a') {
1788 /* Not a matchable element */
1793 * If here, it means it's an IP address (N2L case)
1794 * So continue processing as if it was mmt_item
1800 * In order to find the end of the item value, we must look
1801 * ahead and determine the start of the next formatting element.
1802 * If successful, 'next' will be the start of the fmt element
1803 * after the next one; we don't care about that, other than to
1806 * Since an item match is somewhat like an any match, in that
1807 * we don't know a priori if the first occurence of the next
1808 * element really is the one we want, we have to scan ahead
1809 * until we've reached the end.
1812 while ((next
= scanMappingFormat(f
, curf
+1, nf
, tmpstr
, 0,
1813 &start
, sepset
)) != 0) {
1817 for (cf
= curf
+2; cf
< nf
; cf
++) {
1818 tmp
= scanMappingFormat(f
, cf
, nf
, tmp
, 0,
1825 } else if (strchr(sepset
, *tmp
) != 0) {
1832 if (next
== 0 || start
== 0)
1836 len
= (int)((long)start
- (long)str
);
1837 *val
= am(myself
, len
+ 1);
1840 memcpy(*val
, str
, len
);
1843 if (ipaddr
== TRUE
) {
1845 * In N2L, we need to check if *val is truly an
1848 af
= checkIPaddress(*val
, len
, &tmpstr
);
1851 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1852 "%s:Internal error while "
1853 "processing IPaddress %s",
1857 } else if (af
== -1) {
1858 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1859 "%s:%s is not an IP address",
1863 } else if (af
== 0) {
1864 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1865 "%s:IP address %s is not "
1866 "supported by rfc2307bis",
1870 } else if (sstrncmp(*val
, tmpstr
, len
) != 0) {
1871 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1872 "%s:IPaddress %s converted "
1873 "to %s", myself
, *val
, tmpstr
);
1887 if ((mstr
= f
[curf
].match
.string
) == 0 || *mstr
== '\0') {
1889 * Count this as a successful match of an empty
1898 * In N2L, if the format string 'mstr' contains only
1899 * whitespaces (spaces and tabs), then it should
1900 * match one or more whitespaces from the input
1903 if (yp2ldap
&& strspn(mstr
, " \t") == strlen(mstr
)) {
1906 next
= str
+ strcspn(str
, " \t");
1908 * Even if there is no whitespace in 'str',
1909 * it's OK. This is to allow formats like
1910 * "%s %s %s" to match inputs like "foo bar".
1915 /* No match string in 'str' => failure */
1916 if ((next
= strstr(str
, mstr
)) == 0)
1920 /* If 'fmtstart' == 0, we require 'next' == 'str' */
1921 if (fmtstart
== 0 && next
!= str
)
1923 /* Success; save start of match string if requested */
1926 /* Update position in the value string */
1927 str
= (char *)((long)next
+ (long)strlen(mstr
));
1929 /* Skip whitespaces for N2L */
1930 if (skipspaces
== 1)
1931 for (; *str
== ' ' || *str
== '\t'; str
++);
1936 if (fmtstart
!= 0) {
1938 /* Skip ahead until we match */
1939 for (next
= str
; *next
!= '\0'; next
++) {
1940 unsigned char *lo
= f
[curf
].match
.single
.lo
;
1941 unsigned char *hi
= f
[curf
].match
.single
.hi
;
1943 for (i
= 0; i
< f
[curf
].match
.single
.numRange
;
1945 if (*next
>= lo
[i
] && *next
<= hi
[i
]) {
1959 for (i
= 0; i
< f
[curf
].match
.single
.numRange
; i
++) {
1960 if (*str
>= f
[curf
].match
.single
.lo
[i
] &&
1961 *str
<= f
[curf
].match
.single
.hi
[i
]) {
1969 /* Step over the matched character */
1975 * Look ahead to find the beginning of the next element.
1976 * Because a wildcard-match isn't necessarily uniquely
1977 * determined until we've reached the end, we then continue
1980 while ((next
= scanMappingFormat(f
, curf
+1, nf
, str
, 0,
1981 &start
, sepset
)) != 0) {
1985 for (cf
= curf
+2; cf
< nf
; cf
++) {
1986 tmp
= scanMappingFormat(f
, cf
, nf
, tmp
, 0,
1993 } else if (*tmp
== '\0') {
1999 if (next
== 0 || start
== 0)
2008 if (f
[curf
].match
.limit
== eos
) {
2009 if (fmtstart
!= 0) {
2010 /* Skip to the end */
2011 str
= str
+ strcspn(str
, sepset
);
2013 } else if (strchr(sepset
, *str
) == 0) {
2025 if (fmtstart
!= 0) {
2026 /* Skip to the end */
2027 str
= str
+ strcspn(str
, sepset
);
2031 /* No skipping, so we must be at the end of the value */
2032 if (strchr(sepset
, *str
) == 0)
2044 * Verify that the string 'str' matches the mapping format array 'f'.
2045 * Returns 1 in case of a match, 0 otherwise.
2048 verifyMappingMatch(__nis_mapping_format_t
*f
, char *str
) {
2050 __nis_mapping_format_t
*ftmp
;
2052 /* Count the number of format elements in the format */
2053 for (nf
= 0, ftmp
= f
; ftmp
->type
!= mmt_end
; ftmp
++) {
2056 /* Count the mmt_end as well */
2059 for (n
= 0; n
< nf
; n
++) {
2060 str
= scanMappingFormat(f
, n
, nf
, str
, 0, 0, 0);
2065 return ((str
!= 0) ? 1 : 0);
2069 * Perform a match operation. For example, given the rule
2070 * ("{%s}%s", auth_name, public_data)=nisPublicKey
2071 * and assuming that 'nisPublicKey' has the value "{dh640-0}abcdef12345",
2072 * assign "dh640-0" to 'auth_name' and "abcdef12345" to 'public_data'.
2074 * Note that this function doesn't perform the actual assignment. Rather,
2075 * it returns an array of __nis_value_t's, with element zero of the value
2076 * array being the new value of the first matched item, element one the
2077 * value of the second matched item, etc. In the example above, we'd
2078 * return a value array with two elements.
2080 * If there is more than one input value (inVal->numVals > 1), the
2081 * output array elements will also be multi-valued.
2083 * f The match format
2084 * inVal Input value(s)
2085 * numVal Number of elements in the output value array
2086 * sepset List of separators
2087 * outstr Points to the updated position upto which the
2088 * input string has been matched
2091 matchMappingItem(__nis_mapping_format_t
*f
, __nis_value_t
*inVal
,
2092 int *numVals
, char *sepset
, char **outstr
) {
2093 __nis_value_t
**v
= 0;
2094 int i
, n
, ni
, numItems
, nf
;
2096 __nis_mapping_format_t
*ftmp
;
2097 char *myself
= "matchMappingItem";
2100 inVal
== 0 || inVal
->numVals
< 1 || inVal
->type
!= vt_string
)
2103 /* Count the number of format elements and items in the format */
2104 for (nf
= numItems
= 0, ftmp
= f
; ftmp
->type
!= mmt_end
; ftmp
++) {
2108 * Count mmt_item and mmt_berstring (used by N2L to
2109 * represent address %a)
2111 if (ftmp
->type
== mmt_item
)
2113 else if (ftmp
->type
== mmt_berstring
&& ftmp
->match
.berString
&&
2114 ftmp
->match
.berString
[0] == 'a')
2117 /* Count the mmt_end as well */
2121 * If no items, there will be no values. This isn't exactly an error
2122 * from the limited point of view of this function, so we return a
2123 * __nis_value_t with zero values.
2125 if (numItems
<= 0) {
2126 v
= am(myself
, sizeof (v
[0]));
2129 v
[0] = am(myself
, sizeof (*v
[0]));
2134 v
[0]->type
= vt_string
;
2142 /* Allocate and initialize the return array */
2143 v
= am(myself
, numItems
* sizeof (v
[0]));
2146 for (n
= 0; n
< numItems
; n
++) {
2147 v
[n
] = am(myself
, sizeof (*v
[n
]));
2151 for (j
= 0; j
< n
; j
++)
2156 v
[n
]->type
= vt_string
;
2158 v
[n
]->val
= am(myself
, inVal
->numVals
* sizeof (v
[n
]->val
[0]));
2159 if (v
[n
]->val
== 0) {
2162 for (j
= 0; j
< n
; j
++)
2167 for (i
= 0; i
< inVal
->numVals
; i
++) {
2168 v
[n
]->val
[i
].length
= 0;
2169 v
[n
]->val
[i
].value
= 0;
2173 /* For each input value, perform the match operation */
2174 for (i
= 0; i
< inVal
->numVals
; i
++) {
2175 str
= inVal
->val
[i
].value
;
2178 for (n
= 0, ni
= 0; n
< nf
; n
++) {
2180 str
= scanMappingFormat(f
, n
, nf
, str
, &valstr
,
2184 if (valstr
!= 0 && ni
< numItems
&&
2185 v
[ni
]->numVals
< inVal
->numVals
) {
2186 v
[ni
]->val
[v
[ni
]->numVals
].value
= valstr
;
2187 v
[ni
]->val
[v
[ni
]->numVals
].length
=
2191 } else if (valstr
!= 0) {
2196 for (n
= 0; n
< numItems
; n
++)
2204 *numVals
= numItems
;
2207 * Update the return string upto the point it has been matched
2208 * This string will be used by the N2L code in its next call
2218 * Perform an extract operation. For example, given the expression
2220 * and assuming 'name' is an item with the value "some.thing", the
2221 * value returned by the extract is "some".
2224 extractMappingItem(__nis_mapping_item_t
*item
, __nis_mapping_format_t
*f
,
2225 __nis_rule_value_t
*rv
, int *stat
) {
2226 __nis_value_t
*val
= getMappingItem(item
, mit_any
,
2228 __nis_single_value_t
*nval
;
2230 __nis_mapping_format_t
*ftmp
;
2234 else if (f
== 0 || rv
== 0 || val
->val
== 0 ||
2235 val
->numVals
<= 0 || val
->type
!= vt_string
) {
2240 /* Sanity check the format; it must have one and only one mmt_item */
2244 for (nf
= numitem
= 0, ftmp
= f
; ftmp
->type
!= mmt_end
;
2247 if (ftmp
->type
== mmt_item
)
2250 /* Count the mmt_end as well */
2260 val
->repeat
= FALSE
;
2264 /* If the item has multiple values, we extract each one independently */
2265 for (i
= 0; i
< nv
; i
++) {
2266 char *str
= nval
[i
].value
;
2268 __nis_single_value_t
*newval
;
2270 if (nval
[i
].value
== 0)
2274 * We match the whole string, even if we find a value for
2275 * the item before exhausting all format elements. By doing
2276 * this, we ensure that the string really matches the complete
2277 * format specification.
2279 for (n
= 0; n
< nf
; n
++) {
2280 str
= scanMappingFormat(f
, n
, nf
, str
, &newstr
, 0, 0);
2286 * *str should now be NUL, meaning we've reached the end of
2287 * the string (value), and it completely matched the format.
2288 * If 'str' is NULL, there was an error, and if 'newstr' is
2289 * 0, we somehow failed to obtain a value.
2291 if (str
== 0 || *str
!= '\0' || newstr
== 0 ||
2292 (newval
= realloc(val
->val
,
2294 sizeof (val
->val
[0]))) == 0) {
2296 for (n
= 0; n
< nv
; n
++) {
2297 sfree(nval
[n
].value
);
2305 val
->val
[val
->numVals
].value
= newstr
;
2306 val
->val
[val
->numVals
].length
= strlen(newstr
) + 1;
2309 free(nval
[i
].value
);
2318 * For each value in 'val', remove the last character, provided that
2319 * it matches 'elide'.
2322 stringElide(__nis_value_t
*val
, char elide
) {
2324 if (val
!= 0 && val
->type
== vt_string
) {
2327 for (i
= 0; i
< val
->numVals
; i
++) {
2328 int end
= val
->val
[i
].length
;
2329 char *str
= val
->val
[i
].value
;
2331 if (str
== 0 || end
<= 0)
2335 * If the NUL was counted in the length, step back
2338 if (str
[end
-1] == '\0')
2340 if (end
> 0 && str
[end
-1] == elide
) {
2342 val
->val
[i
].length
--;
2349 * Obtain the value for the mapping sub-element 'e', given the input
2353 getMappingSubElement(__nis_mapping_sub_element_t
*e
,
2354 __nis_rule_value_t
*rv
, int *np_ldap_stat
) {
2362 val
= getMappingItem(&e
->element
.item
, mit_any
, rv
, 0,
2366 val
= getMappingFormatArray(e
->element
.print
.fmt
, rv
,
2368 e
->element
.print
.numItems
,
2369 e
->element
.print
.item
);
2370 if (e
->element
.print
.doElide
)
2371 stringElide(val
, e
->element
.print
.elide
);
2374 val
= splitMappingItem(&e
->element
.split
.item
,
2375 e
->element
.split
.delim
,
2379 val
= extractMappingItem(&e
->element
.extract
.item
,
2380 e
->element
.extract
.fmt
,
2393 * Obtain the value of the mapping element 'e', given the input rule-
2394 * value 'rv'. The 'native' mapping type is used when 'rv' is NULL,
2395 * and the result is a string representation of the mapping element;
2396 * in that case, items of the 'native' type are printed without their
2397 * type designation ("nis+" or "ldap").
2400 getMappingElement(__nis_mapping_element_t
*e
, __nis_mapping_item_type_t native
,
2401 __nis_rule_value_t
*rv
, int *stat
) {
2402 __nis_value_t
*val
, **tv
;
2403 int i
, success
= 0, novalue
= 0;
2405 char *myself
= "getMappingElement";
2409 val
= getMappingItem(&e
->element
.item
, native
, rv
, 0, NULL
);
2412 tv
= am(myself
, e
->element
.print
.numSubElements
*
2414 np_ldap_stat
= am(myself
,
2415 e
->element
.print
.numSubElements
* sizeof (int));
2416 if ((e
->element
.print
.numSubElements
> 0) &&
2417 (tv
== 0 || np_ldap_stat
== 0)) {
2420 sfree(np_ldap_stat
);
2423 for (i
= 0; i
< e
->element
.print
.numSubElements
; i
++) {
2424 np_ldap_stat
[i
] = 0;
2425 tv
[i
] = getMappingSubElement(
2426 &e
->element
.print
.subElement
[i
],
2427 rv
, &np_ldap_stat
[i
]);
2430 * if we get NP_LDAP_NO_VALUE to any of the subelement
2431 * and we get NP_LDAP_MAP_SUCCESS to all other subelement
2432 * then we had enough nis+ column values which can
2433 * produce value for this rule, but didn't. So return
2434 * NP_LDAP_RULES_NO_VALUE to indicate to proceed to
2437 for (i
= 0; i
< e
->element
.print
.numSubElements
; i
++) {
2438 if (np_ldap_stat
[i
] == NP_LDAP_MAP_SUCCESS
)
2440 if (np_ldap_stat
[i
] == NP_LDAP_NO_VALUE
)
2443 if (stat
!= NULL
&& novalue
> 0 &&
2444 ((novalue
+success
) ==
2445 e
->element
.print
.numSubElements
))
2446 *stat
= NP_LDAP_RULES_NO_VALUE
;
2447 val
= getMappingFormatArray(e
->element
.print
.fmt
, rv
,
2449 e
->element
.print
.numSubElements
,
2451 for (i
= 0; i
< e
->element
.print
.numSubElements
; i
++) {
2452 freeValue(tv
[i
], 1);
2455 sfree(np_ldap_stat
);
2456 if (e
->element
.print
.doElide
)
2457 stringElide(val
, e
->element
.print
.elide
);
2460 val
= splitMappingItem(&e
->element
.split
.item
,
2461 e
->element
.split
.delim
,
2466 * A match doesn't produce an assignable value per se,
2467 * so we shouldn't get one here.
2472 val
= extractMappingItem(&e
->element
.extract
.item
,
2473 e
->element
.extract
.fmt
,