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 *
bsdaddr_to_uri(papi_attribute_t ** list,char * bsdaddr)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
solaris_lpsched_shortcircuit_hack(papi_attribute_t *** list)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
fill_printer_uri_supported(papi_attribute_t *** list)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
fill_printer_uri(papi_attribute_t *** list)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
cvt_all_to_member_names(papi_attribute_t *** list)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 **
_cvt_nss_entry_to_printer(char * entry)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
_nss_initf_printers(p)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
str2printer(const char * instr,int lenstr,void * ent,char * buffer,int buflen)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
setprinterentry(int stayopen,char * ns)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
endprinterentry(int i)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 **
getprinterentry(char * ns)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 **
getprinterbyname(char * name,char * ns)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