xref: /csrg-svn/usr.sbin/chown/chown.c (revision 38427)
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
634777Sbostic  * provided that the above copyright notice and this paragraph are
734777Sbostic  * duplicated in all such forms and that any documentation,
834777Sbostic  * advertising materials, and other materials related to such
934777Sbostic  * distribution and use acknowledge that the software was developed
1034777Sbostic  * by the University of California, Berkeley.  The name of the
1134777Sbostic  * University may not be used to endorse or promote products derived
1234777Sbostic  * from this software without specific prior written permission.
1334777Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434777Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534777Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622488Sdist  */
1718450Smckusick 
1822488Sdist #ifndef lint
1922488Sdist char copyright[] =
2034039Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\
2122488Sdist  All rights reserved.\n";
2234039Sbostic #endif /* not lint */
2322488Sdist 
2422488Sdist #ifndef lint
25*38427Sbostic static char sccsid[] = "@(#)chown.c	5.13 (Berkeley) 07/07/89";
2634039Sbostic #endif /* not lint */
2722488Sdist 
2834039Sbostic #include <sys/param.h>
29975Sbill #include <sys/stat.h>
30*38427Sbostic #include <sys/errno.h>
31*38427Sbostic #include <dirent.h>
32975Sbill #include <pwd.h>
3318450Smckusick #include <grp.h>
3434039Sbostic #include <stdio.h>
3534039Sbostic #include <ctype.h>
36975Sbill 
3734039Sbostic static int ischown, uid, gid, fflag, rflag, retval;
3834056Sbostic static char *gname, *myname;
39975Sbill 
40975Sbill main(argc, argv)
4134039Sbostic 	int argc;
4234039Sbostic 	char **argv;
43975Sbill {
4434039Sbostic 	extern char *optarg;
4534039Sbostic 	extern int optind;
4634039Sbostic 	register char *cp;
4734039Sbostic 	int ch;
4836959Sbostic 	char curpath[MAXPATHLEN], *reset, *index(), *rindex();
49975Sbill 
5034039Sbostic 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
5134039Sbostic 	ischown = myname[2] == 'o';
5224505Ssam 
5334039Sbostic 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
5434039Sbostic 		switch((char)ch) {
5534039Sbostic 		case 'R':
5634039Sbostic 			rflag++;
5734039Sbostic 			break;
5824505Ssam 		case 'f':
5924505Ssam 			fflag++;
6024505Ssam 			break;
6134039Sbostic 		case '?':
6234039Sbostic 		default:
6334039Sbostic 			usage();
6434039Sbostic 		}
6534039Sbostic 	argv += optind;
6634039Sbostic 	argc -= optind;
6724505Ssam 
6834039Sbostic 	if (argc < 2)
6934039Sbostic 		usage();
7024505Ssam 
7134039Sbostic 	if (ischown) {
7234039Sbostic 		if (cp = index(*argv, '.')) {
7334039Sbostic 			*cp++ = '\0';
7434039Sbostic 			setgid(cp);
7524505Ssam 		}
7634039Sbostic 		else
7734039Sbostic 			gid = -1;
7834039Sbostic 		setuid(*argv);
7924505Ssam 	}
8034039Sbostic 	else {
8134039Sbostic 		uid = -1;
8234039Sbostic 		setgid(*argv);
83975Sbill 	}
8434039Sbostic 
8536959Sbostic 	while (*++argv) {
8636959Sbostic 		if (reset = index(*argv, '/'))
8736959Sbostic 			(void)getwd(curpath);
8834039Sbostic 		change(*argv);
8936959Sbostic 		if (reset && chdir(curpath)) {
9036959Sbostic 			if (fflag)
9136959Sbostic 				exit(0);
9236959Sbostic 			err(curpath);
9336959Sbostic 			exit(-1);
9436959Sbostic 		}
9536959Sbostic 	}
9634039Sbostic 	exit(retval);
9734039Sbostic }
9834039Sbostic 
9934039Sbostic static
10034039Sbostic setgid(s)
10134039Sbostic 	register char *s;
10234039Sbostic {
10334039Sbostic 	struct group *gr, *getgrnam();
10434039Sbostic 
10534039Sbostic 	if (!*s) {
10634039Sbostic 		gid = -1;			/* argument was "uid." */
10734039Sbostic 		return;
10811442Smckusick 	}
10934056Sbostic 	for (gname = s; *s && isdigit(*s); ++s);
11034039Sbostic 	if (!*s)
11134056Sbostic 		gid = atoi(gname);
11234039Sbostic 	else {
11334056Sbostic 		if (!(gr = getgrnam(gname))) {
11434039Sbostic 			if (fflag)
11534039Sbostic 				exit(0);
116*38427Sbostic 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
11734056Sbostic 			    myname, gname);
11834039Sbostic 			exit(-1);
11918450Smckusick 		}
12034039Sbostic 		gid = gr->gr_gid;
121975Sbill 	}
122975Sbill }
123975Sbill 
12434039Sbostic static
12534039Sbostic setuid(s)
12634039Sbostic 	register char *s;
127975Sbill {
12834039Sbostic 	struct passwd *pwd, *getpwnam();
12934039Sbostic 	char *beg;
130975Sbill 
13134039Sbostic 	if (!*s) {
13234039Sbostic 		uid = -1;			/* argument was ".gid" */
13334039Sbostic 		return;
13434039Sbostic 	}
13534039Sbostic 	for (beg = s; *s && isdigit(*s); ++s);
13634039Sbostic 	if (!*s)
13734039Sbostic 		uid = atoi(beg);
13834039Sbostic 	else {
13934039Sbostic 		if (!(pwd = getpwnam(beg))) {
14034039Sbostic 			if (fflag)
14134039Sbostic 				exit(0);
142*38427Sbostic 			(void)fprintf(stderr,
143*38427Sbostic 			    "chown: unknown user id: %s\n", beg);
14434039Sbostic 			exit(-1);
14534039Sbostic 		}
14634039Sbostic 		uid = pwd->pw_uid;
14734039Sbostic 	}
148975Sbill }
14918450Smckusick 
15034039Sbostic static
15134039Sbostic change(file)
15234039Sbostic 	char *file;
15318450Smckusick {
15424505Ssam 	register DIR *dirp;
155*38427Sbostic 	register struct dirent *dp;
15634039Sbostic 	struct stat buf;
15718450Smckusick 
15834056Sbostic 	if (chown(file, uid, gid)) {
15934069Sbostic 		chownerr(file);
16034039Sbostic 		return;
16128349Smckusick 	}
16234056Sbostic 	if (!rflag)
16334056Sbostic 		return;
16434056Sbostic 	if (lstat(file, &buf)) {
16534056Sbostic 		err(file);
16634056Sbostic 		return;
16734056Sbostic 	}
16834056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
16934039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
17034039Sbostic 			err(file);
17134039Sbostic 			return;
17218450Smckusick 		}
17334039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
17434039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
17534039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
17634039Sbostic 				continue;
17734039Sbostic 			change(dp->d_name);
17824505Ssam 		}
17934039Sbostic 		closedir(dirp);
18034039Sbostic 		if (chdir("..")) {
18134039Sbostic 			err("..");
18234039Sbostic 			exit(fflag ? 0 : -1);
18334039Sbostic 		}
18418450Smckusick 	}
18518450Smckusick }
18624505Ssam 
18734039Sbostic static
18834069Sbostic chownerr(file)
18934069Sbostic 	char *file;
19034069Sbostic {
191*38427Sbostic 	extern int errno;
19234069Sbostic 	static int euid = -1, ngroups = -1;
19334069Sbostic 
19434069Sbostic 	/* check for chown without being root */
195*38427Sbostic 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
19634069Sbostic 		if (fflag)
19734069Sbostic 			exit(0);
19834069Sbostic 		err(file);
19934069Sbostic 		exit(-1);
20034069Sbostic 	}
20134069Sbostic 	/* check group membership; kernel just returns EPERM */
20234069Sbostic 	if (gid != -1 && ngroups == -1) {
20334069Sbostic 		int groups[NGROUPS];
20434069Sbostic 
20534069Sbostic 		ngroups = getgroups(NGROUPS, groups);
20634069Sbostic 		while (--ngroups >= 0 && gid != groups[ngroups]);
20734069Sbostic 		if (ngroups < 0) {
20834069Sbostic 			if (fflag)
20934069Sbostic 				exit(0);
210*38427Sbostic 			(void)fprintf(stderr,
21134069Sbostic 			    "%s: you are not a member of group %s.\n",
21234069Sbostic 			    myname, gname);
21334069Sbostic 			exit(-1);
21434069Sbostic 		}
21534069Sbostic 	}
21634069Sbostic 	err(file);
21734069Sbostic }
21834069Sbostic 
21934069Sbostic static
22034039Sbostic err(s)
22134039Sbostic 	char *s;
22224505Ssam {
22336959Sbostic 	extern int errno;
22436959Sbostic 	char *strerror();
22536959Sbostic 
22634039Sbostic 	if (fflag)
22734039Sbostic 		return;
228*38427Sbostic 	(void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
22934039Sbostic 	retval = -1;
23024505Ssam }
23124505Ssam 
23234039Sbostic static
23334039Sbostic usage()
23424505Ssam {
235*38427Sbostic 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
23634039Sbostic 	    ischown ? "owner[.group]" : "group");
23734039Sbostic 	exit(-1);
23824505Ssam }
239