xref: /csrg-svn/usr.sbin/chown/chown.c (revision 34777)
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
6*34777Sbostic  * provided that the above copyright notice and this paragraph are
7*34777Sbostic  * duplicated in all such forms and that any documentation,
8*34777Sbostic  * advertising materials, and other materials related to such
9*34777Sbostic  * distribution and use acknowledge that the software was developed
10*34777Sbostic  * by the University of California, Berkeley.  The name of the
11*34777Sbostic  * University may not be used to endorse or promote products derived
12*34777Sbostic  * from this software without specific prior written permission.
13*34777Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34777Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34777Sbostic  * 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*34777Sbostic static char sccsid[] = "@(#)chown.c	5.11 (Berkeley) 06/18/88";
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;
4734039Sbostic 	char *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 
8434039Sbostic 	while (*++argv)
8534039Sbostic 		change(*argv);
8634039Sbostic 	exit(retval);
8734039Sbostic }
8834039Sbostic 
8934039Sbostic static
9034039Sbostic setgid(s)
9134039Sbostic 	register char *s;
9234039Sbostic {
9334039Sbostic 	struct group *gr, *getgrnam();
9434039Sbostic 
9534039Sbostic 	if (!*s) {
9634039Sbostic 		gid = -1;			/* argument was "uid." */
9734039Sbostic 		return;
9811442Smckusick 	}
9934056Sbostic 	for (gname = s; *s && isdigit(*s); ++s);
10034039Sbostic 	if (!*s)
10134056Sbostic 		gid = atoi(gname);
10234039Sbostic 	else {
10334056Sbostic 		if (!(gr = getgrnam(gname))) {
10434039Sbostic 			if (fflag)
10534039Sbostic 				exit(0);
10634039Sbostic 			fprintf(stderr, "%s: unknown group id: %s\n",
10734056Sbostic 			    myname, gname);
10834039Sbostic 			exit(-1);
10918450Smckusick 		}
11034039Sbostic 		gid = gr->gr_gid;
111975Sbill 	}
112975Sbill }
113975Sbill 
11434039Sbostic static
11534039Sbostic setuid(s)
11634039Sbostic 	register char *s;
117975Sbill {
11834039Sbostic 	struct passwd *pwd, *getpwnam();
11934039Sbostic 	char *beg;
120975Sbill 
12134039Sbostic 	if (!*s) {
12234039Sbostic 		uid = -1;			/* argument was ".gid" */
12334039Sbostic 		return;
12434039Sbostic 	}
12534039Sbostic 	for (beg = s; *s && isdigit(*s); ++s);
12634039Sbostic 	if (!*s)
12734039Sbostic 		uid = atoi(beg);
12834039Sbostic 	else {
12934039Sbostic 		if (!(pwd = getpwnam(beg))) {
13034039Sbostic 			if (fflag)
13134039Sbostic 				exit(0);
13234039Sbostic 			fprintf(stderr, "chown: unknown user id: %s\n", beg);
13334039Sbostic 			exit(-1);
13434039Sbostic 		}
13534039Sbostic 		uid = pwd->pw_uid;
13634039Sbostic 	}
137975Sbill }
13818450Smckusick 
13934039Sbostic static
14034039Sbostic change(file)
14134039Sbostic 	char *file;
14218450Smckusick {
14324505Ssam 	register DIR *dirp;
14424505Ssam 	register struct direct *dp;
14534039Sbostic 	struct stat buf;
14618450Smckusick 
14734056Sbostic 	if (chown(file, uid, gid)) {
14834069Sbostic 		chownerr(file);
14934039Sbostic 		return;
15028349Smckusick 	}
15134056Sbostic 	if (!rflag)
15234056Sbostic 		return;
15334056Sbostic 	if (lstat(file, &buf)) {
15434056Sbostic 		err(file);
15534056Sbostic 		return;
15634056Sbostic 	}
15734056Sbostic 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
15834039Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
15934039Sbostic 			err(file);
16034039Sbostic 			return;
16118450Smckusick 		}
16234039Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
16334039Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
16434039Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
16534039Sbostic 				continue;
16634039Sbostic 			change(dp->d_name);
16724505Ssam 		}
16834039Sbostic 		closedir(dirp);
16934039Sbostic 		if (chdir("..")) {
17034039Sbostic 			err("..");
17134039Sbostic 			exit(fflag ? 0 : -1);
17234039Sbostic 		}
17318450Smckusick 	}
17418450Smckusick }
17524505Ssam 
17634039Sbostic static
17734069Sbostic chownerr(file)
17834069Sbostic 	char *file;
17934069Sbostic {
18034069Sbostic 	static int euid = -1, ngroups = -1;
18134069Sbostic 
18234069Sbostic 	/* check for chown without being root */
18334069Sbostic 	if (uid != -1 && euid == -1 && (euid = geteuid())) {
18434069Sbostic 		if (fflag)
18534069Sbostic 			exit(0);
18634069Sbostic 		err(file);
18734069Sbostic 		exit(-1);
18834069Sbostic 	}
18934069Sbostic 	/* check group membership; kernel just returns EPERM */
19034069Sbostic 	if (gid != -1 && ngroups == -1) {
19134069Sbostic 		int groups[NGROUPS];
19234069Sbostic 
19334069Sbostic 		ngroups = getgroups(NGROUPS, groups);
19434069Sbostic 		while (--ngroups >= 0 && gid != groups[ngroups]);
19534069Sbostic 		if (ngroups < 0) {
19634069Sbostic 			if (fflag)
19734069Sbostic 				exit(0);
19834069Sbostic 			fprintf(stderr,
19934069Sbostic 			    "%s: you are not a member of group %s.\n",
20034069Sbostic 			    myname, gname);
20134069Sbostic 			exit(-1);
20234069Sbostic 		}
20334069Sbostic 	}
20434069Sbostic 	err(file);
20534069Sbostic }
20634069Sbostic 
20734069Sbostic static
20834039Sbostic err(s)
20934039Sbostic 	char *s;
21024505Ssam {
21134039Sbostic 	if (fflag)
21234039Sbostic 		return;
21334056Sbostic 	fprintf(stderr, "%s: ", myname);
21434039Sbostic 	perror(s);
21534039Sbostic 	retval = -1;
21624505Ssam }
21724505Ssam 
21834039Sbostic static
21934039Sbostic usage()
22024505Ssam {
22134039Sbostic 	fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
22234039Sbostic 	    ischown ? "owner[.group]" : "group");
22334039Sbostic 	exit(-1);
22424505Ssam }
225