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