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