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