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