5910 libnisdb won't build with modern GCC
[unleashed.git] / usr / src / lib / libnisdb / ldap_val.c
blob84b0c330a8ffde275907d531190771f33376b6e1
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 = realloc(val->val,
1711 (val->numVals+1) *
1712 sizeof (val->val[0]));
1713 if (newval != 0)
1714 val->val = newval;
1715 if (newstr == 0 || newval == 0) {
1716 freeValue(val, 1);
1717 for (n = i; n < nv; n++) {
1718 sfree(nval[n].value);
1720 free(nval);
1721 sfree(newstr);
1722 return (0);
1724 val->val[val->numVals].value = newstr;
1725 val->val[val->numVals].length = strlen(newstr) + 1;
1726 val->numVals++;
1728 free(nval[i].value);
1729 nval[i].value = 0;
1731 /* Already freed the nval[i].value's as we traversed nval */
1732 free(nval);
1734 return (val);
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
1754 char *
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;
1758 int i, len;
1759 bool_t match;
1760 char *myself = "scanMappingFormat";
1761 /* N2L variables */
1762 int af, skipspaces = 0;
1763 bool_t ipaddr = FALSE;
1764 char *spacestr = " ", *emptystr = "";
1767 if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1768 return (0);
1771 * If separator list is NULL (which will be the case for
1772 * nis+2ldap), then simply use empty string
1774 if (sepset == 0)
1775 sepset = emptystr;
1777 if (curf >= nf) {
1778 /* OK if the string also is exhausted */
1779 if (strchr(sepset, *str) != 0)
1780 return (str);
1781 else
1782 return (0);
1785 switch (f[curf].type) {
1786 case mmt_berstring:
1787 if (f[curf].match.berString[0] != 'a') {
1788 /* Not a matchable element */
1789 return (0);
1793 * If here, it means it's an IP address (N2L case)
1794 * So continue processing as if it was mmt_item
1796 ipaddr = TRUE;
1798 case 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
1804 * check for error.
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.
1811 tmpstr = str;
1812 while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1813 &start, sepset)) != 0) {
1814 char *tmp = next;
1815 int cf;
1817 for (cf = curf+2; cf < nf; cf++) {
1818 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1819 0, sepset);
1820 if (tmp == 0)
1821 break;
1823 if (tmp == 0) {
1824 tmpstr = next;
1825 } else if (strchr(sepset, *tmp) != 0) {
1826 break;
1827 } else {
1828 return (0);
1832 if (next == 0 || start == 0)
1833 return (0);
1835 if (val != 0) {
1836 len = (int)((long)start - (long)str);
1837 *val = am(myself, len + 1);
1838 if (*val == 0)
1839 return (0);
1840 memcpy(*val, str, len);
1841 (*val)[len] = '\0';
1843 if (ipaddr == TRUE) {
1845 * In N2L, we need to check if *val is truly an
1846 * IP address
1848 af = checkIPaddress(*val, len, &tmpstr);
1850 if (af == -2) {
1851 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1852 "%s:Internal error while "
1853 "processing IPaddress %s",
1854 myself, *val);
1855 sfree(*val);
1856 return (0);
1857 } else if (af == -1) {
1858 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1859 "%s:%s is not an IP address",
1860 myself, *val);
1861 sfree(*val);
1862 return (0);
1863 } else if (af == 0) {
1864 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1865 "%s:IP address %s is not "
1866 "supported by rfc2307bis",
1867 myself, *val);
1868 sfree(*val);
1869 return (0);
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);
1876 sfree(*val);
1877 *val = tmpstr;
1881 if (fmtstart != 0)
1882 *fmtstart = str;
1884 return (start);
1886 case mmt_string:
1887 if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1889 * Count this as a successful match of an empty
1890 * string.
1892 if (fmtstart != 0)
1893 *fmtstart = str;
1894 return (str);
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
1901 * string 'str'.
1903 if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1904 mstr = spacestr;
1905 skipspaces = 1;
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".
1912 if (*next == '\0')
1913 mstr = emptystr;
1914 } else {
1915 /* No match string in 'str' => failure */
1916 if ((next = strstr(str, mstr)) == 0)
1917 return (0);
1920 /* If 'fmtstart' == 0, we require 'next' == 'str' */
1921 if (fmtstart == 0 && next != str)
1922 return (0);
1923 /* Success; save start of match string if requested */
1924 if (fmtstart != 0)
1925 *fmtstart = next;
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++);
1933 return (str);
1935 case mmt_single:
1936 if (fmtstart != 0) {
1937 match = FALSE;
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;
1944 i++) {
1945 if (*next >= lo[i] && *next <= hi[i]) {
1946 match = TRUE;
1947 break;
1950 if (match)
1951 break;
1953 if (!match)
1954 return (0);
1955 *fmtstart = next;
1956 str = next;
1957 } else {
1958 match = FALSE;
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]) {
1962 match = TRUE;
1963 break;
1966 if (!match)
1967 return (0);
1969 /* Step over the matched character */
1970 str++;
1971 return (str);
1973 case mmt_any:
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
1978 * to scan ahead.
1980 while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1981 &start, sepset)) != 0) {
1982 char *tmp = next;
1983 int cf;
1985 for (cf = curf+2; cf < nf; cf++) {
1986 tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1987 0, sepset);
1988 if (tmp == 0)
1989 break;
1991 if (tmp == 0) {
1992 str = next;
1993 } else if (*tmp == '\0') {
1994 break;
1995 } else {
1996 return (0);
1999 if (next == 0 || start == 0)
2000 return (0);
2002 if (fmtstart != 0)
2003 *fmtstart = str;
2005 return (start);
2007 case mmt_limit:
2008 if (f[curf].match.limit == eos) {
2009 if (fmtstart != 0) {
2010 /* Skip to the end */
2011 str = str + strcspn(str, sepset);
2012 *fmtstart = str;
2013 } else if (strchr(sepset, *str) == 0) {
2014 return (0);
2017 return (str);
2019 case mmt_begin:
2020 if (fmtstart != 0)
2021 *fmtstart = str;
2022 return (str);
2024 case mmt_end:
2025 if (fmtstart != 0) {
2026 /* Skip to the end */
2027 str = str + strcspn(str, sepset);
2028 *fmtstart = str;
2029 return (str);
2031 /* No skipping, so we must be at the end of the value */
2032 if (strchr(sepset, *str) == 0)
2033 return (0);
2034 return (str);
2036 default:
2037 break;
2040 return (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) {
2049 int n, nf;
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++) {
2054 nf++;
2056 /* Count the mmt_end as well */
2057 nf++;
2059 for (n = 0; n < nf; n++) {
2060 str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2061 if (str == 0)
2062 break;
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
2090 __nis_value_t **
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;
2095 char *str, *valstr;
2096 __nis_mapping_format_t *ftmp;
2097 char *myself = "matchMappingItem";
2099 if (f == 0 ||
2100 inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2101 return (0);
2103 /* Count the number of format elements and items in the format */
2104 for (nf = numItems = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2105 nf++;
2108 * Count mmt_item and mmt_berstring (used by N2L to
2109 * represent address %a)
2111 if (ftmp->type == mmt_item)
2112 numItems++;
2113 else if (ftmp->type == mmt_berstring && ftmp->match.berString &&
2114 ftmp->match.berString[0] == 'a')
2115 numItems++;
2117 /* Count the mmt_end as well */
2118 nf++;
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]));
2127 if (v == 0)
2128 return (0);
2129 v[0] = am(myself, sizeof (*v[0]));
2130 if (v[0] == 0) {
2131 sfree(v);
2132 return (0);
2134 v[0]->type = vt_string;
2135 v[0]->numVals = 0;
2136 v[0]->val = 0;
2137 if (numVals != 0)
2138 *numVals = 1;
2139 return (v);
2142 /* Allocate and initialize the return array */
2143 v = am(myself, numItems * sizeof (v[0]));
2144 if (v == 0)
2145 return (0);
2146 for (n = 0; n < numItems; n++) {
2147 v[n] = am(myself, sizeof (*v[n]));
2148 if (v[n] == 0) {
2149 int j;
2151 for (j = 0; j < n; j++)
2152 freeValue(v[j], 1);
2153 sfree(v);
2154 return (0);
2156 v[n]->type = vt_string;
2157 v[n]->numVals = 0;
2158 v[n]->val = am(myself, inVal->numVals * sizeof (v[n]->val[0]));
2159 if (v[n]->val == 0) {
2160 int j;
2162 for (j = 0; j < n; j++)
2163 freeValue(v[j], 1);
2164 sfree(v);
2165 return (0);
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;
2176 if (str == 0)
2177 continue;
2178 for (n = 0, ni = 0; n < nf; n++) {
2179 valstr = 0;
2180 str = scanMappingFormat(f, n, nf, str, &valstr,
2181 0, sepset);
2182 if (str == 0)
2183 break;
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 =
2188 strlen(valstr) + 1;
2189 v[ni]->numVals++;
2190 ni++;
2191 } else if (valstr != 0) {
2192 sfree(valstr);
2195 if (str == 0) {
2196 for (n = 0; n < numItems; n++)
2197 freeValue(v[n], 1);
2198 sfree(v);
2199 return (0);
2203 if (numVals != 0)
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
2209 * to this function
2211 if (outstr != 0)
2212 *outstr = str;
2214 return (v);
2218 * Perform an extract operation. For example, given the expression
2219 * (name, "%s.*")
2220 * and assuming 'name' is an item with the value "some.thing", the
2221 * value returned by the extract is "some".
2223 __nis_value_t *
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,
2227 rv, 0, stat);
2228 __nis_single_value_t *nval;
2229 int i, n, nv, nf;
2230 __nis_mapping_format_t *ftmp;
2232 if (val == 0)
2233 return (0);
2234 else if (f == 0 || rv == 0 || val->val == 0 ||
2235 val->numVals <= 0 || val->type != vt_string) {
2236 freeValue(val, 1);
2237 return (0);
2240 /* Sanity check the format; it must have one and only one mmt_item */
2242 int numitem;
2244 for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2245 ftmp++) {
2246 nf++;
2247 if (ftmp->type == mmt_item)
2248 numitem++;
2250 /* Count the mmt_end as well */
2251 nf++;
2252 if (numitem != 1) {
2253 freeValue(val, 1);
2254 return (0);
2258 nval = val->val;
2259 nv = val->numVals;
2260 val->repeat = FALSE;
2261 val->val = 0;
2262 val->numVals = 0;
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;
2267 char *newstr = 0;
2268 __nis_single_value_t *newval;
2270 if (nval[i].value == 0)
2271 continue;
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);
2281 if (str == 0)
2282 break;
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,
2293 (val->numVals+1) *
2294 sizeof (val->val[0]))) == 0) {
2295 freeValue(val, 1);
2296 for (n = 0; n < nv; n++) {
2297 sfree(nval[n].value);
2299 free(nval);
2300 sfree(newstr);
2301 return (0);
2304 val->val = newval;
2305 val->val[val->numVals].value = newstr;
2306 val->val[val->numVals].length = strlen(newstr) + 1;
2307 val->numVals++;
2309 free(nval[i].value);
2310 nval[i].value = 0;
2312 free(nval);
2314 return (val);
2318 * For each value in 'val', remove the last character, provided that
2319 * it matches 'elide'.
2321 void
2322 stringElide(__nis_value_t *val, char elide) {
2324 if (val != 0 && val->type == vt_string) {
2325 int i;
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)
2332 continue;
2335 * If the NUL was counted in the length, step back
2336 * over it.
2338 if (str[end-1] == '\0')
2339 end--;
2340 if (end > 0 && str[end-1] == elide) {
2341 str[end-1] = '\0';
2342 val->val[i].length--;
2349 * Obtain the value for the mapping sub-element 'e', given the input
2350 * rule-value 'rv'.
2352 __nis_value_t *
2353 getMappingSubElement(__nis_mapping_sub_element_t *e,
2354 __nis_rule_value_t *rv, int *np_ldap_stat) {
2355 __nis_value_t *val;
2357 if (e == 0)
2358 return (0);
2360 switch (e->type) {
2361 case me_item:
2362 val = getMappingItem(&e->element.item, mit_any, rv, 0,
2363 np_ldap_stat);
2364 break;
2365 case me_print:
2366 val = getMappingFormatArray(e->element.print.fmt, rv,
2367 fa_item,
2368 e->element.print.numItems,
2369 e->element.print.item);
2370 if (e->element.print.doElide)
2371 stringElide(val, e->element.print.elide);
2372 break;
2373 case me_split:
2374 val = splitMappingItem(&e->element.split.item,
2375 e->element.split.delim,
2376 rv);
2377 break;
2378 case me_extract:
2379 val = extractMappingItem(&e->element.extract.item,
2380 e->element.extract.fmt,
2381 rv, np_ldap_stat);
2382 break;
2383 case me_match:
2384 default:
2385 val = 0;
2386 break;
2389 return (val);
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").
2399 __nis_value_t *
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;
2404 int *np_ldap_stat;
2405 char *myself = "getMappingElement";
2407 switch (e->type) {
2408 case me_item:
2409 val = getMappingItem(&e->element.item, native, rv, 0, NULL);
2410 break;
2411 case me_print:
2412 tv = am(myself, e->element.print.numSubElements *
2413 sizeof (tv[0]));
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)) {
2418 val = 0;
2419 sfree(tv);
2420 sfree(np_ldap_stat);
2421 break;
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
2435 * next database id.
2437 for (i = 0; i < e->element.print.numSubElements; i++) {
2438 if (np_ldap_stat[i] == NP_LDAP_MAP_SUCCESS)
2439 success++;
2440 if (np_ldap_stat[i] == NP_LDAP_NO_VALUE)
2441 novalue++;
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,
2448 fa_value,
2449 e->element.print.numSubElements,
2450 tv);
2451 for (i = 0; i < e->element.print.numSubElements; i++) {
2452 freeValue(tv[i], 1);
2454 sfree(tv);
2455 sfree(np_ldap_stat);
2456 if (e->element.print.doElide)
2457 stringElide(val, e->element.print.elide);
2458 break;
2459 case me_split:
2460 val = splitMappingItem(&e->element.split.item,
2461 e->element.split.delim,
2462 rv);
2463 break;
2464 case me_match:
2466 * A match doesn't produce an assignable value per se,
2467 * so we shouldn't get one here.
2469 val = 0;
2470 break;
2471 case me_extract:
2472 val = extractMappingItem(&e->element.extract.item,
2473 e->element.extract.fmt,
2474 rv, NULL);
2475 break;
2476 default:
2477 val = 0;
2478 break;
2481 return (val);