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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* Id: nss.c 180 2006-07-20 17:33:02Z njacobs $ */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <sys/types.h> 36 #include <syslog.h> 37 #include <papi.h> 38 #include <uri.h> 39 #include <papi_impl.h> 40 #ifdef NSS_EMULATION 41 #include <nss-emulation.h> 42 #elif NSS_SOLARIS 43 #include <nss_dbdefs.h> 44 #endif 45 #include <config-site.h> 46 #if defined(__sun) && defined(__SVR4) 47 #include <sys/systeminfo.h> 48 #endif 49 50 51 static char * 52 bsdaddr_to_uri(papi_attribute_t **list, char *bsdaddr) 53 { 54 char *result = NULL; 55 56 if (bsdaddr != NULL) { 57 char *bsd[3], *tmp, *iter = NULL; 58 char buf[512]; 59 60 tmp = strdup(bsdaddr); 61 62 bsd[0] = strtok_r(tmp, ":,", &iter); 63 if ((bsd[1] = strtok_r(NULL, ":,", &iter)) == NULL) 64 papiAttributeListGetString(list, NULL, 65 "printer-name", &bsd[1]); 66 bsd[2] = strtok_r(NULL, ":,", &iter); 67 68 snprintf(buf, sizeof (buf), "lpd://%s/printers/%s%s%s", bsd[0], 69 (bsd[1] != NULL) ? bsd[1] : "", 70 (bsd[2] != NULL) ? "#" : "", 71 (bsd[2] != NULL) ? bsd[2] : ""); 72 73 free(tmp); 74 75 result = strdup(buf); 76 } 77 78 return (result); 79 } 80 81 #if defined(__sun) && defined(__SVR4) 82 /* 83 * This is an awful HACK to force the dynamic PAPI library to use the 84 * lpsched support when the destination apears to be a local lpsched 85 * queue on Solaris. 86 */ 87 static void 88 solaris_lpsched_shortcircuit_hack(papi_attribute_t ***list) 89 { 90 papi_attribute_t *attribute; 91 uri_t *uri = NULL; 92 char *printer = NULL; 93 char buf[128], buf2[128]; 94 95 /* setting this in the calling env can be useful for debugging */ 96 if (getenv("DISABLE_LPSCHED_SHORTCIRCUIT") != NULL) 97 return; 98 99 papiAttributeListGetString(*list, NULL, 100 "printer-uri-supported", &printer); 101 /* if there is no printer-uri-supported, there is nothing to do */ 102 if (printer == NULL) { 103 return; 104 } 105 106 if (uri_from_string(printer, &uri) < 0) { 107 papiAttributeListFree(*list); 108 *list = NULL; 109 uri_free(uri); 110 return; 111 } 112 113 /* already an lpsched URI ? */ 114 if (strcasecmp(uri->scheme, "lpsched") == 0) { 115 uri_free(uri); 116 return; 117 } 118 119 if (uri->path == NULL) { 120 printer = ""; 121 } else { 122 if ((printer = strrchr(uri->path, '/')) == NULL) 123 printer = uri->path; 124 else 125 printer++; 126 } 127 128 /* is there an lpsched queue (printer/class) */ 129 snprintf(buf, sizeof (buf), "/etc/lp/interfaces/%s", printer); 130 snprintf(buf2, sizeof (buf2), "/etc/lp/classes/%s", printer); 131 if ((access(buf, F_OK) < 0) && (access(buf2, F_OK) < 0)) { 132 uri_free(uri); 133 return; 134 } 135 136 /* is this the "local" host */ 137 if ((uri->host != NULL) && (is_localhost(uri->host) == 0)) { 138 uri_free(uri); 139 return; 140 } 141 142 snprintf(buf, sizeof (buf), "lpsched://%s/printers/%s", 143 (uri->host ? uri->host : "localhost"), printer); 144 papiAttributeListAddString(list, PAPI_ATTR_REPLACE, 145 "printer-uri-supported", buf); 146 uri_free(uri); 147 } 148 #endif 149 150 static void 151 fill_printer_uri_supported(papi_attribute_t ***list) 152 { 153 papi_attribute_t *attribute; 154 char *string = NULL; 155 156 /* do we have a printer-uri-supported */ 157 attribute = papiAttributeListFind(*list, "printer-uri-supported"); 158 if (attribute != NULL) /* we have what we need, return */ 159 return; 160 161 /* do we have a printer-uri (in URI form) to rename */ 162 attribute = papiAttributeListFind(*list, "printer-uri"); 163 if ((attribute != NULL) && 164 (attribute->type == PAPI_STRING) && 165 (attribute->values != NULL) && 166 (attribute->values[0]->string != NULL) && 167 (strstr(attribute->values[0]->string, "://") != NULL)) { 168 /* rename it in place and return */ 169 free(attribute->name); 170 attribute->name = strdup("printer-uri-supported"); 171 return; 172 } 173 174 /* do we have a printers.conf(4) "bsdaddr" to convert */ 175 papiAttributeListGetString(*list, NULL, "bsdaddr", &string); 176 if (string != NULL) { /* parse it, convert it, add it */ 177 char *uri = bsdaddr_to_uri(*list, string); 178 179 if (uri != NULL) { 180 papiAttributeListAddString(list, PAPI_ATTR_APPEND, 181 "printer-uri-supported", uri); 182 papiAttributeListDelete(list, "bsdaddr"); 183 free(uri); 184 return; 185 } 186 } 187 188 /* do we have a printers.conf(4) "rm" (and "rp") to convert */ 189 papiAttributeListGetString(*list, NULL, "rm", &string); 190 if (string != NULL) { 191 char *rp = NULL; 192 193 /* default to "printer-name", but use "rp" if we have it */ 194 papiAttributeListGetString(*list, NULL, "printer-name", &rp); 195 papiAttributeListGetString(*list, NULL, "rp", &rp); 196 197 if (rp != NULL) { /* fill in the uri if we have the data */ 198 char buf[BUFSIZ]; 199 200 snprintf(buf, sizeof (buf), "lpd://%s/printers/%s", 201 string, rp); 202 papiAttributeListAddString(list, PAPI_ATTR_APPEND, 203 "printer-uri-supported", strdup(buf)); 204 return; 205 } 206 } 207 208 /* if were are here, we don't have a printer-uri-supported */ 209 } 210 211 #ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC 212 static void 213 fill_printer_uri(papi_attribute_t ***list) 214 { 215 papi_attribute_t *attribute; 216 char *uri = NULL; 217 218 if ((list == NULL) || (*list == NULL)) 219 return; 220 221 /* do we have a printer-uri */ 222 attribute = papiAttributeListFind(*list, "printer-uri"); 223 if (attribute != NULL) /* we have what we need, return */ 224 return; 225 226 /* 227 * this is sufficient to fool libgnomeprintpapi, but not promote it's 228 * use in the future. 229 */ 230 papiAttributeListAddString(list, PAPI_ATTR_EXCL, "printer-uri", 231 "broken printer-uri semantic"); 232 } 233 #endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */ 234 235 static void 236 cvt_all_to_member_names(papi_attribute_t ***list) 237 { 238 papi_status_t status; 239 void *iter = NULL; 240 char *string = NULL; 241 242 papiAttributeListGetString(*list, NULL, "member-names", &string); 243 if (string != NULL) /* already have a member-names */ 244 return; 245 246 for (status = papiAttributeListGetString(*list, &iter, "all", &string); 247 status == PAPI_OK; 248 status = papiAttributeListGetString(*list, &iter, NULL, &string)) { 249 char *s_iter = NULL, *value, *tmp = strdup(string); 250 251 for (value = strtok_r(tmp, ", \t", &s_iter); 252 value != NULL; 253 value = strtok_r(NULL, ", \t", &s_iter)) 254 papiAttributeListAddString(list, PAPI_ATTR_APPEND, 255 "member-names", value); 256 free(tmp); 257 } 258 } 259 260 static papi_attribute_t ** 261 _cvt_nss_entry_to_printer(char *entry) 262 { 263 char *key = NULL, 264 *cp, 265 buf[BUFSIZ]; 266 int in_namelist = 1, buf_pos = 0; 267 papi_attribute_t **list = NULL; 268 269 if (entry == NULL) 270 return (NULL); 271 272 memset(buf, 0, sizeof (buf)); 273 for (cp = entry; *cp != '\0'; cp++) { 274 switch (*cp) { 275 case ':': /* end of kvp */ 276 if (in_namelist != 0) { 277 papiAttributeListAddString(&list, 278 PAPI_ATTR_APPEND, "printer-name", buf); 279 in_namelist = 0; 280 } else if (key != NULL) { 281 papiAttributeListAddString(&list, 282 PAPI_ATTR_APPEND, key, buf); 283 free(key); 284 } 285 memset(buf, 0, sizeof (buf)); 286 buf_pos = 0; 287 key = NULL; 288 break; 289 case '=': /* kvp seperator */ 290 if (key == NULL) { 291 key = strdup(buf); 292 memset(buf, 0, sizeof (buf)); 293 buf_pos = 0; 294 } else 295 buf[buf_pos++] = *cp; 296 break; 297 case '|': /* namelist seperator */ 298 if (in_namelist != 0) { 299 papiAttributeListAddString(&list, 300 PAPI_ATTR_APPEND, "printer-name", buf); 301 memset(buf, 0, sizeof (buf)); 302 buf_pos = 0; 303 } else /* add it to the buffer */ 304 buf[buf_pos++] = *cp; 305 break; 306 case '\\': /* escape char */ 307 buf[buf_pos++] = *(++cp); 308 break; 309 default: 310 buf[buf_pos++] = *cp; 311 } 312 313 } 314 315 if (key != NULL) { 316 papiAttributeListAddString(&list, PAPI_ATTR_APPEND, key, buf); 317 free(key); 318 } 319 320 /* resolve any "use" references in the configuration DB */ 321 key = NULL; 322 papiAttributeListGetString(list, NULL, "use", &key); 323 if (key != NULL) { 324 papi_attribute_t **use_attrs = getprinterbyname(key, NULL); 325 326 list_concatenate(&list, use_attrs); 327 } 328 329 fill_printer_uri_supported(&list); 330 cvt_all_to_member_names(&list); /* convert "all" to "member-names" */ 331 332 return (list); 333 } 334 335 #if defined(NSS_SOLARIS) && !defined(NSS_EMULATION) 336 337 #ifndef NSS_DBNAM__PRINTERS /* not in nss_dbdefs.h because it's private */ 338 #define NSS_DBNAM__PRINTERS "_printers" 339 #endif 340 341 static DEFINE_NSS_DB_ROOT(db_root); 342 static DEFINE_NSS_GETENT(context); 343 344 static char *private_ns = NULL; 345 346 static void 347 _nss_initf_printers(p) 348 nss_db_params_t *p; 349 { 350 if (private_ns != NULL) { 351 /* 352 * because we need to support a legacy interface that allows 353 * us to select a specific name service, we need to dummy up 354 * the parameters to use a private nsswitch database and set 355 * the * default_config entry to the name service we are 356 * looking into. 357 */ 358 p->name = NSS_DBNAM__PRINTERS; /* "_printers" */ 359 p->default_config = private_ns; 360 } else { 361 /* regular behaviour */ 362 p->name = NSS_DBNAM_PRINTERS; /* "printers" */ 363 p->default_config = NSS_DEFCONF_PRINTERS; 364 } 365 syslog(LOG_DEBUG, "database: %s, default: %s", 366 (p->name ? p->name : "NULL"), 367 (p->default_config ? p->default_config : "NULL")); 368 } 369 370 /* 371 * Return values: 0 = success, 1 = parse error, 2 = erange ... 372 * The structure pointer passed in is a structure in the caller's space 373 * wherein the field pointers would be set to areas in the buffer if 374 * need be. instring and buffer should be separate areas. 375 */ 376 /* ARGSUSED */ 377 static int 378 str2printer(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 379 { 380 if (lenstr + 1 > buflen) 381 return (NSS_STR_PARSE_ERANGE); 382 383 /* skip entries that begin with '#' */ 384 if (instr[0] == '#') 385 return (NSS_STR_PARSE_PARSE); 386 387 /* 388 * We copy the input string into the output buffer 389 */ 390 (void) memcpy(buffer, instr, lenstr); 391 buffer[lenstr] = '\0'; 392 393 return (NSS_STR_PARSE_SUCCESS); 394 } 395 #endif /* NSS_SOLARIS */ 396 397 int 398 setprinterentry(int stayopen, char *ns) 399 { 400 #ifdef NSS_EMULATION 401 emul_setprinterentry(stayopen); 402 #elif NSS_SOLARIS 403 private_ns = ns; 404 nss_setent(&db_root, _nss_initf_printers, &context); 405 private_ns = NULL; 406 #endif 407 return (0); 408 } 409 410 411 int 412 endprinterentry(int i) 413 { 414 #ifdef NSS_EMULATION 415 emul_endprinterentry(); 416 #elif NSS_SOLARIS 417 nss_endent(&db_root, _nss_initf_printers, &context); 418 nss_delete(&db_root); 419 private_ns = NULL; 420 #endif 421 return (0); 422 } 423 424 /* ARGSUSED2 */ 425 papi_attribute_t ** 426 getprinterentry(char *ns) 427 { 428 papi_attribute_t **result = NULL; 429 430 #if defined(NSS_EMULATION) || defined(NSS_SOLARIS) 431 char buf[10240]; 432 nss_status_t res = NSS_NOTFOUND; 433 434 #ifdef NSS_EMULATION 435 res = emul_getprinterentry_r(buf, sizeof (buf)); 436 #elif NSS_SOLARIS 437 nss_XbyY_args_t arg; 438 439 private_ns = ns; 440 NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer); 441 res = nss_getent(&db_root, _nss_initf_printers, &context, &arg); 442 (void) NSS_XbyY_FINI(&arg); 443 private_ns = NULL; 444 #endif 445 446 if (res != NSS_SUCCESS) 447 buf[0] = '\0'; 448 449 result = _cvt_nss_entry_to_printer(buf); 450 #if defined(__sun) && defined(__SVR4) 451 solaris_lpsched_shortcircuit_hack(&result); 452 #endif 453 #ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC 454 fill_printer_uri(&result); 455 #endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */ 456 #endif 457 458 #ifdef DEBUG 459 printf("getprinterentry(%s): 0x%8.8x\n", (ns ? ns : "NULL"), result); 460 if (result != NULL) { 461 char buf[4096]; 462 463 papiAttributeListToString(result, "\n\t", buf, sizeof (buf)); 464 printf("\t%s\n", buf); 465 } 466 #endif /* DEBUG */ 467 468 return (result); 469 } 470 471 472 papi_attribute_t ** 473 getprinterbyname(char *name, char *ns) 474 { 475 papi_attribute_t **result = NULL; 476 477 if (strstr(name, "://") != NULL) { /* shortcut for URI form */ 478 papiAttributeListAddString(&result, PAPI_ATTR_APPEND, 479 "printer-name", name); 480 papiAttributeListAddString(&result, PAPI_ATTR_APPEND, 481 "printer-uri-supported", name); 482 } else if (strchr(name, ':') != NULL) { /* shortcut for POSIX form */ 483 char *uri = bsdaddr_to_uri(result, name); 484 485 papiAttributeListAddString(&result, PAPI_ATTR_APPEND, 486 "printer-name", name); 487 if (uri != NULL) { 488 papiAttributeListAddString(&result, PAPI_ATTR_APPEND, 489 "printer-uri-supported", uri); 490 free(uri); 491 } 492 } else { /* anything else */ 493 #if defined(NSS_EMULATION) || defined(NSS_SOLARIS) 494 char buf[10240]; 495 nss_status_t res = NSS_NOTFOUND; 496 497 #ifdef NSS_EMULATION 498 res = emul_getprinterbyname_r(name, buf, sizeof (buf)); 499 #elif NSS_SOLARIS 500 nss_XbyY_args_t arg; 501 502 private_ns = ns; 503 NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer); 504 arg.key.name = name; 505 res = nss_search(&db_root, _nss_initf_printers, 506 NSS_DBOP_PRINTERS_BYNAME, &arg); 507 (void) NSS_XbyY_FINI(&arg); 508 private_ns = NULL; 509 510 if (res != NSS_SUCCESS) 511 buf[0] = '\0'; 512 #endif 513 514 result = _cvt_nss_entry_to_printer(buf); 515 #endif 516 } 517 #if defined(__sun) && defined(__SVR4) 518 solaris_lpsched_shortcircuit_hack(&result); 519 #endif 520 #ifdef DEBUG 521 printf("getprinterbyname(%s): %s = 0x%8.8x\n", (ns ? ns : "NULL"), 522 name, result); 523 if (result != NULL) { 524 char buf[4096]; 525 526 papiAttributeListToString(result, "\n\t", buf, sizeof (buf)); 527 printf("\t%s\n", buf); 528 } 529 #endif /* DEBUG */ 530 531 return (result); 532 } 533