xref: /csrg-svn/usr.sbin/chown/chown.c (revision 34069)
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*34069Sbostic static char sccsid[] = "@(#)chown.c	5.10 (Berkeley) 04/23/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;
3234056Sbostic 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 	}
9434056Sbostic 	for (gname = s; *s && isdigit(*s); ++s);
9534039Sbostic 	if (!*s)
9634056Sbostic 		gid = atoi(gname);
9734039Sbostic 	else {
9834056Sbostic 		if (!(gr = getgrnam(gname))) {
9934039Sbostic 			if (fflag)
10034039Sbostic 				exit(0);
10134039Sbostic 			fprintf(stderr, "%s: unknown group id: %s\n",
10234056Sbostic 			    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 
14234056Sbostic 	if (chown(file, uid, gid)) {
143*34069Sbostic 		chownerr(file);
14434039Sbostic 		return;
14528349Smckusick 	}
14634056Sbostic 	if (!rflag)
14734056Sbostic 		return;
14834056Sbostic 	if (lstat(file, &buf)) {
14934056Sbostic 		err(file);
15034056Sbostic 		return;
15134056Sbostic 	}
15234056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
15334039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
15434039Sbostic 			err(file);
15534039Sbostic 			return;
15618450Smckusick 		}
15734039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
15834039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
15934039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
16034039Sbostic 				continue;
16134039Sbostic 			change(dp->d_name);
16224505Ssam 		}
16334039Sbostic 		closedir(dirp);
16434039Sbostic 		if (chdir("..")) {
16534039Sbostic 			err("..");
16634039Sbostic 			exit(fflag ? 0 : -1);
16734039Sbostic 		}
16818450Smckusick 	}
16918450Smckusick }
17024505Ssam 
17134039Sbostic static
172*34069Sbostic chownerr(file)
173*34069Sbostic 	char *file;
174*34069Sbostic {
175*34069Sbostic 	static int euid = -1, ngroups = -1;
176*34069Sbostic 
177*34069Sbostic 	/* check for chown without being root */
178*34069Sbostic 	if (uid != -1 && euid == -1 && (euid = geteuid())) {
179*34069Sbostic 		if (fflag)
180*34069Sbostic 			exit(0);
181*34069Sbostic 		err(file);
182*34069Sbostic 		exit(-1);
183*34069Sbostic 	}
184*34069Sbostic 	/* check group membership; kernel just returns EPERM */
185*34069Sbostic 	if (gid != -1 && ngroups == -1) {
186*34069Sbostic 		int groups[NGROUPS];
187*34069Sbostic 
188*34069Sbostic 		ngroups = getgroups(NGROUPS, groups);
189*34069Sbostic 		while (--ngroups >= 0 && gid != groups[ngroups]);
190*34069Sbostic 		if (ngroups < 0) {
191*34069Sbostic 			if (fflag)
192*34069Sbostic 				exit(0);
193*34069Sbostic 			fprintf(stderr,
194*34069Sbostic 			    "%s: you are not a member of group %s.\n",
195*34069Sbostic 			    myname, gname);
196*34069Sbostic 			exit(-1);
197*34069Sbostic 		}
198*34069Sbostic 	}
199*34069Sbostic 	err(file);
200*34069Sbostic }
201*34069Sbostic 
202*34069Sbostic static
20334039Sbostic err(s)
20434039Sbostic 	char *s;
20524505Ssam {
20634039Sbostic 	if (fflag)
20734039Sbostic 		return;
20834056Sbostic 	fprintf(stderr, "%s: ", myname);
20934039Sbostic 	perror(s);
21034039Sbostic 	retval = -1;
21124505Ssam }
21224505Ssam 
21334039Sbostic static
21434039Sbostic usage()
21524505Ssam {
21634039Sbostic 	fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
21734039Sbostic 	    ischown ? "owner[.group]" : "group");
21834039Sbostic 	exit(-1);
21924505Ssam }
220