I got a problem report from Mark Willson:

    "I recently installed mg (via the Debian package) under WSL on Windows
10.
    I found that the 'backup-to-home-directory' option didn't work.

    The cause of this appears to be that getlogin under WSL returns NULL,
    probably due to my use of wsltty to invoke bash.  The patch below fixes
    the issue for me:"

[snip]
-               if ((un = getlogin()) != NULL)
+               if ((un = getenv("LOGNAME")) != NULL)
[snip]

Which put me onto the track of what was going on. I found the
following in the Linux manpage:

BUGS
       Unfortunately, it is often rather easy to fool  getlogin().
 Sometimes
       it  does not work at all, because some program messed up the utmp
file.
       Often, it gives only the first 8 characters of  the  login  name.
 The
       user  currently  logged  in  on the controlling terminal of our
program
       need not be the user who started it.  Avoid  getlogin()  for
security-
       related purposes.

       Note  that glibc does not follow the POSIX specification and uses
stdin
       instead of /dev/tty.  A bug.  (Other recent systems, like SunOS 5.8
and
       HP-UX  11.11  and FreeBSD 4.8 all return the login name also when
stdin
       is redirected.)

       Nobody knows precisely what cuserid() does; avoid it in  portable
pro‐
       grams.   Or  avoid  it  altogether: use getpwuid(geteuid()) instead,
if
       that is what you meant.  Do not use cuserid().

So I started looking at the code and rewrote it a bit, which I think
makes it more portable and removes a syscall in the process. I do
suspect this can be written even more elegantly, but didn't want to
rework the code too much.

I also took the liberty to remove some whitespace.


Index: fileio.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/fileio.c,v
retrieving revision 1.104
@@ -703,7 +706,7 @@ expandtilde(const char *fn)
        struct stat      statbuf;
        const char      *cp;
        char             user[LOGIN_NAME_MAX], path[NFILEN];
-       char            *un, *ret;
+       char            *ret;
        size_t           ulen, plen;

        path[0] = '\0';
@@ -722,21 +725,21 @@ expandtilde(const char *fn)
                        return (NULL);
                return(ret);
        }
+       pw = getpwuid(geteuid());
        if (ulen == 0) { /* ~/ or ~ */
-               if ((un = getlogin()) != NULL)
-                       (void)strlcpy(user, un, sizeof(user));
+               if (pw != NULL)
+                       (void)strlcpy(user, pw->pw_name, sizeof(user));
                else
                        user[0] = '\0';
        } else { /* ~user/ or ~user */
                memcpy(user, &fn[1], ulen);
                user[ulen] = '\0';
        }
-       pw = getpwnam(user);
        if (pw != NULL) {
                plen = strlcpy(path, pw->pw_dir, sizeof(path));
                if (plen == 0 || path[plen - 1] != '/') {
                        if (strlcat(path, "/", sizeof(path)) >=
sizeof(path)) {
-                               dobeep();
+                               dobeep();
                                ewprintf("Path too long");
                                return (NULL);
                        }

Reply via email to