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*36959Sbostic static char sccsid[] = "@(#)chown.c 5.12 (Berkeley) 03/05/89"; 2634039Sbostic #endif /* not lint */ 2722488Sdist 2834039Sbostic #include <sys/param.h> 29975Sbill #include <sys/stat.h> 3034039Sbostic #include <sys/dir.h> 31975Sbill #include <pwd.h> 3218450Smckusick #include <grp.h> 3334039Sbostic #include <stdio.h> 3434039Sbostic #include <ctype.h> 35975Sbill 3634039Sbostic static int ischown, uid, gid, fflag, rflag, retval; 3734056Sbostic static char *gname, *myname; 38975Sbill 39975Sbill main(argc, argv) 4034039Sbostic int argc; 4134039Sbostic char **argv; 42975Sbill { 4334039Sbostic extern char *optarg; 4434039Sbostic extern int optind; 4534039Sbostic register char *cp; 4634039Sbostic int ch; 47*36959Sbostic char curpath[MAXPATHLEN], *reset, *index(), *rindex(); 48975Sbill 4934039Sbostic myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 5034039Sbostic ischown = myname[2] == 'o'; 5124505Ssam 5234039Sbostic while ((ch = getopt(argc, argv, "Rf")) != EOF) 5334039Sbostic switch((char)ch) { 5434039Sbostic case 'R': 5534039Sbostic rflag++; 5634039Sbostic break; 5724505Ssam case 'f': 5824505Ssam fflag++; 5924505Ssam break; 6034039Sbostic case '?': 6134039Sbostic default: 6234039Sbostic usage(); 6334039Sbostic } 6434039Sbostic argv += optind; 6534039Sbostic argc -= optind; 6624505Ssam 6734039Sbostic if (argc < 2) 6834039Sbostic usage(); 6924505Ssam 7034039Sbostic if (ischown) { 7134039Sbostic if (cp = index(*argv, '.')) { 7234039Sbostic *cp++ = '\0'; 7334039Sbostic setgid(cp); 7424505Ssam } 7534039Sbostic else 7634039Sbostic gid = -1; 7734039Sbostic setuid(*argv); 7824505Ssam } 7934039Sbostic else { 8034039Sbostic uid = -1; 8134039Sbostic setgid(*argv); 82975Sbill } 8334039Sbostic 84*36959Sbostic while (*++argv) { 85*36959Sbostic if (reset = index(*argv, '/')) 86*36959Sbostic (void)getwd(curpath); 8734039Sbostic change(*argv); 88*36959Sbostic if (reset && chdir(curpath)) { 89*36959Sbostic if (fflag) 90*36959Sbostic exit(0); 91*36959Sbostic err(curpath); 92*36959Sbostic exit(-1); 93*36959Sbostic } 94*36959Sbostic } 9534039Sbostic exit(retval); 9634039Sbostic } 9734039Sbostic 9834039Sbostic static 9934039Sbostic setgid(s) 10034039Sbostic register char *s; 10134039Sbostic { 10234039Sbostic struct group *gr, *getgrnam(); 10334039Sbostic 10434039Sbostic if (!*s) { 10534039Sbostic gid = -1; /* argument was "uid." */ 10634039Sbostic return; 10711442Smckusick } 10834056Sbostic for (gname = s; *s && isdigit(*s); ++s); 10934039Sbostic if (!*s) 11034056Sbostic gid = atoi(gname); 11134039Sbostic else { 11234056Sbostic if (!(gr = getgrnam(gname))) { 11334039Sbostic if (fflag) 11434039Sbostic exit(0); 11534039Sbostic fprintf(stderr, "%s: unknown group id: %s\n", 11634056Sbostic myname, gname); 11734039Sbostic exit(-1); 11818450Smckusick } 11934039Sbostic gid = gr->gr_gid; 120975Sbill } 121975Sbill } 122975Sbill 12334039Sbostic static 12434039Sbostic setuid(s) 12534039Sbostic register char *s; 126975Sbill { 12734039Sbostic struct passwd *pwd, *getpwnam(); 12834039Sbostic char *beg; 129975Sbill 13034039Sbostic if (!*s) { 13134039Sbostic uid = -1; /* argument was ".gid" */ 13234039Sbostic return; 13334039Sbostic } 13434039Sbostic for (beg = s; *s && isdigit(*s); ++s); 13534039Sbostic if (!*s) 13634039Sbostic uid = atoi(beg); 13734039Sbostic else { 13834039Sbostic if (!(pwd = getpwnam(beg))) { 13934039Sbostic if (fflag) 14034039Sbostic exit(0); 14134039Sbostic fprintf(stderr, "chown: unknown user id: %s\n", beg); 14234039Sbostic exit(-1); 14334039Sbostic } 14434039Sbostic uid = pwd->pw_uid; 14534039Sbostic } 146975Sbill } 14718450Smckusick 14834039Sbostic static 14934039Sbostic change(file) 15034039Sbostic char *file; 15118450Smckusick { 15224505Ssam register DIR *dirp; 15324505Ssam register struct direct *dp; 15434039Sbostic struct stat buf; 15518450Smckusick 15634056Sbostic if (chown(file, uid, gid)) { 15734069Sbostic chownerr(file); 15834039Sbostic return; 15928349Smckusick } 16034056Sbostic if (!rflag) 16134056Sbostic return; 16234056Sbostic if (lstat(file, &buf)) { 16334056Sbostic err(file); 16434056Sbostic return; 16534056Sbostic } 16634056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 16734039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 16834039Sbostic err(file); 16934039Sbostic return; 17018450Smckusick } 17134039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 17234039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 17334039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 17434039Sbostic continue; 17534039Sbostic change(dp->d_name); 17624505Ssam } 17734039Sbostic closedir(dirp); 17834039Sbostic if (chdir("..")) { 17934039Sbostic err(".."); 18034039Sbostic exit(fflag ? 0 : -1); 18134039Sbostic } 18218450Smckusick } 18318450Smckusick } 18424505Ssam 18534039Sbostic static 18634069Sbostic chownerr(file) 18734069Sbostic char *file; 18834069Sbostic { 18934069Sbostic static int euid = -1, ngroups = -1; 19034069Sbostic 19134069Sbostic /* check for chown without being root */ 19234069Sbostic if (uid != -1 && euid == -1 && (euid = geteuid())) { 19334069Sbostic if (fflag) 19434069Sbostic exit(0); 19534069Sbostic err(file); 19634069Sbostic exit(-1); 19734069Sbostic } 19834069Sbostic /* check group membership; kernel just returns EPERM */ 19934069Sbostic if (gid != -1 && ngroups == -1) { 20034069Sbostic int groups[NGROUPS]; 20134069Sbostic 20234069Sbostic ngroups = getgroups(NGROUPS, groups); 20334069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 20434069Sbostic if (ngroups < 0) { 20534069Sbostic if (fflag) 20634069Sbostic exit(0); 20734069Sbostic fprintf(stderr, 20834069Sbostic "%s: you are not a member of group %s.\n", 20934069Sbostic myname, gname); 21034069Sbostic exit(-1); 21134069Sbostic } 21234069Sbostic } 21334069Sbostic err(file); 21434069Sbostic } 21534069Sbostic 21634069Sbostic static 21734039Sbostic err(s) 21834039Sbostic char *s; 21924505Ssam { 220*36959Sbostic extern int errno; 221*36959Sbostic char *strerror(); 222*36959Sbostic 22334039Sbostic if (fflag) 22434039Sbostic return; 225*36959Sbostic fprintf(stderr, "%s: %s: %s", myname, s, strerror(errno)); 22634039Sbostic retval = -1; 22724505Ssam } 22824505Ssam 22934039Sbostic static 23034039Sbostic usage() 23124505Ssam { 23234039Sbostic fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 23334039Sbostic ischown ? "owner[.group]" : "group"); 23434039Sbostic exit(-1); 23524505Ssam } 236