xref: /original-bsd/usr.sbin/chown/chown.c (revision 78204ff3)
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.13 (Berkeley) 07/07/89";
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 static int ischown, uid, gid, fflag, rflag, retval;
38 static 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 static
100 setgid(s)
101 	register char *s;
102 {
103 	struct group *gr, *getgrnam();
104 
105 	if (!*s) {
106 		gid = -1;			/* argument was "uid." */
107 		return;
108 	}
109 	for (gname = s; *s && isdigit(*s); ++s);
110 	if (!*s)
111 		gid = atoi(gname);
112 	else {
113 		if (!(gr = getgrnam(gname))) {
114 			if (fflag)
115 				exit(0);
116 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
117 			    myname, gname);
118 			exit(-1);
119 		}
120 		gid = gr->gr_gid;
121 	}
122 }
123 
124 static
125 setuid(s)
126 	register char *s;
127 {
128 	struct passwd *pwd, *getpwnam();
129 	char *beg;
130 
131 	if (!*s) {
132 		uid = -1;			/* argument was ".gid" */
133 		return;
134 	}
135 	for (beg = s; *s && isdigit(*s); ++s);
136 	if (!*s)
137 		uid = atoi(beg);
138 	else {
139 		if (!(pwd = getpwnam(beg))) {
140 			if (fflag)
141 				exit(0);
142 			(void)fprintf(stderr,
143 			    "chown: unknown user id: %s\n", beg);
144 			exit(-1);
145 		}
146 		uid = pwd->pw_uid;
147 	}
148 }
149 
150 static
151 change(file)
152 	char *file;
153 {
154 	register DIR *dirp;
155 	register struct dirent *dp;
156 	struct stat buf;
157 
158 	if (chown(file, uid, gid)) {
159 		chownerr(file);
160 		return;
161 	}
162 	if (!rflag)
163 		return;
164 	if (lstat(file, &buf)) {
165 		err(file);
166 		return;
167 	}
168 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
169 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
170 			err(file);
171 			return;
172 		}
173 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
174 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
175 			    dp->d_name[1] == '.' && !dp->d_name[2]))
176 				continue;
177 			change(dp->d_name);
178 		}
179 		closedir(dirp);
180 		if (chdir("..")) {
181 			err("..");
182 			exit(fflag ? 0 : -1);
183 		}
184 	}
185 }
186 
187 static
188 chownerr(file)
189 	char *file;
190 {
191 	extern int errno;
192 	static int euid = -1, ngroups = -1;
193 
194 	/* check for chown without being root */
195 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
196 		if (fflag)
197 			exit(0);
198 		err(file);
199 		exit(-1);
200 	}
201 	/* check group membership; kernel just returns EPERM */
202 	if (gid != -1 && ngroups == -1) {
203 		int groups[NGROUPS];
204 
205 		ngroups = getgroups(NGROUPS, groups);
206 		while (--ngroups >= 0 && gid != groups[ngroups]);
207 		if (ngroups < 0) {
208 			if (fflag)
209 				exit(0);
210 			(void)fprintf(stderr,
211 			    "%s: you are not a member of group %s.\n",
212 			    myname, gname);
213 			exit(-1);
214 		}
215 	}
216 	err(file);
217 }
218 
219 static
220 err(s)
221 	char *s;
222 {
223 	extern int errno;
224 	char *strerror();
225 
226 	if (fflag)
227 		return;
228 	(void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
229 	retval = -1;
230 }
231 
232 static
233 usage()
234 {
235 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
236 	    ischown ? "owner[.group]" : "group");
237 	exit(-1);
238 }
239