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