xref: /illumos-gate/usr/src/cmd/lp/cmd/lpsched/disp1.c (revision 7380b00c)
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 2009 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 #include "dispatch.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <syslog.h>
33 
34 static char	*reqpath(char *, char **);
35 static int	mv_file(RSTATUS *, char *);
36 
37 
38 RSTATUS			*NewRequest;
39 
40 /*
41  * s_alloc_files()
42  */
43 
44 void
45 s_alloc_files(char *m, MESG *md)	/* funcdef */
46 {
47 	char		*file_prefix;
48 	ushort_t	count;
49 	mode_t		old_msk;
50 
51 
52 	/*
53 	 * Bugid 4140311
54 	 * Set umask to 0 before creating files.
55 	 */
56 	old_msk = umask((mode_t)0);
57 
58 	getmessage(m, S_ALLOC_FILES, &count);
59 	syslog(LOG_DEBUG, "s_alloc_files(%d)", count);
60 
61 	if ((file_prefix = _alloc_files(count, (char *)0, md->uid, md->gid))) {
62 		mputm(md, R_ALLOC_FILES, MOK, file_prefix);
63 		add_flt_act(md, FLT_FILES, file_prefix, count);
64 	} else if (errno == EEXIST)
65 		mputm(md, R_ALLOC_FILES, MERRDEST, "");
66 	else
67 		mputm(md, R_ALLOC_FILES, MNOMEM, "");
68 
69 	(void) umask(old_msk);
70 
71 }
72 
73 /*
74  * s_print_request()
75  */
76 
77 void
78 s_print_request(char *m, MESG *md)
79 {
80 	extern char		*Local_System;
81 	char			*file;
82 	char			*idno;
83 	char			*path;
84 	char			*req_file;
85 	char			*req_id	= 0;
86 	RSTATUS			*rp;
87 	REQUEST			*r;
88 	SECURE			*s;
89 	struct passwd		*pw;
90 	short			err;
91 	short			status;
92 	off_t			size;
93 	uid_t			org_uid;
94 	gid_t			org_gid;
95 #ifdef LP_USE_PAPI_ATTR
96 	struct stat		tmpBuf;
97 	char 			tmpName[BUFSIZ];
98 #endif
99 
100 
101 	(void) getmessage(m, S_PRINT_REQUEST, &file);
102 	syslog(LOG_DEBUG, "s_print_request(%s)", (file ? file : "NULL"));
103 
104 	/*
105 	 * "NewRequest" points to a request that's not yet in the
106 	 * request list but is to be considered with the rest of the
107 	 * requests (e.g. calculating # of requests awaiting a form).
108 	 */
109 	if ((rp = NewRequest = new_rstatus(NULL, NULL)) == NULL)
110 		status = MNOMEM;
111 
112 	else
113 	{
114 		req_file = reqpath(file, &idno);
115 		path = makepath(Lp_Tmp, req_file, (char *)0);
116 		(void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
117 		Free(path);
118 
119 		if (!(r = Getrequest(req_file)))
120 			status = MNOOPEN;
121 
122 		else
123 		{
124 			rp->req_file = Strdup(req_file);
125 
126 			freerequest(rp->request);
127 			rp->request = r;
128 
129 			rp->request->outcome = 0;
130 			rp->secure->uid = md->uid;
131 			rp->secure->gid = md->gid;
132 			if (md->slabel != NULL)
133 				rp->secure->slabel = Strdup(md->slabel);
134 
135 			pw = getpwuid(md->uid);
136 			endpwent();
137 			if (pw && pw->pw_name && *pw->pw_name)
138 				rp->secure->user = Strdup(pw->pw_name);
139 			else {
140 				rp->secure->user = Strdup(BIGGEST_NUMBER_S);
141 				(void) sprintf(rp->secure->user, "%u",
142 				    md->uid);
143 			}
144 
145 			if ((rp->request->actions & ACT_SPECIAL) == ACT_HOLD)
146 				rp->request->outcome |= RS_HELD;
147 			if ((rp->request->actions & ACT_SPECIAL) == ACT_RESUME)
148 				rp->request->outcome &= ~RS_HELD;
149 			if ((rp->request->actions & ACT_SPECIAL) ==
150 			    ACT_IMMEDIATE) {
151 				if (!md->admin) {
152 					status = MNOPERM;
153 					goto Return;
154 				}
155 				rp->request->outcome |= RS_IMMEDIATE;
156 			}
157 
158 			size = chfiles(rp->request->file_list, Lp_Uid, Lp_Gid);
159 
160 			if (size < 0) {
161 				/*
162 				 * at this point, chfiles() may have
163 				 * failed because the file may live on
164 				 * an NFS mounted filesystem, under
165 				 * a directory of mode 700. such a
166 				 * directory isn't accessible even by
167 				 * root, according to the NFS protocol
168 				 * (i.e. the Stat() in chfiles() failed).
169 				 * this most commonly happens via the
170 				 * automounter, and rlogin. thus we
171 				 * change our euid/egid to that of the
172 				 * user, and try again. if *this* fails,
173 				 * then the file must really be
174 				 * inaccessible.
175 				 */
176 				org_uid = geteuid();
177 				org_gid = getegid();
178 
179 				if (setegid(md->gid) != 0) {
180 					status = MUNKNOWN;
181 					goto Return;
182 				}
183 
184 				if (seteuid(md->uid) != 0) {
185 					setgid(org_gid);
186 					status = MUNKNOWN;
187 					goto Return;
188 				}
189 
190 				size = chfiles(rp->request->file_list,
191 				    Lp_Uid, Lp_Gid);
192 
193 				if (seteuid(org_uid) != 0) {
194 					/* should never happen */
195 					note("s_print_request(): ");
196 					note("seteuid back to uid=%d "
197 					    "failed!!\n", org_uid);
198 					size = -1;
199 				}
200 
201 				if (setegid(org_gid) != 0) {
202 					/* should never happen */
203 					note("s_print_request(): ");
204 					note("setegid back to uid=%d "
205 					    "failed!!\n", org_uid);
206 					size = -1;
207 				}
208 
209 				if (size < 0) {
210 					status = MUNKNOWN;
211 					goto Return;
212 				}
213 			}
214 			if (!(rp->request->outcome & RS_HELD) && size == 0) {
215 				status = MNOPERM;
216 				goto Return;
217 			}
218 			rp->secure->size = size;
219 
220 			(void) time(&rp->secure->date);
221 			rp->secure->req_id = NULL;
222 
223 			if (!rp->request->title) {
224 				if (strlen(*rp->request->file_list) <
225 				    (size_t)24)
226 					rp->request->title =
227 					    Strdup(*rp->request->file_list);
228 				else {
229 					/*
230 					 * In case of standard input
231 					 * the title page should be
232 					 * 'standard input'
233 					 */
234 					rp->request->title = malloc(25);
235 					sprintf(rp->request->title,
236 					    "%-.24s", "standard input");
237 				}
238 			}
239 
240 			if ((err = validate_request(rp, &req_id, 0)) != MOK)
241 				status = err;
242 			else {
243 				/*
244 				 * "req_id" will be supplied if this is from a
245 				 * remote system.
246 				 */
247 				if (rp->secure->req_id == NULL) {
248 					req_id = makestr(req_id, "-",
249 					    idno, (char *)0);
250 					rp->secure->req_id = req_id;
251 				} else
252 					req_id = rp->secure->req_id;
253 
254 #ifdef LP_USE_PAPI_ATTR
255 				/*
256 				 * Check if the PAPI job attribute file
257 				 * exists, if it does change the
258 				 * permissions and ownership of the file.
259 				 * This file is created when print jobs
260 				 * are submitted via the PAPI interface,
261 				 * the file pathname of this file is
262 				 * passed to the slow-filters and printer
263 				 * interface script as an environment
264 				 * variable when they are executed
265 				 */
266 				snprintf(tmpName, sizeof (tmpName),
267 				    "%s-%s", idno, LP_PAPIATTRNAME);
268 				path = makepath(Lp_Temp, tmpName, (char *)0);
269 
270 				if (stat(path, &tmpBuf) == 0) {
271 					syslog(LOG_DEBUG,
272 					    "s_print_request: "\
273 					    "attribute file ='%s'", path);
274 
275 					/*
276 					 * IPP job attribute file exists
277 					 * for this job so change
278 					 * permissions and ownership of
279 					 * the file
280 					 */
281 					(void) chownmod(path, Lp_Uid,
282 					    Lp_Gid, 0644);
283 					Free(path);
284 				}
285 				else
286 				{
287 					syslog(LOG_DEBUG,
288 					    "s_print_request: "\
289 					    "no attribute file");
290 				}
291 #endif
292 
293 				/*
294 				 * fix for bugid 1103890.
295 				 * use Putsecure instead.
296 				 */
297 				if ((Putsecure(req_file, rp->secure) == -1) ||
298 				    (putrequest(req_file, rp->request) == -1))
299 					status = MNOMEM;
300 				else
301 				{
302 					status = MOK;
303 
304 					insertr(rp);
305 					NewRequest = 0;
306 
307 					if (rp->slow)
308 						schedule(EV_SLOWF, rp);
309 					else
310 						schedule(EV_INTERF,
311 						    rp->printer);
312 
313 					del_flt_act(md, FLT_FILES);
314 				}
315 			}
316 		}
317 	}
318 
319 Return:
320 	NewRequest = 0;
321 	Free(req_file);
322 	Free(idno);
323 	if (status != MOK && rp) {
324 		rmfiles(rp, 0);
325 		free_rstatus(rp);
326 	}
327 	mputm(md, R_PRINT_REQUEST, status, NB(req_id), chkprinter_result);
328 }
329 
330 /*
331  * s_start_change_request()
332  */
333 
334 void
335 s_start_change_request(char *m, MESG *md)
336 {
337 	char		*req_id;
338 	char		*req_file	= "";
339 	short		status;
340 	RSTATUS		*rp;
341 	char		*path;
342 	char		tmpName[BUFSIZ];
343 	struct stat	tmpBuf;
344 
345 	(void) getmessage(m, S_START_CHANGE_REQUEST, &req_id);
346 	syslog(LOG_DEBUG, "s_start_change_request(%s)",
347 	    (req_id ? req_id : "NULL"));
348 
349 	if (!(rp = request_by_id(req_id)))
350 		status = MUNKNOWN;
351 	else if ((md->admin == 0) && (is_system_labeled()) &&
352 	    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
353 	    (!STREQU(md->slabel, rp->secure->slabel)))
354 		status = MUNKNOWN;
355 	else if (rp->request->outcome & RS_DONE)
356 		status = M2LATE;
357 	else if (!md->admin && md->uid != rp->secure->uid)
358 		status = MNOPERM;
359 	else if (rp->request->outcome & RS_CHANGING)
360 		status = MNOOPEN;
361 	else if (rp->request->outcome & RS_NOTIFYING)
362 		status = MBUSY;
363 	else {
364 		status = MOK;
365 
366 		if (rp->request->outcome & RS_FILTERING &&
367 		    !(rp->request->outcome & RS_STOPPED)) {
368 			rp->request->outcome |= (RS_REFILTER|RS_STOPPED);
369 			terminate(rp->exec);
370 		}
371 
372 		if (rp->request->outcome & RS_PRINTING &&
373 		    !(rp->request->outcome & RS_STOPPED)) {
374 			rp->request->outcome |= RS_STOPPED;
375 			terminate(rp->printer->exec);
376 		}
377 
378 		rp->request->outcome |= RS_CHANGING;
379 
380 		/*
381 		 * Change the ownership of the request file to be "md->uid".
382 		 * Either this is identical to "rp->secure->uid", or it is
383 		 * "Lp_Uid" or it is root. The idea is that the
384 		 * person at the other end needs access, and that may not
385 		 * be who queued the request.
386 		 */
387 
388 		path = makepath(Lp_Tmp, rp->req_file, (char *)0);
389 		(void) Chown(path, md->uid, rp->secure->gid);
390 		Free(path);
391 
392 #ifdef LP_USE_PAPI_ATTR
393 
394 		/*
395 		 * Check if the PAPI job attribute file exists, if it does
396 		 * change the ownership of the file to be "md->uid".
397 		 * Either this is identical to "rp->secure->uid", or it is
398 		 * "Lp_Uid" or it is root. The idea is that the
399 		 * person at the other end needs access, and that may not
400 		 * be who queued the request.
401 		 */
402 
403 		snprintf(tmpName, sizeof (tmpName),
404 		    "%s-%s", strtok(strdup(rp->req_file), "-"),
405 		    LP_PAPIATTRNAME);
406 
407 		path = makepath(Lp_Tmp, tmpName, (char *)0);
408 
409 		if (stat(path, &tmpBuf) == 0) {
410 			syslog(LOG_DEBUG,
411 			    "s_start_change_request: attribute file ='%s'",
412 			    path);
413 
414 			/*
415 			 * IPP job attribute file exists for this job so
416 			 * change permissions and ownership of the file
417 			 */
418 			(void) Chown(path, md->uid, rp->secure->gid);
419 			Free(path);
420 		}
421 		else
422 		{
423 			syslog(LOG_DEBUG,
424 			    "s_start_change_request: no attribute file");
425 		}
426 #endif
427 
428 		add_flt_act(md, FLT_CHANGE, rp);
429 		req_file = rp->req_file;
430 
431 	}
432 
433 	mputm(md, R_START_CHANGE_REQUEST, status, req_file);
434 }
435 
436 /*
437  * s_end_change_request()
438  */
439 
440 void
441 s_end_change_request(char *m, MESG *md)
442 {
443 	char		*req_id;
444 	RSTATUS		*rp;
445 	off_t		size;
446 	off_t		osize;
447 	short		err;
448 	short		status;
449 	REQUEST		*r = 0;
450 	REQUEST		oldr;
451 	int		call_schedule = 0;
452 	int		move_ok	= 0;
453 	char		*path;
454 	char		tmpName[BUFSIZ];
455 	struct stat	tmpBuf;
456 
457 	(void) getmessage(m, S_END_CHANGE_REQUEST, &req_id);
458 	syslog(LOG_DEBUG, "s_end_change_request(%s)",
459 	    (req_id ? req_id : "NULL"));
460 
461 	if (!(rp = request_by_id(req_id)))
462 		status = MUNKNOWN;
463 	else if ((md->admin == 0) && (is_system_labeled()) &&
464 	    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
465 	    (!STREQU(md->slabel, rp->secure->slabel)))
466 		status = MUNKNOWN;
467 	else if (!(rp->request->outcome & RS_CHANGING))
468 		status = MNOSTART;
469 	else {
470 		path = makepath(Lp_Tmp, rp->req_file, (char *)0);
471 		(void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
472 		Free(path);
473 
474 #ifdef LP_USE_PAPI_ATTR
475 
476 		/*
477 		 * Check if the PAPI job attribute file exists,
478 		 * if it does change the permission and the ownership
479 		 * of the file to be "Lp_Uid".
480 		 */
481 
482 		snprintf(tmpName, sizeof (tmpName),
483 		    "%s-%s", strtok(strdup(rp->req_file), "-"),
484 		    LP_PAPIATTRNAME);
485 
486 		path = makepath(Lp_Tmp, tmpName, (char *)0);
487 
488 		if (stat(path, &tmpBuf) == 0) {
489 			syslog(LOG_DEBUG,
490 			    "s_end_change_request: attribute file ='%s'",
491 			    path);
492 
493 			/*
494 			 * IPP job attribute file exists for this job so
495 			 * change permissions and ownership of the file
496 			 */
497 			(void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
498 			Free(path);
499 		}
500 		else
501 		{
502 			syslog(LOG_DEBUG,
503 			    "s_end_change_request: no attribute file");
504 		}
505 #endif
506 		rp->request->outcome &= ~(RS_CHANGING);
507 		del_flt_act(md, FLT_CHANGE);
508 		/*
509 		 * The RS_CHANGING bit may have been the only thing
510 		 * preventing this request from filtering or printing,
511 		 * so regardless of what happens below,
512 		 * we must check to see if the request can proceed.
513 		 */
514 		call_schedule = 1;
515 
516 		if (!(r = Getrequest(rp->req_file)))
517 			status = MNOOPEN;
518 		else {
519 			oldr = *(rp->request);
520 			*(rp->request) = *r;
521 
522 			move_ok =
523 			    STREQU(oldr.destination, r->destination);
524 
525 			/*
526 			 * Preserve the current request status!
527 			 */
528 			rp->request->outcome = oldr.outcome;
529 
530 			/*
531 			 * Here's an example of the dangers one meets
532 			 * when public flags are used for private
533 			 * purposes. ".actions" (indeed, anything in the
534 			 * REQUEST structure) is set by the person
535 			 * changing the job. However, lpsched uses
536 			 * ".actions" as place to indicate that a job
537 			 * came from a remote system and we must send
538 			 * back job completion--this is a strictly
539 			 * private flag that we must preserve.
540 			 */
541 			rp->request->actions |=
542 			    (oldr.actions & ACT_NOTIFY);
543 
544 			if ((rp->request->actions & ACT_SPECIAL) ==
545 			    ACT_HOLD) {
546 				rp->request->outcome |= RS_HELD;
547 				/*
548 				 * To be here means either the user owns
549 				 * the request or he or she is the
550 				 * administrator. Since we don't want to
551 				 * set the RS_ADMINHELD flag if the user
552 				 * is the administrator, the following
553 				 * compare will work.
554 				 */
555 				if (md->uid != rp->secure->uid)
556 					rp->request->outcome |=
557 					    RS_ADMINHELD;
558 			}
559 
560 			if ((rp->request->actions & ACT_SPECIAL) ==
561 			    ACT_RESUME) {
562 				if ((rp->request->outcome & RS_ADMINHELD) &&
563 				    !md->admin) {
564 					status = MNOPERM;
565 					goto Return;
566 				}
567 				rp->request->outcome &=
568 				    ~(RS_ADMINHELD|RS_HELD);
569 			}
570 
571 			if ((rp->request->actions & ACT_SPECIAL)
572 			    == ACT_IMMEDIATE) {
573 				if (!md->admin) {
574 					status = MNOPERM;
575 					goto Return;
576 				}
577 				rp->request->outcome |= RS_IMMEDIATE;
578 			}
579 
580 			size = chfiles(rp->request->file_list, Lp_Uid,
581 			    Lp_Gid);
582 			if (size < 0) {
583 				status = MUNKNOWN;
584 				goto Return;
585 			}
586 			if (!(rp->request->outcome & RS_HELD) &&
587 			    size == 0) {
588 				status = MNOPERM;
589 				goto Return;
590 			}
591 
592 			osize = rp->secure->size;
593 			rp->secure->size = size;
594 
595 			if (move_ok == 0) {
596 				char *dest = strdup(r->destination);
597 				if ((status = mv_file(rp, dest)) == MOK)
598 					rp->secure->size = osize;
599 				free(dest);
600 			} else if ((err = validate_request(rp, (char **)0,
601 			    move_ok)) != MOK) {
602 				status = err;
603 				rp->secure->size = osize;
604 			} else {
605 				status = MOK;
606 
607 				if ((rp->request->outcome & RS_IMMEDIATE) ||
608 				    (rp->request->priority != oldr.priority)) {
609 					remover(rp);
610 					insertr(rp);
611 				}
612 
613 				freerequest(&oldr);
614 				(void) putrequest(rp->req_file, rp->request);
615 				/*
616 				 * fix for bugid 1103890.
617 				 * use Putsecure instead.
618 				 */
619 				(void) Putsecure(rp->req_file, rp->secure);
620 			}
621 		}
622 	}
623 
624 Return:
625 	if (status != MOK && rp) {
626 		if (r) {
627 			freerequest(r);
628 			*(rp->request) = oldr;
629 		}
630 		if (status != MNOSTART)
631 			(void) putrequest(rp->req_file, rp->request);
632 	}
633 
634 	if (call_schedule)
635 		maybe_schedule(rp);
636 
637 	mputm(md, R_END_CHANGE_REQUEST, status, chkprinter_result);
638 }
639 
640 /*
641  * _cancel()
642  *	user may be (host!user)
643  */
644 
645 static char *
646 _cancel(MESG *md, char *dest, char *user, char *req_id)
647 {
648 	static RSTATUS	*rp;
649 	static char		*s_dest;
650 	static char		*s_user;
651 	static char		*s_req_id;
652 	static int		current;
653 	RSTATUS		*crp;
654 	char		*creq_id;
655 
656 	syslog(LOG_DEBUG, "_cancel(%s, %s, %s)", (dest ? dest : "NULL"),
657 	    (user ? user : "NULL"), (req_id ? req_id : "NULL"));
658 
659 	if (dest || user || req_id) {
660 		s_dest = dest;
661 		if (STREQU(user, "!"))
662 			s_user = strdup("all!all");
663 		else
664 			s_user = user;
665 		s_req_id = req_id;
666 		rp = Request_List;
667 		current = 0;
668 		if (STREQU(s_req_id, CURRENT_REQ)) {
669 			current = 1;
670 			s_req_id = NULL;
671 		}
672 	}
673 
674 	while (rp != NULL) {
675 		crp = rp;
676 		rp = rp->next;
677 
678 		if (*s_dest && !STREQU(s_dest, crp->request->destination))
679 			continue;
680 
681 		if (current && !(crp->request->outcome & RS_PRINTING))
682 			continue;
683 
684 		if (s_req_id && *s_req_id &&
685 		    !STREQU(s_req_id, crp->secure->req_id))
686 			continue;
687 
688 		if (*s_user && !bangequ(s_user, crp->secure->user))
689 			continue;
690 
691 		if (!md->admin && md->uid != crp->secure->uid) {
692 			errno = MNOPERM;
693 			return (Strdup(crp->secure->req_id));
694 		}
695 
696 		/*
697 		 * For Trusted Extensions, we need to check the
698 		 * sensitivity label of the
699 		 * connection and job before we try to cancel it.
700 		 */
701 		if ((md->admin == 0) && (is_system_labeled()) &&
702 		    (md->slabel != NULL) && (crp->secure->slabel != NULL) &&
703 		    (!STREQU(md->slabel, crp->secure->slabel)))
704 			continue;
705 
706 		crp->reason = MOK;
707 		creq_id = Strdup(crp->secure->req_id);
708 
709 		syslog(LOG_DEBUG, "cancel reqid (%s) uid: %d, secureuid: %d",
710 		    creq_id, md->uid, crp->secure->uid);
711 
712 		if (cancel(crp, (md->uid != crp->secure->uid)))
713 			errno = MOK;
714 		else
715 			errno = M2LATE;
716 		return (creq_id);
717 	}
718 
719 	errno = MUNKNOWN;
720 	return (NULL);
721 }
722 
723 /*
724  * s_cancel_request()
725  */
726 
727 void
728 s_cancel_request(char *m, MESG *md)
729 {
730 	char	*req_id, *rid;
731 	short	status;
732 
733 	(void) getmessage(m, S_CANCEL_REQUEST, &req_id);
734 	syslog(LOG_DEBUG, "s_cancel_request(%s)", (req_id ? req_id : "NULL"));
735 
736 	if ((rid = _cancel(md, "", "", req_id)) != NULL)
737 		Free(rid);
738 	status = (short)errno;
739 
740 	mputm(md, R_CANCEL_REQUEST, status);
741 }
742 
743 /*
744  * s_cancel()
745  */
746 
747 void
748 s_cancel(char *m, MESG *md)
749 {
750 	char	*req_id;
751 	char	*user;
752 	char	*destination;
753 	char	*rid;
754 	char	*nrid;
755 	int		nerrno;
756 	int		oerrno;
757 
758 	(void) getmessage(m, S_CANCEL, &destination, &user, &req_id);
759 	syslog(LOG_DEBUG, "s_cancel(%s, %s, %s)",
760 	    (destination ? destination : "NULL"), (user ? user : "NULL"),
761 	    (req_id ? req_id : "NULL"));
762 
763 	if (STREQU(destination, NAME_ALL))
764 		destination = "";
765 	if (STREQU(req_id, NAME_ALL))
766 		req_id = "";
767 
768 	if (rid = _cancel(md, destination, user, req_id)) {
769 		oerrno = errno;
770 
771 		while ((nrid = _cancel(md, NULL, NULL, NULL)) != NULL) {
772 			nerrno = errno;
773 			mputm(md, R_CANCEL, MOKMORE, oerrno, rid);
774 			Free(rid);
775 			rid = nrid;
776 			oerrno = nerrno;
777 		}
778 		mputm(md, R_CANCEL, MOK, oerrno, rid);
779 		Free(rid);
780 		return;
781 	}
782 
783 	mputm(md, R_CANCEL, MOK, MUNKNOWN, "");
784 }
785 
786 /*
787  * s_inquire_request_rank()
788  */
789 
790 void
791 s_inquire_request_rank(char *m, MESG *md)
792 {
793 	char		*form;
794 	char		*dest;
795 	char		*pwheel;
796 	char		*user;
797 	char		*req_id;
798 	RSTATUS		*rp;
799 	RSTATUS		*found = NULL;
800 	int		found_rank = 0;
801 	short		prop;
802 	char		files[BUFSIZ];
803 	int 		i;
804 
805 	(void) getmessage(m, S_INQUIRE_REQUEST_RANK, &prop, &form, &dest,
806 	    &req_id, &user, &pwheel);
807 	syslog(LOG_DEBUG, "s_inquire_request_rank(%d, %s, %s, %s, %s, %s)",
808 	    prop, (form ? form : "NULL"), (dest ? dest : "NULL"),
809 	    (req_id ? req_id : "NULL"), (user ? user : "NULL"),
810 	    (pwheel ? pwheel : "NULL"));
811 
812 	for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
813 		PStatus[i]->nrequests = 0;
814 
815 	for (rp = Request_List; rp != NULL; rp = rp->next) {
816 		if (rp->printer && !(rp->request->outcome & RS_DONE))
817 			rp->printer->nrequests++;
818 
819 		if (*form && !SAME(form, rp->request->form))
820 			continue;
821 
822 		if (*dest && !STREQU(dest, rp->request->destination)) {
823 			if (!rp->printer)
824 				continue;
825 			if (!STREQU(dest, rp->printer->printer->name))
826 				continue;
827 		}
828 
829 		if (*req_id && !STREQU(req_id, rp->secure->req_id))
830 			continue;
831 
832 		if (*user && !bangequ(user, rp->secure->user))
833 			continue;
834 
835 		if (*pwheel && !SAME(pwheel, rp->pwheel_name))
836 			continue;
837 		/*
838 		 * For Trusted Extensions, we need to check the sensitivity
839 		 * label of the connection and job before we return it to the
840 		 * client.
841 		 */
842 		if ((md->admin <= 0) && (is_system_labeled()) &&
843 		    (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
844 		    (!STREQU(md->slabel, rp->secure->slabel)))
845 			continue;
846 
847 		if (found) {
848 			GetRequestFiles(found->request, files, sizeof (files));
849 			mputm(md, R_INQUIRE_REQUEST_RANK,
850 			    MOKMORE,
851 			    found->secure->req_id,
852 			    found->request->user,
853 			    /* bgolden 091996, bug 1257405 */
854 			    found->secure->slabel,
855 			    found->secure->size,
856 			    found->secure->date,
857 			    found->request->outcome,
858 			    found->printer->printer->name,
859 			    (found->form? found->form->form->name : ""),
860 			    NB(found->pwheel_name),
861 			    found_rank,
862 			    files);
863 		}
864 		found = rp;
865 		found_rank = found->printer->nrequests;
866 	}
867 
868 	if (found) {
869 		GetRequestFiles(found->request, files, sizeof (files));
870 		mputm(md, R_INQUIRE_REQUEST_RANK,
871 		    MOK,
872 		    found->secure->req_id,
873 		    found->request->user, /* bgolden 091996, bug 1257405 */
874 		    found->secure->slabel,
875 		    found->secure->size,
876 		    found->secure->date,
877 		    found->request->outcome,
878 		    found->printer->printer->name,
879 		    (found->form? found->form->form->name : ""),
880 		    NB(found->pwheel_name),
881 		    found_rank,
882 		    files);
883 	} else
884 		mputm(md, R_INQUIRE_REQUEST_RANK, MNOINFO, "", "", "", 0L, 0L,
885 		    0, "", "", "", 0, "");
886 }
887 
888 static int
889 mv_file(RSTATUS *rp, char *dest)
890 {
891 	int	stat;
892 	char	*olddest;
893 	EXEC	*oldexec;
894 	SECURE * securep;
895 	RSTATUS * prs;
896 	char *reqno;
897 
898 	oldexec = rp->printer->exec;
899 	olddest = rp->request->destination;
900 	rp->request->destination = Strdup(dest);
901 	if ((stat = validate_request(rp, (char **)0, 1)) == MOK) {
902 		Free(olddest);
903 
904 		if (rp->request->outcome & RS_FILTERED) {
905 			int cnt = 0;
906 			char *reqno;
907 			char **listp;
908 			char tmp_nam[MAXPATHLEN];
909 
910 			reqno = getreqno(rp->secure->req_id);
911 			for (listp = rp->request->file_list; *listp; listp++) {
912 				cnt++;
913 				snprintf(tmp_nam, sizeof (tmp_nam),
914 				    "%s/F%s-%d", Lp_Temp, reqno, cnt);
915 				unlink(tmp_nam);
916 
917 			}
918 			rp->request->outcome &= ~RS_FILTERED;
919 		}
920 
921 		/* update /var/spool/lp/tmp/<host>/nnn-0 */
922 		if (putrequest(rp->req_file, rp->request) < 0) {
923 			note("putrequest failed\n");
924 			return (MNOMEM);
925 		}
926 
927 		/* update /var/spool/lp/requests/<host>/nnn-0 */
928 		if ((securep = Getsecure(rp->req_file))) {
929 			reqno = strdup(getreqno(securep->req_id));
930 			(void) free(securep->req_id);
931 			if ((securep->req_id = calloc(strlen(dest) + 1 +
932 			    strlen(reqno) +1, sizeof (char))) == NULL)
933 				return (MNOMEM);
934 			(void) sprintf(securep->req_id, "%s-%s", dest, reqno);
935 			/* remove the old request file; save new one */
936 			(void) rmsecure(rp->secure->req_id);
937 			if (Putsecure(rp->req_file, securep) < 0) {
938 				/* Putsecure includes note/errmessage */
939 				return (MNOMEM);
940 			}
941 		} else {
942 			note("Getsecure failed\n");
943 			return (MNOMEM);
944 		}
945 
946 		/* update internal jobs list: Request_list */
947 		if (prs = request_by_id(rp->secure->req_id)) {
948 			free(prs->secure->req_id);
949 			prs->secure->req_id = strdup(securep->req_id);
950 
951 			/*
952 			 * We calloc'd securep->reqid earlier, now we free it
953 			 * here because we no longer call 'freesecure' from
954 			 * Putsecure() if we use a static structure
955 			 */
956 
957 			free(securep->req_id);
958 		} else {
959 			note("request_by_id failed\n");
960 			return (MUNKNOWN);
961 		}
962 
963 		/*
964 		 * If the request was being filtered or was printing,
965 		 * it would have been stopped in "validate_request()",
966 		 * but only if it has to be refiltered. Thus, the
967 		 * filtering has been stopped if it has to be stopped,
968 		 * but the printing may still be going.
969 		 */
970 		if (rp->request->outcome & RS_PRINTING &&
971 		    !(rp->request->outcome & RS_STOPPED)) {
972 			rp->request->outcome |= RS_STOPPED;
973 			terminate(oldexec);
974 		}
975 
976 		maybe_schedule(rp);
977 		return (MOK);
978 	}
979 
980 	Free(rp->request->destination);
981 	rp->request->destination = olddest;
982 	return (stat);
983 }
984 
985 /*
986  * s_move_request()
987  */
988 
989 void
990 s_move_request(char *m, MESG *md)
991 {
992 	RSTATUS	*rp;
993 	short	err;
994 	char	*req_id;
995 	char	*dest;
996 
997 	(void) getmessage(m, S_MOVE_REQUEST, &req_id, &dest);
998 	syslog(LOG_DEBUG, "s_move_request(%s, %s)", (req_id ? req_id : "NULL"),
999 	    (dest ? dest : "NULL"));
1000 
1001 
1002 	if (!(search_pstatus(dest)) && !(search_cstatus(dest))) {
1003 		mputm(md, R_MOVE_REQUEST, MNODEST, 0L);
1004 		return;
1005 	}
1006 
1007 	if ((rp = request_by_id(req_id))) {
1008 		if (STREQU(rp->request->destination, dest)) {
1009 			mputm(md, R_MOVE_REQUEST, MOK, 0L);
1010 			return;
1011 		}
1012 		if (rp->request->outcome & (RS_DONE|RS_NOTIFYING)) {
1013 			mputm(md, R_MOVE_REQUEST, M2LATE, 0L);
1014 			return;
1015 		}
1016 		if (rp->request->outcome & RS_CHANGING)	{
1017 			mputm(md, R_MOVE_REQUEST, MBUSY, 0L);
1018 			return;
1019 		}
1020 		if ((err = mv_file(rp, dest)) == MOK) {
1021 			mputm(md, R_MOVE_REQUEST, MOK, 0L);
1022 			return;
1023 		}
1024 		mputm(md, R_MOVE_REQUEST, err, chkprinter_result);
1025 		return;
1026 	}
1027 	mputm(md, R_MOVE_REQUEST, MUNKNOWN, 0L);
1028 }
1029 
1030 /*
1031  * s_move_dest()
1032  */
1033 
1034 void
1035 s_move_dest(char *m, MESG *md)
1036 {
1037 	char		*dest;
1038 	char		*fromdest;
1039 	RSTATUS		*rp;
1040 	char		*found = (char *)0;
1041 	short		num_ok = 0;
1042 
1043 	(void) getmessage(m, S_MOVE_DEST, &fromdest, &dest);
1044 	syslog(LOG_DEBUG, "s_move_dest(%s, %s)", (fromdest ? fromdest : "NULL"),
1045 	    (dest ? dest : "NULL"));
1046 
1047 	if (!search_pstatus(fromdest) && !search_cstatus(fromdest)) {
1048 		mputm(md, R_MOVE_DEST, MNODEST, fromdest, 0);
1049 		return;
1050 	}
1051 
1052 	if (!(search_pstatus(dest)) && !(search_cstatus(dest))) {
1053 		mputm(md, R_MOVE_DEST, MNODEST, dest, 0);
1054 		return;
1055 	}
1056 
1057 	if (STREQU(dest, fromdest)) {
1058 		mputm(md, R_MOVE_DEST, MOK, "", 0);
1059 		return;
1060 	}
1061 
1062 	for (rp = Request_List; rp != NULL; rp = rp->next) {
1063 		if ((STREQU(rp->request->destination, fromdest)) &&
1064 		    (!(rp->request->outcome &
1065 		    (RS_DONE|RS_CHANGING|RS_NOTIFYING)))) {
1066 			if (mv_file(rp, dest) == MOK) {
1067 				num_ok++;
1068 				continue;
1069 			}
1070 		}
1071 
1072 		if (found)
1073 			mputm(md, R_MOVE_DEST, MMORERR, found, 0);
1074 
1075 		found = rp->secure->req_id;
1076 	}
1077 
1078 	if (found)
1079 		mputm(md, R_MOVE_DEST, MERRDEST, found, num_ok);
1080 	else
1081 		mputm(md, R_MOVE_DEST, MOK, "", num_ok);
1082 }
1083 
1084 /*
1085  * reqpath
1086  */
1087 
1088 static char *
1089 reqpath(char *file, char **idnumber)
1090 {
1091 	char	*path;
1092 	char	*cp;
1093 	char	*cp2;
1094 
1095 	/*
1096 	 *	/var/spool/lp/tmp/machine/123-0
1097 	 *	/var/spool/lp/temp/123-0
1098 	 *	/usr/spool/lp/temp/123-0
1099 	 *	/usr/spool/lp/tmp/machine/123-0
1100 	 *	123-0
1101 	 *	machine/123-0
1102 	 *
1103 	 *	/var/spool/lp/tmp/machine/123-0 + 123
1104 	 */
1105 	if (*file == '/') {
1106 		/*CONSTCOND*/
1107 		if (STRNEQU(file, Lp_Spooldir, strlen(Lp_Spooldir)))
1108 			cp = file + strlen(Lp_Spooldir) + 1;
1109 		else {
1110 			if (STRNEQU(file, "/usr/spool/lp", 13))
1111 				cp = file + strlen("/usr/spool/lp") + 1;
1112 			else {
1113 				*idnumber = NULL;
1114 				return (NULL);
1115 			}
1116 		}
1117 
1118 		if (STRNEQU(cp, "temp", 4)) {
1119 			cp += 5;
1120 			path = makepath(Local_System, cp, NULL);
1121 		}
1122 		else
1123 			path = Strdup(cp);
1124 	}
1125 	else
1126 	{
1127 		if (strchr(file, '/'))
1128 			path = makepath(file, NULL);
1129 		else
1130 			path = makepath(Local_System, file, NULL);
1131 	}
1132 
1133 	cp = strrchr(path, '/');
1134 	cp++;
1135 	if ((cp2 = strrchr(cp, '-')) == NULL)
1136 		*idnumber = Strdup(cp);
1137 	else
1138 	{
1139 		*cp2 = '\0';
1140 		*idnumber = Strdup(cp);
1141 		*cp2 = '-';
1142 	}
1143 
1144 	return (path);
1145 }
1146 
1147 /*
1148  * The client is sending a peer connection to retrieve label information
1149  * from.  This is used in the event that the client is an intermediary for
1150  * the actual requestor in a Trusted environment.
1151  */
1152 void
1153 s_pass_peer_connection(char *m, MESG *md)
1154 {
1155 	short	status = MTRANSMITERR;
1156 	char	*dest;
1157 	struct strrecvfd recv_fd;
1158 
1159 	(void) getmessage(m, S_PASS_PEER_CONNECTION);
1160 	syslog(LOG_DEBUG, "s_pass_peer_connection()");
1161 
1162 	memset(&recv_fd, NULL, sizeof (recv_fd));
1163 	if (ioctl(md->readfd, I_RECVFD, &recv_fd) == 0) {
1164 		int fd = recv_fd.fd;
1165 
1166 		if (get_peer_label(fd, &md->slabel) == 0) {
1167 			if (md->admin == 1)
1168 				md->admin = -1; /* turn off query privilege */
1169 			status = MOK;
1170 		}
1171 
1172 		close(fd);
1173 	}
1174 
1175 	mputm(md, R_PASS_PEER_CONNECTION, status);
1176 }
1177