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