Blame sysdeps/unix/sysv/linux/getlogin_r.c

Packit 6c4009
/* Copyright (C) 2010-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <pwd.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
#include <scratch_buffer.h>
Packit 6c4009
Packit 6c4009
#define STATIC static
Packit 6c4009
static int getlogin_r_fd0 (char *name, size_t namesize);
Packit 6c4009
#define __getlogin_r getlogin_r_fd0
Packit 6c4009
#include <sysdeps/unix/getlogin_r.c>
Packit 6c4009
#undef __getlogin_r
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Try to determine login name from /proc/self/loginuid and return 0
Packit 6c4009
   if successful.  If /proc/self/loginuid cannot be read return -1.
Packit 6c4009
   Otherwise return the error number.  */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
attribute_hidden
Packit 6c4009
__getlogin_r_loginuid (char *name, size_t namesize)
Packit 6c4009
{
Packit 6c4009
  int fd = __open_nocancel ("/proc/self/loginuid", O_RDONLY);
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  /* We are reading a 32-bit number.  12 bytes are enough for the text
Packit 6c4009
     representation.  If not, something is wrong.  */
Packit 6c4009
  char uidbuf[12];
Packit 6c4009
  ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, uidbuf,
Packit 6c4009
						   sizeof (uidbuf)));
Packit 6c4009
  __close_nocancel_nostatus (fd);
Packit 6c4009
Packit 6c4009
  uid_t uid;
Packit 6c4009
  char *endp;
Packit 6c4009
  if (n <= 0
Packit 6c4009
      || n == sizeof (uidbuf)
Packit 6c4009
      || (uidbuf[n] = '\0',
Packit 6c4009
	  uid = strtoul (uidbuf, &endp, 10),
Packit 6c4009
	  endp == uidbuf || *endp != '\0'))
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  /* If there is no login uid, linux sets /proc/self/loginid to the sentinel
Packit 6c4009
     value of, (uid_t) -1, so check if that value is set and return early to
Packit 6c4009
     avoid making unneeded nss lookups. */
Packit 6c4009
  if (uid == (uid_t) -1)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENXIO);
Packit 6c4009
      return ENXIO;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  struct passwd pwd;
Packit 6c4009
  struct passwd *tpwd;
Packit 6c4009
  int result = 0;
Packit 6c4009
  int res;
Packit 6c4009
  struct scratch_buffer tmpbuf;
Packit 6c4009
  scratch_buffer_init (&tmpbuf);
Packit 6c4009
Packit 6c4009
  while ((res =  __getpwuid_r (uid, &pwd,
Packit 6c4009
			       tmpbuf.data, tmpbuf.length, &tpwd)) == ERANGE)
Packit 6c4009
    {
Packit 6c4009
      if (!scratch_buffer_grow (&tmpbuf))
Packit 6c4009
	{
Packit 6c4009
	  result = ENOMEM;
Packit 6c4009
	  goto out;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (res != 0 || tpwd == NULL)
Packit 6c4009
    {
Packit 6c4009
      result = -1;
Packit 6c4009
      goto out;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  size_t needed = strlen (pwd.pw_name) + 1;
Packit 6c4009
  if (needed > namesize)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ERANGE);
Packit 6c4009
      result = ERANGE;
Packit 6c4009
      goto out;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  memcpy (name, pwd.pw_name, needed);
Packit 6c4009
Packit 6c4009
 out:
Packit 6c4009
  scratch_buffer_free (&tmpbuf);
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return at most NAME_LEN characters of the login name of the user in NAME.
Packit 6c4009
   If it cannot be determined or some other error occurred, return the error
Packit 6c4009
   code.  Otherwise return 0.  */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__getlogin_r (char *name, size_t namesize)
Packit 6c4009
{
Packit 6c4009
  int res = __getlogin_r_loginuid (name, namesize);
Packit 6c4009
  if (res >= 0)
Packit 6c4009
    return res;
Packit 6c4009
Packit 6c4009
  return getlogin_r_fd0 (name, namesize);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__getlogin_r)
Packit 6c4009
weak_alias (__getlogin_r, getlogin_r)
Packit 6c4009
libc_hidden_weak (getlogin_r)