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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
33 
34 #include "stdio.h"
35 #include "string.h"
36 #include "errno.h"
37 #include "sys/types.h"
38 #include "stdlib.h"
39 #include <syslog.h>
40 
41 #include "lp.h"
42 #include "printers.h"
43 
44 extern struct {
45 	char			*v;
46 	short			len,
47 				okremote;
48 }			prtrheadings[];
49 
50 /**
51  ** getprinter() - EXTRACT PRINTER STRUCTURE FROM DISK FILE
52  **/
53 
54 PRINTER *
55 getprinter(char *name)
56 {
57 	static long		lastdir		= -1;
58 
59 	PRINTER		*prp;
60 
61 	char			buf[BUFSIZ];
62 
63 	short			daisy;
64 
65 	int			fld;
66 
67 	int fd;
68 
69 	FALERT			*pa;
70 
71 	register char *		p;
72 	register char **	pp;
73 	register char ***	ppp;
74 	register char *		path;
75 	int			isNameAll;
76 
77 
78 
79 	if (!name || !*name) {
80 		errno = EINVAL;
81 		return (0);
82 	}
83 
84 	syslog(LOG_DEBUG, "getprinter(%s)", name ? name : "");
85 	/*
86 	 * Getting ``all''? If so, jump into the directory
87 	 * wherever we left off.
88 	 */
89 	isNameAll = STREQU(NAME_ALL, name);
90 	for (; ; ) {
91 		/* fix for bug 1117241
92 		 * occasionally when a printer is removed, a printer directory
93 		 * is left behind, but the CONFIGFILE is removed.  In this
94 		 * case this directory terminates the search for additional
95 		 * printers as we have been returning 0 in this case.
96 		 * Now, we loop back and try the next directory until
97 		 * we have no more directories or we find a directory with
98 		 * a CONFIGFILE
99 		 */
100 		if (isNameAll) {
101 			if (!(name = next_dir(Lp_A_Printers, &lastdir)))
102 				return (0);
103 		} else
104 			lastdir = -1;
105 
106 		/*
107 		 * Get the printer configuration information.
108 		 */
109 
110 		path = getprinterfile(name, CONFIGFILE);
111 		if (!path) {
112 			if (isNameAll)
113 				Free(name);
114 			return (0);
115 		}
116 
117 		if ((fd = open_locked(path, "r", 0)) < 0) {
118 			Free(path);	/*
119 					 * go around to loop again for
120 					 * NAME_ALL case
121 					 */
122 
123 			if (!isNameAll) /* fix for bug 1117241 */
124 				return(0);
125 			else
126 				Free(name);
127 		}
128 		else
129 			break;
130 	}
131 	Free (path);
132 
133 	/*
134 	 * Initialize the entire structure, to ensure no random
135 	 * values get in it. However, make sure some values won't
136 	 * be null or empty. Do the latter here as opposed to
137 	 * after reading the file, because sometimes the file
138 	 * contains an empty header to FORCE a null/empty value.
139 	 */
140 	prp = calloc(sizeof (*prp), 1);
141 	prp->name = Strdup(name);
142 	if (isNameAll)
143 		Free(name);
144 	prp->printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
145 	prp->input_types = getlist(NAME_SIMPLE, LP_WS, LP_SEP);
146 #if	defined(CAN_DO_MODULES)
147 	prp->modules = getlist(NAME_DEFAULT, LP_WS, LP_SEP);
148 #endif
149 
150 	/*
151 	 * Read the file.
152 	 */
153 	errno = 0;
154 	while (fdgets(buf, BUFSIZ, fd) != NULL) {
155 
156 		buf[strlen(buf) - 1] = 0;
157 
158 		for (fld = 0; fld < PR_MAX; fld++)
159 			if (
160 				prtrheadings[fld].v
161 			     && prtrheadings[fld].len
162 			     && STRNEQU(
163 					buf,
164 					prtrheadings[fld].v,
165 					prtrheadings[fld].len
166 				)
167 			) {
168 				p = buf + prtrheadings[fld].len;
169 				while (*p && *p == ' ')
170 					p++;
171 				break;
172 			}
173 
174 		/*
175 		 * To allow future extensions to not impact applications
176 		 * using old versions of this routine, ignore strange
177 		 * fields.
178 		 */
179 		if (fld >= PR_MAX)
180 			continue;
181 
182 		switch (fld) {
183 
184 		case PR_BAN:
185 			if ((pp = getlist(p, LP_WS, ":"))) {
186 				if (pp[0] != NULL) {
187 					if (strcmp(pp[0], NAME_OPTIONAL) == 0)
188 						prp->banner = BAN_OPTIONAL;
189 					else if (strcmp(pp[0], NAME_OFF) == 0)
190 						prp->banner = BAN_NEVER;
191 					else if (strcmp(pp[0], NAME_ON) == 0)
192 						prp->banner = BAN_ALWAYS;
193 					else /* default to the LP default */
194 						prp->banner = BAN_ALWAYS;
195 				}
196 				if (pp[1] && CS_STREQU(pp[1], NAME_ALWAYS))
197 					prp->banner |= BAN_ALWAYS;
198 				freelist (pp);
199 			}
200 			break;
201 
202 		case PR_LOGIN:
203 			prp->login = LOG_IN;
204 			break;
205 
206 		case PR_CPI:
207 			prp->cpi = getcpi(p);
208 			break;
209 
210 		case PR_LPI:
211 			prp->lpi = getsdn(p);
212 			break;
213 
214 		case PR_LEN:
215 			prp->plen = getsdn(p);
216 			break;
217 
218 		case PR_WIDTH:
219 			prp->pwid = getsdn(p);
220 			break;
221 
222 		case PR_CS:
223 			ppp = &(prp->char_sets);
224 			goto CharStarStar;
225 
226 		case PR_ITYPES:
227 			ppp = &(prp->input_types);
228 CharStarStar:		if (*ppp)
229 				freelist (*ppp);
230 			*ppp = getlist(p, LP_WS, LP_SEP);
231 			break;
232 
233 		case PR_DEV:
234 			pp = &(prp->device);
235 			goto CharStar;
236 
237 		case PR_DIAL:
238 			pp = &(prp->dial_info);
239 			goto CharStar;
240 
241 		case PR_RECOV:
242 			pp = &(prp->fault_rec);
243 			goto CharStar;
244 
245 		case PR_INTFC:
246 			pp = &(prp->interface);
247 			goto CharStar;
248 
249 		case PR_PTYPE:
250 			ppp = &(prp->printer_types);
251 			goto CharStarStar;
252 
253 		case PR_REMOTE:
254 			pp = &(prp->remote);
255 			goto CharStar;
256 
257 		case PR_SPEED:
258 			pp = &(prp->speed);
259 			goto CharStar;
260 
261 		case PR_STTY:
262 			pp = &(prp->stty);
263 CharStar:		if (*pp)
264 				Free (*pp);
265 			*pp = Strdup(p);
266 			break;
267 
268 #if	defined(CAN_DO_MODULES)
269 		case PR_MODULES:
270 			ppp = &(prp->modules);
271 			goto CharStarStar;
272 #endif
273 
274 		case PR_OPTIONS:
275 			ppp = &(prp->options);
276 			goto CharStarStar;
277 			break;
278 
279 		case PR_PPD:
280 		{
281 			pp = &(prp->ppd);
282 			goto CharStar;
283 		}
284 		}
285 
286 	}
287 	if (errno != 0) {
288 		int			save_errno = errno;
289 
290 		freeprinter (prp);
291 		close(fd);
292 		errno = save_errno;
293 		return (0);
294 	}
295 	close(fd);
296 
297 	/*
298 	 * Get the printer description (if it exists).
299 	 */
300 	if (!(path = getprinterfile(prp->name, COMMENTFILE)))
301 		return (0);
302 	if (!(prp->description = loadstring(path)) && errno != ENOENT) {
303 		Free (path);
304 		freeprinter (prp);
305 		return (0);
306 	}
307 	Free (path);
308 
309 	/*
310 	 * Get the information for the alert. Don't fail if we can't
311 	 * read it because of access permission UNLESS we're "root"
312 	 * or "lp"
313 	 */
314 	if (!(pa = getalert(Lp_A_Printers, prp->name))) {
315 		if (
316 			errno != ENOENT
317 		     && (
318 				errno != EACCES
319 			     || !getpid()		  /* we be root */
320 			     || STREQU(getname(), LPUSER) /* we be lp   */
321 			)
322 		) {
323 			freeprinter (prp);
324 			return (0);
325 		}
326 	} else
327 		prp->fault_alert = *pa;
328 
329 	/*
330 	 * Now go through the structure and see if we have
331 	 * anything strange.
332 	 */
333 	if (!okprinter(prp->name, prp, 0)) {
334 		freeprinter (prp);
335 		errno = EBADF;
336 		return (0);
337 	}
338 
339 	/*
340 	 * Just in case somebody tried to pull a fast one
341 	 * by giving a printer type header by itself....
342 	 */
343 	if (!prp->printer_types)
344 		prp->printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
345 
346 	/*
347 	 * If there are more than one printer type, then we can't
348 	 * have any input types, except perhaps ``simple''.
349 	 */
350 	if (
351 		lenlist(prp->printer_types) > 1
352 	     && prp->input_types
353 	     && (
354 			lenlist(prp->input_types) > 1
355 		     || !STREQU(NAME_SIMPLE, *prp->input_types)
356 		)
357 	) {
358 		freeprinter (prp);
359 		badprinter = BAD_ITYPES;
360 		errno = EBADF;
361 		return (0);
362 	}
363 
364 	/*
365 	 * If there are more than one printer types, none can
366 	 * be ``unknown''.
367 	 */
368 	if (
369 		lenlist(prp->printer_types) > 1
370 	     && searchlist(NAME_UNKNOWN, prp->printer_types)
371 	) {
372 		freeprinter (prp);
373 		badprinter = BAD_PTYPES;
374 		errno = EBADF;
375 		return (0);
376 	}
377 
378 	/*
379 	 * All the printer types had better agree on whether the
380 	 * printer takes print wheels!
381 	 */
382 	prp->daisy = -1;
383 	for (pp = prp->printer_types; *pp; pp++) {
384 		tidbit (*pp, "daisy", &daisy);
385 		if (daisy == -1)
386 			daisy = 0;
387 		if (prp->daisy == -1)
388 			prp->daisy = daisy;
389 		else if (prp->daisy != daisy) {
390 			freeprinter (prp);
391 			badprinter = BAD_DAISY;
392 			errno = EBADF;
393 			return (0);
394 		}
395 	}
396 
397 	/*
398 	 * Help out those who are still using the obsolete
399 	 * "printer_type" member.
400 	 */
401 	prp->printer_type = Strdup(*prp->printer_types);
402 
403 	return (prp);
404 }
405