1/***************************************************************************
2 * LPRng - An Extended Print Spooler System
3 *
4 * Copyright 1988-2003, Patrick Powell, San Diego, CA
5 *     papowell@lprng.com
6 * See LICENSE for conditions of use.
7 *
8 ***************************************************************************/
9
10 static char *const _id =
11"$Id: lpd_remove.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
12
13
14#include "lp.h"
15#include "lpd_remove.h"
16#include "getqueue.h"
17#include "getprinter.h"
18#include "gethostinfo.h"
19#include "getopt.h"
20#include "permission.h"
21#include "child.h"
22#include "proctitle.h"
23#include "fileopen.h"
24#include "sendreq.h"
25/**** ENDINCLUDE ****/
26
27/***************************************************************************
28 * Commentary:
29 * Patrick Powell Tue May  2 09:32:50 PDT 1995
30 *
31 * Remove a Job.
32 * This is very similar to the status program.
33 *
34 * 1. We check for permissions first
35 *    - first we check to see if the remote host has permissions
36 *    - next we check to see if the user has permissions
37 * Note:
38 *   if we have control permissions,  then we can remove any job.
39 *   Normally,  the options passed are 'user jobnumber' and we
40 *   use the user name and/or job number to select them.  When we have
41 *   control permissions,  we are not restricted to our own jobs.
42 *     so: if we have control permissions,  AND pass an option, we
43 *         do not check for our name.
44 *         if we have control permissions AND we do not pass an option,
45 *         we check for our name.
46 *
47 *  we have \006printer user key key key
48 *              0       1    2 ...        index
49 ***************************************************************************/
50
51int Job_remove( int *sock, char *input )
52{
53printf("Job_remove\n");//JY
54#if !defined(JYWENG20031106remove)
55	if( input && *input ) ++input;//JY1114
56
57	if(get_queue_name(input))
58	{
59		printf("QueueName is not LPRServer\n");
60		send_ack_packet(sock, ACK_FAIL);//JY1120
61		return(0);
62	}
63	else
64		printf("QueueName is LPRServer\n");
65
66	if(lptstatus.pid != 0){
67		check_prn_status(ONLINE, "");
68		kill(lptstatus.pid, SIGKILL);
69	}
70	else
71		return(0);
72#endif
73
74#ifdef REMOVE
75	char error[LINEBUFFER];
76	int i;
77	char *name, *s, *user = 0;
78	struct line_list tokens, done_list;
79
80	Init_line_list(&tokens);
81	Init_line_list(&done_list);
82	Name = "Job_remove";
83
84	/* get the options */
85	++input;
86	DEBUGF(DLPRM1)("Job_remove: input '%s'", input );
87	Split(&tokens,input,Whitespace,0,0,0,0,0,0);
88#ifdef ORIGINAL_DEBUG//JY@1020
89	DEBUGFC(DLPRM2)Dump_line_list("Job_remove: input", &tokens );
90#endif
91
92	/* check printername for characters, underscore, digits */
93
94	if( tokens.count < 2 ){
95		SNPRINTF( error, sizeof(error))
96			_("missing user or printer name"));
97		goto error;
98	}
99	name = tokens.list[0];
100
101	DEBUGF(DLPRM1)("Job_remove: checking '%s'", name );
102	if( (s = Is_clean_name( name )) ){
103		SNPRINTF( error, sizeof(error))
104			_("printer '%s' has illegal character at '%s' in name"), name, s );
105		goto error;
106	}
107	DEBUGF(DLPRM1)("Job_remove: result '%s'", name );
108	Set_DYN(&Printer_DYN,name);
109
110	user = safestrdup(tokens.list[1],__FILE__,__LINE__);
111	Perm_check.remoteuser = user;
112
113	/* remove the first two tokens */
114	Remove_line_list(&tokens,1);
115	Remove_line_list(&tokens,0);
116	Check_max(&tokens,1);
117	tokens.list[tokens.count] = 0;
118
119	if( safestrcmp( Printer_DYN, ALL ) ){
120		DEBUGF(DLPRM2)( "Job_remove: checking printcap entry '%s'",  Printer_DYN );
121		Set_DYN(&Printer_DYN, Printer_DYN );
122		Get_queue_remove( user, sock, &tokens, &done_list );
123	} else {
124/*1103
125		Get_all_printcap_entries();
126		for( i = 0; i < All_line_list.count; ++i ){
127			Set_DYN(&Printer_DYN, All_line_list.list[i]);
128			Get_queue_remove( user, sock, &tokens, &done_list );
129		}
130*/
131	}
132	goto done;
133
134 error:
135	LOGMSG( LOG_INFO) _("Job_remove: error '%s'"), error );
136	DEBUGF(DLPRM2)("Job_remove: error msg '%s'", error );
137	safestrncat(error,"\n");
138	if( Write_fd_str( *sock, error ) < 0 ) cleanup(0);
139 done:
140	DEBUGF(DLPRM2)( "Job_remove: done" );
141	if( user ) free(user); user = 0;
142	Free_line_list(&done_list);
143	Free_line_list(&tokens);
144#endif
145	return( 0 );
146}
147
148#ifdef REMOVE
149/***************************************************************************
150 * void Get_queue_remove
151 *  - find and remove the spool queue entries
152 ***************************************************************************/
153
154void Get_queue_remove( char *user, int *sock, struct line_list *tokens,
155	struct line_list *done_list )
156{
157	char msg[SMALLBUFFER], header[SMALLBUFFER];
158	int control_perm, permission, count, removed, status,
159		i, c = 0, pid, fd;
160	char *s, *identifier;
161	struct stat statb;
162	struct line_list info, active_pid;
163	struct job job;
164
165	Init_line_list(&info);
166	Init_line_list(&active_pid);
167	Init_job(&job);
168
169	/* set printer name and printcap variables */
170
171#ifdef ORIGINAL_DEBUG//JY@1020
172	DEBUGFC(DLPRM2)Dump_line_list("Get_queue_remove - tokens", tokens );
173	DEBUGF(DLPRM2)( "Get_queue_remove: user '%s', printer '%s'",
174		user, Printer_DYN );
175#endif
176
177	Errorcode = 0;
178
179	setproctitle( "lpd LPRM '%s'", Printer_DYN );
180	/* first check to see if you have control permissions */
181
182	msg[0] = 0;
183	status = Setup_printer( Printer_DYN, msg, sizeof(msg), 0 );
184	if( status ){
185		if( msg[0] == 0 ){
186			DEBUGF(DLPRM2)("Get_queue_remove: cannot set up printer '%s'", Printer_DYN);
187		}
188		goto error;
189	}
190
191	c = Debug;
192	i = DbgFlag;
193	s = Find_str_value(&Spool_control,DEBUG,Value_sep);
194	if( !s ) s = New_debug_DYN;
195	Parse_debug( s, 0 );
196
197	if( !(DbgFlag & DLPRMMASK) ){
198		Debug = c;
199		DbgFlag = i;
200	} else {
201		i = Debug;
202		Debug = c;
203		if( Log_file_DYN ){
204			fd = Trim_status_file( -1, Log_file_DYN, Max_log_file_size_DYN,
205				Min_log_file_size_DYN );
206			if( fd > 0 && fd != 2 ){
207				dup2(fd,2);
208				close(fd);
209			}
210		}
211		Debug = i;
212	}
213
214	/* set up status */
215	if( Find_exists_value(done_list,Printer_DYN,Value_sep ) ){
216		return;
217	}
218	Add_line_list(done_list,Printer_DYN,Value_sep,1,1);
219
220	/* check for permissions */
221
222	Perm_check.service = 'C';
223	Perm_check.printer = Printer_DYN;
224	Perm_check.host = 0;
225	Perm_check.user = 0;
226
227	control_perm = Perms_check( &Perm_line_list, &Perm_check, 0, 0 );
228	DEBUGF(DLPRM2)("Job_status: permission '%s'", perm_str(control_perm));
229
230	if( control_perm != P_ACCEPT ) control_perm = 0;
231
232	SNPRINTF( msg, sizeof(msg)) _("Printer %s@%s:\n"),
233		Printer_DYN, ShortHost_FQDN );
234	Write_fd_str( *sock, msg );
235
236	Free_line_list( &Sort_order );
237	Scan_queue( &Spool_control, &Sort_order,0,0,0,0,0,0,0,0 );
238	DEBUGF(DLPRM2)("Get_queue_remove: total files %d", Sort_order.count );
239
240	/* scan the files to see if there is one which matches */
241	removed = 0;
242#ifdef ORIGINAL_DEBUG//JY@1020
243	DEBUGFC(DLPRM3)Dump_line_list("Get_queue_remove - tokens", tokens );
244#endif
245	for( count = 0; count < Sort_order.count; ++count ){
246		Free_job(&job);
247		Get_hold_file(&job, Sort_order.list[count] );
248
249#ifdef ORIGINAL_DEBUG//JY@1020
250		DEBUGFC(DLPRM3)Dump_job("Get_queue_remove - info",&job);
251#endif
252        if( tokens->count && Patselect( tokens, &job.info, 0) ){
253			continue;
254        }
255
256		/* get everything for the job now */
257		Setup_cf_info( &job, 0 );
258		identifier = Find_str_value(&job.info,IDENTIFIER,Value_sep);
259		if( !identifier ) identifier
260			= Find_str_value(&job.info,TRANSFERNAME,Value_sep);
261
262		DEBUGF(DLPRM3)("Get_queue_remove: matched '%s'", identifier );
263		SNPRINTF( msg, sizeof(msg)) _("  checking perms '%s'\n"),
264			identifier );
265		Write_fd_str( *sock, msg );
266
267
268		/* we check to see if we can remove this one if we are the user */
269		if( control_perm == 0 ){
270			/* now we get the user name and IP address */
271			Perm_check.user = Find_str_value(&job.info,LOGNAME,Value_sep);
272			Perm_check.host = 0;
273			if( (s = Find_str_value(&job.info,FROMHOST,Value_sep))
274				&& Find_fqdn( &PermHost_IP, s ) ){
275				Perm_check.host = &PermHost_IP;
276			}
277			Perm_check.service = 'M';
278			permission = Perms_check( &Perm_line_list, &Perm_check, &job, 1 );
279			if( permission == P_REJECT ){
280				SNPRINTF( msg, sizeof(msg)) _("  no permissions '%s'\n"),
281					identifier );
282				Write_fd_str( *sock, msg );
283				continue;
284			}
285		}
286
287		/* log this to the world */
288		DEBUGF(DLPRM4)("Get_queue_remove: removing '%s'", identifier );
289		SNPRINTF( msg, sizeof(msg)) _("  dequeued '%s'\n"), identifier );
290		Write_fd_str( *sock, msg );
291
292#ifdef ORIGINAL_DEBUG//JY@1020
293		setmessage( &job, "LPRM", "start" );
294#endif
295		if( Remove_job( &job ) ){
296#ifdef ORIGINAL_DEBUG//JY@1020
297			setmessage( &job, "LPRM", "fail" );
298#endif
299			SNPRINTF( msg, sizeof(msg))
300				_("error: could not remove '%s'"), identifier );
301			Write_fd_str( *sock, msg );
302			goto error;
303		}
304#ifdef ORIGINAL_DEBUG//JY@1020
305		setmessage( &job, "LPRM", "success" );
306#endif
307		if( (pid = Find_flag_value(&job.info,SERVER,Value_sep)) ){
308			DEBUGF(DLPRM4)("Get_queue_remove: active_pid %d", pid );
309			if( kill( pid, 0 ) == 0 ){
310				Check_max(&active_pid,1);
311				active_pid.list[active_pid.count++] = Cast_int_to_voidstar(pid);
312			}
313		}
314		++removed;
315		if( tokens->count == 0 ) break;
316	}
317	Free_line_list(&info);
318	Free_job(&job);
319	Free_line_list( &Sort_order );
320	if( removed ){
321		for( i = 0; i < active_pid.count; ++i ){
322			pid = Cast_ptr_to_int(active_pid.list[i]);
323			active_pid.list[i] = 0;
324			DEBUGF(DLPRM2)("Get_queue_remove: killing pid '%d' SIGHUP/SIGINT/SIGQUIT/SIGCONT", pid );
325			killpg( pid, SIGHUP );
326			kill( pid, SIGHUP );
327			killpg( pid, SIGINT );
328			kill( pid, SIGINT );
329			killpg( pid, SIGQUIT );
330			kill( pid, SIGQUIT );
331			killpg( pid, SIGCONT );
332			kill( pid, SIGCONT );
333		}
334		/* kill spooler process */
335
336		pid = 0;
337#if 0//1103
338		if( (fd = Checkread( Queue_lock_file_DYN, &statb )) >= 0 ){
339			pid = Read_pid( fd, (char *)0, 0 );
340			close( fd );
341		}
342#else
343#endif
344		DEBUGF(DLPRM2)("Get_queue_status: checking server pid %d", pid );
345		/* kill active spooler */
346		if( pid > 0 ){
347			kill( pid, SIGUSR2 );
348		}
349	}
350
351	if( Server_names_DYN ){
352		Free_line_list(&info);
353		Split(&info, Server_names_DYN, File_sep, 0,0,0,0,0,0);
354		for( i = 0; i < info.count; ++i ){
355			DEBUGF(DLPRM2)("Get_queue_status: getting subserver status '%s'",
356				info.list[i] );
357			Set_DYN(&Printer_DYN,info.list[i]);
358			Get_local_or_remote_remove( user, sock, tokens, done_list );
359			DEBUGF(DLPRM2)("Get_queue_status: finished subserver status '%s'",
360				info.list[i] );
361		}
362	} else if( Destinations_DYN ){
363		Free_line_list(&info);
364		Split(&info, Destinations_DYN, File_sep, 0,0,0,0,0,0);
365		for( i = 0; i < info.count; ++i ){
366			DEBUGF(DLPRM2)("Get_queue_status: getting destination status '%s'",
367				info.list[i] );
368			Set_DYN(&Printer_DYN,info.list[i]);
369			Get_local_or_remote_remove( user, sock, tokens, done_list );
370			DEBUGF(DLPRM2)("Get_queue_status: finished destination status '%s'",
371				info.list[i] );
372		}
373	} else if( RemoteHost_DYN ){
374		if( Find_fqdn( &LookupHost_IP, RemoteHost_DYN )
375			&& ( !Same_host(&LookupHost_IP,&Host_IP )
376				|| !Same_host(&LookupHost_IP,&Localhost_IP )) ){
377			DEBUGF(DLPQ1)("Get_local_or_remote_status: doing local");
378			if( safestrcmp(RemotePrinter_DYN, Printer_DYN) ){
379				Set_DYN(&Printer_DYN,RemotePrinter_DYN);
380				Get_queue_remove( user, sock, tokens, done_list );
381			} else {
382				SNPRINTF(msg,sizeof(msg))"Error: loop in printcap- %s@%s -> %s@%s\n",
383					Printer_DYN, FQDNHost_FQDN, RemotePrinter_DYN, RemoteHost_DYN );
384				Write_fd_str(*sock, msg );
385			}
386		} else {
387			/* put user name at start of list */
388			Check_max(tokens,2);
389			for( i = tokens->count; i > 0; --i ){
390				tokens->list[i] = tokens->list[i-1];
391			}
392			tokens->list[0] = user;
393			++tokens->count;
394			tokens->list[tokens->count] = 0;
395#ifdef ORIGINAL_DEBUG//JY@1020
396			fd = Send_request( 'M', REQ_REMOVE, tokens->list, Connect_timeout_DYN,
397				Send_query_rw_timeout_DYN, *sock );
398#endif
399			if( fd >= 0 ){
400				shutdown( fd, 1 );
401				while( (c = read(fd,msg,sizeof(msg))) > 0 ){
402					Write_fd_len(*sock,msg,c);
403				}
404				close(fd); fd = -1;
405			}
406			for( i = 0; i < tokens->count; ++i ){
407				tokens->list[i] = tokens->list[i+1];
408			}
409			--tokens->count;
410		}
411	}
412
413	DEBUGF(DLPRM2)("Get_queue_remove: finished '%s'", Printer_DYN );
414	goto done;
415
416 error:
417	DEBUGF(DLPRM2)("Get_queue_remove: error msg '%s'", msg );
418	SNPRINTF(header, sizeof(header)) "Printer: %s", Printer_DYN );
419	safestrncpy( header, _(" ERROR: ") );
420	safestrncat( header, msg );
421	safestrncat( header, "\n" );
422	Write_fd_str( *sock, header );
423 done:
424	active_pid.count = 0;
425	Free_line_list(&info);
426	Free_line_list(&active_pid);
427	Free_job(&job);
428	return;
429}
430
431void Get_local_or_remote_remove( char *user, int *sock,
432	struct line_list *tokens, struct line_list *done_list )
433{
434	char msg[LARGEBUFFER];
435	int fd, n, i;
436
437	/* we have to see if the host is on this machine */
438
439	if( !safestrchr(Printer_DYN,'@') ){
440		Get_queue_remove( user, sock, tokens, done_list );
441		return;
442	}
443/*1103
444	Fix_Rm_Rp_info(0,0);
445*/
446	/* now we look at the remote host */
447	if( Find_fqdn( &LookupHost_IP, RemoteHost_DYN )
448		&& ( !Same_host(&LookupHost_IP,&Host_IP )
449			|| !Same_host(&LookupHost_IP,&Localhost_IP )) ){
450		Get_queue_remove( user, sock, tokens, done_list );
451		return;
452	}
453	/* put user name at start of list */
454	Check_max(tokens,2);
455	for( i = tokens->count; i > 0; --i ){
456		tokens->list[i] = tokens->list[i-1];
457	}
458	tokens->list[0] = user;
459	++tokens->count;
460	tokens->list[tokens->count] = 0;
461#ifdef ORIGINAL_DEBUG//JY@1020
462	fd = Send_request( 'M', REQ_REMOVE, tokens->list, Connect_timeout_DYN,
463		Send_query_rw_timeout_DYN, *sock );
464#endif
465	if( fd >= 0 ){
466		shutdown( fd, 1 );
467		while( (n = read(fd,msg,sizeof(msg))) > 0 ){
468			Write_fd_len(*sock,msg,n);
469		}
470		close(fd); fd = -1;
471	}
472	for( i = 0; i < tokens->count; ++i ){
473		tokens->list[i] = tokens->list[i+1];
474	}
475	--tokens->count;
476}
477
478int Remove_file( char *openname )
479{
480	int fail = 0;
481	struct stat statb;
482
483	if( openname && stat( openname, &statb ) == 0 ){
484		DEBUGF(DLPRM3)("Remove_file: removing '%s'", openname );
485		if( unlink( openname ) || stat( openname, &statb ) == 0 ){
486			LOGERR(LOG_INFO) "Remove_file: unlink did not remove '%s'",
487				openname);
488			fail |= 1;
489		}
490	}
491	return( fail );
492}
493
494int Remove_job( struct job *job )
495{
496	int i;
497	int fail = 0;
498	char *identifier, *openname;
499	struct line_list *datafile;
500
501#ifdef ORIGINAL_DEBUG//JY@1020
502	DEBUGFC(DLPRM1)Dump_job("Remove_job",job);
503#endif
504#ifdef ORIGINAL_DEBUG//JY@1020
505	setmessage(job,STATE,"REMOVE");
506#endif
507	identifier = Find_str_value(&job->info,IDENTIFIER,Value_sep);
508#ifdef ORIGINAL_DEBUG//JY@1020
509	setmessage( job, TRACE, "remove START" );
510#endif
511	if( !identifier ){
512		identifier = Find_str_value(&job->info,TRANSFERNAME,Value_sep);
513	}
514
515	DEBUGF(DLPRM1)("Remove_job: identifier '%s'",identifier);
516	fail = 0;
517	for( i = 0; i < job->datafiles.count; ++i ){
518		datafile = (void *)job->datafiles.list[i];
519		openname = Find_str_value(datafile,OPENNAME,Value_sep);
520		fail |= Remove_file( openname );
521		openname = Find_str_value(datafile,TRANSFERNAME,Value_sep);
522		fail |= Remove_file( openname );
523	}
524	openname = Find_str_value(&job->info,OPENNAME,Value_sep);
525	fail |= Remove_file( openname );
526	openname = Find_str_value(&job->info,TRANSFERNAME,Value_sep);
527	fail |= Remove_file( openname );
528	openname = Find_str_value(&job->info,HF_NAME,Value_sep);
529	fail |= Remove_file( openname );
530
531	if( fail == 0 ){
532#ifdef ORIGINAL_DEBUG//JY@1020
533		setmessage( job, TRACE, "remove SUCCESS" );
534#endif
535	} else {
536#ifdef ORIGINAL_DEBUG//JY@1020
537		setmessage( job, TRACE, "remove FAILED" );
538#endif
539	}
540	if( Lpq_status_file_DYN ){
541		unlink(Lpq_status_file_DYN);
542	}
543	return( fail );
544}
545#endif
546
547
548