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