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