xref: /illumos-gate/usr/src/lib/print/libprint/common/ns_bsd_addr.c (revision 2983dda76a6d296fdb560c88114fe41caad1b84f)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*LINTLIBRARY*/
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <syslog.h>
37 
38 #include <ns.h>
39 #include <list.h>
40 
41 static char **
42 strsplit(char *string, char *seperators)
43 {
44 	char **list = NULL;
45 	char *where = NULL;
46 	char *element;
47 
48 	for (element = strtok_r(string, seperators, &where); element != NULL;
49 	    element = strtok_r(NULL, seperators, &where))
50 		list = (char **)list_append((void **)list, element);
51 
52 	return (list);
53 }
54 
55 /*
56  *	Manipulate bsd_addr structures
57  */
58 ns_bsd_addr_t *
59 bsd_addr_create(const char *server, const char *printer, const char *extension)
60 {
61 	ns_bsd_addr_t *addr = NULL;
62 
63 	if ((server != NULL) &&
64 	    ((addr = calloc(1, sizeof (*addr))) != NULL)) {
65 		addr->printer = (char *)printer;
66 		addr->server = (char *)server;
67 		addr->extension = (char *)extension;
68 	}
69 
70 	return (addr);
71 }
72 
73 static char *
74 bsd_addr_to_string(const ns_bsd_addr_t *addr)
75 {
76 	char buf[BUFSIZ];
77 
78 	if ((addr == NULL) || (addr->server == NULL))
79 		return (NULL);
80 
81 	if (snprintf(buf, sizeof (buf), "%s", addr->server) >= sizeof (buf)) {
82 		syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
83 		return (NULL);
84 	}
85 
86 	if ((addr->printer != NULL) || (addr->extension != NULL))
87 		(void) strlcat(buf, ",", sizeof (buf));
88 	if (addr->printer != NULL)
89 		if (strlcat(buf, addr->printer, sizeof (buf)) >= sizeof (buf)) {
90 			syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
91 			return (NULL);
92 		}
93 	if (addr->extension != NULL) {
94 		(void) strlcat(buf, ",", sizeof (buf));
95 		if (strlcat(buf, addr->extension, sizeof (buf))
96 						>= sizeof (buf)) {
97 			syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
98 			return (NULL);
99 		}
100 	}
101 
102 	return (strdup(buf));
103 }
104 
105 ns_bsd_addr_t *
106 string_to_bsd_addr(const char *string)
107 {
108 	char **list, *tmp, *printer = NULL, *extension = NULL;
109 
110 	if (string == NULL)
111 		return (NULL);
112 
113 	tmp = strdup(string);
114 	list = strsplit(tmp, ",");
115 
116 	if (list[1] != NULL) {
117 		printer = list[1];
118 		if (list[2] != NULL)
119 			extension = list[2];
120 	}
121 
122 	return (bsd_addr_create(list[0], printer, extension));
123 }
124 
125 static char *
126 list_to_string(const char **list)
127 {
128 	char buf[BUFSIZ];
129 
130 	if ((list == NULL) || (*list == NULL))
131 		return (NULL);
132 
133 	if (snprintf(buf, sizeof (buf), "%s", *list) >= sizeof (buf)) {
134 		syslog(LOG_ERR, "list_to_string: buffer overflow");
135 		return (NULL);
136 	}
137 
138 	while (*++list != NULL) {
139 		(void) strlcat(buf, ",", sizeof (buf));
140 		if (strlcat(buf, *list, sizeof (buf)) >= sizeof (buf)) {
141 			syslog(LOG_ERR, "list_to_string: buffer overflow");
142 			return (NULL);
143 		}
144 	}
145 
146 	return (strdup(buf));
147 }
148 
149 static char *
150 internal_list_to_string(const ns_printer_t **list)
151 {
152 	char buf[BUFSIZ];
153 
154 	if ((list == NULL) || (*list == NULL))
155 		return (NULL);
156 
157 	if (snprintf(buf, sizeof (buf), "%s", (*list)->name) >= sizeof (buf)) {
158 		syslog(LOG_ERR, "internal_list_to_string:buffer overflow");
159 		return (NULL);
160 	}
161 
162 	while (*++list != NULL) {
163 		(void) strlcat(buf, ",", sizeof (buf));
164 		if (strlcat(buf, (*list)->name, sizeof (buf)) >= sizeof (buf)) {
165 			syslog(LOG_ERR,
166 				"internal_list_to_string:buffer overflow");
167 			return (NULL);
168 		}
169 	}
170 
171 	return (strdup(buf));
172 }
173 
174 
175 char *
176 value_to_string(const char *key, void *value)
177 {
178 	char *string = NULL;
179 
180 	if ((key != NULL) && (value != NULL)) {
181 		if (strcmp(key, NS_KEY_BSDADDR) == 0) {
182 			string = bsd_addr_to_string(value);
183 		} else if ((strcmp(key, NS_KEY_ALL) == 0) ||
184 			    (strcmp(key, NS_KEY_GROUP) == 0)) {
185 			string = list_to_string(value);
186 		} else if (strcmp(key, NS_KEY_LIST) == 0) {
187 			string = internal_list_to_string(value);
188 		} else {
189 			string = strdup((char *)value);
190 		}
191 	}
192 
193 	return (string);
194 }
195 
196 
197 void *
198 string_to_value(const char *key, char *string)
199 {
200 	void *value = NULL;
201 
202 	if ((key != NULL) && (string != NULL) && (string[0] != NULL)) {
203 		if (strcmp(key, NS_KEY_BSDADDR) == 0) {
204 			value = (void *)string_to_bsd_addr(string);
205 		} else if ((strcmp(key, NS_KEY_ALL) == 0) ||
206 			    (strcmp(key, NS_KEY_GROUP) == 0)) {
207 			value = (void *)strsplit(string, ",");
208 		} else {
209 			value = (void *)string;
210 		}
211 	}
212 
213 	return (value);
214 }
215 
216 static void
217 split_name(char *name, const char *delimiter, char **p1, char **p2, char **p3)
218 {
219 	char *tmp, *junk = NULL;
220 
221 	if (p1 != NULL)
222 		*p1 = NULL;
223 	if (p2 != NULL)
224 		*p2 = NULL;
225 	if (p3 != NULL)
226 		*p3 = NULL;
227 
228 	if ((name == NULL) || (delimiter == NULL)) {
229 		syslog(LOG_DEBUG, "split_name(): name/delimter invalid\n");
230 		return;
231 	}
232 
233 	for (tmp = (char *)strtok_r(name, delimiter, &junk); tmp != NULL;
234 	    tmp = (char *)strtok_r(NULL, delimiter, &junk))
235 		if ((p1 != NULL) && (*p1 == NULL))
236 			*p1 = tmp;
237 		else if ((p2 != NULL) && (*p2 == NULL)) {
238 			*p2 = tmp;
239 			if (p3 == NULL)
240 				break;
241 		} else if ((p3 != NULL) && (*p3 == NULL)) {
242 			*p3 = tmp;
243 			break;
244 		}
245 }
246 
247 /*
248  * This implements support for printer names that are fully resolvable
249  * on their own.  These "complete" names are converted into a ns_printer_t
250  * structure containing an appropriate "bsdaddr" attribute.  The supported
251  * formats are as follows:
252  *	POSIX style (server:printer[:conformance]).
253  *		This format is an adaptation of the format originally
254  *		described in POSIX 1387.4.  The POSIX draft has since been
255  *		squashed, but this particular component lives on.  The
256  *		conformace field has been added to allow further identification
257  *		of the the server.
258  */
259 ns_printer_t *
260 posix_name(const char *name)
261 {
262 	ns_printer_t *printer = NULL;
263 	char *tmp = NULL;
264 
265 	if ((name != NULL) && ((tmp = strpbrk(name, ":")) != NULL)) {
266 		char *server = NULL;
267 		char *queue = NULL;
268 		char *extension = NULL;
269 		char *addr = strdup(name);
270 		char buf[BUFSIZ];
271 
272 		if (*tmp == ':')
273 			split_name(addr, ": \t", &server, &queue, &extension);
274 
275 		memset(buf, 0, sizeof (buf));
276 		if ((server != NULL) && (queue != NULL))
277 			snprintf(buf, sizeof (buf), "%s,%s%s%s", server,
278 				queue, (extension != NULL ? "," : ""),
279 				(extension != NULL ? extension : ""));
280 
281 		/* build the structure here */
282 		if (buf[0] != NULL) {
283 			ns_kvp_t **list, *kvp;
284 
285 			kvp = ns_kvp_create(NS_KEY_BSDADDR, buf);
286 			list = (ns_kvp_t **)list_append(NULL, kvp);
287 			if (list != NULL)
288 				printer = ns_printer_create(strdup(name), NULL,
289 							"posix", list);
290 		}
291 	}
292 
293 	return (printer);
294 }
295 
296 /*
297  * FUNCTION:
298  *	int ns_bsd_addr_cmp(ns_bsd_addr_t *at, ns_bsd_addr_t *a2)
299  * INPUTS:
300  *	ns_bsd_addr_t *a1 - a bsd addr
301  *	ns_bsd_addr_t *21 - another bsd addr
302  * DESCRIPTION:
303  *	This functions compare 2 bsd_addr structures to determine if the
304  *	information in them is the same.
305  */
306 static int
307 ns_bsd_addr_cmp(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
308 {
309 	int rc;
310 
311 	if ((a1 == NULL) || (a2 == NULL))
312 		return (1);
313 
314 	if ((rc = strcmp(a1->server, a2->server)) != 0)
315 		return (rc);
316 
317 	if ((a1->printer == NULL) || (a2->printer == NULL))
318 		return (a1->printer != a2->printer);
319 
320 	return (strcmp(a1->printer, a2->printer));
321 }
322 
323 
324 
325 
326 /*
327  * FUNCTION:    ns_bsd_addr_cmp_local()
328  *
329  * DESCRIPTION: This function compares 2 bsd_addr structures to determine if
330  *              the information in them is the same. It destinquishes between
331  *              real printer names and alias names while doing the compare.
332  *
333  * INPUTS:      ns_bsd_addr_t *a1 - a bsd addr
334  *              ns_bsd_addr_t *21 - another bsd addr
335  */
336 
337 static int
338 ns_bsd_addr_cmp_local(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
339 
340 {
341 	int rc;
342 
343 	if ((a1 == NULL) || (a2 == NULL))
344 	{
345 		return (1);
346 	}
347 
348 	if ((rc = strcmp(a1->server, a2->server)) != 0)
349 	{
350 		return (rc);
351 	}
352 
353 	if ((a1->printer == NULL) || (a2->printer == NULL))
354 	{
355 		return (a1->printer != a2->printer);
356 	}
357 
358 	rc = strcmp(a1->printer, a2->printer);
359 	if (rc == 0)
360 	{
361 		/*
362 		 * The printer's real names are the same, but now check if
363 		 * their local names (alias) are the same.
364 		 */
365 		rc = strcmp(a1->pname, a2->pname);
366 	}
367 
368 	return (rc);
369 } /* ns_bsd_addr_cmp_local */
370 
371 
372 
373 /*
374  * FUNCTION:
375  *	ns_bsd_addr_t *ns_bsd_addr_get_name(char *name)
376  * INPUTS:
377  *	char *name - name of printer to get address for
378  * OUTPUTS:
379  *	ns_bsd_addr_t *(return) - the address of the printer
380  * DESCRIPTION:
381  *	This function will get the BSD address of the printer specified.
382  *	it fills in the printer name if none is specified in the "name service"
383  *	as a convenience to calling functions.
384  */
385 ns_bsd_addr_t *
386 ns_bsd_addr_get_name(char *name)
387 {
388 	ns_printer_t *printer;
389 	ns_bsd_addr_t *addr = NULL;
390 
391 	endprinterentry();
392 	if ((printer = ns_printer_get_name(name, NULL)) != NULL) {
393 		addr = ns_get_value(NS_KEY_BSDADDR, printer);
394 
395 		if (addr != NULL && addr->printer == NULL)
396 			addr->printer = strdup(printer->name);
397 		if (addr != NULL) {
398 			/*
399 			 * if the name given is not the same as that in the
400 			 * this is an alias/remote name so put that into the
401 			 * pname field otherwise duplicate the real printer
402 			 * name
403 			 */
404 			if (strcmp(name, printer->name) != 0) {
405 				addr->pname = strdup(name);
406 			} else {
407 				addr->pname = strdup(printer->name);
408 			}
409 		}
410 	}
411 
412 	return (addr);
413 }
414 
415 
416 /*
417  * FUNCTION:
418  *	ns_bsd_addr_t **ns_bsd_addr_get_list()
419  * OUTPUT:
420  *	ns_bsd_addr_t **(return) - a list of bsd addresses for all printers
421  *				   in all "name services"
422  * DESCRIPTION:
423  *	This function will gather a list of all printer addresses in all
424  *	of the "name services".  All redundancy is removed.
425  */
426 ns_bsd_addr_t **
427 ns_bsd_addr_get_list(int unique)
428 
429 {
430 	ns_printer_t **printers;
431 	ns_bsd_addr_t **list = NULL;
432 	char **aliases = NULL;
433 
434 	for (printers = ns_printer_get_list(NULL);
435 			printers != NULL && *printers != NULL; printers++) {
436 		ns_bsd_addr_t *addr;
437 
438 		if (strcmp(NS_NAME_ALL, (*printers)->name) == 0)
439 			continue;
440 
441 		if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) {
442 			if (addr->printer == NULL)
443 				addr->printer = strdup((*printers)->name);
444 			addr->pname = strdup((*printers)->name);
445 		}
446 
447 		if (unique == UNIQUE)
448 			list =
449 			    (ns_bsd_addr_t **)list_append_unique((void **)list,
450 				(void *)addr, (COMP_T)ns_bsd_addr_cmp);
451 		else
452 		if (unique == LOCAL_UNIQUE)
453 			list =
454 			    (ns_bsd_addr_t **)list_append_unique((void **)list,
455 				(void *)addr, (COMP_T)ns_bsd_addr_cmp_local);
456 		else
457 			list = (ns_bsd_addr_t **)list_append((void **)list,
458 					(void *)addr);
459 
460 		for (aliases = (*printers)->aliases;
461 			(aliases != NULL) && (*aliases != NULL); aliases++)
462 		{
463 			/*
464 			 * Include any alias names that belong to the printer
465 			 */
466 
467 			if ((addr =
468 			    ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL)
469 			{
470 				if (addr->printer == NULL)
471 				{
472 					addr->printer = strdup(*aliases);
473 				}
474 				addr->pname = strdup(*aliases);
475 			}
476 
477 			if (unique == UNIQUE)
478 			{
479 				list = (ns_bsd_addr_t **)
480 					list_append_unique((void **)list,
481 					(void *)addr, (COMP_T)ns_bsd_addr_cmp);
482 			}
483 			else
484 			if (unique == LOCAL_UNIQUE)
485 			{
486 				list = (ns_bsd_addr_t **)
487 					list_append_unique((void **)list,
488 						(void *)addr,
489 						(COMP_T)ns_bsd_addr_cmp_local);
490 			}
491 			else
492 			{
493 				list = (ns_bsd_addr_t **)
494 				    list_append((void **)list, (void *)addr);
495 			}
496 		}
497 	}
498 
499 	return (list);
500 }
501 
502 
503 
504 
505 /*
506  * FUNCTION:
507  *	ns_bsd_addr_t **ns_bsd_addr_get_list()
508  * OUTPUT:
509  *	ns_bsd_addr_t **(return) - a list of bsd addresses for "_all" printers
510  *				   in the "name service"
511  * DESCRIPTION:
512  *	This function will use the "_all" entry to find a list of printers and
513  *	addresses. The "default" printer is also added to the list.
514  *	All redundancy is removed.
515  */
516 ns_bsd_addr_t **
517 ns_bsd_addr_get_all(int unique)
518 {
519 	ns_printer_t *printer;
520 	ns_bsd_addr_t **list = NULL;
521 	char **printers;
522 	char *def = NULL;
523 
524 	if (((def = (char *)getenv("PRINTER")) == NULL) &&
525 	    ((def = (char *)getenv("LPDEST")) == NULL))
526 		def = NS_NAME_DEFAULT;
527 
528 	list = (ns_bsd_addr_t **)list_append((void **)list,
529 			(void *)ns_bsd_addr_get_name(def));
530 
531 	endprinterentry();
532 	if ((printer = ns_printer_get_name(NS_NAME_ALL, NULL)) == NULL)
533 		return (ns_bsd_addr_get_list(unique));
534 
535 	for (printers = (char **)ns_get_value(NS_KEY_ALL, printer);
536 			printers != NULL && *printers != NULL; printers++) {
537 		ns_bsd_addr_t *addr;
538 
539 		addr = ns_bsd_addr_get_name(*printers);
540 		if (addr != NULL)
541 			addr->pname = *printers;
542 		if (unique == UNIQUE)
543 			list =
544 			    (ns_bsd_addr_t **)list_append_unique((void **)list,
545 				(void *)addr, (COMP_T)ns_bsd_addr_cmp);
546 		else
547 			list = (ns_bsd_addr_t **)list_append((void **)list,
548 					(void *)addr);
549 	}
550 
551 	return (list);
552 }
553 
554 ns_bsd_addr_t *
555 ns_bsd_addr_get_default()
556 {
557 	char *def = NULL;
558 	ns_bsd_addr_t *addr;
559 
560 	if (((def = (char *)getenv("PRINTER")) == NULL) &&
561 	    ((def = (char *)getenv("LPDEST")) == NULL)) {
562 		def = NS_NAME_DEFAULT;
563 		addr = ns_bsd_addr_get_name(def);
564 		if (addr != NULL) {
565 			addr->pname = def;
566 			return (addr);
567 		}
568 	}
569 
570 	return (NULL);
571 }
572