only root should execute this, no need for setuid or special ownership
[unix-history] / usr / src / usr.sbin / chown / chown.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1988 Regents of the University of California.\n\
11 All rights reserved.\n";
12#endif /* not lint */
13
14#ifndef lint
15static char sccsid[] = "@(#)chown.c 5.15 (Berkeley) %G%";
16#endif /* not lint */
17
18#include <sys/param.h>
19#include <sys/stat.h>
20#include <sys/errno.h>
21#include <dirent.h>
22#include <pwd.h>
23#include <grp.h>
24#include <stdio.h>
25#include <ctype.h>
26
27int ischown, uid, gid, fflag, rflag, retval;
28char *gname, *myname;
29
30main(argc, argv)
31 int argc;
32 char **argv;
33{
34 extern char *optarg;
35 extern int optind;
36 register char *cp;
37 int ch;
38 char curpath[MAXPATHLEN], *reset, *index(), *rindex();
39
40 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
41 ischown = myname[2] == 'o';
42
43 while ((ch = getopt(argc, argv, "Rf")) != EOF)
44 switch((char)ch) {
45 case 'R':
46 rflag++;
47 break;
48 case 'f':
49 fflag++;
50 break;
51 case '?':
52 default:
53 usage();
54 }
55 argv += optind;
56 argc -= optind;
57
58 if (argc < 2)
59 usage();
60
61 if (ischown) {
62 if (cp = index(*argv, '.')) {
63 *cp++ = '\0';
64 setgid(cp);
65 }
66 else
67 gid = -1;
68 setuid(*argv);
69 }
70 else {
71 uid = -1;
72 setgid(*argv);
73 }
74
75 while (*++argv) {
76 if (reset = index(*argv, '/'))
77 (void)getwd(curpath);
78 change(*argv);
79 if (reset && chdir(curpath)) {
80 if (fflag)
81 exit(0);
82 err(curpath);
83 exit(-1);
84 }
85 }
86 exit(retval);
87}
88
89setgid(s)
90 register char *s;
91{
92 struct group *gr, *getgrnam();
93
94 if (!*s) {
95 gid = -1; /* argument was "uid." */
96 return;
97 }
98 for (gname = s; *s && isdigit(*s); ++s);
99 if (!*s)
100 gid = atoi(gname);
101 else {
102 if (!(gr = getgrnam(gname))) {
103 if (fflag)
104 exit(0);
105 (void)fprintf(stderr, "%s: unknown group id: %s\n",
106 myname, gname);
107 exit(-1);
108 }
109 gid = gr->gr_gid;
110 }
111}
112
113setuid(s)
114 register char *s;
115{
116 struct passwd *pwd, *getpwnam();
117 char *beg;
118
119 if (!*s) {
120 uid = -1; /* argument was ".gid" */
121 return;
122 }
123 for (beg = s; *s && isdigit(*s); ++s);
124 if (!*s)
125 uid = atoi(beg);
126 else {
127 if (!(pwd = getpwnam(beg))) {
128 if (fflag)
129 exit(0);
130 (void)fprintf(stderr,
131 "chown: unknown user id: %s\n", beg);
132 exit(-1);
133 }
134 uid = pwd->pw_uid;
135 }
136}
137
138change(file)
139 char *file;
140{
141 register DIR *dirp;
142 register struct dirent *dp;
143 struct stat buf;
144
145 if (chown(file, uid, gid)) {
146 chownerr(file);
147 return;
148 }
149 if (!rflag)
150 return;
151 if (lstat(file, &buf)) {
152 err(file);
153 return;
154 }
155 if ((buf.st_mode & S_IFMT) == S_IFDIR) {
156 if (chdir(file) < 0 || !(dirp = opendir("."))) {
157 err(file);
158 return;
159 }
160 for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
161 if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
162 dp->d_name[1] == '.' && !dp->d_name[2]))
163 continue;
164 change(dp->d_name);
165 }
166 closedir(dirp);
167 if (chdir("..")) {
168 err("..");
169 exit(fflag ? 0 : -1);
170 }
171 }
172}
173
174chownerr(file)
175 char *file;
176{
177 extern int errno;
178 static int euid = -1, ngroups = -1;
179
180 /* check for chown without being root */
181 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
182 if (fflag)
183 exit(0);
184 err(file);
185 exit(-1);
186 }
187 /* check group membership; kernel just returns EPERM */
188 if (gid != -1 && ngroups == -1) {
189 int groups[NGROUPS];
190
191 ngroups = getgroups(NGROUPS, groups);
192 while (--ngroups >= 0 && gid != groups[ngroups]);
193 if (ngroups < 0) {
194 if (fflag)
195 exit(0);
196 (void)fprintf(stderr,
197 "%s: you are not a member of group %s.\n",
198 myname, gname);
199 exit(-1);
200 }
201 }
202 err(file);
203}
204
205err(s)
206 char *s;
207{
208 extern int errno;
209 char *strerror();
210
211 if (fflag)
212 return;
213 (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
214 retval = -1;
215}
216
217usage()
218{
219 (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
220 ischown ? "owner[.group]" : "group");
221 exit(-1);
222}