1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <lber.h>
  28 #include <ldap.h>
  29 #include <strings.h>
  30 
  31 #include "nisdb_mt.h"
  32 
  33 #include "ldap_util.h"
  34 #include "ldap_val.h"
  35 #include "ldap_attr.h"
  36 #include "ldap_ldap.h"
  37 #include "ldap_ruleval.h"
  38 
  39 
  40 /*
  41  * Free an array of 'count' rule-value elements.
  42  */
  43 void
  44 freeRuleValue(__nis_rule_value_t *rv, int count) {
  45         int     n, i, j;
  46 
  47         if (rv == 0)
  48                 return;
  49 
  50         for (n = 0; n < count; n++) {
  51 
  52                 if (rv[n].colName != 0) {
  53                         for (i = 0; i < rv[n].numColumns; i++) {
  54                                 sfree(rv[n].colName[i]);
  55                         }
  56                         free(rv[n].colName);
  57                 }
  58                 if (rv[n].colVal != 0) {
  59                         for (i = 0; i < rv[n].numColumns; i++) {
  60                                 for (j = 0; j < rv[n].colVal[i].numVals; j++) {
  61                                         sfree(rv[n].colVal[i].val[j].value);
  62                                 }
  63                                 if (rv[n].colVal[i].numVals > 0)
  64                                         sfree(rv[n].colVal[i].val);
  65                         }
  66                         free(rv[n].colVal);
  67                 }
  68 
  69                 if (rv[n].attrName != 0) {
  70                         for (i = 0; i < rv[n].numAttrs; i++) {
  71                                 sfree(rv[n].attrName[i]);
  72                         }
  73                         free(rv[n].attrName);
  74                 }
  75                 if (rv[n].attrVal != 0) {
  76                         for (i = 0; i < rv[n].numAttrs; i++) {
  77                                 for (j = 0; j < rv[n].attrVal[i].numVals;
  78                                                 j++) {
  79                                         sfree(rv[n].attrVal[i].val[j].value);
  80                                 }
  81                                 if (rv[n].attrVal[i].numVals > 0)
  82                                         sfree(rv[n].attrVal[i].val);
  83                         }
  84                         free(rv[n].attrVal);
  85                 }
  86 
  87         }
  88         sfree(rv);
  89 }
  90 
  91 /*
  92  * Return an array of 'count' __nis_rule_value_t elements, initialized
  93  * to be copies of 'rvIn' if supplied; empty otherwise.
  94  */
  95 __nis_rule_value_t *
  96 initRuleValue(int count, __nis_rule_value_t *rvIn) {
  97         return (growRuleValue(0, count, 0, rvIn));
  98 }
  99 
 100 static const __nis_rule_value_t rvZero = {0};
 101 
 102 /*
 103  * Grow 'old' from 'oldCount' to 'newCount' elements, initialize the
 104  * new portion to 'rvIn' (empty if not supplied), and return a pointer
 105  * to the result. Following a call to this function, the caller must
 106  * refer only to the returned array, not to 'old'.
 107  */
 108 __nis_rule_value_t *
 109 growRuleValue(int oldCount, int newCount, __nis_rule_value_t *old,
 110                 __nis_rule_value_t *rvIn) {
 111         __nis_rule_value_t      *rv;
 112         int                     i, j;
 113         char                    *myself = "growRuleValue";
 114 
 115         if (newCount <= 0 || newCount <= oldCount)
 116                 return (old);
 117 
 118         if (oldCount <= 0) {
 119                 oldCount = 0;
 120                 old = 0;
 121         }
 122 
 123         if (rvIn == 0)
 124                 rvIn = (__nis_rule_value_t *)&rvZero;
 125 
 126         rv = realloc(old, newCount * sizeof (rv[0]));
 127         if (rv == 0) {
 128                 logmsg(MSG_NOMEM, LOG_ERR,
 129                         "%s: realloc(%d ((%d+%d)*%d)) => 0",
 130                         myself, (oldCount+newCount) * sizeof (rv[0]),
 131                         oldCount, newCount, sizeof (rv[0]));
 132                 freeRuleValue(old, oldCount);
 133                 return (0);
 134         }
 135 
 136         (void) memset(&rv[oldCount], 0, (newCount-oldCount)*sizeof (rv[0]));
 137 
 138         for (i = oldCount; i < newCount; i++) {
 139                 rv[i].numColumns = rvIn->numColumns;
 140                 if (rv[i].numColumns > 0) {
 141                         rv[i].colName = cloneName(rvIn->colName,
 142                                         rv[i].numColumns);
 143                         rv[i].colVal = cloneValue(rvIn->colVal,
 144                                         rv[i].numColumns);
 145                 }
 146                 if (rv[i].numColumns > 0 &&
 147                                 (rv[i].colName == 0 || rv[i].colVal == 0)) {
 148                         freeRuleValue(rv, i);
 149                         return (0);
 150                 }
 151                 rv[i].numAttrs = rvIn->numAttrs;
 152                 rv[i].attrName = cloneName(rvIn->attrName, rv[i].numAttrs);
 153                 rv[i].attrVal = cloneValue(rvIn->attrVal, rv[i].numAttrs);
 154                 if (rv[i].numAttrs > 0 &&
 155                         (rv[i].attrName == 0 || rv[i].attrVal == 0)) {
 156                         freeRuleValue(rv, i);
 157                         return (0);
 158                 }
 159         }
 160 
 161         return (rv);
 162 }
 163 
 164 /*
 165  * Merge the source rule-value 's' into the target rule-value 't'.
 166  * If successful, unless 's' is a sub-set of 't', 't' will be changed
 167  * on exit, and will contain the values from 's' as well.
 168  */
 169 int
 170 mergeRuleValue(__nis_rule_value_t *t, __nis_rule_value_t *s) {
 171         int     i, j;
 172 
 173         if (s == 0)
 174                 return (0);
 175         else if (t == 0)
 176                 return (-1);
 177 
 178         for (i = 0; i < s->numColumns; i++) {
 179                 for (j = 0; j < s->colVal[i].numVals; j++) {
 180                         if (addCol2RuleValue(s->colVal[i].type, s->colName[i],
 181                                         s->colVal[i].val[j].value,
 182                                         s->colVal[i].val[j].length,
 183                                         t))
 184                                 return (-1);
 185                 }
 186         }
 187 
 188         for (i = 0; i < s->numAttrs; i++) {
 189                 for (j = 0; j < s->attrVal[i].numVals; j++) {
 190                         if (addAttr2RuleValue(s->attrVal[i].type,
 191                                         s->attrName[i],
 192                                         s->attrVal[i].val[j].value,
 193                                         s->attrVal[i].val[j].length,
 194                                         t))
 195                                 return (-1);
 196                 }
 197         }
 198 
 199         return (0);
 200 }
 201 
 202 static int
 203 addVal2RuleValue(char *msg, int caseSens, int snipNul, __nis_value_type_t type,
 204                 char *name, void *value, int valueLen,
 205                 int *numP, char ***inNameP, __nis_value_t **inValP) {
 206         int                     i, j, copyLen = valueLen;
 207         __nis_single_value_t    *v;
 208         char                    **inName = *inNameP;
 209         __nis_value_t           *inVal = *inValP;
 210         int                     num = *numP;
 211         int                     (*comp)(const char *s1, const char *s2);
 212         char                    *myself = "addVal2RuleValue";
 213 
 214         /* Internal function, so assume arguments OK */
 215 
 216         if (msg == 0)
 217                 msg = myself;
 218 
 219         /* Should we match the 'inName' value case sensitive or not ? */
 220         if (caseSens)
 221                 comp = strcmp;
 222         else
 223                 comp = strcasecmp;
 224 
 225         /*
 226          * String-valued NIS+ entries count the concluding NUL in the
 227          * length, while LDAP entries don't. In order to support this,
 228          * we implement the following for vt_string value types:
 229          *
 230          * If the last byte of the value isn't a NUL, add one to the
 231          * allocated length, so that there always is a NUL after the
 232          * value, making it safe to pass to strcmp() etc.
 233          *
 234          * If 'snipNul' is set (presumably meaning we're inserting a
 235          * value derived from a NIS+ entry), and the last byte of the
 236          * value already is a NUL, decrement the length to be copied by
 237          * one. This (a) doesn't count the NUL in the value length, but
 238          * (b) still leaves a NUL following the value.
 239          *
 240          * In N2L, for all cases we set 'copyLen' to the number of non-0
 241          * characters in 'value'.
 242          */
 243         if (type == vt_string && valueLen > 0) {
 244                 char    *charval = value;
 245 
 246                 if (charval[valueLen-1] != '\0')
 247                         valueLen += 1;
 248                 else if (yp2ldap || snipNul)
 249                         copyLen -= 1;
 250         } else if (valueLen == 0) {
 251                 /*
 252                  * If the 'value' pointer is non-NULL, we create a zero-
 253                  * length value with one byte allocated. This takes care
 254                  * of empty strings.
 255                  */
 256                 valueLen += 1;
 257         }
 258 
 259         /* If we already have values for this attribute, add another one */
 260         for (i = 0; i < num; i++) {
 261                 if ((*comp)(inName[i], name) == 0) {
 262 
 263                         /*
 264                          * Our caller often doesn't know the type of the
 265                          * value; this happens because the type (vt_string
 266                          * or vt_ber) is determined by the format in the
 267                          * rule sets, and we may be invoked as a preparation
 268                          * for evaluating the rules. Hence, we only use the
 269                          * supplied 'type' if we need to create a value.
 270                          * Otherwise, we accept mixed types.
 271                          *
 272                          * Strings are OK in any case, since we always make
 273                          * sure to have a zero byte at the end of any value,
 274                          * whatever the type.
 275                          */
 276 
 277                         if (inVal[i].numVals < 0) {
 278                                 /*
 279                                  * Used to indicate deletion of attribute,
 280                                  * so we honor that and don't add a value.
 281                                  */
 282                                 return (0);
 283                         }
 284 
 285                         /*
 286                          * If 'value' is NULL, we should delete, so
 287                          * remove any existing values, and set the
 288                          * 'numVals' field to -1.
 289                          */
 290                         if (value == 0) {
 291                                 for (j = 0; j < inVal[i].numVals; j++) {
 292                                         sfree(inVal[i].val[j].value);
 293                                 }
 294                                 sfree(inVal[i].val);
 295                                 inVal[i].val = 0;
 296                                 inVal[i].numVals = -1;
 297                                 return (0);
 298                         }
 299 
 300                         /* Is the value a duplicate ? */
 301                         for (j = 0; j < inVal[i].numVals; j++) {
 302                                 if (copyLen == inVal[i].val[j].length &&
 303                                         memcmp(value, inVal[i].val[j].value,
 304                                                 copyLen) == 0) {
 305                                         break;
 306                                 }
 307                         }
 308                         if (j < inVal[i].numVals)
 309                                 return (0);
 310 
 311                         /* Not a duplicate, so add the name/value pair */
 312                         v = realloc(inVal[i].val,
 313                                         (inVal[i].numVals+1) *
 314                                         sizeof (inVal[i].val[0]));
 315                         if (v == 0)
 316                                 return (-1);
 317                         inVal[i].val = v;
 318                         v[inVal[i].numVals].length = copyLen;
 319                         v[inVal[i].numVals].value = am(msg, valueLen);
 320                         if (v[inVal[i].numVals].value == 0 &&
 321                                         value != 0) {
 322                                 sfree(v);
 323                                 return (-1);
 324                         }
 325                         memcpy(v[inVal[i].numVals].value, value, copyLen);
 326                         inVal[i].numVals++;
 327 
 328                         return (0);
 329                 }
 330         }
 331 
 332         /* No previous value for this attribute */
 333 
 334         /*
 335          * value == 0 means deletion, in which case we create a
 336          * __nis_value_t with the numVals field set to -1.
 337          */
 338         if (value != 0) {
 339                 if ((v = am(msg, sizeof (*v))) == 0)
 340                         return (-1);
 341                 v->length = copyLen;
 342                 v->value = am(msg, valueLen);
 343                 if (v->value == 0 && value != 0) {
 344                         sfree(v);
 345                         return (-1);
 346                 }
 347                 memcpy(v->value, value, copyLen);
 348         }
 349 
 350         inVal = realloc(inVal, (num+1)*sizeof (inVal[0]));
 351         if (inVal == 0) {
 352                 if (value != 0) {
 353                         sfree(v->value);
 354                         sfree(v);
 355                 }
 356                 return (-1);
 357         }
 358         *inValP = inVal;
 359 
 360         inName = realloc(inName,
 361                 (num+1)*sizeof (inName[0]));
 362         if (inName == 0 || (inName[num] =
 363                         sdup(msg, T, name)) == 0) {
 364                 sfree(v->value);
 365                 sfree(v);
 366                 return (-1);
 367         }
 368         *inNameP = inName;
 369 
 370         inVal[num].type = type;
 371         inVal[num].repeat = 0;
 372         if (value != 0) {
 373                 inVal[num].numVals = 1;
 374                 inVal[num].val = v;
 375         } else {
 376                 inVal[num].numVals = -1;
 377                 inVal[num].val = 0;
 378         }
 379 
 380         *numP += 1;
 381 
 382         return (0);
 383 }
 384 
 385 int
 386 addAttr2RuleValue(__nis_value_type_t type, char *name, void *value,
 387                 int valueLen, __nis_rule_value_t *rv) {
 388         char                    *myself = "addAttr2RuleValue";
 389 
 390         if (name == 0 || rv == 0)
 391                 return (-1);
 392 
 393         return (addVal2RuleValue(myself, 0, 0, type, name, value, valueLen,
 394                                 &rv->numAttrs, &rv->attrName, &rv->attrVal));
 395 }
 396 
 397 int
 398 addSAttr2RuleValue(char *name, char *value, __nis_rule_value_t *rv) {
 399         return (addAttr2RuleValue(vt_string, name, value, slen(value), rv));
 400 }
 401 
 402 int
 403 addCol2RuleValue(__nis_value_type_t type, char *name, void *value,
 404                 int valueLen, __nis_rule_value_t *rv) {
 405         char *myself = "addCol2RuleValue";
 406 
 407         if (name == 0 || rv == 0)
 408                 return (-1);
 409 
 410         return (addVal2RuleValue(myself, 1, 1, type, name, value, valueLen,
 411                                 &rv->numColumns, &rv->colName, &rv->colVal));
 412 }
 413 
 414 int
 415 addSCol2RuleValue(char *name, char *value, __nis_rule_value_t *rv) {
 416         return (addCol2RuleValue(vt_string, name, value, slen(value), rv));
 417 }
 418 
 419 /*
 420  * Given a table mapping, a NIS+ DB query, and (optionally) an existing
 421  * and compatible __nis_rule_value_t, return a new __nis_rule_value_t
 422  * with the values from the query added.
 423  */
 424 __nis_rule_value_t *
 425 buildNisPlusRuleValue(__nis_table_mapping_t *t, db_query *q,
 426                         __nis_rule_value_t *rv) {
 427         int                     i;
 428         __nis_single_value_t    *sv;
 429         char                    *myself = "buildNisPlusRuleValue";
 430 
 431         if (t == 0 || q == 0)
 432                 return (0);
 433 
 434         rv = initRuleValue(1, rv);
 435         if (rv == 0)
 436                 return (0);
 437 
 438         for (i = 0; i < q->components.components_len; i++) {
 439                 int     ic;
 440                 int     iv, v, dup;
 441                 int     len;
 442 
 443                 /* Ignore out-of-range column index */
 444                 if (q->components.components_val[i].which_index >=
 445                                 t->numColumns)
 446                         continue;
 447 
 448                 /*
 449                  * Add the query value. A NULL value indicates deletion,
 450                  * but addCol2RuleValue() takes care of that for us.
 451                  */
 452                 if (addCol2RuleValue(vt_string,
 453                                 t->column[q->components.components_val[i].
 454                                                 which_index],
 455                                 q->components.components_val[i].index_value->
 456                                         itemvalue.itemvalue_val,
 457                                 q->components.components_val[i].index_value->
 458                                         itemvalue.itemvalue_len, rv) != 0) {
 459                         freeRuleValue(rv, 1);
 460                         rv = 0;
 461                         break;
 462                 }
 463         }
 464 
 465         return (rv);
 466 }
 467 
 468 
 469 /*
 470  * Given a LHS rule 'rl', return an array containing the item names,
 471  * and the number of elements in the array in '*numItems'.
 472  *
 473  * If there are 'me_match' __nis_mapping_element_t's, we use the
 474  * supplied '*rval' (if any) to derive values for the items in
 475  * the 'me_match', and add the values thus derived to '*rval' (in
 476  * which case the '*rval' pointer will change; the old '*rval'
 477  * is deleted).
 478  */
 479 __nis_mapping_item_t *
 480 buildLvalue(__nis_mapping_rlhs_t *rl, __nis_value_t **rval, int *numItems) {
 481         __nis_value_t           *val, *r;
 482         __nis_mapping_item_t    *item = 0;
 483         int                     i, n, ni = 0, nv = 0;
 484         int                     repeat = 0;
 485 
 486         if (rl == 0)
 487                 return (0);
 488 
 489         if (rval != 0) {
 490                 r = *rval;
 491                 repeat = r->repeat;
 492         } else
 493                 r = 0;
 494 
 495         /* If there is more than one element, we concatenate the items */
 496         for (i = 0; i < rl->numElements; i++) {
 497                 __nis_mapping_element_t *e = &rl->element[i];
 498                 __nis_mapping_item_t    *olditem, *tmpitem = 0;
 499                 __nis_value_t           **tmp;
 500 
 501                 switch (e->type) {
 502                 case me_item:
 503                         tmpitem = cloneItem(&e->element.item);
 504                         break;
 505                 case me_match:
 506                         /*
 507                          * Obtain values for the items in the 'me_match'
 508                          * element.
 509                          */
 510                         tmp = matchMappingItem(e->element.match.fmt, r, &nv,
 511                                 0, 0);
 512                         if (tmp != 0) {
 513                                 freeValue(r, 1);
 514                                 val = 0;
 515                                 for (n = 0; n < nv; n++) {
 516                                         r = concatenateValues(val, tmp[n]);
 517                                         freeValue(val, 1);
 518                                         freeValue(tmp[n], 1);
 519                                         val = r;
 520                                         if (val == 0) {
 521                                                 for (n++; n < nv; n++) {
 522                                                         freeValue(tmp[n], 1);
 523                                                 }
 524                                                 break;
 525                                         }
 526                                 }
 527                                 free(tmp);
 528                                 if (rval != 0) {
 529                                         if (repeat && val != 0)
 530                                                 val->repeat = repeat;
 531                                         *rval = val;
 532                                 }
 533                                 for (n = 0; n < e->element.match.numItems;
 534                                                 n++) {
 535                                         olditem = item;
 536                                         item = concatenateMappingItem(item, ni,
 537                                                 &e->element.match.item[n]);
 538                                         freeMappingItem(olditem, ni);
 539                                         if (item == 0) {
 540                                                 ni = 0;
 541                                                 break;
 542                                         }
 543                                         ni++;
 544                                 }
 545                         }
 546                         break;
 547                 case me_print:
 548                 case me_split:
 549                 case me_extract:
 550                 default:
 551                         /* These shouldn't show up on the LHS; ignore */
 552                         break;
 553                 }
 554 
 555                 if (tmpitem != 0) {
 556                         olditem = item;
 557                         item = concatenateMappingItem(item, ni, tmpitem);
 558                         freeMappingItem(olditem, ni);
 559                         freeMappingItem(tmpitem, 1);
 560                         ni++;
 561                         if (item == 0) {
 562                                 ni = 0;
 563                                 break;
 564                         }
 565                 }
 566         }
 567 
 568         if (numItems != 0)
 569                 *numItems = ni;
 570 
 571         return (item);
 572 }
 573 
 574 __nis_value_t *
 575 buildRvalue(__nis_mapping_rlhs_t *rl, __nis_mapping_item_type_t native,
 576                 __nis_rule_value_t *rv, int *stat) {
 577         __nis_value_t   *val, *vold = 0, *vnew;
 578         int             i;
 579         char            *myself = "buildRvalue";
 580 
 581         if (rl == 0 || rl->numElements <= 0) {
 582                 /*
 583                  * No RHS indicates deletion, as does a __nis_value_t
 584                  * with numVals == -1, so we return such a creature.
 585                  */
 586                 val = am(myself, sizeof (*val));
 587                 if (val != 0) {
 588                         val->type = vt_string;
 589                         val->numVals = -1;
 590                 }
 591                 return (val);
 592         }
 593 
 594         /* If there is more than one element, we concatenate the values */
 595         for (i = 0; i < rl->numElements; i++) {
 596                 vnew = getMappingElement(&rl->element[i], native, rv, stat);
 597                 val = concatenateValues(vold, vnew);
 598                 freeValue(vnew, 1);
 599                 freeValue(vold, 1);
 600                 vold = val;
 601         }
 602         return (val);
 603 }
 604 
 605 /*
 606  * Derive values for the LDAP attributes specified by the rule 'r',
 607  * and add them to the rule-value 'rv'.
 608  *
 609  * If 'doAssign' is set, out-of-context assignments are performed,
 610  * otherwise not.
 611  */
 612 __nis_rule_value_t *
 613 addLdapRuleValue(__nis_table_mapping_t *t,
 614                         __nis_mapping_rule_t *r,
 615                         __nis_mapping_item_type_t lnative,
 616                         __nis_mapping_item_type_t rnative,
 617                         __nis_rule_value_t *rv,
 618                         int doAssign, int *stat) {
 619         int                     i, j;
 620         char                    **new;
 621         __nis_value_t           *rval, *lval;
 622         __nis_buffer_t          b = {0, 0};
 623         __nis_mapping_item_t    *litem;
 624         int                     numItems;
 625         char                    **dn = 0;
 626         int                     numDN = 0;
 627         char                    *myself = "addLdapRuleValue";
 628 
 629 
 630         /* Do we have the required values ? */
 631         if (rv == 0)
 632                 return (0);
 633 
 634         /*
 635          * Establish appropriate search base. For rnative == mit_nisplus,
 636          * we're deriving LDAP attribute values from NIS+ columns; in other
 637          * words, we're writing to LDAP, and should use the write.base value.
 638          */
 639         __nisdb_get_tsd()->searchBase = (rnative == mit_nisplus) ?
 640                 t->objectDN->write.base : t->objectDN->read.base;
 641 
 642         /* Set escapeFlag if LHS is "dn" to escape special chars */
 643         if (yp2ldap && r->lhs.numElements == 1 &&
 644                 r->lhs.element->type == me_item &&
 645                 r->lhs.element->element.item.type == mit_ldap &&
 646                 strcasecmp(r->lhs.element->element.item.name, "dn") == 0) {
 647                         __nisdb_get_tsd()->escapeFlag = '1';
 648         }
 649 
 650         /* Build the RHS value */
 651         rval = buildRvalue(&r->rhs, rnative, rv, stat);
 652 
 653         /* Reset escapeFlag */
 654         __nisdb_get_tsd()->escapeFlag = '\0';
 655 
 656         if (rval == 0)
 657                 return (rv);
 658 
 659         /*
 660          * Special case: If we got no value for the RHS (presumably because
 661          * we're missing one or more item values), we don't produce an lval.
 662          * Note that this isn't the same thing as an empty value, which we
 663          * faithfully try to transmit to LDAP.
 664          */
 665         if (rval->numVals == 1 && rval->val[0].value == 0) {
 666                 freeValue(rval, 1);
 667                 return (rv);
 668         }
 669 
 670         /* Obtain the LHS item names */
 671         litem = buildLvalue(&r->lhs, &rval, &numItems);
 672         if (litem == 0) {
 673                 freeValue(rval, 1);
 674                 return (rv);
 675         }
 676 
 677         /* Get string representations of the LHS item names */
 678         lval = 0;
 679         for (i = 0; i < numItems; i++) {
 680                 __nis_value_t   *tmpval, *old;
 681 
 682                 tmpval = getMappingItem(&litem[i], lnative, 0, 0, NULL);
 683 
 684                 /*
 685                  * If the LHS item is out-of-context, we do the
 686                  * assignment right here.
 687                  */
 688                 if (doAssign && litem[i].type == mit_ldap &&
 689                                 litem[i].searchSpec.triple.scope !=
 690                                         LDAP_SCOPE_UNKNOWN &&
 691                                 slen(litem[i].searchSpec.triple.base) > 0 &&
 692                                 (slen(litem[i].searchSpec.triple.attrs) > 0 ||
 693                                 litem[i].searchSpec.triple.element != 0)) {
 694                         int     stat;
 695 
 696                         if (dn == 0)
 697                                 dn = findDNs(myself, rv, 1,
 698                                         t->objectDN->write.base,
 699                                         &numDN);
 700 
 701                         stat = storeLDAP(&litem[i], i, numItems, rval,
 702                                 t->objectDN, dn, numDN);
 703                         if (stat != LDAP_SUCCESS) {
 704                                 char    *iname = "<unknown>";
 705 
 706                                 if (tmpval != 0 &&
 707                                                 tmpval->numVals == 1)
 708                                         iname = tmpval->val[0].value;
 709                                 logmsg(MSG_NOTIMECHECK, LOG_ERR,
 710                                         "%s: LDAP store \"%s\": %s",
 711                                         myself, iname,
 712                                         ldap_err2string(stat));
 713                         }
 714 
 715                         freeValue(tmpval, 1);
 716                         continue;
 717                 }
 718 
 719                 old = lval;
 720                 lval = concatenateValues(old, tmpval);
 721                 freeValue(tmpval, 1);
 722                 freeValue(old, 1);
 723         }
 724 
 725         /* Don't need the LHS items themselves anymore */
 726         freeMappingItem(litem, numItems);
 727 
 728         /*
 729          * If we don't have an 'lval' (probably because all litem[i]:s
 730          * were out-of-context assignments), we're done.
 731          */
 732         if (lval == 0 || lval->numVals <= 0) {
 733                 freeValue(lval, 1);
 734                 freeValue(rval, 1);
 735                 return (rv);
 736         }
 737 
 738         for (i = 0, j = 0; i < lval->numVals; i++) {
 739                 /* Special case: rval->numVals < 0 means deletion */
 740                 if (rval->numVals < 0) {
 741                         (void) addAttr2RuleValue(rval->type,
 742                                 lval->val[i].value, 0, 0, rv);
 743                         continue;
 744                 }
 745                 /* If we're out of values, repeat the last one */
 746                 if (j >= rval->numVals)
 747                         j = (rval->numVals > 0) ? rval->numVals-1 : 0;
 748                 for (0; j < rval->numVals; j++) {
 749                         /*
 750                          * If this is the 'dn', and the value ends in a
 751                          * comma, append the appropriate search base.
 752                          */
 753                         if (strcasecmp("dn", lval->val[i].value) == 0 &&
 754                                         lastChar(&rval->val[j]) == ',' &&
 755                                         t->objectDN->write.scope !=
 756                                                 LDAP_SCOPE_UNKNOWN) {
 757                                 void    *nval;
 758                                 int     nlen = -1;
 759 
 760                                 nval = appendString2SingleVal(
 761                                         t->objectDN->write.base, &rval->val[j],
 762                                         &nlen);
 763                                 if (nval != 0 && nlen >= 0) {
 764                                         sfree(rval->val[j].value);
 765                                         rval->val[j].value = nval;
 766                                         rval->val[j].length = nlen;
 767                                 }
 768                         }
 769                         (void) addAttr2RuleValue(rval->type,
 770                                 lval->val[i].value, rval->val[j].value,
 771                                 rval->val[j].length, rv);
 772                         /*
 773                          * If the lval is multi-valued, go on to the
 774                          * other values; otherwise, quit (but increment
 775                          * the 'rval' value index).
 776                          */
 777                         if (!lval->repeat) {
 778                                 j++;
 779                                 break;
 780                         }
 781                 }
 782         }
 783 
 784         /* Clean up */
 785         freeValue(lval, 1);
 786         freeValue(rval, 1);
 787 
 788         return (rv);
 789 }
 790 
 791 /*
 792  * Remove the indicated attribute, and any values for it, from the
 793  * rule-value.
 794  */
 795 void
 796 delAttrFromRuleValue(__nis_rule_value_t *rv, char *attrName) {
 797         int     i;
 798 
 799         if (rv == 0 || attrName == 0)
 800                 return;
 801 
 802         for (i = 0; i < rv->numAttrs; i++) {
 803                 if (strcasecmp(attrName, rv->attrName[i]) == 0) {
 804                         int     j;
 805 
 806                         for (j = 0; j < rv->attrVal[i].numVals; j++)
 807                                 sfree(rv->attrVal[i].val[j].value);
 808                         if (rv->attrVal[i].numVals > 0)
 809                                 sfree(rv->attrVal[i].val);
 810 
 811                         sfree(rv->attrName[i]);
 812 
 813                         /* Move up the rest of the attribute names/values */
 814                         for (j = i+1; j < rv->numAttrs; j++) {
 815                                 rv->attrName[j-1] = rv->attrName[j];
 816                                 rv->attrVal[j-1] = rv->attrVal[j];
 817                         }
 818 
 819                         rv->numAttrs -= 1;
 820 
 821                         break;
 822                 }
 823         }
 824 }
 825 
 826 /*
 827  * Remove the indicated column, and any values for it, from the
 828  * rule-value.
 829  */
 830 void
 831 delColFromRuleValue(__nis_rule_value_t *rv, char *colName) {
 832         int     i;
 833 
 834         if (rv == 0 || colName == 0)
 835                 return;
 836 
 837         for (i = 0; i < rv->numColumns; i++) {
 838                 if (strcmp(colName, rv->colName[i]) == 0) {
 839                         int     j;
 840 
 841                         for (j = 0; j < rv->colVal[i].numVals; j++)
 842                                 sfree(rv->colVal[i].val[j].value);
 843                         if (rv->colVal[i].numVals > 0)
 844                                 sfree(rv->colVal[i].val);
 845 
 846                         sfree(rv->colName[i]);
 847 
 848                         /* Move up the rest of the column names/values */
 849                         for (j = i+1; j < rv->numColumns; j++) {
 850                                 rv->colName[j-1] = rv->colName[j];
 851                                 rv->colVal[j-1] = rv->colVal[j];
 852                         }
 853 
 854                         rv->numColumns -= 1;
 855 
 856                         break;
 857                 }
 858         }
 859 }
 860 
 861 /*
 862  * Add the write-mode object classes specified by 'objClassAttrs' to the
 863  * rule-value 'rv'.
 864  * If there's an error, 'rv' is deleted, and NULL returned.
 865  */
 866 __nis_rule_value_t *
 867 addObjectClasses(__nis_rule_value_t *rv, char *objClassAttrs) {
 868         char    *filter = 0, **fc = 0;
 869         int     i, nfc = 0;
 870 
 871         /*
 872          * Expect to only use this for existing rule-values, so rv == 0 is
 873          * an error.
 874          */
 875         if (rv == 0)
 876                 return (0);
 877 
 878         /*
 879          * If 'objClassAttrs' is NULL, we trivially have nothing to do.
 880          * Assume the caller knows what it's doing, and return success.
 881          */
 882         if (objClassAttrs == 0)
 883                 return (rv);
 884 
 885         /*
 886          * Make an AND-filter of the object classes, and split into
 887          * components. (Yes, this is a bit round-about, but leverages
 888          * existing functions.)
 889          */
 890         filter = makeFilter(objClassAttrs);
 891         if (filter == 0) {
 892                 freeRuleValue(rv, 1);
 893                 return (0);
 894         }
 895 
 896         fc = makeFilterComp(filter, &nfc);
 897         if (fc == 0 || nfc <= 0) {
 898                 free(filter);
 899                 freeRuleValue(rv, 1);
 900                 return (0);
 901         }
 902 
 903         /* Add the objectClass attributes to the rule-value */
 904         for (i = 0; i < nfc; i++) {
 905                 char    *name, *value;
 906 
 907                 name = fc[i];
 908                 /* Skip if not of the "name=value" form */
 909                 if ((value = strchr(name, '=')) == 0)
 910                         continue;
 911 
 912                 *value = '\0';
 913                 value++;
 914 
 915                 /* Skip if the attribute name isn't "objectClass" */
 916                 if (strcasecmp("objectClass", name) != 0)
 917                         continue;
 918 
 919                 if (addSAttr2RuleValue(name, value, rv) != 0) {
 920                         free(filter);
 921                         freeFilterComp(fc, nfc);
 922                         freeRuleValue(rv, 1);
 923                         return (0);
 924                 }
 925         }
 926 
 927         free(filter);
 928         freeFilterComp(fc, nfc);
 929 
 930         return (rv);
 931 }
 932 
 933 
 934 static char *
 935 valString(__nis_value_t *val) {
 936         int     i;
 937 
 938         if (val == 0 || val->type != vt_string)
 939                 return (0);
 940 
 941         for (i = 0; i < val->numVals; i++) {
 942                 /* Look for a non-NULL, non-zero length value */
 943                 if (val->val[i].value != 0 && val->val[i].length > 0) {
 944                         char    *v = val->val[i].value;
 945 
 946                         /*
 947                          * Check that there's a NUL at the end. True,
 948                          * if there isn't, we may be looking beyond
 949                          * allocated memory. However, we would have done
 950                          * so in any case when the supposed string was
 951                          * traversed (printed, etc.), very possibly by
 952                          * a lot more than one byte. So, it's better to
 953                          * take a small risk here than a large one later.
 954                          */
 955                         if (v[val->val[i].length-1] == '\0' ||
 956                                         v[val->val[i].length] == '\0')
 957                                 return (v);
 958                 }
 959         }
 960 
 961         return (0);
 962 }
 963 
 964 char *
 965 findVal(char *name, __nis_rule_value_t *rv, __nis_mapping_item_type_t type) {
 966         int     i;
 967 
 968         if (type == mit_nisplus) {
 969                 for (i = 0; i < rv->numColumns; i++) {
 970                         if (rv->colName[i] == 0)
 971                                 continue;
 972                         if (strcmp(name, rv->colName[i]) == 0) {
 973                                 return (valString(&rv->colVal[i]));
 974                         }
 975                 }
 976         } else if (type == mit_ldap) {
 977                 for (i = 0; i < rv->numAttrs; i++) {
 978                         if (rv->attrName[i] == 0)
 979                                 continue;
 980                         if (strcasecmp(name, rv->attrName[i]) == 0) {
 981                                 return (valString(&rv->attrVal[i]));
 982                         }
 983                 }
 984         }
 985 
 986         return (0);
 987 }
 988 
 989 static char     *norv = "<NIL>";
 990 static char     *unknown = "<unknown>";
 991 
 992 /*
 993  * Attempt to derive a string identifying the rule-value 'rv'. The
 994  * returned string is a pointer, either into 'rv', or to static
 995  * storage, and must not be freed.
 996  */
 997 char *
 998 rvId(__nis_rule_value_t *rv, __nis_mapping_item_type_t type) {
 999         char    *v;
1000 
1001         if (rv == 0)
1002                 return (norv);
1003 
1004         if (rv->numColumns > 0 && type == mit_nisplus) {
1005                 /*
1006                  * Look for a column called "cname" or "name".
1007                  * If that fails, try "key" or "alias".
1008                  */
1009                 if ((v = findVal("cname", rv, type)) != 0)
1010                         return (v);
1011                 else if ((v = findVal("name", rv, type)) != 0)
1012                         return (v);
1013                 else if ((v = findVal("key", rv, type)) != 0)
1014                         return (v);
1015                 else if ((v = findVal("alias", rv, type)) != 0)
1016                         return (v);
1017         } else if (rv->numAttrs > 0 && type == mit_ldap) {
1018                 /*
1019                  * Look for "dn", or "cn".
1020                  */
1021                 if ((v = findVal("dn", rv, type)) != 0)
1022                         return (v);
1023                 else if ((v = findVal("cn", rv, type)) != 0)
1024                         return (v);
1025         }
1026 
1027         return (unknown);
1028 }
1029 
1030 /*
1031  * Merge the rule-values with the same DN into one. Each rule-value
1032  * in the returned array will have unique 'dn'. On entry, *numVals
1033  * contains the number of rule-values in 'rv'. On exit, it contains
1034  * the number of rule-values in the returned array or -1 on error.
1035  */
1036 __nis_rule_value_t *
1037 mergeRuleValueWithSameDN(__nis_rule_value_t *rv, int *numVals) {
1038         __nis_rule_value_t      *rvq = 0;
1039         char                    *dn, *odn;
1040         int                     count = 0;
1041         int                     i, j;
1042 
1043         if (numVals == 0)
1044                 return (0);
1045 
1046         for (i = 0; i < *numVals; i++) {
1047                 if ((dn = findVal("dn", &rv[i], mit_ldap)) != 0) {
1048                         for (j = 0; j < count; j++) {
1049                                 if ((odn = findVal("dn", &rvq[j],
1050                                                 mit_ldap)) != 0) {
1051                                         /* case sensitive compare */
1052                                         if (strcmp(dn, odn) != 0)
1053                                                 continue;
1054                                         if (mergeRuleValue(&rvq[j],
1055                                                         &rv[i]) == -1) {
1056                                                 freeRuleValue(rvq, count);
1057                                                 *numVals = -1;
1058                                                 return (0);
1059                                         }
1060                                         break;
1061                                 } else {
1062                                         freeRuleValue(rvq, count);
1063                                         *numVals = -1;
1064                                         return (0);
1065                                 }
1066                         }
1067                         /* if no match, then add it to the rulevalue array */
1068                         if (j == count) {
1069                                 rvq = growRuleValue(count, count + 1, rvq,
1070                                                                         &rv[i]);
1071                                 if (rvq == 0) {
1072                                         *numVals = -1;
1073                                         return (0);
1074                                 }
1075                                 count++;
1076                         }
1077                 }
1078         }
1079 
1080         *numVals = count;
1081         return (rvq);
1082 }