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 <strings.h>
  28 #include <string.h>
  29 #include <lber.h>
  30 #include <ldap.h>
  31 
  32 #include "db_item_c.h"
  33 
  34 #include "nisdb_mt.h"
  35 
  36 #include "ldap_util.h"
  37 #include "ldap_structs.h"
  38 #include "ldap_val.h"
  39 #include "ldap_ruleval.h"
  40 #include "ldap_op.h"
  41 #include "ldap_nisdbquery.h"
  42 #include "ldap_attr.h"
  43 #include "ldap_xdr.h"
  44 
  45 
  46 item *
  47 buildItem(int len, void *value) {
  48         char    *myself = "buildItem";
  49         item    *i = am(myself, sizeof (*i));
  50         int     mlen = len;
  51 
  52         if (i == 0)
  53                 return (0);
  54 
  55         /*
  56          * To this function, a NULL value, or a length less than or equal
  57          * zero means an item with no value. Hence, buildItem(0, 0) is
  58          * _not_ the right way to create index_value == 0 to indicate
  59          * deletion.
  60          */
  61         if (value == 0 || len <= 0) {
  62                 i->itemvalue.itemvalue_len = 0;
  63                 i->itemvalue.itemvalue_val = 0;
  64                 return (i);
  65         }
  66 
  67         /*
  68          * NIS+ usually stores the terminating NUL for strings, so we add
  69          * it here just in case. This means we usually waste a byte for
  70          * binary column values...
  71          */
  72         if (len > 0 && ((char *)value)[len-1] != '\0')
  73                 mlen++;
  74 
  75         i->itemvalue.itemvalue_len = len;
  76         i->itemvalue.itemvalue_val = am(myself, mlen);
  77         if (mlen > 0 && i->itemvalue.itemvalue_val == 0) {
  78                 free(i);
  79                 return (0);
  80         }
  81         memcpy(i->itemvalue.itemvalue_val, value, len);
  82 
  83         return (i);
  84 }
  85 
  86 void
  87 freeItem(item *i) {
  88         if (i != 0) {
  89                 sfree(i->itemvalue.itemvalue_val);
  90                 free(i);
  91         }
  92 }
  93 
  94 void
  95 freeQcomp(db_qcomp *qc, int doFree) {
  96 
  97         if (qc == 0)
  98                 return;
  99 
 100         freeItem(qc->index_value);
 101         if (doFree)
 102                 free(qc);
 103 }
 104 
 105 db_query *
 106 buildQuery(int num_components, db_qcomp *components) {
 107         char            *myself = "buildQuery";
 108         db_query        *q = am(myself, sizeof (*q));
 109 
 110         if (q == 0)
 111                 return (0);
 112 
 113         q->components.components_len = num_components;
 114         q->components.components_val = components;
 115 
 116         return (q);
 117 }
 118 
 119 /*
 120  * Clone a db_query. The 'numComps' parameter can be used to specify
 121  * the number of db_qcomp's to allocate (in the 'components.components_val'
 122  * array), if 'components.components_len' hasn't yet reached its expected
 123  * maximum value.
 124  */
 125 db_query *
 126 cloneQuery(db_query *old, int numComps) {
 127         db_query        *new;
 128         int             i;
 129         char            *myself = "cloneQuery";
 130 
 131         if (old == 0)
 132                 return (0);
 133 
 134         new = am(myself, sizeof (*new));
 135         if (new == 0)
 136                 return (0);
 137 
 138         if (old->components.components_len > numComps)
 139                 numComps = old->components.components_len;
 140 
 141         new->components.components_val = am(myself,
 142                                 sizeof (new->components.components_val[0]) *
 143                                 numComps);
 144         if (numComps > 0 && new->components.components_val == 0) {
 145                 free(new);
 146                 return (0);
 147         }
 148 
 149         for (i = 0; i < old->components.components_len; i++) {
 150                 item    *it;
 151 
 152                 if (old->components.components_val[i].index_value == 0) {
 153                         new->components.components_val[i].index_value = 0;
 154                         new->components.components_val[i].which_index =
 155                                 old->components.components_val[i].which_index;
 156                         continue;
 157                 }
 158 
 159                 it = buildItem(old->components.components_val[i].index_value->
 160                                         itemvalue.itemvalue_len,
 161                                 old->components.components_val[i].index_value->
 162                                         itemvalue.itemvalue_val);
 163 
 164                 if (it == 0) {
 165                         new->components.components_len = i + 1;
 166                         freeQuery(new);
 167                         return (0);
 168                 }
 169 
 170                 new->components.components_val[i].index_value = it;
 171                 new->components.components_val[i].which_index =
 172                         old->components.components_val[i].which_index;
 173         }
 174 
 175         new->components.components_len = old->components.components_len;
 176 
 177         return (new);
 178 }
 179 
 180 void
 181 freeQuery(db_query *q) {
 182         int     i;
 183 
 184         if (q == 0)
 185                 return;
 186 
 187         for (i = 0; i < q->components.components_len; i++) {
 188                 freeItem(q->components.components_val[i].index_value);
 189         }
 190 
 191         sfree(q->components.components_val);
 192         sfree(q);
 193 }
 194 
 195 void
 196 freeQueries(db_query **q, int numQ) {
 197         int     i;
 198 
 199         if (q == 0)
 200                 return;
 201 
 202         for (i = 0; i < numQ; i++)
 203                 freeQuery(q[i]);
 204 
 205         sfree(q);
 206 }
 207 
 208 /*
 209  * Given an array index[0..num-1] of pointers to strings of the form
 210  * "name=value", create the corresponding db_queries. "name=" indicates
 211  * deletion, which results in a db_query component where index_value == 0.
 212  *
 213  * The __nis_table_mapping_t structure is used to translate column
 214  * names to indices.
 215  *
 216  * If 'rvP' is non-NULL, the searchable columns from the 'index'
 217  * name/value pairs are used to retrieve copies of the corresponding NIS+
 218  * entries, and '*rvP' is initialized with the current entry values
 219  * and object attributes. Names/values supplied in 'index' override
 220  * those from existing NIS+ entries.
 221  */
 222 db_query **
 223 createQuery(int num, char **index, __nis_table_mapping_t *t,
 224                 __nis_rule_value_t **rvP, int *numVals) {
 225         db_query                **q;
 226         db_qcomp                *qc;
 227         int                     i, j, n, a, nv, niv, stat, sinum;
 228         __nis_rule_value_t      *rvq;
 229         __nis_buffer_t          b = {0, 0};
 230         char                    *table = 0;
 231         char                    *myself = "createQuery";
 232 
 233         rvq = initRuleValue(1, 0);
 234         if (rvq == 0)
 235                 return (0);
 236 
 237         if (numVals == 0)
 238                 numVals = &nv;
 239         *numVals = 0;
 240 
 241         if (rvP != 0) {
 242                 /*
 243                  * Try to obtain a copy of the table object, in order to
 244                  * determine the searchable columns. A failure isn't
 245                  * necessarily fatal; we just try to compose the entire
 246                  * LDAP data from the col=val pairs.
 247                  */
 248                 table = fullObjName(F, t->objName);
 249                 if (table == 0) {
 250                         logmsg(MSG_NOTIMECHECK, LOG_ERR,
 251                                 "%s: Error converting \"%s\" to FQ object name",
 252                                 myself, NIL(t->objName));
 253                         freeRuleValue(rvq, 1);
 254                         return (0);
 255                 }
 256         }
 257 
 258         /* Create a rule-value from the col=val pairs */
 259         for (n = 0; n < num; n++) {
 260                 char    *name;
 261                 char    *value;
 262 
 263                 if ((value = strchr(index[n], '=')) == 0) {
 264                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
 265                                 "%s: no '=' in \"%s\"",
 266                                 myself, index[n]);
 267                         continue;
 268                 }
 269 
 270                 *value = '\0';
 271                 value++;
 272 
 273                 for (a = 0; a < t->numColumns; a++) {
 274                         if (strcmp(index[n], t->column[a]) == 0) {
 275                                 int             i, len = slen(value)+1;
 276 
 277                                 /* Add col=val pair to 'rvq' */
 278                                 if (addSCol2RuleValue(index[n], value, rvq)) {
 279                                         freeRuleValue(rvq, 1);
 280                                         sfree(table);
 281                                         return (0);
 282                                 }
 283 
 284                                 break;
 285                         }
 286                 }
 287                 if (a >= t->numColumns) {
 288                         logmsg(MSG_NOTIMECHECK, LOG_WARNING,
 289                                 "%s: Ignoring unknown column \"%s\"",
 290                                 myself, NIL(index[n]));
 291                 }
 292         }
 293 
 294         /*
 295          * Find out if any of the columns specified via the 'index'
 296          * array are multi-valued.
 297          */
 298         for (n = 0, niv = 1; n < rvq->numColumns; n++) {
 299                 if (rvq->colVal[n].numVals > 1)
 300                         niv *= rvq->colVal[n].numVals;
 301         }
 302 
 303         *numVals = 1;
 304 
 305         sfree(b.buf);
 306         sfree(table);
 307 
 308         if (rvq->numColumns <= 0) {
 309                 freeRuleValue(rvq, *numVals);
 310                 *numVals = 0;
 311                 return (0);
 312         }
 313 
 314         /*
 315          * If any column name was repeated in the col=val pairs (but with
 316          * different values), 'rvq' will have one or more multi-valued
 317          * column values. We now convert those into an array of rule-values
 318          * where every column is single-valued.
 319          *
 320          * Since we want all combinations of column values, the number
 321          * of array elements is the product of all column value counts.
 322          *
 323          * There are four possible combinations of 'index' and NIS+ data:
 324          *
 325          * (1)  Only single-valued 'index' columns, and at most one NIS+
 326          *      entry, so 'rvq' is complete, and '*numVals' == 1.
 327          *
 328          * (2)  Single-valued 'index' columns, but multiple NIS+ entries.
 329          *      '*numVals' reflects the number of NIS+ entries, and no
 330          *      expansion of 'index' column values to array elements is
 331          *      needed.
 332          *
 333          * (3)  At least one multi-valued 'index', and multiple NIS+
 334          *      entries. We already rejected the NIS+ data for this case
 335          *      above, so it is in fact equivalent to case (4).
 336          *
 337          * (4)  At least one multi-valued 'index', but at most one NIS+
 338          *      entry. This is the case where we must expand the multi-valued
 339          *      columns to multiple array elements.
 340          */
 341         if (niv > 1 && *numVals == 1) {
 342                 __nis_rule_value_t      *rv;
 343                 int                     repeat;
 344 
 345                 /*
 346                  * By using initRuleValue() to create 'rv', and make each
 347                  * element a clone of 'rvq', we save a lot of code. The
 348                  * down side is that 'rv' only really needs one element
 349                  * for each rv[].colVal[].val array, but we know that at
 350                  * least one rvq->colVal[].val array has more than one
 351                  * element. Hence, making 'rv' a clone of 'rvq' will waste
 352                  * memory.
 353                  *
 354                  * However, we believe this waste is acceptable, because
 355                  * we expect that 'niv' will be small. Also, we are executing
 356                  * in the context of a utility command, not in a daemon.
 357                  */
 358                 rv = initRuleValue(niv, rvq);
 359                 if (rv == 0) {
 360                         freeRuleValue(rvq, 1);
 361                         *numVals = 0;
 362                         return (0);
 363                 }
 364 
 365                 /*
 366                  * For each column value in 'rvq', copy to the appropriate
 367                  * place in 'rv', so that the end result is that all
 368                  * combinations of values are enumerated, and each
 369                  * 'rv[n].colVal[i]' is single-valued.
 370                  *
 371                  * We do this by traversing the rv[] array 'rvq->numColumns'
 372                  * times, where each traversal 'i' works on the values
 373                  * for rvq->colVal[i]. A repeat factor 'repeat' starts out
 374                  * at '1', and is multiplied by 'rvq->colVal[i].numVals'
 375                  * at the end of each traversal. Every value
 376                  * rvq->colVal[i].val[j] is repeated 'repeat' times.
 377                  *
 378                  * This algorithm works by regarding the rv[] array as
 379                  * an I-dimensional array (I = rvq->numColumns), where
 380                  * each dimension 'i' corresponds to the values for
 381                  * rvq->colVal[i]. The I-dimensional array is stored
 382                  * in column-major order.
 383                  *
 384                  * Since the 'rv' elements start out as copies of 'rvq',
 385                  * we achieve the "copy" of the 'rvq' column values by
 386                  * deleting those we don't want from the 'rv' elements.
 387                  */
 388                 for (i = 0, repeat = 1; i < rvq->numColumns; i++) {
 389                         int     r, k;
 390                         for (n = 0, j = 0, r = 0; n < niv; n++) {
 391                                 /*
 392                                  * Free all but element 'j' of the
 393                                  * rv[n].colVal[i].val array.
 394                                  */
 395                                 for (k = 0; k < rv[n].colVal[i].numVals; k++) {
 396                                         /* Leave element 'j' in place */
 397                                         if (k == j)
 398                                                 continue;
 399                                         sfree(rv[n].colVal[i].val[k].
 400                                                 value);
 401                                 }
 402                                 rv[n].colVal[i].numVals = 1;
 403                                 /* Move element 'j' to zero */
 404                                 if (j != 0)
 405                                         rv[n].colVal[i].val[0] =
 406                                                 rv[n].colVal[i].val[j];
 407 
 408                                 /*
 409                                  * Increment the repeat index 'r'. If >=
 410                                  * 'repeat', reset 'r' and increment the
 411                                  * value index 'j'. If 'j' >=
 412                                  * rvq->colVal[i].numVals, start over on
 413                                  * the column values for column 'i' (i.e.,
 414                                  * reset 'j' to zero).
 415                                  */
 416                                 r += 1;
 417                                 if (r >= repeat) {
 418                                         r = 0;
 419                                         j += 1;
 420                                         if (j >= rvq->colVal[i].numVals)
 421                                                 j = 0;
 422                                 }
 423                         }
 424                         repeat *= rvq->colVal[i].numVals;
 425                 }
 426 
 427                 *numVals = niv;
 428                 freeRuleValue(rvq, 1);
 429                 rvq = rv;
 430                 rv = 0;
 431         }
 432 
 433         q = am(myself, *numVals * sizeof (q[0]));
 434         if (q == 0) {
 435                 freeRuleValue(rvq, *numVals);
 436                 return (0);
 437         }
 438 
 439         /*
 440          * Create queries from the rvq[] array.
 441          */
 442         for (a = 0; a < *numVals; a++) {
 443                 int     nn, err = 0;
 444 
 445                 qc = am(myself, rvq[a].numColumns * sizeof (*qc));
 446                 if (qc != 0) {
 447                         for (nn = 0, i = 0; i < rvq[a].numColumns; i++) {
 448                                 for (j = 0; j < t->numColumns; j++) {
 449                                         if (strcmp(rvq[a].colName[i],
 450                                                         t->column[j]) == 0) {
 451                                                 break;
 452                                         }
 453                                 }
 454                                 if (j >= t->numColumns)
 455                                         continue;
 456                                 qc[nn].which_index = j;
 457                                 if (rvq[a].colVal[i].numVals > 0) {
 458                                         qc[nn].index_value = buildItem(
 459                                                 rvq[a].colVal[i].val[0].length,
 460                                                 rvq[a].colVal[i].val[0].value);
 461                                         if (qc[nn].index_value == 0)
 462                                                 err++;
 463                                 } else {
 464                                         logmsg(MSG_NOTIMECHECK, LOG_ERR,
 465                                                 "%s: No values for [%d]%s",
 466                                                 myself, a, rvq[a].colName[i]);
 467                                         err++;
 468                                 }
 469                                 nn++;
 470                         }
 471                         if (err == 0)
 472                                 q[a] = buildQuery(nn, qc);
 473                 }
 474                 if (err > 0 || q[a] == 0) {
 475                         freeQueries(q, a);
 476                         for (a = 0; a < nn; a++)
 477                                 freeQcomp(&qc[a], F);
 478                         sfree(qc);
 479                         freeRuleValue(rvq, *numVals);
 480                         return (0);
 481                 }
 482         }
 483 
 484         if (rvP != 0) {
 485                 *rvP = rvq;
 486         } else {
 487                 freeRuleValue(rvq, 1);
 488                 *numVals = 0;
 489         }
 490 
 491         return (q);
 492 }
 493 
 494 void
 495 printQuery(db_query *q, __nis_table_mapping_t *t) {
 496         int     i, mc = -1;
 497         char    *myself = "printQuery";
 498         char    *val[NIS_MAXCOLUMNS];
 499 
 500         if (q == 0)
 501                 return;
 502 
 503         (void) memset(val, 0, sizeof (val));
 504 
 505         /*
 506          * Collect the values, which may be out of order in 'q'.
 507          * Remember the largest index.
 508          */
 509         for (i = 0; i < q->components.components_len; i++) {
 510                 int     ix = q->components.components_val[i].which_index;
 511 
 512                 if (ix >= NIS_MAXCOLUMNS ||
 513                                 (t != 0 && ix >= t->numColumns))
 514                         continue;
 515                 if (ix > mc)
 516                         mc = ix;
 517                 val[ix] = q->components.components_val[i].index_value->
 518                                 itemvalue.itemvalue_val;
 519         }
 520 
 521         /* Print the values we collected */
 522         for (i = 0; i <= mc; i++) {
 523                 p2buf(myself, "%s%s", (i != 0 ? " " : ""),
 524                         (val[i] != 0 ? val[i] : ""));
 525         }
 526         /* If we printed anything, add a newline */
 527         if (mc >= 0)
 528                 p2buf(myself, "\n");
 529 }
 530 
 531 /*
 532  * Verify that the db_query's 'q' and 'fq' match, in the sense that if
 533  * they both have a value for a certain index, the values are the same.
 534  */
 535 int
 536 verifyQueryMatch(db_query *q, db_query *fq) {
 537         int     i, j, match;
 538 
 539         if (fq == 0)
 540                 return (1);
 541 
 542         if (q == 0)
 543                 return ((fq == 0) ? 1 : 0);
 544 
 545         for (i = 0, match = 1; match && i < q->components.components_len;
 546                         i++) {
 547                 for (j = 0; j < fq->components.components_len; j++) {
 548                         int     len, flen;
 549 
 550                         /* Same index ? */
 551                         if (q->components.components_val[i].which_index !=
 552                                         fq->components.components_val[j].
 553                                                 which_index)
 554                                 continue;
 555                         /*
 556                          * If one 'index_value' is NULL, the other one must
 557                          * be NULL as well.
 558                          */
 559                         if (q->components.components_val[i].index_value == 0) {
 560                                 if (fq->components.components_val[j].
 561                                                 index_value == 0)
 562                                         continue;
 563                                 else {
 564                                         match = 0;
 565                                         break;
 566                                 }
 567                         }
 568                         if (fq->components.components_val[j].index_value ==
 569                                         0) {
 570                                 match = 0;
 571                                 break;
 572                         }
 573                         /* Same value lengths ? */
 574                         len = q->components.components_val[i].index_value->
 575                                 itemvalue.itemvalue_len;
 576                         flen = fq->components.components_val[j].index_value->
 577                                 itemvalue.itemvalue_len;
 578                         if (len != flen) {
 579                                 /*
 580                                  * There's a twist here: the input query
 581                                  * may well _not_ count a concluding NUL
 582                                  * in a string value, while the output
 583                                  * usually will. So, if the difference in
 584                                  * length is one, and the "extra" byte is
 585                                  * a zero-valued one, we accept equality.
 586                                  * 'q' is assumed to be the output, and
 587                                  * 'fq' the input.
 588                                  */
 589                                 if (!(len > 0 && len == (flen+1) &&
 590                                         q->components.components_val[i].
 591                                         index_value->
 592                                         itemvalue.itemvalue_val[len-1] == 0)) {
 593                                         match = 0;
 594                                         break;
 595                                 }
 596                         }
 597                         /* Same value ? */
 598                         if (memcmp(q->components.components_val[i].index_value->
 599                                         itemvalue.itemvalue_val,
 600                                 fq->components.components_val[j].index_value->
 601                                         itemvalue.itemvalue_val,
 602                                         flen) != 0) {
 603                                 match = 0;
 604                                 break;
 605                         }
 606                 }
 607         }
 608 
 609         return (match);
 610 }
 611 
 612 /*
 613  * Remove those queries in 'q' that don't match t->index.
 614  * Returns a pointer to the filtered array, which could be
 615  * a compacted version of the original, or a new copy; in
 616  * the latter case, the original will have been freed.
 617  *
 618  * Filtered/removed db_query's are freed.
 619  */
 620 db_query **
 621 filterQuery(__nis_table_mapping_t *t, db_query **q, db_query *qin,
 622                 __nis_obj_attr_t ***objAttr, int *numQueries) {
 623         db_query                **new;
 624         __nis_obj_attr_t        **attr;
 625         int                     i, nq, nn;
 626         char                    *myself = "filterQuery";
 627 
 628         if ((t == 0 && qin == 0) || q == 0 ||
 629                         numQueries == 0 || *numQueries <= 0)
 630                 return (q);
 631 
 632         nq = *numQueries;
 633         new = am(myself, nq * sizeof (new[0]));
 634         if (objAttr != 0)
 635                 attr = am(myself, nq * sizeof (attr[0]));
 636         else
 637                 attr = 0;
 638         if (new == 0 || (objAttr != 0 && attr == 0)) {
 639                 sfree(new);
 640                 freeQueries(q, nq);
 641                 sfree(attr);
 642                 if (objAttr != 0) {
 643                         freeObjAttr(*objAttr, nq);
 644                         *objAttr = 0;
 645                 }
 646                 *numQueries = -1;
 647                 return (0);
 648         }
 649 
 650         for (i = 0, nn = 0; i < nq; i++) {
 651                 int     retain = 1;
 652 
 653                 if (t != 0)
 654                         retain = verifyIndexMatch(t, q[i], 0, 0, 0);
 655 
 656                 if (retain && qin != 0)
 657                         retain = verifyQueryMatch(q[i], qin);
 658 
 659                 if (retain) {
 660                         new[nn] = q[i];
 661                         if (objAttr != 0)
 662                                 attr[nn] = (*objAttr)[i];
 663                         nn++;
 664                 } else {
 665                         freeQuery(q[i]);
 666                         q[i] = 0;
 667                         if (objAttr != 0) {
 668                                 freeSingleObjAttr((*objAttr)[i]);
 669                                 (*objAttr)[i] = 0;
 670                         }
 671                 }
 672         }
 673 
 674         /* All q[i]'s are either in 'new', or have been deleted */
 675         free(q);
 676         if (objAttr != 0) {
 677                 sfree(*objAttr);
 678                 *objAttr = attr;
 679         }
 680 
 681         *numQueries = nn;
 682 
 683         return (new);
 684 }
 685 
 686 db_query **
 687 createNisPlusEntry(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
 688                         db_query *qin, __nis_obj_attr_t ***objAttr,
 689                         int *numQueries) {
 690         db_query                **query = 0;
 691         int                     r, i, j, ir;
 692         __nis_value_t           *rval, *lval;
 693         __nis_mapping_item_t    *litem;
 694         int                     numItems;
 695         int                     nq, iqc;
 696         __nis_obj_attr_t        **attr = 0;
 697         char                    **dn = 0;
 698         int                     numDN = 0;
 699         char                    *myself = "createNisPlusEntry";
 700 
 701         if (t == 0 || t->objectDN == 0 || rv == 0)
 702                 return (0);
 703 
 704         /* Establish default, per-thread, search base */
 705         __nisdb_get_tsd()->searchBase = t->objectDN->read.base;
 706 
 707         for (r = 0, nq = 0; r < t->numRulesFromLDAP; r++) {
 708                 int                     nrq, ntq, err;
 709                 db_query                **newq;
 710                 __nis_obj_attr_t        **newattr;
 711 
 712                 rval = buildRvalue(&t->ruleFromLDAP[r]->rhs,
 713                         mit_ldap, rv, NULL);
 714                 if (rval == 0)
 715                         continue;
 716 
 717                 litem = buildLvalue(&t->ruleFromLDAP[r]->lhs, &rval,
 718                                         &numItems);
 719                 if (litem == 0) {
 720                         freeValue(rval, 1);
 721                         /* XXX Should this be a fatal error ? */
 722                         continue;
 723                 }
 724 
 725                 lval = 0;
 726                 for (i = 0; i < numItems; i++) {
 727                         __nis_value_t   *tmpval, *old;
 728 
 729                         tmpval = getMappingItem(&litem[i],
 730                                 mit_nisplus, 0, 0, NULL);
 731 
 732                         /*
 733                          * If the LHS specifies an out-of-context LDAP or
 734                          * NIS+ item, we do the update right here. We
 735                          * don't add any values to 'lval'; instead, we
 736                          * skip to the next item. (However, we still
 737                          * get a string representation of the LHS in case
 738                          * we need to report an error.)
 739                          */
 740                         if (litem[i].type == mit_ldap) {
 741                                 int     stat;
 742 
 743                                 if (dn == 0)
 744                                         dn = findDNs(myself, rv, 1,
 745                                                 t->objectDN->write.base,
 746                                                 &numDN);
 747 
 748                                 stat = storeLDAP(&litem[i], i, numItems, rval,
 749                                         t->objectDN, dn, numDN);
 750                                 if (stat != LDAP_SUCCESS) {
 751                                         char    *iname = "<unknown>";
 752 
 753                                         if (tmpval != 0 &&
 754                                                         tmpval->numVals == 1)
 755                                                 iname = tmpval->val[0].value;
 756                                         logmsg(MSG_NOTIMECHECK, LOG_ERR,
 757                                                 "%s: LDAP store \"%s\": %s",
 758                                                 myself, iname,
 759                                                 ldap_err2string(stat));
 760                                 }
 761 
 762                                 freeValue(tmpval, 1);
 763                                 continue;
 764                         }
 765 
 766                         old = lval;
 767                         lval = concatenateValues(old, tmpval);
 768                         freeValue(tmpval, 1);
 769                         freeValue(old, 1);
 770                 }
 771 
 772                 freeMappingItem(litem, numItems);
 773                 if (lval == 0 || lval->numVals <= 0 || rval->numVals <= 0) {
 774                         freeValue(lval, 1);
 775                         freeValue(rval, 1);
 776                         continue;
 777                 }
 778 
 779                 /*
 780                  * We now have a number of possible cases. The notation
 781                  * used in the table is:
 782                  *
 783                  *      single          A single value (numVals == 1)
 784                  *      single/rep      A single value with repeat == 1
 785                  *      multi[N]        N values
 786                  *      multi[N]/rep    M values with repeat == 1
 787                  *      (M)             M resulting db_query's
 788                  *
 789                  * lval \ rval  single  single/rep      multi[N] multi[N]/rep
 790                  * single         (1)       (1)          (1)        (1)
 791                  * single/rep     (1)       (1)          (N)        (N)
 792                  * multi[M]       (1)       (1)          (1)     1+(N-1)/M
 793                  * multi[M]/rep   (1)       (1)          (1)     1+(N-1)/M
 794                  *
 795                  * Of course, we already have 'nq' db_query's from previous
 796                  * rules, so the resulting number of queries is max(1,nq)
 797                  * times the numbers in the table above.
 798                  */
 799 
 800                 /* The number of queries resulting from the current rule */
 801                 if (rval->numVals > 1) {
 802                         if (lval->numVals == 1 && lval->repeat)
 803                                 nrq = rval->numVals;
 804                         else if (lval->numVals > 1 && rval->repeat)
 805                                 nrq = 1 + ((rval->numVals-1)/lval->numVals);
 806                         else
 807                                 nrq = 1;
 808                 } else {
 809                         nrq = 1;
 810                 }
 811 
 812                 /* Total number of queries after adding the current rule */
 813                 if (nq <= 0)
 814                         ntq = nrq;
 815                 else
 816                         ntq = nq * nrq;
 817 
 818                 if (ntq > nq) {
 819                         newq = realloc(query, ntq * sizeof (query[0]));
 820                         newattr = realloc(attr, ntq * sizeof (attr[0]));
 821                         if (newq == 0 || newattr == 0) {
 822                                 logmsg(MSG_NOMEM, LOG_ERR,
 823                                         "%s: realloc(%d) => NULL",
 824                                         myself, ntq * sizeof (query[0]));
 825                                 freeValue(lval, 1);
 826                                 freeValue(rval, 1);
 827                                 freeQueries(query, nq);
 828                                 freeObjAttr(attr, nq);
 829                                 sfree(newq);
 830                                 freeDNs(dn, numDN);
 831                                 return (0);
 832                         }
 833                         query = newq;
 834                         attr = newattr;
 835                 }
 836 
 837                 /*
 838                  * Copy/clone the existing queries to the new array,
 839                  * remembering that realloc() has done the first 'nq'
 840                  * ones.
 841                  *
 842                  * If there's an error (probably memory allocation), we
 843                  * still go through the rest of the array, so that it's
 844                  * simple to free the elements when we clean up.
 845                  */
 846                 for (i = 1, err = 0; i < nrq; i++) {
 847                         for (j = 0; j < nq; j++) {
 848                                 query[(nq*i)+j] = cloneQuery(query[j],
 849                                                 t->numColumns);
 850                                 if (query[(nq*i)+j] == 0 &&
 851                                                 query[j] != 0)
 852                                         err++;
 853                                 attr[(nq*i)+j] = cloneObjAttr(attr[j]);
 854                                 if (attr[(nq*i)+j] == 0 &&
 855                                                 attr[j] != 0)
 856                                         err++;
 857                         }
 858                 }
 859 
 860                 if (err > 0) {
 861                         freeValue(lval, 1);
 862                         freeValue(rval, 1);
 863                         freeQueries(query, ntq);
 864                         freeObjAttr(attr, ntq);
 865                         freeDNs(dn, numDN);
 866                         return (0);
 867                 }
 868 
 869                 /*
 870                  * Special case if nq == 0 (i.e., the first time we
 871                  * allocated db_query's). If so, we now allocate empty
 872                  * db_qcomp arrays, which simplifies subsequent
 873                  * copying of values.
 874                  */
 875                 if (nq <= 0) {
 876                         (void) memset(query, 0, ntq * sizeof (query[0]));
 877                         (void) memset(attr, 0, ntq * sizeof (attr[0]));
 878                         for (i = 0, err = 0; i < ntq; i++) {
 879                                 query[i] = am(myself, sizeof (*query[i]));
 880                                 if (query[i] == 0) {
 881                                         err++;
 882                                         break;
 883                                 }
 884                                 query[i]->components.components_val =
 885                                         am(myself, t->numColumns *
 886                         sizeof (query[i]->components.components_val[0]));
 887                                 if (query[i]->components.components_val == 0) {
 888                                         err++;
 889                                         break;
 890                                 }
 891                                 query[i]->components.components_len = 0;
 892                         }
 893                         if (err > 0) {
 894                                 freeValue(lval, 1);
 895                                 freeValue(rval, 1);
 896                                 freeQueries(query, ntq);
 897                                 freeObjAttr(attr, ntq);
 898                                 freeDNs(dn, numDN);
 899                                 return (0);
 900                         }
 901                 }
 902 
 903                 /* Now we're ready to add the new values */
 904                 for (i = 0, ir = 0; i < lval->numVals; i++) {
 905                         char    *oaName = 0;
 906                         int     index;
 907 
 908                         /* Find column index */
 909                         for (index = 0; index < t->numColumns;
 910                                         index++) {
 911                                 if (strncmp(t->column[index],
 912                                                 lval->val[i].value,
 913                                         lval->val[i].length) == 0)
 914                                         break;
 915                         }
 916                         if (index >= t->numColumns) {
 917                                 /*
 918                                  * Could be one of the special object
 919                                  * attributes.
 920                                  */
 921                                 oaName = isObjAttr(&lval->val[i]);
 922                                 if (oaName == 0)
 923                                         continue;
 924                         }
 925 
 926                         for (j = i*nrq; j < (i+1)*nrq; j++) {
 927                                 int     k;
 928 
 929                                 /* If we're out of values, repeat last one */
 930                                 ir = (j < rval->numVals) ?
 931                                         j : rval->numVals - 1;
 932 
 933                                 /*
 934                                  * Step through the query array, adding
 935                                  * the new value every 'nrq' queries, and
 936                                  * starting at 'query[j % nrq]'.
 937                                  */
 938                                 for (k = j % nrq, err = 0; k < ntq; k += nrq) {
 939                                         int     ic, c;
 940 
 941                                         if (oaName != 0) {
 942                                                 int     fail = setObjAttrField(
 943                                                                 oaName,
 944                                                                 &rval->val[ir],
 945                                                                 &attr[k]);
 946                                                 if (fail) {
 947                                                         err++;
 948                                                         break;
 949                                                 }
 950                                                 continue;
 951                                         }
 952 
 953                                         ic = query[k]->components.
 954                                                 components_len;
 955                                         /*
 956                                          * If we've already filled this
 957                                          * query, the new value is a dup
 958                                          * which we'll ignore.
 959                                          */
 960                                         if (ic >= t->numColumns)
 961                                                 continue;
 962 
 963                                         /*
 964                                          * Do we already have a value for
 965                                          * this 'index' ?
 966                                          */
 967                                         for (c = 0; c < ic; c++) {
 968                                                 if (query[k]->components.
 969                                                         components_val[c].
 970                                                         which_index == index)
 971                                                         break;
 972                                         }
 973 
 974                                         /* If no previous value, add it */
 975                                         if (c >= ic) {
 976                                                 int     l;
 977                                                 char    *v;
 978 
 979                                                 query[k]->components.
 980                                                         components_val[ic].
 981                                                         which_index = index;
 982                                                 l = rval->val[ir].length;
 983                                                 v = rval->val[ir].value;
 984                                                 if (rval->type == vt_string &&
 985                                                         l > 0 &&
 986                                                         v[l-1] != '\0' &&
 987                                                         v[l] == '\0')
 988                                                         l++;
 989                                                 query[k]->components.
 990                                                         components_val[ic].
 991                                                         index_value =
 992                                                         buildItem(l, v);
 993                                                 if (query[k]->
 994                                                         components.
 995                                                         components_val[ic].
 996                                                         index_value == 0) {
 997                                                         err++;
 998                                                         break;
 999                                                 }
1000                                                 query[k]->components.
1001                                                         components_len++;
1002                                         }
1003                                 }
1004                                 if (err > 0) {
1005                                         freeValue(lval, 1);
1006                                         freeValue(rval, 1);
1007                                         freeQueries(query, ntq);
1008                                         freeObjAttr(attr, ntq);
1009                                         freeDNs(dn, numDN);
1010                                         return (0);
1011                                 }
1012                         }
1013                 }
1014                 freeValue(lval, 1);
1015                 freeValue(rval, 1);
1016 
1017                 nq = ntq;
1018         }
1019 
1020         freeDNs(dn, numDN);
1021 
1022         if (nq <= 0) {
1023                 sfree(query);
1024                 query = 0;
1025         }
1026 
1027         /* Should we filter on index or input query ? */
1028         if (query != 0) {
1029                 if (t->index.numIndexes > 0)
1030                         query = filterQuery(t, query, qin, &attr, &nq);
1031                 else if (qin != 0)
1032                         query = filterQuery(0, query, qin, &attr, &nq);
1033         }
1034 
1035         if (query != 0 && numQueries != 0)
1036                 *numQueries = nq;
1037 
1038         if (objAttr != 0)
1039                 *objAttr = attr;
1040         else
1041                 freeObjAttr(attr, nq);
1042 
1043         return (query);
1044 }
1045 /*
1046  * Given a table mapping and a rule-value, convert to an array of
1047  * (db_query *), using the fromLDAP ruleset.
1048  *
1049  * On entry, '*numQueries' holds the number of elements in the 'rv'
1050  * array. On exit, it holds the number of (db_query *)'s in the return
1051  * value array.
1052  */
1053 db_query **
1054 ruleValue2Query(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
1055                 db_query *qin, __nis_obj_attr_t ***objAttr, int *numQueries) {
1056         db_query                **q = 0, ***qp = 0;
1057         int                     i, nqp, nq, *nnp = 0, nv;
1058         __nis_obj_attr_t        **attr = 0, ***atp = 0;
1059         char                    *myself = "ruleValue2Query";
1060 
1061 
1062         if (t == 0 || rv == 0 || numQueries == 0)
1063                 return (0);
1064 
1065         nv = *numQueries;
1066         if (nv <= 0)
1067                 return (0);
1068 
1069         /*
1070          * 'qp' is an array of (db_query **), and we get one element for
1071          * each call to createNisPlusEntry(); i.e., one for each rule-value.
1072          *
1073          * 'nnp[i]' is the count of (db_query *) in each 'qp[i]'.
1074          */
1075         qp = am(myself, nv * sizeof (*qp));
1076         nnp = am(myself, nv * sizeof (*nnp));
1077         atp = am(myself, nv * sizeof (*atp));
1078         if (qp == 0 || nnp == 0 || atp == 0) {
1079                 sfree(qp);
1080                 sfree(nnp);
1081                 sfree(atp);
1082                 return (0);
1083         }
1084 
1085         for (i = 0, nq = 0, nqp = 0; i < nv; i++) {
1086                 qp[nqp] = createNisPlusEntry(t, &rv[i], qin, &atp[nqp],
1087                                                 &nnp[nqp]);
1088                 /* If we fail, abort (XXX??? or continue ???) */
1089                 if (qp[nqp] == 0)
1090                         goto cleanup;
1091                 nq += nnp[nqp];
1092                 nqp++;
1093         }
1094 
1095         /* If we didn't get any (db_query **)'s, return failure */
1096         if (nqp == 0 || nq <= 0)
1097                 goto cleanup;
1098 
1099         q = am(myself, nq * sizeof (q[0]));
1100         attr = am(myself, nq * sizeof (attr[0]));
1101         if (q == 0 || attr == 0) {
1102                 nq = 0;
1103                 goto cleanup;
1104         }
1105 
1106         /* Convert 'qp' to an array of (db_query *)'s */
1107         for (i = 0, nq = 0; i < nqp; i++) {
1108                 (void) memcpy(&q[nq], qp[i], nnp[i] * sizeof (qp[i][0]));
1109                 (void) memcpy(&attr[nq], atp[i], nnp[i] * sizeof (atp[i][0]));
1110                 nq += nnp[i];
1111                 free(qp[i]);
1112                 free(atp[i]);
1113         }
1114 
1115         *numQueries = nq;
1116         if (objAttr != 0)
1117                 *objAttr = attr;
1118         else
1119                 freeObjAttr(attr, nq);
1120 
1121         /* Make sure 'cleanup' doesn't free the db_query pointers */
1122         nqp = 0;
1123 
1124 cleanup:
1125         for (i = 0; i < nqp; i++) {
1126                 freeQueries(qp[i], nnp[i]);
1127                 sfree(atp[i]);
1128         }
1129         sfree(qp);
1130         sfree(nnp);
1131         sfree(atp);
1132 
1133         return (q);
1134 }
1135 
1136 db_query *
1137 pseudoEntryObj2Query(entry_obj *e, nis_object *tobj, __nis_rule_value_t *rv) {
1138         db_query                *qbuf;
1139         db_qcomp                *qcbuf;
1140         int                     nc, i;
1141         __nis_rule_value_t      *rvt = 0;
1142         char                    *myself = "pseudoEntryObj2Query";
1143 
1144         nc = e->en_cols.en_cols_len - 1;
1145 
1146         if (e == 0 || nc < 0 || nc > NIS_MAXCOLUMNS)
1147                 return (0);
1148 
1149         /*
1150          * If 'rvP' is non-NULL, build a rule value from the pseudo-
1151          * nis_object in e->en_cols.en_cols_val[0].
1152          */
1153         if (rv != 0) {
1154                 nis_object              *o;
1155 
1156                 o = unmakePseudoEntryObj(e, tobj);
1157                 if (o == 0)
1158                         return (0);
1159                 rvt = addObjAttr2RuleValue(o, 0);
1160                 nis_destroy_object(o);
1161                 if (rvt == 0)
1162                         return (0);
1163         }
1164 
1165         qbuf = am(myself, sizeof (*qbuf));
1166         /*
1167          * If there are no columns (other than the pseudo-entry object),
1168          * we're done.
1169          */
1170         if (nc == 0)
1171                 return (qbuf);
1172 
1173         qcbuf = am(myself, nc * sizeof (*qcbuf));
1174         if (qcbuf == 0) {
1175                 sfree(qcbuf);
1176                 if (rvt != 0)
1177                         freeRuleValue(rvt, 1);
1178                 return (0);
1179         }
1180 
1181         /*
1182          * Build the db_query, remembering that e->en_cols.en_cols_val[0]
1183          * is the pseudo-nis_object.
1184          */
1185         qbuf->components.components_val = qcbuf;
1186         qbuf->components.components_len = nc;
1187         for (i = 0; i < nc; i++) {
1188                 qcbuf[i].which_index = i;
1189                 qcbuf[i].index_value = buildItem(
1190                         e->en_cols.en_cols_val[i+1].ec_value.ec_value_len,
1191                         e->en_cols.en_cols_val[i+1].ec_value.ec_value_val);
1192                 if (qcbuf[i].index_value == 0) {
1193                         freeQuery(qbuf);
1194                         if (rvt != 0)
1195                                 freeRuleValue(rvt, 1);
1196                         return (0);
1197                 }
1198         }
1199 
1200         if (rvt != 0) {
1201                 *rv = *rvt;
1202                 sfree(rvt);
1203         }
1204 
1205         return (qbuf);
1206 }
1207 
1208 /*
1209  * Given an input query 'q', and a db_query work buffer 'qbuf', return
1210  * a pointer to a query with one component corresponding to component
1211  * 'index' in 'q'.
1212  *
1213  * Note that no memory is allocated, and that the returned query has
1214  * pointers into 'q'.
1215  */
1216 db_query *
1217 queryFromComponent(db_query *q, int index, db_query *qbuf) {
1218 
1219         if (q == 0 || index < 0 || index >= q->components.components_len ||
1220                         qbuf == 0)
1221                 return (0);
1222 
1223         qbuf->components.components_len = 1;
1224         qbuf->components.components_val = &q->components.components_val[index];
1225 
1226         return (qbuf);
1227 }