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