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 2015 Gary Mills
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <strings.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <rpcsvc/nis.h>
33 #include <rpc/xdr.h>
34
35 #include "ldap_util.h"
36 #include "ldap_attr.h"
37 #include "ldap_ruleval.h"
38 #include "ldap_op.h"
39 #include "ldap_map.h"
40 #include "ldap_glob.h"
41 #include "ldap_xdr.h"
42 #include "ldap_val.h"
43
44 /* From yptol/dit_access_utils.h */
45 #define N2LKEY "rf_key"
46 #define N2LIPKEY "rf_ipkey"
47
48 __nis_hash_table_mt ldapMappingList = NIS_HASH_TABLE_MT_INIT;
49 extern int yp2ldap;
50
51
52 int
setColumnNames(__nis_table_mapping_t * t)53 setColumnNames(__nis_table_mapping_t *t) {
54 int i, j, nic, noc;
55 char **col;
56 char *myself = "setColumnNames";
57
58 if (t == 0)
59 return (0);
60
61 col = t->column;
62 nic = (col != 0) ? t->numColumns : -1;
63
64 t->objType = NIS_BOGUS_OBJ;
65 t->obj = 0;
66
67 /*
68 * If it's a table object, but there are no translation rules,
69 * this mapping is for the table object itself. In that case,
70 * we throw away the column names (if any).
71 */
72 if (t->objType == NIS_TABLE_OBJ && t->numRulesFromLDAP == 0 &&
73 t->numRulesToLDAP == 0) {
74 for (i = 0; i < t->numColumns; i++)
75 sfree(t->column[i]);
76 sfree(t->column);
77 t->column = 0;
78 t->numColumns = 0;
79 noc = 0;
80 }
81
82 /*
83 * Verify that all column names found by the parser
84 * are present in the actual column list.
85 */
86 if (verbose) {
87 for (i = 0, noc = 0; i < nic; i++) {
88 int found = 0;
89
90 if (col[i] == 0)
91 continue;
92 /* Skip the 'zo_*' special column names */
93 if (isObjAttrString(col[i]))
94 continue;
95 for (j = 0; j < t->numColumns; j++) {
96 if (strcmp(col[i], t->column[j]) == 0) {
97 noc++;
98 found = 1;
99 break;
100 }
101 }
102 if (!found) {
103 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
104 "%s: No column \"%s\" in \"%s\"",
105 myself, NIL(col[i]), NIL(t->objName));
106 }
107 }
108 }
109
110 /* Remove any setup by the parser */
111 for (i = 0; i < nic; i++) {
112 sfree(col[i]);
113 }
114 sfree(col);
115
116 return (0);
117 }
118
119 void
freeSingleObjAttr(__nis_obj_attr_t * attr)120 freeSingleObjAttr(__nis_obj_attr_t *attr) {
121 if (attr == 0)
122 return;
123
124 sfree(attr->zo_owner);
125 sfree(attr->zo_group);
126 sfree(attr->zo_domain);
127 sfree(attr);
128 }
129
130 void
freeObjAttr(__nis_obj_attr_t ** attr,int numAttr)131 freeObjAttr(__nis_obj_attr_t **attr, int numAttr) {
132 int i;
133
134 if (attr == 0)
135 return;
136
137 for (i = 0; i < numAttr; i++) {
138 freeSingleObjAttr(attr[i]);
139 }
140
141 sfree(attr);
142 }
143
144 __nis_obj_attr_t *
cloneObjAttr(__nis_obj_attr_t * old)145 cloneObjAttr(__nis_obj_attr_t *old) {
146 __nis_obj_attr_t *new;
147 char *myself = "cloneObjAttr";
148
149 if (old == 0)
150 return (0);
151
152 new = am(myself, sizeof (*new));
153 if (new == 0)
154 return (0);
155
156 new->zo_owner = sdup(myself, T, old->zo_owner);
157 if (new->zo_owner == 0 && old->zo_owner != 0)
158 goto cleanup;
159
160 new->zo_group = sdup(myself, T, old->zo_group);
161 if (new->zo_group == 0 && old->zo_group != 0)
162 goto cleanup;
163
164 new->zo_domain = sdup(myself, T, old->zo_domain);
165 if (new->zo_domain == 0 && old->zo_domain != 0)
166 goto cleanup;
167
168 new->zo_access = old->zo_access;
169 new->zo_ttl = old->zo_ttl;
170
171 return (new);
172
173 cleanup:
174 freeSingleObjAttr(new);
175
176 return (0);
177 }
178
179
180 /*
181 * Obtain NIS+ entries (in the form of db_query's) from the supplied table
182 * mapping and db_query.
183 *
184 * If 'qin' is NULL, enumeration is desired.
185 *
186 * On exit, '*numQueries' contains the number of (db_query *)'s in the
187 * return array, '*ldapStat' the LDAP operation status, and '*objAttr'
188 * a pointer to an array (of '*numQueries elements) of object attributes
189 * (zo_owner, etc.). If no object attributes were retrieved, '*objAttr'
190 * is NULL; any and all of the (*objAttr)[i]'s may be NULL.
191 */
192 db_query **
mapFromLDAP(__nis_table_mapping_t * t,db_query * qin,int * numQueries,char * dbId,int * ldapStat,__nis_obj_attr_t *** objAttr)193 mapFromLDAP(__nis_table_mapping_t *t, db_query *qin, int *numQueries,
194 char *dbId, int *ldapStat, __nis_obj_attr_t ***objAttr) {
195 __nis_table_mapping_t **tp;
196 db_query **q;
197 __nis_rule_value_t *rv;
198 __nis_ldap_search_t *ls;
199 int n, numVals, numMatches = 0;
200 int stat;
201 __nis_obj_attr_t **attr;
202 char *myself = "mapFromLDAP";
203
204 if (ldapStat == 0)
205 ldapStat = &stat;
206
207 if (t == 0 || numQueries == 0) {
208 *ldapStat = LDAP_PARAM_ERROR;
209 return (0);
210 }
211
212 /* Select the correct table mapping(s) */
213 tp = selectTableMapping(t, qin, 0, 0, dbId, &numMatches);
214 if (tp == 0 || numMatches <= 0) {
215 /*
216 * Not really an error; just no matching mapping
217 * for the query.
218 */
219 *ldapStat = LDAP_SUCCESS;
220 return (0);
221 }
222
223 q = 0;
224 attr = 0;
225
226 /* For each mapping */
227 for (numVals = 0, n = 0; n < numMatches; n++) {
228 db_query **qt;
229 int i, nqt = 0, filterOnQin, res = 0;
230
231 t = tp[n];
232
233 if (qin != 0) {
234 rv = buildNisPlusRuleValue(t, qin, 0);
235 if (rv != 0) {
236 /*
237 * Depending on the value of res, we shall
238 * proceed to next table mapping.
239 */
240 ls = createLdapRequest(t, rv, 0, 1, &res, NULL);
241 }
242 else
243 ls = 0;
244 } else {
245 /* Build enumeration request */
246 rv = 0;
247 ls = createLdapRequest(t, 0, 0, 1, NULL, NULL);
248 }
249
250 freeRuleValue(rv, 1);
251
252 if (ls == 0) {
253 /*
254 * if the res is NP_LDAP_RULES_NO_VALUE, that means we
255 * have enough NIS+ columns for the rules to produce
256 * values, but none of them did, so continue to the
257 * next table mapping. Otherwise do cleanup and return
258 * error.
259 */
260 if (res == NP_LDAP_RULES_NO_VALUE)
261 continue;
262 for (i = 0; i < numVals; i++)
263 freeQuery(q[i]);
264 sfree(q);
265 free(tp);
266 *ldapStat = LDAP_OPERATIONS_ERROR;
267 return (0);
268 }
269
270 /* Query LDAP */
271 nqt = (ls->isDN || qin != 0) ? 0 : -1;
272 rv = ldapSearch(ls, &nqt, 0, ldapStat);
273
274 /*
275 * If qin != 0, then we need to make sure that the
276 * LDAP search is filtered so that only entries that
277 * are compatible with 'qin' are retained. This will
278 * happen automatically if we do a DN search (in which
279 * case, no need to filter on 'qin').
280 */
281 if (ls->isDN || qin == 0)
282 filterOnQin = 0;
283 else
284 filterOnQin = 1;
285
286 freeLdapSearch(ls);
287
288 /* Convert rule-values to db_query's */
289 if (rv != 0 && nqt > 0) {
290 int nrv = nqt;
291 __nis_obj_attr_t **at = 0;
292
293 qt = ruleValue2Query(t, rv,
294 (filterOnQin) ? qin : 0, &at, &nqt);
295 freeRuleValue(rv, nrv);
296
297 if (qt != 0 && q == 0) {
298 q = qt;
299 attr = at;
300 numVals = nqt;
301 } else if (qt != 0) {
302 db_query **tmp;
303 __nis_obj_attr_t **atmp;
304
305 /* Extend the 'q' array */
306 tmp = realloc(q,
307 (numVals+nqt) * sizeof (q[0]));
308 /* ... and the 'attr' array */
309 atmp = realloc(attr,
310 (numVals+nqt) * sizeof (attr[0]));
311 if (tmp == 0 || atmp == 0) {
312 logmsg(MSG_NOMEM, LOG_ERR,
313 "%s: realloc(%d) => NULL",
314 myself,
315 (numVals+nqt) * sizeof (q[0]));
316 for (i = 0; i < numVals; i++)
317 freeQuery(q[i]);
318 for (i = 0; i < nqt; i++)
319 freeQuery(qt[i]);
320 sfree(tmp);
321 sfree(atmp);
322 sfree(q);
323 sfree(qt);
324 sfree(tp);
325 freeObjAttr(at, nqt);
326 freeObjAttr(attr, numVals);
327 *ldapStat = LDAP_NO_MEMORY;
328 return (0);
329 }
330 q = tmp;
331 attr = atmp;
332 /* Add the results for this 't' */
333 (void) memcpy(&q[numVals], qt,
334 nqt * sizeof (qt[0]));
335 (void) memcpy(&attr[numVals], at,
336 nqt * sizeof (at[0]));
337 numVals += nqt;
338
339 sfree(qt);
340 sfree(at);
341 }
342 }
343 }
344
345 *numQueries = numVals;
346 if (objAttr != 0)
347 *objAttr = attr;
348 else
349 freeObjAttr(attr, numVals);
350 sfree(tp);
351
352 return (q);
353 }
354
355 /*
356 * Add the object attributes (zo_owner, etc.) to the rule-value 'rv'.
357 * Returns a pointer to the (possibly newly allocated) rule-value,
358 * or NULL in case of failure. If not returning 'rvIn', the latter
359 * will have been freed.
360 */
361 __nis_rule_value_t *
addObjAttr2RuleValue(nis_object * obj,__nis_rule_value_t * rvIn)362 addObjAttr2RuleValue(nis_object *obj, __nis_rule_value_t *rvIn) {
363 __nis_rule_value_t *rv;
364 char abuf[2 * sizeof (obj->zo_access) + 1];
365 char tbuf[2 * sizeof (obj->zo_ttl) + 1];
366
367 if (obj == 0)
368 return (0);
369
370 if (rvIn != 0) {
371 rv = rvIn;
372 } else {
373 rv = initRuleValue(1, 0);
374 if (rv == 0)
375 return (0);
376 }
377
378 if (obj->zo_owner != 0) {
379 if (addSCol2RuleValue("zo_owner", obj->zo_owner, rv) != 0) {
380 freeRuleValue(rv, 1);
381 return (0);
382 }
383 }
384
385 if (obj->zo_group != 0) {
386 if (addSCol2RuleValue("zo_group", obj->zo_group, rv) != 0) {
387 freeRuleValue(rv, 1);
388 return (0);
389 }
390 }
391
392 if (obj->zo_domain != 0) {
393 if (addSCol2RuleValue("zo_domain", obj->zo_domain, rv) != 0) {
394 freeRuleValue(rv, 1);
395 return (0);
396 }
397 }
398
399 (void) memset(abuf, 0, sizeof (abuf));
400 (void) memset(tbuf, 0, sizeof (tbuf));
401
402 sprintf(abuf, "%x", obj->zo_access);
403 sprintf(tbuf, "%x", obj->zo_ttl);
404
405 if (addSCol2RuleValue("zo_access", abuf, rv) != 0) {
406 freeRuleValue(rv, 1);
407 return (0);
408 }
409 if (addSCol2RuleValue("zo_ttl", tbuf, rv) != 0) {
410 freeRuleValue(rv, 1);
411 return (0);
412 }
413
414 return (rv);
415 }
416
417 /*
418 * Returns a pointer to (NOT a copy of) the value for the specified
419 * column 'col' in the rule-value 'rv'.
420 */
421 __nis_value_t *
findColValue(char * col,__nis_rule_value_t * rv)422 findColValue(char *col, __nis_rule_value_t *rv) {
423 int i;
424
425 if (col == 0 || rv == 0 || rv->numColumns <= 0)
426 return (0);
427
428 for (i = 0; i < rv->numColumns; i++) {
429 if (strcmp(col, rv->colName[i]) == 0)
430 return (&rv->colVal[i]);
431 }
432
433 return (0);
434 }
435
436 /*
437 * Return the NIS+ object attributes (if any) in the rule-value 'rv'.
438 */
439 __nis_obj_attr_t *
ruleValue2ObjAttr(__nis_rule_value_t * rv)440 ruleValue2ObjAttr(__nis_rule_value_t *rv) {
441 __nis_obj_attr_t *attr;
442 __nis_value_t *val;
443 char *myself = "ruleValue2ObjAttr";
444
445 if (rv == 0 || rv->numColumns <= 0)
446 return (0);
447
448 attr = am(myself, sizeof (*attr));
449
450 if ((val = findColValue("zo_owner", rv)) != 0 &&
451 val->type == vt_string && val->numVals == 1 &&
452 val->val[0].value != 0) {
453 attr->zo_owner = sdup(myself, T, val->val[0].value);
454 if (attr->zo_owner == 0) {
455 freeSingleObjAttr(attr);
456 return (0);
457 }
458 }
459
460 if ((val = findColValue("zo_group", rv)) != 0 &&
461 val->type == vt_string && val->numVals == 1 &&
462 val->val[0].value != 0) {
463 attr->zo_group = sdup(myself, T, val->val[0].value);
464 if (attr->zo_group == 0) {
465 freeSingleObjAttr(attr);
466 return (0);
467 }
468 }
469
470 if ((val = findColValue("zo_domain", rv)) != 0 &&
471 val->type == vt_string && val->numVals == 1 &&
472 val->val[0].value != 0) {
473 attr->zo_domain = sdup(myself, T, val->val[0].value);
474 if (attr->zo_domain == 0) {
475 freeSingleObjAttr(attr);
476 return (0);
477 }
478 }
479
480 if ((val = findColValue("zo_access", rv)) != 0 &&
481 val->type == vt_string && val->numVals == 1 &&
482 val->val[0].value != 0) {
483 if (sscanf(val->val[0].value, "%x", &attr->zo_access) != 1) {
484 freeSingleObjAttr(attr);
485 return (0);
486 }
487 }
488
489 if ((val = findColValue("zo_ttl", rv)) != 0 &&
490 val->type == vt_string && val->numVals == 1 &&
491 val->val[0].value != 0) {
492 if (sscanf(val->val[0].value, "%x", &attr->zo_ttl) != 1) {
493 freeSingleObjAttr(attr);
494 return (0);
495 }
496 }
497
498 return (attr);
499 }
500
501 /*
502 * If the supplied string is one of the object attributes, return one.
503 * Otherwise, return zero.
504 */
505 int
isObjAttrString(char * str)506 isObjAttrString(char *str) {
507 if (str == 0)
508 return (0);
509
510 if (strcmp("zo_owner", str) == 0 ||
511 strcmp("zo_group", str) == 0 ||
512 strcmp("zo_domain", str) == 0 ||
513 strcmp("zo_access", str) == 0 ||
514 strcmp("zo_ttl", str) == 0)
515 return (1);
516 else
517 return (0);
518 }
519
520
521 /*
522 * If the supplied value is one of the object attribute strings, return
523 * a pointer to the string. Otherwise, return NULL.
524 */
525 char *
isObjAttr(__nis_single_value_t * val)526 isObjAttr(__nis_single_value_t *val) {
527 if (val == 0 || val->length <= 0 || val->value == 0)
528 return (0);
529
530 if (isObjAttrString(val->value))
531 return (val->value);
532 else
533 return (0);
534 }
535
536 int
setObjAttrField(char * attrName,__nis_single_value_t * val,__nis_obj_attr_t ** objAttr)537 setObjAttrField(char *attrName, __nis_single_value_t *val,
538 __nis_obj_attr_t **objAttr) {
539 __nis_obj_attr_t *attr;
540 char *myself = "setObjAttrField";
541
542 if (attrName == 0 || val == 0 || objAttr == 0 ||
543 val->value == 0 || val->length <= 0)
544 return (-1);
545
546 if (*objAttr != 0) {
547 attr = *objAttr;
548 } else {
549 attr = am(myself, sizeof (*attr));
550 if (attr == 0)
551 return (-2);
552 *objAttr = attr;
553 }
554
555 if (strcmp("zo_owner", attrName) == 0) {
556 if (attr->zo_owner == 0) {
557 attr->zo_owner = sdup(myself, T, val->value);
558 if (attr->zo_owner == 0)
559 return (-11);
560 }
561 } else if (strcmp("zo_group", attrName) == 0) {
562 if (attr->zo_group == 0) {
563 attr->zo_group = sdup(myself, T, val->value);
564 if (attr->zo_group == 0)
565 return (-12);
566 }
567 } else if (strcmp("zo_domain", attrName) == 0) {
568 if (attr->zo_domain == 0) {
569 attr->zo_domain = sdup(myself, T, val->value);
570 if (attr->zo_domain == 0)
571 return (-13);
572 }
573 } else if (strcmp("zo_access", attrName) == 0) {
574 if (attr->zo_access == 0) {
575 if (sscanf(val->value, "%x", &attr->zo_access) != 1)
576 return (-14);
577 }
578 } else if (strcmp("zo_ttl", attrName) == 0) {
579 if (attr->zo_ttl == 0) {
580 if (sscanf(val->value, "%x", &attr->zo_ttl) != 1)
581 return (-15);
582 }
583 }
584
585 return (0);
586 }
587
588 /*
589 * Return a DN and rule-value for the supplied mapping, db_query's, and
590 * input rule-value. This function only works on a single mapping. See
591 * mapToLDAP() below for a description of the action depending on the
592 * values of 'old' and 'new'.
593 *
594 * If both 'old' and 'new' are supplied, and the modify would result
595 * in a change to the DN, '*oldDN' will contain the old DN. Otherwise
596 * (and normally), '*oldDN' will be NULL.
597 */
598 char *
map1qToLDAP(__nis_table_mapping_t * t,db_query * old,db_query * new,__nis_rule_value_t * rvIn,__nis_rule_value_t ** rvOutP,char ** oldDnP)599 map1qToLDAP(__nis_table_mapping_t *t, db_query *old, db_query *new,
600 __nis_rule_value_t *rvIn, __nis_rule_value_t **rvOutP,
601 char **oldDnP) {
602
603 __nis_rule_value_t *rv, *rvt;
604 __nis_ldap_search_t *ls;
605 char *dn = 0, *oldDn = 0;
606 __nis_table_mapping_t del;
607 char *myself = "map1qToLDAP";
608
609 if (t == 0 || (old == 0 && new == 0) || rvOutP == 0)
610 return (0);
611
612 /*
613 * If entry should be deleted, we look at the delete
614 * policy in the table mapping. Should it specify a
615 * rule set, we use that rule set to build a rule-
616 * value, and the delete actually becomes a modify
617 * operation.
618 */
619 if (old != 0 && new == 0) {
620 if (t->objectDN->delDisp == dd_perDbId) {
621 /*
622 * The functions that build a rule-value from a
623 * rule set expect a __nis_table_mapping_t, but the
624 * rule set in the __nis_object_dn_t isn't of that
625 * form. So, build a pseudo-__nis_table_mapping_t that
626 * borrows heavily from 't'.
627 */
628 del = *t;
629
630 del.numRulesToLDAP = del.objectDN->numDbIds;
631 del.ruleToLDAP = del.objectDN->dbId;
632
633 /*
634 * Do a modify with the pseudo-table
635 * mapping, and the 'old' db_query
636 * supplying input to the delete rule
637 * set.
638 */
639 t = &del;
640 new = old;
641 } else if (t->objectDN->delDisp == dd_always) {
642
643 /* Nothing to do here; all handled below */
644
645 } else if (t->objectDN->delDisp == dd_never) {
646
647 return (0);
648
649 } else {
650
651 logmsg(MSG_INVALIDDELDISP, LOG_WARNING,
652 "%s: Invalid delete disposition %d for \"%s\"",
653 myself, t->objectDN->delDisp,
654 NIL(t->dbId));
655 return (0);
656
657 }
658 }
659
660 /* Make a copy of the input rule-value */
661 if (rvIn != 0) {
662 rv = initRuleValue(1, rvIn);
663 if (rv == 0)
664 return (0);
665 } else {
666 rv = 0;
667 }
668
669 /* First get a rule-value from the supplied NIS+ entry. */
670 rvt = rv;
671 rv = buildNisPlusRuleValue(t, ((old != 0) ? old : new), rvt);
672 freeRuleValue(rvt, 1);
673 if (rv == 0) {
674 logmsg(MSG_NORULEVALUE, LOG_WARNING,
675 "%s: No in-query rule-value derived for \"%s\"",
676 myself, NIL(t->dbId));
677 return (0);
678 }
679
680 /*
681 * Create a request (really only care about the DN) from the
682 * supplied NIS+ entry data.
683 */
684 ls = createLdapRequest(t, rv, &dn, 0, NULL, NULL);
685 if (ls == 0 || dn == 0) {
686 logmsg(MSG_NOTIMECHECK, LOG_ERR,
687 "%s: Unable to create LDAP request for %s: %s",
688 myself, NIL(t->dbId),
689 (dn != 0) ? dn : rvId(rv, mit_nisplus));
690 sfree(dn);
691 freeLdapSearch(ls);
692 freeRuleValue(rv, 1);
693 return (0);
694 }
695
696 freeLdapSearch(ls);
697
698 if (new != 0) {
699 /*
700 * Create a rule-value from the new NIS+ entry.
701 * Don't want to mix in the rule-value derived
702 * from 'old', so delete it. However, we still
703 * want the owner, group, etc., from 'rvIn'.
704 */
705 if (old != 0) {
706 freeRuleValue(rv, 1);
707 if (rvIn != 0) {
708 rv = initRuleValue(1, rvIn);
709 if (rv == 0) {
710 sfree(dn);
711 return (0);
712 }
713 } else {
714 rv = 0;
715 }
716 }
717 rvt = rv;
718 rv = buildNisPlusRuleValue(t, new, rvt);
719 freeRuleValue(rvt, 1);
720 if (rv == 0) {
721 logmsg(MSG_NORULEVALUE, LOG_WARNING,
722 "%s: No new rule-value derived for \"%s: %s\"",
723 myself, NIL(t->dbId), dn);
724 sfree(dn);
725 return (0);
726 }
727 /*
728 * Check if the proposed modification would result in a
729 * a change to the DN.
730 */
731 if (old != 0) {
732 oldDn = dn;
733 dn = 0;
734 ls = createLdapRequest(t, rv, &dn, 0, NULL, NULL);
735 if (ls == 0 || dn == 0) {
736 logmsg(MSG_NOTIMECHECK, LOG_ERR,
737 "%s: Unable to create new DN for \"%s: %s\"",
738 myself, NIL(t->dbId), oldDn);
739 sfree(oldDn);
740 freeLdapSearch(ls);
741 freeRuleValue(rv, 1);
742 return (0);
743 }
744 freeLdapSearch(ls);
745 if (strcasecmp(oldDn, dn) == 0) {
746 sfree(oldDn);
747 oldDn = 0;
748 }
749 }
750 }
751
752
753 *rvOutP = rv;
754 if (oldDnP != 0)
755 *oldDnP = oldDn;
756
757 return (dn);
758 }
759
760 /*
761 * Since the DN hash list is an automatic variable, there's no need for
762 * locking, and we remove the locking overhead by using the libnsl
763 * hash functions.
764 */
765 #undef NIS_HASH_ITEM
766 #undef NIS_HASH_TABLE
767
768 typedef struct {
769 NIS_HASH_ITEM item;
770 int index;
771 char *oldDn;
772 } __dn_item_t;
773
774 /*
775 * Update LDAP per the supplied table mapping and db_query's.
776 *
777 * 'nq' is the number of elements in the 'old', 'new', and 'rvIn'
778 * arrays. mapToLDAP() generally performs one update for each
779 * element; however, if one or more of the individual queries
780 * produce the same DN, they're merged into a single update.
781 *
782 * There are four cases, depending on the values of 'old[iq]' and
783 * 'new[iq]':
784 *
785 * (1) old[iq] == 0 && new[iq] == 0
786 * No action; skip to next query
787 *
788 * (2) old[iq] == 0 && new[iq] != 0
789 * Attempt to use the 'new' db_query to get a DN, and try to create
790 * the corresponding LDAP entry.
791 *
792 * (3) old[iq] != 0 && new[iq] == 0
793 * Use the 'old' db_query to get a DN, and try to delete the LDAP
794 * entry per the table mapping.
795 *
796 * (4) old[iq] != 0 && new[iq] != 0
797 * Use the 'old' db_query to get a DN, and update (possibly create)
798 * the corresponding LDAP entry per the 'new' db_query.
799 *
800 * If 'rvIn' is non-NULL, it is expected to contain the object attributes
801 * (zo_owner, etc.) to be written to LDAP. 'rvIn' is an array with 'nq'
802 * elements.
803 *
804 * If 'firstOnly' is set, only the first old[iq]/new[iq] pair is used
805 * to perform the actual update. Any additional queries specified will
806 * have their values folded in, but are not used to derive update targets.
807 * This mode is inteded to support the case where multiple NIS+ entries
808 * map to one and the same LDAP entry. Note that 'rvIn' must still be
809 * an array of 'nq' elements, though if 'firstOnly' is set, it should be
810 * OK to leave all but 'rvIn[0]' empty.
811 *
812 * 'dbId' is used to further narow down the selection of mapping candidates
813 * to those matching the 'dbId' value.
814 */
815 int
mapToLDAP(__nis_table_mapping_t * tm,int nq,db_query ** old,db_query ** new,__nis_rule_value_t * rvIn,int firstOnly,char * dbId)816 mapToLDAP(__nis_table_mapping_t *tm, int nq, db_query **old, db_query **new,
817 __nis_rule_value_t *rvIn, int firstOnly, char *dbId) {
818 __nis_table_mapping_t **tp, **tpa;
819 int i, n, rnq, iq, r, ret = LDAP_SUCCESS;
820 int maxMatches, numMatches = 0;
821 __nis_ldap_search_t *ls;
822 char **dn = 0, **odn = 0;
823 __nis_rule_value_t **rv;
824 __dn_item_t *dni;
825 char *myself = "mapToLDAP";
826
827
828 if (tm == 0 || (old == 0 && new == 0) || nq <= 0)
829 return (LDAP_PARAM_ERROR);
830
831 /* Determine maximum number of table mapping matches */
832 if (nq == 1) {
833 tp = selectTableMapping(tm,
834 (old != 0 && old[0] != 0) ? old[0] : new[0], 1, 0,
835 dbId, &maxMatches);
836 numMatches = maxMatches;
837 } else {
838 tp = selectTableMapping(tm, 0, 1, 0, dbId, &maxMatches);
839 }
840
841 /*
842 * If no matching mapping, we're not mapping to LDAP in this
843 * particular case.
844 */
845 if (tp == 0 || maxMatches == 0) {
846 sfree(tp);
847 return (LDAP_SUCCESS);
848 }
849
850 /*
851 * Allocate the 'rv', 'dn', and 'tpa' arrays. Worst case is that
852 * we need nq * maxMatches elements in each array. However, if
853 * 'firstOnly' is set, we only need one element per matching
854 * mapping in each.
855 */
856 dn = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (dn[0]));
857 odn = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (odn[0]));
858 rv = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (rv[0]));
859 tpa = am(myself, (firstOnly ? 1 : nq) * maxMatches * sizeof (tpa[0]));
860 if (dn == 0 || odn == 0 || rv == 0 || tpa == 0) {
861 sfree(tp);
862 sfree(dn);
863 sfree(odn);
864 sfree(rv);
865 sfree(tpa);
866 return (LDAP_NO_MEMORY);
867 }
868
869 /* Unless nq == 1, we don't need the 'tp' value */
870 if (nq != 1)
871 sfree(tp);
872
873 logmsg(MSG_NOTIMECHECK,
874 #ifdef NISDB_LDAP_DEBUG
875 LOG_WARNING,
876 #else
877 LOG_INFO,
878 #endif /* NISDB_LDAP_DEBUG */
879 "%s: %s: %d * %d potential updates",
880 myself, NIL(tm->objName), nq, maxMatches);
881
882 /*
883 * Create DNs, column and attribute values, and merge duplicate DNs.
884 */
885 for (iq = 0, rnq = 0; iq < nq; iq++) {
886 int idx;
887
888 if ((old == 0 || old[iq] == 0) &&
889 (new == 0 || new[iq] == 0))
890 continue;
891
892 /*
893 * Select matching table mappings; if nq == 1, we've already
894 * got the 'tp' array from above. We expect this to be the
895 * most common case, so it's worth special treatment.
896 */
897 if (nq != 1)
898 tp = selectTableMapping(tm,
899 (old != 0 && old[iq] != 0) ? old[iq] : new[iq], 1, 0,
900 dbId, &numMatches);
901 if (tp == 0)
902 continue;
903 else if (numMatches <= 0) {
904 sfree(tp);
905 continue;
906 }
907
908 idx = iq * maxMatches;
909
910 if (idx == 0 || !firstOnly)
911 (void) memcpy(&tpa[idx], tp,
912 numMatches * sizeof (tpa[idx]));
913
914 for (n = 0; n < numMatches; n++) {
915 char *dnt, *odnt;
916 __nis_rule_value_t *rvt = 0;
917
918 if (tp[n] == 0)
919 continue;
920
921 dnt = map1qToLDAP(tp[n],
922 (old != 0) ? old[iq] : 0,
923 (new != 0) ? new[iq] : 0,
924 (rvIn != 0) ? &rvIn[iq] : 0,
925 &rvt, &odnt);
926
927 if (dnt == 0)
928 continue;
929 if (rvt == 0) {
930 #ifdef NISDB_LDAP_DEBUG
931 abort();
932 #else
933 sfree(dnt);
934 sfree(odnt);
935 continue;
936 #endif /* NISDB_LDAP_DEBUG */
937 }
938
939 /*
940 * Create a request to get a rule-value with
941 * NIS+ data translated to LDAP equivalents.
942 */
943 ls = createLdapRequest(tp[n], rvt, 0, 0, NULL, NULL);
944 if (ls == 0) {
945 if (ret == LDAP_SUCCESS)
946 ret = LDAP_OPERATIONS_ERROR;
947 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
948 "%s: Unable to map to LDAP attrs for %s:dn=%s",
949 myself, NIL(tp[n]->dbId), dnt);
950 sfree(dnt);
951 freeRuleValue(rvt, 1);
952 continue;
953 }
954 freeLdapSearch(ls);
955
956 /*
957 * If the DN is the same as one we already know
958 * about, merge the rule-values.
959 */
960
961 if ((iq == 0 || !firstOnly) && dnt != 0) {
962 dni = am(myself, sizeof (*dni));
963 if (dni != 0) {
964 dni->item.name = dnt;
965 dni->index = idx + n;
966 dni->oldDn = odnt;
967 } else {
968 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
969 "%s: Skipping update for dn=\"%s\"",
970 myself, dnt);
971 sfree(dnt);
972 dnt = 0;
973 }
974 if (dnt != 0) {
975 dn[idx+n] = dnt;
976 odn[idx+n] = odnt;
977 rv[idx+n] = rvt;
978 rnq++;
979 } else {
980 freeRuleValue(rvt, 1);
981 rvt = 0;
982 }
983 } else if (dnt != 0) {
984 sfree(dnt);
985 sfree(odnt);
986 freeRuleValue(rvt, 1);
987 }
988 }
989 sfree(tp);
990 }
991
992 logmsg(MSG_NOTIMECHECK,
993 #ifdef NISDB_LDAP_DEBUG
994 LOG_WARNING,
995 #else
996 LOG_INFO,
997 #endif /* NISDB_LDAP_DEBUG */
998 "%s: %s: %d update%s requested",
999 myself, NIL(tm->objName), rnq, rnq != 1 ? "s" : "");
1000
1001 /* Perform the updates */
1002 for (i = rnq = 0; i < (firstOnly ? maxMatches : nq*maxMatches); i++) {
1003 int delPerDbId;
1004
1005 if (dn[i] == 0)
1006 continue;
1007
1008 #ifdef NISDB_LDAP_DEBUG
1009 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1010 "%s: %s %s:dn=%s",
1011 myself,
1012 (new != 0 && new[i/maxMatches] != 0) ?
1013 "modify" : "delete",
1014 NIL(tpa[i]->dbId), dn[i]);
1015 #endif /* NISDB_LDAP_DEBUG */
1016
1017 delPerDbId = (tpa[i]->objectDN->delDisp == dd_perDbId);
1018 if ((new != 0 && new[i/maxMatches] != 0) || delPerDbId) {
1019 /*
1020 * Try to modify/create the specified DN. First,
1021 * however, if the update changes the DN, make
1022 * that change.
1023 */
1024 if (odn[i] == 0 || (r = ldapChangeDN(odn[i], dn[i])) ==
1025 LDAP_SUCCESS) {
1026 int addFirst;
1027
1028 addFirst = (new != 0 &&
1029 new[i/maxMatches] != 0 &&
1030 !delPerDbId);
1031 r = ldapModify(dn[i], rv[i],
1032 tpa[i]->objectDN->write.attrs,
1033 addFirst);
1034 }
1035 } else {
1036 /* Try to delete the specified DN */
1037 r = ldapModify(dn[i], 0,
1038 tpa[i]->objectDN->write.attrs, 0);
1039 }
1040
1041 if (r == LDAP_SUCCESS) {
1042 rnq++;
1043 } else {
1044 if (ret == LDAP_SUCCESS)
1045 ret = r;
1046 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1047 "%s: LDAP %s request error %d for %s:dn=%s",
1048 myself,
1049 (new != 0 && new[i/maxMatches] != 0) ?
1050 "modify" : "delete",
1051 r, NIL(tpa[i]->dbId), dn[i]);
1052 }
1053
1054 sfree(dn[i]);
1055 dn[i] = 0;
1056 freeRuleValue(rv[i], 1);
1057 rv[i] = 0;
1058 }
1059
1060 sfree(dn);
1061 sfree(odn);
1062 sfree(rv);
1063 sfree(tpa);
1064
1065 logmsg(MSG_NOTIMECHECK,
1066 #ifdef NISDB_LDAP_DEBUG
1067 LOG_WARNING,
1068 #else
1069 LOG_INFO,
1070 #endif /* NISDB_LDAP_DEBUG */
1071 "%s: %s: %d update%s performed",
1072 myself, NIL(tm->objName), rnq, rnq != 1 ? "s" : "");
1073
1074 return (ret);
1075 }
1076
1077 /*
1078 * In nis+2ldap, check if the query 'q' matches the selector index 'x->index'.
1079 *
1080 * In nis2ldap, if 'name' is provided then check if its value in 'val'
1081 * matches the selector index. If 'name' is NULL, then check if rule-value 'rv'
1082 * matches the index.
1083 * To match the selector index, all fieldspecs in the indexlist should match
1084 * (AND). In nis2ldap, an exception is, if there are multiple fieldspecs with
1085 * the same fieldname then only one of them needs to match (OR).
1086 * Example:
1087 * Indexlist = [host="H*", host="I*", user="U*", domain="D*"]
1088 * Then,
1089 * host = "H1", user="U1", domain="D1" ==> pass
1090 * host = "I1", user="U1", domain="D1" ==> pass
1091 * host = "X1", user="U1", domain="D1" ==> fail
1092 * host = "H1", user="X1", domain="D1" ==> fail
1093 * host = "H1", user="U1" ==> fail
1094 *
1095 * Return 1 in case of a match, 0 otherwise.
1096 */
1097 int
verifyIndexMatch(__nis_table_mapping_t * x,db_query * q,__nis_rule_value_t * rv,char * name,char * val)1098 verifyIndexMatch(__nis_table_mapping_t *x, db_query *q,
1099 __nis_rule_value_t *rv, char *name, char *val) {
1100 int i, j, k, match = 1;
1101 char *myself = "verifyIndexMatch";
1102
1103 /*
1104 * The pass and fail arrays are used by N2L to keep track of
1105 * index matches. This saves us from having matches in a
1106 * nested loop to decide OR or AND.
1107 */
1108 int ppos, fpos;
1109 char **pass, **fail;
1110
1111 if (x == 0)
1112 return (0);
1113
1114 /* Trivial match */
1115 if (x->index.numIndexes <= 0 || (!yp2ldap && q == 0))
1116 return (1);
1117
1118 if (yp2ldap) {
1119 if (!(pass = am(myself, x->index.numIndexes * sizeof (char *))))
1120 return (0);
1121 if (!(fail = am(myself,
1122 x->index.numIndexes * sizeof (char *)))) {
1123 sfree(pass);
1124 return (0);
1125 }
1126 ppos = fpos = 0;
1127 }
1128
1129 /* Check each index */
1130 for (i = 0; i < x->index.numIndexes; i++) {
1131 char *value = 0;
1132
1133 /* Skip NULL index names */
1134 if (x->index.name[i] == 0)
1135 continue;
1136
1137 /* Check N2L values */
1138 if (yp2ldap) {
1139 if (name) {
1140 if (strcasecmp(x->index.name[i], name) == 0)
1141 value = val;
1142 else
1143 continue;
1144 } else if (rv) {
1145 if (strcasecmp(x->index.name[i], N2LKEY) == 0 ||
1146 strcasecmp(x->index.name[i], N2LIPKEY)
1147 == 0)
1148 continue;
1149 value = findVal(x->index.name[i], rv,
1150 mit_nisplus);
1151 }
1152
1153 if (value && verifyMappingMatch(x->index.value[i],
1154 value))
1155 pass[ppos++] = x->index.name[i];
1156 else
1157 fail[fpos++] = x->index.name[i];
1158 continue;
1159 }
1160
1161 /* If here, means nis+2ldap */
1162
1163 /* Is the index name a known column ? */
1164 for (j = 0; j < x->numColumns; j++) {
1165 if (strcmp(x->index.name[i], x->column[j]) == 0) {
1166 /*
1167 * Do we have a value for the column ?
1168 */
1169 for (k = 0; k < q->components.components_len;
1170 k++) {
1171 if (q->components.components_val[k].
1172 which_index == j) {
1173 value = q->components.
1174 components_val[k].
1175 index_value->
1176 itemvalue.
1177 itemvalue_val;
1178 break;
1179 }
1180 }
1181 if (value != 0)
1182 break;
1183 }
1184 }
1185
1186 /*
1187 * If we found a value, check if it matches the
1188 * format. If no value found or no match, this
1189 * mapping is _not_ an alternative. Otherwise,
1190 * we continue checking any other indexes.
1191 */
1192 if (value == 0 ||
1193 !verifyMappingMatch(x->index.value[i],
1194 value)) {
1195 match = 0;
1196 break;
1197 }
1198 }
1199
1200 if (yp2ldap) {
1201 for (--fpos; fpos >= 0; fpos--) {
1202 for (i = 0; i < ppos; i++) {
1203 if (strcmp(pass[i], fail[fpos]) == 0)
1204 break;
1205 }
1206 if (i == ppos) {
1207 match = 0;
1208 break;
1209 }
1210 }
1211 sfree(pass);
1212 sfree(fail);
1213 }
1214
1215 return (match);
1216 }
1217
1218 /*
1219 * Return all table mappings that match the column values in 'q'.
1220 * If there's no match, return those alternative mappings that don't
1221 * have an index; if no such mapping exists, return NULL.
1222 *
1223 * If 'wantWrite' is set, we want mappings for writing (i.e., data
1224 * to LDAP); otherwise, we want mappings for reading.
1225 *
1226 * If 'wantObj' is set, we want object mappings only (i.e., _not_
1227 * those used to map entries in tables).
1228 *
1229 * If 'dbId' is non-NULL, we select mappings with a matching dbId field.
1230 */
1231 __nis_table_mapping_t **
selectTableMapping(__nis_table_mapping_t * t,db_query * q,int wantWrite,int wantObj,char * dbId,int * numMatches)1232 selectTableMapping(__nis_table_mapping_t *t, db_query *q,
1233 int wantWrite, int wantObj, char *dbId,
1234 int *numMatches) {
1235 __nis_table_mapping_t *x, **tp;
1236 int i, nm, numap;
1237 char *myself = "selectTableMapping";
1238
1239 if (numMatches == 0)
1240 numMatches = &nm;
1241
1242 /*
1243 * Count the number of possible mappings, so that we can
1244 * allocate the 'tp' array up front.
1245 */
1246 for (numap = 0, x = t; x != 0; numap++, x = x->next);
1247
1248 if (numap == 0) {
1249 *numMatches = 0;
1250 return (0);
1251 }
1252
1253 tp = am(myself, numap * sizeof (tp[0]));
1254 if (tp == 0) {
1255 *numMatches = -1;
1256 return (0);
1257 }
1258
1259 /*
1260 * Special cases:
1261 *
1262 * q == 0 trivially matches any 't' of the correct object type
1263 *
1264 * wantObj != 0 means we ignore 'q'
1265 */
1266 if (q == 0 || wantObj) {
1267 for (i = 0, x = t, nm = 0; i < numap; i++, x = x->next) {
1268 if (x->objectDN == 0)
1269 continue;
1270 if (wantWrite) {
1271 if (x->objectDN->write.scope ==
1272 LDAP_SCOPE_UNKNOWN)
1273 continue;
1274 } else {
1275 if (x->objectDN->read.scope ==
1276 LDAP_SCOPE_UNKNOWN)
1277 continue;
1278 }
1279 if (wantObj) {
1280 if (x->numColumns > 0)
1281 continue;
1282 } else {
1283 if (x->numColumns <= 0)
1284 continue;
1285 }
1286 if (dbId != 0 && x->dbId != 0 &&
1287 strcmp(dbId, x->dbId) != 0)
1288 continue;
1289 tp[nm] = x;
1290 nm++;
1291 }
1292 *numMatches = nm;
1293 if (nm == 0) {
1294 sfree(tp);
1295 tp = 0;
1296 }
1297 return (tp);
1298 }
1299
1300 /* Scan all mappings, and collect candidates */
1301 for (nm = 0, x = t; x != 0; x = x->next) {
1302 if (x->objectDN == 0)
1303 continue;
1304 if (wantWrite) {
1305 if (x->objectDN->write.scope == LDAP_SCOPE_UNKNOWN)
1306 continue;
1307 } else {
1308 if (x->objectDN->read.scope == LDAP_SCOPE_UNKNOWN)
1309 continue;
1310 }
1311 /* Only want table/entry mappings */
1312 if (x->numColumns <= 0)
1313 continue;
1314 if (dbId != 0 && x->dbId != 0 &&
1315 strcmp(dbId, x->dbId) != 0)
1316 continue;
1317 /*
1318 * It's a match if: there are no indexes, or we actually
1319 * match the query with the indexes.
1320 */
1321 if (x->index.numIndexes <= 0 ||
1322 verifyIndexMatch(x, q, 0, 0, 0)) {
1323 tp[nm] = x;
1324 nm++;
1325 }
1326 }
1327
1328 if (nm == 0) {
1329 free(tp);
1330 tp = 0;
1331 }
1332
1333 *numMatches = nm;
1334
1335 return (tp);
1336 }
1337
1338 /*
1339 * Return 1 if there's an indexed mapping, 0 otherwise.
1340 */
1341 int
haveIndexedMapping(__nis_table_mapping_t * t)1342 haveIndexedMapping(__nis_table_mapping_t *t) {
1343 __nis_table_mapping_t *x;
1344
1345 for (x = t; x != 0; x = x->next) {
1346 if (x->index.numIndexes > 0)
1347 return (1);
1348 }
1349
1350 return (0);
1351 }
1352
1353 /*
1354 * Given an input string 'attrs' of the form "attr1=val1,attr2=val2,...",
1355 * or a filter, return the value associated with the attribute 'attrName'.
1356 * If no instance of 'attrName' is found, return 'default'. In all cases,
1357 * the return value is a copy, and must be freed by the caller.
1358 *
1359 * Of course, return NULL in case of failure.
1360 */
1361 static char *
attrVal(char * msg,char * attrName,char * def,char * attrs)1362 attrVal(char *msg, char *attrName, char *def, char *attrs) {
1363 char *val, *filter, **fc = 0;
1364 int i, nfc;
1365 char *myself = "attrVal";
1366
1367 if (attrName == 0 || attrs == 0)
1368 return (0);
1369
1370 if (msg == 0)
1371 msg = myself;
1372
1373 val = def;
1374
1375 filter = makeFilter(attrs);
1376 if (filter != 0 && (fc = makeFilterComp(filter, &nfc)) != 0 &&
1377 nfc > 0) {
1378 for (i = 0; i < nfc; i++) {
1379 char *name, *value;
1380
1381 name = fc[i];
1382 /* Skip if not of attr=value form */
1383 if ((value = strchr(name, '=')) == 0)
1384 continue;
1385
1386 *value = '\0';
1387 value++;
1388
1389 if (strcasecmp(attrName, name) == 0) {
1390 val = value;
1391 break;
1392 }
1393 }
1394 }
1395
1396 if (val != 0)
1397 val = sdup(msg, T, val);
1398
1399 sfree(filter);
1400 freeFilterComp(fc, nfc);
1401
1402 return (val);
1403 }
1404
1405 extern bool_t xdr_nis_object(XDR *xdrs, nis_object *objp);
1406
1407 /*
1408 * Copy an XDR:ed version of the NIS+ object 'o' (or the one indicated
1409 * by 't->objName' if 'o' is NULL) to the place indicated by
1410 * 't->objectDN->write'. Return an appropriate LDAP status code.
1411 */
1412 int
objToLDAP(__nis_table_mapping_t * t,nis_object * o,entry_obj ** ea,int numEa)1413 objToLDAP(__nis_table_mapping_t *t, nis_object *o, entry_obj **ea, int numEa) {
1414 __nis_table_mapping_t **tp;
1415 int stat, osize, n, numMatches = 0;
1416 void *buf;
1417 __nis_rule_value_t *rv;
1418 __nis_value_t *val;
1419 __nis_single_value_t *sv;
1420 char **attrName, *dn;
1421 char *myself = "objToLDAP";
1422
1423 if (t == 0)
1424 return (LDAP_PARAM_ERROR);
1425
1426 logmsg(MSG_NOTIMECHECK,
1427 #ifdef NISDB_LDAP_DEBUG
1428 LOG_WARNING,
1429 #else
1430 LOG_INFO,
1431 #endif /* NISDB_LDAP_DEBUG */
1432 "%s: %s", myself, NIL(t->objName));
1433
1434 tp = selectTableMapping(t, 0, 1, 1, 0, &numMatches);
1435 if (tp == 0 || numMatches <= 0) {
1436 sfree(tp);
1437 logmsg(MSG_NOTIMECHECK,
1438 #ifdef NISDB_LDAP_DEBUG
1439 LOG_WARNING,
1440 #else
1441 LOG_INFO,
1442 #endif /* NISDB_LDAP_DEBUG */
1443 "%s: %s (no mapping)", myself, NIL(t->objName));
1444 return (LDAP_SUCCESS);
1445 }
1446
1447 for (n = 0; n < numMatches; n++) {
1448
1449 t = tp[n];
1450
1451 if (o == 0) {
1452 sfree(tp);
1453 return (LDAP_OPERATIONS_ERROR);
1454 }
1455
1456 buf = (char *)xdrNisObject(o, ea, numEa, &osize);
1457 if (buf == 0) {
1458 sfree(tp);
1459 return (LDAP_OPERATIONS_ERROR);
1460 }
1461
1462 /*
1463 * Prepare to build a rule-value containing the XDR:ed
1464 * object
1465 */
1466 rv = am(myself, sizeof (*rv));
1467 sv = am(myself, sizeof (*sv));
1468 val = am(myself, sizeof (*val));
1469 attrName = am(myself, sizeof (attrName[0]));
1470 if (attrName != 0)
1471 attrName[0] = attrVal(myself, "nisplusObject",
1472 "nisplusObject",
1473 t->objectDN->write.attrs);
1474 if (rv == 0 || sv == 0 || val == 0 || attrName == 0 ||
1475 attrName[0] == 0) {
1476 sfree(tp);
1477 sfree(buf);
1478 sfree(rv);
1479 sfree(sv);
1480 sfree(val);
1481 sfree(attrName);
1482 return (LDAP_NO_MEMORY);
1483 }
1484
1485 sv->length = osize;
1486 sv->value = buf;
1487
1488 /* 'vt_ber' just means "not a NUL-terminated string" */
1489 val->type = vt_ber;
1490 val->repeat = 0;
1491 val->numVals = 1;
1492 val->val = sv;
1493
1494 rv->numAttrs = 1;
1495 rv->attrName = attrName;
1496 rv->attrVal = val;
1497
1498 /*
1499 * The 'write.base' is the actual DN of the entry (and the
1500 * scope had better be 'base', but we don't check that).
1501 */
1502 dn = t->objectDN->write.base;
1503
1504 stat = ldapModify(dn, rv, t->objectDN->write.attrs, 1);
1505
1506 freeRuleValue(rv, 1);
1507
1508 logmsg(MSG_NOTIMECHECK,
1509 #ifdef NISDB_LDAP_DEBUG
1510 LOG_WARNING,
1511 #else
1512 LOG_INFO,
1513 #endif /* NISDB_LDAP_DEBUG */
1514 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat));
1515
1516 if (stat != LDAP_SUCCESS)
1517 break;
1518
1519 }
1520
1521 sfree(tp);
1522
1523 return (stat);
1524 }
1525
1526 /*
1527 * Retrieve a copy of the 't->objName' object from LDAP, where it's
1528 * stored in XDR:ed form in the place indicated by 't->objectDN->read'.
1529 * Un-XDR the object, and return a pointer to it in '*obj'; it's the
1530 * responsibility of the caller to free the object when it's no
1531 * longer needed.
1532 *
1533 * Returns an appropriate LDAP status.
1534 */
1535 int
objFromLDAP(__nis_table_mapping_t * t,nis_object ** obj,entry_obj *** eaP,int * numEaP)1536 objFromLDAP(__nis_table_mapping_t *t, nis_object **obj,
1537 entry_obj ***eaP, int *numEaP) {
1538 __nis_table_mapping_t **tp;
1539 nis_object *o;
1540 __nis_rule_value_t *rv;
1541 __nis_ldap_search_t *ls;
1542 char *attrs[2], *filter, **fc = 0;
1543 void *buf;
1544 int i, j, nfc, nrv, blen, stat = LDAP_SUCCESS;
1545 int n, numMatches;
1546 char *myself = "objFromLDAP";
1547
1548 if (t == 0)
1549 return (LDAP_PARAM_ERROR);
1550
1551 /*
1552 * If there's nowhere to store the result, we might as
1553 * well pretend all went well, and return right away.
1554 */
1555 if (obj == 0)
1556 return (LDAP_SUCCESS);
1557
1558 /* Prepare for the worst */
1559 *obj = 0;
1560
1561 logmsg(MSG_NOTIMECHECK,
1562 #ifdef NISDB_LDAP_DEBUG
1563 LOG_WARNING,
1564 #else
1565 LOG_INFO,
1566 #endif /* NISDB_LDAP_DEBUG */
1567 "%s: %s", myself, NIL(t->objName));
1568
1569 tp = selectTableMapping(t, 0, 0, 1, 0, &numMatches);
1570 if (tp == 0 || numMatches <= 0) {
1571 sfree(tp);
1572 logmsg(MSG_NOTIMECHECK,
1573 #ifdef NISDB_LDAP_DEBUG
1574 LOG_WARNING,
1575 #else
1576 LOG_INFO,
1577 #endif /* NISDB_LDAP_DEBUG */
1578 "%s: %s (no mapping)", myself, NIL(t->objName));
1579 return (LDAP_SUCCESS);
1580 }
1581
1582 for (n = 0; n < numMatches; n++) {
1583
1584 t = tp[n];
1585
1586 filter = makeFilter(t->objectDN->read.attrs);
1587 if (filter == 0 || (fc = makeFilterComp(filter, &nfc)) == 0 ||
1588 nfc <= 0) {
1589 sfree(tp);
1590 sfree(filter);
1591 freeFilterComp(fc, nfc);
1592 return ((t->objectDN->read.attrs != 0) ?
1593 LDAP_NO_MEMORY : LDAP_PARAM_ERROR);
1594 }
1595 /* Don't need the filter, just the components */
1596 sfree(filter);
1597
1598 /*
1599 * Look for a "nisplusObject" attribute, and (if found) copy
1600 * the value to attrs[0]. Also remove the "nisplusObject"
1601 * attribute and value from the filter components.
1602 */
1603 attrs[0] = sdup(myself, T, "nisplusObject");
1604 if (attrs[0] == 0) {
1605 sfree(tp);
1606 freeFilterComp(fc, nfc);
1607 return (LDAP_NO_MEMORY);
1608 }
1609 attrs[1] = 0;
1610 for (i = 0; i < nfc; i++) {
1611 char *name, *value;
1612 int compare;
1613
1614 name = fc[i];
1615 /* Skip if not of attr=value form */
1616 if ((value = strchr(name, '=')) == 0)
1617 continue;
1618
1619 /* Temporarily overWrite the '=' with a '\0' */
1620 *value = '\0';
1621
1622 /* Compare with our target attribute name */
1623 compare = strcasecmp("nisplusObject", name);
1624
1625 /* Put back the '=' */
1626 *value = '=';
1627
1628 /* Is it the name we're looking for ? */
1629 if (compare == 0) {
1630 sfree(attrs[0]);
1631 attrs[0] = sdup(myself, T, value+1);
1632 if (attrs[0] == 0) {
1633 sfree(tp);
1634 freeFilterComp(fc, nfc);
1635 return (LDAP_NO_MEMORY);
1636 }
1637 sfree(fc[i]);
1638 if (i < nfc-1)
1639 (void) memmove(&fc[i], &fc[i+1],
1640 (nfc-1-i) * sizeof (fc[i]));
1641 nfc--;
1642 break;
1643 }
1644 }
1645
1646 ls = buildLdapSearch(t->objectDN->read.base,
1647 t->objectDN->read.scope,
1648 nfc, fc, 0, attrs, 0, 1);
1649 sfree(attrs[0]);
1650 freeFilterComp(fc, nfc);
1651 if (ls == 0) {
1652 sfree(tp);
1653 return (LDAP_OPERATIONS_ERROR);
1654 }
1655
1656 nrv = 0;
1657 rv = ldapSearch(ls, &nrv, 0, &stat);
1658 if (rv == 0) {
1659 sfree(tp);
1660 freeLdapSearch(ls);
1661 return (stat);
1662 }
1663
1664 for (i = 0, buf = 0; i < nrv && buf == 0; i++) {
1665 for (j = 0; j < rv[i].numAttrs; j++) {
1666 if (strcasecmp(ls->attrs[0],
1667 rv[i].attrName[j]) == 0) {
1668 if (rv[i].attrVal[j].numVals <= 0)
1669 continue;
1670 buf = rv[i].attrVal[j].val[0].value;
1671 blen = rv[i].attrVal[j].val[0].length;
1672 break;
1673 }
1674 }
1675 }
1676
1677 if (buf != 0) {
1678 o = unXdrNisObject(buf, blen, eaP, numEaP);
1679 if (o == 0) {
1680 sfree(tp);
1681 freeLdapSearch(ls);
1682 freeRuleValue(rv, nrv);
1683 return (LDAP_OPERATIONS_ERROR);
1684 }
1685 stat = LDAP_SUCCESS;
1686 *obj = o;
1687 } else {
1688 stat = LDAP_NO_SUCH_OBJECT;
1689 }
1690
1691 freeLdapSearch(ls);
1692 freeRuleValue(rv, nrv);
1693
1694 logmsg(MSG_NOTIMECHECK,
1695 #ifdef NISDB_LDAP_DEBUG
1696 LOG_WARNING,
1697 #else
1698 LOG_INFO,
1699 #endif /* NISDB_LDAP_DEBUG */
1700 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat));
1701
1702 if (stat != LDAP_SUCCESS)
1703 break;
1704
1705 }
1706
1707 sfree(tp);
1708
1709 return (stat);
1710 }
1711
1712 int
deleteLDAPobj(__nis_table_mapping_t * t)1713 deleteLDAPobj(__nis_table_mapping_t *t) {
1714 __nis_table_mapping_t **tp;
1715 int n, stat, numMatches = 0;
1716 char *myself = "deleteLDAPobj";
1717
1718 if (t == 0)
1719 return (LDAP_PARAM_ERROR);
1720
1721 logmsg(MSG_NOTIMECHECK,
1722 #ifdef NISDB_LDAP_DEBUG
1723 LOG_WARNING,
1724 #else
1725 LOG_INFO,
1726 #endif /* NISDB_LDAP_DEBUG */
1727 "%s: %s", myself, NIL(t->objName));
1728
1729 tp = selectTableMapping(t, 0, 1, 1, 0, &numMatches);
1730 if (tp == 0 || numMatches <= 0) {
1731 sfree(tp);
1732 logmsg(MSG_NOTIMECHECK,
1733 #ifdef NISDB_LDAP_DEBUG
1734 LOG_WARNING,
1735 #else
1736 LOG_INFO,
1737 #endif /* NISDB_LDAP_DEBUG */
1738 "%s: %s (no mapping)", myself, NIL(t->objName));
1739 return (LDAP_SUCCESS);
1740 }
1741
1742 for (n = 0; n < numMatches; n++) {
1743
1744 t = tp[n];
1745
1746 if (t->objectDN->delDisp == dd_always) {
1747 /* Delete entire entry */
1748 stat = ldapModify(t->objectDN->write.base, 0,
1749 t->objectDN->write.attrs, 1);
1750 } else if (t->objectDN->delDisp == dd_perDbId) {
1751 /*
1752 * Delete the attribute holding the object.
1753 * First, determine what that attribute is called.
1754 */
1755 char *attrName =
1756 attrVal(myself,
1757 "nisplusObject",
1758 "nisplusObject",
1759 t->objectDN->write.attrs);
1760 __nis_rule_value_t rv;
1761 __nis_value_t val;
1762
1763 if (attrName == 0) {
1764 sfree(tp);
1765 return (LDAP_NO_MEMORY);
1766 }
1767
1768 /*
1769 * Build a __nis_value_t with 'numVals' < 0 to
1770 * indicate deletion.
1771 */
1772 val.type = vt_ber;
1773 val.numVals = -1;
1774 val.val = 0;
1775
1776 /*
1777 * Build a rule-value with the name we determined
1778 * above, and the deletion value.
1779 */
1780 (void) memset(&rv, 0, sizeof (rv));
1781 rv.numAttrs = 1;
1782 rv.attrName = &attrName;
1783 rv.attrVal = &val;
1784
1785 stat = ldapModify(t->objectDN->write.base, &rv,
1786 t->objectDN->write.attrs, 0);
1787
1788 sfree(attrName);
1789 } else if (t->objectDN->delDisp == dd_never) {
1790 /* Nothing to do, so we're trivially successful */
1791 stat = LDAP_SUCCESS;
1792 } else {
1793 stat = LDAP_PARAM_ERROR;
1794 }
1795
1796 logmsg(MSG_NOTIMECHECK,
1797 #ifdef NISDB_LDAP_DEBUG
1798 LOG_WARNING,
1799 #else
1800 LOG_INFO,
1801 #endif /* NISDB_LDAP_DEBUG */
1802 "%s: %s (%s)", myself, NIL(t->objName), ldap_err2string(stat));
1803
1804 /* If there were no such object, we've trivially succeeded */
1805 if (stat == LDAP_NO_SUCH_OBJECT)
1806 stat = LDAP_SUCCESS;
1807
1808 if (stat != LDAP_SUCCESS)
1809 break;
1810
1811 }
1812
1813 sfree(tp);
1814
1815 return (stat);
1816 }
1817