Merge branch 'cleanups'
[unleashed.git] / usr / src / lib / libnisdb / ldap_val.c
blobec6b5e8106f30dbb5bddb5a5f5631e9486da9478
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2015 Gary Mills
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <lber.h>
29 #include <ldap.h>
30 #include <strings.h>
31 #include <errno.h>
33 #include "nisdb_mt.h"
35 #include "ldap_util.h"
36 #include "ldap_op.h"
37 #include "ldap_ruleval.h"
38 #include "ldap_attr.h"
39 #include "ldap_val.h"
40 #include "ldap_ldap.h"
42 extern int yp2ldap;
45 __nis_mapping_format_t *
46 cloneMappingFormat(__nis_mapping_format_t *m) {
47 __nis_mapping_format_t *new;
48 int i, nf, err;
49 char *myself = "cloneMappingFormat";
51 if (m == 0)
52 return (0);
54 for (nf = 0; m[nf].type != mmt_end; nf++);
55 nf++;
57 new = am(myself, nf * sizeof (new[0]));
58 if (new == 0)
59 return (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++) {
66 switch (m[i].type) {
67 case mmt_string:
68 new[i].match.string = sdup(myself, T,
69 m[i].match.string);
70 if (new[i].match.string == 0 && m[i].match.string != 0)
71 err++;
72 break;
73 case mmt_single:
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,
82 m[i].match.single.lo,
83 m[i].match.single.numRange);
84 else if (m[i].match.single.lo != 0)
85 err++;
86 if (new[i].match.single.hi != 0)
87 memcpy(new[i].match.single.hi,
88 m[i].match.single.hi,
89 m[i].match.single.numRange);
90 else if (m[i].match.single.hi != 0)
91 err++;
92 break;
93 case mmt_berstring:
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)
98 err++;
99 break;
100 case mmt_item:
101 case mmt_limit:
102 case mmt_any:
103 case mmt_begin:
104 case mmt_end:
105 default:
106 break;
110 /* If there were memory allocation errors, free the copy */
111 if (err > 0) {
112 freeMappingFormat(new);
113 new = 0;
116 return (new);
119 void
120 freeMappingFormat(__nis_mapping_format_t *m) {
121 int i;
123 if (m == 0)
124 return;
126 for (i = 0; m[i].type != mmt_end; i++) {
127 switch (m[i].type) {
128 case mmt_string:
129 sfree(m[i].match.string);
130 break;
131 case mmt_single:
132 sfree(m[i].match.single.lo);
133 sfree(m[i].match.single.hi);
134 break;
135 case mmt_berstring:
136 sfree(m[i].match.berString);
137 break;
138 case mmt_item:
139 case mmt_limit:
140 case mmt_any:
141 case mmt_begin:
142 case mmt_end:
143 default:
144 break;
148 free(m);
152 void
153 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) {
154 int i;
155 char *myself = "copyIndex";
157 if (old == 0 || new == 0) {
158 *err = EINVAL;
159 return;
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) {
165 *err = ENOMEM;
166 return;
168 new->value[i] = cloneMappingFormat(old->value[i]);
169 if (new->value[i] == 0 && old->value[i] != 0) {
170 *err = ENOMEM;
171 return;
175 new->numIndexes = old->numIndexes;
178 __nis_index_t *
179 cloneIndex(__nis_index_t *old) {
180 char *myself = "cloneIndex";
181 int err = 0;
182 __nis_index_t *new = am(myself, sizeof (*new));
184 if (old == 0)
185 return (0);
187 if (new != 0) {
188 copyIndex(old, new, &err);
189 if (err != 0) {
190 freeIndex(new, 1);
191 new = 0;
195 return (new);
198 void
199 freeIndex(__nis_index_t *old, bool_t doFree) {
200 int i;
202 if (old == 0)
203 return;
205 for (i = 0; i < old->numIndexes; i++) {
206 sfree(old->name[i]);
207 freeMappingFormat(old->value[i]);
210 if (doFree)
211 free(old);
214 char **
215 cloneName(char **name, int numNames) {
216 char **new;
217 int i;
218 char *myself = "cloneName";
220 if (name == 0 || numNames <= 0)
221 return (0);
223 new = am(myself, numNames * sizeof (new[0]));
224 if (new == 0)
225 return (0);
227 for (i = 0; i < numNames; i++) {
228 if (name[i] != 0) {
229 new[i] = sdup(myself, T, name[i]);
230 if (new[i] == 0) {
231 for (i--; i >= 0; i--) {
232 sfree(new[i]);
234 sfree(new);
235 return (0);
237 } else {
238 new[i] = 0;
242 return (new);
245 void
246 freeValue(__nis_value_t *val, int count) {
247 int c, i;
249 if (val == 0)
250 return;
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);
257 free(val[c].val);
261 free(val);
264 __nis_value_t *
265 cloneValue(__nis_value_t *val, int count) {
266 __nis_value_t *n;
267 int c, i;
268 char *myself = "cloneValue";
270 if (count <= 0 || val == 0)
271 return (0);
273 n = am(myself, count * sizeof (*n));
274 if (n == 0)
275 return (0);
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]));
284 if (n[c].val == 0) {
285 freeValue(n, c);
286 return (0);
288 } else {
289 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
305 * memory.
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] !=
310 '\0') {
311 amlen++;
313 n[c].val[i].value = am(myself, amlen);
314 if (amlen > 0 && n[c].val[i].value == 0) {
315 freeValue(n, c);
316 return (0);
318 memcpy(n[c].val[i].value, val[c].val[i].value,
319 n[c].val[i].length);
323 return (n);
326 /* Define LBER_USE_DER per ber_decode(3LDAP) */
327 #ifndef LBER_USE_DER
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.
335 __nis_value_t *
336 berEncode(__nis_value_t *valIn, char *berstring) {
337 char *myself = "berEncode";
338 __nis_value_t *val;
339 int i;
341 if (valIn == 0 || berstring == 0)
342 return (0);
344 val = cloneValue(valIn, 1);
345 if (val == 0)
346 return (0);
348 for (i = 0; i < val->numVals; i++) {
349 BerElement *ber = ber_alloc();
350 struct berval *bv = 0;
351 int ret;
353 if (ber == 0) {
354 logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL",
355 myself);
356 freeValue(val, 1);
357 return (0);
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)));
365 } else {
366 ret = -1;
368 } else if (strcmp("B", berstring) == 0) {
369 ret = ber_printf(ber, berstring,
370 val->val[i].value,
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);
380 if (str != 0) {
381 ret = ber_printf(ber, berstring, str);
382 free(str);
383 } else {
384 ret = -1;
386 } else {
387 ret = -1;
390 if (ret == -1) {
391 reportError(NPL_BERENCODE, "%s: BER encoding error",
392 myself);
393 ber_free(ber, 1);
394 freeValue(val, 1);
395 return (0);
398 if (ber_flatten(ber, &bv) != 0 || bv == 0) {
399 reportError(NPL_BERENCODE, "%s: ber_flatten() error",
400 myself);
401 ber_free(ber, 1);
402 freeValue(val, 1);
403 return (0);
406 sfree(val->val[i].value);
407 val->val[i].length = bv->bv_len;
408 val->val[i].value = bv->bv_val;
410 ber_free(ber, 1);
413 val->type = vt_ber;
415 return (val);
418 __nis_value_t *
419 berDecode(__nis_value_t *valIn, char *berstring) {
420 __nis_value_t *val;
421 int i;
422 char *myself = "berDecode";
424 if (valIn == 0 || berstring == 0)
425 return (0);
427 val = cloneValue(valIn, 1);
428 if (val == 0)
429 return (0);
431 for (i = 0; i < val->numVals; i++) {
432 void *v = 0;
433 int ret, len = 0;
434 struct berval bv;
435 BerElement *ber;
437 if (val->val[i].value == 0 || val->val[i].length <= 0)
438 continue;
440 bv.bv_val = val->val[i].value;
441 bv.bv_len = val->val[i].length;
442 ber = ber_init(&bv);
443 if (ber == 0) {
444 reportError(NPL_BERDECODE, "%s: ber_init() error",
445 myself);
446 freeValue(val, 1);
447 return (0);
450 if ((strcmp("b", berstring) == 0 ||
451 strcmp("i", berstring) == 0)) {
452 len = sizeof (int);
453 v = am(myself, len);
454 if (v != 0) {
455 ret = ber_scanf(ber, berstring, v);
456 } else {
457 ret = -1;
459 } else if (strcmp("B", berstring) == 0) {
460 long llen;
462 ret = ber_scanf(ber, berstring, &v, &llen);
463 if (ret != -1) {
464 len = llen/8;
466 } else if (strcmp("n", berstring) == 0) {
467 ret = 0;
468 } else if (strcmp("o", berstring) == 0) {
469 struct berval *bv = am(myself, sizeof (*bv));
471 if (bv != 0) {
472 ret = ber_scanf(ber, "O", &bv);
473 if (ret != -1 && bv != 0) {
474 v = bv->bv_val;
475 len = bv->bv_len;
476 } else {
477 ret = -1;
479 /* Only free 'bv' itself */
480 free(bv);
481 } else {
482 ret = -1;
484 } else if (strcmp("s", berstring) == 0) {
485 ret = ber_scanf(ber, "a", &v);
486 if (ret != -1) {
487 len = slen(v);
489 } else {
490 ret = -1;
493 if (ret == -1) {
494 reportError(NPL_BERDECODE, "%s: BER decoding error",
495 myself);
496 freeValue(val, 1);
497 return (0);
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;
506 return (val);
510 * Return the value of the specified item.
512 __nis_value_t *
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;
517 int i, j, k;
518 char **name;
519 enum {rvOnly, rvThenLookup, lookupOnly} check;
520 unsigned char fromldap = '\0';
522 if (item == 0)
523 return (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) {
530 case mit_nisplus:
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.
538 if (rv != 0) {
539 name = rv->colName;
540 nameVal = rv->colVal;
541 numName = rv->numColumns;
542 caseInsens = 0;
543 check = rvOnly;
544 } else {
545 return (0);
547 } else {
549 * Valid index, so skip the rule-value and do
550 * a direct NIS+ lookup.
552 check = lookupOnly;
554 break;
555 case mit_ldap:
556 if (rv != 0) {
557 name = rv->attrName;
558 nameVal = rv->attrVal;
559 numName = rv->numAttrs;
560 caseInsens = 1;
561 fromldap = '1';
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.
569 if (rv != 0) {
570 check = rvOnly;
571 } else {
572 return (0);
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
583 * LDAP lookup.
585 if (rv != 0) {
586 check = rvThenLookup;
587 } else {
588 check = lookupOnly;
590 } else {
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.
596 check = lookupOnly;
598 break;
599 default:
600 return (0);
603 /* Check the rule-value */
604 if (check == rvOnly || check == rvThenLookup) {
605 for (i = 0; i < numName; i++) {
606 if (caseInsens)
607 cmp = strcasecmp(item->name, name[i]);
608 else
609 cmp = strcmp(item->name, name[i]);
610 if (cmp == 0) {
611 if (nameVal[i].numVals <= 0)
612 break;
613 if (berstring == 0) {
614 val = cloneValue(&nameVal[i], 1);
615 } else if (yp2ldap && berstring[0] == 'a') {
616 val = cloneValue(&nameVal[i], 1);
617 } else {
618 val = berDecode(&nameVal[i],
619 berstring);
621 if (val != 0) {
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
637 * to np_ldap-stat.
640 if (np_ldap_stat != NULL)
641 *np_ldap_stat =
642 NP_LDAP_MAP_SUCCESS;
644 break;
649 /* Do a direct lookup ? */
650 if (val == 0 && (check == rvThenLookup || check == lookupOnly)) {
651 if (item->type == mit_ldap) {
652 int err = 0;
653 __nis_search_triple_t triple;
654 char *baseDN;
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;
668 } else {
669 baseDN = __nisdb_get_tsd()->searchBase;
671 triple.base = appendBase(item->searchSpec.triple.base,
672 baseDN, &err, 0);
673 if (err == 0) {
674 triple.scope = item->searchSpec.triple.scope;
675 triple.attrs = item->searchSpec.triple.attrs;
676 triple.element =
677 item->searchSpec.triple.element;
678 val = lookupLDAP(&triple, item->name, rv, 0,
679 np_ldap_stat);
680 fromldap = '1';
681 } else {
682 val = 0;
684 sfree(triple.base);
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) {
698 freeValue(val, 1);
699 return (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
711 /* Obtain exVal */
712 if (item->exItem)
713 exVal = getMappingItemVal(item->exItem, native, rv,
714 berstring, NULL);
716 /* delete */
717 if (exVal != 0) {
718 for (i = 0; i < val->numVals; ) {
719 for (j = 0; j < exVal->numVals; j++) {
720 if (sstrncmp(val->val[i].value,
721 exVal->val[j].value,
722 MAX(val->val[i].length,
723 exVal->val[j].length))
724 == 0)
725 break;
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;
736 val->numVals--;
737 } else
738 i++;
741 freeValue(exVal, 1);
744 * If val->numVals <= 0, then we have no val to
745 * return. So free up stuff.
747 if (val->numVals <= 0) {
748 free(val->val);
749 val->val = 0;
750 free(val);
751 return (0);
756 return (val);
759 __nis_value_t *
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};
765 int i;
767 if (f == 0)
768 return (0);
770 if (rv == 0) {
771 val = am(myself, sizeof (*val));
772 if (val == 0)
773 return (0);
775 switch (f->type) {
776 case mmt_item:
777 bp2buf(myself, &b, "%%s");
778 break;
779 case mmt_string:
780 bp2buf(myself, &b, "%s", NIL(f->match.string));
781 break;
782 case mmt_single:
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]);
789 else
790 bp2buf(myself, &b, "%c-%c",
791 f->match.single.lo[i],
792 f->match.single.hi[i]);
794 bp2buf(myself, &b, "]");
795 break;
796 case mmt_limit:
797 break;
798 case mmt_any:
799 bp2buf(myself, &b, "*");
800 break;
801 case mmt_berstring:
802 bp2buf(myself, &b, "%s", NIL(f->match.berString));
803 break;
804 case mmt_begin:
805 case mmt_end:
806 bp2buf(myself, &b, "\"");
807 break;
808 default:
809 bp2buf(myself, &b, "<unknown>");
811 val->type = vt_string;
812 val->numVals = 1;
813 val->val = am(myself, sizeof (val->val[0]));
814 if (val->val == 0) {
815 sfree(val);
816 return (0);
818 val->val[0].value = b.buf;
819 val->val[0].length = b.len;
820 } else {
821 switch (f->type) {
822 case mmt_item:
823 case mmt_berstring:
824 if (a != 0) {
825 if (at == fa_item) {
826 val = getMappingItemVal(
827 (__nis_mapping_item_t *)a,
828 mit_any, rv,
829 (f->type == mmt_berstring) ? f->match.berString : 0, NULL);
830 if (numArg != 0)
831 (*numArg)++;
832 } else {
833 val = cloneValue(
834 (__nis_value_t *)a, 1);
835 if (numArg != 0)
836 (*numArg)++;
839 break;
840 case mmt_string:
841 val = am(myself, sizeof (*val));
842 if (val == 0)
843 return (0);
844 val->type = vt_string;
845 val->numVals = 1;
846 val->val = am(myself, sizeof (val->val[0]));
847 if (val->val == 0) {
848 sfree(val);
849 return (0);
851 val->val[0].value = sdup(myself, T, f->match.string);
852 val->val[0].length = strlen(val->val[0].value);
853 break;
854 case mmt_single:
855 case mmt_limit:
856 case mmt_any:
857 case mmt_begin:
858 case mmt_end:
859 /* Not an error, so return an empty value */
860 val = am(myself, sizeof (*val));
861 if (val == 0)
862 return (0);
863 val->type = vt_string;
864 val->numVals = 0;
865 val->val = 0;
866 break;
867 default:
868 /* Do nothing */
869 val = 0;
870 break;
873 return (val);
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'
882 * M ditto).
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.
897 __nis_value_t *
898 explodeValues(__nis_value_t *v1, __nis_value_t *v2) {
899 int i1, i2, n, nv;
900 __nis_value_t *v;
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));
916 if (v == 0)
917 return (0);
919 if (!v1->repeat && !v2->repeat)
920 nv = v1->numVals * v2->numVals;
921 else if (v1->repeat && !v2->repeat)
922 nv = v2->numVals;
923 else if (!v1->repeat && v2->repeat)
924 nv = v1->numVals;
925 else /* v1->repeat && v2->repeat */
926 nv = 1;
928 v->val = am(myself, nv * sizeof (v->val[0]));
929 if (v->val == 0) {
930 free(v);
931 return (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,
942 v1->val[i1].length,
943 &b);
944 else
945 bc2buf(myself, v1->val[i1].value,
946 v1->val[i1].length,
947 &b);
948 if (v2->type == vt_string)
949 sbc2buf(myself, v2->val[i2].value,
950 v2->val[i2].length,
951 &b);
952 else
953 bc2buf(myself, v2->val[i2].value,
954 v2->val[i2].length,
955 &b);
956 v->val[n].value = b.buf;
957 v->val[n].length = b.len;
958 n++;
959 b.buf = 0;
960 b.len = 0;
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,
968 v1->val[i1].length,
969 &b);
970 else
971 bc2buf(myself, v1->val[i1].value,
972 v1->val[i1].length,
973 &b);
974 if (v2->type == vt_string)
975 sbc2buf(myself, v2->val[i2].value,
976 v2->val[i2].length,
977 &b);
978 else
979 bc2buf(myself, v2->val[i2].value,
980 v2->val[i2].length,
981 &b);
983 v->val[n].value = b.buf;
984 v->val[n].length = b.len;
985 n++;
986 b.buf = 0;
987 b.len = 0;
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,
994 v1->val[i1].length,
995 &b);
996 else
997 bc2buf(myself, v1->val[i1].value,
998 v1->val[i1].length,
999 &b);
1000 if (v2->type == vt_string)
1001 sbc2buf(myself, v2->val[i2].value,
1002 v2->val[i2].length,
1003 &b);
1004 else
1005 bc2buf(myself, v2->val[i2].value,
1006 v2->val[i2].length,
1007 &b);
1009 v->val[n].value = b.buf;
1010 v->val[n].length = b.len;
1011 n++;
1012 b.buf = 0;
1013 b.len = 0;
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,
1020 v1->val[i1].length,
1021 &b);
1022 else
1023 bc2buf(myself, v1->val[i1].value,
1024 v1->val[i1].length,
1025 &b);
1026 if (v2->type == vt_string)
1027 sbc2buf(myself, v2->val[i2].value,
1028 v2->val[i2].length,
1029 &b);
1030 else
1031 bc2buf(myself, v2->val[i2].value,
1032 v2->val[i2].length,
1033 &b);
1036 v->val[n].value = b.buf;
1037 v->val[n].length = b.len;
1038 n++;
1039 b.buf = 0;
1040 b.len = 0;
1043 #ifdef NISDB_LDAP_DEBUG
1044 /* Sanity check */
1045 if (n != nv)
1046 abort();
1047 #endif /* NISD__LDAP_DEBUG */
1049 v->type = (v1->type == vt_string) ?
1050 ((v2->type == vt_string) ?
1051 vt_string : vt_ber) : vt_ber;
1052 v->repeat = 0;
1053 v->numVals = n;
1055 return (v);
1058 __nis_value_t *
1059 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv,
1060 __nis_format_arg_t at, int numArgs, void *arg) {
1061 int i, ia = 0;
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);
1073 } else {
1074 __nis_value_t **ival = arg;
1075 val = getMappingFormat(&a[i], rv, at,
1076 ((ival != 0) ? ival[ia] : 0), &ia);
1078 if (val != 0) {
1079 __nis_value_t *new = explodeValues(v, val);
1081 freeValue(v, 1);
1082 freeValue(val, 1);
1083 if (new == 0)
1084 return (0);
1086 v = new;
1087 } else {
1088 freeValue(v, 1);
1089 return (0);
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;
1098 moreArgs = FALSE;
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
1109 * loop.
1111 if (numArgs > 0 && ia <= 0) {
1112 freeValue(v, 1);
1113 return (0);
1115 moreFormat = 1;
1119 return (v);
1123 * Returns a string representation (such as "[name=foo, value=bar]")
1124 * of a nis_index_t.
1126 char *
1127 getIndex(__nis_index_t *i, int *len) {
1128 int n;
1129 __nis_buffer_t b = {0, 0};
1130 char *myself = "getIndex";
1132 if (i == 0)
1133 return (0);
1135 if (i->numIndexes > 0) {
1136 bp2buf(myself, &b, "[");
1137 for (n = 0; n < i->numIndexes; n++) {
1138 __nis_value_t *val;
1139 int j;
1141 val = getMappingFormatArray(i->value[n],
1142 0, fa_any, 0, 0);
1143 if (n > 0)
1144 bp2buf(myself, &b, ", ");
1145 bp2buf(myself, &b, "%s=", i->name[n]);
1146 if (val != 0) {
1147 for (j = 0; j < val->numVals; j++) {
1148 bc2buf(myself, val->val[j].value,
1149 val->val[j].length, &b);
1151 } else {
1152 bp2buf(myself, &b, "<no-vals>");
1154 freeValue(val, 1);
1156 bp2buf(myself, &b, "]");
1158 if (len != 0)
1159 *len = b.len;
1160 return (b.buf);
1163 char *
1164 getObjSpec(__nis_obj_spec_t *o, int *len) {
1165 __nis_buffer_t b = {0, 0};
1166 char *myself = "getObjSpec";
1168 if (o == 0)
1169 return (0);
1171 b.buf = getIndex(&o->index, &b.len);
1172 sbc2buf(myself, o->name, slen(o->name), &b);
1173 if (len != 0)
1174 *len = b.len;
1175 return (b.buf);
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).
1183 char *
1184 getScope(int scope) {
1185 switch (scope) {
1186 case LDAP_SCOPE_BASE:
1187 return ("base");
1188 case LDAP_SCOPE_ONELEVEL:
1189 return ("one");
1190 case LDAP_SCOPE_SUBTREE:
1191 return ("sub");
1192 default:
1193 return ("one");
1198 * Return a string representation of an LDAP search triple (such as
1199 * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1201 char *
1202 getSearchTriple(__nis_search_triple_t *s, int *len) {
1203 __nis_buffer_t b = {0, 0};
1204 char *a;
1205 int l;
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) {
1210 if (len != 0)
1211 *len = 0;
1212 return (0);
1215 if (s->base != 0)
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
1226 * want it.
1228 a = am(myself, l+1);
1229 if (a != 0) {
1230 int i, la;
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);
1238 sfree(a);
1239 } else {
1240 sbc2buf(myself, s->attrs, slen(s->attrs), &b);
1244 if (len != 0)
1245 *len = b.len;
1246 return (b.buf);
1249 __nis_value_t *
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};
1255 int len = 0;
1256 char *buf;
1258 if (i == 0)
1259 return (0);
1261 if (rv != 0)
1262 return (getMappingItemVal(i, native, rv, berstring,
1263 np_ldap_stat));
1265 val = am(myself, sizeof (*val));
1266 if (val == 0)
1267 return (0);
1269 switch (i->type) {
1270 case mit_nisplus:
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);
1279 sfree(buf);
1280 val->type = vt_string;
1281 val->repeat = i->repeat;
1282 val->numVals = 1;
1283 val->val = am(myself, sizeof (val->val[0]));
1284 if (val->val == 0) {
1285 sfree(b.buf);
1286 free(val);
1287 return (0);
1289 val->val[0].value = b.buf;
1290 val->val[0].length = b.len;
1291 break;
1292 case mit_ldap:
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);
1301 sfree(buf);
1302 val->type = vt_string;
1303 val->repeat = i->repeat;
1304 val->numVals = 1;
1305 val->val = am(myself, sizeof (val->val[0]));
1306 if (val->val == 0) {
1307 sfree(b.buf);
1308 free(val);
1309 return (0);
1311 val->val[0].value = b.buf;
1312 val->val[0].length = b.len;
1313 break;
1314 default:
1315 p2buf(myself, "<unknown>:");
1316 p2buf(myself, "%s", NIL(i->name));
1317 break;
1320 return (val);
1323 void
1324 copyObjSpec(__nis_obj_spec_t *old, __nis_obj_spec_t *new, int *err) {
1325 char *myself = "copyObjSpec";
1327 if (old == 0 || new == 0) {
1328 *err = EINVAL;
1329 return;
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) {
1336 *err = ENOMEM;
1337 return;
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) {
1342 *err = ENOMEM;
1343 return;
1346 new->name = sdup(myself, T, old->name);
1347 if (new->name == 0 && old->name != 0) {
1348 *err = ENOMEM;
1349 return;
1351 copyIndex(&old->index, &new->index, err);
1354 __nis_obj_spec_t *
1355 cloneObjSpec(__nis_obj_spec_t *old) {
1356 char *myself = "cloneObjSpec";
1357 int err = 0;
1358 __nis_obj_spec_t *new = am(myself, sizeof (*new));
1360 if (new != 0) {
1361 copyObjSpec(old, new, &err);
1362 if (err != 0) {
1363 freeObjSpec(new, 1);
1364 new = 0;
1368 return (new);
1371 void
1372 freeObjSpec(__nis_obj_spec_t *old, bool_t doFree) {
1374 if (old == 0)
1375 return;
1377 sfree(old->name);
1378 freeIndex(&old->index, FALSE);
1379 if (doFree)
1380 free(old);
1383 void
1384 copySearchTriple(__nis_search_triple_t *old, __nis_search_triple_t *new,
1385 int *err) {
1386 char *myself = "copySearchTriple";
1388 *err = 0;
1390 if (old == 0 || new == 0) {
1391 *err = EINVAL;
1392 return;
1395 if (old->base != NULL)
1396 new->base = sdup(myself, T, old->base);
1397 else
1398 new->base = NULL;
1399 if (old->attrs != NULL)
1400 new->attrs = sdup(myself, T, old->attrs);
1401 else
1402 new->attrs = NULL;
1403 if ((new->base == 0 && old->base != 0) ||
1404 (new->attrs == 0 && old->attrs != 0)) {
1405 sfree(new->base);
1406 new->base = 0;
1407 sfree(new->attrs);
1408 new->attrs = 0;
1409 *err = ENOMEM;
1410 return;
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";
1425 int err = 0;
1426 __nis_search_triple_t *new = am(myself, sizeof (*new));
1428 if (new != 0) {
1429 copySearchTriple(old, new, &err);
1430 if (err != 0) {
1431 freeSearchTriple(new, 1);
1432 new = 0;
1436 return (new);
1439 void
1440 freeSearchTriple(__nis_search_triple_t *old, bool_t doFree) {
1442 if (old == 0)
1443 return;
1445 sfree(old->base);
1446 sfree(old->attrs);
1448 * Since we only copied the element pointer when this structure
1449 * was created, we don't free old->element.
1451 if (doFree)
1452 free(old);
1455 void
1456 copyTripleOrObj(__nis_mapping_item_type_t type,
1457 __nis_triple_or_obj_t *old, __nis_triple_or_obj_t *new,
1458 int *err) {
1460 *err = 0;
1462 if (old == 0 || new == 0) {
1463 *err = EINVAL;
1464 return;
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";
1477 int err = 0;
1478 __nis_triple_or_obj_t *new = am(myself, sizeof (*new));
1480 if (new != 0) {
1481 copyTripleOrObj(type, old, new, &err);
1482 if (err != 0) {
1483 freeTripleOrObj(type, new, 1);
1484 new = 0;
1488 return (new);
1491 void
1492 freeTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old,
1493 bool_t doFree) {
1495 if (old == 0)
1496 return;
1498 if (type == mit_nisplus)
1499 freeObjSpec(&old->obj, doFree);
1500 else if (type == mit_ldap)
1501 freeSearchTriple(&old->triple, doFree);
1503 if (doFree)
1504 free(old);
1507 void
1508 copyItem(__nis_mapping_item_t *old, __nis_mapping_item_t *new, int *err) {
1510 *err = 0;
1512 if (old == 0 || new == 0) {
1513 *err = EINVAL;
1514 return;
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) {
1522 *err = ENOMEM;
1523 return;
1525 } else {
1526 new->name = 0;
1528 if (old->type == mit_nisplus || old->type == mit_ldap)
1529 copyTripleOrObj(old->type, &old->searchSpec, &new->searchSpec,
1530 err);
1531 else
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;
1538 int err = 0;
1539 char *myself = "cloneItem";
1541 if (old == 0)
1542 return (0);
1544 new = am(myself, sizeof (*new));
1545 if (new == 0)
1546 return (0);
1548 copyItem(old, new, &err);
1549 if (err != 0) {
1550 freeMappingItem(new, 1);
1551 return (0);
1554 return (new);
1557 void
1558 freeMappingItem(__nis_mapping_item_t *item, int numItems) {
1559 int i;
1561 if (item == 0)
1562 return;
1564 for (i = 0; i < numItems; i++) {
1565 sfree(item[i].name);
1566 freeTripleOrObj(item[i].type, &item[i].searchSpec, FALSE);
1568 sfree(item);
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;
1575 int i, err = 0;
1576 char *myself = "concatenateMappingItem";
1578 if (old == 0 || numItems < 1)
1579 return (cloneItem(cat));
1581 new = am(myself, (numItems + 1) * sizeof (*new));
1582 if (new == 0)
1583 return (0);
1585 for (i = 0; i < numItems; i++) {
1586 copyItem(&old[i], &new[i], &err);
1587 if (err != 0) {
1588 freeMappingItem(new, i);
1589 return (0);
1592 copyItem(cat, &new[numItems], &err);
1593 if (err != 0) {
1594 freeMappingItem(new, numItems);
1595 new = 0;
1598 return (new);
1601 __nis_value_t *
1602 concatenateValues(__nis_value_t *v1, __nis_value_t *v2) {
1603 int i, n, a;
1604 __nis_value_t *v;
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)
1613 return (0);
1615 n = v1->numVals + v2->numVals;
1616 v = am(myself, sizeof (*v));
1617 if (v == 0)
1618 return (0);
1619 v->val = am(myself, n * sizeof (v->val[0]));
1620 if (v->val == 0) {
1621 free(v);
1622 return (0);
1624 v->type = v1->type;
1625 v->numVals = 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 :
1630 v2->numVals;
1631 for (i = 0; i < numv; i++) {
1632 int clen, alen = val[i].length;
1634 clen = alen;
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')
1643 alen += 1;
1644 v->val[v->numVals].value = am(myself, alen);
1645 if (v->val[v->numVals].value == 0) {
1646 freeValue(v, 1);
1647 return (0);
1649 memcpy(v->val[v->numVals].value, val[i].value, clen);
1650 v->val[v->numVals].length = val[i].length;
1651 v->numVals++;
1655 return (v);
1658 __nis_value_t *
1659 splitMappingItem(__nis_mapping_item_t *item, char delim,
1660 __nis_rule_value_t *rv) {
1661 __nis_value_t *val = getMappingItem(item, mit_any,
1662 rv, 0, NULL);
1663 __nis_single_value_t *nval;
1664 int i, n, nv;
1666 if (val == 0)
1667 return (0);
1668 else if (delim == 0 || val->val == 0 || val->numVals <= 0 ||
1669 val->type != vt_string) {
1670 freeValue(val, 1);
1671 return (0);
1674 nval = val->val;
1675 nv = val->numVals;
1676 val->repeat = FALSE;
1677 val->val = 0;
1678 val->numVals = 0;
1680 /* In N2L, space and tab delimiters are treated the same */
1681 if (yp2ldap && delim == '\t')
1682 delim = ' ';
1684 /* If the item has multiple values, we split each one independently */
1685 for (i = 0; i < nv; i++) {
1686 char *str;
1687 int s, e;
1688 char *newstr;
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)
1698 continue;
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.
1707 str[e] = '\0';
1708 /* Add to val->val */
1709 newstr = strdup(&str[s]);
1710 newval = reallocarray(val->val, val->numVals + 1,
1711 sizeof (val->val[0]));
1712 if (newval != 0)
1713 val->val = newval;
1714 if (newstr == 0 || newval == 0) {
1715 freeValue(val, 1);
1716 for (n = i; n < nv; n++) {
1717 sfree(nval[n].value);
1719 free(nval);
1720 sfree(newstr);
1721 return (0);
1723 val->val[val->numVals].value = newstr;
1724 val->val[val->numVals].length = strlen(newstr) + 1;
1725 val->numVals++;
1727 free(nval[i].value);
1728 nval[i].value = 0;
1730 /* Already freed the nval[i].value's as we traversed nval */
1731 free(nval);
1733 return (val);
1737 * Match the format spec 'f[curf]' to the input value string 'str'.
1739 * If successful, returns the updated position in the value string 'str'.
1740 * Otherwise, NULL is returned.
1742 * curf Current index (i.e., the one we should look at) in 'f'
1743 * nf Number of elements in 'f', including 'mmt_end'
1744 * str The value string we're scanning
1745 * val Pointer to where an item value (if any) should be returned
1746 * Set to NULL if not an 'mmt_item'.
1747 * fmtstart If non-zero on entry, skip characters in 'str' until we find
1748 * the f[curf].type data, if doing so makes any sense. On exit,
1749 * set to the start of the fmt element data (which will be 'str',
1750 * unless we did skip characters)
1751 * sepset List of separators
1753 char *
1754 scanMappingFormat(__nis_mapping_format_t *f, int curf, int nf, char *str,
1755 char **val, char **fmtstart, char *sepset) {
1756 char *mstr, *next, *start = 0, *tmpstr;
1757 int i, len;
1758 bool_t match;
1759 char *myself = "scanMappingFormat";
1760 /* N2L variables */
1761 int af, skipspaces = 0;
1762 bool_t ipaddr = FALSE;
1763 char *spacestr = " ", *emptystr = "";
1766 if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1767 return (0);
1770 * If separator list is NULL (which will be the case for
1771 * nis+2ldap), then simply use empty string
1773 if (sepset == 0)
1774 sepset = emptystr;
1776 if (curf >= nf) {
1777 /* OK if the string also is exhausted */
1778 if (strchr(sepset, *str) != 0)
1779 return (str);
1780 else
1781 return (0);
1784 switch (f[curf].type) {
1785 case mmt_berstring:
1786 if (f[curf].match.berString[0] != 'a') {
1787 /* Not a matchable element */
1788 return (0);
1792 * If here, it means it's an IP address (N2L case)
1793 * So continue processing as if it was mmt_item
1795 ipaddr = TRUE;
1796 /* FALLTHROUGH */
1797 case mmt_item:
1799 * In order to find the end of the item value, we must look
1800 * ahead and determine the start of the next formatting element.
1801 * If successful, 'next' will be the start of the fmt element
1802 * after the next one; we don't care about that, other than to
1803 * check for error.
1805 * Since an item match is somewhat like an any match, in that
1806 * we don't know a priori if the first occurence of the next
1807 * element really is the one we want, we have to scan ahead
1808 * until we've reached the end.
1810 tmpstr = str;
1811 while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1812 &start, sepset)) != 0) {
1813 char *tmp = next;
1814 int cf;
1816 for (cf = curf+2; cf < nf; cf++) {
1817 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1818 0, sepset);
1819 if (tmp == 0)
1820 break;
1822 if (tmp == 0) {
1823 tmpstr = next;
1824 } else if (strchr(sepset, *tmp) != 0) {
1825 break;
1826 } else {
1827 return (0);
1831 if (next == 0 || start == 0)
1832 return (0);
1834 if (val != 0) {
1835 len = (int)((long)start - (long)str);
1836 *val = am(myself, len + 1);
1837 if (*val == 0)
1838 return (0);
1839 memcpy(*val, str, len);
1840 (*val)[len] = '\0';
1842 if (ipaddr == TRUE) {
1844 * In N2L, we need to check if *val is truly an
1845 * IP address
1847 af = checkIPaddress(*val, len, &tmpstr);
1849 if (af == -2) {
1850 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1851 "%s:Internal error while "
1852 "processing IPaddress %s",
1853 myself, *val);
1854 sfree(*val);
1855 return (0);
1856 } else if (af == -1) {
1857 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1858 "%s:%s is not an IP address",
1859 myself, *val);
1860 sfree(*val);
1861 return (0);
1862 } else if (af == 0) {
1863 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1864 "%s:IP address %s is not "
1865 "supported by rfc2307bis",
1866 myself, *val);
1867 sfree(*val);
1868 return (0);
1869 } else if (sstrncmp(*val, tmpstr, len) != 0) {
1870 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1871 "%s:IPaddress %s converted "
1872 "to %s", myself, *val, tmpstr);
1875 sfree(*val);
1876 *val = tmpstr;
1880 if (fmtstart != 0)
1881 *fmtstart = str;
1883 return (start);
1885 case mmt_string:
1886 if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1888 * Count this as a successful match of an empty
1889 * string.
1891 if (fmtstart != 0)
1892 *fmtstart = str;
1893 return (str);
1897 * In N2L, if the format string 'mstr' contains only
1898 * whitespaces (spaces and tabs), then it should
1899 * match one or more whitespaces from the input
1900 * string 'str'.
1902 if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1903 mstr = spacestr;
1904 skipspaces = 1;
1905 next = str + strcspn(str, " \t");
1907 * Even if there is no whitespace in 'str',
1908 * it's OK. This is to allow formats like
1909 * "%s %s %s" to match inputs like "foo bar".
1911 if (*next == '\0')
1912 mstr = emptystr;
1913 } else {
1914 /* No match string in 'str' => failure */
1915 if ((next = strstr(str, mstr)) == 0)
1916 return (0);
1919 /* If 'fmtstart' == 0, we require 'next' == 'str' */
1920 if (fmtstart == 0 && next != str)
1921 return (0);
1922 /* Success; save start of match string if requested */
1923 if (fmtstart != 0)
1924 *fmtstart = next;
1925 /* Update position in the value string */
1926 str = (char *)((long)next + (long)strlen(mstr));
1928 /* Skip whitespaces for N2L */
1929 if (skipspaces == 1)
1930 for (; *str == ' ' || *str == '\t'; str++);
1932 return (str);
1934 case mmt_single:
1935 if (fmtstart != 0) {
1936 match = FALSE;
1937 /* Skip ahead until we match */
1938 for (next = str; *next != '\0'; next++) {
1939 unsigned char *lo = f[curf].match.single.lo;
1940 unsigned char *hi = f[curf].match.single.hi;
1942 for (i = 0; i < f[curf].match.single.numRange;
1943 i++) {
1944 if (*next >= lo[i] && *next <= hi[i]) {
1945 match = TRUE;
1946 break;
1949 if (match)
1950 break;
1952 if (!match)
1953 return (0);
1954 *fmtstart = next;
1955 str = next;
1956 } else {
1957 match = FALSE;
1958 for (i = 0; i < f[curf].match.single.numRange; i++) {
1959 if (*str >= f[curf].match.single.lo[i] &&
1960 *str <= f[curf].match.single.hi[i]) {
1961 match = TRUE;
1962 break;
1965 if (!match)
1966 return (0);
1968 /* Step over the matched character */
1969 str++;
1970 return (str);
1972 case mmt_any:
1974 * Look ahead to find the beginning of the next element.
1975 * Because a wildcard-match isn't necessarily uniquely
1976 * determined until we've reached the end, we then continue
1977 * to scan ahead.
1979 while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1980 &start, sepset)) != 0) {
1981 char *tmp = next;
1982 int cf;
1984 for (cf = curf+2; cf < nf; cf++) {
1985 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1986 0, sepset);
1987 if (tmp == 0)
1988 break;
1990 if (tmp == 0) {
1991 str = next;
1992 } else if (*tmp == '\0') {
1993 break;
1994 } else {
1995 return (0);
1998 if (next == 0 || start == 0)
1999 return (0);
2001 if (fmtstart != 0)
2002 *fmtstart = str;
2004 return (start);
2006 case mmt_limit:
2007 if (f[curf].match.limit == eos) {
2008 if (fmtstart != 0) {
2009 /* Skip to the end */
2010 str = str + strcspn(str, sepset);
2011 *fmtstart = str;
2012 } else if (strchr(sepset, *str) == 0) {
2013 return (0);
2016 return (str);
2018 case mmt_begin:
2019 if (fmtstart != 0)
2020 *fmtstart = str;
2021 return (str);
2023 case mmt_end:
2024 if (fmtstart != 0) {
2025 /* Skip to the end */
2026 str = str + strcspn(str, sepset);
2027 *fmtstart = str;
2028 return (str);
2030 /* No skipping, so we must be at the end of the value */
2031 if (strchr(sepset, *str) == 0)
2032 return (0);
2033 return (str);
2035 default:
2036 break;
2039 return (0);
2043 * Verify that the string 'str' matches the mapping format array 'f'.
2044 * Returns 1 in case of a match, 0 otherwise.
2047 verifyMappingMatch(__nis_mapping_format_t *f, char *str) {
2048 int n, nf;
2049 __nis_mapping_format_t *ftmp;
2051 /* Count the number of format elements in the format */
2052 for (nf = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2053 nf++;
2055 /* Count the mmt_end as well */
2056 nf++;
2058 for (n = 0; n < nf; n++) {
2059 str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2060 if (str == 0)
2061 break;
2064 return ((str != 0) ? 1 : 0);
2068 * Perform a match operation. For example, given the rule
2069 * ("{%s}%s", auth_name, public_data)=nisPublicKey
2070 * and assuming that 'nisPublicKey' has the value "{dh640-0}abcdef12345",
2071 * assign "dh640-0" to 'auth_name' and "abcdef12345" to 'public_data'.
2073 * Note that this function doesn't perform the actual assignment. Rather,
2074 * it returns an array of __nis_value_t's, with element zero of the value
2075 * array being the new value of the first matched item, element one the
2076 * value of the second matched item, etc. In the example above, we'd
2077 * return a value array with two elements.
2079 * If there is more than one input value (inVal->numVals > 1), the
2080 * output array elements will also be multi-valued.
2082 * f The match format
2083 * inVal Input value(s)
2084 * numVal Number of elements in the output value array
2085 * sepset List of separators
2086 * outstr Points to the updated position upto which the
2087 * input string has been matched
2089 __nis_value_t **
2090 matchMappingItem(__nis_mapping_format_t *f, __nis_value_t *inVal,
2091 int *numVals, char *sepset, char **outstr) {
2092 __nis_value_t **v = 0;
2093 int i, n, ni, numItems, nf;
2094 char *str, *valstr;
2095 __nis_mapping_format_t *ftmp;
2096 char *myself = "matchMappingItem";
2098 if (f == 0 ||
2099 inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2100 return (0);
2102 /* Count the number of format elements and items in the format */
2103 for (nf = numItems = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2104 nf++;
2107 * Count mmt_item and mmt_berstring (used by N2L to
2108 * represent address %a)
2110 if (ftmp->type == mmt_item)
2111 numItems++;
2112 else if (ftmp->type == mmt_berstring && ftmp->match.berString &&
2113 ftmp->match.berString[0] == 'a')
2114 numItems++;
2116 /* Count the mmt_end as well */
2117 nf++;
2120 * If no items, there will be no values. This isn't exactly an error
2121 * from the limited point of view of this function, so we return a
2122 * __nis_value_t with zero values.
2124 if (numItems <= 0) {
2125 v = am(myself, sizeof (v[0]));
2126 if (v == 0)
2127 return (0);
2128 v[0] = am(myself, sizeof (*v[0]));
2129 if (v[0] == 0) {
2130 sfree(v);
2131 return (0);
2133 v[0]->type = vt_string;
2134 v[0]->numVals = 0;
2135 v[0]->val = 0;
2136 if (numVals != 0)
2137 *numVals = 1;
2138 return (v);
2141 /* Allocate and initialize the return array */
2142 v = am(myself, numItems * sizeof (v[0]));
2143 if (v == 0)
2144 return (0);
2145 for (n = 0; n < numItems; n++) {
2146 v[n] = am(myself, sizeof (*v[n]));
2147 if (v[n] == 0) {
2148 int j;
2150 for (j = 0; j < n; j++)
2151 freeValue(v[j], 1);
2152 sfree(v);
2153 return (0);
2155 v[n]->type = vt_string;
2156 v[n]->numVals = 0;
2157 v[n]->val = am(myself, inVal->numVals * sizeof (v[n]->val[0]));
2158 if (v[n]->val == 0) {
2159 int j;
2161 for (j = 0; j < n; j++)
2162 freeValue(v[j], 1);
2163 sfree(v);
2164 return (0);
2166 for (i = 0; i < inVal->numVals; i++) {
2167 v[n]->val[i].length = 0;
2168 v[n]->val[i].value = 0;
2172 /* For each input value, perform the match operation */
2173 for (i = 0; i < inVal->numVals; i++) {
2174 str = inVal->val[i].value;
2175 if (str == 0)
2176 continue;
2177 for (n = 0, ni = 0; n < nf; n++) {
2178 valstr = 0;
2179 str = scanMappingFormat(f, n, nf, str, &valstr,
2180 0, sepset);
2181 if (str == 0)
2182 break;
2183 if (valstr != 0 && ni < numItems &&
2184 v[ni]->numVals < inVal->numVals) {
2185 v[ni]->val[v[ni]->numVals].value = valstr;
2186 v[ni]->val[v[ni]->numVals].length =
2187 strlen(valstr) + 1;
2188 v[ni]->numVals++;
2189 ni++;
2190 } else if (valstr != 0) {
2191 sfree(valstr);
2194 if (str == 0) {
2195 for (n = 0; n < numItems; n++)
2196 freeValue(v[n], 1);
2197 sfree(v);
2198 return (0);
2202 if (numVals != 0)
2203 *numVals = numItems;
2206 * Update the return string upto the point it has been matched
2207 * This string will be used by the N2L code in its next call
2208 * to this function
2210 if (outstr != 0)
2211 *outstr = str;
2213 return (v);
2217 * Perform an extract operation. For example, given the expression
2218 * (name, "%s.*")
2219 * and assuming 'name' is an item with the value "some.thing", the
2220 * value returned by the extract is "some".
2222 __nis_value_t *
2223 extractMappingItem(__nis_mapping_item_t *item, __nis_mapping_format_t *f,
2224 __nis_rule_value_t *rv, int *stat) {
2225 __nis_value_t *val = getMappingItem(item, mit_any,
2226 rv, 0, stat);
2227 __nis_single_value_t *nval;
2228 int i, n, nv, nf;
2229 __nis_mapping_format_t *ftmp;
2231 if (val == 0)
2232 return (0);
2233 else if (f == 0 || rv == 0 || val->val == 0 ||
2234 val->numVals <= 0 || val->type != vt_string) {
2235 freeValue(val, 1);
2236 return (0);
2239 /* Sanity check the format; it must have one and only one mmt_item */
2241 int numitem;
2243 for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2244 ftmp++) {
2245 nf++;
2246 if (ftmp->type == mmt_item)
2247 numitem++;
2249 /* Count the mmt_end as well */
2250 nf++;
2251 if (numitem != 1) {
2252 freeValue(val, 1);
2253 return (0);
2257 nval = val->val;
2258 nv = val->numVals;
2259 val->repeat = FALSE;
2260 val->val = 0;
2261 val->numVals = 0;
2263 /* If the item has multiple values, we extract each one independently */
2264 for (i = 0; i < nv; i++) {
2265 char *str = nval[i].value;
2266 char *newstr = 0;
2267 __nis_single_value_t *newval;
2269 if (nval[i].value == 0)
2270 continue;
2273 * We match the whole string, even if we find a value for
2274 * the item before exhausting all format elements. By doing
2275 * this, we ensure that the string really matches the complete
2276 * format specification.
2278 for (n = 0; n < nf; n++) {
2279 str = scanMappingFormat(f, n, nf, str, &newstr, 0, 0);
2280 if (str == 0)
2281 break;
2285 * *str should now be NUL, meaning we've reached the end of
2286 * the string (value), and it completely matched the format.
2287 * If 'str' is NULL, there was an error, and if 'newstr' is
2288 * 0, we somehow failed to obtain a value.
2290 if (str == 0 || *str != '\0' || newstr == 0 ||
2291 (newval = reallocarray(val->val,
2292 val->numVals + 1,
2293 sizeof (val->val[0]))) == 0) {
2294 freeValue(val, 1);
2295 for (n = 0; n < nv; n++) {
2296 sfree(nval[n].value);
2298 free(nval);
2299 sfree(newstr);
2300 return (0);
2303 val->val = newval;
2304 val->val[val->numVals].value = newstr;
2305 val->val[val->numVals].length = strlen(newstr) + 1;
2306 val->numVals++;
2308 free(nval[i].value);
2309 nval[i].value = 0;
2311 free(nval);
2313 return (val);
2317 * For each value in 'val', remove the last character, provided that
2318 * it matches 'elide'.
2320 void
2321 stringElide(__nis_value_t *val, char elide) {
2323 if (val != 0 && val->type == vt_string) {
2324 int i;
2326 for (i = 0; i < val->numVals; i++) {
2327 int end = val->val[i].length;
2328 char *str = val->val[i].value;
2330 if (str == 0 || end <= 0)
2331 continue;
2334 * If the NUL was counted in the length, step back
2335 * over it.
2337 if (str[end-1] == '\0')
2338 end--;
2339 if (end > 0 && str[end-1] == elide) {
2340 str[end-1] = '\0';
2341 val->val[i].length--;
2348 * Obtain the value for the mapping sub-element 'e', given the input
2349 * rule-value 'rv'.
2351 __nis_value_t *
2352 getMappingSubElement(__nis_mapping_sub_element_t *e,
2353 __nis_rule_value_t *rv, int *np_ldap_stat) {
2354 __nis_value_t *val;
2356 if (e == 0)
2357 return (0);
2359 switch (e->type) {
2360 case me_item:
2361 val = getMappingItem(&e->element.item, mit_any, rv, 0,
2362 np_ldap_stat);
2363 break;
2364 case me_print:
2365 val = getMappingFormatArray(e->element.print.fmt, rv,
2366 fa_item,
2367 e->element.print.numItems,
2368 e->element.print.item);
2369 if (e->element.print.doElide)
2370 stringElide(val, e->element.print.elide);
2371 break;
2372 case me_split:
2373 val = splitMappingItem(&e->element.split.item,
2374 e->element.split.delim,
2375 rv);
2376 break;
2377 case me_extract:
2378 val = extractMappingItem(&e->element.extract.item,
2379 e->element.extract.fmt,
2380 rv, np_ldap_stat);
2381 break;
2382 case me_match:
2383 default:
2384 val = 0;
2385 break;
2388 return (val);
2392 * Obtain the value of the mapping element 'e', given the input rule-
2393 * value 'rv'. The 'native' mapping type is used when 'rv' is NULL,
2394 * and the result is a string representation of the mapping element;
2395 * in that case, items of the 'native' type are printed without their
2396 * type designation ("nis+" or "ldap").
2398 __nis_value_t *
2399 getMappingElement(__nis_mapping_element_t *e, __nis_mapping_item_type_t native,
2400 __nis_rule_value_t *rv, int *stat) {
2401 __nis_value_t *val, **tv;
2402 int i, success = 0, novalue = 0;
2403 int *np_ldap_stat;
2404 char *myself = "getMappingElement";
2406 switch (e->type) {
2407 case me_item:
2408 val = getMappingItem(&e->element.item, native, rv, 0, NULL);
2409 break;
2410 case me_print:
2411 tv = am(myself, e->element.print.numSubElements *
2412 sizeof (tv[0]));
2413 np_ldap_stat = am(myself,
2414 e->element.print.numSubElements * sizeof (int));
2415 if ((e->element.print.numSubElements > 0) &&
2416 (tv == 0 || np_ldap_stat == 0)) {
2417 val = 0;
2418 sfree(tv);
2419 sfree(np_ldap_stat);
2420 break;
2422 for (i = 0; i < e->element.print.numSubElements; i++) {
2423 np_ldap_stat[i] = 0;
2424 tv[i] = getMappingSubElement(
2425 &e->element.print.subElement[i],
2426 rv, &np_ldap_stat[i]);
2429 * if we get NP_LDAP_NO_VALUE to any of the subelement
2430 * and we get NP_LDAP_MAP_SUCCESS to all other subelement
2431 * then we had enough nis+ column values which can
2432 * produce value for this rule, but didn't. So return
2433 * NP_LDAP_RULES_NO_VALUE to indicate to proceed to
2434 * next database id.
2436 for (i = 0; i < e->element.print.numSubElements; i++) {
2437 if (np_ldap_stat[i] == NP_LDAP_MAP_SUCCESS)
2438 success++;
2439 if (np_ldap_stat[i] == NP_LDAP_NO_VALUE)
2440 novalue++;
2442 if (stat != NULL && novalue > 0 &&
2443 ((novalue+success) ==
2444 e->element.print.numSubElements))
2445 *stat = NP_LDAP_RULES_NO_VALUE;
2446 val = getMappingFormatArray(e->element.print.fmt, rv,
2447 fa_value,
2448 e->element.print.numSubElements,
2449 tv);
2450 for (i = 0; i < e->element.print.numSubElements; i++) {
2451 freeValue(tv[i], 1);
2453 sfree(tv);
2454 sfree(np_ldap_stat);
2455 if (e->element.print.doElide)
2456 stringElide(val, e->element.print.elide);
2457 break;
2458 case me_split:
2459 val = splitMappingItem(&e->element.split.item,
2460 e->element.split.delim,
2461 rv);
2462 break;
2463 case me_match:
2465 * A match doesn't produce an assignable value per se,
2466 * so we shouldn't get one here.
2468 val = 0;
2469 break;
2470 case me_extract:
2471 val = extractMappingItem(&e->element.extract.item,
2472 e->element.extract.fmt,
2473 rv, NULL);
2474 break;
2475 default:
2476 val = 0;
2477 break;
2480 return (val);