Home | History | Annotate | Download | only in lpadmin
      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