Fix Linux getlogin{_r,} implementation

The old implementation uses fd 0 to determine the login TTY.  This
was needed because using /dev/tty it is not possible to deduce the
login TTY.  For some time now there is the pseudo-file
/proc/self/loginuid which directly helps us to find the user.  Prefer
using this file.  It also works if stdin is closed, redirected, or
re-opened.
This commit is contained in:
Ulrich Drepper 2010-03-24 17:02:57 -07:00
parent fd8ccb0427
commit c8727fa6e5
6 changed files with 161 additions and 3 deletions

View File

@ -1,5 +1,12 @@
2010-03-24 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/getlogin_r.c: New file.
* sysdeps/unix/sysv/linux/getlogin.c: New file.
* sysdeps/unix/getlogin_r.c: Allow compiling getlogin as static
function.
* sysdeps/unix/getlogin.c: Likewise. Move name variable to toplevel.
* include/unistd.h: Declare __getlogin_r_loginuid.
[BZ #11397]
* sysdeps/posix/cuserid.c (cuserid): Make sure the returned string
is NUL terminated.

View File

@ -176,6 +176,9 @@ extern int __have_sock_cloexec;
unless it is really necessary. */
#define __have_pipe2 __have_sock_cloexec
extern int __getlogin_r_loginuid (char *name, size_t namesize)
attribute_hidden;
__END_DECLS
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc.
/* Copyright (C) 1991, 1992, 1996, 1997, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -25,16 +25,20 @@
#include <utmp.h>
static char name[UT_NAMESIZE + 1];
/* Return the login name of the user, or NULL if it can't be determined.
The returned pointer, if not NULL, is good only until the next call. */
#ifdef STATIC
STATIC
#endif
char *
getlogin (void)
{
char tty_pathname[2 + 2 * NAME_MAX];
char *real_tty_path = tty_pathname;
char *result = NULL;
static char name[UT_NAMESIZE + 1];
struct utmp *ut, line, buffer;
/* Get name of tty connected to fd 0. Return NULL if not a tty or

View File

@ -1,5 +1,5 @@
/* Reentrant function to return the current login name. Unix version.
Copyright (C) 1991,92,96,97,98,2002 Free Software Foundation, Inc.
Copyright (C) 1991,92,96,97,98,2002,2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -31,6 +31,9 @@
If it cannot be determined or some other error occurred, return the error
code. Otherwise return 0. */
#ifdef STATIC
STATIC
#endif
int
getlogin_r (name, name_len)
char *name;
@ -96,4 +99,6 @@ getlogin_r (name, name_len)
return result;
}
#ifndef STATIC
libc_hidden_def (getlogin_r)
#endif

View File

@ -0,0 +1,39 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <pwd.h>
#include <unistd.h>
#include <not-cancel.h>
#define STATIC static
#define getlogin getlogin_fd0
#include <sysdeps/unix/getlogin.c>
#undef getlogin
/* Return the login name of the user, or NULL if it can't be determined.
The returned pointer, if not NULL, is good only until the next call. */
char *
getlogin (void)
{
if (__getlogin_r_loginuid (name, sizeof (name)) == 0)
return name;
return getlogin_fd0 ();
}

View File

@ -0,0 +1,100 @@
/* Copyright (C) 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <pwd.h>
#include <unistd.h>
#include <not-cancel.h>
#define STATIC static
static int getlogin_r_fd0 (char *name, size_t namesize);
#define getlogin_r getlogin_r_fd0
#include <sysdeps/unix/getlogin_r.c>
#undef getlogin_r
int
attribute_hidden
__getlogin_r_loginuid (name, namesize)
char *name;
size_t namesize;
{
int fd = open_not_cancel_2 ("/proc/self/loginuid", O_RDONLY);
if (fd == -1)
return 1;
ssize_t n = TEMP_FAILURE_RETRY (read_not_cancel (fd, name, namesize));
close_not_cancel_no_status (fd);
uid_t uid;
char *endp;
if (n <= 0
|| (uid = strtoul (name, &endp, 10), endp == name || *endp != '\0'))
return 1;
size_t buflen = 1024;
char *buf = alloca (buflen);
bool use_malloc = false;
struct passwd pwd;
struct passwd *tpwd;
int res;
while ((res = __getpwuid_r (uid, &pwd, buf, buflen, &tpwd)) != 0)
if (__libc_use_alloca (2 * buflen))
extend_alloca (buf, buflen, 2 * buflen);
else
{
buflen *= 2;
char *newp = realloc (use_malloc ? buf : NULL, buflen);
if (newp == NULL)
{
fail:
if (use_malloc)
free (buf);
return 1;
}
buf = newp;
use_malloc = true;
}
if (tpwd == NULL)
goto fail;
strncpy (name, pwd.pw_name, namesize - 1);
name[namesize - 1] = '\0';
if (use_malloc)
free (buf);
return 0;
}
/* Return the login name of the user, or NULL if it can't be determined.
The returned pointer, if not NULL, is good only until the next call. */
int
getlogin_r (name, namesize)
char *name;
size_t namesize;
{
if (__getlogin_r_loginuid (name, namesize) == 0)
return 0;
return getlogin_r_fd0 (name, namesize);
}
libc_hidden_def (getlogin_r)