xref: /illumos-gate/usr/src/lib/print/libpapi-dynamic/common/nss.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 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 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <syslog.h>
37 #include <papi.h>
38 #include <uri.h>
39 #include <papi_impl.h>
40 #ifdef NSS_EMULATION
41 #include <nss-emulation.h>
42 #elif NSS_SOLARIS
43 #include <nss_dbdefs.h>
44 #endif
45 #include <config-site.h>
46 #if defined(__sun) && defined(__SVR4)
47 #include <sys/systeminfo.h>
48 #endif
49 
50 
51 static char *
52 bsdaddr_to_uri(papi_attribute_t **list, char *bsdaddr)
53 {
54 	char *result = NULL;
55 
56 	if (bsdaddr != NULL) {
57 		char *bsd[3], *tmp, *iter = NULL;
58 		char buf[512];
59 
60 		tmp = strdup(bsdaddr);
61 
62 		bsd[0] = strtok_r(tmp, ":,", &iter);
63 		if ((bsd[1] = strtok_r(NULL, ":,", &iter)) == NULL)
64 			papiAttributeListGetString(list, NULL,
65 					"printer-name", &bsd[1]);
66 		bsd[2] = strtok_r(NULL, ":,", &iter);
67 
68 		snprintf(buf, sizeof (buf), "lpd://%s/printers/%s%s%s", bsd[0],
69 			(bsd[1] != NULL) ? bsd[1] : "",
70 			(bsd[2] != NULL) ? "#" : "",
71 			(bsd[2] != NULL) ? bsd[2] : "");
72 
73 		free(tmp);
74 
75 		result = strdup(buf);
76 	}
77 
78 	return (result);
79 }
80 
81 #if defined(__sun) && defined(__SVR4)
82 /*
83  * This is an awful HACK to force the dynamic PAPI library to use the
84  * lpsched support when the destination apears to be a local lpsched
85  * queue on Solaris.
86  */
87 static void
88 solaris_lpsched_shortcircuit_hack(papi_attribute_t ***list)
89 {
90 	papi_attribute_t *attribute;
91 	uri_t *uri = NULL;
92 	char *printer = NULL;
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 there is no printer-uri-supported, there is nothing to do */
102 	if (printer == NULL) {
103 		return;
104 	}
105 
106 	if (uri_from_string(printer, &uri) < 0) {
107 		papiAttributeListFree(*list);
108 		*list = NULL;
109 		uri_free(uri);
110 		return;
111 	}
112 
113 	/* already an lpsched URI ? */
114 	if (strcasecmp(uri->scheme, "lpsched") == 0) {
115 		uri_free(uri);
116 		return;
117 	}
118 
119 	if (uri->path == NULL) {
120 		printer = "";
121 	} else {
122 		if ((printer = strrchr(uri->path, '/')) == NULL)
123 			printer = uri->path;
124 		else
125 			printer++;
126 	}
127 
128 	/* is there an lpsched queue (printer/class) */
129 	snprintf(buf, sizeof (buf), "/etc/lp/interfaces/%s", printer);
130 	snprintf(buf2, sizeof (buf2), "/etc/lp/classes/%s", printer);
131 	if ((access(buf, F_OK) < 0) && (access(buf2, F_OK) < 0)) {
132 		uri_free(uri);
133 		return;
134 	}
135 
136 	/* is this the "local" host */
137 	if ((uri->host != NULL) && (is_localhost(uri->host) == 0)) {
138 		uri_free(uri);
139 		return;
140 	}
141 
142 	snprintf(buf, sizeof (buf), "lpsched://%s/printers/%s",
143 			(uri->host ? uri->host : "localhost"), printer);
144 	papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
145 			"printer-uri-supported", buf);
146 	uri_free(uri);
147 }
148 #endif
149 
150 static void
151 fill_printer_uri_supported(papi_attribute_t ***list)
152 {
153 	papi_attribute_t *attribute;
154 	char *string = NULL;
155 
156 	/* do we have a printer-uri-supported */
157 	attribute = papiAttributeListFind(*list, "printer-uri-supported");
158 	if (attribute != NULL) /* we have what we need, return */
159 		return;
160 
161 	/* do we have a printer-uri (in URI form) to rename */
162 	attribute = papiAttributeListFind(*list, "printer-uri");
163 	if ((attribute != NULL) &&
164 	    (attribute->type == PAPI_STRING) &&
165 	    (attribute->values != NULL) &&
166 	    (attribute->values[0]->string != NULL) &&
167 	    (strstr(attribute->values[0]->string, "://") != NULL)) {
168 			/* rename it in place and return */
169 		free(attribute->name);
170 		attribute->name = strdup("printer-uri-supported");
171 		return;
172 	}
173 
174 	/* do we have a printers.conf(4) "bsdaddr" to convert */
175 	papiAttributeListGetString(*list, NULL, "bsdaddr", &string);
176 	if (string != NULL) { /* parse it, convert it, add it */
177 		char *uri = bsdaddr_to_uri(*list, string);
178 
179 		if (uri != NULL) {
180 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
181 					"printer-uri-supported", uri);
182 			papiAttributeListDelete(list, "bsdaddr");
183 			free(uri);
184 			return;
185 		}
186 	}
187 
188 	/* do we have a printers.conf(4) "rm" (and "rp") to convert */
189 	papiAttributeListGetString(*list, NULL, "rm", &string);
190 	if (string != NULL) {
191 		char *rp = NULL;
192 
193 		/* default to "printer-name", but use "rp" if we have it */
194 		papiAttributeListGetString(*list, NULL, "printer-name", &rp);
195 		papiAttributeListGetString(*list, NULL, "rp", &rp);
196 
197 		if (rp != NULL) { /* fill in the uri if we have the data */
198 			char buf[BUFSIZ];
199 
200 			snprintf(buf, sizeof (buf), "lpd://%s/printers/%s",
201 				string, rp);
202 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
203 					"printer-uri-supported", strdup(buf));
204 			return;
205 		}
206 	}
207 
208 	/* if were are here, we don't have a printer-uri-supported */
209 }
210 
211 #ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC
212 static void
213 fill_printer_uri(papi_attribute_t ***list)
214 {
215 	papi_attribute_t *attribute;
216 	char *uri = NULL;
217 
218 	if ((list == NULL) || (*list == NULL))
219 		return;
220 
221 	/* do we have a printer-uri */
222 	attribute = papiAttributeListFind(*list, "printer-uri");
223 	if (attribute != NULL) /* we have what we need, return */
224 		return;
225 
226 	/*
227 	 * this is sufficient to fool libgnomeprintpapi, but not promote it's
228 	 * use in the future.
229 	 */
230 	papiAttributeListAddString(list, PAPI_ATTR_EXCL, "printer-uri",
231 			"broken printer-uri semantic");
232 }
233 #endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */
234 
235 static void
236 cvt_all_to_member_names(papi_attribute_t ***list)
237 {
238 	papi_status_t status;
239 	void *iter = NULL;
240 	char *string = NULL;
241 
242 	papiAttributeListGetString(*list, NULL, "member-names", &string);
243 	if (string != NULL) /* already have a member-names */
244 		return;
245 
246 	for (status = papiAttributeListGetString(*list, &iter, "all", &string);
247 	    status == PAPI_OK;
248 	    status = papiAttributeListGetString(*list, &iter, NULL, &string)) {
249 		char *s_iter = NULL, *value, *tmp = strdup(string);
250 
251 		for (value = strtok_r(tmp, ", \t", &s_iter);
252 		    value != NULL;
253 		    value = strtok_r(NULL, ", \t", &s_iter))
254 			papiAttributeListAddString(list, PAPI_ATTR_APPEND,
255 					"member-names", value);
256 		free(tmp);
257 	}
258 }
259 
260 static papi_attribute_t **
261 _cvt_nss_entry_to_printer(char *entry)
262 {
263 	char    *key = NULL,
264 		*cp,
265 		buf[BUFSIZ];
266 	int in_namelist = 1, buf_pos = 0;
267 	papi_attribute_t **list = NULL;
268 
269 	if (entry == NULL)
270 		return (NULL);
271 
272 	memset(buf, 0, sizeof (buf));
273 	for (cp = entry; *cp != '\0'; cp++) {
274 		switch (*cp) {
275 		case ':':	/* end of kvp */
276 			if (in_namelist != 0) {
277 				papiAttributeListAddString(&list,
278 					PAPI_ATTR_APPEND, "printer-name", buf);
279 				in_namelist = 0;
280 			} else if (key != NULL) {
281 				papiAttributeListAddString(&list,
282 					PAPI_ATTR_APPEND, key, buf);
283 				free(key);
284 			}
285 			memset(buf, 0, sizeof (buf));
286 			buf_pos = 0;
287 			key = NULL;
288 			break;
289 		case '=':	/* kvp seperator */
290 			if (key == NULL) {
291 				key = strdup(buf);
292 				memset(buf, 0, sizeof (buf));
293 				buf_pos = 0;
294 			} else
295 				buf[buf_pos++] = *cp;
296 			break;
297 		case '|':	/* namelist seperator */
298 			if (in_namelist != 0) {
299 				papiAttributeListAddString(&list,
300 					PAPI_ATTR_APPEND, "printer-name", buf);
301 				memset(buf, 0, sizeof (buf));
302 				buf_pos = 0;
303 			} else	/* add it to the buffer */
304 				buf[buf_pos++] = *cp;
305 			break;
306 		case '\\':	/* escape char */
307 			buf[buf_pos++] = *(++cp);
308 			break;
309 		default:
310 			buf[buf_pos++] = *cp;
311 		}
312 
313 	}
314 
315 	if (key != NULL) {
316 		papiAttributeListAddString(&list, PAPI_ATTR_APPEND, key, buf);
317 		free(key);
318 	}
319 
320 	/* resolve any "use" references in the configuration DB */
321 	key = NULL;
322 	papiAttributeListGetString(list, NULL, "use", &key);
323 	if (key != NULL) {
324 		papi_attribute_t **use_attrs = getprinterbyname(key, NULL);
325 
326 		list_concatenate(&list, use_attrs);
327 	}
328 
329 	fill_printer_uri_supported(&list);
330 	cvt_all_to_member_names(&list); /* convert "all" to "member-names" */
331 
332 	return (list);
333 }
334 
335 #if defined(NSS_SOLARIS) && !defined(NSS_EMULATION)
336 
337 #ifndef	NSS_DBNAM__PRINTERS	/* not in nss_dbdefs.h because it's private */
338 #define	NSS_DBNAM__PRINTERS	"_printers"
339 #endif
340 
341 static DEFINE_NSS_DB_ROOT(db_root);
342 static DEFINE_NSS_GETENT(context);
343 
344 static char *private_ns = NULL;
345 
346 static void
347 _nss_initf_printers(p)
348     nss_db_params_t *p;
349 {
350 	if (private_ns != NULL) {
351 		/*
352 		 * because we need to support a legacy interface that allows
353 		 * us to select a specific name service, we need to dummy up
354 		 * the parameters to use a private nsswitch database and set
355 		 * the * default_config entry to the name service we are
356 		 * looking into.
357 		 */
358 		p->name = NSS_DBNAM__PRINTERS;		/* "_printers" */
359 		p->default_config = private_ns;
360 	} else {
361 		/* regular behaviour */
362 		p->name = NSS_DBNAM_PRINTERS;	 /* "printers" */
363 		p->default_config = NSS_DEFCONF_PRINTERS;
364 	}
365 	syslog(LOG_DEBUG, "database: %s, default: %s",
366 		(p->name ? p->name : "NULL"),
367 		(p->default_config ? p->default_config : "NULL"));
368 }
369 
370 /*
371  * Return values: 0 = success, 1 = parse error, 2 = erange ...
372  * The structure pointer passed in is a structure in the caller's space
373  * wherein the field pointers would be set to areas in the buffer if
374  * need be. instring and buffer should be separate areas.
375  */
376 /* ARGSUSED */
377 static int
378 str2printer(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
379 {
380 	if (lenstr + 1 > buflen)
381 		return (NSS_STR_PARSE_ERANGE);
382 
383 	/* skip entries that begin with '#' */
384 	if (instr[0] == '#')
385 		return (NSS_STR_PARSE_PARSE);
386 
387 	/*
388 	 * We copy the input string into the output buffer
389 	 */
390 	(void) memcpy(buffer, instr, lenstr);
391 	buffer[lenstr] = '\0';
392 
393 	return (NSS_STR_PARSE_SUCCESS);
394 }
395 #endif /* NSS_SOLARIS */
396 
397 int
398 setprinterentry(int stayopen, char *ns)
399 {
400 #ifdef NSS_EMULATION
401 	emul_setprinterentry(stayopen);
402 #elif NSS_SOLARIS
403 	private_ns = ns;
404 	nss_setent(&db_root, _nss_initf_printers, &context);
405 	private_ns = NULL;
406 #endif
407 	return (0);
408 }
409 
410 
411 int
412 endprinterentry(int i)
413 {
414 #ifdef NSS_EMULATION
415 	emul_endprinterentry();
416 #elif NSS_SOLARIS
417 	nss_endent(&db_root, _nss_initf_printers, &context);
418 	nss_delete(&db_root);
419 	private_ns = NULL;
420 #endif
421 	return (0);
422 }
423 
424 /* ARGSUSED2 */
425 papi_attribute_t **
426 getprinterentry(char *ns)
427 {
428 	papi_attribute_t **result = NULL;
429 
430 #if defined(NSS_EMULATION) || defined(NSS_SOLARIS)
431 	char buf[10240];
432 	nss_status_t	res = NSS_NOTFOUND;
433 
434 #ifdef NSS_EMULATION
435 	res = emul_getprinterentry_r(buf, sizeof (buf));
436 #elif NSS_SOLARIS
437 	nss_XbyY_args_t arg;
438 
439 	private_ns = ns;
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 **
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