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 634039Sbostic * provided that this notice is preserved and that due credit is given 734039Sbostic * to the University of California at Berkeley. The name of the University 834039Sbostic * may not be used to endorse or promote products derived from this 934039Sbostic * software without specific prior written permission. This software 1034039Sbostic * is provided ``as is'' without express or implied warranty. 1122488Sdist */ 1218450Smckusick 1322488Sdist #ifndef lint 1422488Sdist char copyright[] = 1534039Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 1622488Sdist All rights reserved.\n"; 1734039Sbostic #endif /* not lint */ 1822488Sdist 1922488Sdist #ifndef lint 20*34069Sbostic static char sccsid[] = "@(#)chown.c 5.10 (Berkeley) 04/23/88"; 2134039Sbostic #endif /* not lint */ 2222488Sdist 2334039Sbostic #include <sys/param.h> 24975Sbill #include <sys/stat.h> 2534039Sbostic #include <sys/dir.h> 26975Sbill #include <pwd.h> 2718450Smckusick #include <grp.h> 2834039Sbostic #include <stdio.h> 2934039Sbostic #include <ctype.h> 30975Sbill 3134039Sbostic static int ischown, uid, gid, fflag, rflag, retval; 3234056Sbostic static char *gname, *myname; 33975Sbill 34975Sbill main(argc, argv) 3534039Sbostic int argc; 3634039Sbostic char **argv; 37975Sbill { 3834039Sbostic extern char *optarg; 3934039Sbostic extern int optind; 4034039Sbostic register char *cp; 4134039Sbostic int ch; 4234039Sbostic char *index(), *rindex(); 43975Sbill 4434039Sbostic myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 4534039Sbostic ischown = myname[2] == 'o'; 4624505Ssam 4734039Sbostic while ((ch = getopt(argc, argv, "Rf")) != EOF) 4834039Sbostic switch((char)ch) { 4934039Sbostic case 'R': 5034039Sbostic rflag++; 5134039Sbostic break; 5224505Ssam case 'f': 5324505Ssam fflag++; 5424505Ssam break; 5534039Sbostic case '?': 5634039Sbostic default: 5734039Sbostic usage(); 5834039Sbostic } 5934039Sbostic argv += optind; 6034039Sbostic argc -= optind; 6124505Ssam 6234039Sbostic if (argc < 2) 6334039Sbostic usage(); 6424505Ssam 6534039Sbostic if (ischown) { 6634039Sbostic if (cp = index(*argv, '.')) { 6734039Sbostic *cp++ = '\0'; 6834039Sbostic setgid(cp); 6924505Ssam } 7034039Sbostic else 7134039Sbostic gid = -1; 7234039Sbostic setuid(*argv); 7324505Ssam } 7434039Sbostic else { 7534039Sbostic uid = -1; 7634039Sbostic setgid(*argv); 77975Sbill } 7834039Sbostic 7934039Sbostic while (*++argv) 8034039Sbostic change(*argv); 8134039Sbostic exit(retval); 8234039Sbostic } 8334039Sbostic 8434039Sbostic static 8534039Sbostic setgid(s) 8634039Sbostic register char *s; 8734039Sbostic { 8834039Sbostic struct group *gr, *getgrnam(); 8934039Sbostic 9034039Sbostic if (!*s) { 9134039Sbostic gid = -1; /* argument was "uid." */ 9234039Sbostic return; 9311442Smckusick } 9434056Sbostic for (gname = s; *s && isdigit(*s); ++s); 9534039Sbostic if (!*s) 9634056Sbostic gid = atoi(gname); 9734039Sbostic else { 9834056Sbostic if (!(gr = getgrnam(gname))) { 9934039Sbostic if (fflag) 10034039Sbostic exit(0); 10134039Sbostic fprintf(stderr, "%s: unknown group id: %s\n", 10234056Sbostic myname, gname); 10334039Sbostic exit(-1); 10418450Smckusick } 10534039Sbostic gid = gr->gr_gid; 106975Sbill } 107975Sbill } 108975Sbill 10934039Sbostic static 11034039Sbostic setuid(s) 11134039Sbostic register char *s; 112975Sbill { 11334039Sbostic struct passwd *pwd, *getpwnam(); 11434039Sbostic char *beg; 115975Sbill 11634039Sbostic if (!*s) { 11734039Sbostic uid = -1; /* argument was ".gid" */ 11834039Sbostic return; 11934039Sbostic } 12034039Sbostic for (beg = s; *s && isdigit(*s); ++s); 12134039Sbostic if (!*s) 12234039Sbostic uid = atoi(beg); 12334039Sbostic else { 12434039Sbostic if (!(pwd = getpwnam(beg))) { 12534039Sbostic if (fflag) 12634039Sbostic exit(0); 12734039Sbostic fprintf(stderr, "chown: unknown user id: %s\n", beg); 12834039Sbostic exit(-1); 12934039Sbostic } 13034039Sbostic uid = pwd->pw_uid; 13134039Sbostic } 132975Sbill } 13318450Smckusick 13434039Sbostic static 13534039Sbostic change(file) 13634039Sbostic char *file; 13718450Smckusick { 13824505Ssam register DIR *dirp; 13924505Ssam register struct direct *dp; 14034039Sbostic struct stat buf; 14118450Smckusick 14234056Sbostic if (chown(file, uid, gid)) { 143*34069Sbostic chownerr(file); 14434039Sbostic return; 14528349Smckusick } 14634056Sbostic if (!rflag) 14734056Sbostic return; 14834056Sbostic if (lstat(file, &buf)) { 14934056Sbostic err(file); 15034056Sbostic return; 15134056Sbostic } 15234056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 15334039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 15434039Sbostic err(file); 15534039Sbostic return; 15618450Smckusick } 15734039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 15834039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 15934039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 16034039Sbostic continue; 16134039Sbostic change(dp->d_name); 16224505Ssam } 16334039Sbostic closedir(dirp); 16434039Sbostic if (chdir("..")) { 16534039Sbostic err(".."); 16634039Sbostic exit(fflag ? 0 : -1); 16734039Sbostic } 16818450Smckusick } 16918450Smckusick } 17024505Ssam 17134039Sbostic static 172*34069Sbostic chownerr(file) 173*34069Sbostic char *file; 174*34069Sbostic { 175*34069Sbostic static int euid = -1, ngroups = -1; 176*34069Sbostic 177*34069Sbostic /* check for chown without being root */ 178*34069Sbostic if (uid != -1 && euid == -1 && (euid = geteuid())) { 179*34069Sbostic if (fflag) 180*34069Sbostic exit(0); 181*34069Sbostic err(file); 182*34069Sbostic exit(-1); 183*34069Sbostic } 184*34069Sbostic /* check group membership; kernel just returns EPERM */ 185*34069Sbostic if (gid != -1 && ngroups == -1) { 186*34069Sbostic int groups[NGROUPS]; 187*34069Sbostic 188*34069Sbostic ngroups = getgroups(NGROUPS, groups); 189*34069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 190*34069Sbostic if (ngroups < 0) { 191*34069Sbostic if (fflag) 192*34069Sbostic exit(0); 193*34069Sbostic fprintf(stderr, 194*34069Sbostic "%s: you are not a member of group %s.\n", 195*34069Sbostic myname, gname); 196*34069Sbostic exit(-1); 197*34069Sbostic } 198*34069Sbostic } 199*34069Sbostic err(file); 200*34069Sbostic } 201*34069Sbostic 202*34069Sbostic static 20334039Sbostic err(s) 20434039Sbostic char *s; 20524505Ssam { 20634039Sbostic if (fflag) 20734039Sbostic return; 20834056Sbostic fprintf(stderr, "%s: ", myname); 20934039Sbostic perror(s); 21034039Sbostic retval = -1; 21124505Ssam } 21224505Ssam 21334039Sbostic static 21434039Sbostic usage() 21524505Ssam { 21634039Sbostic fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 21734039Sbostic ischown ? "owner[.group]" : "group"); 21834039Sbostic exit(-1); 21924505Ssam } 220