xref: /csrg-svn/usr.sbin/chown/chown.c (revision 36959)
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*36959Sbostic static char sccsid[] = "@(#)chown.c	5.12 (Berkeley) 03/05/89";
2634039Sbostic #endif /* not lint */
2722488Sdist 
2834039Sbostic #include <sys/param.h>
29975Sbill #include <sys/stat.h>
3034039Sbostic #include <sys/dir.h>
31975Sbill #include <pwd.h>
3218450Smckusick #include <grp.h>
3334039Sbostic #include <stdio.h>
3434039Sbostic #include <ctype.h>
35975Sbill 
3634039Sbostic static int ischown, uid, gid, fflag, rflag, retval;
3734056Sbostic static char *gname, *myname;
38975Sbill 
39975Sbill main(argc, argv)
4034039Sbostic 	int argc;
4134039Sbostic 	char **argv;
42975Sbill {
4334039Sbostic 	extern char *optarg;
4434039Sbostic 	extern int optind;
4534039Sbostic 	register char *cp;
4634039Sbostic 	int ch;
47*36959Sbostic 	char curpath[MAXPATHLEN], *reset, *index(), *rindex();
48975Sbill 
4934039Sbostic 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
5034039Sbostic 	ischown = myname[2] == 'o';
5124505Ssam 
5234039Sbostic 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
5334039Sbostic 		switch((char)ch) {
5434039Sbostic 		case 'R':
5534039Sbostic 			rflag++;
5634039Sbostic 			break;
5724505Ssam 		case 'f':
5824505Ssam 			fflag++;
5924505Ssam 			break;
6034039Sbostic 		case '?':
6134039Sbostic 		default:
6234039Sbostic 			usage();
6334039Sbostic 		}
6434039Sbostic 	argv += optind;
6534039Sbostic 	argc -= optind;
6624505Ssam 
6734039Sbostic 	if (argc < 2)
6834039Sbostic 		usage();
6924505Ssam 
7034039Sbostic 	if (ischown) {
7134039Sbostic 		if (cp = index(*argv, '.')) {
7234039Sbostic 			*cp++ = '\0';
7334039Sbostic 			setgid(cp);
7424505Ssam 		}
7534039Sbostic 		else
7634039Sbostic 			gid = -1;
7734039Sbostic 		setuid(*argv);
7824505Ssam 	}
7934039Sbostic 	else {
8034039Sbostic 		uid = -1;
8134039Sbostic 		setgid(*argv);
82975Sbill 	}
8334039Sbostic 
84*36959Sbostic 	while (*++argv) {
85*36959Sbostic 		if (reset = index(*argv, '/'))
86*36959Sbostic 			(void)getwd(curpath);
8734039Sbostic 		change(*argv);
88*36959Sbostic 		if (reset && chdir(curpath)) {
89*36959Sbostic 			if (fflag)
90*36959Sbostic 				exit(0);
91*36959Sbostic 			err(curpath);
92*36959Sbostic 			exit(-1);
93*36959Sbostic 		}
94*36959Sbostic 	}
9534039Sbostic 	exit(retval);
9634039Sbostic }
9734039Sbostic 
9834039Sbostic static
9934039Sbostic setgid(s)
10034039Sbostic 	register char *s;
10134039Sbostic {
10234039Sbostic 	struct group *gr, *getgrnam();
10334039Sbostic 
10434039Sbostic 	if (!*s) {
10534039Sbostic 		gid = -1;			/* argument was "uid." */
10634039Sbostic 		return;
10711442Smckusick 	}
10834056Sbostic 	for (gname = s; *s && isdigit(*s); ++s);
10934039Sbostic 	if (!*s)
11034056Sbostic 		gid = atoi(gname);
11134039Sbostic 	else {
11234056Sbostic 		if (!(gr = getgrnam(gname))) {
11334039Sbostic 			if (fflag)
11434039Sbostic 				exit(0);
11534039Sbostic 			fprintf(stderr, "%s: unknown group id: %s\n",
11634056Sbostic 			    myname, gname);
11734039Sbostic 			exit(-1);
11818450Smckusick 		}
11934039Sbostic 		gid = gr->gr_gid;
120975Sbill 	}
121975Sbill }
122975Sbill 
12334039Sbostic static
12434039Sbostic setuid(s)
12534039Sbostic 	register char *s;
126975Sbill {
12734039Sbostic 	struct passwd *pwd, *getpwnam();
12834039Sbostic 	char *beg;
129975Sbill 
13034039Sbostic 	if (!*s) {
13134039Sbostic 		uid = -1;			/* argument was ".gid" */
13234039Sbostic 		return;
13334039Sbostic 	}
13434039Sbostic 	for (beg = s; *s && isdigit(*s); ++s);
13534039Sbostic 	if (!*s)
13634039Sbostic 		uid = atoi(beg);
13734039Sbostic 	else {
13834039Sbostic 		if (!(pwd = getpwnam(beg))) {
13934039Sbostic 			if (fflag)
14034039Sbostic 				exit(0);
14134039Sbostic 			fprintf(stderr, "chown: unknown user id: %s\n", beg);
14234039Sbostic 			exit(-1);
14334039Sbostic 		}
14434039Sbostic 		uid = pwd->pw_uid;
14534039Sbostic 	}
146975Sbill }
14718450Smckusick 
14834039Sbostic static
14934039Sbostic change(file)
15034039Sbostic 	char *file;
15118450Smckusick {
15224505Ssam 	register DIR *dirp;
15324505Ssam 	register struct direct *dp;
15434039Sbostic 	struct stat buf;
15518450Smckusick 
15634056Sbostic 	if (chown(file, uid, gid)) {
15734069Sbostic 		chownerr(file);
15834039Sbostic 		return;
15928349Smckusick 	}
16034056Sbostic 	if (!rflag)
16134056Sbostic 		return;
16234056Sbostic 	if (lstat(file, &buf)) {
16334056Sbostic 		err(file);
16434056Sbostic 		return;
16534056Sbostic 	}
16634056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
16734039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
16834039Sbostic 			err(file);
16934039Sbostic 			return;
17018450Smckusick 		}
17134039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
17234039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
17334039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
17434039Sbostic 				continue;
17534039Sbostic 			change(dp->d_name);
17624505Ssam 		}
17734039Sbostic 		closedir(dirp);
17834039Sbostic 		if (chdir("..")) {
17934039Sbostic 			err("..");
18034039Sbostic 			exit(fflag ? 0 : -1);
18134039Sbostic 		}
18218450Smckusick 	}
18318450Smckusick }
18424505Ssam 
18534039Sbostic static
18634069Sbostic chownerr(file)
18734069Sbostic 	char *file;
18834069Sbostic {
18934069Sbostic 	static int euid = -1, ngroups = -1;
19034069Sbostic 
19134069Sbostic 	/* check for chown without being root */
19234069Sbostic 	if (uid != -1 && euid == -1 && (euid = geteuid())) {
19334069Sbostic 		if (fflag)
19434069Sbostic 			exit(0);
19534069Sbostic 		err(file);
19634069Sbostic 		exit(-1);
19734069Sbostic 	}
19834069Sbostic 	/* check group membership; kernel just returns EPERM */
19934069Sbostic 	if (gid != -1 && ngroups == -1) {
20034069Sbostic 		int groups[NGROUPS];
20134069Sbostic 
20234069Sbostic 		ngroups = getgroups(NGROUPS, groups);
20334069Sbostic 		while (--ngroups >= 0 && gid != groups[ngroups]);
20434069Sbostic 		if (ngroups < 0) {
20534069Sbostic 			if (fflag)
20634069Sbostic 				exit(0);
20734069Sbostic 			fprintf(stderr,
20834069Sbostic 			    "%s: you are not a member of group %s.\n",
20934069Sbostic 			    myname, gname);
21034069Sbostic 			exit(-1);
21134069Sbostic 		}
21234069Sbostic 	}
21334069Sbostic 	err(file);
21434069Sbostic }
21534069Sbostic 
21634069Sbostic static
21734039Sbostic err(s)
21834039Sbostic 	char *s;
21924505Ssam {
220*36959Sbostic 	extern int errno;
221*36959Sbostic 	char *strerror();
222*36959Sbostic 
22334039Sbostic 	if (fflag)
22434039Sbostic 		return;
225*36959Sbostic 	fprintf(stderr, "%s: %s: %s", myname, s, strerror(errno));
22634039Sbostic 	retval = -1;
22724505Ssam }
22824505Ssam 
22934039Sbostic static
23034039Sbostic usage()
23124505Ssam {
23234039Sbostic 	fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
23334039Sbostic 	    ischown ? "owner[.group]" : "group");
23434039Sbostic 	exit(-1);
23524505Ssam }
236