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 are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)chown.c 5.14 (Berkeley) 04/25/90"; 26 #endif /* not lint */ 27 28 #include <sys/param.h> 29 #include <sys/stat.h> 30 #include <sys/errno.h> 31 #include <dirent.h> 32 #include <pwd.h> 33 #include <grp.h> 34 #include <stdio.h> 35 #include <ctype.h> 36 37 int ischown, uid, gid, fflag, rflag, retval; 38 char *gname, *myname; 39 40 main(argc, argv) 41 int argc; 42 char **argv; 43 { 44 extern char *optarg; 45 extern int optind; 46 register char *cp; 47 int ch; 48 char curpath[MAXPATHLEN], *reset, *index(), *rindex(); 49 50 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 51 ischown = myname[2] == 'o'; 52 53 while ((ch = getopt(argc, argv, "Rf")) != EOF) 54 switch((char)ch) { 55 case 'R': 56 rflag++; 57 break; 58 case 'f': 59 fflag++; 60 break; 61 case '?': 62 default: 63 usage(); 64 } 65 argv += optind; 66 argc -= optind; 67 68 if (argc < 2) 69 usage(); 70 71 if (ischown) { 72 if (cp = index(*argv, '.')) { 73 *cp++ = '\0'; 74 setgid(cp); 75 } 76 else 77 gid = -1; 78 setuid(*argv); 79 } 80 else { 81 uid = -1; 82 setgid(*argv); 83 } 84 85 while (*++argv) { 86 if (reset = index(*argv, '/')) 87 (void)getwd(curpath); 88 change(*argv); 89 if (reset && chdir(curpath)) { 90 if (fflag) 91 exit(0); 92 err(curpath); 93 exit(-1); 94 } 95 } 96 exit(retval); 97 } 98 99 setgid(s) 100 register char *s; 101 { 102 struct group *gr, *getgrnam(); 103 104 if (!*s) { 105 gid = -1; /* argument was "uid." */ 106 return; 107 } 108 for (gname = s; *s && isdigit(*s); ++s); 109 if (!*s) 110 gid = atoi(gname); 111 else { 112 if (!(gr = getgrnam(gname))) { 113 if (fflag) 114 exit(0); 115 (void)fprintf(stderr, "%s: unknown group id: %s\n", 116 myname, gname); 117 exit(-1); 118 } 119 gid = gr->gr_gid; 120 } 121 } 122 123 setuid(s) 124 register char *s; 125 { 126 struct passwd *pwd, *getpwnam(); 127 char *beg; 128 129 if (!*s) { 130 uid = -1; /* argument was ".gid" */ 131 return; 132 } 133 for (beg = s; *s && isdigit(*s); ++s); 134 if (!*s) 135 uid = atoi(beg); 136 else { 137 if (!(pwd = getpwnam(beg))) { 138 if (fflag) 139 exit(0); 140 (void)fprintf(stderr, 141 "chown: unknown user id: %s\n", beg); 142 exit(-1); 143 } 144 uid = pwd->pw_uid; 145 } 146 } 147 148 change(file) 149 char *file; 150 { 151 register DIR *dirp; 152 register struct dirent *dp; 153 struct stat buf; 154 155 if (chown(file, uid, gid)) { 156 chownerr(file); 157 return; 158 } 159 if (!rflag) 160 return; 161 if (lstat(file, &buf)) { 162 err(file); 163 return; 164 } 165 if ((buf.st_mode & S_IFMT) == S_IFDIR) { 166 if (chdir(file) < 0 || !(dirp = opendir("."))) { 167 err(file); 168 return; 169 } 170 for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 171 if (dp->d_name[0] == '.' && (!dp->d_name[1] || 172 dp->d_name[1] == '.' && !dp->d_name[2])) 173 continue; 174 change(dp->d_name); 175 } 176 closedir(dirp); 177 if (chdir("..")) { 178 err(".."); 179 exit(fflag ? 0 : -1); 180 } 181 } 182 } 183 184 chownerr(file) 185 char *file; 186 { 187 extern int errno; 188 static int euid = -1, ngroups = -1; 189 190 /* check for chown without being root */ 191 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 192 if (fflag) 193 exit(0); 194 err(file); 195 exit(-1); 196 } 197 /* check group membership; kernel just returns EPERM */ 198 if (gid != -1 && ngroups == -1) { 199 int groups[NGROUPS]; 200 201 ngroups = getgroups(NGROUPS, groups); 202 while (--ngroups >= 0 && gid != groups[ngroups]); 203 if (ngroups < 0) { 204 if (fflag) 205 exit(0); 206 (void)fprintf(stderr, 207 "%s: you are not a member of group %s.\n", 208 myname, gname); 209 exit(-1); 210 } 211 } 212 err(file); 213 } 214 215 err(s) 216 char *s; 217 { 218 extern int errno; 219 char *strerror(); 220 221 if (fflag) 222 return; 223 (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno)); 224 retval = -1; 225 } 226 227 usage() 228 { 229 (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 230 ischown ? "owner[.group]" : "group"); 231 exit(-1); 232 } 233