xref: /onnv-gate/usr/src/cmd/cron/atrm.c (revision 11115:bcfb2bb98fca)
1523Sbasabi /*
2*11115SNobutomo.Nakano@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3523Sbasabi  * Use is subject to license terms.
4523Sbasabi  */
5523Sbasabi 
60Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /*
110Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
120Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
130Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
140Sstevel@tonic-gate  */
150Sstevel@tonic-gate 
160Sstevel@tonic-gate /*
170Sstevel@tonic-gate  *	synopsis: atrm [-f] [-i] [-a] [[job #] [user] ...]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  *	Remove "at" jobs.
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate 
230Sstevel@tonic-gate #include <stdio.h>
240Sstevel@tonic-gate #include <pwd.h>
250Sstevel@tonic-gate #include <ctype.h>
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <dirent.h>
280Sstevel@tonic-gate #include <sys/file.h>
290Sstevel@tonic-gate #include <sys/stat.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <locale.h>
33523Sbasabi #include <strings.h>
344774Sas145665 #include <stdlib.h>
354774Sas145665 #include <libintl.h>
360Sstevel@tonic-gate #include "cron.h"
374774Sas145665 #include "getresponse.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate extern time_t	num();
400Sstevel@tonic-gate extern char	*errmsg();
414774Sas145665 extern void	audit_at_delete(char *, char *, int);
420Sstevel@tonic-gate 
43523Sbasabi #define	SUPERUSER	0			/* is user super-user? */
44523Sbasabi #define	CANTCD		"can't change directory to the at directory"
45523Sbasabi #define	NOREADDIR	"can't read the at directory"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate uid_t user;					/* person requesting removal */
480Sstevel@tonic-gate int fflag = 0;					/* suppress announcements? */
490Sstevel@tonic-gate int iflag = 0;					/* run interactively? */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate char login[UNAMESIZE];
520Sstevel@tonic-gate char login_authchk[UNAMESIZE]; /* used for authorization checks */
530Sstevel@tonic-gate 
54523Sbasabi #define	INVALIDUSER	"you are not a valid user (no entry in /etc/passwd)"
55523Sbasabi #define	NOTALLOWED	"you are not authorized to use at.  Sorry."
560Sstevel@tonic-gate #define	NAMETOOLONG	"login name too long"
570Sstevel@tonic-gate 
58523Sbasabi static void usage(void);
59523Sbasabi static void atabortperror(char *msg);
60523Sbasabi static void atabort(char *msg);
61523Sbasabi static void atperror(char *msg);
62523Sbasabi static void atperror2(char *msg, char *name);
63523Sbasabi static void aterror(char *msg);
64523Sbasabi static void powner(char *file);
650Sstevel@tonic-gate 
664774Sas145665 int	getjoblist(struct dirent ***, struct stat ***, int (*)());
674774Sas145665 int	removentry(char *, struct stat *, uid_t);
684774Sas145665 
69523Sbasabi int
main(int argc,char ** argv)70523Sbasabi main(int argc, char **argv)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate 	int i;				/* for loop index */
730Sstevel@tonic-gate 	int numjobs;			/* # of jobs in spooling area */
740Sstevel@tonic-gate 	int allflag = 0;		/* remove all jobs belonging to user? */
750Sstevel@tonic-gate 	int jobexists;			/* does a requested job exist? */
760Sstevel@tonic-gate 	char *pp;
770Sstevel@tonic-gate 	struct dirent **namelist;	/* names of jobs in spooling area */
780Sstevel@tonic-gate 	struct stat **statlist;
790Sstevel@tonic-gate 	struct passwd *pwd;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	/*
820Sstevel@tonic-gate 	 * If job number, user name, or "-" is not specified, just print
830Sstevel@tonic-gate 	 * usage info and exit.
840Sstevel@tonic-gate 	 */
85523Sbasabi 	(void) setlocale(LC_ALL, "");
864774Sas145665 	(void) textdomain(TEXT_DOMAIN);
870Sstevel@tonic-gate 	if (argc < 2)
880Sstevel@tonic-gate 		usage();
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	--argc; ++argv;
910Sstevel@tonic-gate 
92523Sbasabi 	pp = getuser((user = getuid()));
930Sstevel@tonic-gate 	if (pp == NULL)
940Sstevel@tonic-gate 		atabort(INVALIDUSER);
950Sstevel@tonic-gate 	if (strlcpy(login, pp, sizeof (login)) >= sizeof (login))
960Sstevel@tonic-gate 		atabort(NAMETOOLONG);
970Sstevel@tonic-gate 	if (strlcpy(login_authchk, pp, sizeof (login_authchk))
980Sstevel@tonic-gate 	    >= sizeof (NAMETOOLONG))
990Sstevel@tonic-gate 		atabort(INVALIDUSER);
1000Sstevel@tonic-gate 	if (!allowed(login, ATALLOW, ATDENY))
1010Sstevel@tonic-gate 		atabort(NOTALLOWED);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/*
1040Sstevel@tonic-gate 	 * Process command line flags.
1050Sstevel@tonic-gate 	 * Special case the "-" option so that others may be grouped.
1060Sstevel@tonic-gate 	 */
1070Sstevel@tonic-gate 	while (argc > 0 && **argv == '-') {
1080Sstevel@tonic-gate 		*(*argv)++;
109523Sbasabi 		while (**argv) {
110523Sbasabi 			switch (*(*argv)++) {
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 			case 'a':	++allflag;
1130Sstevel@tonic-gate 					break;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 			case 'f':	++fflag;
1160Sstevel@tonic-gate 					break;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 			case 'i':	++iflag;
1190Sstevel@tonic-gate 					break;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 			default:	usage();
122523Sbasabi 			}
1230Sstevel@tonic-gate 		}
1240Sstevel@tonic-gate 		++argv; --argc;
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/*
128523Sbasabi 	 * If all jobs are to be removed and extra command line arguments
1290Sstevel@tonic-gate 	 * are given, print usage info and exit.
1300Sstevel@tonic-gate 	 */
131523Sbasabi 	if (allflag && argc)
1320Sstevel@tonic-gate 		usage();
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/*
1350Sstevel@tonic-gate 	 * If only certain jobs are to be removed and no job #'s or user
1360Sstevel@tonic-gate 	 * names are specified, print usage info and exit.
1370Sstevel@tonic-gate 	 */
138523Sbasabi 	if (!allflag && !argc)
1390Sstevel@tonic-gate 		usage();
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/*
1420Sstevel@tonic-gate 	 * If interactive removal and quiet removal are requested, override
1430Sstevel@tonic-gate 	 * quiet removal and run interactively.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	if (iflag && fflag)
1460Sstevel@tonic-gate 		fflag = 0;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/*
1500Sstevel@tonic-gate 	 * Move to spooling directory and get a list of the files in the
1510Sstevel@tonic-gate 	 * spooling area.
1520Sstevel@tonic-gate 	 */
153523Sbasabi 	numjobs = getjoblist(&namelist, &statlist, strcmp);
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * If all jobs belonging to the user are to be removed, compare
1560Sstevel@tonic-gate 	 * the user's id to the owner of the file. If they match, remove
1570Sstevel@tonic-gate 	 * the file. If the user is the super-user, don't bother comparing
1580Sstevel@tonic-gate 	 * the id's. After all files are removed, exit (status 0).
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	if (allflag) {
161523Sbasabi 		for (i = 0; i < numjobs; ++i) {
162*11115SNobutomo.Nakano@Sun.COM 			if (cron_admin(login_authchk) ||
1630Sstevel@tonic-gate 			    user == statlist[i]->st_uid)
1640Sstevel@tonic-gate 				(void) removentry(namelist[i]->d_name,
1650Sstevel@tonic-gate 				    statlist[i], user);
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 		exit(0);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/*
1710Sstevel@tonic-gate 	 * If only certain jobs are to be removed, interpret each command
1720Sstevel@tonic-gate 	 * line argument. A check is done to see if it is a user's name or
1730Sstevel@tonic-gate 	 * a job number (inode #). If it's a user's name, compare the argument
1740Sstevel@tonic-gate 	 * to the files owner. If it's a job number, compare the argument to
175523Sbasabi 	 * the file name. In either case, if a match occurs, try to
1760Sstevel@tonic-gate 	 * remove the file.
1770Sstevel@tonic-gate 	 */
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	while (argc--) {
1800Sstevel@tonic-gate 		jobexists = 0;
1810Sstevel@tonic-gate 		for (i = 0; i < numjobs; ++i) {
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 			/* if the inode number is 0, this entry was removed */
1840Sstevel@tonic-gate 			if (statlist[i]->st_ino == 0)
1850Sstevel@tonic-gate 				continue;
1860Sstevel@tonic-gate 
187523Sbasabi 			/*
1880Sstevel@tonic-gate 			 * if argv is a username, compare his/her uid to
1890Sstevel@tonic-gate 			 * the uid of the owner of the file......
1900Sstevel@tonic-gate 			 */
1910Sstevel@tonic-gate 			if (pwd = getpwnam(*argv)) {
1920Sstevel@tonic-gate 				if (statlist[i]->st_uid != pwd->pw_uid)
1930Sstevel@tonic-gate 					continue;
1940Sstevel@tonic-gate 			/*
1950Sstevel@tonic-gate 			 * otherwise, we assume that the argv is a job # and
1960Sstevel@tonic-gate 			 * thus compare argv to the file name.
1970Sstevel@tonic-gate 			 */
1980Sstevel@tonic-gate 			} else {
199523Sbasabi 				if (strcmp(namelist[i]->d_name, *argv))
2000Sstevel@tonic-gate 					continue;
2010Sstevel@tonic-gate 			}
2020Sstevel@tonic-gate 			++jobexists;
2030Sstevel@tonic-gate 			/*
2040Sstevel@tonic-gate 			 * if the entry is ultimately removed, don't
2050Sstevel@tonic-gate 			 * try to remove it again later.
2060Sstevel@tonic-gate 			 */
207523Sbasabi 			if (removentry(namelist[i]->d_name, statlist[i],
208523Sbasabi 			    user)) {
2090Sstevel@tonic-gate 				statlist[i]->st_ino = 0;
2100Sstevel@tonic-gate 			}
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 		/*
2140Sstevel@tonic-gate 		 * If a requested argument doesn't exist, print a message.
2150Sstevel@tonic-gate 		 */
2160Sstevel@tonic-gate 		if (!jobexists && !fflag) {
217523Sbasabi 			fprintf(stderr, "atrm: %s: no such job number\n",
218523Sbasabi 			    *argv);
2190Sstevel@tonic-gate 		}
2200Sstevel@tonic-gate 		++argv;
2210Sstevel@tonic-gate 	}
222523Sbasabi 	return (0);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate  * Print usage info and exit.
2270Sstevel@tonic-gate  */
228523Sbasabi static void
usage(void)229523Sbasabi usage(void)
2300Sstevel@tonic-gate {
231523Sbasabi 	fprintf(stderr, "usage: atrm [-f] [-i] [-a] [[job #] [user] ...]\n");
2320Sstevel@tonic-gate 	exit(1);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * Remove an entry from the queue. The access of the file is checked for
2380Sstevel@tonic-gate  * write permission (since all jobs are mode 644). If access is granted,
2390Sstevel@tonic-gate  * unlink the file. If the fflag (suppress announcements) is not set,
2400Sstevel@tonic-gate  * print the job number that we are removing and the result of the access
241523Sbasabi  * check (either "permission denied" or "removed"). If we are running
242523Sbasabi  * interactively (iflag), prompt the user before we unlink the file. If
243523Sbasabi  * the super-user is removing jobs, inform him/her who owns each file before
2440Sstevel@tonic-gate  * it is removed.  Return TRUE if file removed, else FALSE.
2450Sstevel@tonic-gate  */
2460Sstevel@tonic-gate int
removentry(char * filename,struct stat * statptr,uid_t user)247523Sbasabi removentry(char *filename, struct stat *statptr, uid_t user)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	struct passwd *pwd;
2500Sstevel@tonic-gate 	char *pp;
2510Sstevel@tonic-gate 	int r;
2520Sstevel@tonic-gate 
2534774Sas145665 	if (init_yes() < 0) {
2544774Sas145665 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
2554774Sas145665 		    strerror(errno));
2564774Sas145665 		exit(1);
2574774Sas145665 	}
2584774Sas145665 
2590Sstevel@tonic-gate 	if (!fflag)
260523Sbasabi 		printf("%s: ", filename);
2610Sstevel@tonic-gate 
262*11115SNobutomo.Nakano@Sun.COM 	if (user != statptr->st_uid && !cron_admin(login_authchk)) {
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (!fflag) {
2650Sstevel@tonic-gate 			printf("permission denied\n");
2660Sstevel@tonic-gate 		}
2670Sstevel@tonic-gate 		return (0);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	} else {
2700Sstevel@tonic-gate 		if (iflag) {
271*11115SNobutomo.Nakano@Sun.COM 			if (cron_admin(login_authchk)) {
2720Sstevel@tonic-gate 				printf("\t(owned by ");
2730Sstevel@tonic-gate 				powner(filename);
2740Sstevel@tonic-gate 				printf(") ");
2750Sstevel@tonic-gate 			}
2764774Sas145665 			printf(gettext("remove it? "));
2774774Sas145665 			if (yes() == 0)
2780Sstevel@tonic-gate 				return (0);
2790Sstevel@tonic-gate 		}
2800Sstevel@tonic-gate 
281*11115SNobutomo.Nakano@Sun.COM 		if (cron_admin(login_authchk)) {
282523Sbasabi 			pp = getuser((uid_t)statptr->st_uid);
2830Sstevel@tonic-gate 			if (pp == NULL)
2840Sstevel@tonic-gate 				atabort(INVALIDUSER);
2850Sstevel@tonic-gate 			if (strlcpy(login, pp, sizeof (login)) >=
2860Sstevel@tonic-gate 			    sizeof (login))
2870Sstevel@tonic-gate 				atabort(NAMETOOLONG);
2880Sstevel@tonic-gate 		}
289523Sbasabi 		cron_sendmsg(DELETE, login, filename, AT);
2900Sstevel@tonic-gate 		if ((r = unlink(filename)) < 0) {
2910Sstevel@tonic-gate 			if (!fflag) {
2920Sstevel@tonic-gate 				fputs("could not remove\n", stdout);
2930Sstevel@tonic-gate 				(void) fprintf(stderr, "atrm: %s: %s\n",
2940Sstevel@tonic-gate 				    filename, errmsg(errno));
2950Sstevel@tonic-gate 			}
2960Sstevel@tonic-gate 			audit_at_delete(filename, NULL, r);
2970Sstevel@tonic-gate 			return (0);
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate 		audit_at_delete(filename, NULL, r);
3000Sstevel@tonic-gate 		if (!fflag && !iflag)
3010Sstevel@tonic-gate 			printf("removed\n");
3020Sstevel@tonic-gate 		return (1);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate /*
3070Sstevel@tonic-gate  * Print the owner of the job. This is the owner of the spoolfile.
3080Sstevel@tonic-gate  * If we run into trouble getting the name, we'll just print "???".
3090Sstevel@tonic-gate  */
310523Sbasabi static void
powner(char * file)311523Sbasabi powner(char *file)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	struct stat statb;
3140Sstevel@tonic-gate 	char *getname();
3150Sstevel@tonic-gate 
316523Sbasabi 	if (stat(file, &statb) < 0) {
317523Sbasabi 		printf("%s", "???");
318523Sbasabi 		(void) fprintf(stderr, "atrm: Couldn't stat spoolfile %s: %s\n",
3190Sstevel@tonic-gate 		    file, errmsg(errno));
320523Sbasabi 		return;
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 
323523Sbasabi 	printf("%s", getname(statb.st_uid));
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate int
getjoblist(struct dirent *** namelistp,struct stat *** statlistp,int (* sortfunc)())328523Sbasabi getjoblist(struct dirent ***namelistp, struct stat ***statlistp,
329523Sbasabi     int (*sortfunc)())
3300Sstevel@tonic-gate {
331523Sbasabi 	int numjobs;
332523Sbasabi 	struct dirent **namelist;
333523Sbasabi 	int i;
334523Sbasabi 	struct stat *statptr;	/* pointer to file stat structure */
335523Sbasabi 	struct stat **statlist;
3360Sstevel@tonic-gate 	extern int filewanted();	/* should a file be listed in queue? */
3370Sstevel@tonic-gate 	if (chdir(ATDIR) < 0)
3380Sstevel@tonic-gate 		atabortperror(CANTCD);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/*
3410Sstevel@tonic-gate 	 * Get a list of the files in the spooling area.
3420Sstevel@tonic-gate 	 */
3436628Sjk217608 	if ((numjobs = scandir(".", namelistp, filewanted, sortfunc)) < 0)
3440Sstevel@tonic-gate 		atabortperror(NOREADDIR);
3450Sstevel@tonic-gate 
346523Sbasabi 	if ((statlist =
347523Sbasabi 	    (struct stat **)malloc(numjobs * sizeof (struct stat ***)))
348523Sbasabi 	    == NULL)
3490Sstevel@tonic-gate 		atabort("Out of memory");
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	namelist = *namelistp;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * Build an array of pointers to the file stats for all jobs in
3550Sstevel@tonic-gate 	 * the spooling area.
3560Sstevel@tonic-gate 	 */
357523Sbasabi 	for (i = 0; i < numjobs; ++i) {
358523Sbasabi 		statptr = (struct stat *)malloc(sizeof (struct stat));
3590Sstevel@tonic-gate 		if (statptr == NULL)
3600Sstevel@tonic-gate 			atabort("Out of memory");
3610Sstevel@tonic-gate 		if (stat(namelist[i]->d_name, statptr) < 0) {
362523Sbasabi 			atperror2("Can't stat", namelist[i]->d_name);
3630Sstevel@tonic-gate 			continue;
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 		statlist[i] = statptr;
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	*statlistp = statlist;
3690Sstevel@tonic-gate 	return (numjobs);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate  * Get the full login name of a person using his/her user id.
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate char *
getname(uid_t uid)376523Sbasabi getname(uid_t uid)
3770Sstevel@tonic-gate {
378523Sbasabi 	struct passwd *pwdinfo;		/* password info structure */
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if ((pwdinfo = getpwuid(uid)) == 0)
382523Sbasabi 		return ("???");
383523Sbasabi 	return (pwdinfo->pw_name);
384523Sbasabi }
385523Sbasabi 
386523Sbasabi static void
aterror(char * msg)387523Sbasabi aterror(char *msg)
388523Sbasabi {
389523Sbasabi 	fprintf(stderr, "atrm: %s\n", msg);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
392523Sbasabi static void
atperror(char * msg)393523Sbasabi atperror(char *msg)
3940Sstevel@tonic-gate {
395523Sbasabi 	fprintf(stderr, "atrm: %s: %s\n", msg, errmsg(errno));
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
398523Sbasabi static void
atperror2(char * msg,char * name)399523Sbasabi atperror2(char *msg, char *name)
4000Sstevel@tonic-gate {
401523Sbasabi 	fprintf(stderr, "atrm: %s %s: %s\n", msg, name, errmsg(errno));
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
404523Sbasabi static void
atabort(char * msg)405523Sbasabi atabort(char *msg)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 	aterror(msg);
4080Sstevel@tonic-gate 	exit(1);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
411523Sbasabi static void
atabortperror(char * msg)412523Sbasabi atabortperror(char *msg)
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate 	atperror(msg);
4150Sstevel@tonic-gate 	exit(1);
4160Sstevel@tonic-gate }
417