From: jason@jarthur.claremont.edu (Fool on a Pedestal)
Subject: Fix for chown(2)-related probs on Sequents
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 11 Nov 1992 03:01:07 GMT

My strategy went along the lines of the rename/mvdir pair already in the
fileutils distribution; I wrote a wrapper for chown(2), called dochown,
which is installed setuid root.  The programs then call xchown, which
spawns a dochown process if necessary.  If chown(2) behaves reasonably,
then xchown is #defined to chown.

Previously the code for dochown was sitting in the middle of chgrp, but I
decided to break it out so that chown and install could behave reasonably,
too.

The check for chown(2) brain damage requires using AC_TEST_PROG; is this an
acceptable thing to do?

diff -ur tmp/fileutils-3.4/Makefile.in fileutils-3.4/Makefile.in
--- tmp/fileutils-3.4/Makefile.in	Thu Sep 10 19:46:28 1992
+++ fileutils-3.4/Makefile.in	Tue Nov 10 18:30:07 1992
@@ -60,6 +60,10 @@
 # -DAFS			If you use the Andrew File System and want
 #			install to ignore AFS errors from trying to
 #			change files' groups.
+# -DDOCHOWN=\"$(libdir)/dochown\"
+#			If your chown system call can only be used by the
+#			superuser (Sequent Dynix), so must be called
+#			suid root.
 # Define zero or one of the following; you need one to compile df.
 # The numbers after STATFS are the number of args it's passed.
 # See lib/fsusage.c for more details.
diff -ur tmp/fileutils-3.4/configure.in fileutils-3.4/configure.in
--- tmp/fileutils-3.4/configure.in	Thu Oct 29 11:57:10 1992
+++ fileutils-3.4/configure.in	Tue Nov 10 17:30:10 1992
@@ -119,6 +119,11 @@
 AC_ALLOCA
 AC_ST_BLOCKS
 AC_UTIME_NULL
+echo checking for brain damaged chown
+touch conftest.f
+AC_TEST_PROGRAM([main() { return chown("conftest.f",getuid(),getgid()); }]
+, ,LIBOBJS="$LIBOBJS xchown.o" LIBPROGS="$LIBPROGS dochown" 
+AC_DEFINE(DOCHOWN, \\\\\"\$(libdir)/dochown\\\\\"))
 AC_XENIX_DIR
 AC_IRIX_SUN
 AC_DYNIX_SEQ
diff -ur tmp/fileutils-3.4/lib/Makefile.in fileutils-3.4/lib/Makefile.in
--- tmp/fileutils-3.4/lib/Makefile.in	Thu Sep 10 19:24:05 1992
+++ fileutils-3.4/lib/Makefile.in	Tue Nov 10 18:30:32 1992
@@ -28,7 +28,7 @@
 stripslash.c xgetcwd.c xmalloc.c xstrdup.c userspec.c yesno.c \
 getdate.y posixtm.y \
 fileblocks.c fnmatch.c ftruncate.c mkdir.c mktime.c rename.c stpcpy.c \
-strdup.c strstr.c alloca.c
+strdup.c strstr.c alloca.c xchown.c
 
 OBJECTS = argmatch.o backupfile.o basename.o dirname.o eaccess.o \
 error.o filemode.o getopt.o getopt1.o \
diff -ur tmp/fileutils-3.4/lib/makepath.c fileutils-3.4/lib/makepath.c
--- tmp/fileutils-3.4/lib/makepath.c	Sat Aug 22 12:28:18 1992
+++ fileutils-3.4/lib/makepath.c	Tue Nov 10 17:38:24 1992
@@ -61,6 +61,10 @@
 typedef int gid_t;
 #endif
 
+#ifndef DOCHOWN
+#define xchown chown
+#endif
+
 void error ();
 
 /* Ensure that the directory ARGPATH exists.
@@ -144,7 +148,7 @@
 		    error (0, 0, verbose_fmt_string, dirpath);
 
 		  if (owner != (uid_t) -1 && group != (gid_t) -1
-		      && chown (dirpath, owner, group)
+		      && xchown (dirpath, owner, group)
 #ifdef AFS
 		      && errno != EPERM
 #endif
@@ -192,7 +196,7 @@
 
       if (owner != (uid_t) -1 && group != (gid_t) -1)
 	{
-	  if (chown (dirpath, owner, group)
+	  if (xchown (dirpath, owner, group)
 #ifdef AFS
 	      && errno != EPERM
 #endif
@@ -240,7 +244,7 @@
 	 be able to chmod them.  So don't give files away.  */
 
       if (owner != (uid_t) -1 && group != (gid_t) -1
-	  && chown (dirpath, owner, group)
+	  && xchown (dirpath, owner, group)
 #ifdef AFS
 	  && errno != EPERM
 #endif
diff -ur tmp/fileutils-3.4/lib/system.h fileutils-3.4/lib/system.h
--- tmp/fileutils-3.4/lib/system.h	Sat Aug 22 12:03:48 1992
+++ fileutils-3.4/lib/system.h	Tue Nov 10 17:30:24 1992
@@ -226,3 +226,7 @@
 #endif
 #endif
 #endif
+
+#ifndef DOCHOWN
+#define xchown chown
+#endif
diff -ur tmp/fileutils-3.4/lib/xchown.c fileutils-3.4/lib/xchown.c
--- tmp/fileutils-3.4/lib/xchown.c	Tue Nov 10 15:45:02 1992
+++ fileutils-3.4/lib/xchown.c	Tue Nov 10 18:34:00 1992
@@ -0,0 +1,63 @@
+/* xchown.c -- reasonable chown() replacement for Sequent Dynix
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+int
+xchown (path, owner, group)
+     char *path;
+     int owner, group;
+{
+  if (getuid () == 0)
+    return chown (path, owner, group);
+  else
+    {
+      int pid;
+      union wait status;
+      char ownstr[5],grpstr[5];
+
+      sprintf (ownstr, "%d", owner); /* Is there a better way? */
+      sprintf (grpstr, "%d", group);
+  
+      pid = fork ();
+      switch (pid)
+	{
+	case -1:		/* Error. */
+	  error (1, errno, "xchown: cannot fork");
+
+	case 0:			/* Child. */
+	  execl (DOCHOWN, "dochown", path, ownstr, grpstr, 0);
+	  error (255, errno, "xchown: cannot run `%s'", DOCHOWN);
+
+	default:		/* Parent. */
+	  while (wait (&status) != pid)
+	    /* Slack. */ ;
+
+	  errno = status.w_retcode;
+	  if (errno == 2)	/* dochown wasn't happy */
+	    exit (2);
+	  if (errno != 0)
+	    return -1;
+	}
+      return 0;
+    }
+}
diff -ur tmp/fileutils-3.4/src/Makefile.in fileutils-3.4/src/Makefile.in
--- tmp/fileutils-3.4/src/Makefile.in	Thu Sep 10 19:28:13 1992
+++ fileutils-3.4/src/Makefile.in	Tue Nov 10 18:31:07 1992
@@ -23,7 +23,7 @@
 
 SOURCES = chmod.c chgrp.c chown.c cp-aux.c cp-hash.c cp.c \
 dd.c df.c du.c install.c ln.c ls.c mkdir.c mkfifo.c mknod.c mv.c mvdir.c \
-rm.c rmdir.c touch.c version.c
+rm.c rmdir.c touch.c version.c dochown.c
 
 DISTFILES = Makefile.in cp.h $(SOURCES)
 
@@ -88,6 +88,9 @@
 
 dir: dir.o
 	$(CC) $(LDFLAGS) -o $@ dir.o ../lib/libfu.a version.o $(LIBS)
+
+dochown: dochown.o
+	$(CC) $(LDFLAGS) -o $@ dochown.o ../lib/libfu.a version.o $(LIBS)
 
 du: du.o
 	$(CC) $(LDFLAGS) -o $@ du.o ../lib/libfu.a version.o $(LIBS)
diff -ur tmp/fileutils-3.4/src/chgrp.c fileutils-3.4/src/chgrp.c
--- tmp/fileutils-3.4/src/chgrp.c	Fri Jul 17 12:48:38 1992
+++ fileutils-3.4/src/chgrp.c	Tue Nov 10 17:30:59 1992
@@ -167,7 +167,7 @@
     {
       if (verbose)
 	describe_change (file, 1);
-      if (chown (file, file_stats.st_uid, group))
+      if (xchown (file, file_stats.st_uid, group))
 	{
 	  if (force_silent == 0)
 	    error (0, errno, "%s", file);
diff -ur tmp/fileutils-3.4/src/chown.c fileutils-3.4/src/chown.c
--- tmp/fileutils-3.4/src/chown.c	Fri Aug 21 18:32:40 1992
+++ fileutils-3.4/src/chown.c	Tue Nov 10 17:32:05 1992
@@ -171,7 +171,7 @@
     {
       if (verbose)
 	describe_change (file, 1);
-      if (chown (file, newuser, newgroup))
+      if (xchown (file, newuser, newgroup))
 	{
 	  if (force_silent == 0)
 	    error (0, errno, "%s", file);
diff -ur tmp/fileutils-3.4/src/cp.c fileutils-3.4/src/cp.c
--- tmp/fileutils-3.4/src/cp.c	Thu Oct 29 12:01:18 1992
+++ fileutils-3.4/src/cp.c	Tue Nov 10 17:32:41 1992
@@ -741,7 +741,7 @@
 
       /* If non-root uses -p, it's ok if we can't preserve ownership.
 	 But root probably wants to know, e.g. if NFS disallows it.  */
-      if (chown (dst_path, src_sb.st_uid, src_sb.st_gid)
+      if (xchown (dst_path, src_sb.st_uid, src_sb.st_gid)
 	  && (errno != EPERM || myeuid == 0))
 	{
 	  error (0, errno, "%s", dst_path);
@@ -967,7 +967,7 @@
 
 	  /* If non-root uses -p, it's ok if we can't preserve ownership.
 	     But root probably wants to know, e.g. if NFS disallows it.  */
-	  if (chown (dst_path, src_sb.st_uid, src_sb.st_gid)
+	  if (xchown (dst_path, src_sb.st_uid, src_sb.st_gid)
 	      && (errno != EPERM || myeuid == 0))
 	    {
 	      error (0, errno, "%s", dst_path);
diff -ur tmp/fileutils-3.4/src/dochown.c fileutils-3.4/src/dochown.c
--- tmp/fileutils-3.4/src/dochown.c	Tue Nov 10 18:26:38 1992
+++ fileutils-3.4/src/dochown.c	Tue Nov 10 18:18:16 1992
@@ -0,0 +1,117 @@
+/* dochown -- Execute chown() system call on Sequent Symmetry
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Helper program for GNU chgrp and install on systems which restrict the
+   chown() system call (i.e. Sequent Symmetry running Dynix)
+
+   Usage: dochown path owner group
+
+   PATH is the file or directory to modify (string).
+   OWNER is the desired uid (uid_t).
+   GROUP is the desired gid (gid_t).
+   This program performs the necessary sanity checking on its arguments.
+
+   All error messages are #ifdefed so that chgrp can be made silent.
+
+   Must be installed setuid root.
+
+   Jason Merrill (jason@jarthur.claremont.edu) */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include "system.h"
+
+char *program_name;		/* Name of program */
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *path;
+  int owner, group;
+  uid_t uid;
+  int retval;
+  struct stat file_stats;
+
+  program_name = argv[0];
+  if (argc != 4)
+    {
+      int i;
+      fprintf (stderr, "Usage: %s path owner group\n", program_name);
+      for (i = 0; i < argc; i++)
+	fprintf (stderr, "Arg %d: %s\n", i, argv[i]);
+      return 2;
+    }
+
+  path = argv[1];
+  owner = atoi (argv[2]);
+  group = atoi (argv[3]);
+  
+  if (lstat (path, &file_stats))
+    return errno;		/* Problem with file */
+  
+  retval = 0;
+  uid = getuid ();
+  if (uid != 0)			/* No need to check if you're root */
+    {
+      if (owner == -1) owner = file_stats.st_uid;
+      if (group == -1) group = file_stats.st_gid;
+      if (uid != file_stats.st_uid || uid != owner)
+	{
+#ifdef DEBUG	  
+	  error (0, 0, "uid %d, now %d, want %d",
+		 uid, file_stats.st_uid, owner);
+#endif	  
+	  retval = EPERM;		/* Not owner */
+	}
+      else
+	{
+	  struct passwd *pwd = getpwuid (uid);
+	  if (pwd == NULL)
+	    {
+#ifdef DEBUG	      
+	      error (0, 0, "No passwd entry");
+#endif	      
+	      retval = EPERM;	/* Fake user */
+	    }
+	  else if (pwd->pw_gid != group)
+	    {
+	      struct group *grp = getgrgid (group);
+	      char **p = grp->gr_mem;
+	      for (; *p != NULL; p++)
+		if (strcmp (*p, pwd->pw_name) == 0) goto found;
+#ifdef DEBUG
+	      error (0, 0, "Not in group %s", grp->gr_name);
+#endif	      
+	      retval = EPERM;	/* Not in group */
+	    found:
+	      endgrent ();
+	    }
+	  endpwent ();
+	}
+    }
+  if (retval == 0 && chown (path, owner, group))
+    {
+#ifdef DEBUG
+      error (0, errno, "%s", path);
+#endif      
+      retval = errno;
+    }
+  return retval;  
+}
diff -ur tmp/fileutils-3.4/src/install.c fileutils-3.4/src/install.c
--- tmp/fileutils-3.4/src/install.c	Thu Oct 29 11:00:50 1992
+++ fileutils-3.4/src/install.c	Tue Nov 10 17:31:24 1992
@@ -379,7 +379,7 @@
      want to know.  But AFS returns EPERM when you try to change a
      file's group; thus the kludge.  */
 
-  if (chown (path, owner_id, group_id)
+  if (xchown (path, owner_id, group_id)
 #ifdef AFS
       && errno != EPERM
 #endif
diff -ur tmp/fileutils-3.4/src/mv.c fileutils-3.4/src/mv.c
--- tmp/fileutils-3.4/src/mv.c	Thu Oct 29 12:14:28 1992
+++ fileutils-3.4/src/mv.c	Tue Nov 10 17:33:08 1992
@@ -406,7 +406,7 @@
 
   /* Try to preserve ownership.  For non-root it might fail, but that's ok.
      But root probably wants to know, e.g. if NFS disallows it.  */
-  if (chown (dest, source_stats.st_uid, source_stats.st_gid)
+  if (xchown (dest, source_stats.st_uid, source_stats.st_gid)
       && (errno != EPERM || myeuid == 0))
     {
       error (0, errno, "%s", dest);

Newsgroups: gnu.utils.bug