1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2015 Gary Mills 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <strings.h> 29 #include <string.h> 30 #include <lber.h> 31 #include <ldap.h> 32 33 #include "db_item_c.h" 34 35 #include "nisdb_mt.h" 36 37 #include "ldap_util.h" 38 #include "ldap_structs.h" 39 #include "ldap_val.h" 40 #include "ldap_ruleval.h" 41 #include "ldap_op.h" 42 #include "ldap_nisdbquery.h" 43 #include "ldap_attr.h" 44 #include "ldap_xdr.h" 45 #include "ldap_ldap.h" 46 47 48 item * 49 buildItem(int len, void *value) { 50 char *myself = "buildItem"; 51 item *i = am(myself, sizeof (*i)); 52 int mlen = len; 53 54 if (i == 0) 55 return (0); 56 57 /* 58 * To this function, a NULL value, or a length less than or equal 59 * zero means an item with no value. Hence, buildItem(0, 0) is 60 * _not_ the right way to create index_value == 0 to indicate 61 * deletion. 62 */ 63 if (value == 0 || len <= 0) { 64 i->itemvalue.itemvalue_len = 0; 65 i->itemvalue.itemvalue_val = 0; 66 return (i); 67 } 68 69 /* 70 * NIS+ usually stores the terminating NUL for strings, so we add 71 * it here just in case. This means we usually waste a byte for 72 * binary column values... 73 */ 74 if (len > 0 && ((char *)value)[len-1] != '\0') 75 mlen++; 76 77 i->itemvalue.itemvalue_len = len; 78 i->itemvalue.itemvalue_val = am(myself, mlen); 79 if (mlen > 0 && i->itemvalue.itemvalue_val == 0) { 80 free(i); 81 return (0); 82 } 83 memcpy(i->itemvalue.itemvalue_val, value, len); 84 85 return (i); 86 } 87 88 void 89 freeItem(item *i) { 90 if (i != 0) { 91 sfree(i->itemvalue.itemvalue_val); 92 free(i); 93 } 94 } 95 96 void 97 freeQcomp(db_qcomp *qc, int doFree) { 98 99 if (qc == 0) 100 return; 101 102 freeItem(qc->index_value); 103 if (doFree) 104 free(qc); 105 } 106 107 db_query * 108 buildQuery(int num_components, db_qcomp *components) { 109 char *myself = "buildQuery"; 110 db_query *q = am(myself, sizeof (*q)); 111 112 if (q == 0) 113 return (0); 114 115 q->components.components_len = num_components; 116 q->components.components_val = components; 117 118 return (q); 119 } 120 121 /* 122 * Clone a db_query. The 'numComps' parameter can be used to specify 123 * the number of db_qcomp's to allocate (in the 'components.components_val' 124 * array), if 'components.components_len' hasn't yet reached its expected 125 * maximum value. 126 */ 127 db_query * 128 cloneQuery(db_query *old, int numComps) { 129 db_query *new; 130 int i; 131 char *myself = "cloneQuery"; 132 133 if (old == 0) 134 return (0); 135 136 new = am(myself, sizeof (*new)); 137 if (new == 0) 138 return (0); 139 140 if (old->components.components_len > numComps) 141 numComps = old->components.components_len; 142 143 new->components.components_val = am(myself, 144 sizeof (new->components.components_val[0]) * 145 numComps); 146 if (numComps > 0 && new->components.components_val == 0) { 147 free(new); 148 return (0); 149 } 150 151 for (i = 0; i < old->components.components_len; i++) { 152 item *it; 153 154 if (old->components.components_val[i].index_value == 0) { 155 new->components.components_val[i].index_value = 0; 156 new->components.components_val[i].which_index = 157 old->components.components_val[i].which_index; 158 continue; 159 } 160 161 it = buildItem(old->components.components_val[i].index_value-> 162 itemvalue.itemvalue_len, 163 old->components.components_val[i].index_value-> 164 itemvalue.itemvalue_val); 165 166 if (it == 0) { 167 new->components.components_len = i + 1; 168 freeQuery(new); 169 return (0); 170 } 171 172 new->components.components_val[i].index_value = it; 173 new->components.components_val[i].which_index = 174 old->components.components_val[i].which_index; 175 } 176 177 new->components.components_len = old->components.components_len; 178 179 return (new); 180 } 181 182 void 183 freeQuery(db_query *q) { 184 int i; 185 186 if (q == 0) 187 return; 188 189 for (i = 0; i < q->components.components_len; i++) { 190 freeItem(q->components.components_val[i].index_value); 191 } 192 193 sfree(q->components.components_val); 194 sfree(q); 195 } 196 197 void 198 freeQueries(db_query **q, int numQ) { 199 int i; 200 201 if (q == 0) 202 return; 203 204 for (i = 0; i < numQ; i++) 205 freeQuery(q[i]); 206 207 sfree(q); 208 } 209 210 /* 211 * Given an array index[0..num-1] of pointers to strings of the form 212 * "name=value", create the corresponding db_queries. "name=" indicates 213 * deletion, which results in a db_query component where index_value == 0. 214 * 215 * The __nis_table_mapping_t structure is used to translate column 216 * names to indices. 217 * 218 * If 'rvP' is non-NULL, the searchable columns from the 'index' 219 * name/value pairs are used to retrieve copies of the corresponding NIS+ 220 * entries, and '*rvP' is initialized with the current entry values 221 * and object attributes. Names/values supplied in 'index' override 222 * those from existing NIS+ entries. 223 */ 224 db_query ** 225 createQuery(int num, char **index, __nis_table_mapping_t *t, 226 __nis_rule_value_t **rvP, int *numVals) { 227 db_query **q; 228 db_qcomp *qc; 229 int i, j, n, a, nv, niv; 230 __nis_rule_value_t *rvq; 231 __nis_buffer_t b = {0, 0}; 232 char *table = 0; 233 char *myself = "createQuery"; 234 235 rvq = initRuleValue(1, 0); 236 if (rvq == 0) 237 return (0); 238 239 if (numVals == 0) 240 numVals = &nv; 241 *numVals = 0; 242 243 if (rvP != 0) { 244 /* 245 * Try to obtain a copy of the table object, in order to 246 * determine the searchable columns. A failure isn't 247 * necessarily fatal; we just try to compose the entire 248 * LDAP data from the col=val pairs. 249 */ 250 table = fullObjName(F, t->objName); 251 if (table == 0) { 252 logmsg(MSG_NOTIMECHECK, LOG_ERR, 253 "%s: Error converting \"%s\" to FQ object name", 254 myself, NIL(t->objName)); 255 freeRuleValue(rvq, 1); 256 return (0); 257 } 258 } 259 260 /* Create a rule-value from the col=val pairs */ 261 for (n = 0; n < num; n++) { 262 char *value; 263 264 if ((value = strchr(index[n], '=')) == 0) { 265 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 266 "%s: no '=' in \"%s\"", 267 myself, index[n]); 268 continue; 269 } 270 271 *value = '\0'; 272 value++; 273 274 for (a = 0; a < t->numColumns; a++) { 275 if (strcmp(index[n], t->column[a]) == 0) { 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; 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 } 1228