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