Skip to content

Commit

Permalink
Fix Linux getlogin{_r,} implementation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Ulrich Drepper committed Mar 25, 2010
1 parent fd8ccb0 commit c8727fa
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 3 deletions.
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
3 changes: 3 additions & 0 deletions include/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 6 additions & 2 deletions sysdeps/unix/getlogin.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
7 changes: 6 additions & 1 deletion sysdeps/unix/getlogin_r.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -96,4 +99,6 @@ getlogin_r (name, name_len)

return result;
}
#ifndef STATIC
libc_hidden_def (getlogin_r)
#endif
39 changes: 39 additions & 0 deletions sysdeps/unix/sysv/linux/getlogin.c
Original file line number Diff line number Diff line change
@@ -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 ();
}
100 changes: 100 additions & 0 deletions sysdeps/unix/sysv/linux/getlogin_r.c
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit c8727fa

Please sign in to comment.