xref: /illumos-gate/usr/src/cmd/lp/cmd/lpsched/validate.c (revision d0b12b66)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2016 by Delphix. All rights reserved.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /* SVr4.0 1.11.1.10	*/
32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
33 
34 #include "lpsched.h"
35 
36 #include "validate.h"
37 
38 #include <syslog.h>
39 #include <errno.h>
40 #include <deflt.h>
41 #include <tsol/label.h>
42 #include <auth_list.h>
43 
44 #define register auto
45 
46 
47 int		pickfilter ( RSTATUS * , CANDIDATE * , FSTATUS * );
48 
49 unsigned long		chkprinter_result	= 0;
50 char *			o_cpi		= 0;
51 char *			o_lpi		= 0;
52 char *			o_width		= 0;
53 char *			o_length	= 0;
54 
55 static int		wants_nobanner	= 0;
56 static int		wants_nolabels	= 0;
57 static int		lp_or_root	= 0;
58 
59 static int		_chkopts ( RSTATUS *, CANDIDATE * , FSTATUS * );
60 static void		free_candidate ( CANDIDATE * );
61 static int		tsol_check_printer_label_range(char *, const char *);
62 static int		tsol_lpauth(char *, char *);
63 static int		secpolicy_chkpolicy(char *policyp);
64 
65 /**
66  ** _validate() - FIND A PRINTER TO HANDLE A REQUEST
67  **/
68 
69 short
_validate(RSTATUS * prs,PSTATUS * pps,PSTATUS * stop_pps,char ** prefixp,int moving)70 _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp,
71 	 int moving)
72 {
73 	register CANDIDATE	*pc		= 0,
74 				*pcend,
75 				*best_pc	= 0;
76 
77 	register FSTATUS	*pfs		= 0;
78 
79 	register CLSTATUS	*pcs		= 0;
80 
81 	CANDIDATE		*arena		= 0,
82 				single;
83 
84 	size_t			n;
85 	int i;
86 
87 	short			ret;
88 
89 	chkprinter_result = 0;
90 	o_cpi = o_lpi = o_width = o_length = 0;
91 	wants_nobanner = 0;
92 	memset (&single, 0, sizeof(single));
93 
94 	wants_nolabels = 0;
95 	/*
96 	 * If the system is labeled, the printing of postscript files
97 	 * is restricted.  All users can print postscript files if the
98 	 * file /etc/default/print contains "PRINT_POSTSCRIPT=1".
99 	 * (this is checked by secpolicy_chkpolicy).  Otherwise the
100 	 * user must have PRINT_POSTSCRIPT_AUTH to print postscript files.
101 	 */
102 	if ((is_system_labeled() &&
103 	    strcmp(prs->request->input_type, "postscript") == 0) &&
104 	    (secpolicy_chkpolicy("PRINT_POSTSCRIPT=") == 0)) {
105 		if (tsol_lpauth(PRINT_POSTSCRIPT_AUTH, prs->secure->user)
106 		    == 0) {
107 			ret = MDENYDEST;
108 			goto Return;
109 		}
110 	}
111 	lp_or_root = 0;
112 
113 	if (bangequ(prs->secure->user, "root") ||
114 	    bangequ(prs->secure->user, "lp"))
115 			lp_or_root = 1;
116 
117 	if (prefixp)
118 		*prefixp = prs->request->destination;
119 
120 	/*
121 	 * If a destination other than "any" was given,
122 	 * see if it exists in our internal tables.
123 	 */
124 	if (!pps && prs->request->destination &&
125 	    !STREQU(prs->request->destination, NAME_ANY))
126 		if (((pps = search_pstatus(prs->request->destination)) != NULL) ||
127 		    ((pcs = search_cstatus(prs->request->destination)) != NULL) &&
128 		    pcs->class->members)
129 			/*EMPTY*/;
130 		else {
131 			ret = MNODEST;
132 			goto Return;
133 		}
134 
135 	/*
136 	 * If we are trying to avoid a printer, but the request
137 	 * was destined for just that printer, we're out.
138 	 */
139 	if (pps && pps == stop_pps) {
140 		ret = MERRDEST;
141 		goto Return;
142 	}
143 
144 	/*
145 	 * If a form was given, see if it exists; if so,
146 	 * see if the user is allowed to use it.
147 	 * If a remote printer was specified, then don't use any local
148 	 * form knowledge.
149 	 */
150 	if (prs && prs->request && prs->request->form && (pps || pcs)) {
151 		if ((pfs = search_fstatus(prs->request->form))) {
152 			if (lp_or_root || allowed(prs->secure->user,
153 				pfs->users_allowed, pfs->users_denied))
154 				/*EMPTY*/;
155 			else {
156 				ret = MDENYMEDIA;
157 				goto Return;
158 			}
159 		} else {
160 			ret = MNOMEDIA;
161 			goto Return;
162 		}
163 	}
164 
165 	/*
166 	 * If the request includes -o options there may be pitch and
167 	 * size and no-banner requests that have to be checked. One
168 	 * could argue that this shouldn't be in the Spooler, because
169 	 * the Spooler's job is SPOOLING, not PRINTING. That's right,
170 	 * except that the Spooler will be making a choice of printers
171 	 * so it has to evaluate carefully: E.g. user wants ANY printer,
172 	 * so we should pick one that can handle what they want.
173 	 *
174 	 * Parse out the important stuff here so we have it when we
175 	 * need it.
176 	 */
177 	{
178 		register char		**list,
179 					**pl;
180 
181 		if (
182 			prs->request->options
183 		     && (list = dashos(prs->request->options))
184 		) {
185 			for (pl = list ; *pl; pl++)
186 				if (STRNEQU(*pl, "cpi=", 4))
187 					o_cpi = Strdup(*pl + 4);
188 				else if (STRNEQU(*pl, "lpi=", 4))
189 					o_lpi = Strdup(*pl + 4);
190 				else if (STRNEQU(*pl, "width=", 6))
191 					o_width = Strdup(*pl + 6);
192 				else if (STRNEQU(*pl, "length=", 7))
193 					o_length = Strdup(*pl + 7);
194 				else if (STREQU(*pl, "nobanner"))
195 					wants_nobanner = 1;
196 				else if (STREQU(*pl, "nolabels"))
197 					wants_nolabels = 1;
198 			freelist (list);
199 		}
200 	}
201 
202 	/*
203 	 * This macro checks that a form has a mandatory print wheel
204 	 * (or character set).
205 	 */
206 #define	CHKMAND(PFS) \
207 	( \
208 		(PFS) \
209 	     && (PFS)->form->chset \
210 	     && !STREQU((PFS)->form->chset, NAME_ANY) \
211 	     && (PFS)->form->mandatory \
212 	)
213 
214 	/*
215 	 * This macro checks that the user is allowed to use the
216 	 * printer.
217 	 */
218 #define CHKU(PRS,PPS) \
219 	( \
220 		lp_or_root \
221 	     || allowed( \
222 			(PRS)->secure->user, \
223 			(PPS)->users_allowed, \
224 			(PPS)->users_denied \
225 		) \
226 	)
227 
228 	/*
229 	 * This macro checks that the form is allowed on the printer,
230 	 * or is already mounted there.
231 	 * Note: By doing this check we don't have to check that the
232 	 * characteristics of the form, such as pitch, size, or
233 	 * character set, against the printer's capabilities, ASSUMING,
234 	 * of course, that the allow list is correct. That is, the
235 	 * allow list lists forms that have already been checked against
236 	 * the printer!
237 	 */
238 #define CHKF(PFS,PPS) \
239 	( \
240 		isFormMountedOnPrinter(PPS,PFS) \
241 	     || allowed( \
242 			(PFS)->form->name, \
243 			(PPS)->forms_allowed, \
244 			(PPS)->forms_denied \
245 		) \
246 	)
247 
248 	/*
249 	 * This macro checks that the print wheel is acceptable
250 	 * for the printer or is mounted. Note: If the printer doesn't
251 	 * take print wheels, the check passes. The check for printers
252 	 * that don't take print wheels is below.
253 	 */
254 #define CHKPW(PW,PPS) \
255 	( \
256 		!(PPS)->printer->daisy \
257 	     || ( \
258 			(PPS)->pwheel_name \
259 		     && STREQU((PPS)->pwheel_name, (PW)) \
260 		) \
261 	     || searchlist((PW), (PPS)->printer->char_sets) \
262 	)
263 
264 	/*
265 	 * This macro checks the pitch, page size, and (if need be)
266 	 * the character set. The character set isn't checked if the
267 	 * printer takes print wheels, or if the character set is
268 	 * listed in the printer's alias list.
269 	 * The form has to be checked as well; while we're sure that
270 	 * at least one type for each printer can handle the form's
271 	 * cpi/lpi/etc. characteristics (lpadmin made sure), we aren't
272 	 * sure that ALL the types work.
273 	 */
274 #define CHKOPTS(PRS,PC,PFS) _chkopts((PRS),(PC),(PFS)) /* was a macro */
275 
276 	/*
277 	 * This macro checks the acceptance status of a printer.
278 	 * If the request is already assigned to that printer,
279 	 * then it's okay. It's ambiguous what should happen if
280 	 * originally a "-d any" request was accepted, temporarily
281 	 * assigned one printer, then the administrator (1) rejected
282 	 * further requests for the printers and (2) made the
283 	 * temporarily assigned printer unusable for the request.
284 	 * What will happen, of course, is that the request will
285 	 * be canceled, even though the other printers would be okay
286 	 * if not rejecting....but if we were to say, gee it's okay,
287 	 * the request has already been accepted, we may be allowing
288 	 * it on printers that were NEVER accepting. Thus we can
289 	 * continue to accept it only for the printer already assigned.
290 	 */
291 #define CHKACCEPT(PRS,PPS) \
292 	( \
293 		!((PPS)->status & PS_REJECTED) \
294 	     || (PRS)->printer == (PPS) \
295 	     || moving \
296 	)
297 
298 	/*
299 	 * If a print wheel or character set is given, see if it
300 	 * is allowed on the form.
301 	 */
302 	if (prs->request->charset)
303 		if (
304 			!CHKMAND(pfs)
305 		     || STREQU(prs->request->charset, pfs->form->chset)
306 		)
307 			/*EMPTY*/;
308 		else {
309 			ret = MDENYMEDIA;
310 			chkprinter_result |= PCK_CHARSET;
311 			goto Return;
312 		}
313 
314 	/*
315 	 * If a single printer was named, check the request against it.
316 	 * Do the accept/reject check late so that we give the most
317 	 * useful information to the user.
318 	 */
319 	if (pps) {
320 		(pc = &single)->pps = pps;
321 
322 		/* Does the printer allow the user? */
323 		if (!CHKU(prs, pps)) {
324 			ret = MDENYDEST;
325 			goto Return;
326 		}
327 
328 		/* Check printer label range */
329 		if (is_system_labeled() && prs->secure->slabel != NULL) {
330 			if (tsol_check_printer_label_range(
331 			    prs->secure->slabel,
332 			    pps->printer->name) == 0) {
333 				ret = MDENYDEST;
334 				goto Return;
335 			}
336 		}
337 
338 		/* Does the printer allow the form? */
339 		if (pfs && !CHKF(pfs, pps)) {
340 			ret = MNOMOUNT;
341 			goto Return;
342 		}
343 
344 		/* Does the printer allow the pwheel? */
345 		if (
346 			prs->request->charset
347 		     && !CHKPW(prs->request->charset, pps)
348 		) {
349 			ret = MNOMOUNT;
350 			goto Return;
351 		}
352 
353 		/* Can printer handle the pitch/size/charset/nobanner? */
354 		if (!CHKOPTS(prs, pc, pfs)) {
355 			ret = MDENYDEST;
356 			goto Return;
357 		}
358 
359 		/* Is the printer allowing requests? */
360 		if (!CHKACCEPT(prs, pps)) {
361 			ret = MERRDEST;
362 			goto Return;
363 		}
364 
365 		/* Is there a filter which will convert the input? */
366 		if (!pickfilter(prs, pc, pfs)) {
367 			ret = MNOFILTER;
368 			goto Return;
369 		}
370 
371 		best_pc = pc;
372 		ret = MOK;
373 		goto Return;
374 	}
375 
376 	/*
377 	 * Do the acceptance check on the class (if we have one)
378 	 * now so we can proceed with checks on individual printers
379 	 * in the class. Don't toss out the request if it is already
380 	 * assigned a printer just because the class is NOW rejecting.
381 	 */
382 	if (
383 		pcs
384 	     && (pcs->status & CS_REJECTED)
385 	     && !moving
386 	     && !prs->printer
387 	) {
388 		ret = MERRDEST;
389 		goto Return;
390 	}
391 
392 	/*
393 	 * Construct a list of printers based on the destination
394 	 * given. Cross off those that aren't accepting requests,
395 	 * that can't take the form, or which the user can't use.
396 	 * See if the list becomes empty.
397 	 */
398 
399 	if (pcs)
400 		n = lenlist(pcs->class->members);
401 	else {
402 		for (n = 0; PStatus != NULL && PStatus[n] != NULL; n++) ;
403 	}
404 	pcend = arena = (CANDIDATE *)Calloc(n, sizeof(CANDIDATE));
405 
406 	/*
407 	 * Start with a list of printers that are accepting requests.
408 	 * Don't skip a printer if it's rejecting but the request
409 	 * has already been accepted for it.
410 	 */
411 	if (pcs) {
412 		register char		 **pn;
413 
414 		for (pn = pcs->class->members; *pn; pn++)
415 			if (
416 				((pps = search_pstatus(*pn)) != NULL)
417 			     && pps != stop_pps
418 			)
419 				(pcend++)->pps = pps;
420 
421 
422 	} else
423 		for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
424 			pps = PStatus[i];
425 
426 			if (CHKACCEPT(prs, pps) && pps != stop_pps)
427 				(pcend++)->pps = pps;
428 		}
429 
430 	if (pcend == arena) {
431 		ret = MERRDEST;
432 		goto Return;
433 	}
434 
435 	/*
436 	 * Clean out printers that the user can't use. We piggy-back
437 	 * the pitch/size/banner checks here because the same error return
438 	 * is given (strange, eh?).
439 	 */
440 	{
441 		register CANDIDATE	*pcend2;
442 
443 		for (pcend2 = pc = arena; pc < pcend; pc++) {
444 			if (CHKU(prs, pc->pps) && CHKOPTS(prs, pc, pfs))
445 				*pcend2++ = *pc;
446 			else
447 				free_candidate (pc);
448 		}
449 
450 		if (pcend2 == arena) {
451 			ret = MDENYDEST;
452 			goto Return;
453 		}
454 		pcend = pcend2;
455 
456 	}
457 
458 	/*
459 	 * Clean out printers that can't mount the form,
460 	 * EXCEPT for printers that already have it mounted:
461 	 */
462 	if (pfs) {
463 		register CANDIDATE	*pcend2;
464 
465 		for (pcend2 = pc = arena; pc < pcend; pc++)
466 			if (CHKF(pfs, pc->pps))
467 				*pcend2++ = *pc;
468 			else
469 				free_candidate (pc);
470 
471 		if (pcend2 == arena) {
472 			ret = MNOMOUNT;
473 			goto Return;
474 		}
475 		pcend = pcend2;
476 
477 	}
478 
479 	/*
480 	 * Clean out printers that can't take the print wheel
481 	 * EXCEPT for printers that already have it mounted
482 	 * or printers for which it is a selectable character set:
483 	 */
484 	if (prs->request->charset) {
485 		register CANDIDATE	*pcend2;
486 
487 		for (pcend2 = pc = arena; pc < pcend; pc++)
488 			if (CHKPW(prs->request->charset, pc->pps))
489 				*pcend2++ = *pc;
490 			else
491 				free_candidate (pc);
492 
493 		if (pcend2 == arena) {
494 			ret = MNOMOUNT;
495 			goto Return;
496 		}
497 		pcend = pcend2;
498 
499 	}
500 
501 	/*
502 	 * Clean out printers that can't handle the printing
503 	 * and for which there's no filter to convert the input.
504 	 *
505 	 */
506 
507 	/*
508 	 * Is the form mounted, or is none needed?
509 	 */
510 #define CHKFMNT(PFS,PPS) (isFormUsableOnPrinter(PPS,PFS))
511 
512 	/*
513 	 * Is the print-wheel mounted, or is none needed?
514 	 */
515 #define CHKPWMNT(PRS,PPS) SAME((PPS)->pwheel_name, (PRS)->request->charset)
516 
517 	/*
518 	 * Do we NOT need a special character set, or can we select
519 	 * it on the printer? Note: Getting this far means that IF
520 	 * the printer has selectable character sets (!daisy) then
521 	 * it can select the one we want.
522 	 */
523 #define CHKCHSET(PRS,PPS) \
524 	( \
525 		!(PRS)->request->charset \
526 	     || !(PPS)->printer->daisy \
527 	)
528 
529 	/*
530 	 * Is the printer able to print now?
531 	 */
532 #define CHKENB(PPS)	 (!((PPS)->status & (PS_DISABLED|PS_FAULTED)))
533 
534 	/*
535 	 * Is the printer not busy printing another request, or
536 	 * not awaiting an auto-retry after a fault?
537 	 */
538 #define CHKFREE(PPS)	 (!((PPS)->status & (PS_BUSY|PS_LATER)))
539 
540 	{
541 		register CANDIDATE	*pcend2;
542 
543 		for (pcend2 = pc = arena; pc < pcend; pc++)
544 			if (pickfilter(prs, pc, pfs)) {
545 
546 				/*
547 				 * Compute a ``weight'' for this printer,
548 				 * based on its status. We'll later pick
549 				 * the printer with the highest weight.
550 				 */
551 				pc->weight = 0;
552 				if (!pc->fast && !pc->slow)
553 					pc->weight += WEIGHT_NOFILTER;
554 				if (CHKFREE(pc->pps))
555 					pc->weight += WEIGHT_FREE;
556 				if (CHKENB(pc->pps))
557 					pc->weight += WEIGHT_ENABLED;
558 				if (CHKFMNT(pfs, pc->pps))
559 					pc->weight += WEIGHT_MOUNTED;
560 				if (CHKPWMNT(prs, pc->pps))
561 					pc->weight += WEIGHT_MOUNTED;
562 				if (CHKCHSET(prs, pc->pps))
563 					pc->weight += WEIGHT_SELECTS;
564 
565 #if	defined(FILTER_EARLY_OUT)
566 				if (pc->weight == WEIGHT_MAX) {
567 					/*
568 					 * This is the one!
569 					 */
570 					best_pc = pc;
571 					ret = MOK;
572 					goto Return;
573 				}
574 #endif
575 				/*
576 				 * This is a candidate!
577 				 */
578 				*pcend2++ = *pc;
579 
580 			} else
581 				/*
582 				 * No filter for this one!
583 				 */
584 				free_candidate (pc);
585 
586 		if (pcend2 == arena) {
587 			ret = MNOFILTER;
588 			goto Return;
589 		}
590 		pcend = pcend2;
591 
592 	}
593 
594 	if (pcend - arena == 1) {
595 		best_pc = arena;
596 		ret = MOK;
597 		goto Return;
598 	}
599 	/*
600 	 * Clean out local printers
601 	 * where the request is outside the printer label range.
602 	 */
603 	{
604 		register CANDIDATE	*pcend2 = pcend;
605 
606 		if (is_system_labeled()) {
607 			for (pcend2 = pc = arena; pc < pcend; pc++) {
608 				if (tsol_check_printer_label_range(
609 				    prs->secure->slabel,
610 				    pps->printer->name) == 1)
611 					*pcend2++ = *pc;
612 				else
613 					free_candidate(pc);
614 			}
615 		}
616 
617 		if (pcend2 == arena) {
618 			ret = MDENYDEST;
619 			goto Return;
620 		}
621 		pcend = pcend2;
622 	}
623 
624 #if	defined(OTHER_FACTORS)
625 	/*
626 	 * Here you might want to add code that considers
627 	 * other factors: the size of the file(s) to be
628 	 * printed ("prs->secure->size") in relation to the
629 	 * printer (e.g. printer A gets mostly large
630 	 * files, printer B gets mostly small files); the
631 	 * number/total-size of requests currently queued
632 	 * for the printer; etc.
633 	 *
634 	 * If your code includes eliminating printers drop them
635 	 * from the list (as done in several places above).
636 	 * Otherwise, your code should add weights to the weight
637 	 * already computed. Change the WEIGHT_MAX, increase the
638 	 * other WEIGHT_X values to compensate, etc., as appropriate.
639 	 */
640 	;
641 #endif
642 
643 	/*
644 	 * Pick the best printer from a list of eligible candidates.
645 	 */
646 	best_pc = arena;
647 	for (pc = arena + 1; pc < pcend; pc++)
648 		if (pc->weight > best_pc->weight)
649 			best_pc = pc;
650 	ret = MOK;
651 
652 	/*
653 	 * Branch to here if MOK and/or if things have been allocated.
654 	 */
655 Return:	if (ret == MOK) {
656 		register USER		*pu = Getuser(prs->secure->user);
657 
658 		register char		*pwheel_name;
659 
660 		PSTATUS			*oldpps = prs->printer;
661 
662 
663 		/*
664 		 * We are going to accept this print request, having
665 		 * found a printer for it. This printer will be assigned
666 		 * to the request, although this assignment may be
667 		 * temporary if other printers qualify and this printer
668 		 * is changed to no longer qualify. Qualification in
669 		 * this context includes being ready to print!
670 		 */
671 		prs->printer = best_pc->pps;
672 		load_str (&(prs->printer_type), best_pc->printer_type);
673 
674 		/*
675 		 * Assign the form (if any) to the request. Adjust
676 		 * the number of requests queued for old and new form
677 		 * accordingly.
678 		 */
679 		if (prs->form != pfs) {
680 			unqueue_form (prs);
681 			queue_form (prs, pfs);
682 		}
683 
684 		/*
685 		 * Ditto for the print wheel, except include here the
686 		 * print wheel needed by the form.
687 		 * CAUTION: When checking this request later, don't
688 		 * refuse to service it if the print wheel for the
689 		 * form isn't mounted but the form is; a mounted form
690 		 * overrides its other needs. Don't be confused by the
691 		 * name of the bit, RSS_PWMAND; a printer that prints
692 		 * this request MUST have the print wheel mounted
693 		 * (if it takes print wheels) if the user asked for
694 		 * a particular print wheel.
695 		 */
696 		prs->status &= ~RSS_PWMAND;
697 		if (CHKMAND(pfs))
698 			pwheel_name = pfs->form->chset;
699 		else
700 			if ((pwheel_name = prs->request->charset) != NULL)
701 				prs->status |= RSS_PWMAND;
702 
703 		if (!SAME(pwheel_name, prs->pwheel_name)) {
704 			unqueue_pwheel (prs);
705 			queue_pwheel (prs, pwheel_name);
706 		}
707 
708 		/*
709 		 * Adjust the priority to lie within the limits allowed
710 		 * for the user (this is a silent adjustment as required).
711 		 * CURRENTLY, ONLY NEW REQUESTS WILL GET QUEUED ACCORDING
712 		 * TO THIS PRIORITY. EXISTING REQUESTS BEING (RE)EVALUATED
713 		 * WILL NOT BE REQUEUED.
714 		 * A wild priority is changed to the default, or the
715 		 * limit, whichever is the lower priority (higher value).
716 		 */
717 		if (prs->request->priority < 0 || 39 < prs->request->priority)
718 			prs->request->priority = getdfltpri();
719 		if (pu && prs->request->priority < pu->priority_limit)
720 			prs->request->priority = pu->priority_limit;
721 
722 		/*
723 		 * If a filter is involved, change the number of
724 		 * copies to 1 (if the filter handles it).
725 		 */
726 		if (
727 			(best_pc->fast || best_pc->slow)
728 		     && (best_pc->flags & FPARM_COPIES)
729 		     && prs->request->copies > 1
730 		)
731 			prs->copies = 1;
732 		else
733 			/*
734 			 * We use two ".copies" because we don't
735 			 * want to lose track of the number requested,
736 			 * but do want to mark the number the interface
737 			 * program is to handle. Here is the best
738 			 * place to know this.
739 			 */
740 			prs->copies = prs->request->copies;
741 
742 		if (best_pc->slow) {
743 			/*
744 			 * If the filter has changed, the request will
745 			 * have to be refiltered. This may mean stopping
746 			 * a currently running filter or interface.
747 			 */
748 			if (!SAME(best_pc->slow, prs->slow)) {
749 
750 			    if (prs->request->outcome & RS_FILTERED)
751 				prs->request->outcome &= ~RS_FILTERED;
752 
753 			    if (
754 				prs->request->outcome & RS_FILTERING
755 			     && !(prs->request->outcome & RS_STOPPED)
756 			    ) {
757 				prs->request->outcome |= RS_REFILTER;
758 				prs->request->outcome |= RS_STOPPED;
759 				terminate (prs->exec);
760 
761 			    } else if (
762 				prs->request->outcome & RS_PRINTING
763 			     && !(prs->request->outcome & RS_STOPPED)
764 			    ) {
765 				prs->request->outcome |= RS_STOPPED;
766 				terminate (oldpps->exec);
767 			    }
768 
769 			}
770 
771 			load_str (&(prs->slow), best_pc->slow);
772 			/* Assumption: if there is a slow filter,
773 			 * there is an output_type
774 			 */
775 
776 			load_str (&(prs->output_type), best_pc->output_type);
777 		} else
778 			unload_str (&(prs->slow));
779 
780 		load_str (&(prs->fast), best_pc->fast);
781 
782 		if (prs->request->actions & ACT_FAST && prs->slow) {
783 			if (prs->fast) {
784 				prs->fast = makestr(
785 					prs->slow,
786 					"|",
787 					prs->fast,
788 					(char *)0
789 				);
790 				Free (prs->slow);
791 			} else
792 				prs->fast = prs->slow;
793 			prs->slow = 0;
794 		}
795 
796 	}
797 
798 
799 	/*
800 	 * Free the space allocated for the candidates, INCLUDING
801 	 * the one chosen. Any allocated space in the chosen candidate
802 	 * that has to be saved should have been COPIED already.
803 	 */
804 	if (arena) {
805 		for (pc = arena; pc < pcend; pc++)
806 			free_candidate (pc);
807 		Free ((char *)arena);
808 	} else if (best_pc)
809 		free_candidate (best_pc);
810 
811 	if (o_length)
812 		Free (o_length);
813 	if (o_width)
814 		Free (o_width);
815 	if (o_lpi)
816 		Free (o_lpi);
817 	if (o_cpi)
818 		Free (o_cpi);
819 
820 
821 	/*
822 	 * The following value is valid ONLY IF the request
823 	 * is canceled or rejected. Not all requests that
824 	 * we fail in this routine are tossed out!
825 	 */
826 	prs->reason = ret;
827 
828 
829 	return (ret);
830 }
831 
832 /**
833  ** _chkopts() - CHECK -o OPTIONS
834  **/
835 
836 static int
_chkopts(RSTATUS * prs,CANDIDATE * pc,FSTATUS * pfs)837 _chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
838 {
839 	unsigned long		ret	= 0;
840 	unsigned long		chk	= 0;
841 
842 	char *			charset;
843 	char *			cpi	= 0;
844 	char *			lpi	= 0;
845 	char *			width	= 0;
846 	char *			length	= 0;
847 	char *			paper = NULL;
848 
849 	char **			pt;
850 	int			nobanner_not_allowed = 0;
851 
852 
853 	/*
854 	 * If we have a form, it overrides whatever print characteristics
855 	 * the user gave.
856 	 */
857 	if (pfs) {
858 		cpi = pfs->cpi;
859 		lpi = pfs->lpi;
860 		width = pfs->pwid;
861 		length = pfs->plen;
862 		paper = pfs->form->paper;
863 	} else {
864 		cpi = o_cpi;
865 		lpi = o_lpi;
866 		width = o_width;
867 		length = o_length;
868 	}
869 
870 	/*
871 	 * If the printer takes print wheels, or the character set
872 	 * the user wants is listed in the character set map for this
873 	 * printer, we needn't check if the printer can handle the
874 	 * character set. (Note: The check for the print wheel case
875 	 * is done elsewhere.)
876 	 */
877 
878 	if (pc->pps->printer->daisy ||
879 	    search_cslist(prs->request->charset, pc->pps->printer->char_sets))
880 		charset = 0;
881 	else
882 		charset = prs->request->charset;
883 
884 	pc->printer_types = 0;
885 	for (pt = pc->pps->printer->printer_types; *pt; pt++) {
886 		unsigned long		this;
887 
888 		if (paper) {
889 			if (allowed(paper,pc->pps->paper_allowed,NULL)) {
890 				addlist (&(pc->printer_types), *pt);
891 			} else {
892 				ret |= PCK_PAPER;
893 			}
894 		} else {
895 			this = chkprinter(*pt, cpi, lpi, length, width,
896 				charset);
897 			if (this == 0)
898 				addlist(&(pc->printer_types), *pt);
899 			chk |= this;
900 		}
901 	}
902 	if (!pc->printer_types)
903 		ret |= chk;
904 
905 	/*
906 	 * If the system is labeled, then user who wants 'nolabels' must
907 	 * have PRINT_UNLABELED_AUTH authorizations to allow it.
908 	 */
909 	if (is_system_labeled() && (wants_nolabels == 1)) {
910 		if (!tsol_lpauth(PRINT_UNLABELED_AUTH, prs->secure->user)) {
911 			/* if not authorized, remove "nolabels" from options */
912 			register char		**list;
913 			if (prs->request->options &&
914 			    (list = dashos(prs->request->options))) {
915 				dellist(&list, "nolabels");
916 				free(prs->request->options);
917 				prs->request->options = sprintlist(list);
918 			}
919 		}
920 	}
921 
922 
923 	if (pc->pps->printer->banner == BAN_ALWAYS) {
924 		/* delete "nobanner" */
925 		char **list;
926 
927 		/*
928 		 * If the system is labeled, users must have
929 		 * PRINT_NOBANNER_AUTH authorization to print
930 		 * without a banner.
931 		 */
932 		if (is_system_labeled()) {
933 			if (wants_nobanner == 1) {
934 				if (tsol_lpauth(PRINT_NOBANNER_AUTH,
935 					prs->secure->user) == 0) {
936 					nobanner_not_allowed = 1;
937 				}
938 			}
939 
940 		}
941 		else if ((wants_nobanner == 1) && (lp_or_root != 1)) {
942 			nobanner_not_allowed = 1;
943 		}
944 		if (nobanner_not_allowed == 1) {
945 			/* Take out 'nobanner' from request options. */
946 			if (prs->request->options &&
947 			    (list = dashos(prs->request->options))) {
948 				dellist(&list, "nobanner");
949 				free(prs->request->options);
950 				prs->request->options = sprintlist(list);
951 			}
952 		}
953 	} else if (pc->pps->printer->banner == BAN_NEVER) {
954 		if (wants_nobanner == 0) {
955 			/* add "nobanner" */
956 			char **list = NULL;
957 
958 			if (prs->request->options) {
959 				list = dashos(prs->request->options);
960 				free(prs->request->options);
961 			}
962 			appendlist(&list, "nobanner");
963 			prs->request->options = sprintlist(list);
964 		}
965 	} else /* if (pc->pps->printer->banner == BAN_OPTIONAL) */ {
966 		/* it is optional, leave it alone */
967 	}
968 
969 	chkprinter_result |= ret;
970 	return (ret == 0);
971 }
972 
973 /**
974  ** free_candidate()
975  **/
976 
977 static void
free_candidate(CANDIDATE * pc)978 free_candidate(CANDIDATE *pc)
979 {
980 	if (pc->slow)
981 		unload_str (&(pc->slow));
982 	if (pc->fast)
983 		unload_str (&(pc->fast));
984 	if (pc->printer_types) {
985 		freelist (pc->printer_types);
986 		pc->printer_types = 0;
987 	}
988 	if (pc->printer_type)
989 		unload_str (&(pc->printer_type));
990 	if (pc->output_type)
991 		unload_str (&(pc->output_type));
992 	return;
993 }
994 
995 static int
tsol_check_printer_label_range(char * slabel,const char * printer)996 tsol_check_printer_label_range(char *slabel, const char *printer)
997 {
998 	int			in_range = 0;
999 	int			err = 0;
1000 	m_range_t		*range;
1001 	m_label_t	*sl = NULL;
1002 
1003 	if (slabel == NULL)
1004 		return (0);
1005 
1006 	if ((err =
1007 	    (str_to_label(slabel, &sl, USER_CLEAR, L_NO_CORRECTION, &in_range)))
1008 	    == -1) {
1009 		/* stobsl error on printer max label */
1010 		return (0);
1011 	}
1012 	if ((range = getdevicerange(printer)) == NULL) {
1013 		m_label_free(sl);
1014 		return (0);
1015 	}
1016 
1017 	/* blinrange returns true (1) if in range, false (0) if not */
1018 	in_range = blinrange(sl, range);
1019 
1020 	m_label_free(sl);
1021 	m_label_free(range->lower_bound);
1022 	m_label_free(range->upper_bound);
1023 	free(range);
1024 
1025 	return (in_range);
1026 }
1027 
1028 /*
1029  * Given a character string with a "username" or "system!username"
1030  * this function returns a pointer to "username"
1031  */
1032 static int
tsol_lpauth(char * auth,char * in_name)1033 tsol_lpauth(char *auth, char *in_name)
1034 {
1035 	char *cp;
1036 	int res;
1037 
1038 	if ((cp = strchr(in_name, '@')) != NULL) {
1039 		/* user@system */
1040 		*cp = '\0';
1041 		res = chkauthattr(auth, in_name);
1042 		*cp = '@';
1043 	} else if ((cp = strchr(in_name, '!')) != NULL)
1044 		/* system!user */
1045 		res = chkauthattr(auth, cp+1);
1046 	else
1047 		/* user */
1048 		res = chkauthattr(auth, in_name);
1049 
1050 	return (res);
1051 }
1052 
1053 #define	POLICY_FILE	"/etc/default/print"
1054 
1055 int
secpolicy_chkpolicy(char * policyp)1056 secpolicy_chkpolicy(char *policyp)
1057 {
1058 	char *option;
1059 	int opt_val;
1060 
1061 	if (policyp == NULL)
1062 		return (0);
1063 	opt_val = 0;
1064 	if (defopen(POLICY_FILE) == 0) {
1065 
1066 		defcntl(DC_SETFLAGS, DC_STD & ~DC_CASE); /* ignore case */
1067 
1068 		if ((option = defread(policyp)) != NULL)
1069 			opt_val = atoi(option);
1070 	}
1071 	(void) defopen((char *)NULL);
1072 	syslog(LOG_DEBUG, "--- Policy %s, opt_val==%d",
1073 	    policyp ? policyp : "NULL", opt_val);
1074 	return (opt_val);
1075 }
1076