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