/*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
All rights reserved.\n";
-#endif
+#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)chown.c 5.6 (Berkeley) 5/29/86";
-#endif
+static char sccsid[] = "@(#)chown.c 5.11 (Berkeley) 6/18/88";
+#endif /* not lint */
-/*
- * chown [-fR] uid[.gid] file ...
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/stat.h>
-#include <pwd.h>
#include <sys/dir.h>
+#include <pwd.h>
#include <grp.h>
-#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
-struct passwd *pwd;
-struct passwd *getpwnam();
-struct stat stbuf;
-int uid;
-int status;
-int fflag;
-int rflag;
+static int ischown, uid, gid, fflag, rflag, retval;
+static char *gname, *myname;
main(argc, argv)
- char *argv[];
+ int argc;
+ char **argv;
{
- register int c, gid;
- register char *cp, *group;
- struct group *grp;
+ extern char *optarg;
+ extern int optind;
+ register char *cp;
+ int ch;
+ char *index(), *rindex();
- argc--, argv++;
- while (argc > 0 && argv[0][0] == '-') {
- for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
+ myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
+ ischown = myname[2] == 'o';
+ while ((ch = getopt(argc, argv, "Rf")) != EOF)
+ switch((char)ch) {
+ case 'R':
+ rflag++;
+ break;
case 'f':
fflag++;
break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
- case 'R':
- rflag++;
- break;
+ if (argc < 2)
+ usage();
- default:
- fatal(255, "unknown option: %c", *cp);
+ if (ischown) {
+ if (cp = index(*argv, '.')) {
+ *cp++ = '\0';
+ setgid(cp);
}
- argv++, argc--;
+ else
+ gid = -1;
+ setuid(*argv);
}
- if (argc < 2) {
- fprintf(stderr, "usage: chown [-fR] owner[.group] file ...\n");
- exit(-1);
+ else {
+ uid = -1;
+ setgid(*argv);
}
- gid = -1;
- group = index(argv[0], '.');
- if (group != NULL) {
- *group++ = '\0';
- if (!isnumber(group)) {
- if ((grp = getgrnam(group)) == NULL)
- fatal(255, "unknown group: %s",group);
- gid = grp -> gr_gid;
- (void) endgrent();
- } else if (*group != '\0')
- gid = atoi(group);
+
+ while (*++argv)
+ change(*argv);
+ exit(retval);
+}
+
+static
+setgid(s)
+ register char *s;
+{
+ struct group *gr, *getgrnam();
+
+ if (!*s) {
+ gid = -1; /* argument was "uid." */
+ return;
}
- if (!isnumber(argv[0])) {
- if ((pwd = getpwnam(argv[0])) == NULL)
- fatal(255, "unknown user id: %s",argv[0]);
- uid = pwd->pw_uid;
- } else
- uid = atoi(argv[0]);
- for (c = 1; c < argc; c++) {
- /* do stat for directory arguments */
- if (lstat(argv[c], &stbuf) < 0) {
- status += Perror(argv[c]);
- continue;
- }
- if (rflag && ((stbuf.st_mode&S_IFMT) == S_IFDIR)) {
- status += chownr(argv[c], uid, gid);
- continue;
- }
- if (chown(argv[c], uid, gid)) {
- status += Perror(argv[c]);
- continue;
+ for (gname = s; *s && isdigit(*s); ++s);
+ if (!*s)
+ gid = atoi(gname);
+ else {
+ if (!(gr = getgrnam(gname))) {
+ if (fflag)
+ exit(0);
+ fprintf(stderr, "%s: unknown group id: %s\n",
+ myname, gname);
+ exit(-1);
}
+ gid = gr->gr_gid;
}
- exit(status);
}
-isnumber(s)
- char *s;
+static
+setuid(s)
+ register char *s;
{
- register c;
+ struct passwd *pwd, *getpwnam();
+ char *beg;
- while(c = *s++)
- if (!isdigit(c))
- return (0);
- return (1);
+ if (!*s) {
+ uid = -1; /* argument was ".gid" */
+ return;
+ }
+ for (beg = s; *s && isdigit(*s); ++s);
+ if (!*s)
+ uid = atoi(beg);
+ else {
+ if (!(pwd = getpwnam(beg))) {
+ if (fflag)
+ exit(0);
+ fprintf(stderr, "chown: unknown user id: %s\n", beg);
+ exit(-1);
+ }
+ uid = pwd->pw_uid;
+ }
}
-chownr(dir, uid, gid)
- char *dir;
+static
+change(file)
+ char *file;
{
register DIR *dirp;
register struct direct *dp;
- struct stat st;
- char savedir[1024];
- int ecode;
- extern char *getwd();
-
- if (getwd(savedir) == (char *)0)
- fatal(255, "%s", savedir);
- /*
- * Change what we are given before doing it's contents.
- */
- if (chown(dir, uid, gid) < 0 && Perror(dir))
- return (1);
- if (chdir(dir) < 0) {
- Perror(dir);
- return (1);
+ struct stat buf;
+
+ if (chown(file, uid, gid)) {
+ chownerr(file);
+ return;
}
- if ((dirp = opendir(".")) == NULL) {
- Perror(dir);
- return (1);
+ if (!rflag)
+ return;
+ if (lstat(file, &buf)) {
+ err(file);
+ return;
}
- dp = readdir(dirp);
- dp = readdir(dirp); /* read "." and ".." */
- ecode = 0;
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- if (lstat(dp->d_name, &st) < 0) {
- ecode = Perror(dp->d_name);
- if (ecode)
- break;
- continue;
+ if ((buf.st_mode & S_IFMT) == S_IFDIR) {
+ if (chdir(file) < 0 || !(dirp = opendir("."))) {
+ err(file);
+ return;
}
- if ((st.st_mode&S_IFMT) == S_IFDIR) {
- ecode = chownr(dp->d_name, uid, gid);
- if (ecode)
- break;
- continue;
+ for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
+ if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
+ dp->d_name[1] == '.' && !dp->d_name[2]))
+ continue;
+ change(dp->d_name);
+ }
+ closedir(dirp);
+ if (chdir("..")) {
+ err("..");
+ exit(fflag ? 0 : -1);
}
- if (chown(dp->d_name, uid, gid) < 0 &&
- (ecode = Perror(dp->d_name)))
- break;
}
- closedir(dirp);
- if (chdir(savedir) < 0)
- fatal(255, "can't change back to %s", savedir);
- return (ecode);
}
-error(fmt, a)
- char *fmt, *a;
+static
+chownerr(file)
+ char *file;
{
+ static int euid = -1, ngroups = -1;
- if (!fflag) {
- fprintf(stderr, "chown: ");
- fprintf(stderr, fmt, a);
- putc('\n', stderr);
+ /* check for chown without being root */
+ if (uid != -1 && euid == -1 && (euid = geteuid())) {
+ if (fflag)
+ exit(0);
+ err(file);
+ exit(-1);
+ }
+ /* check group membership; kernel just returns EPERM */
+ if (gid != -1 && ngroups == -1) {
+ int groups[NGROUPS];
+
+ ngroups = getgroups(NGROUPS, groups);
+ while (--ngroups >= 0 && gid != groups[ngroups]);
+ if (ngroups < 0) {
+ if (fflag)
+ exit(0);
+ fprintf(stderr,
+ "%s: you are not a member of group %s.\n",
+ myname, gname);
+ exit(-1);
+ }
}
- return (!fflag);
+ err(file);
}
-fatal(status, fmt, a)
- int status;
- char *fmt, *a;
+static
+err(s)
+ char *s;
{
-
- fflag = 0;
- (void) error(fmt, a);
- exit(status);
+ if (fflag)
+ return;
+ fprintf(stderr, "%s: ", myname);
+ perror(s);
+ retval = -1;
}
-Perror(s)
- char *s;
+static
+usage()
{
-
- if (!fflag) {
- fprintf(stderr, "chown: ");
- perror(s);
- }
- return (!fflag);
+ fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
+ ischown ? "owner[.group]" : "group");
+ exit(-1);
}