1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include <lber.h>
28 #include <ldap.h>
29 #include <strings.h>
30 #include <errno.h>
31
32 #include "nisdb_mt.h"
33
34 #include "ldap_util.h"
35 #include "ldap_op.h"
36 #include "ldap_ruleval.h"
37 #include "ldap_attr.h"
38 #include "ldap_val.h"
39 #include "ldap_ldap.h"
40
41 extern int yp2ldap;
42
43
44 __nis_mapping_format_t *
cloneMappingFormat(__nis_mapping_format_t * m)45 cloneMappingFormat(__nis_mapping_format_t *m) {
46 __nis_mapping_format_t *new;
47 int i, nf, err;
48 char *myself = "cloneMappingFormat";
49
50 if (m == 0)
51 return (0);
52
53 for (nf = 0; m[nf].type != mmt_end; nf++);
54 nf++;
55
56 new = am(myself, nf * sizeof (new[0]));
57 if (new == 0)
58 return (0);
59
60 /* Copy the whole array */
61 memcpy(new, m, nf * sizeof (new[0]));
62
63 /* Make copies of allocated stuff */
64 for (i = 0, err = 0; i < nf; i++) {
65 switch (m[i].type) {
66 case mmt_string:
67 new[i].match.string = sdup(myself, T,
68 m[i].match.string);
69 if (new[i].match.string == 0 && m[i].match.string != 0)
70 err++;
71 break;
72 case mmt_single:
73 new[i].match.single.lo =
74 am(myself, m[i].match.single.numRange *
75 sizeof (new[i].match.single.lo[0]));
76 new[i].match.single.hi =
77 am(myself, m[i].match.single.numRange *
78 sizeof (new[i].match.single.hi[0]));
79 if (new[i].match.single.lo != 0)
80 memcpy(new[i].match.single.lo,
81 m[i].match.single.lo,
82 m[i].match.single.numRange);
83 else if (m[i].match.single.lo != 0)
84 err++;
85 if (new[i].match.single.hi != 0)
86 memcpy(new[i].match.single.hi,
87 m[i].match.single.hi,
88 m[i].match.single.numRange);
89 else if (m[i].match.single.hi != 0)
90 err++;
91 break;
92 case mmt_berstring:
93 new[i].match.berString = sdup(myself, T,
94 m[i].match.berString);
95 if (new[i].match.berString == 0 &&
96 m[i].match.berString != 0)
97 err++;
98 break;
99 case mmt_item:
100 case mmt_limit:
101 case mmt_any:
102 case mmt_begin:
103 case mmt_end:
104 default:
105 break;
106 }
107 }
108
109 /* If there were memory allocation errors, free the copy */
110 if (err > 0) {
111 freeMappingFormat(new);
112 new = 0;
113 }
114
115 return (new);
116 }
117
118 void
freeMappingFormat(__nis_mapping_format_t * m)119 freeMappingFormat(__nis_mapping_format_t *m) {
120 int i;
121
122 if (m == 0)
123 return;
124
125 for (i = 0; m[i].type != mmt_end; i++) {
126 switch (m[i].type) {
127 case mmt_string:
128 sfree(m[i].match.string);
129 break;
130 case mmt_single:
131 sfree(m[i].match.single.lo);
132 sfree(m[i].match.single.hi);
133 break;
134 case mmt_berstring:
135 sfree(m[i].match.berString);
136 break;
137 case mmt_item:
138 case mmt_limit:
139 case mmt_any:
140 case mmt_begin:
141 case mmt_end:
142 default:
143 break;
144 }
145 }
146
147 free(m);
148 }
149
150
151 void
copyIndex(__nis_index_t * old,__nis_index_t * new,int * err)152 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) {
153 int i;
154 char *myself = "copyIndex";
155
156 if (old == 0 || new == 0) {
157 *err = EINVAL;
158 return;
159 }
160
161 for (i = 0; i < old->numIndexes; i++) {
162 new->name[i] = sdup(myself, T, old->name[i]);
163 if (new->name[i] == 0 && old->name[i] != 0) {
164 *err = ENOMEM;
165 return;
166 }
167 new->value[i] = cloneMappingFormat(old->value[i]);
168 if (new->value[i] == 0 && old->value[i] != 0) {
169 *err = ENOMEM;
170 return;
171 }
172 }
173
174 new->numIndexes = old->numIndexes;
175 }
176
177 __nis_index_t *
cloneIndex(__nis_index_t * old)178 cloneIndex(__nis_index_t *old) {
179 char *myself = "cloneIndex";
180 int err = 0;
181 __nis_index_t *new = am(myself, sizeof (*new));
182
183 if (old == 0)
184 return (0);
185
186 if (new != 0) {
187 copyIndex(old, new, &err);
188 if (err != 0) {
189 freeIndex(new, 1);
190 new = 0;
191 }
192 }
193
194 return (new);
195 }
196
197 void
freeIndex(__nis_index_t * old,bool_t doFree)198 freeIndex(__nis_index_t *old, bool_t doFree) {
199 int i;
200
201 if (old == 0)
202 return;
203
204 for (i = 0; i < old->numIndexes; i++) {
205 sfree(old->name[i]);
206 freeMappingFormat(old->value[i]);
207 }
208
209 if (doFree)
210 free(old);
211 }
212
213 char **
cloneName(char ** name,int numNames)214 cloneName(char **name, int numNames) {
215 char **new;
216 int i;
217 char *myself = "cloneName";
218
219 if (name == 0 || numNames <= 0)
220 return (0);
221
222 new = am(myself, numNames * sizeof (new[0]));
223 if (new == 0)
224 return (0);
225
226 for (i = 0; i < numNames; i++) {
227 if (name[i] != 0) {
228 new[i] = sdup(myself, T, name[i]);
229 if (new[i] == 0) {
230 for (i--; i >= 0; i--) {
231 sfree(new[i]);
232 }
233 sfree(new);
234 return (0);
235 }
236 } else {
237 new[i] = 0;
238 }
239 }
240
241 return (new);
242 }
243
244 void
freeValue(__nis_value_t * val,int count)245 freeValue(__nis_value_t *val, int count) {
246 int c, i;
247
248 if (val == 0)
249 return;
250
251 for (c = 0; c < count; c++) {
252 if (val[c].val != 0) {
253 for (i = 0; i < val[c].numVals; i++) {
254 sfree(val[c].val[i].value);
255 }
256 free(val[c].val);
257 }
258 }
259
260 free(val);
261 }
262
263 __nis_value_t *
cloneValue(__nis_value_t * val,int count)264 cloneValue(__nis_value_t *val, int count) {
265 __nis_value_t *n;
266 int c, i;
267 char *myself = "cloneValue";
268
269 if (count <= 0 || val == 0)
270 return (0);
271
272 n = am(myself, count * sizeof (*n));
273 if (n == 0)
274 return (0);
275
276 for (c = 0; c < count; c++) {
277 n[c].type = val[c].type;
278 n[c].repeat = val[c].repeat;
279 n[c].numVals = val[c].numVals;
280 if (n[c].numVals > 0) {
281 n[c].val = am(myself, n[c].numVals *
282 sizeof (n[c].val[0]));
283 if (n[c].val == 0) {
284 freeValue(n, c);
285 return (0);
286 }
287 } else {
288 n[c].val = 0;
289 }
290 for (i = 0; i < n[c].numVals; i++) {
291 int amlen = val[c].val[i].length;
292
293 /*
294 * The functions that create string values try to
295 * make sure that there's a NUL at the end. However,
296 * both NIS+ and LDAP have a tendency to store strings
297 * without a NUL, so the value length may not include
298 * the NUL (even though it's there). In order to
299 * preserve that NUL, we add a byte to the length if
300 * the type is vt_string, and there isn't already a
301 * NUL at the end. The memory allocation function
302 * (am()) will take care of actually putting the NUL
303 * in place, since it allocates zero-initialized
304 * memory.
305 */
306 n[c].val[i].length = val[c].val[i].length;
307 if (n[c].type == vt_string && amlen > 0 &&
308 ((char *)val[c].val[i].value)[amlen-1] !=
309 '\0') {
310 amlen++;
311 }
312 n[c].val[i].value = am(myself, amlen);
313 if (amlen > 0 && n[c].val[i].value == 0) {
314 freeValue(n, c);
315 return (0);
316 }
317 memcpy(n[c].val[i].value, val[c].val[i].value,
318 n[c].val[i].length);
319 }
320 }
321
322 return (n);
323 }
324
325 /* Define LBER_USE_DER per ber_decode(3LDAP) */
326 #ifndef LBER_USE_DER
327 #define LBER_USE_DER 0x01
328 #endif /* LBER_USE_DER */
329
330 /*
331 * Return a copy of 'valIn' where each value has been replaced by the
332 * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged.
333 */
334 __nis_value_t *
berEncode(__nis_value_t * valIn,char * berstring)335 berEncode(__nis_value_t *valIn, char *berstring) {
336 char *myself = "berEncode";
337 __nis_value_t *val;
338 int i;
339
340 if (valIn == 0 || berstring == 0)
341 return (0);
342
343 val = cloneValue(valIn, 1);
344 if (val == 0)
345 return (0);
346
347 for (i = 0; i < val->numVals; i++) {
348 BerElement *ber = ber_alloc();
349 struct berval *bv = 0;
350 int ret;
351
352 if (ber == 0) {
353 logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL",
354 myself);
355 freeValue(val, 1);
356 return (0);
357 }
358
359 if ((strcmp("b", berstring) == 0 ||
360 strcmp("i", berstring) == 0)) {
361 if (val->val[i].length >= sizeof (int)) {
362 ret = ber_printf(ber, berstring,
363 *((int *)(val->val[i].value)));
364 } else {
365 ret = -1;
366 }
367 } else if (strcmp("B", berstring) == 0) {
368 ret = ber_printf(ber, berstring,
369 val->val[i].value,
370 val->val[i].length * 8);
371 } else if (strcmp("n", berstring) == 0) {
372 ret = ber_printf(ber, berstring);
373 } else if (strcmp("o", berstring) == 0) {
374 ret = ber_printf(ber, berstring,
375 val->val[i].value, val->val[i].length);
376 } else if (strcmp("s", berstring) == 0) {
377 char *str = am(myself, val->val[i].length + 1);
378
379 if (str != 0) {
380 ret = ber_printf(ber, berstring, str);
381 free(str);
382 } else {
383 ret = -1;
384 }
385 } else {
386 ret = -1;
387 }
388
389 if (ret == -1) {
390 reportError(NPL_BERENCODE, "%s: BER encoding error",
391 myself);
392 ber_free(ber, 1);
393 freeValue(val, 1);
394 return (0);
395 }
396
397 if (ber_flatten(ber, &bv) != 0 || bv == 0) {
398 reportError(NPL_BERENCODE, "%s: ber_flatten() error",
399 myself);
400 ber_free(ber, 1);
401 freeValue(val, 1);
402 return (0);
403 }
404
405 sfree(val->val[i].value);
406 val->val[i].length = bv->bv_len;
407 val->val[i].value = bv->bv_val;
408
409 ber_free(ber, 1);
410 }
411
412 val->type = vt_ber;
413
414 return (val);
415 }
416
417 __nis_value_t *
berDecode(__nis_value_t * valIn,char * berstring)418 berDecode(__nis_value_t *valIn, char *berstring) {
419 __nis_value_t *val;
420 int i;
421 char *myself = "berDecode";
422
423 if (valIn == 0 || berstring == 0)
424 return (0);
425
426 val = cloneValue(valIn, 1);
427 if (val == 0)
428 return (0);
429
430 for (i = 0; i < val->numVals; i++) {
431 void *v = 0;
432 int ret, len = 0;
433 struct berval bv;
434 BerElement *ber;
435
436 if (val->val[i].value == 0 || val->val[i].length <= 0)
437 continue;
438
439 bv.bv_val = val->val[i].value;
440 bv.bv_len = val->val[i].length;
441 ber = ber_init(&bv);
442 if (ber == 0) {
443 reportError(NPL_BERDECODE, "%s: ber_init() error",
444 myself);
445 freeValue(val, 1);
446 return (0);
447 }
448
449 if ((strcmp("b", berstring) == 0 ||
450 strcmp("i", berstring) == 0)) {
451 len = sizeof (int);
452 v = am(myself, len);
453 if (v != 0) {
454 ret = ber_scanf(ber, berstring, v);
455 } else {
456 ret = -1;
457 }
458 } else if (strcmp("B", berstring) == 0) {
459 long llen;
460
461 ret = ber_scanf(ber, berstring, &v, &llen);
462 if (ret != -1) {
463 len = llen/8;
464 }
465 } else if (strcmp("n", berstring) == 0) {
466 ret = 0;
467 } else if (strcmp("o", berstring) == 0) {
468 struct berval *bv = am(myself, sizeof (*bv));
469
470 if (bv != 0) {
471 ret = ber_scanf(ber, "O", &bv);
472 if (ret != -1 && bv != 0) {
473 v = bv->bv_val;
474 len = bv->bv_len;
475 } else {
476 ret = -1;
477 }
478 /* Only free 'bv' itself */
479 free(bv);
480 } else {
481 ret = -1;
482 }
483 } else if (strcmp("s", berstring) == 0) {
484 ret = ber_scanf(ber, "a", &v);
485 if (ret != -1) {
486 len = slen(v);
487 }
488 } else {
489 ret = -1;
490 }
491
492 if (ret == -1) {
493 reportError(NPL_BERDECODE, "%s: BER decoding error",
494 myself);
495 freeValue(val, 1);
496 return (0);
497 }
498
499 /* Free the old value, and replace it with the decoded one */
500 sfree(val->val[i].value);
501 val->val[i].value = v;
502 val->val[i].length = len;
503 }
504
505 return (val);
506 }
507
508 /*
509 * Return the value of the specified item.
510 */
511 __nis_value_t *
getMappingItemVal(__nis_mapping_item_t * item,__nis_mapping_item_type_t native,__nis_rule_value_t * rv,char * berstring,int * np_ldap_stat)512 getMappingItemVal(__nis_mapping_item_t *item, __nis_mapping_item_type_t native,
513 __nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
514 __nis_value_t *val = 0, *nameVal, *exVal = 0;
515 int numName, caseInsens, cmp;
516 int i, j, k;
517 char **name;
518 enum {rvOnly, rvThenLookup, lookupOnly} check;
519 unsigned char fromldap = '\0';
520
521 if (item == 0)
522 return (0);
523
524 /*
525 * First, we decide if we should look for the value in 'rv',
526 * directly from NIS+/LDAP, or both.
527 */
528 switch (item->type) {
529 case mit_nisplus:
530 /* Do we have a valid index/object spec ? */
531 if (item->searchSpec.obj.index.numIndexes <= 0 &&
532 item->searchSpec.obj.name == 0) {
533 /*
534 * No valid index/object. If we have a rule-value,
535 * use it. Otherwise, return error.
536 */
537 if (rv != 0) {
538 name = rv->colName;
539 nameVal = rv->colVal;
540 numName = rv->numColumns;
541 caseInsens = 0;
542 check = rvOnly;
543 } else {
544 return (0);
545 }
546 } else {
547 /*
548 * Valid index, so skip the rule-value and do
549 * a direct NIS+ lookup.
550 */
551 check = lookupOnly;
552 }
553 break;
554 case mit_ldap:
555 if (rv != 0) {
556 name = rv->attrName;
557 nameVal = rv->attrVal;
558 numName = rv->numAttrs;
559 caseInsens = 1;
560 fromldap = '1';
561 }
562 /* Do we have a valid triple ? */
563 if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) {
564 /*
565 * No valid triple. If we have a rule-value, use it.
566 * Otherwise, return error.
567 */
568 if (rv != 0) {
569 check = rvOnly;
570 } else {
571 return (0);
572 }
573 } else if (item->searchSpec.triple.base == 0 &&
574 item->searchSpec.triple.scope ==
575 LDAP_SCOPE_ONELEVEL &&
576 item->searchSpec.triple.attrs == 0 &&
577 item->searchSpec.triple.element == 0) {
578 /*
579 * We have a valid triple, but it points to the
580 * current LDAP container. Thus, first look in
581 * the rule-value; if that fails, perform a direct
582 * LDAP lookup.
583 */
584 if (rv != 0) {
585 check = rvThenLookup;
586 } else {
587 check = lookupOnly;
588 }
589 } else {
590 /*
591 * Valid triple, and it's not the current container
592 * (at least not in the trivial sense). Hence, do
593 * a direct LDAP lookup.
594 */
595 check = lookupOnly;
596 }
597 break;
598 default:
599 return (0);
600 }
601
602 /* Check the rule-value */
603 if (check == rvOnly || check == rvThenLookup) {
604 for (i = 0; i < numName; i++) {
605 if (caseInsens)
606 cmp = strcasecmp(item->name, name[i]);
607 else
608 cmp = strcmp(item->name, name[i]);
609 if (cmp == 0) {
610 if (nameVal[i].numVals <= 0)
611 break;
612 if (berstring == 0) {
613 val = cloneValue(&nameVal[i], 1);
614 } else if (yp2ldap && berstring[0] == 'a') {
615 val = cloneValue(&nameVal[i], 1);
616 } else {
617 val = berDecode(&nameVal[i],
618 berstring);
619 }
620 if (val != 0) {
621 val->repeat = item->repeat;
622 /*
623 * If value for nis+ column is
624 * passed with value, val is
625 * manipulated in cloneValue().
626 * To decide whether there are
627 * enough nis+ column values
628 * for rule to produce a value,
629 * we need nis+ column values
630 * as well as nis_mapping_element
631 * from the rule. If we are here,
632 * it indicates that the 'val has
633 * an valid value for the column
634 * item-> name. So set
635 * NP_LDAP_MAP_SUCCESS
636 * to np_ldap-stat.
637 */
638
639 if (np_ldap_stat != NULL)
640 *np_ldap_stat =
641 NP_LDAP_MAP_SUCCESS;
642 }
643 break;
644 }
645 }
646 }
647
648 /* Do a direct lookup ? */
649 if (val == 0 && (check == rvThenLookup || check == lookupOnly)) {
650 if (item->type == mit_ldap) {
651 int err = 0;
652 __nis_search_triple_t triple;
653 char *baseDN;
654
655 /*
656 * If item->searchSpec.triple.base is NULL, or ends
657 * in a comma, append the current search base from
658 * the TSD (put there by an upper layer).
659 *
660 * Special case for N2L mode:
661 * if item->searchSpec.triple.base ends in a comma,
662 * the current domain Context is used.
663 */
664 if (yp2ldap && item->searchSpec.triple.base &&
665 strlen(item->searchSpec.triple.base) > 0) {
666 baseDN = __nisdb_get_tsd()->domainContext;
667 } else {
668 baseDN = __nisdb_get_tsd()->searchBase;
669 }
670 triple.base = appendBase(item->searchSpec.triple.base,
671 baseDN, &err, 0);
672 if (err == 0) {
673 triple.scope = item->searchSpec.triple.scope;
674 triple.attrs = item->searchSpec.triple.attrs;
675 triple.element =
676 item->searchSpec.triple.element;
677 val = lookupLDAP(&triple, item->name, rv, 0,
678 np_ldap_stat);
679 fromldap = '1';
680 } else {
681 val = 0;
682 }
683 sfree(triple.base);
684 }
685 }
686
687
688 /* Special processing for NIS to LDAP mode */
689 if (yp2ldap && val != 0) {
690
691 /*
692 * Escape special chars from dn before sending to DIT,
693 * provided val is not ldap-based
694 */
695 if (fromldap == '\0' && __nisdb_get_tsd()->escapeFlag == '1') {
696 if (escapeSpecialChars(val) < 0) {
697 freeValue(val, 1);
698 return (0);
699 }
700 } else if (__nisdb_get_tsd()->escapeFlag == '2') {
701 /* Remove escape chars from data received from DIT */
702 (void) removeEscapeChars(val);
703 }
704
705 /*
706 * Remove from 'val', any values obtained using
707 * the 'removespec' syntax
708 */
709
710 /* Obtain exVal */
711 if (item->exItem)
712 exVal = getMappingItemVal(item->exItem, native, rv,
713 berstring, NULL);
714
715 /* delete */
716 if (exVal != 0) {
717 for (i = 0; i < val->numVals; ) {
718 for (j = 0; j < exVal->numVals; j++) {
719 if (sstrncmp(val->val[i].value,
720 exVal->val[j].value,
721 MAX(val->val[i].length,
722 exVal->val[j].length))
723 == 0)
724 break;
725 }
726 if (j < exVal->numVals) {
727 sfree(val->val[i].value);
728 val->val[i].value = 0;
729 val->val[i].length = 0;
730 for (k = i; k < val->numVals - 1; k++) {
731 val->val[k] = val->val[k + 1];
732 val->val[k + 1].value = 0;
733 val->val[k + 1].length = 0;
734 }
735 val->numVals--;
736 } else
737 i++;
738 }
739
740 freeValue(exVal, 1);
741
742 /*
743 * If val->numVals <= 0, then we have no val to
744 * return. So free up stuff.
745 */
746 if (val->numVals <= 0) {
747 free(val->val);
748 val->val = 0;
749 free(val);
750 return (0);
751 }
752 }
753 }
754
755 return (val);
756 }
757
758 __nis_value_t *
getMappingFormat(__nis_mapping_format_t * f,__nis_rule_value_t * rv,__nis_format_arg_t at,void * a,int * numArg)759 getMappingFormat(__nis_mapping_format_t *f, __nis_rule_value_t *rv,
760 __nis_format_arg_t at, void *a, int *numArg) {
761 char *myself = "getMappingFormat";
762 __nis_value_t *val = 0;
763 __nis_buffer_t b = {0, 0};
764 int i;
765
766 if (f == 0)
767 return (0);
768
769 if (rv == 0) {
770 val = am(myself, sizeof (*val));
771 if (val == 0)
772 return (0);
773
774 switch (f->type) {
775 case mmt_item:
776 bp2buf(myself, &b, "%%s");
777 break;
778 case mmt_string:
779 bp2buf(myself, &b, "%s", NIL(f->match.string));
780 break;
781 case mmt_single:
782 bp2buf(myself, &b, "[");
783 for (i = 0; i < f->match.single.numRange; i++) {
784 if (f->match.single.lo[i] ==
785 f->match.single.hi[i])
786 bp2buf(myself, &b, "%c",
787 f->match.single.lo[i]);
788 else
789 bp2buf(myself, &b, "%c-%c",
790 f->match.single.lo[i],
791 f->match.single.hi[i]);
792 }
793 bp2buf(myself, &b, "]");
794 break;
795 case mmt_limit:
796 break;
797 case mmt_any:
798 bp2buf(myself, &b, "*");
799 break;
800 case mmt_berstring:
801 bp2buf(myself, &b, "%s", NIL(f->match.berString));
802 break;
803 case mmt_begin:
804 case mmt_end:
805 bp2buf(myself, &b, "\"");
806 break;
807 default:
808 bp2buf(myself, &b, "<unknown>");
809 }
810 val->type = vt_string;
811 val->numVals = 1;
812 val->val = am(myself, sizeof (val->val[0]));
813 if (val->val == 0) {
814 sfree(val);
815 return (0);
816 }
817 val->val[0].value = b.buf;
818 val->val[0].length = b.len;
819 } else {
820 switch (f->type) {
821 case mmt_item:
822 case mmt_berstring:
823 if (a != 0) {
824 if (at == fa_item) {
825 val = getMappingItemVal(
826 (__nis_mapping_item_t *)a,
827 mit_any, rv,
828 (f->type == mmt_berstring) ? f->match.berString : 0, NULL);
829 if (numArg != 0)
830 (*numArg)++;
831 } else {
832 val = cloneValue(
833 (__nis_value_t *)a, 1);
834 if (numArg != 0)
835 (*numArg)++;
836 }
837 }
838 break;
839 case mmt_string:
840 val = am(myself, sizeof (*val));
841 if (val == 0)
842 return (0);
843 val->type = vt_string;
844 val->numVals = 1;
845 val->val = am(myself, sizeof (val->val[0]));
846 if (val->val == 0) {
847 sfree(val);
848 return (0);
849 }
850 val->val[0].value = sdup(myself, T, f->match.string);
851 val->val[0].length = strlen(val->val[0].value);
852 break;
853 case mmt_single:
854 case mmt_limit:
855 case mmt_any:
856 case mmt_begin:
857 case mmt_end:
858 /* Not an error, so return an empty value */
859 val = am(myself, sizeof (*val));
860 if (val == 0)
861 return (0);
862 val->type = vt_string;
863 val->numVals = 0;
864 val->val = 0;
865 break;
866 default:
867 /* Do nothing */
868 val = 0;
869 break;
870 }
871 }
872 return (val);
873 }
874
875 /*
876 * Used when evaluating an expression. Typically, the value of the
877 * expression so far will be kept in 'v1', and 'v2' is the value
878 * of the current component of the expression. In the general case,
879 * both will be multi-valued, and the result is an "explosion"
880 * resulting in N*M new values (if 'v1' had N values, and 'v2'
881 * M ditto).
882 *
883 * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"},
884 * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl",
885 * "efgh", "efij", "efkl"}.
886 *
887 * There are special cases when v1->repeat and/or v2->repeat are set.
888 * Repeat mostly makes sense with single values; for example, if
889 * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result
890 * is {"x=1", "x=2", "x=3"}.
891 *
892 * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's
893 * not clear if there's a useful application for this, but the code's
894 * there for the sake of orthogonality.
895 */
896 __nis_value_t *
explodeValues(__nis_value_t * v1,__nis_value_t * v2)897 explodeValues(__nis_value_t *v1, __nis_value_t *v2) {
898 int i1, i2, n, nv;
899 __nis_value_t *v;
900 __nis_buffer_t b = {0, 0};
901 char *myself = "explodeValues";
902
903 if (v1 == 0 || v1->numVals <= 0)
904 return (cloneValue(v2, 1));
905 if (v2 == 0 || v2->numVals <= 0)
906 return (cloneValue(v1, 1));
907
908 /*
909 * XXX What should we do if (v1->type != v2->type) ?
910 * Policy: Just explode anyway, even though the result is
911 * unlikely to be very useful.
912 */
913
914 v = am(myself, sizeof (*v));
915 if (v == 0)
916 return (0);
917
918 if (!v1->repeat && !v2->repeat)
919 nv = v1->numVals * v2->numVals;
920 else if (v1->repeat && !v2->repeat)
921 nv = v2->numVals;
922 else if (!v1->repeat && v2->repeat)
923 nv = v1->numVals;
924 else /* v1->repeat && v2->repeat */
925 nv = 1;
926
927 v->val = am(myself, nv * sizeof (v->val[0]));
928 if (v->val == 0) {
929 free(v);
930 return (0);
931 }
932
933 /*
934 * Four different cases, depending on the 'repeat' flags.
935 */
936 if (!v1->repeat && !v2->repeat) {
937 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
938 for (i2 = 0; i2 < v2->numVals; i2++) {
939 if (v1->type == vt_string)
940 sbc2buf(myself, v1->val[i1].value,
941 v1->val[i1].length,
942 &b);
943 else
944 bc2buf(myself, v1->val[i1].value,
945 v1->val[i1].length,
946 &b);
947 if (v2->type == vt_string)
948 sbc2buf(myself, v2->val[i2].value,
949 v2->val[i2].length,
950 &b);
951 else
952 bc2buf(myself, v2->val[i2].value,
953 v2->val[i2].length,
954 &b);
955 v->val[n].value = b.buf;
956 v->val[n].length = b.len;
957 n++;
958 b.buf = 0;
959 b.len = 0;
960 }
961 }
962 } else if (v1->repeat && !v2->repeat) {
963 for (i2 = 0; i2 < v2->numVals; i2++) {
964 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
965 if (v1->type == vt_string)
966 sbc2buf(myself, v1->val[i1].value,
967 v1->val[i1].length,
968 &b);
969 else
970 bc2buf(myself, v1->val[i1].value,
971 v1->val[i1].length,
972 &b);
973 if (v2->type == vt_string)
974 sbc2buf(myself, v2->val[i2].value,
975 v2->val[i2].length,
976 &b);
977 else
978 bc2buf(myself, v2->val[i2].value,
979 v2->val[i2].length,
980 &b);
981 }
982 v->val[n].value = b.buf;
983 v->val[n].length = b.len;
984 n++;
985 b.buf = 0;
986 b.len = 0;
987 }
988 } else if (!v1->repeat && v2->repeat) {
989 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
990 for (i2 = 0; i2 < v2->numVals; i2++) {
991 if (v1->type == vt_string)
992 sbc2buf(myself, v1->val[i1].value,
993 v1->val[i1].length,
994 &b);
995 else
996 bc2buf(myself, v1->val[i1].value,
997 v1->val[i1].length,
998 &b);
999 if (v2->type == vt_string)
1000 sbc2buf(myself, v2->val[i2].value,
1001 v2->val[i2].length,
1002 &b);
1003 else
1004 bc2buf(myself, v2->val[i2].value,
1005 v2->val[i2].length,
1006 &b);
1007 }
1008 v->val[n].value = b.buf;
1009 v->val[n].length = b.len;
1010 n++;
1011 b.buf = 0;
1012 b.len = 0;
1013 }
1014 } else { /* v1->repeat && v2->repeat */
1015 for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
1016 for (i2 = 0; i2 < v2->numVals; i2++) {
1017 if (v1->type == vt_string)
1018 sbc2buf(myself, v1->val[i1].value,
1019 v1->val[i1].length,
1020 &b);
1021 else
1022 bc2buf(myself, v1->val[i1].value,
1023 v1->val[i1].length,
1024 &b);
1025 if (v2->type == vt_string)
1026 sbc2buf(myself, v2->val[i2].value,
1027 v2->val[i2].length,
1028 &b);
1029 else
1030 bc2buf(myself, v2->val[i2].value,
1031 v2->val[i2].length,
1032 &b);
1033 }
1034 }
1035 v->val[n].value = b.buf;
1036 v->val[n].length = b.len;
1037 n++;
1038 b.buf = 0;
1039 b.len = 0;
1040 }
1041
1042 #ifdef NISDB_LDAP_DEBUG
1043 /* Sanity check */
1044 if (n != nv)
1045 abort();
1046 #endif /* NISD__LDAP_DEBUG */
1047
1048 v->type = (v1->type == vt_string) ?
1049 ((v2->type == vt_string) ?
1050 vt_string : vt_ber) : vt_ber;
1051 v->repeat = 0;
1052 v->numVals = n;
1053
1054 return (v);
1055 }
1056
1057 __nis_value_t *
getMappingFormatArray(__nis_mapping_format_t * a,__nis_rule_value_t * rv,__nis_format_arg_t at,int numArgs,void * arg)1058 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv,
1059 __nis_format_arg_t at, int numArgs, void *arg) {
1060 int i, ia = 0;
1061 __nis_value_t *val, *v = 0;
1062 bool_t moreFormat = (a != 0);
1063 bool_t moreArgs = (numArgs > 0);
1064
1065 while (moreFormat && (arg == 0 || ia < numArgs)) {
1066 for (i = 0; moreFormat; i++) {
1067 moreFormat = (a[i].type != mmt_end);
1068 if (at == fa_item) {
1069 __nis_mapping_item_t *item = arg;
1070 val = getMappingFormat(&a[i], rv, at,
1071 ((item != 0) ? &item[ia] : 0), &ia);
1072 } else {
1073 __nis_value_t **ival = arg;
1074 val = getMappingFormat(&a[i], rv, at,
1075 ((ival != 0) ? ival[ia] : 0), &ia);
1076 }
1077 if (val != 0) {
1078 __nis_value_t *new = explodeValues(v, val);
1079
1080 freeValue(v, 1);
1081 freeValue(val, 1);
1082 if (new == 0)
1083 return (0);
1084
1085 v = new;
1086 } else {
1087 freeValue(v, 1);
1088 return (0);
1089 }
1090 /*
1091 * If we run out of arguments, but still have format
1092 * remaining, repeat the last argument. Keep track of
1093 * the fact that we've really consumed all arguments.
1094 */
1095 if (moreFormat && ia >= numArgs) {
1096 ia = (numArgs > 0) ? numArgs - 1 : 0;
1097 moreArgs = FALSE;
1098 }
1099 }
1100 /*
1101 * We've run out of format, so if we still have arguments
1102 * left, start over on the format.
1103 */
1104 if (ia < numArgs && moreArgs) {
1105 /*
1106 * However, if we didn't consume any arguments going
1107 * through the format once, abort to avoid an infinite
1108 * loop.
1109 */
1110 if (numArgs > 0 && ia <= 0) {
1111 freeValue(v, 1);
1112 return (0);
1113 }
1114 moreFormat = 1;
1115 }
1116 }
1117
1118 return (v);
1119 }
1120
1121 /*
1122 * Returns a string representation (such as "[name=foo, value=bar]")
1123 * of a nis_index_t.
1124 */
1125 char *
getIndex(__nis_index_t * i,int * len)1126 getIndex(__nis_index_t *i, int *len) {
1127 int n;
1128 __nis_buffer_t b = {0, 0};
1129 char *myself = "getIndex";
1130
1131 if (i == 0)
1132 return (0);
1133
1134 if (i->numIndexes > 0) {
1135 bp2buf(myself, &b, "[");
1136 for (n = 0; n < i->numIndexes; n++) {
1137 __nis_value_t *val;
1138 int j;
1139
1140 val = getMappingFormatArray(i->value[n],
1141 0, fa_any, 0, 0);
1142 if (n > 0)
1143 bp2buf(myself, &b, ", ");
1144 bp2buf(myself, &b, "%s=", i->name[n]);
1145 if (val != 0) {
1146 for (j = 0; j < val->numVals; j++) {
1147 bc2buf(myself, val->val[j].value,
1148 val->val[j].length, &b);
1149 }
1150 } else {
1151 bp2buf(myself, &b, "<no-vals>");
1152 }
1153 freeValue(val, 1);
1154 }
1155 bp2buf(myself, &b, "]");
1156 }
1157 if (len != 0)
1158 *len = b.len;
1159 return (b.buf);
1160 }
1161
1162 char *
getObjSpec(__nis_obj_spec_t * o,int * len)1163 getObjSpec(__nis_obj_spec_t *o, int *len) {
1164 __nis_buffer_t b = {0, 0};
1165 char *myself = "getObjSpec";
1166
1167 if (o == 0)
1168 return (0);
1169
1170 b.buf = getIndex(&o->index, &b.len);
1171 sbc2buf(myself, o->name, slen(o->name), &b);
1172 if (len != 0)
1173 *len = b.len;
1174 return (b.buf);
1175 }
1176
1177 /*
1178 * Returns a string representation of the LDAP scope. Note that the
1179 * returned value is a static entity, and must be copied by the
1180 * caller (but, obviously, must not be freed).
1181 */
1182 char *
getScope(int scope)1183 getScope(int scope) {
1184 switch (scope) {
1185 case LDAP_SCOPE_BASE:
1186 return ("base");
1187 case LDAP_SCOPE_ONELEVEL:
1188 return ("one");
1189 case LDAP_SCOPE_SUBTREE:
1190 return ("sub");
1191 default:
1192 return ("one");
1193 }
1194 }
1195
1196 /*
1197 * Return a string representation of an LDAP search triple (such as
1198 * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1199 */
1200 char *
getSearchTriple(__nis_search_triple_t * s,int * len)1201 getSearchTriple(__nis_search_triple_t *s, int *len) {
1202 __nis_buffer_t b = {0, 0};
1203 char *a;
1204 int l;
1205 char *myself = "getSearchTriple";
1206
1207 /* If the scope is LDAP_SCOPE_UNKNOWN, the search triple is unused */
1208 if (s == 0 || s->scope == LDAP_SCOPE_UNKNOWN) {
1209 if (len != 0)
1210 *len = 0;
1211 return (0);
1212 }
1213
1214 if (s->base != 0)
1215 sbc2buf(myself, s->base, slen(s->base), &b);
1216 if (!(s->scope == LDAP_SCOPE_ONELEVEL &&
1217 (s->base == 0 || s->base[0] == '\0'))) {
1218 bp2buf(myself, &b, "?%s?", getScope(s->scope));
1219 }
1220 if ((l = slen(s->attrs)) > 0) {
1221 /*
1222 * Remove white space from the filter/attribute list.
1223 * The parser usually keeps any white space from the
1224 * config file (or LDAP/command line), but we don't
1225 * want it.
1226 */
1227 a = am(myself, l+1);
1228 if (a != 0) {
1229 int i, la;
1230
1231 for (i = 0, la = 0; i < l; i++) {
1232 if (s->attrs[i] != ' ' &&
1233 s->attrs[i] != '\t')
1234 a[la++] = s->attrs[i];
1235 }
1236 sbc2buf(myself, a, la, &b);
1237 sfree(a);
1238 } else {
1239 sbc2buf(myself, s->attrs, slen(s->attrs), &b);
1240 }
1241 }
1242
1243 if (len != 0)
1244 *len = b.len;
1245 return (b.buf);
1246 }
1247
1248 __nis_value_t *
getMappingItem(__nis_mapping_item_t * i,__nis_mapping_item_type_t native,__nis_rule_value_t * rv,char * berstring,int * np_ldap_stat)1249 getMappingItem(__nis_mapping_item_t *i, __nis_mapping_item_type_t native,
1250 __nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
1251 char *myself = "getMappingItem";
1252 __nis_value_t *val = 0;
1253 __nis_buffer_t b = {0, 0};
1254 int len = 0;
1255 char *buf;
1256
1257 if (i == 0)
1258 return (0);
1259
1260 if (rv != 0)
1261 return (getMappingItemVal(i, native, rv, berstring,
1262 np_ldap_stat));
1263
1264 val = am(myself, sizeof (*val));
1265 if (val == 0)
1266 return (0);
1267
1268 switch (i->type) {
1269 case mit_nisplus:
1270 if (native != mit_nisplus)
1271 bp2buf(myself, &b, "nis+:");
1272 bp2buf(myself, &b, "%s", NIL(i->name));
1273 buf = getObjSpec(&i->searchSpec.obj, &len);
1274 if (buf != 0 && len > 0) {
1275 bc2buf(myself, ":", 1, &b);
1276 sbc2buf(myself, buf, len, &b);
1277 }
1278 sfree(buf);
1279 val->type = vt_string;
1280 val->repeat = i->repeat;
1281 val->numVals = 1;
1282 val->val = am(myself, sizeof (val->val[0]));
1283 if (val->val == 0) {
1284 sfree(b.buf);
1285 free(val);
1286 return (0);
1287 }
1288 val->val[0].value = b.buf;
1289 val->val[0].length = b.len;
1290 break;
1291 case mit_ldap:
1292 if (native != mit_ldap)
1293 bp2buf(myself, &b, "ldap:");
1294 bp2buf(myself, &b, "%s", NIL(i->name));
1295 buf = getSearchTriple(&i->searchSpec.triple, &len);
1296 if (buf != 0 && len > 0) {
1297 bc2buf(myself, ":", 1, &b);
1298 sbc2buf(myself, buf, len, &b);
1299 }
1300 sfree(buf);
1301 val->type = vt_string;
1302 val->repeat = i->repeat;
1303 val->numVals = 1;
1304 val->val = am(myself, sizeof (val->val[0]));
1305 if (val->val == 0) {
1306 sfree(b.buf);
1307 free(val);
1308 return (0);
1309 }
1310 val->val[0].value = b.buf;
1311 val->val[0].length = b.len;
1312 break;
1313 default:
1314 p2buf(myself, "<unknown>:");
1315 p2buf(myself, "%s", NIL(i->name));
1316 break;
1317 }
1318
1319 return (val);
1320 }
1321
1322 void
copyObjSpec(__nis_obj_spec_t * old,__nis_obj_spec_t * new,int * err)1323 copyObjSpec(__nis_obj_spec_t *old, __nis_obj_spec_t *new, int *err) {
1324 char *myself = "copyObjSpec";
1325
1326 if (old == 0 || new == 0) {
1327 *err = EINVAL;
1328 return;
1329 }
1330
1331 if (new->index.name == 0) {
1332 new->index.name = am(myself, old->index.numIndexes *
1333 sizeof (new->index.name[0]));
1334 if (old->index.numIndexes > 0 && new->index.name == 0) {
1335 *err = ENOMEM;
1336 return;
1337 }
1338 new->index.value = am(myself, old->index.numIndexes *
1339 sizeof (new->index.value[0]));
1340 if (old->index.numIndexes > 0 && new->index.value == 0) {
1341 *err = ENOMEM;
1342 return;
1343 }
1344 }
1345 new->name = sdup(myself, T, old->name);
1346 if (new->name == 0 && old->name != 0) {
1347 *err = ENOMEM;
1348 return;
1349 }
1350 copyIndex(&old->index, &new->index, err);
1351 }
1352
1353 __nis_obj_spec_t *
cloneObjSpec(__nis_obj_spec_t * old)1354 cloneObjSpec(__nis_obj_spec_t *old) {
1355 char *myself = "cloneObjSpec";
1356 int err = 0;
1357 __nis_obj_spec_t *new = am(myself, sizeof (*new));
1358
1359 if (new != 0) {
1360 copyObjSpec(old, new, &err);
1361 if (err != 0) {
1362 freeObjSpec(new, 1);
1363 new = 0;
1364 }
1365 }
1366
1367 return (new);
1368 }
1369
1370 void
freeObjSpec(__nis_obj_spec_t * old,bool_t doFree)1371 freeObjSpec(__nis_obj_spec_t *old, bool_t doFree) {
1372
1373 if (old == 0)
1374 return;
1375
1376 sfree(old->name);
1377 freeIndex(&old->index, FALSE);
1378 if (doFree)
1379 free(old);
1380 }
1381
1382 void
copySearchTriple(__nis_search_triple_t * old,__nis_search_triple_t * new,int * err)1383 copySearchTriple(__nis_search_triple_t *old, __nis_search_triple_t *new,
1384 int *err) {
1385 char *myself = "copySearchTriple";
1386
1387 *err = 0;
1388
1389 if (old == 0 || new == 0) {
1390 *err = EINVAL;
1391 return;
1392 }
1393
1394 if (old->base != NULL)
1395 new->base = sdup(myself, T, old->base);
1396 else
1397 new->base = NULL;
1398 if (old->attrs != NULL)
1399 new->attrs = sdup(myself, T, old->attrs);
1400 else
1401 new->attrs = NULL;
1402 if ((new->base == 0 && old->base != 0) ||
1403 (new->attrs == 0 && old->attrs != 0)) {
1404 sfree(new->base);
1405 new->base = 0;
1406 sfree(new->attrs);
1407 new->attrs = 0;
1408 *err = ENOMEM;
1409 return;
1410 }
1411 new->scope = old->scope;
1412 /*
1413 * XXX Really should have a cloneMappingElement() function.
1414 * However, since whatever the 'element' field points to
1415 * is allocated at parse time, and never is freed or modified,
1416 * it's sufficient to copy the pointer value.
1417 */
1418 new->element = old->element;
1419 }
1420
1421 __nis_search_triple_t *
cloneSearchTriple(__nis_search_triple_t * old)1422 cloneSearchTriple(__nis_search_triple_t *old) {
1423 char *myself = "cloneSearchTriple";
1424 int err = 0;
1425 __nis_search_triple_t *new = am(myself, sizeof (*new));
1426
1427 if (new != 0) {
1428 copySearchTriple(old, new, &err);
1429 if (err != 0) {
1430 freeSearchTriple(new, 1);
1431 new = 0;
1432 }
1433 }
1434
1435 return (new);
1436 }
1437
1438 void
freeSearchTriple(__nis_search_triple_t * old,bool_t doFree)1439 freeSearchTriple(__nis_search_triple_t *old, bool_t doFree) {
1440
1441 if (old == 0)
1442 return;
1443
1444 sfree(old->base);
1445 sfree(old->attrs);
1446 /*
1447 * Since we only copied the element pointer when this structure
1448 * was created, we don't free old->element.
1449 */
1450 if (doFree)
1451 free(old);
1452 }
1453
1454 void
copyTripleOrObj(__nis_mapping_item_type_t type,__nis_triple_or_obj_t * old,__nis_triple_or_obj_t * new,int * err)1455 copyTripleOrObj(__nis_mapping_item_type_t type,
1456 __nis_triple_or_obj_t *old, __nis_triple_or_obj_t *new,
1457 int *err) {
1458
1459 *err = 0;
1460
1461 if (old == 0 || new == 0) {
1462 *err = EINVAL;
1463 return;
1464 }
1465
1466 if (type == mit_nisplus) {
1467 copyObjSpec(&old->obj, &new->obj, err);
1468 } else if (type == mit_ldap) {
1469 copySearchTriple(&old->triple, &new->triple, err);
1470 }
1471 }
1472
1473 __nis_triple_or_obj_t *
cloneTripleOrObj(__nis_mapping_item_type_t type,__nis_triple_or_obj_t * old)1474 cloneTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old) {
1475 char *myself = "cloneTripleOrObj";
1476 int err = 0;
1477 __nis_triple_or_obj_t *new = am(myself, sizeof (*new));
1478
1479 if (new != 0) {
1480 copyTripleOrObj(type, old, new, &err);
1481 if (err != 0) {
1482 freeTripleOrObj(type, new, 1);
1483 new = 0;
1484 }
1485 }
1486
1487 return (new);
1488 }
1489
1490 void
freeTripleOrObj(__nis_mapping_item_type_t type,__nis_triple_or_obj_t * old,bool_t doFree)1491 freeTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old,
1492 bool_t doFree) {
1493
1494 if (old == 0)
1495 return;
1496
1497 if (type == mit_nisplus)
1498 freeObjSpec(&old->obj, doFree);
1499 else if (type == mit_ldap)
1500 freeSearchTriple(&old->triple, doFree);
1501
1502 if (doFree)
1503 free(old);
1504 }
1505
1506 void
copyItem(__nis_mapping_item_t * old,__nis_mapping_item_t * new,int * err)1507 copyItem(__nis_mapping_item_t *old, __nis_mapping_item_t *new, int *err) {
1508
1509 *err = 0;
1510
1511 if (old == 0 || new == 0) {
1512 *err = EINVAL;
1513 return;
1514 }
1515
1516 new->type = old->type;
1517 new->repeat = old->repeat;
1518 if (old->name != 0) {
1519 new->name = strdup(old->name);
1520 if (new->name == 0) {
1521 *err = ENOMEM;
1522 return;
1523 }
1524 } else {
1525 new->name = 0;
1526 }
1527 if (old->type == mit_nisplus || old->type == mit_ldap)
1528 copyTripleOrObj(old->type, &old->searchSpec, &new->searchSpec,
1529 err);
1530 else
1531 memset(&new->searchSpec, 0, sizeof (new->searchSpec));
1532 }
1533
1534 __nis_mapping_item_t *
cloneItem(__nis_mapping_item_t * old)1535 cloneItem(__nis_mapping_item_t *old) {
1536 __nis_mapping_item_t *new;
1537 int err = 0;
1538 char *myself = "cloneItem";
1539
1540 if (old == 0)
1541 return (0);
1542
1543 new = am(myself, sizeof (*new));
1544 if (new == 0)
1545 return (0);
1546
1547 copyItem(old, new, &err);
1548 if (err != 0) {
1549 freeMappingItem(new, 1);
1550 return (0);
1551 }
1552
1553 return (new);
1554 }
1555
1556 void
freeMappingItem(__nis_mapping_item_t * item,int numItems)1557 freeMappingItem(__nis_mapping_item_t *item, int numItems) {
1558 int i;
1559
1560 if (item == 0)
1561 return;
1562
1563 for (i = 0; i < numItems; i++) {
1564 sfree(item[i].name);
1565 freeTripleOrObj(item[i].type, &item[i].searchSpec, FALSE);
1566 }
1567 sfree(item);
1568 }
1569
1570 __nis_mapping_item_t *
concatenateMappingItem(__nis_mapping_item_t * old,int numItems,__nis_mapping_item_t * cat)1571 concatenateMappingItem(__nis_mapping_item_t *old, int numItems,
1572 __nis_mapping_item_t *cat) {
1573 __nis_mapping_item_t *new;
1574 int i, err = 0;
1575 char *myself = "concatenateMappingItem";
1576
1577 if (old == 0 || numItems < 1)
1578 return (cloneItem(cat));
1579
1580 new = am(myself, (numItems + 1) * sizeof (*new));
1581 if (new == 0)
1582 return (0);
1583
1584 for (i = 0; i < numItems; i++) {
1585 copyItem(&old[i], &new[i], &err);
1586 if (err != 0) {
1587 freeMappingItem(new, i);
1588 return (0);
1589 }
1590 }
1591 copyItem(cat, &new[numItems], &err);
1592 if (err != 0) {
1593 freeMappingItem(new, numItems);
1594 new = 0;
1595 }
1596
1597 return (new);
1598 }
1599
1600 __nis_value_t *
concatenateValues(__nis_value_t * v1,__nis_value_t * v2)1601 concatenateValues(__nis_value_t *v1, __nis_value_t *v2) {
1602 int i, n, a;
1603 __nis_value_t *v;
1604 char *myself = "concatenateValues";
1605
1606 if (v1 == 0 || v1->numVals <= 0)
1607 return (cloneValue(v2, 1));
1608 if (v2 == 0 || v2->numVals <= 0)
1609 return (cloneValue(v1, 1));
1610
1611 if (v1->type != v2->type)
1612 return (0);
1613
1614 n = v1->numVals + v2->numVals;
1615 v = am(myself, sizeof (*v));
1616 if (v == 0)
1617 return (0);
1618 v->val = am(myself, n * sizeof (v->val[0]));
1619 if (v->val == 0) {
1620 free(v);
1621 return (0);
1622 }
1623 v->type = v1->type;
1624 v->numVals = 0;
1625
1626 for (a = 0; a < 2; a++) {
1627 __nis_single_value_t *val = (a == 0) ? v1->val : v2->val;
1628 int numv = (a == 0) ? v1->numVals :
1629 v2->numVals;
1630 for (i = 0; i < numv; i++) {
1631 int clen, alen = val[i].length;
1632
1633 clen = alen;
1634
1635 /*
1636 * Make sure there's a NUL at the end of a string,
1637 * but avoid adding to the allocated length if there's
1638 * already a NUL at the end.
1639 */
1640 if (alen > 0 && v->type == vt_string &&
1641 ((char *)val[i].value)[alen-1] != '\0')
1642 alen += 1;
1643 v->val[v->numVals].value = am(myself, alen);
1644 if (v->val[v->numVals].value == 0) {
1645 freeValue(v, 1);
1646 return (0);
1647 }
1648 memcpy(v->val[v->numVals].value, val[i].value, clen);
1649 v->val[v->numVals].length = val[i].length;
1650 v->numVals++;
1651 }
1652 }
1653
1654 return (v);
1655 }
1656
1657 __nis_value_t *
splitMappingItem(__nis_mapping_item_t * item,char delim,__nis_rule_value_t * rv)1658 splitMappingItem(__nis_mapping_item_t *item, char delim,
1659 __nis_rule_value_t *rv) {
1660 __nis_value_t *val = getMappingItem(item, mit_any,
1661 rv, 0, NULL);
1662 __nis_single_value_t *nval;
1663 int i, n, nv;
1664
1665 if (val == 0)
1666 return (0);
1667 else if (delim == 0 || val->val == 0 || val->numVals <= 0 ||
1668 val->type != vt_string) {
1669 freeValue(val, 1);
1670 return (0);
1671 }
1672
1673 nval = val->val;
1674 nv = val->numVals;
1675 val->repeat = FALSE;
1676 val->val = 0;
1677 val->numVals = 0;
1678
1679 /* In N2L, space and tab delimiters are treated the same */
1680 if (yp2ldap && delim == '\t')
1681 delim = ' ';
1682
1683 /* If the item has multiple values, we split each one independently */
1684 for (i = 0; i < nv; i++) {
1685 char *str;
1686 int s, e;
1687 char *newstr;
1688 __nis_single_value_t *newval;
1689
1690 if (yp2ldap && delim == ' ')
1691 nval[i].value = trimWhiteSpaces(nval[i].value,
1692 &nval[i].length, 1);
1693
1694 str = nval[i].value;
1695
1696 if (nval[i].value == 0)
1697 continue;
1698
1699 for (s = 0; s < nval[i].length; s = e+1) {
1700 /* Find the next delimiter, or end-of-string */
1701 for (e = s; str[e] != '\0' && str[e] != delim; e++);
1702 /*
1703 * 'str[e]' is either a delimiter, or the concluding
1704 * NUL. Make sure it's NUL.
1705 */
1706 str[e] = '\0';
1707 /* Add to val->val */
1708 newstr = strdup(&str[s]);
1709 newval = realloc(val->val,
1710 (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);
1718 }
1719 free(nval);
1720 sfree(newstr);
1721 return (0);
1722 }
1723 val->val[val->numVals].value = newstr;
1724 val->val[val->numVals].length = strlen(newstr) + 1;
1725 val->numVals++;
1726 }
1727 free(nval[i].value);
1728 nval[i].value = 0;
1729 }
1730 /* Already freed the nval[i].value's as we traversed nval */
1731 free(nval);
1732
1733 return (val);
1734 }
1735
1736 /*
1737 * Match the format spec 'f[curf]' to the input value string 'str'.
1738 *
1739 * If successful, returns the updated position in the value string 'str'.
1740 * Otherwise, NULL is returned.
1741 *
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
1752 */
1753 char *
scanMappingFormat(__nis_mapping_format_t * f,int curf,int nf,char * str,char ** val,char ** fmtstart,char * sepset)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 = "";
1764
1765
1766 if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1767 return (0);
1768
1769 /*
1770 * If separator list is NULL (which will be the case for
1771 * nis+2ldap), then simply use empty string
1772 */
1773 if (sepset == 0)
1774 sepset = emptystr;
1775
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);
1782 }
1783
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);
1789 }
1790
1791 /*
1792 * If here, it means it's an IP address (N2L case)
1793 * So continue processing as if it was mmt_item
1794 */
1795 ipaddr = TRUE;
1796
1797 case mmt_item:
1798 /*
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.
1804 *
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.
1809 */
1810 tmpstr = str;
1811 while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1812 &start, sepset)) != 0) {
1813 char *tmp = next;
1814 int cf;
1815
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;
1821 }
1822 if (tmp == 0) {
1823 tmpstr = next;
1824 } else if (strchr(sepset, *tmp) != 0) {
1825 break;
1826 } else {
1827 return (0);
1828 }
1829
1830 }
1831 if (next == 0 || start == 0)
1832 return (0);
1833
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';
1841
1842 if (ipaddr == TRUE) {
1843 /*
1844 * In N2L, we need to check if *val is truly an
1845 * IP address
1846 */
1847 af = checkIPaddress(*val, len, &tmpstr);
1848
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);
1873 }
1874
1875 sfree(*val);
1876 *val = tmpstr;
1877 }
1878 }
1879
1880 if (fmtstart != 0)
1881 *fmtstart = str;
1882
1883 return (start);
1884
1885 case mmt_string:
1886 if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1887 /*
1888 * Count this as a successful match of an empty
1889 * string.
1890 */
1891 if (fmtstart != 0)
1892 *fmtstart = str;
1893 return (str);
1894 }
1895
1896 /*
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'.
1901 */
1902 if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1903 mstr = spacestr;
1904 skipspaces = 1;
1905 next = str + strcspn(str, " \t");
1906 /*
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".
1910 */
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);
1917 }
1918
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));
1927
1928 /* Skip whitespaces for N2L */
1929 if (skipspaces == 1)
1930 for (; *str == ' ' || *str == '\t'; str++);
1931
1932 return (str);
1933
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;
1941
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;
1947 }
1948 }
1949 if (match)
1950 break;
1951 }
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;
1963 }
1964 }
1965 if (!match)
1966 return (0);
1967 }
1968 /* Step over the matched character */
1969 str++;
1970 return (str);
1971
1972 case mmt_any:
1973 /*
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.
1978 */
1979 while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1980 &start, sepset)) != 0) {
1981 char *tmp = next;
1982 int cf;
1983
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;
1989 }
1990 if (tmp == 0) {
1991 str = next;
1992 } else if (*tmp == '\0') {
1993 break;
1994 } else {
1995 return (0);
1996 }
1997 }
1998 if (next == 0 || start == 0)
1999 return (0);
2000
2001 if (fmtstart != 0)
2002 *fmtstart = str;
2003
2004 return (start);
2005
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);
2014 }
2015 }
2016 return (str);
2017
2018 case mmt_begin:
2019 if (fmtstart != 0)
2020 *fmtstart = str;
2021 return (str);
2022
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);
2029 }
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);
2034
2035 default:
2036 break;
2037 }
2038
2039 return (0);
2040 }
2041
2042 /*
2043 * Verify that the string 'str' matches the mapping format array 'f'.
2044 * Returns 1 in case of a match, 0 otherwise.
2045 */
2046 int
verifyMappingMatch(__nis_mapping_format_t * f,char * str)2047 verifyMappingMatch(__nis_mapping_format_t *f, char *str) {
2048 int n, nf;
2049 __nis_mapping_format_t *ftmp;
2050
2051 /* Count the number of format elements in the format */
2052 for (nf = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2053 nf++;
2054 }
2055 /* Count the mmt_end as well */
2056 nf++;
2057
2058 for (n = 0; n < nf; n++) {
2059 str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2060 if (str == 0)
2061 break;
2062 }
2063
2064 return ((str != 0) ? 1 : 0);
2065 }
2066
2067 /*
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'.
2072 *
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.
2078 *
2079 * If there is more than one input value (inVal->numVals > 1), the
2080 * output array elements will also be multi-valued.
2081 *
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
2088 */
2089 __nis_value_t **
matchMappingItem(__nis_mapping_format_t * f,__nis_value_t * inVal,int * numVals,char * sepset,char ** outstr)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, nv = 0;
2094 char *str, *valstr;
2095 __nis_mapping_format_t *ftmp;
2096 char *myself = "matchMappingItem";
2097
2098 if (f == 0 ||
2099 inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2100 return (0);
2101
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++;
2105
2106 /*
2107 * Count mmt_item and mmt_berstring (used by N2L to
2108 * represent address %a)
2109 */
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++;
2115 }
2116 /* Count the mmt_end as well */
2117 nf++;
2118
2119 /*
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.
2123 */
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);
2132 }
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);
2139 }
2140
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;
2149
2150 for (j = 0; j < n; j++)
2151 freeValue(v[j], 1);
2152 sfree(v);
2153 return (0);
2154 }
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;
2160
2161 for (j = 0; j < n; j++)
2162 freeValue(v[j], 1);
2163 sfree(v);
2164 return (0);
2165 }
2166 for (i = 0; i < inVal->numVals; i++) {
2167 v[n]->val[i].length = 0;
2168 v[n]->val[i].value = 0;
2169 }
2170 }
2171
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);
2192 }
2193 }
2194 if (str == 0) {
2195 for (n = 0; n < numItems; n++)
2196 freeValue(v[n], 1);
2197 sfree(v);
2198 return (0);
2199 }
2200 }
2201
2202 if (numVals != 0)
2203 *numVals = numItems;
2204
2205 /*
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
2209 */
2210 if (outstr != 0)
2211 *outstr = str;
2212
2213 return (v);
2214 }
2215
2216 /*
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".
2221 */
2222 __nis_value_t *
extractMappingItem(__nis_mapping_item_t * item,__nis_mapping_format_t * f,__nis_rule_value_t * rv,int * stat)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;
2230
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);
2237 }
2238
2239 /* Sanity check the format; it must have one and only one mmt_item */
2240 {
2241 int numitem;
2242
2243 for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2244 ftmp++) {
2245 nf++;
2246 if (ftmp->type == mmt_item)
2247 numitem++;
2248 }
2249 /* Count the mmt_end as well */
2250 nf++;
2251 if (numitem != 1) {
2252 freeValue(val, 1);
2253 return (0);
2254 }
2255 }
2256
2257 nval = val->val;
2258 nv = val->numVals;
2259 val->repeat = FALSE;
2260 val->val = 0;
2261 val->numVals = 0;
2262
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;
2268
2269 if (nval[i].value == 0)
2270 continue;
2271
2272 /*
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.
2277 */
2278 for (n = 0; n < nf; n++) {
2279 str = scanMappingFormat(f, n, nf, str, &newstr, 0, 0);
2280 if (str == 0)
2281 break;
2282 }
2283
2284 /*
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.
2289 */
2290 if (str == 0 || *str != '\0' || newstr == 0 ||
2291 (newval = realloc(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);
2297 }
2298 free(nval);
2299 sfree(newstr);
2300 return (0);
2301 }
2302
2303 val->val = newval;
2304 val->val[val->numVals].value = newstr;
2305 val->val[val->numVals].length = strlen(newstr) + 1;
2306 val->numVals++;
2307
2308 free(nval[i].value);
2309 nval[i].value = 0;
2310 }
2311 free(nval);
2312
2313 return (val);
2314 }
2315
2316 /*
2317 * For each value in 'val', remove the last character, provided that
2318 * it matches 'elide'.
2319 */
2320 void
stringElide(__nis_value_t * val,char elide)2321 stringElide(__nis_value_t *val, char elide) {
2322
2323 if (val != 0 && val->type == vt_string) {
2324 int i;
2325
2326 for (i = 0; i < val->numVals; i++) {
2327 int end = val->val[i].length;
2328 char *str = val->val[i].value;
2329
2330 if (str == 0 || end <= 0)
2331 continue;
2332
2333 /*
2334 * If the NUL was counted in the length, step back
2335 * over it.
2336 */
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--;
2342 }
2343 }
2344 }
2345 }
2346
2347 /*
2348 * Obtain the value for the mapping sub-element 'e', given the input
2349 * rule-value 'rv'.
2350 */
2351 __nis_value_t *
getMappingSubElement(__nis_mapping_sub_element_t * e,__nis_rule_value_t * rv,int * np_ldap_stat)2352 getMappingSubElement(__nis_mapping_sub_element_t *e,
2353 __nis_rule_value_t *rv, int *np_ldap_stat) {
2354 __nis_value_t *val;
2355
2356 if (e == 0)
2357 return (0);
2358
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;
2386 }
2387
2388 return (val);
2389 }
2390
2391 /*
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").
2397 */
2398 __nis_value_t *
getMappingElement(__nis_mapping_element_t * e,__nis_mapping_item_type_t native,__nis_rule_value_t * rv,int * stat)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";
2405
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;
2421 }
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]);
2427 }
2428 /*
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.
2435 */
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++;
2441 }
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);
2452 }
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:
2464 /*
2465 * A match doesn't produce an assignable value per se,
2466 * so we shouldn't get one here.
2467 */
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;
2478 }
2479
2480 return (val);
2481 }
2482