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