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