122488Sdist /* 234039Sbostic * Copyright (c) 1988 Regents of the University of California. 334039Sbostic * All rights reserved. 434039Sbostic * 534039Sbostic * Redistribution and use in source and binary forms are permitted 634777Sbostic * provided that the above copyright notice and this paragraph are 734777Sbostic * duplicated in all such forms and that any documentation, 834777Sbostic * advertising materials, and other materials related to such 934777Sbostic * distribution and use acknowledge that the software was developed 1034777Sbostic * by the University of California, Berkeley. The name of the 1134777Sbostic * University may not be used to endorse or promote products derived 1234777Sbostic * from this software without specific prior written permission. 1334777Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434777Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534777Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622488Sdist */ 1718450Smckusick 1822488Sdist #ifndef lint 1922488Sdist char copyright[] = 2034039Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 2122488Sdist All rights reserved.\n"; 2234039Sbostic #endif /* not lint */ 2322488Sdist 2422488Sdist #ifndef lint 25*38427Sbostic static char sccsid[] = "@(#)chown.c 5.13 (Berkeley) 07/07/89"; 2634039Sbostic #endif /* not lint */ 2722488Sdist 2834039Sbostic #include <sys/param.h> 29975Sbill #include <sys/stat.h> 30*38427Sbostic #include <sys/errno.h> 31*38427Sbostic #include <dirent.h> 32975Sbill #include <pwd.h> 3318450Smckusick #include <grp.h> 3434039Sbostic #include <stdio.h> 3534039Sbostic #include <ctype.h> 36975Sbill 3734039Sbostic static int ischown, uid, gid, fflag, rflag, retval; 3834056Sbostic static char *gname, *myname; 39975Sbill 40975Sbill main(argc, argv) 4134039Sbostic int argc; 4234039Sbostic char **argv; 43975Sbill { 4434039Sbostic extern char *optarg; 4534039Sbostic extern int optind; 4634039Sbostic register char *cp; 4734039Sbostic int ch; 4836959Sbostic char curpath[MAXPATHLEN], *reset, *index(), *rindex(); 49975Sbill 5034039Sbostic myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 5134039Sbostic ischown = myname[2] == 'o'; 5224505Ssam 5334039Sbostic while ((ch = getopt(argc, argv, "Rf")) != EOF) 5434039Sbostic switch((char)ch) { 5534039Sbostic case 'R': 5634039Sbostic rflag++; 5734039Sbostic break; 5824505Ssam case 'f': 5924505Ssam fflag++; 6024505Ssam break; 6134039Sbostic case '?': 6234039Sbostic default: 6334039Sbostic usage(); 6434039Sbostic } 6534039Sbostic argv += optind; 6634039Sbostic argc -= optind; 6724505Ssam 6834039Sbostic if (argc < 2) 6934039Sbostic usage(); 7024505Ssam 7134039Sbostic if (ischown) { 7234039Sbostic if (cp = index(*argv, '.')) { 7334039Sbostic *cp++ = '\0'; 7434039Sbostic setgid(cp); 7524505Ssam } 7634039Sbostic else 7734039Sbostic gid = -1; 7834039Sbostic setuid(*argv); 7924505Ssam } 8034039Sbostic else { 8134039Sbostic uid = -1; 8234039Sbostic setgid(*argv); 83975Sbill } 8434039Sbostic 8536959Sbostic while (*++argv) { 8636959Sbostic if (reset = index(*argv, '/')) 8736959Sbostic (void)getwd(curpath); 8834039Sbostic change(*argv); 8936959Sbostic if (reset && chdir(curpath)) { 9036959Sbostic if (fflag) 9136959Sbostic exit(0); 9236959Sbostic err(curpath); 9336959Sbostic exit(-1); 9436959Sbostic } 9536959Sbostic } 9634039Sbostic exit(retval); 9734039Sbostic } 9834039Sbostic 9934039Sbostic static 10034039Sbostic setgid(s) 10134039Sbostic register char *s; 10234039Sbostic { 10334039Sbostic struct group *gr, *getgrnam(); 10434039Sbostic 10534039Sbostic if (!*s) { 10634039Sbostic gid = -1; /* argument was "uid." */ 10734039Sbostic return; 10811442Smckusick } 10934056Sbostic for (gname = s; *s && isdigit(*s); ++s); 11034039Sbostic if (!*s) 11134056Sbostic gid = atoi(gname); 11234039Sbostic else { 11334056Sbostic if (!(gr = getgrnam(gname))) { 11434039Sbostic if (fflag) 11534039Sbostic exit(0); 116*38427Sbostic (void)fprintf(stderr, "%s: unknown group id: %s\n", 11734056Sbostic myname, gname); 11834039Sbostic exit(-1); 11918450Smckusick } 12034039Sbostic gid = gr->gr_gid; 121975Sbill } 122975Sbill } 123975Sbill 12434039Sbostic static 12534039Sbostic setuid(s) 12634039Sbostic register char *s; 127975Sbill { 12834039Sbostic struct passwd *pwd, *getpwnam(); 12934039Sbostic char *beg; 130975Sbill 13134039Sbostic if (!*s) { 13234039Sbostic uid = -1; /* argument was ".gid" */ 13334039Sbostic return; 13434039Sbostic } 13534039Sbostic for (beg = s; *s && isdigit(*s); ++s); 13634039Sbostic if (!*s) 13734039Sbostic uid = atoi(beg); 13834039Sbostic else { 13934039Sbostic if (!(pwd = getpwnam(beg))) { 14034039Sbostic if (fflag) 14134039Sbostic exit(0); 142*38427Sbostic (void)fprintf(stderr, 143*38427Sbostic "chown: unknown user id: %s\n", beg); 14434039Sbostic exit(-1); 14534039Sbostic } 14634039Sbostic uid = pwd->pw_uid; 14734039Sbostic } 148975Sbill } 14918450Smckusick 15034039Sbostic static 15134039Sbostic change(file) 15234039Sbostic char *file; 15318450Smckusick { 15424505Ssam register DIR *dirp; 155*38427Sbostic register struct dirent *dp; 15634039Sbostic struct stat buf; 15718450Smckusick 15834056Sbostic if (chown(file, uid, gid)) { 15934069Sbostic chownerr(file); 16034039Sbostic return; 16128349Smckusick } 16234056Sbostic if (!rflag) 16334056Sbostic return; 16434056Sbostic if (lstat(file, &buf)) { 16534056Sbostic err(file); 16634056Sbostic return; 16734056Sbostic } 16834056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 16934039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 17034039Sbostic err(file); 17134039Sbostic return; 17218450Smckusick } 17334039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 17434039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 17534039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 17634039Sbostic continue; 17734039Sbostic change(dp->d_name); 17824505Ssam } 17934039Sbostic closedir(dirp); 18034039Sbostic if (chdir("..")) { 18134039Sbostic err(".."); 18234039Sbostic exit(fflag ? 0 : -1); 18334039Sbostic } 18418450Smckusick } 18518450Smckusick } 18624505Ssam 18734039Sbostic static 18834069Sbostic chownerr(file) 18934069Sbostic char *file; 19034069Sbostic { 191*38427Sbostic extern int errno; 19234069Sbostic static int euid = -1, ngroups = -1; 19334069Sbostic 19434069Sbostic /* check for chown without being root */ 195*38427Sbostic if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 19634069Sbostic if (fflag) 19734069Sbostic exit(0); 19834069Sbostic err(file); 19934069Sbostic exit(-1); 20034069Sbostic } 20134069Sbostic /* check group membership; kernel just returns EPERM */ 20234069Sbostic if (gid != -1 && ngroups == -1) { 20334069Sbostic int groups[NGROUPS]; 20434069Sbostic 20534069Sbostic ngroups = getgroups(NGROUPS, groups); 20634069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 20734069Sbostic if (ngroups < 0) { 20834069Sbostic if (fflag) 20934069Sbostic exit(0); 210*38427Sbostic (void)fprintf(stderr, 21134069Sbostic "%s: you are not a member of group %s.\n", 21234069Sbostic myname, gname); 21334069Sbostic exit(-1); 21434069Sbostic } 21534069Sbostic } 21634069Sbostic err(file); 21734069Sbostic } 21834069Sbostic 21934069Sbostic static 22034039Sbostic err(s) 22134039Sbostic char *s; 22224505Ssam { 22336959Sbostic extern int errno; 22436959Sbostic char *strerror(); 22536959Sbostic 22634039Sbostic if (fflag) 22734039Sbostic return; 228*38427Sbostic (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno)); 22934039Sbostic retval = -1; 23024505Ssam } 23124505Ssam 23234039Sbostic static 23334039Sbostic usage() 23424505Ssam { 235*38427Sbostic (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 23634039Sbostic ischown ? "owner[.group]" : "group"); 23734039Sbostic exit(-1); 23824505Ssam } 239