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 6*34777Sbostic * provided that the above copyright notice and this paragraph are 7*34777Sbostic * duplicated in all such forms and that any documentation, 8*34777Sbostic * advertising materials, and other materials related to such 9*34777Sbostic * distribution and use acknowledge that the software was developed 10*34777Sbostic * by the University of California, Berkeley. The name of the 11*34777Sbostic * University may not be used to endorse or promote products derived 12*34777Sbostic * from this software without specific prior written permission. 13*34777Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34777Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34777Sbostic * 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*34777Sbostic static char sccsid[] = "@(#)chown.c 5.11 (Berkeley) 06/18/88"; 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; 4734039Sbostic char *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 8434039Sbostic while (*++argv) 8534039Sbostic change(*argv); 8634039Sbostic exit(retval); 8734039Sbostic } 8834039Sbostic 8934039Sbostic static 9034039Sbostic setgid(s) 9134039Sbostic register char *s; 9234039Sbostic { 9334039Sbostic struct group *gr, *getgrnam(); 9434039Sbostic 9534039Sbostic if (!*s) { 9634039Sbostic gid = -1; /* argument was "uid." */ 9734039Sbostic return; 9811442Smckusick } 9934056Sbostic for (gname = s; *s && isdigit(*s); ++s); 10034039Sbostic if (!*s) 10134056Sbostic gid = atoi(gname); 10234039Sbostic else { 10334056Sbostic if (!(gr = getgrnam(gname))) { 10434039Sbostic if (fflag) 10534039Sbostic exit(0); 10634039Sbostic fprintf(stderr, "%s: unknown group id: %s\n", 10734056Sbostic myname, gname); 10834039Sbostic exit(-1); 10918450Smckusick } 11034039Sbostic gid = gr->gr_gid; 111975Sbill } 112975Sbill } 113975Sbill 11434039Sbostic static 11534039Sbostic setuid(s) 11634039Sbostic register char *s; 117975Sbill { 11834039Sbostic struct passwd *pwd, *getpwnam(); 11934039Sbostic char *beg; 120975Sbill 12134039Sbostic if (!*s) { 12234039Sbostic uid = -1; /* argument was ".gid" */ 12334039Sbostic return; 12434039Sbostic } 12534039Sbostic for (beg = s; *s && isdigit(*s); ++s); 12634039Sbostic if (!*s) 12734039Sbostic uid = atoi(beg); 12834039Sbostic else { 12934039Sbostic if (!(pwd = getpwnam(beg))) { 13034039Sbostic if (fflag) 13134039Sbostic exit(0); 13234039Sbostic fprintf(stderr, "chown: unknown user id: %s\n", beg); 13334039Sbostic exit(-1); 13434039Sbostic } 13534039Sbostic uid = pwd->pw_uid; 13634039Sbostic } 137975Sbill } 13818450Smckusick 13934039Sbostic static 14034039Sbostic change(file) 14134039Sbostic char *file; 14218450Smckusick { 14324505Ssam register DIR *dirp; 14424505Ssam register struct direct *dp; 14534039Sbostic struct stat buf; 14618450Smckusick 14734056Sbostic if (chown(file, uid, gid)) { 14834069Sbostic chownerr(file); 14934039Sbostic return; 15028349Smckusick } 15134056Sbostic if (!rflag) 15234056Sbostic return; 15334056Sbostic if (lstat(file, &buf)) { 15434056Sbostic err(file); 15534056Sbostic return; 15634056Sbostic } 15734056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 15834039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 15934039Sbostic err(file); 16034039Sbostic return; 16118450Smckusick } 16234039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 16334039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 16434039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 16534039Sbostic continue; 16634039Sbostic change(dp->d_name); 16724505Ssam } 16834039Sbostic closedir(dirp); 16934039Sbostic if (chdir("..")) { 17034039Sbostic err(".."); 17134039Sbostic exit(fflag ? 0 : -1); 17234039Sbostic } 17318450Smckusick } 17418450Smckusick } 17524505Ssam 17634039Sbostic static 17734069Sbostic chownerr(file) 17834069Sbostic char *file; 17934069Sbostic { 18034069Sbostic static int euid = -1, ngroups = -1; 18134069Sbostic 18234069Sbostic /* check for chown without being root */ 18334069Sbostic if (uid != -1 && euid == -1 && (euid = geteuid())) { 18434069Sbostic if (fflag) 18534069Sbostic exit(0); 18634069Sbostic err(file); 18734069Sbostic exit(-1); 18834069Sbostic } 18934069Sbostic /* check group membership; kernel just returns EPERM */ 19034069Sbostic if (gid != -1 && ngroups == -1) { 19134069Sbostic int groups[NGROUPS]; 19234069Sbostic 19334069Sbostic ngroups = getgroups(NGROUPS, groups); 19434069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 19534069Sbostic if (ngroups < 0) { 19634069Sbostic if (fflag) 19734069Sbostic exit(0); 19834069Sbostic fprintf(stderr, 19934069Sbostic "%s: you are not a member of group %s.\n", 20034069Sbostic myname, gname); 20134069Sbostic exit(-1); 20234069Sbostic } 20334069Sbostic } 20434069Sbostic err(file); 20534069Sbostic } 20634069Sbostic 20734069Sbostic static 20834039Sbostic err(s) 20934039Sbostic char *s; 21024505Ssam { 21134039Sbostic if (fflag) 21234039Sbostic return; 21334056Sbostic fprintf(stderr, "%s: ", myname); 21434039Sbostic perror(s); 21534039Sbostic retval = -1; 21624505Ssam } 21724505Ssam 21834039Sbostic static 21934039Sbostic usage() 22024505Ssam { 22134039Sbostic fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 22234039Sbostic ischown ? "owner[.group]" : "group"); 22334039Sbostic exit(-1); 22424505Ssam } 225