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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <lber.h> 30 #include <ldap.h> 31 #include <strings.h> 32 33 #include "ldap_nisplus.h" 34 #include "ldap_util.h" 35 #include "ldap_val.h" 36 #include "ldap_attr.h" 37 #include "ldap_glob.h" 38 39 40 static void 41 freeColNames(char **name, int numCols) { 42 int i; 43 44 if (name == 0) 45 return; 46 47 for (i = 0; i < numCols; i++) { 48 sfree(name[i]); 49 } 50 sfree(name); 51 } 52 53 /* 54 * Convert the object attributes (zo_owner, etc.) fields of 'o' to 55 * the corresponding char **'s and __nis_value_t's. The 'name' and 56 * 'val' arrays are each assumed to have (at least) 'numVals' elements, 57 * and 'numVals' must be at least five. 58 * 59 * Returns zero if successful, non-zero otherwise. Whether successful 60 * or not, the caller must clean up 'name' and 'val', which may be 61 * partially allocated even after a failure. 62 */ 63 static int 64 objAttr2Value(nis_object *o, char **name, __nis_value_t *val, int numVals) { 65 int i, err; 66 char *myself = "objAttr2Value"; 67 68 if (o == 0 || name == 0 || val == 0 || numVals < 5) 69 return (-1); 70 71 name[0] = sdup(myself, T, "zo_owner"); 72 name[1] = sdup(myself, T, "zo_group"); 73 name[2] = sdup(myself, T, "zo_domain"); 74 name[3] = sdup(myself, T, "zo_access"); 75 name[4] = sdup(myself, T, "zo_ttl"); 76 77 for (err = 0, i = 0; i < 5; i++) { 78 if (name[i] == 0) 79 err++; 80 val[i].val = am(myself, sizeof (val[i].val[0])); 81 if (val[i].val == 0) 82 err++; 83 val[i].type = vt_string; 84 } 85 if (err > 0) { 86 for (i = 0; i < 5; i++) { 87 sfree(name[i]); 88 name[i] = 0; 89 sfree(val[i].val); 90 val[i].val = 0; 91 } 92 return (-2); 93 } 94 95 val[0].val[0].value = sdup(myself, T, o->zo_owner); 96 val[1].val[0].value = sdup(myself, T, o->zo_group); 97 val[2].val[0].value = sdup(myself, T, o->zo_domain); 98 val[3].val[0].value = am(myself, 2 * sizeof (o->zo_access) + 1); 99 val[4].val[0].value = am(myself, 2 * sizeof (o->zo_ttl) + 1); 100 101 for (err = 0, i = 0; i < 5; i++) { 102 if (val[i].val[0].value == 0) 103 err++; 104 val[i].numVals = 1; 105 } 106 if (err > 0) { 107 for (i = 0; i < 5; i++) { 108 sfree(name[i]); 109 name[i] = 0; 110 sfree(val[i].val[0].value); 111 val[i].val[0].value = 0; 112 sfree(val[i].val); 113 val[i].val = 0; 114 } 115 return (-3); 116 } 117 118 sprintf(val[3].val[0].value, "%x", o->zo_access); 119 sprintf(val[4].val[0].value, "%x", o->zo_ttl); 120 121 val[0].val[0].length = slen(o->zo_owner); 122 val[1].val[0].length = slen(o->zo_group); 123 val[2].val[0].length = slen(o->zo_domain); 124 val[3].val[0].length = 2 * sizeof (o->zo_access); 125 val[4].val[0].length = 2 * sizeof (o->zo_ttl); 126 127 return (0); 128 } 129 130 /* 131 * Convert a __nis_index_t to a string, using the supplied rule-value 132 * to evaluate any expressions in the index components. 133 * 134 * The 'table' is used only to produce a more meaningful error message. 135 */ 136 static char * 137 index2string(char *msg, __nis_index_t *index, __nis_rule_value_t *rvIn, 138 char *table) { 139 __nis_buffer_t b = {0, 0}; 140 int i, frv = 0; 141 char *myself = "index2string"; 142 143 if (index == 0) 144 return (0); 145 146 if (rvIn == 0) { 147 rvIn = initRuleValue(1, 0); 148 if (rvIn == 0) 149 return (0); 150 frv = 1; 151 } 152 153 if (msg == 0) 154 msg = myself; 155 156 bp2buf(msg, &b, "["); 157 for (i = 0; i < index->numIndexes; i++) { 158 char *fmt; 159 __nis_value_t *tmpval; 160 161 if (slen(index->name[i]) <= 0 || 162 index->value[i] == 0) { 163 logmsg(MSG_NOTIMECHECK, LOG_ERR, 164 "%s: index spec error for component \"%s\"%s", 165 msg, NIL(index->name[i]), 166 (index->value[i] == 0) ? 167 ", <nil> value" : ""); 168 sfree(b.buf); 169 if (frv) 170 freeRuleValue(rvIn, 1); 171 return (0); 172 } 173 174 /* Derive a value for this index */ 175 tmpval = getMappingFormatArray(index->value[i], rvIn, 176 fa_item, 0, 0); 177 if (tmpval == 0 || tmpval->numVals <= 0) { 178 char *ival; 179 180 freeValue(tmpval, 1); 181 tmpval = getMappingFormatArray(index->value[i], 182 0, fa_item, 0, 0); 183 if (tmpval == 0) 184 ival = "<unknown>"; 185 else if (tmpval->type != vt_string) 186 ival = "<non-string>"; 187 else if (tmpval->numVals != 1) 188 ival = "<# val error>"; 189 else 190 ival = tmpval->val[0].value; 191 logmsg(MSG_NOTIMECHECK, LOG_ERR, 192 "%s: No value for index \"%s = %s\" (table = \"%s\")", 193 msg, index->name[i], ival, 194 NIL(table)); 195 freeValue(tmpval, 1); 196 sfree(b.buf); 197 if (frv) 198 freeRuleValue(rvIn, 1); 199 return (0); 200 } 201 202 /* 203 * There should only be one value, so we ignore 204 * any excess values. 205 */ 206 if (tmpval->type == vt_string) { 207 if (i == 0) 208 fmt = "%s=%s"; 209 else 210 fmt = ",%s=%s"; 211 bp2buf(msg, &b, fmt, 212 index->name[i], tmpval->val[0].value); 213 } else { 214 bc2buf(msg, tmpval->val[0].value, 215 tmpval->val[0].length, &b); 216 } 217 freeValue(tmpval, 1); 218 } 219 bp2buf(msg, &b, "]"); 220 221 if (frv) 222 freeRuleValue(rvIn, 1); 223 224 return (b.buf); 225 } 226 227 /* 228 * Return the rule-value representation of the the entry (or entries) 229 * specified by 'index' and 'table'. 230 * 231 * If 'index' is non-NULL, we evaluate the index->value format using 232 * the supplied 'rvIn'; should 'index' be NULL, 'rvIn' is unused. In either 233 * case, 'rvIn' isn't modified. 234 */ 235 __nis_rule_value_t * 236 getNisPlusEntry(__nis_index_t *index, char *table, __nis_rule_value_t *rvIn, 237 int *numVals) { 238 __nis_buffer_t b = {0, 0}; 239 __nis_rule_value_t *rv; 240 char *myself = "getNisPlusEntry"; 241 242 if (table == 0) 243 return (0); 244 245 if (index != 0 && index->numIndexes > 0) { 246 b.buf = index2string(myself, index, rvIn, table); 247 b.len = slen(b.buf); 248 249 bp2buf(myself, &b, "%s", table, 0); 250 251 rv = getNisPlusEntrySimple(b.buf, numVals); 252 253 sfree(b.buf); 254 } else { 255 /* Special case: want the zo_* attributes for the 'table' */ 256 nis_result *res = 0; 257 int stat; 258 259 stat = getNisPlusObj(table, 0, &res); 260 if (stat != LDAP_SUCCESS) 261 return (0); 262 263 rv = initRuleValue(1, 0); 264 if (rv == 0) { 265 nis_freeresult(res); 266 return (0); 267 } 268 269 /* Allocate space for the object attributes */ 270 rv->colName = am(myself, 5 * sizeof (rv->colName[0])); 271 rv->colVal = am(myself, 5 * sizeof (rv->colVal[0])); 272 if (rv->colName == 0 || rv->colVal == 0) { 273 freeRuleValue(rv, 1); 274 nis_freeresult(res); 275 return (0); 276 } 277 278 if (objAttr2Value(NIS_RES_OBJECT(res), rv->colName, 279 rv->colVal, 5) == 0) { 280 rv->numColumns = 5; 281 if (numVals != 0) 282 *numVals = 1; 283 } else { 284 freeRuleValue(rv, 1); 285 rv = 0; 286 } 287 288 nis_freeresult(res); 289 } 290 291 return (rv); 292 } 293 294 /* 295 * Simple NIS+ entry lookup routine, which accepts an indexed name, and 296 * returns the corresponding rule-value array, and number of elements in 297 * said array. 298 */ 299 __nis_rule_value_t * 300 getNisPlusEntrySimple(char *name, int *numVals) { 301 char *table; 302 __nis_rule_value_t *rv; 303 nis_result *res; 304 int i, nobj, nv, nc = 0; 305 nis_object *o; 306 char **col = 0; 307 zotypes ttype; 308 char *myself = "getNisPlusEntrySimple"; 309 310 if (name == 0) 311 return (0); 312 313 /* Find the table name proper */ 314 table = strrchr(name, ']'); 315 if (table != 0) { 316 /* Point to the start of the table name */ 317 table++; 318 } else { 319 /* 320 * Presumably no indices; this implies enumeration, and 321 * that's not the intended use of this function, so return 322 * failure. 323 */ 324 logmsg(MSG_NOTIMECHECK, LOG_ERR, 325 "%s: un-indexed name \"%s\" used for table entry lookup", 326 myself, name); 327 return (0); 328 } 329 330 if (LDAP_SUCCESS != initializeColumnNames(table, &col, &nc, &ttype, 331 0)) { 332 freeColNames(col, nc); 333 logmsg(MSG_NOTIMECHECK, LOG_ERR, 334 "%s: unable to get column names for \"%s\"", 335 myself, table); 336 return (0); 337 } 338 339 if (ttype != NIS_TABLE_OBJ) { 340 freeColNames(col, nc); 341 logmsg(MSG_NOTIMECHECK, LOG_ERR, 342 "%s: \"%s\" is object type %d, not a table", 343 myself, table, ttype); 344 return (0); 345 } 346 347 if (col == 0 || nc <= 0) { 348 /* col!=0 and nc==0 is possible, so free the column array */ 349 freeColNames(col, nc); 350 logmsg(MSG_NOTIMECHECK, LOG_ERR, 351 "%s: %s for \"%s\"", 352 myself, (col == 0) ? "<nil> column name array" : 353 "no column name elements", 354 table); 355 return (0); 356 } 357 358 res = nis_list(name, 0, 0, 0); 359 if (res == 0) { 360 freeColNames(col, nc); 361 logmsg(MSG_NOTIMECHECK, LOG_ERR, 362 "%s: NIS+ lookup error (no result) for \"%s\"", 363 myself, name); 364 return (0); 365 } 366 if (res->status == NIS_NOTFOUND) { 367 /* 368 * Not really an error from the POV of this function; we 369 * have no way of knowing if the entry should exist or not. 370 */ 371 freeColNames(col, nc); 372 nis_freeresult(res); 373 return (0); 374 } else if (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS) { 375 freeColNames(col, nc); 376 logmsg(MSG_NOTIMECHECK, LOG_ERR, 377 "%s: NIS+ lookup error (%d) for \"%s\"", 378 myself, res->status, name); 379 nis_freeresult(res); 380 return (0); 381 } 382 383 nobj = res->objects.objects_len; 384 385 /* One rule-value element for each entry object */ 386 rv = initRuleValue(nobj, 0); 387 if (rv == 0) { 388 freeColNames(col, nc); 389 nis_freeresult(res); 390 return (0); 391 } 392 393 for (i = 0, nv = 0; i < nobj; i++) { 394 unsigned int nec; 395 entry_col *ec; 396 int j; 397 398 o = &res->objects.objects_val[i]; 399 if (o->zo_data.zo_type != NIS_ENTRY_OBJ) 400 continue; 401 402 nec = o->zo_data.objdata_u.en_data.en_cols.en_cols_len; 403 if (nec == 0) 404 continue; 405 406 if (nec != nc) 407 continue; 408 409 /* 410 * 'nec+5' to account for the object attributes 411 * (zo_owner. etc), of which there are five. 412 */ 413 rv[nv].colName = am(myself, 414 (nec+5) * sizeof (rv[nv].colName[0])); 415 rv[nv].colVal = am(myself, 416 (nec+5) * sizeof (rv[nv].colVal[0])); 417 if (rv[nv].colName == 0 || rv[nv].colVal == 0) { 418 freeRuleValue(rv, nv+1); 419 freeColNames(col, nc); 420 nis_freeresult(res); 421 return (0); 422 } 423 rv[nv].numColumns = nec + 5; 424 425 ec = o->zo_data.objdata_u.en_data.en_cols.en_cols_val; 426 427 for (j = 0; j < nec; j++) { 428 int len; 429 430 rv[nv].colName[j] = sdup(myself, T, col[j]); 431 if (rv[nv].colName[j] == 0) { 432 freeRuleValue(rv, nv+1); 433 freeColNames(col, nc); 434 nis_freeresult(res); 435 return (0); 436 } 437 438 /* What's the type of column value ? */ 439 if ((ec[j].ec_flags & TA_BINARY) != 0 || 440 (ec[j].ec_flags & TA_XDR) != 0 || 441 (ec[j].ec_flags & TA_ASN1) != 0) 442 rv[nv].colVal[j].type = vt_ber; 443 else 444 rv[nv].colVal[j].type = vt_string; 445 446 rv[nv].colVal[j].val = am(myself, 447 sizeof (rv[nv].colVal[j].val[0])); 448 if (rv[nv].colVal[j].val == 0) { 449 freeRuleValue(rv, nv+1); 450 freeColNames(col, nc); 451 nis_freeresult(res); 452 return (0); 453 } 454 rv[nv].colVal[j].numVals = 1; 455 456 len = ec[j].ec_value.ec_value_len; 457 if (len > 0 && 458 ec[j].ec_value.ec_value_val[len-1] == '\0') { 459 /* Don't count NUL in the value length */ 460 len -= 1; 461 } 462 463 /* 464 * Always allocate memory so that there's a NUL at 465 * the end. 466 */ 467 rv[nv].colVal[j].val[0].value = am(myself, len+1); 468 rv[nv].colVal[j].val[0].length = len; 469 470 if (rv[nv].colVal[j].val[0].value == 0) { 471 freeRuleValue(rv, nv+1); 472 freeColNames(col, nc); 473 nis_freeresult(res); 474 return (0); 475 } 476 477 (void) memcpy(rv[nv].colVal[j].val[0].value, 478 ec[j].ec_value.ec_value_val, len); 479 } 480 481 /* Now the object attributes */ 482 if (objAttr2Value(o, &rv[nv].colName[nec], &rv[nv].colVal[nec], 483 5) != 0) { 484 freeRuleValue(rv, nv+1); 485 freeColNames(col, nc); 486 nis_freeresult(res); 487 return (0); 488 } 489 490 nv++; 491 } 492 493 freeColNames(col, nc); 494 nis_freeresult(res); 495 496 if (numVals != 0) 497 *numVals = nv; 498 499 return (rv); 500 } 501 502 /* 503 * Retrieve a copy of the specified NIS+ object. Upon successful return, 504 * the return value is LDAP_SUCCESS, *outRes contains the nis_result 505 * pointer, and there's at least one object in the result. 506 * 507 * On error, return a status other than LDAP_SUCCESS. 508 */ 509 int 510 getNisPlusObj(char *name, char *msg, nis_result **outRes) { 511 nis_result *res; 512 char *objName; 513 char *myself = "getNisPlusObj"; 514 515 objName = fullObjName(F, name); 516 if (objName == 0) { 517 return ((name == 0) ? LDAP_PARAM_ERROR : LDAP_NO_MEMORY); 518 } 519 520 if (msg == 0) 521 msg = myself; 522 523 res = nis_lookup(objName, 0); 524 525 if (res == 0) { 526 sfree(objName); 527 return (LDAP_NO_MEMORY); 528 } 529 530 if (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS) { 531 int msgtype = MSG_NOTIMECHECK; 532 533 if (res->status == NIS_COLDSTART_ERR) 534 msgtype = MSG_NONPCOLDSTART; 535 536 logmsg(msgtype, LOG_ERR, 537 "%s: nis_lookup(\"%s\", 0) => %d (%s)", 538 msg, objName, res->status, nis_sperrno(res->status)); 539 sfree(objName); 540 nis_freeresult(res); 541 return (LDAP_OPERATIONS_ERROR); 542 } 543 544 if (res->objects.objects_len <= 0) { 545 logmsg(MSG_NOTIMECHECK, LOG_ERR, 546 "%s: nis_lookup(\"%s\", 0) => no objects", 547 msg, objName); 548 sfree(objName); 549 nis_freeresult(res); 550 return (LDAP_OPERATIONS_ERROR); 551 } 552 553 if (res->objects.objects_len > 1) { 554 if (verbose) 555 logmsg(MSG_NOTIMECHECK, LOG_WARNING, 556 "%s: Ignoring excess objects (%d) for \"%s\"", 557 msg, res->objects.objects_len - 1, objName); 558 } 559 560 sfree(objName); 561 562 if (outRes != 0) { 563 *outRes = res; 564 } else { 565 nis_freeresult(res); 566 return (LDAP_PARAM_ERROR); 567 } 568 569 return (LDAP_SUCCESS); 570 } 571 572 __nis_value_t * 573 lookupNisPlus(__nis_obj_spec_t *obj, char *col, __nis_rule_value_t *rvIn) { 574 char *objname; 575 __nis_rule_value_t *rv; 576 int i, nv; 577 __nis_value_t *val; 578 char *myself = "lookupNisPlus"; 579 580 if (obj == 0 || col == 0) 581 return (0); 582 583 objname = fullObjName(F, obj->name); 584 if (objname == 0) 585 return (0); 586 587 rv = getNisPlusEntry(&obj->index, objname, rvIn, &nv); 588 sfree(objname); 589 if (rv == 0) 590 return (0); 591 592 val = am(myself, sizeof (*val)); 593 if (val == 0) { 594 freeRuleValue(rv, nv); 595 return (0); 596 } 597 598 for (i = 0, val->numVals = 0; i < nv; i++) { 599 int j; 600 __nis_value_t *oldval; 601 602 for (j = 0; j < rv[i].numColumns; j++) { 603 if (strcmp(col, rv[i].colName[j]) == 0) 604 break; 605 } 606 if (j >= rv[i].numColumns) 607 continue; 608 609 oldval = val; 610 val = concatenateValues(val, &rv[i].colVal[j]); 611 freeValue(oldval, 1); 612 if (val == 0) { 613 freeRuleValue(rv, nv); 614 return (0); 615 } 616 } 617 618 freeRuleValue(rv, nv); 619 620 if (val->numVals == 0) { 621 freeValue(val, 1); 622 val = 0; 623 } 624 625 return (val); 626 } 627 628 /* 629 * Store the specified NIS+ colname/value in the indicated entry. 630 * The 'table' is used if the 'item->searchSpec.obj.name' is 631 * unspecified. If the 'item' doesn't contain an index spec (and 632 * hence indication of the exact NIS+ entry to update), an index 633 * spec is constructed from 'rv'. 634 */ 635 nis_error 636 storeNisPlus(__nis_mapping_item_t *item, int index, int numItems, 637 __nis_rule_value_t *rv, char *table, __nis_value_t *val) { 638 __nis_buffer_t b = {0, 0}; 639 nis_result *res, *mres; 640 char **col = 0; 641 int i, err, nc = 0, ic; 642 zotypes ttype; 643 nis_object *o; 644 entry_obj *e; 645 uint_t orgEcFlg; 646 uint_t orgEcLen; 647 char *orgEcVal; 648 char *myself = "storeNisPlus"; 649 650 if (item == 0 || val == 0 || val->numVals != 1 || index < 0 || 651 index >= numItems || 652 item->type != mit_nisplus || item->name == 0 || 653 item->searchSpec.obj.name == 0) 654 return (NIS_BADREQUEST); 655 656 /* Check that the table has column with the desired name */ 657 if (slen(item->searchSpec.obj.name) > 0) 658 table = item->searchSpec.obj.name; 659 table = fullObjName(F, table); 660 if (slen(table) <= 0) 661 return (NIS_NOMEMORY); 662 if (LDAP_SUCCESS != initializeColumnNames(table, &col, &nc, &ttype, 663 0) || ttype != NIS_TABLE_OBJ) { 664 freeColNames(col, nc); 665 sfree(table); 666 return (NIS_NOSUCHTABLE); 667 } 668 669 for (ic = 0; ic < nc; ic++) { 670 if (strcmp(item->name, col[ic]) == 0) 671 break; 672 } 673 freeColNames(col, nc); 674 if (ic >= nc) { 675 sfree(table); 676 return (NIS_BADATTRIBUTE); 677 } 678 679 /* Construct the index entry object name */ 680 if (item->searchSpec.obj.index.numIndexes > 0) { 681 b.buf = index2string(myself, &item->searchSpec.obj.index, 0, 682 table); 683 b.len = slen(b.buf); 684 if (b.buf == 0 || b.len <= 0) { 685 sfree(b.buf); 686 sfree(table); 687 return (NIS_NOMEMORY); 688 } 689 } else if (rv != 0 && rv->numColumns > 0) { 690 /* Construct index value from rule-value */ 691 bp2buf(myself, &b, "["); 692 for (i = 0; i < rv->numColumns; i++) { 693 if (slen(rv->colName[i]) <= 0 || 694 rv->colVal[i].type != vt_string || 695 rv->colVal[i].numVals != 1 || 696 slen(rv->colVal[i].val[0].value) <= 0) 697 continue; 698 if (i == 0) 699 bp2buf(myself, &b, "%s=%s", rv->colName[i], 700 rv->colVal[i].val[0].value); 701 else 702 bp2buf(myself, &b, ",s=%s", rv->colName[i], 703 rv->colVal[i].val[0].value); 704 } 705 bp2buf(myself, &b, "]"); 706 } else { 707 /* Can't identify entry to modify */ 708 sfree(table); 709 return (NIS_NOTFOUND); 710 } 711 if (strcmp("[]", b.buf) == 0) { 712 sfree(b.buf); 713 sfree(table); 714 return (NIS_NOTFOUND); 715 } 716 bp2buf(myself, &b, "%s", table); 717 sfree(table); 718 719 /* Look it up */ 720 res = nis_list(b.buf, 0, 0, 0); 721 if (res == 0) { 722 sfree(b.buf); 723 return (NIS_NOMEMORY); /* Likely guess */ 724 } else if (res->status != NIS_SUCCESS && 725 res->status != NIS_S_SUCCESS) { 726 err = res->status; 727 sfree(b.buf); 728 nis_freeresult(res); 729 return (err); 730 } 731 732 /* We only want one object, and it must be an entry */ 733 if (res->objects.objects_len != 1 || 734 (o = res->objects.objects_val) == 0 || 735 o->zo_data.zo_type != NIS_ENTRY_OBJ) { 736 sfree(b.buf); 737 nis_freeresult(res); 738 return (NIS_BADOBJECT); 739 } 740 741 /* Verify that the column index 'ic' is in range */ 742 e = &o->zo_data.objdata_u.en_data; 743 if (ic >= e->en_cols.en_cols_len) { 744 sfree(b.buf); 745 nis_freeresult(res); 746 return (NIS_TYPEMISMATCH); 747 } 748 749 /* 750 * Replace the indicated column value, and set the EN_MODIFIED flag. 751 * We keep track of the original value, so that we can restore it 752 * before destroying 'res'. 753 */ 754 orgEcFlg = e->en_cols.en_cols_val[ic].ec_flags; 755 orgEcLen = e->en_cols.en_cols_val[ic].ec_value.ec_value_len; 756 orgEcVal = e->en_cols.en_cols_val[ic].ec_value.ec_value_val; 757 /* 758 * We always make sure that the val->val[].value's have a NUL 759 * at the end. However, the 'length' usually doesn't include 760 * the NUL. Since NIS+ wants the NUL counted, we increase the 761 * length by one if: 762 * (a) the val->type is vt_string, and 763 * (b) val->val[].value[val->val[].length-1] isn't already 764 * NUL, and 765 * (c) val->val[].value[val->val[].length] is NUL. 766 */ 767 if (val->type == vt_string && val->val[0].length > 0 && 768 ((char *)val->val[0].value)[val->val[0].length-1] != '\0' && 769 ((char *)val->val[0].value)[val->val[0].length] == '\0') 770 val->val[0].length++; 771 e->en_cols.en_cols_val[ic].ec_flags |= EN_MODIFIED; 772 e->en_cols.en_cols_val[ic].ec_value.ec_value_len = val->val[0].length; 773 e->en_cols.en_cols_val[ic].ec_value.ec_value_val = val->val[0].value; 774 775 mres = nis_modify_entry(b.buf, o, MOD_SAMEOBJ); 776 777 /* Restore 'res', and destroy it */ 778 e->en_cols.en_cols_val[ic].ec_flags = orgEcFlg; 779 e->en_cols.en_cols_val[ic].ec_value.ec_value_len = orgEcLen; 780 e->en_cols.en_cols_val[ic].ec_value.ec_value_val = orgEcVal; 781 nis_freeresult(res); 782 783 /* Don't need the indexed name anymore */ 784 sfree(b.buf); 785 786 /* Set the return status, and destroy the modification result */ 787 if (mres != 0) { 788 err = mres->status; 789 nis_freeresult(mres); 790 } else { 791 err = NIS_NOMEMORY; 792 } 793 794 return (err); 795 } 796 797 int 798 copyColumnNames(nis_object *o, char ***column, int *numColumns) { 799 int i, nc, stat; 800 char **name; 801 char *myself = "copyColumnNames"; 802 803 if (o == 0 || column == 0 || numColumns == 0) 804 return (LDAP_PARAM_ERROR); 805 806 if (*column == 0 && *numColumns < 0) { 807 /* 808 * This table mapping is used to map the table object 809 * itself. Since that's indicated by t->column == 0 and 810 * t->numColumns == -1, we definitely don't want to set 811 * the column names. 812 */ 813 return (LDAP_SUCCESS); 814 } 815 816 freeColNames(*column, *numColumns); 817 *column = 0; 818 *numColumns = 0; 819 820 if (o->zo_data.zo_type != NIS_TABLE_OBJ) { 821 /* 822 * Since we can map non-table objects, this isn't really 823 * an error, but we return a special value to tell our 824 * caller that this isn't a table (as opposed to a table 825 * with zero columns). 826 */ 827 return (LDAP_OBJECT_CLASS_VIOLATION); 828 } 829 830 nc = o->zo_data.objdata_u.ta_data.ta_cols.ta_cols_len; 831 if (nc < 0) { 832 logmsg(MSG_NOTIMECHECK, LOG_INFO, 833 "%s: negative column count (%d) for \"%s.%s\"", 834 myself, nc, NIL(o->zo_name), NIL(o->zo_domain)); 835 return (LDAP_DECODING_ERROR); 836 } 837 838 if (nc == 0 || o->zo_data.objdata_u.ta_data.ta_cols.ta_cols_val == 0) { 839 return (LDAP_SUCCESS); 840 } 841 842 name = am(myself, nc * sizeof (name[0])); 843 if (name == 0) { 844 return (LDAP_NO_MEMORY); 845 } 846 847 for (i = 0; i < nc; i++) { 848 if (o->zo_data.objdata_u.ta_data.ta_cols. 849 ta_cols_val[i].tc_name == 0) 850 continue; 851 name[i] = sdup(myself, T, o->zo_data.objdata_u.ta_data.ta_cols. 852 ta_cols_val[i].tc_name); 853 if (name[i] == 0) { 854 for (--i; i >= 0; i--) 855 sfree(name[i]); 856 free(name); 857 return (LDAP_NO_MEMORY); 858 } 859 } 860 861 *column = name; 862 *numColumns = nc; 863 864 return (LDAP_SUCCESS); 865 } 866 867 /* 868 * Initialize the column name list for the specified table name 869 * (which must be fully qualified). 870 * 871 * Returns an LDAP error status 872 */ 873 int 874 initializeColumnNames(char *table, char ***column, int *numColumns, 875 zotypes *type, nis_object **obj) { 876 nis_result *res = 0; 877 int stat; 878 char *myself = "initializeColumnNames"; 879 880 if (table == 0 || column == 0 || numColumns == 0 || type == 0) 881 return (LDAP_PARAM_ERROR); 882 883 stat = getNisPlusObj(table, myself, &res); 884 if (stat != LDAP_SUCCESS) 885 return (stat); 886 887 *type = res->objects.objects_val->zo_data.zo_type; 888 *column = 0; 889 *numColumns = 0; 890 891 stat = copyColumnNames(res->objects.objects_val, column, numColumns); 892 893 nis_freeresult(res); 894 895 return (stat); 896 } 897 898 /* 899 * Sets the oid (i.e., the creation and modification times) for the 900 * specified object. In order to avoid retrieving the old incarnation 901 * (if any) from the DB first, we're punting and setting both mtime 902 * and ctime to the current time. 903 */ 904 void 905 setOid(nis_object *obj) { 906 if (obj != 0) { 907 obj->zo_oid.ctime = obj->zo_oid.mtime = time(0); 908 } 909 } 910