xref: /csrg-svn/usr.sbin/chown/chown.c (revision 34056)
122488Sdist /*
234039Sbostic  * Copyright (c) 1988 Regents of the University of California.
334039Sbostic  * All rights reserved.
434039Sbostic  *
534039Sbostic  * Redistribution and use in source and binary forms are permitted
634039Sbostic  * provided that this notice is preserved and that due credit is given
734039Sbostic  * to the University of California at Berkeley. The name of the University
834039Sbostic  * may not be used to endorse or promote products derived from this
934039Sbostic  * software without specific prior written permission. This software
1034039Sbostic  * is provided ``as is'' without express or implied warranty.
1122488Sdist  */
1218450Smckusick 
1322488Sdist #ifndef lint
1422488Sdist char copyright[] =
1534039Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\
1622488Sdist  All rights reserved.\n";
1734039Sbostic #endif /* not lint */
1822488Sdist 
1922488Sdist #ifndef lint
20*34056Sbostic static char sccsid[] = "@(#)chown.c	5.9 (Berkeley) 04/22/88";
2134039Sbostic #endif /* not lint */
2222488Sdist 
2334039Sbostic #include <sys/param.h>
24975Sbill #include <sys/stat.h>
2534039Sbostic #include <sys/dir.h>
26975Sbill #include <pwd.h>
2718450Smckusick #include <grp.h>
2834039Sbostic #include <stdio.h>
2934039Sbostic #include <ctype.h>
30975Sbill 
3134039Sbostic static int ischown, uid, gid, fflag, rflag, retval;
32*34056Sbostic static char *gname, *myname;
33975Sbill 
34975Sbill main(argc, argv)
3534039Sbostic 	int argc;
3634039Sbostic 	char **argv;
37975Sbill {
3834039Sbostic 	extern char *optarg;
3934039Sbostic 	extern int optind;
4034039Sbostic 	register char *cp;
4134039Sbostic 	int ch;
4234039Sbostic 	char *index(), *rindex();
43975Sbill 
4434039Sbostic 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
4534039Sbostic 	ischown = myname[2] == 'o';
4624505Ssam 
4734039Sbostic 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
4834039Sbostic 		switch((char)ch) {
4934039Sbostic 		case 'R':
5034039Sbostic 			rflag++;
5134039Sbostic 			break;
5224505Ssam 		case 'f':
5324505Ssam 			fflag++;
5424505Ssam 			break;
5534039Sbostic 		case '?':
5634039Sbostic 		default:
5734039Sbostic 			usage();
5834039Sbostic 		}
5934039Sbostic 	argv += optind;
6034039Sbostic 	argc -= optind;
6124505Ssam 
6234039Sbostic 	if (argc < 2)
6334039Sbostic 		usage();
6424505Ssam 
6534039Sbostic 	if (ischown) {
6634039Sbostic 		if (cp = index(*argv, '.')) {
6734039Sbostic 			*cp++ = '\0';
6834039Sbostic 			setgid(cp);
6924505Ssam 		}
7034039Sbostic 		else
7134039Sbostic 			gid = -1;
7234039Sbostic 		setuid(*argv);
7324505Ssam 	}
7434039Sbostic 	else {
7534039Sbostic 		uid = -1;
7634039Sbostic 		setgid(*argv);
77975Sbill 	}
7834039Sbostic 
7934039Sbostic 	while (*++argv)
8034039Sbostic 		change(*argv);
8134039Sbostic 	exit(retval);
8234039Sbostic }
8334039Sbostic 
8434039Sbostic static
8534039Sbostic setgid(s)
8634039Sbostic 	register char *s;
8734039Sbostic {
8834039Sbostic 	struct group *gr, *getgrnam();
8934039Sbostic 
9034039Sbostic 	if (!*s) {
9134039Sbostic 		gid = -1;			/* argument was "uid." */
9234039Sbostic 		return;
9311442Smckusick 	}
94*34056Sbostic 	for (gname = s; *s && isdigit(*s); ++s);
9534039Sbostic 	if (!*s)
96*34056Sbostic 		gid = atoi(gname);
9734039Sbostic 	else {
98*34056Sbostic 		if (!(gr = getgrnam(gname))) {
9934039Sbostic 			if (fflag)
10034039Sbostic 				exit(0);
10134039Sbostic 			fprintf(stderr, "%s: unknown group id: %s\n",
102*34056Sbostic 			    myname, gname);
10334039Sbostic 			exit(-1);
10418450Smckusick 		}
10534039Sbostic 		gid = gr->gr_gid;
106975Sbill 	}
107975Sbill }
108975Sbill 
10934039Sbostic static
11034039Sbostic setuid(s)
11134039Sbostic 	register char *s;
112975Sbill {
11334039Sbostic 	struct passwd *pwd, *getpwnam();
11434039Sbostic 	char *beg;
115975Sbill 
11634039Sbostic 	if (!*s) {
11734039Sbostic 		uid = -1;			/* argument was ".gid" */
11834039Sbostic 		return;
11934039Sbostic 	}
12034039Sbostic 	for (beg = s; *s && isdigit(*s); ++s);
12134039Sbostic 	if (!*s)
12234039Sbostic 		uid = atoi(beg);
12334039Sbostic 	else {
12434039Sbostic 		if (!(pwd = getpwnam(beg))) {
12534039Sbostic 			if (fflag)
12634039Sbostic 				exit(0);
12734039Sbostic 			fprintf(stderr, "chown: unknown user id: %s\n", beg);
12834039Sbostic 			exit(-1);
12934039Sbostic 		}
13034039Sbostic 		uid = pwd->pw_uid;
13134039Sbostic 	}
132975Sbill }
13318450Smckusick 
13434039Sbostic static
13534039Sbostic change(file)
13634039Sbostic 	char *file;
13718450Smckusick {
13824505Ssam 	register DIR *dirp;
13924505Ssam 	register struct direct *dp;
14034039Sbostic 	struct stat buf;
14118450Smckusick 
142*34056Sbostic 	if (chown(file, uid, gid)) {
143*34056Sbostic 		static int euid = -1, ngroups = -1;
144*34056Sbostic 
145*34056Sbostic 		if (uid != -1 && euid == -1 && (euid = geteuid())) {
146*34056Sbostic 			if (fflag)
147*34056Sbostic 				exit(0);
148*34056Sbostic 			err(file);
149*34056Sbostic 			exit(-1);
150*34056Sbostic 		}
151*34056Sbostic 		/* check group membership; kernel just returns EPERM */
152*34056Sbostic 		if (gid != -1 && ngroups == -1) {
153*34056Sbostic 			int groups[NGROUPS];
154*34056Sbostic 
155*34056Sbostic 			ngroups = getgroups(NGROUPS, groups);
156*34056Sbostic 			while (--ngroups >= 0 && gid != groups[ngroups]);
157*34056Sbostic 			if (ngroups < 0) {
158*34056Sbostic 				if (fflag)
159*34056Sbostic 					exit(0);
160*34056Sbostic 				fprintf(stderr,
161*34056Sbostic 				    "%s: you are not a member of group %s.\n",
162*34056Sbostic 				    myname, gname);
163*34056Sbostic 				exit(-1);
164*34056Sbostic 			}
165*34056Sbostic 		}
16634039Sbostic 		err(file);
16734039Sbostic 		return;
16828349Smckusick 	}
169*34056Sbostic 	if (!rflag)
170*34056Sbostic 		return;
171*34056Sbostic 	if (lstat(file, &buf)) {
172*34056Sbostic 		err(file);
173*34056Sbostic 		return;
174*34056Sbostic 	}
175*34056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
17634039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
17734039Sbostic 			err(file);
17834039Sbostic 			return;
17918450Smckusick 		}
18034039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
18134039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
18234039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
18334039Sbostic 				continue;
18434039Sbostic 			change(dp->d_name);
18524505Ssam 		}
18634039Sbostic 		closedir(dirp);
18734039Sbostic 		if (chdir("..")) {
18834039Sbostic 			err("..");
18934039Sbostic 			exit(fflag ? 0 : -1);
19034039Sbostic 		}
19118450Smckusick 	}
19218450Smckusick }
19324505Ssam 
19434039Sbostic static
19534039Sbostic err(s)
19634039Sbostic 	char *s;
19724505Ssam {
19834039Sbostic 	if (fflag)
19934039Sbostic 		return;
200*34056Sbostic 	fprintf(stderr, "%s: ", myname);
20134039Sbostic 	perror(s);
20234039Sbostic 	retval = -1;
20324505Ssam }
20424505Ssam 
20534039Sbostic static
20634039Sbostic usage()
20724505Ssam {
20834039Sbostic 	fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
20934039Sbostic 	    ischown ? "owner[.group]" : "group");
21034039Sbostic 	exit(-1);
21124505Ssam }
212