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