xref: /illumos-gate/usr/src/cmd/lp/cmd/lpadmin/chkopts.c (revision 2a8bcb4e)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #include "stdio.h"
32 #include "string.h"
33 #include "pwd.h"
34 #include "sys/types.h"
35 #include "errno.h"
36 
37 #include "lp.h"
38 #include "printers.h"
39 #include "form.h"
40 #include "class.h"
41 
42 #define	WHO_AM_I	I_AM_LPADMIN
43 #include "oam.h"
44 
45 #include "lpadmin.h"
46 
47 #define PPDZIP	".gz"
48 
49 
50 extern PRINTER		*printer_pointer;
51 
52 extern PWHEEL		*pwheel_pointer;
53 
54 extern struct passwd	*getpwnam();
55 
56 void			chkopts2(),
57 			chkopts3();
58 static void		chksys();
59 
60 FORM			formbuf;
61 
62 char			**f_allow,
63 			**f_deny,
64 			**u_allow,
65 			**u_deny,
66 			**p_add,
67 			**p_remove;
68 
69 PRINTER			*oldp		= 0;
70 
71 PWHEEL			*oldS		= 0;
72 
73 short			daisy		= 0;
74 
75 static int		root_can_write();
76 
77 static char		*unpack_sdn();
78 
79 static char **		bad_list;
80 
81 #if	defined(__STDC__)
82 static unsigned long	sum_chkprinter ( char ** , char * , char * , char * , char * , char * );
83 static int isPPD(char *ppd_file);
84 #else
85 static unsigned long	sum_chkprinter();
86 static int isPPD();
87 #endif
88 
89 /**
90  ** chkopts() -- CHECK LEGALITY OF COMMAND LINE OPTIONS
91  **/
92 
chkopts()93 void			chkopts ()
94 {
95 	short		isfAuto = 0;
96 
97 	/*
98 	 * Check -d.
99 	 */
100 	if (d) {
101 		if (
102 			a || c || f || P || j || m || M || t || p || r || u || x
103 #if	defined(DIRECT_ACCESS)
104 		     || C
105 #endif
106 #ifdef LP_USE_PAPI_ATTR
107 		     || n_opt
108 #endif
109 		     || strlen(modifications)
110 		) {
111 			LP_ERRMSG (ERROR, E_ADM_DALONE);
112 			done (1);
113 		}
114 
115 		if (
116 			*d
117 		     && !STREQU(d, NAME_NONE)
118 		     && !isprinter(d)
119 		     && !isclass(d)
120 		) {
121 			LP_ERRMSG1 (ERROR, E_ADM_NODEST, d);
122 			done (1);
123 		}
124 		return;
125 	}
126 
127 	/*
128 	 * Check -x.
129 	 */
130 	if (x) {
131 		if (	/* MR bl88-02718 */
132 			A || a || c || f || P || j || m || M || t || p || r || u || d
133 #if	defined(DIRECT_ACCESS)
134 		     || C
135 #endif
136 #ifdef LP_USE_PAPI_ATTR
137 		     || n_opt
138 #endif
139 		     || strlen(modifications)
140 		) {
141 			LP_ERRMSG (ERROR, E_ADM_XALONE);
142 			done (1);
143 		}
144 
145 		if (
146 			!STREQU(NAME_ALL, x)
147 		     && !STREQU(NAME_ANY, x)
148 		     && !isprinter(x)
149 		     && !isclass(x)
150 		) {
151 			LP_ERRMSG1 (ERROR, E_ADM_NODEST, x);
152 			done (1);
153 		}
154 		return;
155 	}
156 
157 	/*
158 	 * Problems common to both -p and -S (-S alone).
159 	 */
160 	if (A && STREQU(A, NAME_LIST) && (W != -1 || Q != -1)) {
161 		LP_ERRMSG (ERROR, E_ADM_LISTWQ);
162 		done (1);
163 	}
164 
165 
166 	/*
167 	 * Check -S.
168 	 */
169 	if (!p && S) {
170 		if (
171 			M || t || a || f || P || c || r || e || i || m || H || h
172 		     || l || v || I || T || D || F || u || U || j || o
173 #ifdef LP_USE_PAPI_ATTR
174 		     || n_opt
175 #endif
176 		) {
177 			LP_ERRMSG (ERROR, E_ADM_SALONE);
178 			done (1);
179 		}
180 		if (!A && W == -1 && Q == -1) {
181 			LP_ERRMSG (ERROR, E_ADM_NOAWQ);
182 			done (1);
183 		}
184 		if (S[0] && S[1])
185 			LP_ERRMSG (WARNING, E_ADM_ASINGLES);
186 		if (!STREQU(NAME_ALL, *S) && !STREQU(NAME_ANY, *S))
187 			chkopts3(1);
188 		return;
189 	}
190 
191 	/*
192 	 * At this point we must have a printer (-p option).
193 	 */
194 	if (!p) {
195 		LP_ERRMSG (ERROR, E_ADM_NOACT);
196 		done (1);
197 	}
198 	if (STREQU(NAME_NONE, p)) {
199 		LP_ERRMSG1 (ERROR, E_LP_NULLARG, "p");
200 		done (1);
201 	}
202 
203 
204 	/*
205 	 * Mount but nothing to mount?
206 	 */
207 	if (M && (!f && !S)) {
208 		LP_ERRMSG (ERROR, E_ADM_MNTNONE);
209 		done (1);
210 	}
211 
212 	/*
213 	 * -Q isn't allowed with -p.
214 	 */
215 	if (Q != -1) {
216 		LP_ERRMSG (ERROR, E_ADM_PNOQ);
217 		done (1);
218 	}
219 
220 	/*
221 	 * Fault recovery.
222 	 */
223 	if (
224 		F
225 	     && !STREQU(F, NAME_WAIT)
226 	     && !STREQU(F, NAME_BEGINNING)
227 	     && (
228 			!STREQU(F, NAME_CONTINUE)
229 		     || j
230 		     && STREQU(F, NAME_CONTINUE)
231 		)
232 	) {
233 #if	defined(J_OPTION)
234 		if (j)
235 			LP_ERRMSG (ERROR, E_ADM_FBADJ);
236 		else
237 #endif
238 			LP_ERRMSG (ERROR, E_ADM_FBAD);
239 		done (1);
240 	}
241 
242 #if	defined(J_OPTION)
243 	/*
244 	 * The -j option is used only with the -F option.
245 	 */
246  	if (j) {
247 		if (M || t || a || f || P || c || r || e || i || m || H || h ||
248 #ifdef LP_USE_PAPI_ATTR
249 		    n_opt ||
250 #endif
251 		    l || v || I || T || D || u || U || o) {
252 			LP_ERRMSG (ERROR, E_ADM_JALONE);
253 			done (1);
254 		}
255 		if (j && !F) {
256 			LP_ERRMSG (ERROR, E_ADM_JNOF);
257 			done (1);
258 		}
259 		return;
260 	}
261 #endif
262 
263 #if	defined(DIRECT_ACCESS)
264 	/*
265 	 * -C is only used to modify -u
266 	 */
267 	if (C && !u) {
268 		LP_ERRMSG (ERROR, E_ADM_CNOU);
269 		done (1);
270 	}
271 #endif
272 
273 	/*
274 	 * The -a option needs the -M and -f options,
275 	 * Also, -ofilebreak is used only with -a.
276 	 */
277 	if (a && (!M || !f)) {
278 		LP_ERRMSG (ERROR, E_ADM_MALIGN);
279 		done (1);
280 	}
281 	if (filebreak && !a)
282 		LP_ERRMSG (WARNING, E_ADM_FILEBREAK);
283 
284 	/*
285 	 * The "-p all" case is restricted to certain options.
286 	 */
287 	if (
288 		(STREQU(NAME_ANY, p) || STREQU(NAME_ALL, p))
289 	     && (
290 			a || h || l || M || t || D || e || f || P || H || s
291 #ifdef LP_USE_PAPI_ATTR
292 		      || n_opt
293 #endif
294 		     || i || I || m || S || T || u || U || v || banner != -1
295 		     || cpi || lpi || width || length || stty_opt
296 		)
297 	) {
298 		LP_ERRMSG (ERROR, E_ADM_ANYALLNONE);
299 		done (1);
300 
301 	}
302 
303 	/*
304 	 * Allow giving -v or -U option as way of making
305 	 * remote printer into local printer.
306 	 * Note: "!s" here means the user has not given the -s;
307 	 * later it means the user gave -s local-system.
308 	 */
309 	if (!s && (v || U))
310 		s = Local_System;
311 
312 	/*
313 	 * Be careful about checking "s" before getting here.
314 	 * We want "s == 0" to mean this is a local printer; however,
315 	 * if the user wants to change a remote printer to a local
316 	 * printer, we have to have "s == Local_System" long enough
317 	 * to get into "chkopts2()" where a special check is made.
318 	 * After "chkopts2()", "s == 0" means local.
319 	 */
320 	if (!STREQU(NAME_ALL, p) && !STREQU(NAME_ANY, p))
321 		/*
322 		 * If old printer, make sure it exists. If new printer,
323 		 * check that the name is okay, and that enough is given.
324 		 * (This stuff has been moved to "chkopts2()".)
325 		 */
326 		chkopts2(1);
327 
328 	if (!s) {
329 
330 		/*
331 		 * Only one of -i, -m, -e.
332 		 */
333 		if ((i && e) || (m && e) || (i && m)) {
334 			LP_ERRMSG (ERROR, E_ADM_INTCONF);
335 			done (1);
336 		}
337 
338 		/*
339 		 * Check -e arg.
340 		 */
341 		if (e) {
342 			if (!isprinter(e)) {
343 				LP_ERRMSG1 (ERROR, E_ADM_NOPR, e);
344 				done (1);
345 			}
346 			if (strcmp(e, p) == 0) {
347 				LP_ERRMSG (ERROR, E_ADM_SAMEPE);
348 				done (1);
349 			}
350 		}
351 
352 		/*
353 		 * Check -m arg.
354 		 */
355 		if (m && !ismodel(m)) {
356 			LP_ERRMSG1 (ERROR, E_ADM_NOMODEL, m);
357 			done (1);
358 		}
359 
360 #ifdef LP_USE_PAPI_ATTR
361 		/*
362 		 * Check -n arg. The ppd file exists.
363 		 */
364 		if ((n_opt != NULL) && !isPPD(n_opt)) {
365 			LP_ERRMSG1 (ERROR, E_ADM_NOPPD, n_opt);
366 			done (1);
367 		}
368 #endif
369 
370 		/*
371 		 * Need exactly one of -h or -l (but will default -h).
372 		 */
373 		if (h && l) {
374 			LP_ERRMSG2 (ERROR, E_ADM_CONFLICT, 'h', 'l');
375 			done (1);
376 		}
377 		if (!h && !l)
378 			h = 1;
379 
380 		/*
381 		 * Check -c and -r.
382 		 */
383 		if (c && r && strcmp(c, r) == 0) {
384 			LP_ERRMSG (ERROR, E_ADM_SAMECR);
385 			done (1);
386 		}
387 
388 
389 		/*
390 		 * Are we creating a class with the same name as a printer?
391 		 */
392 		if (c) {
393 			if (STREQU(c, p)) {
394 				LP_ERRMSG1 (ERROR, E_ADM_CLNPR, c);
395 				done (1);
396 			}
397 			if (isprinter(c)) {
398 				LP_ERRMSG1 (ERROR, E_ADM_CLPR, c);
399 				done (1);
400 			}
401 		}
402 
403 		if (v && (is_printer_uri(v) < 0)) {
404 			/*
405 			 * The device must be writeable by root.
406 			 */
407 			if (v && root_can_write(v) == -1)
408 				done (1);
409 		}
410 
411 		/*
412 		 * Can't have both device and dial-out.
413 		 */
414 		if (v && U) {
415 			LP_ERRMSG (ERROR, E_ADM_BOTHUV);
416 			done (1);
417 		}
418 
419 	} else
420 		if (
421 			A || a || e || H || h || i || l || m || ( t && !M) || ( M && !t)
422 		     || o || U || v || Q != -1 || W != -1
423 #ifdef LP_USE_PAPI_ATTR
424 		     || n_opt
425 #endif
426 		) {
427 			LP_ERRMSG (ERROR, E_ADM_NOTLOCAL);
428 			done(1);
429 		}
430 
431 
432 	/*
433 	 * We need the printer type for some things, and the boolean
434 	 * "daisy" (from Terminfo) for other things.
435 	 */
436 	if (!T && oldp)
437 		T = oldp->printer_types;
438 	if (T) {
439 		short			a_daisy;
440 
441 		char **			pt;
442 
443 
444 		if (lenlist(T) > 1 && searchlist(NAME_UNKNOWN, T)) {
445 			LP_ERRMSG (ERROR, E_ADM_MUNKNOWN);
446 			done (1);
447 		}
448 
449 		for (pt = T; *pt; pt++)
450 			if (tidbit(*pt, (char *)0) == -1) {
451 				LP_ERRMSG1 (ERROR, E_ADM_BADTYPE, *pt);
452 				done (1);
453 			}
454 
455 		/*
456 		 * All the printer types had better agree on whether the
457 		 * printer takes print wheels!
458 		 */
459 		daisy = a_daisy = -1;
460 		for (pt = T; *pt; pt++) {
461 			tidbit (*pt, "daisy", &daisy);
462 			if (daisy == -1)
463 				daisy = 0;
464 			if (a_daisy == -1)
465 				a_daisy = daisy;
466 			else if (a_daisy != daisy) {
467 				LP_ERRMSG (ERROR, E_ADM_MIXEDTYPES);
468 				done (1);
469 			}
470 		}
471 	}
472 	if (cpi || lpi || length || width || S || f || filebreak)
473 		if (!T) {
474 			LP_ERRMSG (ERROR, E_ADM_TOPT);
475 			done (1);
476 
477 		}
478 
479 	/*
480 	 * Check -o cpi=, -o lpi=, -o length=, -o width=
481 	 */
482 	if (cpi || lpi || length || width) {
483 		unsigned	long	rc;
484 
485 		if ((rc = sum_chkprinter(T, cpi, lpi, length, width, NULL)) == 0) {
486 			if (bad_list)
487 				LP_ERRMSG1 (
488 					INFO,
489 					E_ADM_NBADCAPS,
490 					sprintlist(bad_list)
491 				);
492 
493 		} else {
494 			if ((rc & PCK_CPI) && cpi)
495 				LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "cpi=");
496 
497 			if ((rc & PCK_LPI) && lpi)
498 				LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "lpi=");
499 
500 			if ((rc & PCK_WIDTH) && width)
501 				LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "width=");
502 
503 			if ((rc & PCK_LENGTH) && length)
504 				LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "length=");
505 
506 			LP_ERRMSG (ERROR, E_ADM_BADCAPS);
507 			done(1);
508 		}
509 	}
510 
511 	/*
512 	 * Check -I (old or new):
513 	 */
514 	if (T && lenlist(T) > 1) {
515 
516 #define BADILIST(X) (lenlist(X) > 1 || X && *X && !STREQU(NAME_SIMPLE, *X))
517 		if (
518 			I && BADILIST(I)
519 		     || !I && oldp && BADILIST(oldp->input_types)
520 		) {
521 			LP_ERRMSG (ERROR, E_ADM_ONLYSIMPLE);
522 			done (1);
523 		}
524 	}
525 
526 	/*
527 	 * MOUNT:
528 	 * Only one print wheel can be mounted at a time.
529 	 */
530 	if (M && S && S[0] && S[1])
531 		LP_ERRMSG (WARNING, E_ADM_MSINGLES);
532 
533 	/*
534 	 * NO MOUNT:
535 	 * If the printer takes print wheels, the -S argument
536 	 * should be a simple list; otherwise, it must be a
537 	 * mapping list. (EXCEPT: In either case, "none" alone
538 	 * means delete the existing list.)
539 	 */
540 	if (S && !M) {
541 		register char		**item,
542 					*cp;
543 
544 		/*
545 		 * For us to be here, "daisy" must have been set.
546 		 * (-S requires knowing printer type (T), and knowing
547 		 * T caused call to "tidbit()" to set "daisy").
548 		 */
549 		if (!STREQU(S[0], NAME_NONE) || S[1])
550 		    if (daisy) {
551 			for (item = S; *item; item++) {
552 				if (strchr(*item, '=')) {
553 					LP_ERRMSG (ERROR, E_ADM_PWHEELS);
554 					done (1);
555 				}
556 				if (!syn_name(*item)) {
557 					LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *item);
558 					done (1);
559 				}
560 			}
561 		    } else {
562 			register int		die = 0;
563 
564 			for (item = S; *item; item++) {
565 				if (!(cp = strchr(*item, '='))) {
566 					LP_ERRMSG (ERROR, E_ADM_CHARSETS);
567 					done (1);
568 				}
569 
570 				*cp = 0;
571 				if (!syn_name(*item)) {
572 					LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *item);
573 					done (1);
574 				}
575 				if (PCK_CHARSET & sum_chkprinter(T, (char *)0, (char *)0, (char *)0, (char *)0, *item)) {
576 					LP_ERRMSG1 (ERROR, E_ADM_BADSET, *item);
577 					die = 1;
578 				} else {
579 					if (bad_list)
580 						LP_ERRMSG2 (
581 							INFO,
582 							E_ADM_NBADSET,
583 							*item,
584 							sprintlist(bad_list)
585 						);
586 				}
587 				*cp++ = '=';
588 				if (!syn_name(cp)) {
589 					LP_ERRMSG1 (ERROR, E_LP_NOTNAME, cp);
590 					done (1);
591 				}
592 			}
593 			if (die) {
594 				LP_ERRMSG (ERROR, E_ADM_BADSETS);
595 				done (1);
596 			}
597 		}
598 	}
599 
600 	if (P) {
601 		int createForm = 0;
602 		char **plist;
603 
604 		if (getform(P, &formbuf, (FALERT *)0, (FILE **)0) != -1) {
605 			if ((!formbuf.paper) || (!STREQU(formbuf.paper,P)) ) {
606 				LP_ERRMSG (ERROR, E_ADM_ALSO_SEP_FORM);
607 				done (1);
608 			}
609 		} else
610 			createForm = 1;
611 
612 		if (*P == '~') { /* removing types of papers */
613 			P++;
614 			p_remove = getlist(P, LP_WS, LP_SEP);
615 			p_add = NULL;
616 		} else  { /* adding types of papers */
617 			p_add = getlist(P, LP_WS, LP_SEP);
618 			p_remove = NULL;
619 			if (createForm) {
620 				char cmdBuf[200];
621 
622 				for (plist = p_add; *plist; plist++) {
623 					snprintf(cmdBuf, sizeof (cmdBuf),
624 					    "lpforms -f %s -d\n", *plist);
625 					system(cmdBuf);
626 				}
627 			}
628 		}
629 
630 		if (!f && !M) {  /* make paper allowed on printer too */
631 			f = Malloc(strlen(P) + strlen(NAME_ALLOW) +
632 			    strlen(": "));
633 			sprintf(f, "%s:%s", NAME_ALLOW, P);
634 			isfAuto = 1;
635 		}
636 	}
637 	/*
638 	 * NO MOUNT:
639 	 * The -f option restricts the forms that can be used with
640 	 * the printer.
641 	 *	- construct the allow/deny lists
642 	 *	- check each allowed form to see if it'll work
643 	 *	  on the printer
644 	 */
645 	if (f && !M) {
646 		register char		*type	= strtok(f, ":"),
647 					*str	= strtok((char *)0, ":"),
648 					**pf;
649 
650 		register int		die	= 0;
651 
652 
653 		if (STREQU(type, NAME_ALLOW) && str) {
654 			if ((pf = f_allow = getlist(str, LP_WS, LP_SEP)) != NULL) {
655 				while (*pf) {
656 					if ((!isfAuto) &&
657 						!STREQU(*pf, NAME_NONE)
658 					     && verify_form(*pf) < 0
659 					)
660 						die = 1;
661 					pf++;
662 				}
663 				if (die) {
664 					LP_ERRMSG (ERROR, E_ADM_FORMCAPS);
665 					done (1);
666 				}
667 
668 			} else
669 				LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_ALLOW);
670 
671 		} else if (STREQU(type, NAME_DENY) && str) {
672 			if ((pf = f_deny = getlist(str, LP_WS, LP_SEP)) != NULL) {
673 				if (!STREQU(*pf, NAME_ALL)) {
674 					while (*pf) {
675 						if ((!isfAuto) &&
676 						  !STREQU(*pf, NAME_NONE) &&
677 					     	  getform(*pf, &formbuf,
678 						  (FALERT *)0, (FILE **)0) < 0
679 						) {
680 						   LP_ERRMSG2(WARNING,
681 							E_ADM_ICKFORM, *pf, p);
682 						   die = 1;
683 						}
684 						pf++;
685 					}
686 				}
687 				if (die) {
688 					done (1);
689 				}
690 
691 			} else
692 				LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_DENY);
693 
694 		} else {
695 			LP_ERRMSG (ERROR, E_ADM_FALLOWDENY);
696 			done (1);
697 		}
698 	}
699 
700 	/*
701 	 * The -u option is setting use restrictions on printers.
702 	 *	- construct the allow/deny lists
703 	 */
704 	if (u) {
705 		register char		*type	= strtok(u, ":"),
706 					*str	= strtok((char *)0, ":");
707 
708 		if (STREQU(type, NAME_ALLOW) && str) {
709 			if (!(u_allow = getlist(str, LP_WS, LP_SEP)))
710 				LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_ALLOW);
711 
712 		} else if (STREQU(type, NAME_DENY) && str) {
713 			if (!(u_deny = getlist(str, LP_WS, LP_SEP)))
714 				LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_DENY);
715 
716 		} else {
717 			LP_ERRMSG (ERROR, E_LP_UALLOWDENY);
718 			done (1);
719 		}
720 	}
721 
722 	return;
723 }
724 
725 /**
726  ** root_can_write() - CHECK THAT "root" CAN SENSIBLY WRITE TO PATH
727  **/
728 
root_can_write(path)729 static int		root_can_write (path)
730 	char			*path;
731 {
732 	static int		lp_uid		= -1;
733 
734 	struct passwd		*ppw;
735 
736 	struct stat		statbuf;
737 
738 
739 	if (lstat(path, &statbuf) == -1) {
740 		LP_ERRMSG1 (ERROR, E_ADM_NOENT, v);
741 		return (-1);
742 	}
743 	/*
744 	 * If the device is a symlink (and it is not a root owned symlink),
745 	 * verify that the owner matches the destination owner.
746 	 */
747 	if (S_ISLNK(statbuf.st_mode) && statbuf.st_uid != 0) {
748 		uid_t uid = statbuf.st_uid;
749 
750 		if (Stat(path, &statbuf) == -1) {
751 			LP_ERRMSG1 (ERROR, E_ADM_NOENT, v);
752 			return (-1);
753 		}
754 
755 		if (statbuf.st_uid != uid) {
756 			LP_ERRMSG1 (ERROR, E_ADM_ISMISMATCH, v);
757 			done(1);
758 		}
759 
760 		LP_ERRMSG1(WARNING, E_ADM_ISNOTROOTOWNED, v);
761 	}
762 
763 	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
764 		LP_ERRMSG1 (WARNING, E_ADM_ISDIR, v);
765 	} else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
766 		LP_ERRMSG1 (WARNING, E_ADM_ISBLK, v);
767 
768 	if (lp_uid == -1) {
769 		if (!(ppw = getpwnam(LPUSER)))
770 			ppw = getpwnam(ROOTUSER);
771 		endpwent ();
772 		if (ppw)
773 			lp_uid = ppw->pw_uid;
774 		else
775 			lp_uid = 0;
776 	}
777 	if (!STREQU(v, "/dev/null"))
778 	    if ((statbuf.st_uid && statbuf.st_uid != lp_uid)
779 		|| (statbuf.st_mode & (S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH)))
780 		LP_ERRMSG1 (WARNING, E_ADM_DEVACCESS, v);
781 
782 	return (0);
783 }
784 
785 /**
786  ** unpack_sdn() - TURN SCALED TYPE INTO char* TYPE
787  **/
788 
unpack_sdn(sdn)789 static char		*unpack_sdn (sdn)
790 	SCALED			sdn;
791 {
792 	register char		*cp;
793 	extern char		*malloc();
794 
795 	if (sdn.val <= 0 || 99999 < sdn.val)
796 		cp = 0;
797 
798 	else if (sdn.val == N_COMPRESSED)
799 		cp = strdup(NAME_COMPRESSED);
800 
801 	else if ((cp = malloc(sizeof("99999.999x"))))
802 		(void) sprintf(cp, "%.3f%c", sdn.val, sdn.sc);
803 
804 	return (cp);
805 }
806 
807 /**
808  ** verify_form() - SEE IF PRINTER CAN HANDLE FORM
809  **/
810 
verify_form(form)811 int			verify_form (form)
812 	char			*form;
813 {
814 	register char		*cpi_f,
815 				*lpi_f,
816 				*width_f,
817 				*length_f,
818 				*chset;
819 
820 	register int		rc	= 0;
821 	char			**paperAllowed = NULL;
822 	char			**paperDenied = NULL;
823 
824 	register unsigned long	checks;
825 
826 
827 	if (STREQU(form, NAME_ANY))
828 		form = NAME_ALL;
829 
830 	while (getform(form, &formbuf, (FALERT *)0, (FILE **)0) != -1) {
831 		if (formbuf.paper) {
832 			if (!paperAllowed) {
833 				load_paperprinter_access(p, &paperAllowed,
834 					&paperDenied);
835 				freelist(paperDenied);
836 			}
837 			if (!allowed(formbuf.paper,paperAllowed,NULL)) {
838 				LP_ERRMSG1 (INFO, E_ADM_BADCAP,
839 				gettext("printer doesn't support paper type"));
840 				rc = -1;
841 			}
842 		}
843 		else {
844 
845 		cpi_f = unpack_sdn(formbuf.cpi);
846 		lpi_f = unpack_sdn(formbuf.lpi);
847 		width_f = unpack_sdn(formbuf.pwid);
848 		length_f = unpack_sdn(formbuf.plen);
849 
850 		if (
851 			formbuf.mandatory
852 		     && !daisy
853 		     && !search_cslist(
854 				formbuf.chset,
855 				(S && !M? S : (oldp? oldp->char_sets : (char **)0))
856 			)
857 		)
858 			chset = formbuf.chset;
859 		else
860 			chset = 0;
861 
862 		if ((checks = sum_chkprinter(
863 			T,
864 			cpi_f,
865 			lpi_f,
866 			length_f,
867 			width_f,
868 			chset
869 		))) {
870 			rc = -1;
871 			if ((checks & PCK_CPI) && cpi_f)
872 				LP_ERRMSG1 (INFO, E_ADM_BADCAP, "cpi");
873 
874 			if ((checks & PCK_LPI) && lpi_f)
875 				LP_ERRMSG1 (INFO, E_ADM_BADCAP, "lpi");
876 
877 			if ((checks & PCK_WIDTH) && width_f)
878 				LP_ERRMSG1 (INFO, E_ADM_BADCAP, "width");
879 
880 			if ((checks & PCK_LENGTH) && length_f)
881 				LP_ERRMSG1 (INFO, E_ADM_BADCAP, "length");
882 
883 			if ((checks & PCK_CHARSET) && formbuf.chset) {
884 				LP_ERRMSG1 (INFO, E_ADM_BADSET, formbuf.chset);
885 				rc = -2;
886 			}
887 			LP_ERRMSG1 (INFO, E_ADM_FORMCAP, formbuf.name);
888 		} else {
889 			if (bad_list)
890 				LP_ERRMSG2 (
891 					INFO,
892 					E_ADM_NBADMOUNT,
893 					formbuf.name,
894 					sprintlist(bad_list)
895 				);
896 		}
897 		}
898 
899 		if (!STREQU(form, NAME_ALL)) {
900 			if (paperAllowed)
901 				freelist(paperAllowed);
902 			return (rc);
903 		}
904 
905 	}
906 	if (paperAllowed)
907 		freelist(paperAllowed);
908 
909 	if (!STREQU(form, NAME_ALL)) {
910 		LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
911 		done (1);
912 	}
913 
914 	return (rc);
915 }
916 
917 /*
918 	Second phase of parsing for -p option.
919 	In a seperate routine so we can call it from other
920 	routines. This is used when any or all are used as
921 	a printer name. main() loops over each printer, and
922 	must call this function for each printer found.
923 */
924 void
chkopts2(called_from_chkopts)925 chkopts2(called_from_chkopts)
926 int	called_from_chkopts;
927 {
928 	/*
929 		Only do the getprinter() if we are not being called
930 		from lpadmin.c. Otherwise we mess up our arena for
931 		"all" processing.
932 	*/
933 	if (!called_from_chkopts)
934 		oldp = printer_pointer;
935 	else if (!(oldp = getprinter(p)) && errno != ENOENT) {
936 		LP_ERRMSG2 (ERROR, E_LP_GETPRINTER, p, PERROR);
937 		done(1);
938 	}
939 
940 	if (oldp) {
941 		if (
942 			!c && !d && !f && !P && !M && !t && !r && !u && !x && !A
943 	     		&& !strlen(modifications)
944 		) {
945 			LP_ERRMSG (ERROR, E_ADM_PLONELY);
946 			done (1);
947 		}
948 
949 		/*
950 		 * For the case "-s local-system", we need to keep
951 		 * "s != 0" long enough to get here, where it keeps
952 		 * us from taking the old value. After this, we make
953 		 * "s == 0" to indicate this is a local printer.
954 		 */
955 		if (s && s != Local_System)
956 			chksys(s);
957 		if (!s && oldp->remote && *(oldp->remote))
958 			s = strdup(oldp->remote);
959 		if (s == Local_System)
960 			s = 0;
961 
962 		/*
963 		 * A remote printer converted to a local printer
964 		 * requires device or dial info.
965 		 */
966 		if (!s && oldp->remote && !v && !U) {
967 			LP_ERRMSG (ERROR, E_ADM_NOUV);
968 			done (1);
969 		}
970 
971 
972 	} else {
973 		if (getclass(p)) {
974 			LP_ERRMSG1 (ERROR, E_ADM_PRCL, p);
975 			done (1);
976 		}
977 
978 		if (!syn_name(p)) {
979 			LP_ERRMSG1 (ERROR, E_LP_NOTNAME, p);
980 			done (1);
981 		}
982 
983 		if (s == Local_System)
984 			s = 0;
985 		if (s)
986 			chksys(s);
987 
988 #ifdef LP_USE_PAPI_ATTR
989 		/*
990 		 * New printer - if no model and a PPD file is defined then
991 		 *               use 'standard_foomatic' otherwise use
992 		 *               the 'standard' model.
993 		 */
994 		if (!(e || i || m) && !s) {
995 			if (n_opt != NULL) {
996 				m = STANDARD_FOOMATIC;
997 			} else {
998 				m = STANDARD;
999 			}
1000 		}
1001 #else
1002 		/*
1003 		 * New printer - if no model, use standard
1004 		 */
1005 		if (!(e || i || m) && !s)
1006 			m = STANDARD;
1007 #endif
1008 
1009 		/*
1010 		 * A new printer requires device or dial info.
1011 		 */
1012 		if (!v && !U && !s) {
1013 			LP_ERRMSG (ERROR, E_ADM_NOUV);
1014 			done (1);
1015 		}
1016 
1017 		/*
1018 		 * Can't quiet a new printer,
1019 		 * can't list the alerting for a new printer.
1020 		 */
1021 		if (
1022 			A
1023 		     && (STREQU(A, NAME_QUIET) || STREQU(A, NAME_LIST))
1024 		) {
1025 			LP_ERRMSG1 (ERROR, E_ADM_BADQUIETORLIST, p);
1026 			done (1);
1027 		}
1028 
1029 		/*
1030 		 * New printer - if no input types given, assume "simple".
1031 		 */
1032 		if (!I) {
1033 			I = getlist(NAME_SIMPLE, LP_WS, LP_SEP);
1034 			strcat (modifications, "I");
1035 		}
1036 	}
1037 }
1038 
1039 /*
1040 	Second phase of parsing for -S option.
1041 	In a seperate routine so we can call it from other
1042 	routines. This is used when any or all are used as
1043 	a print wheel name. main() loops over each print wheel,
1044 	and must call this function for each print wheel found.
1045 */
1046 void
chkopts3(called_from_chkopts)1047 chkopts3(called_from_chkopts)
1048 int	called_from_chkopts;
1049 {
1050 	/*
1051 		Only do the getpwheel() if we are not being called
1052 		from lpadmin.c. Otherwise we mess up our arena for
1053 		"all" processing.
1054 	*/
1055 	if (!called_from_chkopts)
1056 		oldS = pwheel_pointer;
1057 	else
1058 		oldS = getpwheel(*S);
1059 
1060 	if (!oldS) {
1061 		if (!syn_name(*S)) {
1062 			LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *S);
1063 			done (1);
1064 		}
1065 
1066 		/*
1067 		 * Can't quiet a new print wheel,
1068 		 * can't list the alerting for a new print wheel.
1069 		 */
1070 		if (
1071 			A
1072 		     && (STREQU(A, NAME_QUIET) || STREQU(A, NAME_LIST))
1073 		) {
1074 			LP_ERRMSG1 (ERROR, E_ADM_BADQUIETORLIST, *S);
1075 			done (1);
1076 		}
1077 	}
1078 }
1079 
1080 static void
chksys(s)1081 chksys(s)
1082 char	*s;
1083 {
1084 	char	*cp;
1085 
1086 	if (STREQU(s, NAME_ALL) || STREQU(s, NAME_ANY)) {
1087 		LP_ERRMSG (ERROR, E_ADM_ANYALLSYS);
1088 		done(1);
1089 	}
1090 
1091 	if ((cp = strchr(s, '!')) != NULL)
1092 		*cp = '\0';
1093 
1094 	if (cp)
1095 		*cp = '!';
1096 
1097 	return;
1098 }
1099 
1100 /**
1101  ** sum_chkprinter() - CHECK TERMINFO STUFF FOR A LIST OF PRINTER TYPES
1102  **/
1103 
1104 #include "lp.set.h"
1105 
1106 static unsigned long
1107 #if	defined(__STDC__)
sum_chkprinter(char ** types,char * cpi,char * lpi,char * len,char * wid,char * cs)1108 sum_chkprinter (
1109 	char **			types,
1110 	char *			cpi,
1111 	char *			lpi,
1112 	char *			len,
1113 	char *			wid,
1114 	char *			cs
1115 )
1116 #else
1117 sum_chkprinter (types, cpi, lpi, len, wid, cs)
1118 	char **			types;
1119 	char *			cpi;
1120 	char *			lpi;
1121 	char *			len;
1122 	char *			wid;
1123 	char *			cs;
1124 #endif
1125 {
1126 	char **			pt;
1127 
1128 	unsigned long		worst	= 0;
1129 	unsigned long		this	= 0;
1130 
1131 
1132 	/*
1133 	 * Check each printer type, to see if any won't work with
1134 	 * the attributes requested. However, return ``success''
1135 	 * if at least one type works. Keep a list of the failed
1136 	 * types for the caller to report.
1137 	 */
1138 	bad_list = 0;
1139 	for (pt = types; *pt; pt++) {
1140 		this = chkprinter(*pt, cpi, lpi, len, wid, cs);
1141 		if (this != 0)
1142 			addlist (&bad_list, *pt);
1143 		worst |= this;
1144 	}
1145 	if (lenlist(types) == lenlist(bad_list))
1146 		return (worst);
1147 	else
1148 		return (0);
1149 }
1150 
1151 /*
1152  * Function:    isPPD()
1153  *
1154  * Description: Check that the given PPD file exists. The argument given can
1155  *              either be a relative path or a full path to the file.
1156  *
1157  * Returns:     1 = PPD file found
1158  *              0 = PPD file not found
1159  */
1160 
1161 static int
isPPD(char * ppd_file)1162 isPPD(char *ppd_file)
1163 {
1164 	int result = 0;
1165 	char *ppd = NULL;
1166 
1167 	if (ppd_file != NULL) {
1168 		if (*ppd_file == '/') {
1169 			ppd = strdup(ppd_file);
1170 		} else {
1171 			ppd = makepath(Lp_Model, "ppd", ppd_file, (char *)0);
1172 		}
1173 
1174 		/*
1175 		 * now check the file exists
1176 		 */
1177 		if ((ppd != NULL) && (Access(ppd, 04) != -1)) {
1178 			result = 1;
1179 		} else {
1180 			/*
1181 			 * files does not exist so append .gz and check if
1182 			 * that exist
1183 			 */
1184 			ppd = Realloc(ppd, strlen(ppd)+ strlen(PPDZIP)+2);
1185 			if (ppd != NULL) {
1186 				ppd = strcat(ppd, PPDZIP);
1187 				if (Access(ppd, 04) != -1) {
1188 					result = 1;
1189 				}
1190 			}
1191 		}
1192 
1193 		if (ppd != NULL) {
1194 			free(ppd);
1195 		}
1196 	}
1197 	return (result);
1198 } /* isPPD() */
1199