xref: /original-bsd/usr.sbin/chown/chown.c (revision a76afa45)
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.12 (Berkeley) 03/05/89";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <sys/dir.h>
31 #include <pwd.h>
32 #include <grp.h>
33 #include <stdio.h>
34 #include <ctype.h>
35 
36 static int ischown, uid, gid, fflag, rflag, retval;
37 static char *gname, *myname;
38 
39 main(argc, argv)
40 	int argc;
41 	char **argv;
42 {
43 	extern char *optarg;
44 	extern int optind;
45 	register char *cp;
46 	int ch;
47 	char curpath[MAXPATHLEN], *reset, *index(), *rindex();
48 
49 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
50 	ischown = myname[2] == 'o';
51 
52 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
53 		switch((char)ch) {
54 		case 'R':
55 			rflag++;
56 			break;
57 		case 'f':
58 			fflag++;
59 			break;
60 		case '?':
61 		default:
62 			usage();
63 		}
64 	argv += optind;
65 	argc -= optind;
66 
67 	if (argc < 2)
68 		usage();
69 
70 	if (ischown) {
71 		if (cp = index(*argv, '.')) {
72 			*cp++ = '\0';
73 			setgid(cp);
74 		}
75 		else
76 			gid = -1;
77 		setuid(*argv);
78 	}
79 	else {
80 		uid = -1;
81 		setgid(*argv);
82 	}
83 
84 	while (*++argv) {
85 		if (reset = index(*argv, '/'))
86 			(void)getwd(curpath);
87 		change(*argv);
88 		if (reset && chdir(curpath)) {
89 			if (fflag)
90 				exit(0);
91 			err(curpath);
92 			exit(-1);
93 		}
94 	}
95 	exit(retval);
96 }
97 
98 static
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 			fprintf(stderr, "%s: unknown group id: %s\n",
116 			    myname, gname);
117 			exit(-1);
118 		}
119 		gid = gr->gr_gid;
120 	}
121 }
122 
123 static
124 setuid(s)
125 	register char *s;
126 {
127 	struct passwd *pwd, *getpwnam();
128 	char *beg;
129 
130 	if (!*s) {
131 		uid = -1;			/* argument was ".gid" */
132 		return;
133 	}
134 	for (beg = s; *s && isdigit(*s); ++s);
135 	if (!*s)
136 		uid = atoi(beg);
137 	else {
138 		if (!(pwd = getpwnam(beg))) {
139 			if (fflag)
140 				exit(0);
141 			fprintf(stderr, "chown: unknown user id: %s\n", beg);
142 			exit(-1);
143 		}
144 		uid = pwd->pw_uid;
145 	}
146 }
147 
148 static
149 change(file)
150 	char *file;
151 {
152 	register DIR *dirp;
153 	register struct direct *dp;
154 	struct stat buf;
155 
156 	if (chown(file, uid, gid)) {
157 		chownerr(file);
158 		return;
159 	}
160 	if (!rflag)
161 		return;
162 	if (lstat(file, &buf)) {
163 		err(file);
164 		return;
165 	}
166 	if ((buf.st_mode & S_IFMT) == S_IFDIR) {
167 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
168 			err(file);
169 			return;
170 		}
171 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
172 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
173 			    dp->d_name[1] == '.' && !dp->d_name[2]))
174 				continue;
175 			change(dp->d_name);
176 		}
177 		closedir(dirp);
178 		if (chdir("..")) {
179 			err("..");
180 			exit(fflag ? 0 : -1);
181 		}
182 	}
183 }
184 
185 static
186 chownerr(file)
187 	char *file;
188 {
189 	static int euid = -1, ngroups = -1;
190 
191 	/* check for chown without being root */
192 	if (uid != -1 && euid == -1 && (euid = geteuid())) {
193 		if (fflag)
194 			exit(0);
195 		err(file);
196 		exit(-1);
197 	}
198 	/* check group membership; kernel just returns EPERM */
199 	if (gid != -1 && ngroups == -1) {
200 		int groups[NGROUPS];
201 
202 		ngroups = getgroups(NGROUPS, groups);
203 		while (--ngroups >= 0 && gid != groups[ngroups]);
204 		if (ngroups < 0) {
205 			if (fflag)
206 				exit(0);
207 			fprintf(stderr,
208 			    "%s: you are not a member of group %s.\n",
209 			    myname, gname);
210 			exit(-1);
211 		}
212 	}
213 	err(file);
214 }
215 
216 static
217 err(s)
218 	char *s;
219 {
220 	extern int errno;
221 	char *strerror();
222 
223 	if (fflag)
224 		return;
225 	fprintf(stderr, "%s: %s: %s", myname, s, strerror(errno));
226 	retval = -1;
227 }
228 
229 static
230 usage()
231 {
232 	fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
233 	    ischown ? "owner[.group]" : "group");
234 	exit(-1);
235 }
236