Subject: GNU tar-1.11.2 bugs - patch and new binary available
From: [email-masked] (Ian Jackson)
Newsgroups: comp.os.linux.announce

-----BEGIN PGP SIGNED MESSAGE-----

Executive summary: get a fixed version of tar from sunsite, or apply
the patch below.  If you maintain a distribution please ensure that
your tar has had this bugfix applied.

It appears that GNU tar is no longer being maintained.

In February 1993 I first reported a bug that caused tar 1.11.1 to
extract files with the wrong ownership if the archive contained
user/group name information but the names couldn't be mapped to IDs.
In this case GNU tar extracts the files with the ownership of the user
invoking tar, rather than using the numeric values provided in the
archive.

This is a serious problem for systems using tar as a backup program
since it means that after a major disaster you can't easily do a
proper restore from a system backup, because the rescue floppy won't
have the right passwd and group files.  You have to extract those from
the archive onto the rescue floppy first.

In June 1993 I reported that the bug was still present in 1.11.2 and
provided a patch.  In April 1994 I asked whether GNU tar was being
maintained, referring to my earlier messages, and reported that if you
give the -C option and the change directory fails GNU tar 1.11.2 just
ploughs on anyway.  I received no response.

Enclosed below is a patch to GNU tar 1.11.2 which ensures that when a
user or group name from the archive is not found by getpwnam or
getgrnam files are extracted using the numeric owner from the archive
rather than uid/gid 0.  It also adds a --numeric-owner option that
forces extraction using the numeric ids from the archive, ignoring the
names.  This is useful when restoring a backup from an emergency
floppy with different passwd/group files.

I'm afraid that I can't see clearly how to fix the problem with -C.

A binary which contains this patch, linked against libc 4.5.26, is
available on sunsite (very shortly, if not already), together with a
copy of the attached patch and this message.

 diff -r -u tar-1.11.2/ChangeLog tar-1.11.2-mine/ChangeLog
 --- tar-1.11.2/ChangeLog	Thu Mar 25 18:54:56 1993
 +++ tar-1.11.2-mine/ChangeLog	Wed Jun 23 01:07:02 1993
 @@ -1,3 +1,22 @@
 +Wed Jun 23 00:55:39 BST 1993  Ian W Jackson  ([email-masked])
 +
 +	* list.c, names.c: Fixed bug which extracted files with wrong
 +          ownership if there were names in the archive but the
 +          user/group names couldn't be mapped to uids. It used to use
 +          the extractor's IDs, now it uses the numeric IDs from the
 +          archive.
 +
 +	* list.c, names.c, create.c, tar.c, tar.h: Added a new
 +          --numeric-owner option which allows (ANSI) archives to be
 +          written without user/group name information or such
 +          information to be ignored when extracting.
 +
 +        * create.c: Fixed bug which could cause uname/gname to fail to
 +          be cleared when the names are not available. Ensured that
 +          the new default linkflag of LF_NORMAL and the ANSI magic
 +          number are used when writing ANSI archives even if NONAMES
 +          is set at compile-time.
 +
  Thu Mar 25 13:32:40 1993  Michael I Bushnell  ([email-masked])

         * version.c: Released version 1.11.2.
 Only in tar-1.11.2-mine: ChangeLog~
 Only in tar-1.11.2-mine: Makefile
 Only in tar-1.11.2-mine: config.status
 diff -r -u tar-1.11.2/create.c tar-1.11.2-mine/create.c
 --- tar-1.11.2/create.c	Thu Mar 25 18:32:31 1993
 +++ tar-1.11.2-mine/create.c	Wed Jun 23 01:00:28 1993
 @@ -1289,16 +1289,22 @@
        to_oct ((long) st->st_ctime, 1 + 12, header->header.ctime);
      }

 -#ifndef NONAMES
 +  header->header.uname[0] = '\0';
 +  header->header.gname[0] = '\0';
    /* Fill in new Unix Standard fields if desired. */
    if (f_standard)
      {
        header->header.linkflag = LF_NORMAL;	/* New default */
        strcpy (header->header.magic, TMAGIC);	/* Mark as Unix Std */
 -      finduname (header->header.uname, st->st_uid);
 -      findgname (header->header.gname, st->st_gid);
 -    }
 +#ifndef NONAMES
 +      if (!f_nonames)
 +        {
 +          finduname (header->header.uname, st->st_uid);
 +          findgname (header->header.gname, st->st_gid);
 +        }
  #endif
 +    }
 +      
    return header;
  }

 Only in tar-1.11.2-mine: create.c~
 diff -r -u tar-1.11.2/list.c tar-1.11.2-mine/list.c
 --- tar-1.11.2/list.c	Tue Mar 16 19:56:01 1993
 +++ tar-1.11.2-mine/list.c	Wed Jun 23 01:00:27 1993
 @@ -461,18 +461,16 @@
        *stdp = 1;
        if (wantug)
         {
 -#ifdef NONAMES
           st->st_uid = from_oct (8, header->header.uid);
           st->st_gid = from_oct (8, header->header.gid);
 -#else
 -	  st->st_uid =
 -	    (*header->header.uname
 -	     ? finduid (header->header.uname)
 -	     : from_oct (8, header->header.uid));
 -	  st->st_gid =
 -	    (*header->header.gname
 -	     ? findgid (header->header.gname)
 -	     : from_oct (8, header->header.gid));
 +#ifndef NONAMES
 +          if (!f_nonames)
 +            {
 +              if (*header->header.uname)
 +                finduid (header->header.uname, &st->st_uid);
 +              if (*header->header.gname)
 +                findgid (header->header.gname, &st->st_gid);
 +            }
  #endif
         }
  #if defined(S_IFBLK) || defined(S_IFCHR)
 Only in tar-1.11.2-mine: list.c~
 diff -r -u tar-1.11.2/names.c tar-1.11.2-mine/names.c
 --- tar-1.11.2/names.c	Fri Sep 18 19:45:08 1992
 +++ tar-1.11.2-mine/names.c	Wed Jun 23 01:07:02 1993
 @@ -74,28 +74,26 @@
    strncpy (uname, saveuname, TUNMLEN);
  }

 -int
 -finduid (uname)
 +void
 +finduid (uname, uidp)
       char uname[TUNMLEN];
 +     uid_t *uidp;
  {
    struct passwd *pw;
    extern struct passwd *getpwnam ();

 -  if (uname[0] != saveuname[0]	/* Quick test w/o proc call */
 -      || 0 != strncmp (uname, saveuname, TUNMLEN))
 +  if (uname[0] == saveuname[0]	/* Quick test w/o proc call */
 +      && 0 == strncmp (uname, saveuname, TUNMLEN))
 +    {
 +      *uidp = saveuid;
 +      return;
 +    }
 +  pw = getpwnam (uname);
 +  if (pw)
      {
 +      saveuid = *uidp = pw->pw_uid;
        strncpy (saveuname, uname, TUNMLEN);
 -      pw = getpwnam (uname);
 -      if (pw)
 -	{
 -	  saveuid = pw->pw_uid;
 -	}
 -      else
 -	{
 -	  saveuid = myuid;
 -	}
      }
 -  return saveuid;
  }

 @@ -122,28 +120,26 @@
  }

 -int
 -findgid (gname)
 +void
 +findgid (gname, gidp)
       char gname[TUNMLEN];
 +     gid_t *gidp;
  {
    struct group *gr;
    extern struct group *getgrnam ();

 -  if (gname[0] != savegname[0]	/* Quick test w/o proc call */
 -      || 0 != strncmp (gname, savegname, TUNMLEN))
 +  if (gname[0] == savegname[0]	/* Quick test w/o proc call */
 +      && 0 == strncmp (gname, savegname, TUNMLEN))
      {
 +      *gidp = savegid;
 +      return;
 +    }
 +  gr = getgrnam (gname);
 +  if (gr)
 +    {
 +      savegid = *gidp = gr->gr_gid;
        strncpy (savegname, gname, TUNMLEN);
 -      gr = getgrnam (gname);
 -      if (gr)
 -	{
 -	  savegid = gr->gr_gid;
 -	}
 -      else
 -	{
 -	  savegid = mygid;
 -	}
      }
 -  return savegid;
  }

  #endif
 Only in tar-1.11.2-mine: names.c~
 diff -r -u tar-1.11.2/tar.c tar-1.11.2-mine/tar.c
 --- tar-1.11.2/tar.c	Wed Mar 17 15:30:46 1993
 +++ tar-1.11.2-mine/tar.c	Wed Jun 23 01:07:01 1993
 @@ -143,6 +143,7 @@
    {"preserve", 0, 0, 10},
    {"same-order", 0, &f_sorted_names, 1},
    {"same-owner", 0, &f_do_chown, 1},
 +  {"numeric-owner", 0, &f_nonames, 1},
    {"preserve-order", 0, &f_sorted_names, 1},

    {"newer", 1, 0, 'N'},
 @@ -735,6 +736,7 @@
  -s, --same-order,\n\
      --preserve-order	list of names to extract is sorted to match archive\n\
  --same-owner		create extracted files with the same ownership \n\
 +--numeric-owner		don't dump or extract user/group names; use numbers\n\
  -S, --sparse		handle sparse files efficiently\n\
  -T, --files-from F	get names to extract or create from file F\n\
  --null			-T reads null-terminated names, disable -C\n\
 Only in tar-1.11.2-mine: tar.c~
 diff -r -u tar-1.11.2/tar.h tar-1.11.2-mine/tar.h
 --- tar-1.11.2/tar.h	Tue Mar 16 20:31:39 1993
 +++ tar-1.11.2-mine/tar.h	Wed Jun 23 01:00:28 1993
 @@ -224,6 +224,7 @@
  TAR_EXTERN int f_exclude;	/* -X */
  TAR_EXTERN char *f_compressprog;	/* -z and -Z */
  TAR_EXTERN int f_do_chown;	/* --do-chown */
 +TAR_EXTERN int f_nonames;	/* --numeric-owner */
  TAR_EXTERN int f_totals;	/* --totals */
  TAR_EXTERN int f_remove_files;	/* --remove-files */
  TAR_EXTERN int f_ignore_failed_read;	/* --ignore-failed-read */
 Only in tar-1.11.2-mine: tar.h~

--
Ian Jackson, at home  <[email-masked]> or <[email-masked]>
PGP2 public key available on server.  Urgent email: <[email-masked]>
2 Lexington Close, Cambridge, CB4 3LS, England;  phone: +44 223 575512