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*34056Sbostic static char sccsid[] = "@(#)chown.c 5.9 (Berkeley) 04/22/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; 32*34056Sbostic 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 } 94*34056Sbostic for (gname = s; *s && isdigit(*s); ++s); 9534039Sbostic if (!*s) 96*34056Sbostic gid = atoi(gname); 9734039Sbostic else { 98*34056Sbostic if (!(gr = getgrnam(gname))) { 9934039Sbostic if (fflag) 10034039Sbostic exit(0); 10134039Sbostic fprintf(stderr, "%s: unknown group id: %s\n", 102*34056Sbostic 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 142*34056Sbostic if (chown(file, uid, gid)) { 143*34056Sbostic static int euid = -1, ngroups = -1; 144*34056Sbostic 145*34056Sbostic if (uid != -1 && euid == -1 && (euid = geteuid())) { 146*34056Sbostic if (fflag) 147*34056Sbostic exit(0); 148*34056Sbostic err(file); 149*34056Sbostic exit(-1); 150*34056Sbostic } 151*34056Sbostic /* check group membership; kernel just returns EPERM */ 152*34056Sbostic if (gid != -1 && ngroups == -1) { 153*34056Sbostic int groups[NGROUPS]; 154*34056Sbostic 155*34056Sbostic ngroups = getgroups(NGROUPS, groups); 156*34056Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 157*34056Sbostic if (ngroups < 0) { 158*34056Sbostic if (fflag) 159*34056Sbostic exit(0); 160*34056Sbostic fprintf(stderr, 161*34056Sbostic "%s: you are not a member of group %s.\n", 162*34056Sbostic myname, gname); 163*34056Sbostic exit(-1); 164*34056Sbostic } 165*34056Sbostic } 16634039Sbostic err(file); 16734039Sbostic return; 16828349Smckusick } 169*34056Sbostic if (!rflag) 170*34056Sbostic return; 171*34056Sbostic if (lstat(file, &buf)) { 172*34056Sbostic err(file); 173*34056Sbostic return; 174*34056Sbostic } 175*34056Sbostic if ((buf.st_mode & S_IFMT) == S_IFDIR) { 17634039Sbostic if (chdir(file) < 0 || !(dirp = opendir("."))) { 17734039Sbostic err(file); 17834039Sbostic return; 17918450Smckusick } 18034039Sbostic for (dp = readdir(dirp); dp; dp = readdir(dirp)) { 18134039Sbostic if (dp->d_name[0] == '.' && (!dp->d_name[1] || 18234039Sbostic dp->d_name[1] == '.' && !dp->d_name[2])) 18334039Sbostic continue; 18434039Sbostic change(dp->d_name); 18524505Ssam } 18634039Sbostic closedir(dirp); 18734039Sbostic if (chdir("..")) { 18834039Sbostic err(".."); 18934039Sbostic exit(fflag ? 0 : -1); 19034039Sbostic } 19118450Smckusick } 19218450Smckusick } 19324505Ssam 19434039Sbostic static 19534039Sbostic err(s) 19634039Sbostic char *s; 19724505Ssam { 19834039Sbostic if (fflag) 19934039Sbostic return; 200*34056Sbostic fprintf(stderr, "%s: ", myname); 20134039Sbostic perror(s); 20234039Sbostic retval = -1; 20324505Ssam } 20424505Ssam 20534039Sbostic static 20634039Sbostic usage() 20724505Ssam { 20834039Sbostic fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 20934039Sbostic ischown ? "owner[.group]" : "group"); 21034039Sbostic exit(-1); 21124505Ssam } 212