xref: /original-bsd/usr.sbin/chown/chown.c (revision 3588a932)
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
9 char 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
15 static char sccsid[] = "@(#)chown.c	5.18 (Berkeley) 03/09/91";
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 <fts.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 int ischown, uid, gid, fflag, rflag, retval;
32 char *gname, *myname;
33 
34 main(argc, argv)
35 	int argc;
36 	char **argv;
37 {
38 	extern int optind;
39 	register FTS *fts;
40 	register FTSENT *p;
41 	register char *cp;
42 	int ch;
43 
44 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
45 	ischown = myname[2] == 'o';
46 
47 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
48 		switch((char)ch) {
49 		case 'R':
50 			rflag = 1;
51 			break;
52 		case 'f':
53 			fflag = 1;
54 			break;
55 		case '?':
56 		default:
57 			usage();
58 		}
59 	argv += optind;
60 	argc -= optind;
61 
62 	if (argc < 2)
63 		usage();
64 
65 	uid = gid = -1;
66 	if (ischown) {
67 #ifdef SUPPORT_DOT
68 		if (cp = index(*argv, '.')) {
69 			*cp++ = '\0';
70 			a_gid(cp);
71 		} else
72 #endif
73 		if (cp = index(*argv, ':')) {
74 			*cp++ = '\0';
75 			a_gid(cp);
76 		}
77 		a_uid(*argv);
78 	}
79 	else
80 		a_gid(*argv);
81 
82 	if (rflag) {
83 		if (!(fts = fts_open(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) {
84 			(void)fprintf(stderr,
85 			    "%s: %s.\n", myname, strerror(errno));
86 			exit(1);
87 		}
88 		while (p = fts_read(fts)) {
89 			if (p->fts_info == FTS_D)
90 				continue;
91 			if (p->fts_info == FTS_ERR) {
92 				error(p->fts_path);
93 				continue;
94 			}
95 			if (chown(p->fts_accpath, uid, gid) && !fflag)
96 				chownerr(p->fts_path);
97 		}
98 		exit(retval);
99 	}
100 	while (*++argv)
101 		if (chown(*argv, uid, gid) && !fflag)
102 			chownerr(*argv);
103 	exit(retval);
104 }
105 
106 a_gid(s)
107 	register char *s;
108 {
109 	struct group *gr;
110 
111 	if (!*s) {
112 		gid = -1;			/* argument was "uid." */
113 		return;
114 	}
115 	gname = s;
116 	if (gr = getgrnam(s))
117 		gid = gr->gr_gid;
118 	else {
119 		for (; *s && isdigit(*s); ++s);
120 		if (!*s)
121 			gid = atoi(gname);
122 		else {
123 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
124 			    myname, gname);
125 			exit(1);
126 		}
127 	}
128 }
129 
130 a_uid(s)
131 	register char *s;
132 {
133 	struct passwd *pw;
134 	char *uname;
135 
136 	if (!*s) {
137 		uid = -1;			/* argument was ".gid" */
138 		return;
139 	}
140 	if (pw = getpwnam(s))
141 		uid = pw->pw_uid;
142 	else {
143 		for (uname = s; *s && isdigit(*s); ++s);
144 		if (!*s)
145 			uid = atoi(uname);
146 		else {
147 			(void)fprintf(stderr,
148 			    "chown: unknown user id: %s\n", uname);
149 			exit(1);
150 		}
151 	}
152 }
153 
154 chownerr(file)
155 	char *file;
156 {
157 	static int euid = -1, ngroups = -1;
158 
159 	/* check for chown without being root */
160 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
161 		if (fflag)
162 			exit(0);
163 		error(file);
164 		exit(1);
165 	}
166 	/* check group membership; kernel just returns EPERM */
167 	if (gid != -1 && ngroups == -1) {
168 		int groups[NGROUPS];
169 
170 		ngroups = getgroups(NGROUPS, groups);
171 		while (--ngroups >= 0 && gid != groups[ngroups]);
172 		if (ngroups < 0) {
173 			if (fflag)
174 				exit(0);
175 			(void)fprintf(stderr,
176 			    "%s: you are not a member of group %s.\n",
177 			    myname, gname);
178 			exit(1);
179 		}
180 	}
181 	if (!fflag)
182 		error(file);
183 }
184 
185 error(name)
186 	char *name;
187 {
188 	(void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
189 	retval = 1;
190 }
191 
192 usage()
193 {
194 	(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
195 	    ischown ? "[owner][:group]" : "group");
196 	exit(1);
197 }
198