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