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