17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
545916cdjpk * Common Development and Distribution License (the "License").
645916cdjpk * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
221333d64keerthi * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
2448bbca8Daniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate
3145916cdjpk/* SVr4.0 1.11.1.10	*/
327c478bdstevel@tonic-gate/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate#include "lpsched.h"
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gate#include "validate.h"
377c478bdstevel@tonic-gate
3845916cdjpk#include <syslog.h>
3945916cdjpk#include <errno.h>
4045916cdjpk#include <deflt.h>
4145916cdjpk#include <tsol/label.h>
4245916cdjpk#include <auth_list.h>
4345916cdjpk
447c478bdstevel@tonic-gate#define register auto
457c478bdstevel@tonic-gate
4645916cdjpk
477c478bdstevel@tonic-gateint		pickfilter ( RSTATUS * , CANDIDATE * , FSTATUS * );
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gateunsigned long		chkprinter_result	= 0;
507c478bdstevel@tonic-gatechar *			o_cpi		= 0;
517c478bdstevel@tonic-gatechar *			o_lpi		= 0;
527c478bdstevel@tonic-gatechar *			o_width		= 0;
537c478bdstevel@tonic-gatechar *			o_length	= 0;
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gatestatic int		wants_nobanner	= 0;
5645916cdjpkstatic int		wants_nolabels	= 0;
577c478bdstevel@tonic-gatestatic int		lp_or_root	= 0;
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gatestatic int		_chkopts ( RSTATUS *, CANDIDATE * , FSTATUS * );
607c478bdstevel@tonic-gatestatic void		free_candidate ( CANDIDATE * );
6145916cdjpkstatic int		tsol_check_printer_label_range(char *, const char *);
6245916cdjpkstatic int		tsol_lpauth(char *, char *);
6345916cdjpkstatic int		secpolicy_chkpolicy(char *policyp);
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate/**
667c478bdstevel@tonic-gate ** _validate() - FIND A PRINTER TO HANDLE A REQUEST
677c478bdstevel@tonic-gate **/
687c478bdstevel@tonic-gate
697c478bdstevel@tonic-gateshort
707c478bdstevel@tonic-gate_validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp,
717c478bdstevel@tonic-gate	 int moving)
727c478bdstevel@tonic-gate{
737c478bdstevel@tonic-gate	register CANDIDATE	*pc		= 0,
747c478bdstevel@tonic-gate				*pcend,
757c478bdstevel@tonic-gate				*best_pc	= 0;
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate	register FSTATUS	*pfs		= 0;
787c478bdstevel@tonic-gate
7919d32b9Robert Mustacchi	register CLSTATUS	*pcs		= 0;
807c478bdstevel@tonic-gate
817c478bdstevel@tonic-gate	CANDIDATE		*arena		= 0,
827c478bdstevel@tonic-gate				single;
837c478bdstevel@tonic-gate
847c478bdstevel@tonic-gate	size_t			n;
850a44ef6jacobs	int i;
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate	short			ret;
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate	chkprinter_result = 0;
907c478bdstevel@tonic-gate	o_cpi = o_lpi = o_width = o_length = 0;
917c478bdstevel@tonic-gate	wants_nobanner = 0;
927c478bdstevel@tonic-gate	memset (&single, 0, sizeof(single));
937c478bdstevel@tonic-gate
9445916cdjpk	wants_nolabels = 0;
9545916cdjpk	/*
9645916cdjpk	 * If the system is labeled, the printing of postscript files
9745916cdjpk	 * is restricted.  All users can print postscript files if the
9845916cdjpk	 * file /etc/default/print contains "PRINT_POSTSCRIPT=1".
9945916cdjpk	 * (this is checked by secpolicy_chkpolicy).  Otherwise the
10045916cdjpk	 * user must have PRINT_POSTSCRIPT_AUTH to print postscript files.
10145916cdjpk	 */
10245916cdjpk	if ((is_system_labeled() &&
10345916cdjpk	    strcmp(prs->request->input_type, "postscript") == 0) &&
10445916cdjpk	    (secpolicy_chkpolicy("PRINT_POSTSCRIPT=") == 0)) {
10545916cdjpk		if (tsol_lpauth(PRINT_POSTSCRIPT_AUTH, prs->secure->user)
10645916cdjpk		    == 0) {
10745916cdjpk			ret = MDENYDEST;
10845916cdjpk			goto Return;
10945916cdjpk		}
11045916cdjpk	}
1117c478bdstevel@tonic-gate	lp_or_root = 0;
1127c478bdstevel@tonic-gate
1130a44ef6jacobs	if (bangequ(prs->secure->user, "root") ||
1140a44ef6jacobs	    bangequ(prs->secure->user, "lp"))
1157c478bdstevel@tonic-gate			lp_or_root = 1;
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gate	if (prefixp)
1187c478bdstevel@tonic-gate		*prefixp = prs->request->destination;
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gate	/*
1217c478bdstevel@tonic-gate	 * If a destination other than "any" was given,
1227c478bdstevel@tonic-gate	 * see if it exists in our internal tables.
1237c478bdstevel@tonic-gate	 */
1247c478bdstevel@tonic-gate	if (!pps && prs->request->destination &&
1257c478bdstevel@tonic-gate	    !STREQU(prs->request->destination, NAME_ANY))
1260a44ef6jacobs		if (((pps = search_pstatus(prs->request->destination)) != NULL) ||
1270a44ef6jacobs		    ((pcs = search_cstatus(prs->request->destination)) != NULL) &&
1287c478bdstevel@tonic-gate		    pcs->class->members)
1297c478bdstevel@tonic-gate			/*EMPTY*/;
1307c478bdstevel@tonic-gate		else {
1317c478bdstevel@tonic-gate			ret = MNODEST;
1327c478bdstevel@tonic-gate			goto Return;
1337c478bdstevel@tonic-gate		}
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gate	/*
1367c478bdstevel@tonic-gate	 * If we are trying to avoid a printer, but the request
1377c478bdstevel@tonic-gate	 * was destined for just that printer, we're out.
1387c478bdstevel@tonic-gate	 */
1397c478bdstevel@tonic-gate	if (pps && pps == stop_pps) {
1407c478bdstevel@tonic-gate		ret = MERRDEST;
1417c478bdstevel@tonic-gate		goto Return;
1427c478bdstevel@tonic-gate	}
1437c478bdstevel@tonic-gate
1447c478bdstevel@tonic-gate	/*
1457c478bdstevel@tonic-gate	 * If a form was given, see if it exists; if so,
1467c478bdstevel@tonic-gate	 * see if the user is allowed to use it.
1477c478bdstevel@tonic-gate	 * If a remote printer was specified, then don't use any local
1487c478bdstevel@tonic-gate	 * form knowledge.
1497c478bdstevel@tonic-gate	 */
1507c478bdstevel@tonic-gate	if (prs && prs->request && prs->request->form && (pps || pcs)) {
1510a44ef6jacobs		if ((pfs = search_fstatus(prs->request->form))) {
1527c478bdstevel@tonic-gate			if (lp_or_root || allowed(prs->secure->user,
1537c478bdstevel@tonic-gate				pfs->users_allowed, pfs->users_denied))
1547c478bdstevel@tonic-gate				/*EMPTY*/;
1557c478bdstevel@tonic-gate			else {
1567c478bdstevel@tonic-gate				ret = MDENYMEDIA;
1577c478bdstevel@tonic-gate				goto Return;
1587c478bdstevel@tonic-gate			}
1597c478bdstevel@tonic-gate		} else {
1607c478bdstevel@tonic-gate			ret = MNOMEDIA;
1617c478bdstevel@tonic-gate			goto Return;
1627c478bdstevel@tonic-gate		}
1637c478bdstevel@tonic-gate	}
1647c478bdstevel@tonic-gate
1657c478bdstevel@tonic-gate	/*
1667c478bdstevel@tonic-gate	 * If the request includes -o options there may be pitch and
1677c478bdstevel@tonic-gate	 * size and no-banner requests that have to be checked. One
1687c478bdstevel@tonic-gate	 * could argue that this shouldn't be in the Spooler, because
1697c478bdstevel@tonic-gate	 * the Spooler's job is SPOOLING, not PRINTING. That's right,
1707c478bdstevel@tonic-gate	 * except that the Spooler will be making a choice of printers
1717c478bdstevel@tonic-gate	 * so it has to evaluate carefully: E.g. user wants ANY printer,
17248bbca8Daniel Hoffman	 * so we should pick one that can handle what they want.
17348bbca8Daniel Hoffman	 *
1747c478bdstevel@tonic-gate	 * Parse out the important stuff here so we have it when we
17548bbca8Daniel Hoffman	 * need it.
1767c478bdstevel@tonic-gate	 */
1777c478bdstevel@tonic-gate	{
1787c478bdstevel@tonic-gate		register char		**list,
1797c478bdstevel@tonic-gate					**pl;
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gate		if (
1827c478bdstevel@tonic-gate			prs->request->options
1837c478bdstevel@tonic-gate		     && (list = dashos(prs->request->options))
1847c478bdstevel@tonic-gate		) {
1857c478bdstevel@tonic-gate			for (pl = list ; *pl; pl++)
1867c478bdstevel@tonic-gate				if (STRNEQU(*pl, "cpi=", 4))
1877c478bdstevel@tonic-gate					o_cpi = Strdup(*pl + 4);
1887c478bdstevel@tonic-gate				else if (STRNEQU(*pl, "lpi=", 4))
1897c478bdstevel@tonic-gate					o_lpi = Strdup(*pl + 4);
1907c478bdstevel@tonic-gate				else if (STRNEQU(*pl, "width=", 6))
1917c478bdstevel@tonic-gate					o_width = Strdup(*pl + 6);
1927c478bdstevel@tonic-gate				else if (STRNEQU(*pl, "length=", 7))
1937c478bdstevel@tonic-gate					o_length = Strdup(*pl + 7);
1947c478bdstevel@tonic-gate				else if (STREQU(*pl, "nobanner"))
1957c478bdstevel@tonic-gate					wants_nobanner = 1;
19645916cdjpk				else if (STREQU(*pl, "nolabels"))
19745916cdjpk					wants_nolabels = 1;
1987c478bdstevel@tonic-gate			freelist (list);
1997c478bdstevel@tonic-gate		}
2007c478bdstevel@tonic-gate	}
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate	/*
2037c478bdstevel@tonic-gate	 * This macro checks that a form has a mandatory print wheel
2047c478bdstevel@tonic-gate	 * (or character set).
2057c478bdstevel@tonic-gate	 */
2067c478bdstevel@tonic-gate#define	CHKMAND(PFS) \
2077c478bdstevel@tonic-gate	( \
2087c478bdstevel@tonic-gate		(PFS) \
2097c478bdstevel@tonic-gate	     && (PFS)->form->chset \
2107c478bdstevel@tonic-gate	     && !STREQU((PFS)->form->chset, NAME_ANY) \
2117c478bdstevel@tonic-gate	     && (PFS)->form->mandatory \
2127c478bdstevel@tonic-gate	)
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gate	/*
2157c478bdstevel@tonic-gate	 * This macro checks that the user is allowed to use the
2167c478bdstevel@tonic-gate	 * printer.
2177c478bdstevel@tonic-gate	 */
2187c478bdstevel@tonic-gate#define CHKU(PRS,PPS) \
2197c478bdstevel@tonic-gate	( \
2207c478bdstevel@tonic-gate		lp_or_root \
2217c478bdstevel@tonic-gate	     || allowed( \
2227c478bdstevel@tonic-gate			(PRS)->secure->user, \
2237c478bdstevel@tonic-gate			(PPS)->users_allowed, \
2247c478bdstevel@tonic-gate			(PPS)->users_denied \
2257c478bdstevel@tonic-gate		) \
2267c478bdstevel@tonic-gate	)
2277c478bdstevel@tonic-gate
2287c478bdstevel@tonic-gate	/*
2297c478bdstevel@tonic-gate	 * This macro checks that the form is allowed on the printer,
2307c478bdstevel@tonic-gate	 * or is already mounted there.
2317c478bdstevel@tonic-gate	 * Note: By doing this check we don't have to check that the
2327c478bdstevel@tonic-gate	 * characteristics of the form, such as pitch, size, or
2337c478bdstevel@tonic-gate	 * character set, against the printer's capabilities, ASSUMING,
2347c478bdstevel@tonic-gate	 * of course, that the allow list is correct. That is, the
2357c478bdstevel@tonic-gate	 * allow list lists forms that have already been checked against
2367c478bdstevel@tonic-gate	 * the printer!
2377c478bdstevel@tonic-gate	 */
2387c478bdstevel@tonic-gate#define CHKF(PFS,PPS) \
2397c478bdstevel@tonic-gate	( \
2407c478bdstevel@tonic-gate		isFormMountedOnPrinter(PPS,PFS) \
2417c478bdstevel@tonic-gate	     || allowed( \
2427c478bdstevel@tonic-gate			(PFS)->form->name, \
2437c478bdstevel@tonic-gate			(PPS)->forms_allowed, \
2447c478bdstevel@tonic-gate			(PPS)->forms_denied \
2457c478bdstevel@tonic-gate		) \
2467c478bdstevel@tonic-gate	)
2477c478bdstevel@tonic-gate
2487c478bdstevel@tonic-gate	/*
2497c478bdstevel@tonic-gate	 * This macro checks that the print wheel is acceptable
2507c478bdstevel@tonic-gate	 * for the printer or is mounted. Note: If the printer doesn't
2517c478bdstevel@tonic-gate	 * take print wheels, the check passes. The check for printers
2527c478bdstevel@tonic-gate	 * that don't take print wheels is below.
2537c478bdstevel@tonic-gate	 */
2547c478bdstevel@tonic-gate#define CHKPW(PW,PPS) \
2557c478bdstevel@tonic-gate	( \
2567c478bdstevel@tonic-gate		!(PPS)->printer->daisy \
2577c478bdstevel@tonic-gate	     || ( \
2587c478bdstevel@tonic-gate			(PPS)->pwheel_name \
2597c478bdstevel@tonic-gate		     && STREQU((PPS)->pwheel_name, (PW)) \
2607c478bdstevel@tonic-gate		) \
2617c478bdstevel@tonic-gate	     || searchlist((PW), (PPS)->printer->char_sets) \
2627c478bdstevel@tonic-gate	)
2637c478bdstevel@tonic-gate
2647c478bdstevel@tonic-gate	/*
2657c478bdstevel@tonic-gate	 * This macro checks the pitch, page size, and (if need be)
2667c478bdstevel@tonic-gate	 * the character set. The character set isn't checked if the
2677c478bdstevel@tonic-gate	 * printer takes print wheels, or if the character set is
2687c478bdstevel@tonic-gate	 * listed in the printer's alias list.
2697c478bdstevel@tonic-gate	 * The form has to be checked as well; while we're sure that
2707c478bdstevel@tonic-gate	 * at least one type for each printer can handle the form's
2717c478bdstevel@tonic-gate	 * cpi/lpi/etc. characteristics (lpadmin made sure), we aren't
2727c478bdstevel@tonic-gate	 * sure that ALL the types work.
2737c478bdstevel@tonic-gate	 */
2747c478bdstevel@tonic-gate#define CHKOPTS(PRS,PC,PFS) _chkopts((PRS),(PC),(PFS)) /* was a macro */
2757c478bdstevel@tonic-gate
2767c478bdstevel@tonic-gate	/*
2777c478bdstevel@tonic-gate	 * This macro checks the acceptance status of a printer.
2787c478bdstevel@tonic-gate	 * If the request is already assigned to that printer,
2797c478bdstevel@tonic-gate	 * then it's okay. It's ambiguous what should happen if
2807c478bdstevel@tonic-gate	 * originally a "-d any" request was accepted, temporarily
2817c478bdstevel@tonic-gate	 * assigned one printer, then the administrator (1) rejected
2827c478bdstevel@tonic-gate	 * further requests for the printers and (2) made the
2837c478bdstevel@tonic-gate	 * temporarily assigned printer unusable for the request.
2847c478bdstevel@tonic-gate	 * What will happen, of course, is that the request will
2857c478bdstevel@tonic-gate	 * be canceled, even though the other printers would be okay
2867c478bdstevel@tonic-gate	 * if not rejecting....but if we were to say, gee it's okay,
2877c478bdstevel@tonic-gate	 * the request has already been accepted, we may be allowing
2887c478bdstevel@tonic-gate	 * it on printers that were NEVER accepting. Thus we can
2897c478bdstevel@tonic-gate	 * continue to accept it only for the printer already assigned.
2907c478bdstevel@tonic-gate	 */
2917c478bdstevel@tonic-gate#define CHKACCEPT(PRS,PPS) \
2927c478bdstevel@tonic-gate	( \
2937c478bdstevel@tonic-gate		!((PPS)->status & PS_REJECTED) \
2947c478bdstevel@tonic-gate	     || (PRS)->printer == (PPS) \
2957c478bdstevel@tonic-gate	     || moving \
2967c478bdstevel@tonic-gate	)
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate	/*
2997c478bdstevel@tonic-gate	 * If a print wheel or character set is given, see if it
3007c478bdstevel@tonic-gate	 * is allowed on the form.
3017c478bdstevel@tonic-gate	 */
3027c478bdstevel@tonic-gate	if (prs->request->charset)
3037c478bdstevel@tonic-gate		if (
3047c478bdstevel@tonic-gate			!CHKMAND(pfs)
3057c478bdstevel@tonic-gate		     || STREQU(prs->request->charset, pfs->form->chset)
3067c478bdstevel@tonic-gate		)
3077c478bdstevel@tonic-gate			/*EMPTY*/;
3087c478bdstevel@tonic-gate		else {
3097c478bdstevel@tonic-gate			ret = MDENYMEDIA;
3107c478bdstevel@tonic-gate			chkprinter_result |= PCK_CHARSET;
3117c478bdstevel@tonic-gate			goto Return;
3127c478bdstevel@tonic-gate		}
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate	/*
3157c478bdstevel@tonic-gate	 * If a single printer was named, check the request against it.
3167c478bdstevel@tonic-gate	 * Do the accept/reject check late so that we give the most
3177c478bdstevel@tonic-gate	 * useful information to the user.
3187c478bdstevel@tonic-gate	 */
3197c478bdstevel@tonic-gate	if (pps) {
3207c478bdstevel@tonic-gate		(pc = &single)->pps = pps;
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate		/* Does the printer allow the user? */
3237c478bdstevel@tonic-gate		if (!CHKU(prs, pps)) {
3247c478bdstevel@tonic-gate			ret = MDENYDEST;
3257c478bdstevel@tonic-gate			goto Return;
3267c478bdstevel@tonic-gate		}
3277c478bdstevel@tonic-gate
32845916cdjpk		/* Check printer label range */
32945916cdjpk		if (is_system_labeled() && prs->secure->slabel != NULL) {
33045916cdjpk			if (tsol_check_printer_label_range(
33145916cdjpk			    prs->secure->slabel,
33245916cdjpk			    pps->printer->name) == 0) {
33345916cdjpk				ret = MDENYDEST;
33445916cdjpk				goto Return;
33545916cdjpk			}
33645916cdjpk		}
33745916cdjpk
3387c478bdstevel@tonic-gate		/* Does the printer allow the form? */
3397c478bdstevel@tonic-gate		if (pfs && !CHKF(pfs, pps)) {
3407c478bdstevel@tonic-gate			ret = MNOMOUNT;
3417c478bdstevel@tonic-gate			goto Return;
3427c478bdstevel@tonic-gate		}
3437c478bdstevel@tonic-gate
3447c478bdstevel@tonic-gate		/* Does the printer allow the pwheel? */
3457c478bdstevel@tonic-gate		if (
3467c478bdstevel@tonic-gate			prs->request->charset
3477c478bdstevel@tonic-gate		     && !CHKPW(prs->request->charset, pps)
3487c478bdstevel@tonic-gate		) {
3497c478bdstevel@tonic-gate			ret = MNOMOUNT;
3507c478bdstevel@tonic-gate			goto Return;
3517c478bdstevel@tonic-gate		}
3527c478bdstevel@tonic-gate
3537c478bdstevel@tonic-gate		/* Can printer handle the pitch/size/charset/nobanner? */
3547c478bdstevel@tonic-gate		if (!CHKOPTS(prs, pc, pfs)) {
3557c478bdstevel@tonic-gate			ret = MDENYDEST;
3567c478bdstevel@tonic-gate			goto Return;
3577c478bdstevel@tonic-gate		}
3587c478bdstevel@tonic-gate
3597c478bdstevel@tonic-gate		/* Is the printer allowing requests? */
3607c478bdstevel@tonic-gate		if (!CHKACCEPT(prs, pps)) {
3617c478bdstevel@tonic-gate			ret = MERRDEST;
3627c478bdstevel@tonic-gate			goto Return;
3637c478bdstevel@tonic-gate		}
3647c478bdstevel@tonic-gate
3657c478bdstevel@tonic-gate		/* Is there a filter which will convert the input? */
3667c478bdstevel@tonic-gate		if (!pickfilter(prs, pc, pfs)) {
3677c478bdstevel@tonic-gate			ret = MNOFILTER;
3687c478bdstevel@tonic-gate			goto Return;
3697c478bdstevel@tonic-gate		}
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gate		best_pc = pc;
3727c478bdstevel@tonic-gate		ret = MOK;
3737c478bdstevel@tonic-gate		goto Return;
3747c478bdstevel@tonic-gate	}
3757c478bdstevel@tonic-gate
3767c478bdstevel@tonic-gate	/*
3777c478bdstevel@tonic-gate	 * Do the acceptance check on the class (if we have one)
3787c478bdstevel@tonic-gate	 * now so we can proceed with checks on individual printers
3797c478bdstevel@tonic-gate	 * in the class. Don't toss out the request if it is already
3807c478bdstevel@tonic-gate	 * assigned a printer just because the class is NOW rejecting.
3817c478bdstevel@tonic-gate	 */
3827c478bdstevel@tonic-gate	if (
3837c478bdstevel@tonic-gate		pcs
3847c478bdstevel@tonic-gate	     && (pcs->status & CS_REJECTED)
3857c478bdstevel@tonic-gate	     && !moving
3867c478bdstevel@tonic-gate	     && !prs->printer
3877c478bdstevel@tonic-gate	) {
3887c478bdstevel@tonic-gate		ret = MERRDEST;
3897c478bdstevel@tonic-gate		goto Return;
3907c478bdstevel@tonic-gate	}
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gate	/*
3937c478bdstevel@tonic-gate	 * Construct a list of printers based on the destination
3947c478bdstevel@tonic-gate	 * given. Cross off those that aren't accepting requests,
3957c478bdstevel@tonic-gate	 * that can't take the form, or which the user can't use.
3967c478bdstevel@tonic-gate	 * See if the list becomes empty.
3977c478bdstevel@tonic-gate	 */
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gate	if (pcs)
4007c478bdstevel@tonic-gate		n = lenlist(pcs->class->members);
4017c478bdstevel@tonic-gate	else {
4020a44ef6jacobs		for (n = 0; PStatus != NULL && PStatus[n] != NULL; n++) ;
4037c478bdstevel@tonic-gate	}
4047c478bdstevel@tonic-gate	pcend = arena = (CANDIDATE *)Calloc(n, sizeof(CANDIDATE));
4057c478bdstevel@tonic-gate
4067c478bdstevel@tonic-gate	/*
4077c478bdstevel@tonic-gate	 * Start with a list of printers that are accepting requests.
4087c478bdstevel@tonic-gate	 * Don't skip a printer if it's rejecting but the request
4097c478bdstevel@tonic-gate	 * has already been accepted for it.
4107c478bdstevel@tonic-gate	 */
4117c478bdstevel@tonic-gate	if (pcs) {
4127c478bdstevel@tonic-gate		register char		 **pn;
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate		for (pn = pcs->class->members; *pn; pn++)
4157c478bdstevel@tonic-gate			if (
4160a44ef6jacobs				((pps = search_pstatus(*pn)) != NULL)
4177c478bdstevel@tonic-gate			     && pps != stop_pps
4187c478bdstevel@tonic-gate			)
4197c478bdstevel@tonic-gate				(pcend++)->pps = pps;
4207c478bdstevel@tonic-gate
4217c478bdstevel@tonic-gate
4227c478bdstevel@tonic-gate	} else
4230a44ef6jacobs		for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
4240a44ef6jacobs			pps = PStatus[i];
4250a44ef6jacobs
4267c478bdstevel@tonic-gate			if (CHKACCEPT(prs, pps) && pps != stop_pps)
4277c478bdstevel@tonic-gate				(pcend++)->pps = pps;
4280a44ef6jacobs		}
4297c478bdstevel@tonic-gate
4307c478bdstevel@tonic-gate	if (pcend == arena) {
4317c478bdstevel@tonic-gate		ret = MERRDEST;
4327c478bdstevel@tonic-gate		goto Return;
4337c478bdstevel@tonic-gate	}
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate	/*
4367c478bdstevel@tonic-gate	 * Clean out printers that the user can't use. We piggy-back
4377c478bdstevel@tonic-gate	 * the pitch/size/banner checks here because the same error return
4387c478bdstevel@tonic-gate	 * is given (strange, eh?).
4397c478bdstevel@tonic-gate	 */
4407c478bdstevel@tonic-gate	{
4417c478bdstevel@tonic-gate		register CANDIDATE	*pcend2;
4427c478bdstevel@tonic-gate
4437c478bdstevel@tonic-gate		for (pcend2 = pc = arena; pc < pcend; pc++) {
4447c478bdstevel@tonic-gate			if (CHKU(prs, pc->pps) && CHKOPTS(prs, pc, pfs))
4457c478bdstevel@tonic-gate				*pcend2++ = *pc;
4467c478bdstevel@tonic-gate			else
4477c478bdstevel@tonic-gate				free_candidate (pc);
4487c478bdstevel@tonic-gate		}
4497c478bdstevel@tonic-gate
4507c478bdstevel@tonic-gate		if (pcend2 == arena) {
4517c478bdstevel@tonic-gate			ret = MDENYDEST;
4527c478bdstevel@tonic-gate			goto Return;
4537c478bdstevel@tonic-gate		}
4547c478bdstevel@tonic-gate		pcend = pcend2;
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gate	}
4577c478bdstevel@tonic-gate
4587c478bdstevel@tonic-gate	/*
4597c478bdstevel@tonic-gate	 * Clean out printers that can't mount the form,
4607c478bdstevel@tonic-gate	 * EXCEPT for printers that already have it mounted:
4617c478bdstevel@tonic-gate	 */
4627c478bdstevel@tonic-gate	if (pfs) {
4637c478bdstevel@tonic-gate		register CANDIDATE	*pcend2;
4647c478bdstevel@tonic-gate
4657c478bdstevel@tonic-gate		for (pcend2 = pc = arena; pc < pcend; pc++)
4667c478bdstevel@tonic-gate			if (CHKF(pfs, pc->pps))
4677c478bdstevel@tonic-gate				*pcend2++ = *pc;
4687c478bdstevel@tonic-gate			else
4697c478bdstevel@tonic-gate				free_candidate (pc);
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate		if (pcend2 == arena) {
4727c478bdstevel@tonic-gate			ret = MNOMOUNT;
4737c478bdstevel@tonic-gate			goto Return;
4747c478bdstevel@tonic-gate		}
4757c478bdstevel@tonic-gate		pcend = pcend2;
4767c478bdstevel@tonic-gate
4777c478bdstevel@tonic-gate	}
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate	/*
4807c478bdstevel@tonic-gate	 * Clean out printers that can't take the print wheel
4817c478bdstevel@tonic-gate	 * EXCEPT for printers that already have it mounted
4827c478bdstevel@tonic-gate	 * or printers for which it is a selectable character set:
4837c478bdstevel@tonic-gate	 */
4847c478bdstevel@tonic-gate	if (prs->request->charset) {
4857c478bdstevel@tonic-gate		register CANDIDATE	*pcend2;
4867c478bdstevel@tonic-gate
4877c478bdstevel@tonic-gate		for (pcend2 = pc = arena; pc < pcend; pc++)
4887c478bdstevel@tonic-gate			if (CHKPW(prs->request->charset, pc->pps))
4897c478bdstevel@tonic-gate				*pcend2++ = *pc;
4907c478bdstevel@tonic-gate			else
4917c478bdstevel@tonic-gate				free_candidate (pc);
4927c478bdstevel@tonic-gate
4937c478bdstevel@tonic-gate		if (pcend2 == arena) {
4947c478bdstevel@tonic-gate			ret = MNOMOUNT;
4957c478bdstevel@tonic-gate			goto Return;
4967c478bdstevel@tonic-gate		}
4977c478bdstevel@tonic-gate		pcend = pcend2;
4987c478bdstevel@tonic-gate
4997c478bdstevel@tonic-gate	}
5007c478bdstevel@tonic-gate
5017c478bdstevel@tonic-gate	/*
5027c478bdstevel@tonic-gate	 * Clean out printers that can't handle the printing
5037c478bdstevel@tonic-gate	 * and for which there's no filter to convert the input.
5047c478bdstevel@tonic-gate	 *
5057c478bdstevel@tonic-gate	 */
5067c478bdstevel@tonic-gate
5077c478bdstevel@tonic-gate	/*
5087c478bdstevel@tonic-gate	 * Is the form mounted, or is none needed?
5097c478bdstevel@tonic-gate	 */
5107c478bdstevel@tonic-gate#define CHKFMNT(PFS,PPS) (isFormUsableOnPrinter(PPS,PFS))
5117c478bdstevel@tonic-gate
5127c478bdstevel@tonic-gate	/*
5137c478bdstevel@tonic-gate	 * Is the print-wheel mounted, or is none needed?
5147c478bdstevel@tonic-gate	 */
5157c478bdstevel@tonic-gate#define CHKPWMNT(PRS,PPS) SAME((PPS)->pwheel_name, (PRS)->request->charset)
5167c478bdstevel@tonic-gate
5177c478bdstevel@tonic-gate	/*
5187c478bdstevel@tonic-gate	 * Do we NOT need a special character set, or can we select
5197c478bdstevel@tonic-gate	 * it on the printer? Note: Getting this far means that IF
5207c478bdstevel@tonic-gate	 * the printer has selectable character sets (!daisy) then
5217c478bdstevel@tonic-gate	 * it can select the one we want.
5227c478bdstevel@tonic-gate	 */
5237c478bdstevel@tonic-gate#define CHKCHSET(PRS,PPS) \
5247c478bdstevel@tonic-gate	( \
5257c478bdstevel@tonic-gate		!(PRS)->request->charset \
5267c478bdstevel@tonic-gate	     || !(PPS)->printer->daisy \
5277c478bdstevel@tonic-gate	)
5287c478bdstevel@tonic-gate
5297c478bdstevel@tonic-gate	/*
5307c478bdstevel@tonic-gate	 * Is the printer able to print now?
5317c478bdstevel@tonic-gate	 */
5327c478bdstevel@tonic-gate#define CHKENB(PPS)	 (!((PPS)->status & (PS_DISABLED|PS_FAULTED)))
5337c478bdstevel@tonic-gate
5347c478bdstevel@tonic-gate	/*
5357c478bdstevel@tonic-gate	 * Is the printer not busy printing another request, or
5367c478bdstevel@tonic-gate	 * not awaiting an auto-retry after a fault?
5377c478bdstevel@tonic-gate	 */
5387c478bdstevel@tonic-gate#define CHKFREE(PPS)	 (!((PPS)->status & (PS_BUSY|PS_LATER)))
5397c478bdstevel@tonic-gate
5407c478bdstevel@tonic-gate	{
5417c478bdstevel@tonic-gate		register CANDIDATE	*pcend2;
5427c478bdstevel@tonic-gate
5437c478bdstevel@tonic-gate		for (pcend2 = pc = arena; pc < pcend; pc++)
5447c478bdstevel@tonic-gate			if (pickfilter(prs, pc, pfs)) {
5457c478bdstevel@tonic-gate
5467c478bdstevel@tonic-gate				/*
5477c478bdstevel@tonic-gate				 * Compute a ``weight'' for this printer,
5487c478bdstevel@tonic-gate				 * based on its status. We'll later pick
5497c478bdstevel@tonic-gate				 * the printer with the highest weight.
5507c478bdstevel@tonic-gate				 */
5517c478bdstevel@tonic-gate				pc->weight = 0;
5527c478bdstevel@tonic-gate				if (!pc->fast && !pc->slow)
5537c478bdstevel@tonic-gate					pc->weight += WEIGHT_NOFILTER;
5547c478bdstevel@tonic-gate				if (CHKFREE(pc->pps))
5557c478bdstevel@tonic-gate					pc->weight += WEIGHT_FREE;
5567c478bdstevel@tonic-gate				if (CHKENB(pc->pps))
5577c478bdstevel@tonic-gate					pc->weight += WEIGHT_ENABLED;
5587c478bdstevel@tonic-gate				if (CHKFMNT(pfs, pc->pps))
5597c478bdstevel@tonic-gate					pc->weight += WEIGHT_MOUNTED;
5607c478bdstevel@tonic-gate				if (CHKPWMNT(prs, pc->pps))
5617c478bdstevel@tonic-gate					pc->weight += WEIGHT_MOUNTED;
5627c478bdstevel@tonic-gate				if (CHKCHSET(prs, pc->pps))
5637c478bdstevel@tonic-gate					pc->weight += WEIGHT_SELECTS;
5647c478bdstevel@tonic-gate
5657c478bdstevel@tonic-gate#if	defined(FILTER_EARLY_OUT)
5667c478bdstevel@tonic-gate				if (pc->weight == WEIGHT_MAX) {
5677c478bdstevel@tonic-gate					/*
5687c478bdstevel@tonic-gate					 * This is the one!
5697c478bdstevel@tonic-gate					 */
5707c478bdstevel@tonic-gate					best_pc = pc;
5717c478bdstevel@tonic-gate					ret = MOK;
5727c478bdstevel@tonic-gate					goto Return;
5737c478bdstevel@tonic-gate				}
5747c478bdstevel@tonic-gate#endif
5757c478bdstevel@tonic-gate				/*
5767c478bdstevel@tonic-gate				 * This is a candidate!
5777c478bdstevel@tonic-gate				 */
5787c478bdstevel@tonic-gate				*pcend2++ = *pc;
5797c478bdstevel@tonic-gate
5807c478bdstevel@tonic-gate			} else
5817c478bdstevel@tonic-gate				/*
5827c478bdstevel@tonic-gate				 * No filter for this one!
5837c478bdstevel@tonic-gate				 */
5847c478bdstevel@tonic-gate				free_candidate (pc);
5857c478bdstevel@tonic-gate
5867c478bdstevel@tonic-gate		if (pcend2 == arena) {
5877c478bdstevel@tonic-gate			ret = MNOFILTER;
5887c478bdstevel@tonic-gate			goto Return;
5897c478bdstevel@tonic-gate		}
5907c478bdstevel@tonic-gate		pcend = pcend2;
5917c478bdstevel@tonic-gate
5927c478bdstevel@tonic-gate	}
5937c478bdstevel@tonic-gate
5947c478bdstevel@tonic-gate	if (pcend - arena == 1) {
5957c478bdstevel@tonic-gate		best_pc = arena;
5967c478bdstevel@tonic-gate		ret = MOK;
5977c478bdstevel@tonic-gate		goto Return;
5987c478bdstevel@tonic-gate	}
59945916cdjpk	/*
60045916cdjpk	 * Clean out local printers
60145916cdjpk	 * where the request is outside the printer label range.
60245916cdjpk	 */
60345916cdjpk	{
6041333d64keerthi		register CANDIDATE	*pcend2 = pcend;
60545916cdjpk
60645916cdjpk		if (is_system_labeled()) {
60745916cdjpk			for (pcend2 = pc = arena; pc < pcend; pc++) {
60845916cdjpk				if (tsol_check_printer_label_range(
60945916cdjpk				    prs->secure->slabel,
61045916cdjpk				    pps->printer->name) == 1)
61145916cdjpk					*pcend2++ = *pc;
61245916cdjpk				else
61345916cdjpk					free_candidate(pc);
61445916cdjpk			}
61545916cdjpk		}
61645916cdjpk
61745916cdjpk		if (pcend2 == arena) {
61845916cdjpk			ret = MDENYDEST;
61945916cdjpk			goto Return;
62045916cdjpk		}
62145916cdjpk		pcend = pcend2;
62245916cdjpk	}
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate#if	defined(OTHER_FACTORS)
6257c478bdstevel@tonic-gate	/*
6267c478bdstevel@tonic-gate	 * Here you might want to add code that considers
6277c478bdstevel@tonic-gate	 * other factors: the size of the file(s) to be
6287c478bdstevel@tonic-gate	 * printed ("prs->secure->size") in relation to the
6297c478bdstevel@tonic-gate	 * printer (e.g. printer A gets mostly large
6307c478bdstevel@tonic-gate	 * files, printer B gets mostly small files); the
6317c478bdstevel@tonic-gate	 * number/total-size of requests currently queued
6327c478bdstevel@tonic-gate	 * for the printer; etc.
6337c478bdstevel@tonic-gate	 *
6347c478bdstevel@tonic-gate	 * If your code includes eliminating printers drop them
6357c478bdstevel@tonic-gate	 * from the list (as done in several places above).
6367c478bdstevel@tonic-gate	 * Otherwise, your code should add weights to the weight
6377c478bdstevel@tonic-gate	 * already computed. Change the WEIGHT_MAX, increase the
6387c478bdstevel@tonic-gate	 * other WEIGHT_X values to compensate, etc., as appropriate.
6397c478bdstevel@tonic-gate	 */
6407c478bdstevel@tonic-gate	;
6417c478bdstevel@tonic-gate#endif
6427c478bdstevel@tonic-gate
6437c478bdstevel@tonic-gate	/*
6447c478bdstevel@tonic-gate	 * Pick the best printer from a list of eligible candidates.
6457c478bdstevel@tonic-gate	 */
6467c478bdstevel@tonic-gate	best_pc = arena;
6477c478bdstevel@tonic-gate	for (pc = arena + 1; pc < pcend; pc++)
6487c478bdstevel@tonic-gate		if (pc->weight > best_pc->weight)
6497c478bdstevel@tonic-gate			best_pc = pc;
6507c478bdstevel@tonic-gate	ret = MOK;
6517c478bdstevel@tonic-gate
6527c478bdstevel@tonic-gate	/*
6537c478bdstevel@tonic-gate	 * Branch to here if MOK and/or if things have been allocated.
6547c478bdstevel@tonic-gate	 */
6557c478bdstevel@tonic-gateReturn:	if (ret == MOK) {
6567c478bdstevel@tonic-gate		register USER		*pu = Getuser(prs->secure->user);
6577c478bdstevel@tonic-gate
6587c478bdstevel@tonic-gate		register char		*pwheel_name;
6597c478bdstevel@tonic-gate
6607c478bdstevel@tonic-gate		PSTATUS			*oldpps = prs->printer;
6617c478bdstevel@tonic-gate
6627c478bdstevel@tonic-gate
6637c478bdstevel@tonic-gate		/*
6647c478bdstevel@tonic-gate		 * We are going to accept this print request, having
6657c478bdstevel@tonic-gate		 * found a printer for it. This printer will be assigned
6667c478bdstevel@tonic-gate		 * to the request, although this assignment may be
6677c478bdstevel@tonic-gate		 * temporary if other printers qualify and this printer
6687c478bdstevel@tonic-gate		 * is changed to no longer qualify. Qualification in
6697c478bdstevel@tonic-gate		 * this context includes being ready to print!
6707c478bdstevel@tonic-gate		 */
6717c478bdstevel@tonic-gate		prs->printer = best_pc->pps;
6727c478bdstevel@tonic-gate		load_str (&(prs->printer_type), best_pc->printer_type);
6737c478bdstevel@tonic-gate
6747c478bdstevel@tonic-gate		/*
6757c478bdstevel@tonic-gate		 * Assign the form (if any) to the request. Adjust
6767c478bdstevel@tonic-gate		 * the number of requests queued for old and new form
6777c478bdstevel@tonic-gate		 * accordingly.
6787c478bdstevel@tonic-gate		 */
6797c478bdstevel@tonic-gate		if (prs->form != pfs) {
6807c478bdstevel@tonic-gate			unqueue_form (prs);
6817c478bdstevel@tonic-gate			queue_form (prs, pfs);
6827c478bdstevel@tonic-gate		}
6837c478bdstevel@tonic-gate
6847c478bdstevel@tonic-gate		/*
6857c478bdstevel@tonic-gate		 * Ditto for the print wheel, except include here the
6867c478bdstevel@tonic-gate		 * print wheel needed by the form.
6877c478bdstevel@tonic-gate		 * CAUTION: When checking this request later, don't
6887c478bdstevel@tonic-gate		 * refuse to service it if the print wheel for the
6897c478bdstevel@tonic-gate		 * form isn't mounted but the form is; a mounted form
6907c478bdstevel@tonic-gate		 * overrides its other needs. Don't be confused by the
6917c478bdstevel@tonic-gate		 * name of the bit, RSS_PWMAND; a printer that prints
6927c478bdstevel@tonic-gate		 * this request MUST have the print wheel mounted
6937c478bdstevel@tonic-gate		 * (if it takes print wheels) if the user asked for
6947c478bdstevel@tonic-gate		 * a particular print wheel.
6957c478bdstevel@tonic-gate		 */
6967c478bdstevel@tonic-gate		prs->status &= ~RSS_PWMAND;
6977c478bdstevel@tonic-gate		if (CHKMAND(pfs))
6987c478bdstevel@tonic-gate			pwheel_name = pfs->form->chset;
6997c478bdstevel@tonic-gate		else
7007c478bdstevel@tonic-gate			if ((pwheel_name = prs->request->charset) != NULL)
7017c478bdstevel@tonic-gate				prs->status |= RSS_PWMAND;
7027c478bdstevel@tonic-gate
7037c478bdstevel@tonic-gate		if (!SAME(pwheel_name, prs->pwheel_name)) {
7047c478bdstevel@tonic-gate			unqueue_pwheel (prs);
7057c478bdstevel@tonic-gate			queue_pwheel (prs, pwheel_name);
7067c478bdstevel@tonic-gate		}
7077c478bdstevel@tonic-gate
7087c478bdstevel@tonic-gate		/*
7097c478bdstevel@tonic-gate		 * Adjust the priority to lie within the limits allowed
7107c478bdstevel@tonic-gate		 * for the user (this is a silent adjustment as required).
7117c478bdstevel@tonic-gate		 * CURRENTLY, ONLY NEW REQUESTS WILL GET QUEUED ACCORDING
7127c478bdstevel@tonic-gate		 * TO THIS PRIORITY. EXISTING REQUESTS BEING (RE)EVALUATED
7137c478bdstevel@tonic-gate		 * WILL NOT BE REQUEUED.
7147c478bdstevel@tonic-gate		 * A wild priority is changed to the default, or the
7157c478bdstevel@tonic-gate		 * limit, whichever is the lower priority (higher value).
7167c478bdstevel@tonic-gate		 */
7177c478bdstevel@tonic-gate		if (prs->request->priority < 0 || 39 < prs->request->priority)
7187c478bdstevel@tonic-gate			prs->request->priority = getdfltpri();
7197c478bdstevel@tonic-gate		if (pu && prs->request->priority < pu->priority_limit)
7207c478bdstevel@tonic-gate			prs->request->priority = pu->priority_limit;
7217c478bdstevel@tonic-gate
7227c478bdstevel@tonic-gate		/*
7237c478bdstevel@tonic-gate		 * If a filter is involved, change the number of
7247c478bdstevel@tonic-gate		 * copies to 1 (if the filter handles it).
7257c478bdstevel@tonic-gate		 */
7267c478bdstevel@tonic-gate		if (
7277c478bdstevel@tonic-gate			(best_pc->fast || best_pc->slow)
7287c478bdstevel@tonic-gate		     && (best_pc->flags & FPARM_COPIES)
7297c478bdstevel@tonic-gate		     && prs->request->copies > 1
7307c478bdstevel@tonic-gate		)
7317c478bdstevel@tonic-gate			prs->copies = 1;
7327c478bdstevel@tonic-gate		else
7337c478bdstevel@tonic-gate			/*
7347c478bdstevel@tonic-gate			 * We use two ".copies" because we don't
7357c478bdstevel@tonic-gate			 * want to lose track of the number requested,
7367c478bdstevel@tonic-gate			 * but do want to mark the number the interface
7377c478bdstevel@tonic-gate			 * program is to handle. Here is the best
7387c478bdstevel@tonic-gate			 * place to know this.
7397c478bdstevel@tonic-gate			 */
7407c478bdstevel@tonic-gate			prs->copies = prs->request->copies;
7417c478bdstevel@tonic-gate
7427c478bdstevel@tonic-gate		if (best_pc->slow) {
7437c478bdstevel@tonic-gate			/*
7447c478bdstevel@tonic-gate			 * If the filter has changed, the request will
7457c478bdstevel@tonic-gate			 * have to be refiltered. This may mean stopping
7467c478bdstevel@tonic-gate			 * a currently running filter or interface.
7477c478bdstevel@tonic-gate			 */
7487c478bdstevel@tonic-gate			if (!SAME(best_pc->slow, prs->slow)) {
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate			    if (prs->request->outcome & RS_FILTERED)
7517c478bdstevel@tonic-gate				prs->request->outcome &= ~RS_FILTERED;
7527c478bdstevel@tonic-gate
7537c478bdstevel@tonic-gate			    if (
7547c478bdstevel@tonic-gate				prs->request->outcome & RS_FILTERING
7557c478bdstevel@tonic-gate			     && !(prs->request->outcome & RS_STOPPED)
7567c478bdstevel@tonic-gate			    ) {
7577c478bdstevel@tonic-gate				prs->request->outcome |= RS_REFILTER;
7587c478bdstevel@tonic-gate				prs->request->outcome |= RS_STOPPED;
7597c478bdstevel@tonic-gate				terminate (prs->exec);
7607c478bdstevel@tonic-gate
7617c478bdstevel@tonic-gate			    } else if (
7627c478bdstevel@tonic-gate				prs->request->outcome & RS_PRINTING
7637c478bdstevel@tonic-gate			     && !(prs->request->outcome & RS_STOPPED)
7647c478bdstevel@tonic-gate			    ) {
7657c478bdstevel@tonic-gate				prs->request->outcome |= RS_STOPPED;
7667c478bdstevel@tonic-gate				terminate (oldpps->exec);
7677c478bdstevel@tonic-gate			    }
7687c478bdstevel@tonic-gate
7697c478bdstevel@tonic-gate			}
7707c478bdstevel@tonic-gate
7717c478bdstevel@tonic-gate			load_str (&(prs->slow), best_pc->slow);
7727c478bdstevel@tonic-gate			/* Assumption: if there is a slow filter,
7737c478bdstevel@tonic-gate			 * there is an output_type
7747c478bdstevel@tonic-gate			 */
7757c478bdstevel@tonic-gate
7767c478bdstevel@tonic-gate			load_str (&(prs->output_type), best_pc->output_type);
7777c478bdstevel@tonic-gate		} else
7787c478bdstevel@tonic-gate			unload_str (&(prs->slow));
7797c478bdstevel@tonic-gate
7807c478bdstevel@tonic-gate		load_str (&(prs->fast), best_pc->fast);
7817c478bdstevel@tonic-gate
7827c478bdstevel@tonic-gate		if (prs->request->actions & ACT_FAST && prs->slow) {
7837c478bdstevel@tonic-gate			if (prs->fast) {
7847c478bdstevel@tonic-gate				prs->fast = makestr(
7857c478bdstevel@tonic-gate					prs->slow,
7867c478bdstevel@tonic-gate					"|",
7877c478bdstevel@tonic-gate					prs->fast,
7887c478bdstevel@tonic-gate					(char *)0
7897c478bdstevel@tonic-gate				);
7907c478bdstevel@tonic-gate				Free (prs->slow);
7917c478bdstevel@tonic-gate			} else
7927c478bdstevel@tonic-gate				prs->fast = prs->slow;
7937c478bdstevel@tonic-gate			prs->slow = 0;
7947c478bdstevel@tonic-gate		}
7957c478bdstevel@tonic-gate
7967c478bdstevel@tonic-gate	}
7977c478bdstevel@tonic-gate
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gate	/*
8007c478bdstevel@tonic-gate	 * Free the space allocated for the candidates, INCLUDING
8017c478bdstevel@tonic-gate	 * the one chosen. Any allocated space in the chosen candidate
8027c478bdstevel@tonic-gate	 * that has to be saved should have been COPIED already.
8037c478bdstevel@tonic-gate	 */
8047c478bdstevel@tonic-gate	if (arena) {
8057c478bdstevel@tonic-gate		for (pc = arena; pc < pcend; pc++)
8067c478bdstevel@tonic-gate			free_candidate (pc);
8077c478bdstevel@tonic-gate		Free ((char *)arena);
8087c478bdstevel@tonic-gate	} else if (best_pc)
8097c478bdstevel@tonic-gate		free_candidate (best_pc);
8107c478bdstevel@tonic-gate
8117c478bdstevel@tonic-gate	if (o_length)
8127c478bdstevel@tonic-gate		Free (o_length);
8137c478bdstevel@tonic-gate	if (o_width)
8147c478bdstevel@tonic-gate		Free (o_width);
8157c478bdstevel@tonic-gate	if (o_lpi)
8167c478bdstevel@tonic-gate		Free (o_lpi);
8177c478bdstevel@tonic-gate	if (o_cpi)
8187c478bdstevel@tonic-gate		Free (o_cpi);
8197c478bdstevel@tonic-gate
8207c478bdstevel@tonic-gate
8217c478bdstevel@tonic-gate	/*
8227c478bdstevel@tonic-gate	 * The following value is valid ONLY IF the request
8237c478bdstevel@tonic-gate	 * is canceled or rejected. Not all requests that
8247c478bdstevel@tonic-gate	 * we fail in this routine are tossed out!
8257c478bdstevel@tonic-gate	 */
8267c478bdstevel@tonic-gate	prs->reason = ret;
8277c478bdstevel@tonic-gate
8287c478bdstevel@tonic-gate
8297c478bdstevel@tonic-gate	return (ret);
8307c478bdstevel@tonic-gate}
8317c478bdstevel@tonic-gate
8327c478bdstevel@tonic-gate/**
8337c478bdstevel@tonic-gate ** _chkopts() - CHECK -o OPTIONS
8347c478bdstevel@tonic-gate **/
8357c478bdstevel@tonic-gate
8367c478bdstevel@tonic-gatestatic int
8377c478bdstevel@tonic-gate_chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
8387c478bdstevel@tonic-gate{
8397c478bdstevel@tonic-gate	unsigned long		ret	= 0;
8407c478bdstevel@tonic-gate	unsigned long		chk	= 0;
8417c478bdstevel@tonic-gate
8427c478bdstevel@tonic-gate	char *			charset;
8437c478bdstevel@tonic-gate	char *			cpi	= 0;
8447c478bdstevel@tonic-gate	char *			lpi	= 0;
8457c478bdstevel@tonic-gate	char *			width	= 0;
8467c478bdstevel@tonic-gate	char *			length	= 0;
8477c478bdstevel@tonic-gate	char *			paper = NULL;
8487c478bdstevel@tonic-gate
8497c478bdstevel@tonic-gate	char **			pt;
85045916cdjpk	int			nobanner_not_allowed = 0;
8517c478bdstevel@tonic-gate
8527c478bdstevel@tonic-gate
8537c478bdstevel@tonic-gate	/*
8547c478bdstevel@tonic-gate	 * If we have a form, it overrides whatever print characteristics
8557c478bdstevel@tonic-gate	 * the user gave.
8567c478bdstevel@tonic-gate	 */
8577c478bdstevel@tonic-gate	if (pfs) {
8587c478bdstevel@tonic-gate		cpi = pfs->cpi;
8597c478bdstevel@tonic-gate		lpi = pfs->lpi;
8607c478bdstevel@tonic-gate		width = pfs->pwid;
8617c478bdstevel@tonic-gate		length = pfs->plen;
8627c478bdstevel@tonic-gate		paper = pfs->form->paper;
8637c478bdstevel@tonic-gate	} else {
8647c478bdstevel@tonic-gate		cpi = o_cpi;
8657c478bdstevel@tonic-gate		lpi = o_lpi;
8667c478bdstevel@tonic-gate		width = o_width;
8677c478bdstevel@tonic-gate		length = o_length;
8687c478bdstevel@tonic-gate	}
8697c478bdstevel@tonic-gate
8707c478bdstevel@tonic-gate	/*
8717c478bdstevel@tonic-gate	 * If the printer takes print wheels, or the character set
8727c478bdstevel@tonic-gate	 * the user wants is listed in the character set map for this
8737c478bdstevel@tonic-gate	 * printer, we needn't check if the printer can handle the
8747c478bdstevel@tonic-gate	 * character set. (Note: The check for the print wheel case
8757c478bdstevel@tonic-gate	 * is done elsewhere.)
8767c478bdstevel@tonic-gate	 */
87748bbca8Daniel Hoffman
8787c478bdstevel@tonic-gate	if (pc->pps->printer->daisy ||
8797c478bdstevel@tonic-gate	    search_cslist(prs->request->charset, pc->pps->printer->char_sets))
8807c478bdstevel@tonic-gate		charset = 0;
8817c478bdstevel@tonic-gate	else
8827c478bdstevel@tonic-gate		charset = prs->request->charset;
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate	pc->printer_types = 0;
8857c478bdstevel@tonic-gate	for (pt = pc->pps->printer->printer_types; *pt; pt++) {
8867c478bdstevel@tonic-gate		unsigned long		this;
8877c478bdstevel@tonic-gate
8887c478bdstevel@tonic-gate		if (paper) {
8897c478bdstevel@tonic-gate			if (allowed(paper,pc->pps->paper_allowed,NULL)) {
8907c478bdstevel@tonic-gate				addlist (&(pc->printer_types), *pt);
8917c478bdstevel@tonic-gate			} else {
8927c478bdstevel@tonic-gate				ret |= PCK_PAPER;
8937c478bdstevel@tonic-gate			}
8947c478bdstevel@tonic-gate		} else {
8957c478bdstevel@tonic-gate			this = chkprinter(*pt, cpi, lpi, length, width,
8967c478bdstevel@tonic-gate				charset);
8977c478bdstevel@tonic-gate			if (this == 0)
8987c478bdstevel@tonic-gate				addlist(&(pc->printer_types), *pt);
8997c478bdstevel@tonic-gate			chk |= this;
9007c478bdstevel@tonic-gate		}
9017c478bdstevel@tonic-gate	}
9027c478bdstevel@tonic-gate	if (!pc->printer_types)
9037c478bdstevel@tonic-gate		ret |= chk;
9047c478bdstevel@tonic-gate
90545916cdjpk	/*
906d0b12b6Toomas Soome	 * If the system is labeled, then user who wants 'nolabels' must
90745916cdjpk	 * have PRINT_UNLABELED_AUTH authorizations to allow it.
90845916cdjpk	 */
90945916cdjpk	if (is_system_labeled() && (wants_nolabels == 1)) {
91045916cdjpk		if (!tsol_lpauth(PRINT_UNLABELED_AUTH, prs->secure->user)) {
91145916cdjpk			/* if not authorized, remove "nolabels" from options */
91245916cdjpk			register char		**list;
91345916cdjpk			if (prs->request->options &&
91445916cdjpk			    (list = dashos(prs->request->options))) {
91545916cdjpk				dellist(&list, "nolabels");
91645916cdjpk				free(prs->request->options);
91745916cdjpk				prs->request->options = sprintlist(list);
91845916cdjpk			}
91945916cdjpk		}
92045916cdjpk	}
92145916cdjpk
92245916cdjpk
9237c478bdstevel@tonic-gate	if (pc->pps->printer->banner == BAN_ALWAYS) {
92445916cdjpk		/* delete "nobanner" */
92545916cdjpk		char **list;
9267c478bdstevel@tonic-gate
92745916cdjpk		/*
92845916cdjpk		 * If the system is labeled, users must have
92945916cdjpk		 * PRINT_NOBANNER_AUTH authorization to print
93045916cdjpk		 * without a banner.
93145916cdjpk		 */
93245916cdjpk		if (is_system_labeled()) {
93345916cdjpk			if (wants_nobanner == 1) {
93445916cdjpk				if (tsol_lpauth(PRINT_NOBANNER_AUTH,
93545916cdjpk					prs->secure->user) == 0) {
93645916cdjpk					nobanner_not_allowed = 1;
93745916cdjpk				}
93845916cdjpk			}
93945916cdjpk
94045916cdjpk		}
94145916cdjpk		else if ((wants_nobanner == 1) && (lp_or_root != 1)) {
94245916cdjpk			nobanner_not_allowed = 1;
94345916cdjpk		}
94445916cdjpk		if (nobanner_not_allowed == 1) {
94545916cdjpk			/* Take out 'nobanner' from request options. */
9467c478bdstevel@tonic-gate			if (prs->request->options &&
9477c478bdstevel@tonic-gate			    (list = dashos(prs->request->options))) {
9487c478bdstevel@tonic-gate				dellist(&list, "nobanner");
9497c478bdstevel@tonic-gate				free(prs->request->options);
9507c478bdstevel@tonic-gate				prs->request->options = sprintlist(list);
9517c478bdstevel@tonic-gate			}
9527c478bdstevel@tonic-gate		}
9537c478bdstevel@tonic-gate	} else if (pc->pps->printer->banner == BAN_NEVER) {
9547c478bdstevel@tonic-gate		if (wants_nobanner == 0) {
9557c478bdstevel@tonic-gate			/* add "nobanner" */
9567c478bdstevel@tonic-gate			char **list = NULL;
9577c478bdstevel@tonic-gate
9587c478bdstevel@tonic-gate			if (prs->request->options) {
9597c478bdstevel@tonic-gate				list = dashos(prs->request->options);
9607c478bdstevel@tonic-gate				free(prs->request->options);
9617c478bdstevel@tonic-gate			}
9627c478bdstevel@tonic-gate			appendlist(&list, "nobanner");
9637c478bdstevel@tonic-gate			prs->request->options = sprintlist(list);
9647c478bdstevel@tonic-gate		}
9657c478bdstevel@tonic-gate	} else /* if (pc->pps->printer->banner == BAN_OPTIONAL) */ {
9667c478bdstevel@tonic-gate		/* it is optional, leave it alone */
9677c478bdstevel@tonic-gate	}
9687c478bdstevel@tonic-gate
9697c478bdstevel@tonic-gate	chkprinter_result |= ret;
9707c478bdstevel@tonic-gate	return (ret == 0);
9717c478bdstevel@tonic-gate}
9727c478bdstevel@tonic-gate
9737c478bdstevel@tonic-gate/**
9747c478bdstevel@tonic-gate ** free_candidate()
9757c478bdstevel@tonic-gate **/
9767c478bdstevel@tonic-gate
9777c478bdstevel@tonic-gatestatic void
9787c478bdstevel@tonic-gatefree_candidate(CANDIDATE *pc)
9797c478bdstevel@tonic-gate{
9807c478bdstevel@tonic-gate	if (pc->slow)
9817c478bdstevel@tonic-gate		unload_str (&(pc->slow));
9827c478bdstevel@tonic-gate	if (pc->fast)
9837c478bdstevel@tonic-gate		unload_str (&(pc->fast));
9847c478bdstevel@tonic-gate	if (pc->printer_types) {
9857c478bdstevel@tonic-gate		freelist (pc->printer_types);
9867c478bdstevel@tonic-gate		pc->printer_types = 0;
9877c478bdstevel@tonic-gate	}
9887c478bdstevel@tonic-gate	if (pc->printer_type)
9897c478bdstevel@tonic-gate		unload_str (&(pc->printer_type));
9907c478bdstevel@tonic-gate	if (pc->output_type)
9917c478bdstevel@tonic-gate		unload_str (&(pc->output_type));
9927c478bdstevel@tonic-gate	return;
9937c478bdstevel@tonic-gate}
99445916cdjpk
99545916cdjpkstatic int
99645916cdjpktsol_check_printer_label_range(char *slabel, const char *printer)
99745916cdjpk{
99845916cdjpk	int			in_range = 0;
99945916cdjpk	int			err = 0;
100045916cdjpk	m_range_t		*range;
100145916cdjpk	m_label_t	*sl = NULL;
100245916cdjpk
100345916cdjpk	if (slabel == NULL)
100445916cdjpk		return (0);
100545916cdjpk
100645916cdjpk	if ((err =
100745916cdjpk	    (str_to_label(slabel, &sl, USER_CLEAR, L_NO_CORRECTION, &in_range)))
100845916cdjpk	    == -1) {
100945916cdjpk		/* stobsl error on printer max label */
101045916cdjpk		return (0);
101145916cdjpk	}
101245916cdjpk	if ((range = getdevicerange(printer)) == NULL) {
101345916cdjpk		m_label_free(sl);
101445916cdjpk		return (0);
101545916cdjpk	}
101645916cdjpk
101745916cdjpk	/* blinrange returns true (1) if in range, false (0) if not */
101845916cdjpk	in_range = blinrange(sl, range);
101945916cdjpk
102045916cdjpk	m_label_free(sl);
102145916cdjpk	m_label_free(range->lower_bound);
102245916cdjpk	m_label_free(range->upper_bound);
102345916cdjpk	free(range);
102445916cdjpk
102545916cdjpk	return (in_range);
102645916cdjpk}
102745916cdjpk
102845916cdjpk/*
102945916cdjpk * Given a character string with a "username" or "system!username"
103045916cdjpk * this function returns a pointer to "username"
103145916cdjpk */
103245916cdjpkstatic int
103345916cdjpktsol_lpauth(char *auth, char *in_name)
103445916cdjpk{
103545916cdjpk	char *cp;
103645916cdjpk	int res;
103745916cdjpk
103845916cdjpk	if ((cp = strchr(in_name, '@')) != NULL) {
103945916cdjpk		/* user@system */
104045916cdjpk		*cp = '\0';
104145916cdjpk		res = chkauthattr(auth, in_name);
104245916cdjpk		*cp = '@';
104345916cdjpk	} else if ((cp = strchr(in_name, '!')) != NULL)
104445916cdjpk		/* system!user */
104545916cdjpk		res = chkauthattr(auth, cp+1);
104645916cdjpk	else
104745916cdjpk		/* user */
104845916cdjpk		res = chkauthattr(auth, in_name);
104945916cdjpk
105045916cdjpk	return (res);
105145916cdjpk}
105245916cdjpk
105345916cdjpk#define	POLICY_FILE	"/etc/default/print"
105445916cdjpk
105545916cdjpkint
105645916cdjpksecpolicy_chkpolicy(char *policyp)
105745916cdjpk{
105845916cdjpk	char *option;
105945916cdjpk	int opt_val;
106045916cdjpk
106145916cdjpk	if (policyp == NULL)
106245916cdjpk		return (0);
106345916cdjpk	opt_val = 0;
106445916cdjpk	if (defopen(POLICY_FILE) == 0) {
106545916cdjpk
106645916cdjpk		defcntl(DC_SETFLAGS, DC_STD & ~DC_CASE); /* ignore case */
106745916cdjpk
106845916cdjpk		if ((option = defread(policyp)) != NULL)
106945916cdjpk			opt_val = atoi(option);
107045916cdjpk	}
107145916cdjpk	(void) defopen((char *)NULL);
107245916cdjpk	syslog(LOG_DEBUG, "--- Policy %s, opt_val==%d",
107345916cdjpk	    policyp ? policyp : "NULL", opt_val);
107445916cdjpk	return (opt_val);
107545916cdjpk}
1076