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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <string.h> 34 #include <stdarg.h> 35 #include <fcntl.h> 36 #include <syslog.h> 37 #include <errno.h> 38 #include <pwd.h> 39 #include <libintl.h> 40 #include <netdb.h> /* for rcmd() */ 41 42 #include <ns.h> 43 #include <list.h> 44 45 #define LDAP_REFERRALS 46 #include <lber.h> 47 #include <ldap.h> 48 #include <sys/systeminfo.h> 49 50 51 /* 52 * This modules contains the code required to manipulate printer objects in 53 * a LDAP directory for the Naming Service (NS) switch. 54 * It can "add", "modify" and "delete" the objects on the given ldap server 55 * and in the given NS domain DN, eg. "dc=mkg,dc=sun,dc=com". 56 * Note: printers known to the naming service are contained in the RDN 57 * "ou=printers" under the NS domain DN 58 */ 59 60 #define PCONTAINER "ou=printers" 61 62 /* attribute keywords */ 63 #define ATTR_DN "dn" 64 #define ATTR_OCLASS "objectClass" 65 #define ATTR_URI "printer-uri" 66 #define ATTR_PNAME "printer-name" 67 #define ATTR_XRISUP "printer-xri-supported" 68 #define ATTR_BSDADDR "sun-printer-bsdaddr" 69 #define ATTR_KVP "sun-printer-kvp" 70 71 /* objectClass values */ 72 #define OCV_TOP "top" 73 #define OCV_PSERVICE "printerService" 74 #define OCV_SUNPRT "sunPrinter" 75 #define OCV_PABSTRACT "printerAbstract" 76 77 /* xri-supported attribute value */ 78 #define AV_UNKNOWN "unknown" 79 80 81 /* 82 * LDAP objectclass atributes that the user can explicity change 83 */ 84 85 static const char *nsl_attr_printerService[] = { 86 "printer-uri", 87 "printer-xri-supported", 88 /* Not allowed "printer-name", */ 89 "printer-natural-language-configured", 90 "printer-location", 91 "printer-info", 92 "printer-more-info", 93 "printer-make-and-model", 94 "printer-charset-configured", 95 "printer-charset-supported", 96 "printer-generated-natural-language-supported", 97 "printer-document-format-supported", 98 "printer-color-supported", 99 "printer-compression-supported", 100 "printer-pages-per-minute", 101 "printer-pages-per-minute-color", 102 "printer-finishings-supported", 103 "printer-number-up-supported", 104 "printer-sides-supported", 105 "printer-media-supported", 106 "printer-media-local-supported", 107 "printer-resolution-supported", 108 "printer-print-quality-supported", 109 "printer-job-priority-supported", 110 "printer-copies-supported", 111 "printer-job-k-octets-supported", 112 "printer-current-operator", 113 "printer-service-person", 114 "printer-delivery-orientation-supported", 115 "printer-stacking-order-supported", 116 "printer-output-features-supported", 117 (char *)NULL 118 }; 119 120 121 static const char *nsl_attr_printerIPP[] = { 122 "printer-ipp-versions-supported", 123 "printer-multiple-document-jobs-supported", 124 (char *)NULL 125 }; 126 127 static const char *nsl_attr_sunPrinter[] = { 128 /* Not allowed "sun-printer-bsdaddr", */ 129 /* Not allowed "sun-printer-kvp", */ 130 (char *)NULL 131 }; 132 133 134 /* 135 * List of LDAP attributes that user is not allowed to explicitly change 136 */ 137 static const char *nsl_attr_notAllowed[] = { 138 ATTR_DN, 139 ATTR_OCLASS, /* objectclass */ 140 ATTR_PNAME, /* printer-name */ 141 ATTR_BSDADDR, 142 ATTR_KVP, 143 (char *)NULL 144 }; 145 146 147 static NSL_RESULT _connectToLDAP(ns_cred_t *cred, LDAP **ld); 148 static uchar_t *_constructPrinterDN(uchar_t *printerName, 149 uchar_t *domainDN, char **attrList); 150 static NSL_RESULT _checkPrinterExists(LDAP *ld, uchar_t *printerName, 151 uchar_t *domainDN, uchar_t **printerDN); 152 static NSL_RESULT _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN); 153 static NSL_RESULT _checkSunPrinter(LDAP *ld, uchar_t *printerDN); 154 static NSL_RESULT _addNewPrinterObject(LDAP *ld, uchar_t *printerName, 155 uchar_t *domainDN, char **attrList); 156 static NSL_RESULT _modifyPrinterObject(LDAP *ld, uchar_t *printerDN, 157 uchar_t *printerName, uchar_t *domainDN, char **attrList); 158 static NSL_RESULT _checkAttributes(char **list); 159 static NSL_RESULT _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value); 160 static NSL_RESULT _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value); 161 static NSL_RESULT _constructAddLDAPMod(uchar_t *printerName, 162 char **attrList, LDAPMod ***attrs); 163 static NSL_RESULT _constructModLDAPMod(uchar_t *printerName, int sunPrinter, 164 char **attrList, char ***oldKVPList, LDAPMod ***attrs); 165 static NSL_RESULT _compareURIinDNs(uchar_t *dn1, uchar_t *dn2); 166 static uchar_t *_getThisNSDomainDN(void); 167 static int _popen(char *cmd, char *results, int size); 168 static int _attrInList(char *attr, const char **list); 169 static int _attrInLDAPList(char *attr); 170 static NSL_RESULT _getCurrentKVPValues(LDAP *ld, 171 uchar_t *objectDN, char ***list); 172 static void _freeList(char ***list); 173 static NSL_RESULT _modAttrKVP(char *value, char ***kvpList); 174 static NSL_RESULT _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists); 175 static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp, 176 int *methodp, int freeit); 177 178 /* 179 * ***************************************************************************** 180 * 181 * Function: ldap_put_printer() 182 * 183 * Description: Action the request to change a printer object in the LDAP 184 * directory DIT. The object is either added, modified or deleted 185 * depending on the request's attribute list. A null list indicates 186 * the request is a delete. 187 * The object's DN is constructed from the supplied domain DN and 188 * a check is done to see if the object exists already, if it 189 * doesn't exist then this is a request to add a new object 190 * If a URI is given in the attribute list and it is different to 191 * the existing printing object's DN then the request will be 192 * rejected. 193 * 194 * 195 * Parameters: 196 * Input: const ns_printer_t *printer 197 * - this structure contains the following : 198 * char *printerName - name of the printer 199 * ns_cred_t *cred - structure containing the ldap host and 200 * port, user, password and NS domain DN for the 201 * directory server to be updated. 202 * char **attrList - pointer to a list of attribute key values 203 * for the printer object. If the object does 204 * not already exist then this list contains the 205 * values for the new object, otherwise this list 206 * is a list of attributes to modify. For modify 207 * a null attribute value is a attribute delete 208 * request. A NULL ptr = delete the object. 209 * Output: None 210 * 211 * Returns: int - 0 = request actioned okay 212 * !0 = error - see NSL_RESULT codes 213 * 214 * ***************************************************************************** 215 */ 216 217 int 218 ldap_put_printer(const ns_printer_t *printer) 219 220 { 221 NSL_RESULT result = NSL_OK; 222 NSL_RESULT printerExists = NSL_ERR_UNKNOWN_PRINTER; 223 LDAP *ld = NULL; 224 uchar_t *printerDN = NULL; 225 uchar_t *domainDN = NULL; 226 char *printerName = NULL; 227 ns_cred_t *cred = NULL; 228 char **attrList = NULL; 229 230 /* -------- */ 231 232 /* 233 * Note: the "attributes" list should be null for ldap as the attribute 234 * values are passed in the nsdata field 235 */ 236 237 if ((printer != NULL) && 238 (printer->attributes == NULL) && (printer->name != NULL)) 239 { 240 /* extract required pointer values from structure */ 241 242 printerName = printer->name; 243 cred = printer->cred; 244 if (printer->nsdata != NULL) 245 { 246 attrList = ((NS_LDAPDATA *)(printer->nsdata))->attrList; 247 } 248 249 /* connect and bind to the ldap directory server */ 250 251 result = _connectToLDAP(cred, &ld); 252 if ((result == NSL_OK) && (ld != NULL)) 253 { 254 /* 255 * check if the NS domain DN was given, if not use the 256 * current NS domain 257 */ 258 259 if (cred->domainDN != NULL) 260 { 261 domainDN = (uchar_t *) 262 strdup((char *)cred->domainDN); 263 } 264 else 265 { 266 /* get DN of current domain */ 267 domainDN = _getThisNSDomainDN(); 268 } 269 270 printerExists = 271 _checkPrinterExists(ld, (uchar_t *)printerName, 272 domainDN, &printerDN); 273 if (printerExists != LDAP_SUCCESS) 274 { 275 /* 276 * could not find the printer by printer-name, 277 * but there could be a non sunPrinter object 278 * so if the printer-uri was given check if 279 * an object for that exists 280 */ 281 printerDN = 282 _constructPrinterDN(NULL, 283 domainDN, attrList); 284 if (printerDN != NULL) 285 { 286 printerExists = _checkPrinterDNExists( 287 ld, printerDN); 288 } 289 } 290 #ifdef DEBUG 291 if (printerExists == NSL_OK) 292 { 293 printf("DN found = '%s' for '%s'\n", printerDN, printerName); 294 } 295 #endif 296 297 if (attrList == NULL) 298 { 299 /* 300 * a null list indicates that this is a DELETE 301 * object request, so if object exists delete 302 * it, otherwise report an error. 303 */ 304 if (printerExists == LDAP_SUCCESS) 305 { 306 result = ldap_delete_s(ld, 307 (char *)printerDN); 308 if (result != LDAP_SUCCESS) 309 { 310 result = NSL_ERR_DEL_FAILED; 311 #ifdef DEBUG 312 ldap_perror(ld, "ldap_delete_s failed"); 313 #endif 314 } 315 } 316 else 317 { 318 result = NSL_ERR_UNKNOWN_PRINTER; 319 } 320 } 321 else 322 { 323 /* 324 * if object exists then this is a 325 * modify request otherwise is is an add request 326 */ 327 328 if (printerExists == LDAP_SUCCESS) 329 { 330 /* 331 * Modify the printer object to 332 * give it the new attribute values 333 * specified by the user 334 */ 335 result = 336 _modifyPrinterObject(ld, printerDN, 337 (uchar_t *)printerName, 338 domainDN, attrList); 339 } 340 else 341 { 342 /* 343 * add new printer object into the 344 * ldap directory with the user 345 * specified attribute values 346 */ 347 result = 348 _addNewPrinterObject(ld, 349 (uchar_t *)printerName, 350 domainDN, attrList); 351 } 352 } 353 354 if (printerDN != NULL) 355 { 356 free(printerDN); 357 } 358 if (domainDN != NULL) 359 { 360 free(domainDN); 361 } 362 363 /* disconnect from LDAP server */ 364 365 (void) ldap_unbind(ld); 366 } 367 } 368 369 else 370 { 371 /* no printerName given */ 372 result = NSL_ERR_INTERNAL; 373 } 374 375 return ((int)result); 376 } /* ldap_put_printer */ 377 378 379 380 381 /* 382 * ***************************************************************************** 383 * 384 * Function: _connectToLDAP() 385 * 386 * Description: Setup the connection and bind to the LDAP directory server. 387 * The function returns the ldap connection descriptor 388 * 389 * Note: Currently the native ldap functions do not support secure 390 * passwords, when this is supported this function will require 391 * updating to allow the type passed in cred->passwdType to 392 * be used with the ldap_simple_bind() 393 * 394 * Parameters: 395 * Input: ns_cred_t *cred - structure containing the credentials (host, 396 * port, user and password) required to bind 397 * to the directory server to be updated. 398 * char *printerName - printer name used only for error messages 399 * Output: LDAP** - ldap connection descriptor pointer. NULL = failed 400 * 401 * Returns: NSL_RESULT - NSL_OK = connected okay 402 * 403 * ***************************************************************************** 404 */ 405 406 static NSL_RESULT 407 _connectToLDAP(ns_cred_t *cred, LDAP **ld) 408 409 { 410 NSL_RESULT result = NSL_OK; 411 int lresult = 0; 412 int ldapPort = LDAP_PORT; /* default LDAP port number */ 413 int protoVersion = LDAP_VERSION3; 414 int derefOption = LDAP_DEREF_NEVER; 415 int referrals = 1; 416 char hostname[MAXHOSTNAMELEN]; 417 int tmpMethod = LDAP_AUTH_SIMPLE; /* temp - until its passed in */ 418 419 /* -------- */ 420 421 if ((ld == NULL) || (cred == NULL) || 422 ((cred->passwd == NULL) || (cred->binddn == NULL))) 423 { 424 result = NSL_ERR_CREDENTIALS; 425 } 426 427 else 428 { 429 *ld = NULL; 430 431 /* if host was not given then bind to local host */ 432 433 if (cred->host != NULL) 434 { 435 (void) strlcpy(hostname, cred->host, sizeof (hostname)); 436 } 437 else 438 { 439 (void) sysinfo(SI_HOSTNAME, 440 hostname, sizeof (hostname)); 441 } 442 443 /* initialise the connection to the ldap server */ 444 445 if (cred->port != 0) 446 { 447 ldapPort = cred->port; 448 } 449 *ld = ldap_init(hostname, ldapPort); 450 if (*ld == NULL) 451 { 452 /* connection setup failed */ 453 result = NSL_ERR_CONNECT; 454 #ifdef DEBUG 455 (void) perror("ldap_init"); 456 #endif 457 } 458 else 459 { 460 /* set ldap options */ 461 462 (void) ldap_set_option(*ld, LDAP_OPT_DEREF, 463 &derefOption); 464 (void) ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION, 465 &protoVersion); 466 (void) ldap_set_option(*ld, LDAP_OPT_REFERRALS, 467 &referrals); 468 469 /* bind to the user DN in the directory */ 470 471 /* cred->passwdType is currently not supported */ 472 473 lresult = ldap_simple_bind_s(*ld, 474 cred->binddn, cred->passwd); 475 476 /* 477 * before doing anything else, set up the function to 478 * call to get authentication details if the 479 * ldap update function calls (eg. ldap_add_s()) get a 480 * "referral" (to another ldap server) from the 481 * original ldap server, eg. if we are trying to do 482 * a update on a LDAP replica server. 483 */ 484 (void) _manageReferralCredentials(*ld, 485 &(cred->binddn), &(cred->passwd), 486 &tmpMethod, -1); 487 ldap_set_rebind_proc(*ld, 488 (LDAP_REBINDPROC_CALLBACK *) 489 _manageReferralCredentials, NULL); 490 491 if (lresult != LDAP_SUCCESS) 492 { 493 result = NSL_ERR_BIND; 494 *ld = NULL; 495 #ifdef DEBUG 496 (void) ldap_perror(*ld, "ldap_simple_bind_s"); 497 #endif 498 } 499 } 500 } 501 502 return (result); 503 } /* _connectToLDAP */ 504 505 506 507 508 509 /* 510 * ***************************************************************************** 511 * 512 * Function: _constructPrinterDN() 513 * 514 * Description: Construct the DN for the printer object from its name and NS 515 * domain DN. If the printer-uri is given in the attrList then 516 * that is used instead of the printerName. 517 * 518 * Parameters: 519 * Input: uchar_t *printerName 520 * uchar_t *domainDN 521 * char **attrList - this list is searched for printer-uri 522 * Output: None 523 * 524 * Returns: uchar_t* - pointer to the DN, this memory is malloced so 525 * must be freed using free() when finished with. 526 * 527 * ***************************************************************************** 528 */ 529 530 static uchar_t * 531 _constructPrinterDN(uchar_t *printerName, uchar_t *domainDN, char **attrList) 532 533 { 534 uchar_t *dn = NULL; 535 uchar_t *uri = NULL; 536 char **p = NULL; 537 int len = 0; 538 539 /* ------- */ 540 541 /* first search for printer-uri in the attribute list */ 542 543 for (p = attrList; (p != NULL) && (*p != NULL) && (uri == NULL); p++) 544 { 545 /* get length of this key word */ 546 547 for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); 548 549 if ((strncasecmp(*p, ATTR_URI, len) == 0) && 550 (strlen(*p) > len+1)) 551 { 552 uri = (uchar_t *)&((*p)[len+1]); 553 } 554 } 555 556 557 if (domainDN != NULL) { 558 size_t size; 559 560 /* malloc memory for the DN and then construct it */ 561 562 if ((uri == NULL) && (printerName != NULL)) 563 { 564 /* use the printerName for the RDN */ 565 566 size = strlen(ATTR_URI) + 567 strlen((char *)printerName) + 568 strlen((char *)domainDN) + 569 strlen(PCONTAINER) + 570 10; /* plus a few extra */ 571 572 if ((dn = malloc(size)) != NULL) 573 (void) snprintf((char *)dn, size, "%s=%s,%s,%s", 574 ATTR_URI, printerName, PCONTAINER, domainDN); 575 } 576 else 577 if (uri != NULL) 578 { 579 /* use the URI for the RDN */ 580 581 size = strlen(ATTR_URI) + 582 strlen((char *)uri) + 583 strlen((char *)domainDN) + 584 strlen(PCONTAINER) + 585 10; /* plus a few extra */ 586 587 if ((dn = malloc(size)) != NULL) 588 (void) snprintf((char *)dn, size, "%s=%s,%s,%s", 589 ATTR_URI, uri, PCONTAINER, domainDN); 590 } 591 592 /* 593 * else 594 * { 595 * printName not given so return null 596 * } 597 */ 598 599 } 600 601 return (dn); /* caller must free this memory */ 602 } /* _constructPrinterDN */ 603 604 605 606 /* 607 * ***************************************************************************** 608 * 609 * Function: _checkPrinterExists() 610 * 611 * Description: Check that the printer object for the printerName exists in the 612 * directory DIT and then extract the object's DN 613 * The function uses an exiting ldap connection and does a 614 * search for the printerName in the supplied domain DN. 615 * 616 * Parameters: 617 * Input: LDAP *ld - existing ldap connection descriptor 618 * uchar_t *printerName - printer name 619 * uchar_t *domainDN - DN of domain to search in 620 * Output: uchar_t **printerDN - DN of the printer - the caller should 621 * free this memory using free() 622 * 623 * Result: NSL_RESULT - NSL_OK = object exists 624 * 625 * ***************************************************************************** 626 */ 627 628 static NSL_RESULT 629 _checkPrinterExists(LDAP *ld, uchar_t *printerName, uchar_t *domainDN, 630 uchar_t **printerDN) 631 632 { 633 NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; 634 int sresult = LDAP_NO_SUCH_OBJECT; 635 LDAPMessage *ldapMsg = NULL; 636 char *requiredAttrs[2] = { ATTR_PNAME, NULL }; 637 LDAPMessage *ldapEntry = NULL; 638 uchar_t *filter = NULL; 639 uchar_t *baseDN = NULL; 640 641 /* ---------- */ 642 643 if ((printerName != NULL) && (domainDN != NULL) && (printerDN != NULL)) 644 { 645 size_t size; 646 647 if (printerDN != NULL) 648 { 649 *printerDN = NULL; 650 } 651 652 /* search for this Printer in the directory */ 653 654 size = (3 + strlen((char *)printerName) + strlen(ATTR_PNAME) + 655 2); 656 657 if ((filter = malloc(size)) != NULL) 658 (void) snprintf((char *)filter, size, "(%s=%s)", 659 ATTR_PNAME, (char *)printerName); 660 661 size = (strlen((char *)domainDN) + strlen(PCONTAINER) + 5); 662 663 if ((baseDN = malloc(size)) != NULL) 664 (void) snprintf((char *)baseDN, size, "%s,%s", 665 PCONTAINER, (char *)domainDN); 666 667 sresult = ldap_search_s(ld, (char *)baseDN, LDAP_SCOPE_SUBTREE, 668 (char *)filter, requiredAttrs, 0, &ldapMsg); 669 if (sresult == LDAP_SUCCESS) 670 { 671 /* check that the object exists and extract its DN */ 672 673 ldapEntry = ldap_first_entry(ld, ldapMsg); 674 if (ldapEntry != NULL) 675 { 676 /* object found - there should only be one */ 677 result = NSL_OK; 678 679 if (printerDN != NULL) 680 { 681 *printerDN = (uchar_t *) 682 ldap_get_dn(ld, ldapEntry); 683 } 684 } 685 686 (void) ldap_msgfree(ldapMsg); 687 } 688 } 689 690 else 691 { 692 result = NSL_ERR_INTERNAL; 693 } 694 695 return (result); 696 } /* _checkPrinterExists */ 697 698 699 700 701 /* 702 * ***************************************************************************** 703 * 704 * Function: _checkPrinterDNExists() 705 * 706 * Description: Check that the printer object for the DN exists in the 707 * directory DIT. 708 * The function uses an exiting ldap connection and does a 709 * search for the DN supplied. 710 * 711 * Parameters: LDAP *ld - existing ldap connection descriptor 712 * char *objectDN - DN to search for 713 * 714 * Result: NSL_RESULT - NSL_OK = object exists 715 * 716 * ***************************************************************************** 717 */ 718 719 static NSL_RESULT 720 _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN) 721 722 { 723 NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; 724 int sresult = LDAP_NO_SUCH_OBJECT; 725 LDAPMessage *ldapMsg; 726 char *requiredAttrs[2] = { ATTR_PNAME, NULL }; 727 LDAPMessage *ldapEntry; 728 729 /* ---------- */ 730 731 if ((ld != NULL) && (objectDN != NULL)) 732 { 733 /* search for this Printer in the directory */ 734 735 sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE, 736 "(objectclass=*)", requiredAttrs, 0, &ldapMsg); 737 if (sresult == LDAP_SUCCESS) 738 { 739 /* check that the object exists */ 740 ldapEntry = ldap_first_entry(ld, ldapMsg); 741 if (ldapEntry != NULL) 742 { 743 /* object found */ 744 result = NSL_OK; 745 } 746 747 (void) ldap_msgfree(ldapMsg); 748 } 749 } 750 751 else 752 { 753 result = NSL_ERR_INTERNAL; 754 } 755 756 return (result); 757 } /* _checkPrinterDNExists */ 758 759 760 761 762 763 /* 764 * ***************************************************************************** 765 * 766 * Function: _checkSunPrinter() 767 * 768 * Description: Check that the printer object for the printerDN is a sunPrinter 769 * ie. it has the required objectclass attribute value. 770 * 771 * Parameters: 772 * Input: LDAP *ld - existing ldap connection descriptor 773 * Output: uchar_t *printerDN - DN of the printer 774 * 775 * Result: NSL_RESULT - NSL_OK = object exists and is a sunPrinter 776 * 777 * ***************************************************************************** 778 */ 779 780 static NSL_RESULT 781 _checkSunPrinter(LDAP *ld, uchar_t *printerDN) 782 783 { 784 NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; 785 int sresult = LDAP_NO_SUCH_OBJECT; 786 char *requiredAttrs[2] = { ATTR_PNAME, NULL }; 787 LDAPMessage *ldapMsg = NULL; 788 LDAPMessage *ldapEntry = NULL; 789 char *filter = NULL; 790 791 /* ---------- */ 792 793 if ((ld != NULL) && (printerDN != NULL)) 794 { 795 size_t size; 796 797 /* search for this Printer in the directory */ 798 799 size = (3 + strlen(OCV_SUNPRT) + strlen(ATTR_OCLASS) + 2); 800 if ((filter = malloc(size)) != NULL) 801 (void) snprintf(filter, size, "(%s=%s)", 802 ATTR_OCLASS, OCV_SUNPRT); 803 804 sresult = ldap_search_s(ld, (char *)printerDN, 805 LDAP_SCOPE_SUBTREE, filter, 806 requiredAttrs, 0, &ldapMsg); 807 if (sresult == LDAP_SUCCESS) 808 { 809 /* check that the printer object exists */ 810 811 ldapEntry = ldap_first_entry(ld, ldapMsg); 812 if (ldapEntry != NULL) 813 { 814 /* object is a sunPrinter */ 815 result = NSL_OK; 816 } 817 818 (void) ldap_msgfree(ldapMsg); 819 } 820 } 821 822 else 823 { 824 result = NSL_ERR_INTERNAL; 825 } 826 827 return (result); 828 } /* _checkSunPrinter */ 829 830 831 832 833 834 /* 835 * ***************************************************************************** 836 * 837 * Function: _addNewPrinterObject() 838 * 839 * Description: For the given printerName add a printer object into the 840 * LDAP directory NS domain. The object is created with the 841 * supplied attribute values. Note: if the printer's uri is 842 * given that is used as the RDN otherwise the printer's 843 * name is used as the RDN 844 * 845 * Parameters: 846 * Input: LDAP *ld - existing ldap connection descriptor 847 * uchar_t *printerName - Name of printer to be added 848 * uchar_t *domainDN - DN of the domain to add the printer 849 * char **attrList - user specified attribute values list 850 * Output: None 851 * 852 * Returns: NSL_RESULT - NSL_OK = request actioned okay 853 * !NSL_OK = error 854 * 855 * ***************************************************************************** 856 */ 857 858 static NSL_RESULT 859 _addNewPrinterObject(LDAP *ld, uchar_t *printerName, 860 uchar_t *domainDN, char **attrList) 861 862 { 863 NSL_RESULT result = NSL_ERR_ADD_FAILED; 864 int lresult = 0; 865 uchar_t *printerDN = NULL; 866 LDAPMod **attrs = NULL; 867 868 /* ---------- */ 869 870 if ((ld != NULL) && (printerName != NULL) && (domainDN != NULL) && 871 (attrList != NULL) && (attrList[0] != NULL)) 872 { 873 result = _checkAttributes(attrList); 874 875 if (result == NSL_OK) 876 { 877 /* 878 * construct a DN for the printer from the 879 * printerName and printer-uri if given. 880 */ 881 printerDN = _constructPrinterDN(printerName, 882 domainDN, attrList); 883 if (printerDN != NULL) 884 { 885 /* 886 * setup attribute values in an LDAPMod 887 * structure and then add the object 888 */ 889 result = _constructAddLDAPMod(printerName, 890 attrList, &attrs); 891 if (result == NSL_OK) 892 { 893 lresult = ldap_add_s(ld, 894 (char *)printerDN, attrs); 895 if (lresult == LDAP_SUCCESS) 896 { 897 result = NSL_OK; 898 } 899 else 900 { 901 result = NSL_ERR_ADD_FAILED; 902 #ifdef DEBUG 903 (void) ldap_perror(ld, "ldap_add_s"); 904 #endif 905 } 906 907 (void) ldap_mods_free(attrs, 1); 908 } 909 free(printerDN); 910 } 911 912 else 913 { 914 result = NSL_ERR_INTERNAL; 915 } 916 } 917 } 918 919 else 920 { 921 result = NSL_ERR_INTERNAL; 922 } 923 924 return (result); 925 } /* _addNewPrinterObject */ 926 927 928 929 930 931 932 /* 933 * ***************************************************************************** 934 * 935 * Function: _modifyPrinterObject() 936 * 937 * Description: Modify the given LDAP printer object to set the new attributes 938 * in the attribute list. If the printer's URI (specified in the 939 * attrList) changes the URI of the object the request is rejected. 940 * 941 * Parameters: 942 * Input: LDAP *ld - existing ldap connection descriptor 943 * uchar_t *printerDN - DN of printer object to modify 944 * uchar_t *printerName - Name of printer to be modified 945 * uchar_t *domainDN - DN of the domain the printer is in 946 * char **attrList - user specified attribute values list 947 * Output: None 948 * 949 * Returns: NSL_RESULT - NSL_OK = object modified okay 950 * 951 * ***************************************************************************** 952 */ 953 954 static NSL_RESULT 955 _modifyPrinterObject(LDAP *ld, uchar_t *printerDN, 956 uchar_t *printerName, uchar_t *domainDN, char **attrList) 957 958 { 959 NSL_RESULT result = NSL_ERR_INTERNAL; 960 int lresult = 0; 961 int sunPrinter = 0; 962 uchar_t *uriDN = NULL; 963 LDAPMod **attrs = NULL; 964 char **kvpList = NULL; 965 966 /* ---------- */ 967 968 if ((ld != NULL) && (printerDN != NULL) && (printerName != NULL) && 969 (domainDN != NULL) && (attrList != NULL) && (attrList[0] != NULL)) 970 { 971 result = _checkAttributes(attrList); 972 973 if (result == NSL_OK) 974 { 975 /* 976 * The user may have requested that the printer object 977 * be given a new URI RDN, so construct a DN for the 978 * printer from the printerName or the printer-uri (if 979 * given). 980 */ 981 uriDN = _constructPrinterDN(NULL, domainDN, attrList); 982 983 /* 984 * compare the 2 DNs to see if the URI has changed, 985 * if uriDN is null then the DN hasn't changed 986 */ 987 if ((uriDN == NULL) || ((uriDN != NULL) && 988 (_compareURIinDNs(printerDN, uriDN) == NSL_OK))) 989 { 990 /* 991 * setup the modify object LDAPMod 992 * structure and then do the modify 993 */ 994 995 if (_checkSunPrinter(ld, printerDN) == NSL_OK) 996 { 997 sunPrinter = 1; 998 } 999 1000 (void) _getCurrentKVPValues(ld, 1001 printerDN, &kvpList); 1002 1003 result = _constructModLDAPMod(printerName, 1004 sunPrinter, attrList, 1005 &kvpList, &attrs); 1006 _freeList(&kvpList); 1007 1008 if ((result == NSL_OK) && (attrs != NULL)) 1009 { 1010 lresult = ldap_modify_s( 1011 ld, (char *)printerDN, attrs); 1012 if (lresult == LDAP_SUCCESS) 1013 { 1014 result = NSL_OK; 1015 } 1016 else 1017 { 1018 result = NSL_ERR_MOD_FAILED; 1019 #ifdef DEBUG 1020 (void) ldap_perror(ld, "ldap_modify_s"); 1021 #endif 1022 } 1023 1024 (void) ldap_mods_free(attrs, 1); 1025 } 1026 } 1027 else 1028 { 1029 /* 1030 * printer-uri name change has been requested 1031 * this is NOT allowed as it requires that 1032 * a new printer object is created 1033 */ 1034 result = NSL_ERR_RENAME; /* NOT ALLOWED */ 1035 } 1036 1037 if (uriDN != NULL) 1038 { 1039 free(uriDN); 1040 } 1041 } 1042 } 1043 1044 return (result); 1045 } /* _modifyPrinterObject */ 1046 1047 1048 1049 1050 /* 1051 * ***************************************************************************** 1052 * 1053 * Function: _checkAttributes() 1054 * 1055 * Description: Check that the given attribute lists does not contain any 1056 * key words that are not allowed. 1057 * 1058 * Parameters: 1059 * Input: char **list - attribute list to check 1060 * Output: None 1061 * 1062 * Returns: NSL_RESULT - NSL_OK = checked okay 1063 * 1064 * ***************************************************************************** 1065 */ 1066 1067 static NSL_RESULT 1068 _checkAttributes(char **list) 1069 1070 { 1071 NSL_RESULT result = NSL_OK; 1072 int len = 0; 1073 char *attr = NULL; 1074 char **p = NULL; 1075 1076 /* ------ */ 1077 1078 for (p = list; (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) 1079 { 1080 /* get length of this key word */ 1081 1082 for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); 1083 1084 /* check if the key word is allowed */ 1085 1086 if (strncasecmp(*p, ATTR_KVP, len) == 0) 1087 { 1088 /* not supported through this interface */ 1089 result = NSL_ERR_KVP; 1090 } 1091 else 1092 if (strncasecmp(*p, ATTR_BSDADDR, len) == 0) 1093 { 1094 /* not supported through this interface */ 1095 result = NSL_ERR_BSDADDR; 1096 } 1097 else 1098 if (strncasecmp(*p, ATTR_PNAME, len) == 0) 1099 { 1100 /* not supported through this interface */ 1101 result = NSL_ERR_PNAME; 1102 } 1103 else 1104 { 1105 /* check for any others */ 1106 1107 attr = strdup(*p); 1108 attr[len] = '\0'; /* terminate the key */ 1109 1110 if (_attrInList(attr, nsl_attr_notAllowed)) 1111 { 1112 result = NSL_ERR_NOTALLOWED; 1113 } 1114 } 1115 1116 } 1117 1118 return (result); 1119 } /* _checkAttributes */ 1120 1121 1122 1123 1124 /* 1125 * ***************************************************************************** 1126 * 1127 * Function: _addLDAPmodValue() 1128 * 1129 * Description: Add the given attribute and its value to the LDAPMod array. 1130 * If this is the first entry in the array then create it. 1131 * 1132 * Parameters: 1133 * Input: LDAPMod ***attrs - array to update 1134 * char *type - attribute to add into array 1135 * char *value - attribute value 1136 * Output: None 1137 * 1138 * Returns: NSL_RESULT - NSL_OK = added okay 1139 * 1140 * ***************************************************************************** 1141 */ 1142 1143 static NSL_RESULT 1144 _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value) 1145 1146 { 1147 int i = 0; 1148 int j = 0; 1149 NSL_RESULT result = NSL_OK; 1150 1151 /* ---------- */ 1152 1153 if ((attrs != NULL) && (type != NULL) && (value != NULL)) 1154 { 1155 #ifdef DEBUG 1156 printf("_addLDAPmodValue() type='%s', value='%s'\n", type, value); 1157 #endif 1158 /* search the existing LDAPMod array for the attribute */ 1159 1160 for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++) 1161 { 1162 if (strcasecmp((*attrs)[i]->mod_type, type) == 0) 1163 { 1164 break; 1165 } 1166 } 1167 1168 if (*attrs == NULL) 1169 { 1170 /* array empty so create it */ 1171 1172 *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *)); 1173 if (*attrs != NULL) 1174 { 1175 i = 0; 1176 } 1177 else 1178 { 1179 result = NSL_ERR_MEMORY; 1180 } 1181 1182 } 1183 else 1184 if ((*attrs)[i] == NULL) 1185 { 1186 *attrs = (LDAPMod **) 1187 realloc(*attrs, (i+2) * sizeof (LDAPMod *)); 1188 if (*attrs == NULL) 1189 { 1190 result = NSL_ERR_MEMORY; 1191 } 1192 } 1193 } 1194 else 1195 { 1196 result = NSL_ERR_INTERNAL; 1197 } 1198 1199 if (result == NSL_OK) 1200 { 1201 if ((*attrs)[i] == NULL) 1202 { 1203 /* We've got a new slot. Create the new mod. */ 1204 1205 (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod)); 1206 if ((*attrs)[i] != NULL) 1207 { 1208 (*attrs)[i]->mod_op = LDAP_MOD_ADD; 1209 (*attrs)[i]->mod_type = strdup(type); 1210 (*attrs)[i]->mod_values = (char **) 1211 malloc(2 * sizeof (char *)); 1212 if ((*attrs)[i]->mod_values != NULL) 1213 { 1214 (*attrs)[i]->mod_values[0] = 1215 strdup(value); 1216 (*attrs)[i]->mod_values[1] = NULL; 1217 (*attrs)[i+1] = NULL; 1218 } 1219 else 1220 { 1221 result = NSL_ERR_MEMORY; 1222 } 1223 } 1224 else 1225 { 1226 result = NSL_ERR_MEMORY; 1227 } 1228 } 1229 1230 else 1231 { 1232 /* Found an existing entry so add value to it */ 1233 1234 for (j = 0; (*attrs)[i]->mod_values[j] != NULL; j++); 1235 1236 (*attrs)[i]->mod_values = 1237 (char **)realloc((*attrs)[i]->mod_values, 1238 (j + 2) * sizeof (char *)); 1239 if ((*attrs)[i]->mod_values != NULL) 1240 { 1241 (*attrs)[i]->mod_values[j] = strdup(value); 1242 (*attrs)[i]->mod_values[j+1] = NULL; 1243 } 1244 else 1245 { 1246 result = NSL_ERR_MEMORY; 1247 } 1248 } 1249 } 1250 1251 return (result); 1252 } /* _addLDAPmodValue */ 1253 1254 1255 1256 1257 /* 1258 * ***************************************************************************** 1259 * 1260 * Function: _modLDAPmodValue() 1261 * 1262 * Description: Add the given attribute modify operation and its value into 1263 * the LDAPMod array. This will either be a "replace" or a 1264 * "delete"; value = null implies a "delete". 1265 * If this is the first entry in the array then create it. 1266 * 1267 * Parameters: 1268 * Input: LDAPMod ***attrs - array to update 1269 * char *type - attribute to modify 1270 * char *value - attribute value, null implies "delete" 1271 * Output: None 1272 * 1273 * Returns: NSL_RESULT - NSL_OK = added okay 1274 * 1275 * ***************************************************************************** 1276 */ 1277 1278 static NSL_RESULT 1279 _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value) 1280 1281 { 1282 int i = 0; 1283 int j = 0; 1284 NSL_RESULT result = NSL_OK; 1285 1286 /* ---------- */ 1287 1288 if ((attrs != NULL) && (type != NULL)) 1289 { 1290 #ifdef DEBUG 1291 if (value != NULL) 1292 printf("_modLDAPmodValue() REPLACE type='%s', value='%s'\n", type, value); 1293 else 1294 printf("_modLDAPmodValue() DELETE type='%s'\n", type); 1295 #endif 1296 /* search the existing LDAPMod array for the attribute */ 1297 1298 for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++) 1299 { 1300 if (strcasecmp((*attrs)[i]->mod_type, type) == 0) 1301 { 1302 break; 1303 } 1304 } 1305 1306 if (*attrs == NULL) 1307 { 1308 /* array empty so create it */ 1309 1310 *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *)); 1311 if (*attrs != NULL) 1312 { 1313 i = 0; 1314 } 1315 else 1316 { 1317 result = NSL_ERR_MEMORY; 1318 } 1319 1320 } 1321 else 1322 if ((*attrs)[i] == NULL) 1323 { 1324 /* attribute not found in array so add slot for it */ 1325 1326 *attrs = (LDAPMod **) 1327 realloc(*attrs, (i+2) * sizeof (LDAPMod *)); 1328 if (*attrs == NULL) 1329 { 1330 result = NSL_ERR_MEMORY; 1331 } 1332 } 1333 } 1334 else 1335 { 1336 result = NSL_ERR_INTERNAL; 1337 } 1338 1339 if (result == NSL_OK) 1340 { 1341 if ((*attrs)[i] == NULL) 1342 { 1343 /* We've got a new slot. Create the new mod entry */ 1344 1345 (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod)); 1346 if (((*attrs)[i] != NULL) && (value != NULL)) 1347 { 1348 /* Do an attribute replace */ 1349 1350 (*attrs)[i]->mod_op = LDAP_MOD_REPLACE; 1351 (*attrs)[i]->mod_type = strdup(type); 1352 (*attrs)[i]->mod_values = (char **) 1353 malloc(2 * sizeof (char *)); 1354 if ((*attrs)[i]->mod_values != NULL) 1355 { 1356 (*attrs)[i]->mod_values[0] = 1357 strdup(value); 1358 (*attrs)[i]->mod_values[1] = NULL; 1359 (*attrs)[i+1] = NULL; 1360 } 1361 else 1362 { 1363 result = NSL_ERR_MEMORY; 1364 } 1365 } 1366 else 1367 if ((*attrs)[i] != NULL) 1368 { 1369 /* value is null so do an attribute delete */ 1370 1371 (*attrs)[i]->mod_op = LDAP_MOD_DELETE; 1372 (*attrs)[i]->mod_type = strdup(type); 1373 (*attrs)[i]->mod_values = NULL; 1374 (*attrs)[i+1] = NULL; 1375 } 1376 else 1377 { 1378 result = NSL_ERR_MEMORY; /* malloc failed */ 1379 } 1380 } 1381 1382 else 1383 { 1384 /* Found an existing entry so add value to it */ 1385 1386 if (value != NULL) 1387 { 1388 /* add value to attribute's replace list */ 1389 1390 if ((*attrs)[i]->mod_op == LDAP_MOD_REPLACE) 1391 { 1392 for (j = 0; 1393 (*attrs)[i]->mod_values[j] != NULL; j++); 1394 1395 (*attrs)[i]->mod_values = 1396 (char **)realloc((*attrs)[i]->mod_values, 1397 (j + 2) * sizeof (char *)); 1398 if ((*attrs)[i]->mod_values != NULL) 1399 { 1400 (*attrs)[i]->mod_values[j] = 1401 strdup(value); 1402 (*attrs)[i]->mod_values[j+1] = NULL; 1403 } 1404 else 1405 { 1406 result = NSL_ERR_MEMORY; 1407 } 1408 } 1409 else 1410 { 1411 /* Delete and replace not allowed */ 1412 result = NSL_ERR_MULTIOP; 1413 } 1414 } 1415 1416 else 1417 { 1418 /* 1419 * attribute delete - so free any existing 1420 * entries in the value array 1421 */ 1422 1423 (*attrs)[i]->mod_op = LDAP_MOD_DELETE; 1424 1425 if ((*attrs)[i]->mod_values != NULL) 1426 { 1427 for (j = 0; 1428 (*attrs)[i]->mod_values[j] != NULL; 1429 j++) 1430 { 1431 free((*attrs)[i]->mod_values[j]); 1432 } 1433 1434 free((*attrs)[i]->mod_values); 1435 (*attrs)[i]->mod_values = NULL; 1436 } 1437 } 1438 } 1439 } 1440 1441 return (result); 1442 } /* _modLDAPmodValue */ 1443 1444 1445 1446 1447 1448 /* 1449 * ***************************************************************************** 1450 * 1451 * Function: _constructAddLDAPMod() 1452 * 1453 * Description: For the given attribute list construct an 1454 * LDAPMod array for the printer object to be added. Default 1455 * attribute values are included. 1456 * 1457 * Parameters: 1458 * Input: 1459 * uchar_t *printerName - Name of printer to be added 1460 * char **attrList - user specified attribute values list 1461 * Output: LDAPMod ***attrs - pointer to the constructed array 1462 * 1463 * Returns: NSL_RESULT - NSL_OK = constructed okay 1464 * 1465 * ***************************************************************************** 1466 */ 1467 1468 static NSL_RESULT 1469 _constructAddLDAPMod(uchar_t *printerName, char **attrList, LDAPMod ***attrs) 1470 1471 { 1472 NSL_RESULT result = NSL_ERROR; 1473 int len = 0; 1474 char **p = NULL; 1475 char *value = NULL; 1476 char *attr = NULL; 1477 1478 /* ---------- */ 1479 1480 if ((printerName != NULL) && 1481 ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL)) 1482 { 1483 *attrs = NULL; 1484 1485 /* 1486 * setup printer object attribute values in an LDAPMod structure 1487 */ 1488 result = _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_TOP); 1489 if (result == NSL_OK) 1490 { 1491 /* Structural Objectclass */ 1492 result = 1493 _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_PSERVICE); 1494 } 1495 if (result == NSL_OK) 1496 { 1497 result = _addLDAPmodValue(attrs, 1498 ATTR_OCLASS, OCV_PABSTRACT); 1499 } 1500 if (result == NSL_OK) 1501 { 1502 result = _addLDAPmodValue(attrs, 1503 ATTR_OCLASS, OCV_SUNPRT); 1504 } 1505 if (result == NSL_OK) 1506 { 1507 result = _addLDAPmodValue(attrs, 1508 ATTR_PNAME, (char *)printerName); 1509 } 1510 1511 /* 1512 * Now work through the user supplied attribute 1513 * values list and add them into the LDAPMod array 1514 */ 1515 1516 for (p = attrList; 1517 (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) 1518 { 1519 /* get length of this key word */ 1520 1521 for (len = 0; 1522 ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); 1523 1524 if ((strlen(*p) > len+1)) 1525 { 1526 attr = strdup(*p); 1527 attr[len] = '\0'; 1528 value = strdup(&attr[len+1]); 1529 1530 /* handle specific Key Value Pairs (KVP) */ 1531 1532 if (strcasecmp(attr, NS_KEY_BSDADDR) == 0) 1533 { 1534 /* use LDAP attribute name */ 1535 free(attr); 1536 attr = strdup(ATTR_BSDADDR); 1537 } 1538 else 1539 if (_attrInLDAPList(attr) == 0) 1540 { 1541 /* 1542 * Non-LDAP attribute so use LDAP 1543 * KVP attribute and the given KVP 1544 * as the value, ie. 1545 * sun-printer-kvp=description=printer 1546 */ 1547 free(attr); 1548 attr = strdup(ATTR_KVP); 1549 value = strdup(*p); 1550 } 1551 1552 /* add it into the LDAPMod array */ 1553 1554 result = _addLDAPmodValue(attrs, attr, value); 1555 1556 free(attr); 1557 free(value); 1558 } 1559 } /* for */ 1560 1561 if ((result != NSL_OK) && (*attrs != NULL)) 1562 { 1563 (void) ldap_mods_free(*attrs, 1); 1564 attrs = NULL; 1565 } 1566 } 1567 else 1568 { 1569 result = NSL_ERR_INTERNAL; 1570 } 1571 1572 return (result); 1573 } /* _constructAddLDAPMod */ 1574 1575 1576 1577 1578 1579 1580 1581 /* 1582 * ***************************************************************************** 1583 * 1584 * Function: _constructModLDAPMod() 1585 * 1586 * Description: For the given modify attribute list, construct an 1587 * LDAPMod array for the printer object to be modified 1588 * 1589 * Parameters: 1590 * Input: uchar_t *printerName - name of printer to be modified 1591 * int sunPrinter - Boolean; object is a sunPrinter 1592 * char **attrList - user specified attribute values list 1593 * char ***oldKVPList - current list of KVP values on object 1594 * Output: LDAPMod ***attrs - pointer to the constructed array 1595 * 1596 * Returns: NSL_RESULT - NSL_OK = constructed okay 1597 * 1598 * ***************************************************************************** 1599 */ 1600 1601 static NSL_RESULT 1602 _constructModLDAPMod(uchar_t *printerName, int sunPrinter, char **attrList, 1603 char ***oldKVPList, LDAPMod ***attrs) 1604 1605 { 1606 NSL_RESULT result = NSL_OK; 1607 int len = 0; 1608 int kvpUpdated = 0; 1609 int kvpExists = 0; 1610 char **p = NULL; 1611 char *value = NULL; 1612 char *attr = NULL; 1613 1614 /* ---------- */ 1615 1616 if ((printerName != NULL) && 1617 ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL)) 1618 { 1619 *attrs = NULL; 1620 1621 if ((oldKVPList != NULL) && (*oldKVPList != NULL)) 1622 { 1623 kvpExists = 1; 1624 } 1625 1626 if (!sunPrinter) 1627 { 1628 /* 1629 * The object was previously not a sunPrinter, so 1630 * add the required objectclass attribute value, and 1631 * ensure it has the printername attribute. 1632 */ 1633 result = _addLDAPmodValue(attrs, 1634 ATTR_OCLASS, OCV_SUNPRT); 1635 if (result == NSL_OK) 1636 { 1637 result = _modLDAPmodValue(attrs, 1638 ATTR_PNAME, (char *)printerName); 1639 } 1640 } 1641 1642 /* 1643 * work through the user supplied attribute 1644 * values list and add them into the LDAPMod array depending 1645 * on if they are a replace or delete attribute operation, 1646 * a "null value" means delete. 1647 */ 1648 1649 for (p = attrList; 1650 (p != NULL) && (*p != NULL) && (result == NSL_OK); p++) 1651 { 1652 /* get length of this key word */ 1653 1654 for (len = 0; 1655 ((*p)[len] != '=') && ((*p)[len] != '\0'); len++); 1656 1657 if ((strlen(*p) > len+1)) 1658 { 1659 attr = strdup(*p); 1660 attr[len] = '\0'; 1661 value = strdup(&attr[len+1]); 1662 1663 /* handle specific Key Value Pairs (KVP) */ 1664 1665 if ((_attrInLDAPList(attr) == 0) && 1666 (strcasecmp(attr, NS_KEY_BSDADDR) != 0)) 1667 { 1668 /* 1669 * Non-LDAP attribute so use LDAP 1670 * KVP attribute and the given KVP as 1671 * the value, ie. 1672 * sun-printer-kvp=description=printer 1673 */ 1674 result = _modAttrKVP(*p, oldKVPList); 1675 kvpUpdated = 1; 1676 } 1677 1678 else 1679 { 1680 if (strcasecmp(attr, NS_KEY_BSDADDR) == 1681 0) 1682 { 1683 /* 1684 * use LDAP bsdaddr attribute 1685 * name 1686 */ 1687 free(attr); 1688 attr = strdup(ATTR_BSDADDR); 1689 } 1690 1691 /* 1692 * else 1693 * use the supplied attribute name 1694 */ 1695 1696 /* add it into the LDAPMod array */ 1697 1698 result = _modLDAPmodValue(attrs, 1699 attr, value); 1700 } 1701 1702 free(attr); 1703 free(value); 1704 } 1705 1706 else 1707 if (strlen(*p) >= 1) 1708 { 1709 /* handle attribute DELETE request */ 1710 1711 attr = strdup(*p); 1712 if (attr[len] == '=') 1713 { 1714 /* terminate "attribute=" */ 1715 attr[len] = '\0'; 1716 } 1717 1718 /* handle specific Key Value Pairs (KVP) */ 1719 1720 if (strcasecmp(attr, NS_KEY_BSDADDR) == 0) 1721 { 1722 /* use LDAP bsdaddr attribute name */ 1723 result = _modLDAPmodValue(attrs, 1724 ATTR_BSDADDR, NULL); 1725 } 1726 else 1727 if (_attrInLDAPList(attr) == 0) 1728 { 1729 /* 1730 * Non-LDAP kvp, so sort items 1731 * in the kvp list 1732 */ 1733 result = _modAttrKVP(*p, oldKVPList); 1734 kvpUpdated = 1; 1735 } 1736 else 1737 { 1738 result = _modLDAPmodValue(attrs, 1739 attr, NULL); 1740 } 1741 1742 free(attr); 1743 } 1744 } /* for */ 1745 1746 if ((result == NSL_OK) && (kvpUpdated)) 1747 { 1748 result = _attrAddKVP(attrs, *oldKVPList, kvpExists); 1749 } 1750 1751 if ((result != NSL_OK) && (*attrs != NULL)) 1752 { 1753 (void) ldap_mods_free(*attrs, 1); 1754 *attrs = NULL; 1755 } 1756 } 1757 else 1758 { 1759 result = NSL_ERR_INTERNAL; 1760 } 1761 1762 return (result); 1763 } /* _constructModLDAPMod */ 1764 1765 1766 1767 1768 1769 1770 /* 1771 * ***************************************************************************** 1772 * 1773 * Function: _compareURIinDNs() 1774 * 1775 * Description: For the 2 given printer object DNs compare the naming part 1776 * part of the DN (printer-uri) to see if they are the same. 1777 * 1778 * Note: This function only returns "compare failed" if their URI don't 1779 * compare. Problems with the dn etc., return a good compare 1780 * because I don't want us to create a new object for these 1781 * 1782 * Parameters: 1783 * Input: uchar_t *dn1 1784 * uchar_t *dn2 1785 * Output: None 1786 * 1787 * Returns: NSL_RESULT - NSL_OK = URIs are the same 1788 * 1789 * ***************************************************************************** 1790 */ 1791 1792 static NSL_RESULT 1793 _compareURIinDNs(uchar_t *dn1, uchar_t *dn2) 1794 1795 { 1796 NSL_RESULT result = NSL_OK; 1797 uchar_t *DN1 = NULL; 1798 uchar_t *DN2 = NULL; 1799 char *p1 = NULL; 1800 char *p2 = NULL; 1801 1802 /* --------- */ 1803 1804 if ((dn1 != NULL) && (dn2 != NULL)) 1805 { 1806 DN1 = (uchar_t *)strdup((char *)dn1); 1807 DN2 = (uchar_t *)strdup((char *)dn2); 1808 1809 /* terminate each string after the printer-uri */ 1810 1811 p1 = strstr((char *)DN1, PCONTAINER); 1812 /* move back to the comma */ 1813 while ((p1 != NULL) && (*p1 != ',') && (p1 >= (char *)DN1)) 1814 { 1815 p1--; 1816 } 1817 1818 p2 = strstr((char *)DN2, PCONTAINER); 1819 /* move back to the comma */ 1820 while ((p2 != NULL) && (*p2 != ',') && (p2 >= (char *)DN2)) 1821 { 1822 p2--; 1823 } 1824 1825 if ((*p1 == ',') && (*p2 == ',')) 1826 { 1827 *p1 = '\0'; /* re-terminate it */ 1828 *p2 = '\0'; /* re-terminate it */ 1829 1830 /* do the compare */ 1831 1832 /* 1833 * Note: SHOULD really normalise the 2 DNs before 1834 * doing the compare 1835 */ 1836 #ifdef DEBUG 1837 printf("_compareURIinDNs() @1 (%s) (%s)\n", DN1, DN2); 1838 #endif 1839 if (strcasecmp((char *)DN1, (char *)DN2) != 0) 1840 { 1841 result = NSL_ERROR; 1842 } 1843 1844 } 1845 1846 free(DN1); 1847 free(DN2); 1848 } 1849 1850 return (result); 1851 } /* _compareURIinDNs */ 1852 1853 1854 1855 1856 1857 1858 1859 /* 1860 * ***************************************************************************** 1861 * 1862 * Function: _getThisNSDomainDN() 1863 * 1864 * Description: Get the current Name Service Domain DN 1865 * This is extracted from the result of executing ldaplist. 1866 * 1867 * Note: Do it this way until the NS LDAP library interface is 1868 * made public. 1869 * 1870 * Parameters: 1871 * Input: None 1872 * Output: None 1873 * 1874 * Returns: uchar_t* - pointer to NS Domain DN (The caller should free this 1875 * returned memory). 1876 * 1877 * ***************************************************************************** 1878 */ 1879 1880 #define LDAPLIST_D "/usr/bin/ldaplist -d 2>&1" 1881 #define DNID "dn: " 1882 1883 static uchar_t * 1884 _getThisNSDomainDN(void) 1885 1886 { 1887 uchar_t *domainDN = NULL; 1888 char *cp = NULL; 1889 char buf[BUFSIZ] = ""; 1890 1891 /* --------- */ 1892 1893 if (_popen(LDAPLIST_D, buf, sizeof (buf)) == 0) 1894 { 1895 if ((cp = strstr(buf, DNID)) != NULL) 1896 { 1897 cp += strlen(DNID); /* increment past "dn: " label */ 1898 domainDN = (uchar_t *)strdup(cp); 1899 1900 if ((cp = strchr((char *)domainDN, '\n')) != NULL) 1901 { 1902 *cp = '\0'; /* terminate it */ 1903 } 1904 } 1905 } 1906 1907 return (domainDN); 1908 } /* _getThisNSDomainDN */ 1909 1910 1911 1912 1913 1914 /* 1915 * ***************************************************************************** 1916 * 1917 * Function: _popen() 1918 * 1919 * Description: General popen function. The caller should always use a full 1920 * path cmd. 1921 * 1922 * Parameters: 1923 * Input: char *cmd - command line to execute 1924 * char *buffer - ptr to buffer to put result in 1925 * int size - size of result buffer 1926 * Output: None 1927 * 1928 * Returns: int - 0 = opened okay 1929 * 1930 * ***************************************************************************** 1931 */ 1932 1933 static int 1934 _popen(char *cmd, char *buffer, int size) 1935 1936 { 1937 int result = -1; 1938 int rsize = 0; 1939 FILE *fptr; 1940 char safe_cmd[BUFSIZ]; 1941 char linebuf[BUFSIZ]; 1942 1943 /* -------- */ 1944 1945 if ((cmd != NULL) && (buffer != NULL) && (size != 0)) 1946 { 1947 (void) strcpy(buffer, ""); 1948 (void) strcpy(linebuf, ""); 1949 (void) snprintf(safe_cmd, BUFSIZ, "IFS=' \t'; %s", cmd); 1950 1951 if ((fptr = popen(safe_cmd, "r")) != NULL) 1952 { 1953 while ((fgets(linebuf, BUFSIZ, fptr) != NULL) && 1954 (rsize < size)) 1955 { 1956 rsize = strlcat(buffer, linebuf, size); 1957 if (rsize >= size) 1958 { 1959 /* result is too long */ 1960 (void) memset(buffer, '\0', size); 1961 } 1962 } 1963 1964 if (strlen(buffer) > 0) 1965 { 1966 result = 0; 1967 } 1968 1969 (void) pclose(fptr); 1970 } 1971 } 1972 1973 return (result); 1974 } /* popen */ 1975 1976 1977 /* 1978 * ***************************************************************************** 1979 * 1980 * Function: _attrInList() 1981 * 1982 * Description: For the given list check if the attribute is it 1983 * 1984 * Parameters: 1985 * Input: char *attr - attribute to check 1986 * char **list - list of attributes to check against 1987 * Output: None 1988 * 1989 * Returns: int - TRUE = attr found in list 1990 * 1991 * ***************************************************************************** 1992 */ 1993 1994 static int 1995 _attrInList(char *attr, const char **list) 1996 1997 { 1998 int result = 0; 1999 int j; 2000 2001 /* ------- */ 2002 2003 if ((attr != NULL) && (list != NULL)) 2004 { 2005 for (j = 0; (list[j] != NULL) && (result != 1); j++) 2006 { 2007 if (strcasecmp(list[j], attr) == 0) 2008 { 2009 result = 1; /* found */ 2010 } 2011 } 2012 } 2013 2014 return (result); 2015 } /* _attrInList */ 2016 2017 2018 2019 2020 /* 2021 * ***************************************************************************** 2022 * 2023 * Function: _attrInLDAPList() 2024 * 2025 * Description: Checks to see if the given attribute is an LDAP printing 2026 * attribute, ie. is either in an IPP objectclass or the 2027 * sun printer objectclass. Note: some attributes are handled 2028 * specifically outside this function, so are excluded from 2029 * the lists that are checked. 2030 * 2031 * Parameters: 2032 * Input: char *attr - attribute to check 2033 * Output: None 2034 * 2035 * Returns: int - TRUE = attr found in list 2036 * 2037 * ***************************************************************************** 2038 */ 2039 2040 static int 2041 _attrInLDAPList(char *attr) 2042 2043 { 2044 int result = 0; 2045 2046 /* ------- */ 2047 2048 if (_attrInList(attr, nsl_attr_printerService)) 2049 { 2050 result = 1; /* in list */ 2051 } 2052 else 2053 if (_attrInList(attr, nsl_attr_printerIPP)) 2054 { 2055 result = 1; /* in list */ 2056 } 2057 else 2058 if (_attrInList(attr, nsl_attr_sunPrinter)) 2059 { 2060 result = 1; /* in list */ 2061 } 2062 2063 return (result); 2064 } /* _attrInLDAPList */ 2065 2066 2067 2068 2069 /* 2070 * ***************************************************************************** 2071 * 2072 * Function: _getCurrentKVPValues() 2073 * 2074 * Description: For the given printer object read the current set of values 2075 * the object has for the sun-printer-kvp (Key Value pair) 2076 * 2077 * Parameters: 2078 * Input: LDAP *ld - existing ldap connection descriptor 2079 * char *objectDN - DN to search for 2080 * Output: char ***list - returned set of kvp values 2081 * 2082 * Result: NSL_RESULT - NSL_OK = object exists 2083 * 2084 * ***************************************************************************** 2085 */ 2086 2087 static NSL_RESULT 2088 _getCurrentKVPValues(LDAP *ld, uchar_t *objectDN, char ***list) 2089 2090 { 2091 NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER; 2092 int sresult = LDAP_NO_SUCH_OBJECT; 2093 int i = 0; 2094 LDAPMessage *ldapMsg; 2095 char *requiredAttrs[2] = { ATTR_KVP, NULL }; 2096 LDAPMessage *ldapEntry = NULL; 2097 char *entryAttrib = NULL; 2098 char **attribValues = NULL; 2099 BerElement *berElement = NULL; 2100 2101 /* ---------- */ 2102 2103 if ((list != NULL) && (ld != NULL) && (objectDN != NULL)) 2104 { 2105 /* search for this Printer in the directory */ 2106 2107 sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE, 2108 "(objectclass=*)", requiredAttrs, 0, &ldapMsg); 2109 if (sresult == LDAP_SUCCESS) 2110 { 2111 /* 2112 * check that the object exists and extract its 2113 * KVP attribute values 2114 */ 2115 ldapEntry = ldap_first_entry(ld, ldapMsg); 2116 if (ldapEntry != NULL) 2117 { 2118 entryAttrib = ldap_first_attribute(ld, 2119 ldapEntry, &berElement); 2120 if ((entryAttrib != NULL) && 2121 (strcasecmp(entryAttrib, ATTR_KVP) == 0)) 2122 2123 { 2124 #ifdef DEBUG 2125 printf("Attribute: %s, its values are:\n", entryAttrib); 2126 #endif 2127 /* 2128 * add each KVP value to the list 2129 * that we will return 2130 */ 2131 attribValues = ldap_get_values( 2132 ld, ldapEntry, entryAttrib); 2133 for (i = 0; 2134 attribValues[i] != NULL; i++) 2135 { 2136 *list = (char **) 2137 list_append((void **)*list, 2138 strdup(attribValues[i])); 2139 #ifdef DEBUG 2140 printf("\t%s\n", attribValues[i]); 2141 #endif 2142 } 2143 (void) ldap_value_free(attribValues); 2144 } 2145 2146 if ((entryAttrib != NULL) && 2147 (berElement != NULL)) 2148 { 2149 ber_free(berElement, 0); 2150 } 2151 2152 2153 /* object found */ 2154 result = NSL_OK; 2155 } 2156 2157 (void) ldap_msgfree(ldapMsg); 2158 } 2159 } 2160 2161 else 2162 { 2163 result = NSL_ERR_INTERNAL; 2164 } 2165 2166 return (result); 2167 } /* _getCurrentKVPValues */ 2168 2169 2170 2171 /* 2172 * ***************************************************************************** 2173 * 2174 * Function: _freeList() 2175 * 2176 * Description: Free the list created by list_append() where the items in 2177 * the list have been strdup'ed. 2178 * 2179 * Parameters: 2180 * Input: char ***list - returned set of kvp values 2181 * 2182 * Result: void 2183 * 2184 * ***************************************************************************** 2185 */ 2186 2187 static void 2188 _freeList(char ***list) 2189 2190 { 2191 int i = 0; 2192 2193 /* ------ */ 2194 2195 if (list != NULL) 2196 { 2197 if (*list != NULL) 2198 { 2199 for (i = 0; (*list)[i] != NULL; i++) 2200 { 2201 free((*list)[i]); 2202 } 2203 free(*list); 2204 } 2205 2206 *list = NULL; 2207 } 2208 } /* _freeList */ 2209 2210 2211 2212 /* 2213 * ***************************************************************************** 2214 * 2215 * Function: _modAttrKVP() 2216 * 2217 * Description: Sort out the KVP attribute value list, such that this new 2218 * value takes precidence over any existing value in the list. 2219 * The current list is updated to remove this key, and the new 2220 * key "value" is added to the list, eg. for 2221 * value: bbb=ddddd 2222 * and kvpList: 2223 * aaa=yyyy 2224 * bbb=zzzz 2225 * ccc=xxxx 2226 * the resulting kvpList is: 2227 * aaa=yyyy 2228 * ccc=xxxx 2229 * bbb=ddddd 2230 * 2231 * Note: When all new values have been handled the function _attrAddKVP() 2232 * must be called to add the "new list" values into the 2233 * LDAPMod array. 2234 * 2235 * Parameters: 2236 * Input: char *value - Key Value Pair to process, 2237 * eg. aaaaa=hhhhh, where aaaaa is the key 2238 * char ***kvpList - list of current KVP values 2239 * Output: char ***kvpList - updated list of KVP values 2240 * 2241 * Returns: NSL_RESULT - NSL_OK = done okay 2242 * 2243 * ***************************************************************************** 2244 */ 2245 2246 static NSL_RESULT 2247 _modAttrKVP(char *value, char ***kvpList) 2248 2249 { 2250 NSL_RESULT result = NSL_ERR_INTERNAL; 2251 int i = 0; 2252 int inList = 0; 2253 int keyDelete = 0; 2254 char *key = NULL; 2255 char **p = NULL; 2256 char **newList = NULL; 2257 2258 /* ------- */ 2259 2260 if ((value != NULL) && (kvpList != NULL)) 2261 { 2262 result = NSL_OK; 2263 2264 /* extract "key" from value */ 2265 2266 key = strdup(value); 2267 2268 for (i = 0; ((key)[i] != '=') && ((key)[i] != '\0'); i++); 2269 key[i] = '\0'; /* terminate the key */ 2270 2271 /* Is this a request to delete a "key" value */ 2272 2273 if ((value[i] == '\0') || (value[i+1] == '\0')) 2274 { 2275 /* this is a request to delete the key */ 2276 keyDelete = 1; 2277 } 2278 2279 if ((*kvpList != NULL) && (**kvpList != NULL)) 2280 { 2281 /* 2282 * for each item in the list remove it if the keys match 2283 */ 2284 for (p = *kvpList; *p != NULL; p++) 2285 { 2286 for (i = 0; 2287 ((*p)[i] != '=') && ((*p)[i] != '\0'); i++); 2288 2289 if ((strlen(key) == i) && 2290 (strncasecmp(*p, key, i) == 0)) 2291 { 2292 inList = 1; 2293 } 2294 else 2295 { 2296 /* no match so add value to new list */ 2297 newList = (char **)list_append( 2298 (void **)newList, 2299 strdup(*p)); 2300 } 2301 } 2302 } 2303 2304 /* 2305 * if it was not a DELETE request add the new key value into 2306 * the newList, otherwise we have already removed the key 2307 */ 2308 2309 if (!keyDelete) 2310 { 2311 newList = (char **)list_append((void **)newList, 2312 strdup(value)); 2313 } 2314 2315 if ((newList != NULL) || (inList)) 2316 { 2317 /* replace old list with the newList */ 2318 _freeList(kvpList); 2319 *kvpList = newList; 2320 } 2321 2322 free(key); 2323 } 2324 2325 return (result); 2326 } /* modAttrKVP */ 2327 2328 2329 2330 2331 /* 2332 * ***************************************************************************** 2333 * 2334 * Function: _attrAddKVP() 2335 * 2336 * Description: Process KVP items in the kvpList adding them to the 2337 * LDAPMod modify array. If the list is empty but there were 2338 * previously LDAP KVP values delete them. 2339 * 2340 * Note: This function should only be called when all the new KVP 2341 * items have been processed by _modAttrKVP() 2342 * 2343 * Parameters: 2344 * Input: LDAPMod ***attrs - array to update 2345 * char **kvpList - list KVP values 2346 * int kvpExists - object currently has LDAP KVP values 2347 * Output: None 2348 * 2349 * Returns: NSL_RESULT - NSL_OK = done okay 2350 * 2351 * ***************************************************************************** 2352 */ 2353 2354 static NSL_RESULT 2355 _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists) 2356 2357 { 2358 NSL_RESULT result = NSL_OK; 2359 2360 /* ------- */ 2361 2362 if (attrs != NULL) 2363 { 2364 if (kvpList != NULL) 2365 { 2366 while ((kvpList != NULL) && (*kvpList != NULL)) 2367 { 2368 /* add item to LDAPMod array */ 2369 2370 result = 2371 _modLDAPmodValue(attrs, ATTR_KVP, *kvpList); 2372 2373 kvpList++; 2374 } 2375 } 2376 else 2377 if (kvpExists) 2378 { 2379 /* 2380 * We now have no LDAP KVP values but there were 2381 * some previously, so delete them 2382 */ 2383 result = _modLDAPmodValue(attrs, ATTR_KVP, NULL); 2384 } 2385 } 2386 2387 else 2388 { 2389 result = NSL_ERR_INTERNAL; 2390 } 2391 2392 return (result); 2393 } /* _attrAddKVP */ 2394 2395 2396 2397 2398 /* 2399 * ***************************************************************************** 2400 * 2401 * Function: _manageReferralCredentials() 2402 * 2403 * Description: This function is called if a referral request is returned by 2404 * the origonal LDAP server during the ldap update request call, 2405 * eg. ldap_add_s(), ldap_modify_s() or ldap_delete_s(). 2406 * Parameters: 2407 * Input: LDAP *ld - LDAP descriptor 2408 * int freeit - 0 = first call to get details 2409 * - 1 = second call to free details 2410 * - -1 = initial store of authentication details 2411 * Input/Output: char **dn - returns DN to bind to on master 2412 * char **credp - returns password for DN 2413 * int *methodp - returns authentication type, eg. simple 2414 * 2415 * Returns: int - 0 = okay 2416 * 2417 * ***************************************************************************** 2418 */ 2419 static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp, 2420 int *methodp, int freeit) 2421 2422 { 2423 int result = 0; 2424 static char *sDN = NULL; 2425 static char *sPasswd = NULL; 2426 static int sMethod = LDAP_AUTH_SIMPLE; 2427 2428 /* -------- */ 2429 2430 if (freeit == 1) 2431 { 2432 /* second call - free memory */ 2433 2434 if ((dn != NULL) && (*dn != NULL)) 2435 { 2436 free(*dn); 2437 } 2438 2439 if ((credp != NULL) && (*credp != NULL)) 2440 { 2441 free(*credp); 2442 } 2443 } 2444 2445 else 2446 if ((ld != NULL) && 2447 (dn != NULL) && (credp != NULL) && (methodp != NULL)) 2448 { 2449 if ((freeit == 0) && (sDN != NULL) && (sPasswd != NULL)) 2450 { 2451 /* first call - get the saved bind credentials */ 2452 2453 *dn = strdup(sDN); 2454 *credp = strdup(sPasswd); 2455 *methodp = sMethod; 2456 } 2457 else 2458 if (freeit == -1) 2459 { 2460 /* initial call - save the saved bind credentials */ 2461 2462 sDN = *dn; 2463 sPasswd = *credp; 2464 sMethod = *methodp; 2465 } 2466 else 2467 { 2468 result = 1; /* error */ 2469 } 2470 } 2471 else 2472 { 2473 result = 1; /* error */ 2474 } 2475 2476 return (result); 2477 } /* _manageReferralCredentials */ 2478