xref: /titanic_44/usr/src/lib/print/libpapi-dynamic/common/nss.c (revision b6917abefc343244b784f0cc34bc65b01469c3bf)
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