xref: /csrg-svn/usr.sbin/chown/chown.c (revision 41090)
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*41090Smarc static char sccsid[] = "@(#)chown.c	5.14 (Berkeley) 04/25/90";
2634039Sbostic #endif /* not lint */
2722488Sdist 
2834039Sbostic #include <sys/param.h>
29975Sbill #include <sys/stat.h>
3038427Sbostic #include <sys/errno.h>
3138427Sbostic #include <dirent.h>
32975Sbill #include <pwd.h>
3318450Smckusick #include <grp.h>
3434039Sbostic #include <stdio.h>
3534039Sbostic #include <ctype.h>
36975Sbill 
37*41090Smarc int ischown, uid, gid, fflag, rflag, retval;
38*41090Smarc 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 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);
11538427Sbostic 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
11634056Sbostic 			    myname, gname);
11734039Sbostic 			exit(-1);
11818450Smckusick 		}
11934039Sbostic 		gid = gr->gr_gid;
120975Sbill 	}
121975Sbill }
122975Sbill 
12334039Sbostic setuid(s)
12434039Sbostic 	register char *s;
125975Sbill {
12634039Sbostic 	struct passwd *pwd, *getpwnam();
12734039Sbostic 	char *beg;
128975Sbill 
12934039Sbostic 	if (!*s) {
13034039Sbostic 		uid = -1;			/* argument was ".gid" */
13134039Sbostic 		return;
13234039Sbostic 	}
13334039Sbostic 	for (beg = s; *s && isdigit(*s); ++s);
13434039Sbostic 	if (!*s)
13534039Sbostic 		uid = atoi(beg);
13634039Sbostic 	else {
13734039Sbostic 		if (!(pwd = getpwnam(beg))) {
13834039Sbostic 			if (fflag)
13934039Sbostic 				exit(0);
14038427Sbostic 			(void)fprintf(stderr,
14138427Sbostic 			    "chown: unknown user id: %s\n", beg);
14234039Sbostic 			exit(-1);
14334039Sbostic 		}
14434039Sbostic 		uid = pwd->pw_uid;
14534039Sbostic 	}
146975Sbill }
14718450Smckusick 
14834039Sbostic change(file)
14934039Sbostic 	char *file;
15018450Smckusick {
15124505Ssam 	register DIR *dirp;
15238427Sbostic 	register struct dirent *dp;
15334039Sbostic 	struct stat buf;
15418450Smckusick 
15534056Sbostic 	if (chown(file, uid, gid)) {
15634069Sbostic 		chownerr(file);
15734039Sbostic 		return;
15828349Smckusick 	}
15934056Sbostic 	if (!rflag)
16034056Sbostic 		return;
16134056Sbostic 	if (lstat(file, &buf)) {
16234056Sbostic 		err(file);
16334056Sbostic 		return;
16434056Sbostic 	}
16534056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
16634039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
16734039Sbostic 			err(file);
16834039Sbostic 			return;
16918450Smckusick 		}
17034039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
17134039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
17234039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
17334039Sbostic 				continue;
17434039Sbostic 			change(dp->d_name);
17524505Ssam 		}
17634039Sbostic 		closedir(dirp);
17734039Sbostic 		if (chdir("..")) {
17834039Sbostic 			err("..");
17934039Sbostic 			exit(fflag ? 0 : -1);
18034039Sbostic 		}
18118450Smckusick 	}
18218450Smckusick }
18324505Ssam 
18434069Sbostic chownerr(file)
18534069Sbostic 	char *file;
18634069Sbostic {
18738427Sbostic 	extern int errno;
18834069Sbostic 	static int euid = -1, ngroups = -1;
18934069Sbostic 
19034069Sbostic 	/* check for chown without being root */
19138427Sbostic 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
19234069Sbostic 		if (fflag)
19334069Sbostic 			exit(0);
19434069Sbostic 		err(file);
19534069Sbostic 		exit(-1);
19634069Sbostic 	}
19734069Sbostic 	/* check group membership; kernel just returns EPERM */
19834069Sbostic 	if (gid != -1 && ngroups == -1) {
19934069Sbostic 		int groups[NGROUPS];
20034069Sbostic 
20134069Sbostic 		ngroups = getgroups(NGROUPS, groups);
20234069Sbostic 		while (--ngroups >= 0 && gid != groups[ngroups]);
20334069Sbostic 		if (ngroups < 0) {
20434069Sbostic 			if (fflag)
20534069Sbostic 				exit(0);
20638427Sbostic 			(void)fprintf(stderr,
20734069Sbostic 			    "%s: you are not a member of group %s.\n",
20834069Sbostic 			    myname, gname);
20934069Sbostic 			exit(-1);
21034069Sbostic 		}
21134069Sbostic 	}
21234069Sbostic 	err(file);
21334069Sbostic }
21434069Sbostic 
21534039Sbostic err(s)
21634039Sbostic 	char *s;
21724505Ssam {
21836959Sbostic 	extern int errno;
21936959Sbostic 	char *strerror();
22036959Sbostic 
22134039Sbostic 	if (fflag)
22234039Sbostic 		return;
22338427Sbostic 	(void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
22434039Sbostic 	retval = -1;
22524505Ssam }
22624505Ssam 
22734039Sbostic usage()
22824505Ssam {
22938427Sbostic 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
23034039Sbostic 	    ischown ? "owner[.group]" : "group");
23134039Sbostic 	exit(-1);
23224505Ssam }
233