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