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