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.13 (Berkeley) 07/07/89"; 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 static int ischown, uid, gid, fflag, rflag, retval; 38 static 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 static 100 setgid(s) 101 register char *s; 102 { 103 struct group *gr, *getgrnam(); 104 105 if (!*s) { 106 gid = -1; /* argument was "uid." */ 107 return; 108 } 109 for (gname = s; *s && isdigit(*s); ++s); 110 if (!*s) 111 gid = atoi(gname); 112 else { 113 if (!(gr = getgrnam(gname))) { 114 if (fflag) 115 exit(0); 116 (void)fprintf(stderr, "%s: unknown group id: %s\n", 117 myname, gname); 118 exit(-1); 119 } 120 gid = gr->gr_gid; 121 } 122 } 123 124 static 125 setuid(s) 126 register char *s; 127 { 128 struct passwd *pwd, *getpwnam(); 129 char *beg; 130 131 if (!*s) { 132 uid = -1; /* argument was ".gid" */ 133 return; 134 } 135 for (beg = s; *s && isdigit(*s); ++s); 136 if (!*s) 137 uid = atoi(beg); 138 else { 139 if (!(pwd = getpwnam(beg))) { 140 if (fflag) 141 exit(0); 142 (void)fprintf(stderr, 143 "chown: unknown user id: %s\n", beg); 144 exit(-1); 145 } 146 uid = pwd->pw_uid; 147 } 148 } 149 150 static 151 change(file) 152 char *file; 153 { 154 register DIR *dirp; 155 register struct dirent *dp; 156 struct stat buf; 157 158 if (chown(file, uid, gid)) { 159 chownerr(file); 160 return; 161 } 162 if (!rflag) 163 return; 164 if (lstat(file, &buf)) { 165 err(file); 166 return; 167 } 168 if ((buf.st_mode & S_IFMT) == S_IFDIR) { 169 if (chdir(file) < 0 || !(dirp = opendir("."))) { 170 err(file); 171 return; 172 } 173 for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 174 if (dp->d_name[0] == '.' && (!dp->d_name[1] || 175 dp->d_name[1] == '.' && !dp->d_name[2])) 176 continue; 177 change(dp->d_name); 178 } 179 closedir(dirp); 180 if (chdir("..")) { 181 err(".."); 182 exit(fflag ? 0 : -1); 183 } 184 } 185 } 186 187 static 188 chownerr(file) 189 char *file; 190 { 191 extern int errno; 192 static int euid = -1, ngroups = -1; 193 194 /* check for chown without being root */ 195 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 196 if (fflag) 197 exit(0); 198 err(file); 199 exit(-1); 200 } 201 /* check group membership; kernel just returns EPERM */ 202 if (gid != -1 && ngroups == -1) { 203 int groups[NGROUPS]; 204 205 ngroups = getgroups(NGROUPS, groups); 206 while (--ngroups >= 0 && gid != groups[ngroups]); 207 if (ngroups < 0) { 208 if (fflag) 209 exit(0); 210 (void)fprintf(stderr, 211 "%s: you are not a member of group %s.\n", 212 myname, gname); 213 exit(-1); 214 } 215 } 216 err(file); 217 } 218 219 static 220 err(s) 221 char *s; 222 { 223 extern int errno; 224 char *strerror(); 225 226 if (fflag) 227 return; 228 (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno)); 229 retval = -1; 230 } 231 232 static 233 usage() 234 { 235 (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 236 ischown ? "owner[.group]" : "group"); 237 exit(-1); 238 } 239