Subject: FTP upload

From: [email-masked] (Robert Chea)
Date: Sun, 9 Jun 1996 17:06:04 -0700

Hi,

I've used some patches that were listed in some of these emails that allows
me to modify the FTP access file so that when a user uploads something, the
uploads will be owned by another group or user.  Unfortunately, since I
installed those patches ( not part of the official wu-ftpd stuff, mind you)
things have been going berserk.  For instance, sometimes, my users won't be
able to create directories in their own accounts, even though they used to
be able to do so. In addition, sometimes when directories are uploaded,
they don't get uploaded with the right permissions, .i.e.,a user uploads a
directory and it gets owned by some random user on my system.  That bizarre
thing only happens for directories though -files are still owned by the
right user.

I don't know if it was the patches that I installed that are causing these
problems.  I do know that installing the patches was the last thing I did
before these problems started arising.  In any event, I'm uninstalling the
patches and waiting for the next official revision of wu-ftpd.

When is the next release going to allow a user to upload files as some
other user or group?

Robert S. Chea
Director of Information Systems
Cedro Group Inc.

---

From: Evan Champion <[email-masked]>
Date: Mon, 10 Jun 1996 07:04:01 -0400

Robert Chea wrote:
> uploads will be owned by another group or user.

I made up a set of patches that I forwarded to the academ people
but never got a response on them.  My patches work just fine with
beta 11.

Note that I had a problem with making directories that looks to
be due to something new in beta 10/11.  In dir_check (extensions.c)
there was a note about changing a && to || on the recommendation
of CERT.  I believe that change breaks the upload dirs/nodirs option
in ftpaccess.  I haven't had time to prove this -- I was trying to
counter a hack attack at the time -- but changing it back to the way
it was seemed to do the trick.  The patches include this fix.

Here are my patches to beta 11.  What they do is they set the owner
and/or group of uploaded files to the owner and/or group of the
directory they are being uploaded in to.  On the upload line in
ftpaccess, set the owner to ":user:" and the group to ":group:"
(without quotes.) I have only tested this in BSDI BSD/OS 2.0 and
2.1, where it works flawlessly.  The only forseeable problem is
that I used INT_MAX in my implementation; you could define this
to any sufficiently large value (anything > 64K would be fine
for most systems).  The point was to choose a value that no one
would use.  AFAIK only 4.4BSD systems have 32 bit user/group
numbers, and I can't think of many people who would create a
uid/gid of 2147483647 :-)

I hope the patches work OK.  I was in a rush to make them as I'm
already late for work :-).  There seem to be some very long lines
so hopefully my editor won't wrap them.  I also attached the patch
at the end in MIME format just in case.

Evan
--
Evan Champion            * Director, Network Operations
mailto:[email-masked] * Directeur, Exploitation du reseau
http://www.synapse.net/  * Synapse Internet

diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/extensions.c /var/home/evanc/wu-evanc/src/extensions.c
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/extensions.c	Mon Apr 15 01:51:05 1996
--- /var/home/evanc/wu-evanc/src/extensions.c	Mon Jun 10 06:39:27 1996
***************
*** 799,814 ****
  
      while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
          if (ARG3 && ARG4) {
              pwent = getpwnam(ARG3);
-             grent = getgrnam(ARG4);
- 
              if (pwent)  sprintf(buf, "%d", pwent->pw_uid);
              else        sprintf(buf, "%d", 0);
              ARG3 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG3, buf);
  
              if (grent)  sprintf(buf, "%d", grent->gr_gid);
              else        sprintf(buf, "%d", 0);
              ARG4 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG4, buf);
  	    endgrent();
--- 799,823 ----
  
      while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
          if (ARG3 && ARG4) {
+ /* set ARG3 to :user: to set owner of uploaded files to owner of directory */
+             if (!strcasecmp(ARG3, ":user:")) sprintf(buf, "%d", INT_MAX);
+ 	    else {
                  pwent = getpwnam(ARG3);
                  if (pwent)  sprintf(buf, "%d", pwent->pw_uid);
                  else        sprintf(buf, "%d", 0);
+ 	    }
+ 
              ARG3 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG3, buf);
  
+ /* set ARG4 to :group: to set group of uploaded files to group of directory */
+ 	    if (!strcasecmp(ARG4, ":group:")) sprintf(buf, "%d", INT_MAX);
+ 	    else {
+                 grent = getgrnam(ARG4);
                  if (grent)  sprintf(buf, "%d", grent->gr_gid);
                  else        sprintf(buf, "%d", 0);
+ 	    }
+ 
              ARG4 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG4, buf);
  	    endgrent();
***************
*** 962,968 ****
    i = match_value;  /* i is -1 here */
    while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
   /* CERT suggested fix (change && to || ) */
!     if ( (!strcmp(ARG0, pw->pw_dir))  ||
  		   ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
            match_value = i;
            ap2 = ARG2;
--- 971,977 ----
    i = match_value;  /* i is -1 here */
    while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
   /* CERT suggested fix (change && to || ) */
!     if ( (!strcmp(ARG0, pw->pw_dir))  &&
  		   ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
            match_value = i;
            ap2 = ARG2;
diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/ftpd.c /var/home/evanc/wu-evanc/src/ftpd.c
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/ftpd.c	Mon Apr 15 01:51:11 1996
--- /var/home/evanc/wu-evanc/src/ftpd.c	Fri May 17 18:45:14 1996
***************
*** 632,662 ****
        entry = (struct aclmember *) NULL;
        while (!set && getaclentry("virtual", &entry)) {
  	if (!strcmp(ARG0, inet_ntoa(virtual_ptr->sin_addr))) {
- 	  if (ARG1 != NULL && ARG2 != NULL) {
- 	    virtual_mode = 1;
- 	    strncpy(virtual_root, ARG1, MAXPATHLEN);
- 	    strncpy(virtual_banner, ARG2, MAXPATHLEN);
- 	    syslog(LOG_ERR, "VirtualFTP Connect to: %s",
- 		   inet_ntoa(virtual_ptr->sin_addr));
- 	  }
- 	}
-       }
-     }
- #endif
- 
- 
- #ifdef VIRTUAL
-     virtual_len = sizeof(virtual_addr);
-     if (getsockname(0, (struct sockaddr *) &virtual_addr,
-                    &virtual_len) < 0) {
-       virtual_mode = 0;
-     }
-     else {
-       virtual_ptr = (struct sockaddr_in *) &virtual_addr;
-       set = 0;
-       entry = (struct aclmember *) NULL;
-       while (!set && getaclentry("virtual", &entry)) {
-        if (!strcmp(ARG0, inet_ntoa(virtual_ptr->sin_addr))) {
           if(!strcmp(ARG1, "root")) {
             syslog(LOG_NOTICE, "VirtualFTP Connect to: %s",
                    inet_ntoa(virtual_ptr->sin_addr));
--- 632,637 ----
***************
*** 1408,1417 ****
      if (log_outbound_xfers || log_incoming_xfers)
  #ifdef VIRTUAL
        if(virtual_mode)
!         xferlog = open(virtual_logfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
        else
  #endif
!         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0660);
  
  #ifdef DEBUG
  /* I had a lot of trouble getting xferlog working, because of two factors:
--- 1383,1392 ----
      if (log_outbound_xfers || log_incoming_xfers)
  #ifdef VIRTUAL
        if(virtual_mode)
!         xferlog = open(virtual_logfile, O_WRONLY | O_APPEND | O_CREAT, 0644);
        else
  #endif
!         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0644);
  
  #ifdef DEBUG
  /* I had a lot of trouble getting xferlog working, because of two factors:
***************
*** 1927,1935 ****
          perror_reply(553, name);
          return;
      }
-     /* if we have a uid and gid, then use them. */
  
      if (valid > 0) {
          oldid = geteuid();
          (void) seteuid((uid_t) 0);
          if ((fchown(fdout, uid, gid)) < 0) {
--- 1902,1917 ----
          perror_reply(553, name);
          return;
      }
  
+     /* if we have a uid and gid, then use them. */
      if (valid > 0) {
+         if (uid == INT_MAX || gid == INT_MAX) {
+ /* set uid and/or gid to that of upload directory */
+             stat(".", &st);
+             if (uid == INT_MAX) uid = st.st_uid;
+             if (gid == INT_MAX) gid = st.st_gid;
+         }
+ 
          oldid = geteuid();
          (void) seteuid((uid_t) 0);
          if ((fchown(fdout, uid, gid)) < 0) {
diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/newvers.sh /var/home/evanc/wu-evanc/src/newvers.sh
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/newvers.sh	Mon Apr 15 01:51:13 1996
--- /var/home/evanc/wu-evanc/src/newvers.sh	Mon Jun 10 06:40:12 1996
***************
*** 21,27 ****
  if [ ! -r edit ]; then echo 0 > edit; fi
  touch edit
  awk '	{	edit = $1 + 1; }\
! END	{	printf "char version[] = \"Version wu-2.4.2-academ[BETA-11](%d) ", edit > "vers.c";\
  #LANG=
  #LC_TIME=
  		printf "%d\n", edit > "edit"; }' < edit
--- 21,27 ----
  if [ ! -r edit ]; then echo 0 > edit; fi
  touch edit
  awk '	{	edit = $1 + 1; }\
! END	{	printf "char version[] = \"Version wu-2.4.2-academ[BETA-11](evanc-%d) ", edit > "vers.c";\
  #LANG=
  #LC_TIME=
  		printf "%d\n", edit > "edit"; }' < edit
diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/extensions.c /var/home/evanc/wu-evanc/src/extensions.c
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/extensions.c	Mon Apr 15 01:51:05 1996
--- /var/home/evanc/wu-evanc/src/extensions.c	Mon Jun 10 06:39:27 1996
***************
*** 799,814 ****
  
      while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
          if (ARG3 && ARG4) {
              pwent = getpwnam(ARG3);
-             grent = getgrnam(ARG4);
- 
              if (pwent)  sprintf(buf, "%d", pwent->pw_uid);
              else        sprintf(buf, "%d", 0);
              ARG3 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG3, buf);
  
              if (grent)  sprintf(buf, "%d", grent->gr_gid);
              else        sprintf(buf, "%d", 0);
              ARG4 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG4, buf);
  	    endgrent();
--- 799,823 ----
  
      while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
          if (ARG3 && ARG4) {
+ /* set ARG3 to :user: to set owner of uploaded files to owner of directory */
+             if (!strcasecmp(ARG3, ":user:")) sprintf(buf, "%d", INT_MAX);
+ 	    else {
                  pwent = getpwnam(ARG3);
                  if (pwent)  sprintf(buf, "%d", pwent->pw_uid);
                  else        sprintf(buf, "%d", 0);
+ 	    }
+ 
              ARG3 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG3, buf);
  
+ /* set ARG4 to :group: to set group of uploaded files to group of directory */
+ 	    if (!strcasecmp(ARG4, ":group:")) sprintf(buf, "%d", INT_MAX);
+ 	    else {
+                 grent = getgrnam(ARG4);
                  if (grent)  sprintf(buf, "%d", grent->gr_gid);
                  else        sprintf(buf, "%d", 0);
+ 	    }
+ 
              ARG4 = (char *) malloc(strlen(buf) + 1);
              strcpy(ARG4, buf);
  	    endgrent();
***************
*** 962,968 ****
    i = match_value;  /* i is -1 here */
    while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
   /* CERT suggested fix (change && to || ) */
!     if ( (!strcmp(ARG0, pw->pw_dir))  ||
  		   ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
            match_value = i;
            ap2 = ARG2;
--- 971,977 ----
    i = match_value;  /* i is -1 here */
    while (getaclentry("upload", &entry) && ARG0 && ARG1 && ARG2 != NULL) {
   /* CERT suggested fix (change && to || ) */
!     if ( (!strcmp(ARG0, pw->pw_dir))  &&
  		   ((i = path_compare(ARG1, cwdir)) >= match_value) ) {
            match_value = i;
            ap2 = ARG2;
diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/ftpd.c /var/home/evanc/wu-evanc/src/ftpd.c
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/ftpd.c	Mon Apr 15 01:51:11 1996
--- /var/home/evanc/wu-evanc/src/ftpd.c	Fri May 17 18:45:14 1996
***************
*** 632,662 ****
        entry = (struct aclmember *) NULL;
        while (!set && getaclentry("virtual", &entry)) {
  	if (!strcmp(ARG0, inet_ntoa(virtual_ptr->sin_addr))) {
- 	  if (ARG1 != NULL && ARG2 != NULL) {
- 	    virtual_mode = 1;
- 	    strncpy(virtual_root, ARG1, MAXPATHLEN);
- 	    strncpy(virtual_banner, ARG2, MAXPATHLEN);
- 	    syslog(LOG_ERR, "VirtualFTP Connect to: %s",
- 		   inet_ntoa(virtual_ptr->sin_addr));
- 	  }
- 	}
-       }
-     }
- #endif
- 
- 
- #ifdef VIRTUAL
-     virtual_len = sizeof(virtual_addr);
-     if (getsockname(0, (struct sockaddr *) &virtual_addr,
-                    &virtual_len) < 0) {
-       virtual_mode = 0;
-     }
-     else {
-       virtual_ptr = (struct sockaddr_in *) &virtual_addr;
-       set = 0;
-       entry = (struct aclmember *) NULL;
-       while (!set && getaclentry("virtual", &entry)) {
-        if (!strcmp(ARG0, inet_ntoa(virtual_ptr->sin_addr))) {
           if(!strcmp(ARG1, "root")) {
             syslog(LOG_NOTICE, "VirtualFTP Connect to: %s",
                    inet_ntoa(virtual_ptr->sin_addr));
--- 632,637 ----
***************
*** 1408,1417 ****
      if (log_outbound_xfers || log_incoming_xfers)
  #ifdef VIRTUAL
        if(virtual_mode)
!         xferlog = open(virtual_logfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
        else
  #endif
!         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0660);
  
  #ifdef DEBUG
  /* I had a lot of trouble getting xferlog working, because of two factors:
--- 1383,1392 ----
      if (log_outbound_xfers || log_incoming_xfers)
  #ifdef VIRTUAL
        if(virtual_mode)
!         xferlog = open(virtual_logfile, O_WRONLY | O_APPEND | O_CREAT, 0644);
        else
  #endif
!         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0644);
  
  #ifdef DEBUG
  /* I had a lot of trouble getting xferlog working, because of two factors:
***************
*** 1927,1935 ****
          perror_reply(553, name);
          return;
      }
-     /* if we have a uid and gid, then use them. */
  
      if (valid > 0) {
          oldid = geteuid();
          (void) seteuid((uid_t) 0);
          if ((fchown(fdout, uid, gid)) < 0) {
--- 1902,1917 ----
          perror_reply(553, name);
          return;
      }
  
+     /* if we have a uid and gid, then use them. */
      if (valid > 0) {
+         if (uid == INT_MAX || gid == INT_MAX) {
+ /* set uid and/or gid to that of upload directory */
+             stat(".", &st);
+             if (uid == INT_MAX) uid = st.st_uid;
+             if (gid == INT_MAX) gid = st.st_gid;
+         }
+ 
          oldid = geteuid();
          (void) seteuid((uid_t) 0);
          if ((fchown(fdout, uid, gid)) < 0) {
diff -c -w /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/newvers.sh /var/home/evanc/wu-evanc/src/newvers.sh
*** /var/home/evanc/wu-ftpd-2.4.2-beta-11/src/newvers.sh	Mon Apr 15 01:51:13 1996
--- /var/home/evanc/wu-evanc/src/newvers.sh	Mon Jun 10 06:40:12 1996
***************
*** 21,27 ****
  if [ ! -r edit ]; then echo 0 > edit; fi
  touch edit
  awk '	{	edit = $1 + 1; }\
! END	{	printf "char version[] = \"Version wu-2.4.2-academ[BETA-11](%d) ", edit > "vers.c";\
  #LANG=
  #LC_TIME=
  		printf "%d\n", edit > "edit"; }' < edit
--- 21,27 ----
  if [ ! -r edit ]; then echo 0 > edit; fi
  touch edit
  awk '	{	edit = $1 + 1; }\
! END	{	printf "char version[] = \"Version wu-2.4.2-academ[BETA-11](evanc-%d) ", edit > "vers.c";\
  #LANG=
  #LC_TIME=
  		printf "%d\n", edit > "edit"; }' < edit