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 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 *
25 * "user" backend for nsswitch "printers" database.  This module implements
26 * the ${HOME}/.printers naming support.  This file provides users with a
27 * convenient method of aliasing and specifying an interest list.
28 */
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32#pragma weak _nss_user__printers_constr = _nss_user_printers_constr
33
34#include <nss_dbdefs.h>
35#include "user_common.h"
36#include <string.h>
37#include <stdlib.h>
38#include <ctype.h>
39
40static nss_status_t
41_nss_user_printers_convert(char *entry, nss_XbyY_args_t *args)
42{
43	nss_status_t		res = NSS_NOTFOUND;
44	char 			*namelist = entry;
45	char			*key = NULL;
46	char			*value = NULL;
47	int			length = 0;
48
49	if ((value = strpbrk(entry, "\t ")) != NULL) {
50		*value = NULL; value++;
51
52		while ((*value != NULL) && (isspace(*value) != 0))
53			value++;
54
55		if ((key = strpbrk(value, "\n\t ")) != NULL)
56			*key = NULL;
57	}
58
59	args->buf.buffer[0] = NULL;
60	if ((value == NULL) || (*value == NULL)) {	/* bad value */
61		args->erange = 1;
62		return (res);
63	}
64
65	if (strcmp(namelist, "_all") == 0)
66		key = "all";
67	else
68		key = "use";
69
70	length = snprintf(args->buf.buffer, args->buf.buflen, "%s:%s=",
71			namelist, key);
72
73	/* append the value  ':' must be escaped for posix style names */
74	while ((length < args->buf.buflen) && (*value != NULL)) {
75		if (*value == ':')
76			args->buf.buffer[length++] = '\\';
77		args->buf.buffer[length++] = *value++;
78	}
79
80	if (length >= args->buf.buflen) {	/* the value was too big */
81		args->erange = 1;
82		return (res);
83	}
84
85	args->buf.buffer[length] = NULL;	/* terminate, just in case */
86	args->returnval = args->buf.result;
87	res = NSS_SUCCESS;
88
89	return (res);
90}
91
92/*
93 * printers has the hostname as part of the data in the file, but the other
94 * backends don't include it in the data passed to the backend.  For this
95 * reason, we process everything here and don't bother calling the backend.
96 */
97/*ARGSUSED*/
98static nss_status_t
99_nss_user_XY_printers(be, args, filter)
100	user_backend_ptr_t	be;
101	nss_XbyY_args_t		*args;
102	const char		*filter;
103			/*
104			 * filter not useful here since the key
105			 * we are looking for is the first "word"
106			 * on the line and we can be fast enough.
107			 */
108{
109	nss_status_t		res;
110	int namelen;
111
112	if (be->buf == 0 &&
113		(be->buf = (char *)malloc(be->minbuf)) == 0) {
114		(void) _nss_user_endent(be, 0);
115		return (NSS_UNAVAIL); /* really panic, malloc failed */
116	}
117
118	res = NSS_NOTFOUND;
119	namelen = strlen(args->key.name);
120
121	/*CONSTCOND*/
122	while (1) {
123		char		*instr	= be->buf;
124		char		*p, *limit;
125		int		linelen;
126		int		found = 0;
127
128		/*
129		 * _nss_user_read_line does process the '\' that are used
130		 * in /etc/printers.conf for continuation and gives one long
131		 * buffer.
132		 *
133		 * linelen counts the characters up to but excluding the '\n'
134		 */
135		if ((linelen = _nss_user_read_line(be->f, instr,
136		    be->minbuf)) < 0) {
137			/* End of file */
138			args->returnval = 0;
139			args->erange    = 0;
140			break;
141		}
142		p = instr;
143
144		if (*p == '#')					/* comment */
145			continue;
146
147		/*
148		 * find the name in the namelist a|b|c...:
149		 */
150		if ((limit = strpbrk(instr, "\t ")) == NULL)	/* bad line */
151			continue;
152		while ((p < limit) && (found == 0)) {
153			if ((strncmp(p, args->key.name, namelen) == 0) &&
154			    ((*(p+namelen) == '|') ||
155			    (isspace(*(p+namelen)) != 0)))
156				found++;
157			else {
158				if ((p = strchr(p, '|')) == NULL)
159					p = limit;
160				else	/* skip the '|' */
161					p++;
162			}
163		}
164		if (found == 0)
165			continue;
166
167		if ((res = _nss_user_printers_convert(be->buf, args))
168		    == NSS_SUCCESS)
169			break;
170	}
171	(void) _nss_user_endent(be, 0);
172	return (res);
173}
174
175static nss_status_t
176getent(be, a)
177	user_backend_ptr_t	be;
178	void			*a;
179{
180	nss_XbyY_args_t		*args = (nss_XbyY_args_t *)a;
181	nss_status_t		res = NSS_UNAVAIL;
182
183	if (be->buf == 0 &&
184		(be->buf = (char *)malloc(be->minbuf)) == 0) {
185		return (NSS_UNAVAIL); /* really panic, malloc failed */
186	}
187
188	if (be->f == 0) {
189		if ((res = _nss_user_setent(be, 0)) != NSS_SUCCESS) {
190			return (res);
191		}
192	}
193
194	res = NSS_NOTFOUND;
195
196	/*CONSTCOND*/
197	while (1) {
198		char	*instr  = be->buf;
199		int	linelen;
200
201		if ((linelen = _nss_user_read_line(be->f, instr,
202		    be->minbuf)) < 0) {
203			/* End of file */
204			args->returnval = 0;
205			args->erange    = 0;
206			break;
207		}
208
209		if (*(be->buf) == '#')				/* comment */
210			continue;
211
212		if ((res = _nss_user_printers_convert(be->buf, args))
213		    == NSS_SUCCESS)
214			break;
215	}
216	return (res);
217}
218
219
220static nss_status_t
221getbyname(be, a)
222	user_backend_ptr_t	be;
223	void			*a;
224{
225	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
226	nss_status_t		res;
227
228	/* printers_getbyname() has not set/endent; rewind on each call */
229	if ((res = _nss_user_setent(be, 0)) != NSS_SUCCESS) {
230		return (res);
231	}
232	return (_nss_user_XY_printers(be, argp, argp->key.name));
233}
234
235static user_backend_op_t printers_ops[] = {
236	_nss_user_destr,
237	_nss_user_endent,
238	_nss_user_setent,
239	getent,
240	getbyname
241};
242
243/*ARGSUSED*/
244nss_backend_t *
245_nss_user_printers_constr(dummy1, dummy2, dummy3)
246	const char	*dummy1, *dummy2, *dummy3;
247{
248	char path[MAXPATHLEN], *home;
249
250	if ((home = getenv("HOME")) == NULL)
251		home = "";
252	(void) snprintf(path, sizeof (path), "%s/.printers", home);
253
254	return (_nss_user_constr(printers_ops,
255		sizeof (printers_ops) / sizeof (printers_ops[0]),
256		path, NSS_LINELEN_PRINTERS));
257}
258