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