xref: /386bsd/usr/src/usr.sbin/chown/chown.c (revision a2142627)
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, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)chown.c	5.18 (Berkeley) 3/9/91";
42 #endif /* not lint */
43 
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <sys/errno.h>
47 #include <dirent.h>
48 #include <fts.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <unistd.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <stdlib.h>
55 #include <string.h>
56 
57 int ischown, uid, gid, fflag, rflag, retval;
58 char *gname, *myname;
59 
main(argc,argv)60 main(argc, argv)
61 	int argc;
62 	char **argv;
63 {
64 	extern int optind;
65 	register FTS *fts;
66 	register FTSENT *p;
67 	register char *cp;
68 	int ch;
69 
70 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
71 	ischown = myname[2] == 'o';
72 
73 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
74 		switch((char)ch) {
75 		case 'R':
76 			rflag = 1;
77 			break;
78 		case 'f':
79 			fflag = 1;
80 			break;
81 		case '?':
82 		default:
83 			usage();
84 		}
85 	argv += optind;
86 	argc -= optind;
87 
88 	if (argc < 2)
89 		usage();
90 
91 	uid = gid = -1;
92 	if (ischown) {
93 #ifdef SUPPORT_DOT
94 		if (cp = index(*argv, '.')) {
95 			*cp++ = '\0';
96 			a_gid(cp);
97 		} else
98 #endif
99 		if (cp = index(*argv, ':')) {
100 			*cp++ = '\0';
101 			a_gid(cp);
102 		}
103 		a_uid(*argv);
104 	}
105 	else
106 		a_gid(*argv);
107 
108 	if (rflag) {
109 		if (!(fts = fts_open(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) {
110 			(void)fprintf(stderr,
111 			    "%s: %s.\n", myname, strerror(errno));
112 			exit(1);
113 		}
114 		while (p = fts_read(fts)) {
115 			if (p->fts_info == FTS_D)
116 				continue;
117 			if (p->fts_info == FTS_ERR) {
118 				error(p->fts_path);
119 				continue;
120 			}
121 			if (chown(p->fts_accpath, uid, gid) && !fflag)
122 				chownerr(p->fts_path);
123 		}
124 		exit(retval);
125 	}
126 	while (*++argv)
127 		if (chown(*argv, uid, gid) && !fflag)
128 			chownerr(*argv);
129 	exit(retval);
130 }
131 
a_gid(s)132 a_gid(s)
133 	register char *s;
134 {
135 	struct group *gr;
136 
137 	if (!*s) {
138 		gid = -1;			/* argument was "uid." */
139 		return;
140 	}
141 	gname = s;
142 	if (gr = getgrnam(s))
143 		gid = gr->gr_gid;
144 	else {
145 		for (; *s && isdigit(*s); ++s);
146 		if (!*s)
147 			gid = atoi(gname);
148 		else {
149 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
150 			    myname, gname);
151 			exit(1);
152 		}
153 	}
154 }
155 
a_uid(s)156 a_uid(s)
157 	register char *s;
158 {
159 	struct passwd *pw;
160 	char *uname;
161 
162 	if (!*s) {
163 		uid = -1;			/* argument was ".gid" */
164 		return;
165 	}
166 	if (pw = getpwnam(s))
167 		uid = pw->pw_uid;
168 	else {
169 		for (uname = s; *s && isdigit(*s); ++s);
170 		if (!*s)
171 			uid = atoi(uname);
172 		else {
173 			(void)fprintf(stderr,
174 			    "chown: unknown user id: %s\n", uname);
175 			exit(1);
176 		}
177 	}
178 }
179 
chownerr(file)180 chownerr(file)
181 	char *file;
182 {
183 	static int euid = -1, ngroups = -1;
184 
185 	/* check for chown without being root */
186 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
187 		if (fflag)
188 			exit(0);
189 		error(file);
190 		exit(1);
191 	}
192 	/* check group membership; kernel just returns EPERM */
193 	if (gid != -1 && ngroups == -1) {
194 		int groups[NGROUPS];
195 
196 		ngroups = getgroups(NGROUPS, groups);
197 		while (--ngroups >= 0 && gid != groups[ngroups]);
198 		if (ngroups < 0) {
199 			if (fflag)
200 				exit(0);
201 			(void)fprintf(stderr,
202 			    "%s: you are not a member of group %s.\n",
203 			    myname, gname);
204 			exit(1);
205 		}
206 	}
207 	if (!fflag)
208 		error(file);
209 }
210 
error(name)211 error(name)
212 	char *name;
213 {
214 	(void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
215 	retval = 1;
216 }
217 
usage()218 usage()
219 {
220 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
221 	    ischown ? "[owner][:group]" : "group");
222 	exit(1);
223 }
224