xref: /original-bsd/usr.sbin/chown/chown.c (revision 23c6a147)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)chown.c	5.14 (Berkeley) 04/25/90";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <sys/errno.h>
31 #include <dirent.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 
37 int ischown, uid, gid, fflag, rflag, retval;
38 char *gname, *myname;
39 
40 main(argc, argv)
41 	int argc;
42 	char **argv;
43 {
44 	extern char *optarg;
45 	extern int optind;
46 	register char *cp;
47 	int ch;
48 	char curpath[MAXPATHLEN], *reset, *index(), *rindex();
49 
50 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
51 	ischown = myname[2] == 'o';
52 
53 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
54 		switch((char)ch) {
55 		case 'R':
56 			rflag++;
57 			break;
58 		case 'f':
59 			fflag++;
60 			break;
61 		case '?':
62 		default:
63 			usage();
64 		}
65 	argv += optind;
66 	argc -= optind;
67 
68 	if (argc < 2)
69 		usage();
70 
71 	if (ischown) {
72 		if (cp = index(*argv, '.')) {
73 			*cp++ = '\0';
74 			setgid(cp);
75 		}
76 		else
77 			gid = -1;
78 		setuid(*argv);
79 	}
80 	else {
81 		uid = -1;
82 		setgid(*argv);
83 	}
84 
85 	while (*++argv) {
86 		if (reset = index(*argv, '/'))
87 			(void)getwd(curpath);
88 		change(*argv);
89 		if (reset && chdir(curpath)) {
90 			if (fflag)
91 				exit(0);
92 			err(curpath);
93 			exit(-1);
94 		}
95 	}
96 	exit(retval);
97 }
98 
99 setgid(s)
100 	register char *s;
101 {
102 	struct group *gr, *getgrnam();
103 
104 	if (!*s) {
105 		gid = -1;			/* argument was "uid." */
106 		return;
107 	}
108 	for (gname = s; *s && isdigit(*s); ++s);
109 	if (!*s)
110 		gid = atoi(gname);
111 	else {
112 		if (!(gr = getgrnam(gname))) {
113 			if (fflag)
114 				exit(0);
115 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
116 			    myname, gname);
117 			exit(-1);
118 		}
119 		gid = gr->gr_gid;
120 	}
121 }
122 
123 setuid(s)
124 	register char *s;
125 {
126 	struct passwd *pwd, *getpwnam();
127 	char *beg;
128 
129 	if (!*s) {
130 		uid = -1;			/* argument was ".gid" */
131 		return;
132 	}
133 	for (beg = s; *s && isdigit(*s); ++s);
134 	if (!*s)
135 		uid = atoi(beg);
136 	else {
137 		if (!(pwd = getpwnam(beg))) {
138 			if (fflag)
139 				exit(0);
140 			(void)fprintf(stderr,
141 			    "chown: unknown user id: %s\n", beg);
142 			exit(-1);
143 		}
144 		uid = pwd->pw_uid;
145 	}
146 }
147 
148 change(file)
149 	char *file;
150 {
151 	register DIR *dirp;
152 	register struct dirent *dp;
153 	struct stat buf;
154 
155 	if (chown(file, uid, gid)) {
156 		chownerr(file);
157 		return;
158 	}
159 	if (!rflag)
160 		return;
161 	if (lstat(file, &buf)) {
162 		err(file);
163 		return;
164 	}
165 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
166 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
167 			err(file);
168 			return;
169 		}
170 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
171 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
172 			    dp->d_name[1] == '.' && !dp->d_name[2]))
173 				continue;
174 			change(dp->d_name);
175 		}
176 		closedir(dirp);
177 		if (chdir("..")) {
178 			err("..");
179 			exit(fflag ? 0 : -1);
180 		}
181 	}
182 }
183 
184 chownerr(file)
185 	char *file;
186 {
187 	extern int errno;
188 	static int euid = -1, ngroups = -1;
189 
190 	/* check for chown without being root */
191 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
192 		if (fflag)
193 			exit(0);
194 		err(file);
195 		exit(-1);
196 	}
197 	/* check group membership; kernel just returns EPERM */
198 	if (gid != -1 && ngroups == -1) {
199 		int groups[NGROUPS];
200 
201 		ngroups = getgroups(NGROUPS, groups);
202 		while (--ngroups >= 0 && gid != groups[ngroups]);
203 		if (ngroups < 0) {
204 			if (fflag)
205 				exit(0);
206 			(void)fprintf(stderr,
207 			    "%s: you are not a member of group %s.\n",
208 			    myname, gname);
209 			exit(-1);
210 		}
211 	}
212 	err(file);
213 }
214 
215 err(s)
216 	char *s;
217 {
218 	extern int errno;
219 	char *strerror();
220 
221 	if (fflag)
222 		return;
223 	(void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
224 	retval = -1;
225 }
226 
227 usage()
228 {
229 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
230 	    ischown ? "owner[.group]" : "group");
231 	exit(-1);
232 }
233