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*41090Smarc static char sccsid[] = "@(#)chown.c 5.14 (Berkeley) 04/25/90"; 2634039Sbostic #endif /* not lint */ 2722488Sdist 2834039Sbostic #include <sys/param.h> 29975Sbill #include <sys/stat.h> 3038427Sbostic #include <sys/errno.h> 3138427Sbostic #include <dirent.h> 32975Sbill #include <pwd.h> 3318450Smckusick #include <grp.h> 3434039Sbostic #include <stdio.h> 3534039Sbostic #include <ctype.h> 36975Sbill 37*41090Smarc int ischown, uid, gid, fflag, rflag, retval; 38*41090Smarc 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 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); 11538427Sbostic (void)fprintf(stderr, "%s: unknown group id: %s\n", 11634056Sbostic myname, gname); 11734039Sbostic exit(-1); 11818450Smckusick } 11934039Sbostic gid = gr->gr_gid; 120975Sbill } 121975Sbill } 122975Sbill 12334039Sbostic setuid(s) 12434039Sbostic register char *s; 125975Sbill { 12634039Sbostic struct passwd *pwd, *getpwnam(); 12734039Sbostic char *beg; 128975Sbill 12934039Sbostic if (!*s) { 13034039Sbostic uid = -1; /* argument was ".gid" */ 13134039Sbostic return; 13234039Sbostic } 13334039Sbostic for (beg = s; *s && isdigit(*s); ++s); 13434039Sbostic if (!*s) 13534039Sbostic uid = atoi(beg); 13634039Sbostic else { 13734039Sbostic if (!(pwd = getpwnam(beg))) { 13834039Sbostic if (fflag) 13934039Sbostic exit(0); 14038427Sbostic (void)fprintf(stderr, 14138427Sbostic "chown: unknown user id: %s\n", beg); 14234039Sbostic exit(-1); 14334039Sbostic } 14434039Sbostic uid = pwd->pw_uid; 14534039Sbostic } 146975Sbill } 14718450Smckusick 14834039Sbostic change(file) 14934039Sbostic char *file; 15018450Smckusick { 15124505Ssam register DIR *dirp; 15238427Sbostic register struct dirent *dp; 15334039Sbostic struct stat buf; 15418450Smckusick 15534056Sbostic if (chown(file, uid, gid)) { 15634069Sbostic chownerr(file); 15734039Sbostic return; 15828349Smckusick } 15934056Sbostic if (!rflag) 16034056Sbostic return; 16134056Sbostic if (lstat(file, &buf)) { 16234056Sbostic err(file); 16334056Sbostic return; 16434056Sbostic } 16534056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 16634039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 16734039Sbostic err(file); 16834039Sbostic return; 16918450Smckusick } 17034039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 17134039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 17234039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 17334039Sbostic continue; 17434039Sbostic change(dp->d_name); 17524505Ssam } 17634039Sbostic closedir(dirp); 17734039Sbostic if (chdir("..")) { 17834039Sbostic err(".."); 17934039Sbostic exit(fflag ? 0 : -1); 18034039Sbostic } 18118450Smckusick } 18218450Smckusick } 18324505Ssam 18434069Sbostic chownerr(file) 18534069Sbostic char *file; 18634069Sbostic { 18738427Sbostic extern int errno; 18834069Sbostic static int euid = -1, ngroups = -1; 18934069Sbostic 19034069Sbostic /* check for chown without being root */ 19138427Sbostic if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 19234069Sbostic if (fflag) 19334069Sbostic exit(0); 19434069Sbostic err(file); 19534069Sbostic exit(-1); 19634069Sbostic } 19734069Sbostic /* check group membership; kernel just returns EPERM */ 19834069Sbostic if (gid != -1 && ngroups == -1) { 19934069Sbostic int groups[NGROUPS]; 20034069Sbostic 20134069Sbostic ngroups = getgroups(NGROUPS, groups); 20234069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 20334069Sbostic if (ngroups < 0) { 20434069Sbostic if (fflag) 20534069Sbostic exit(0); 20638427Sbostic (void)fprintf(stderr, 20734069Sbostic "%s: you are not a member of group %s.\n", 20834069Sbostic myname, gname); 20934069Sbostic exit(-1); 21034069Sbostic } 21134069Sbostic } 21234069Sbostic err(file); 21334069Sbostic } 21434069Sbostic 21534039Sbostic err(s) 21634039Sbostic char *s; 21724505Ssam { 21836959Sbostic extern int errno; 21936959Sbostic char *strerror(); 22036959Sbostic 22134039Sbostic if (fflag) 22234039Sbostic return; 22338427Sbostic (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno)); 22434039Sbostic retval = -1; 22524505Ssam } 22624505Ssam 22734039Sbostic usage() 22824505Ssam { 22938427Sbostic (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 23034039Sbostic ischown ? "owner[.group]" : "group"); 23134039Sbostic exit(-1); 23224505Ssam } 233