1/* Provide a working getlogin_r for systems which lack it. 2 3 Copyright (C) 2005-2007, 2010-2020 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3, or (at your option) 8 any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */ 17 18/* Written by Paul Eggert, Derek Price, and Bruno Haible. */ 19 20#include <config.h> 21 22/* Specification. */ 23#include <unistd.h> 24 25#include <errno.h> 26#include <string.h> 27 28#include "malloca.h" 29 30#if defined _WIN32 && ! defined __CYGWIN__ 31# define WIN32_LEAN_AND_MEAN 32# include <windows.h> 33/* Don't assume that UNICODE is not defined. */ 34# undef GetUserName 35# define GetUserName GetUserNameA 36#else 37# if !HAVE_DECL_GETLOGIN 38extern char *getlogin (void); 39# endif 40#endif 41 42/* See unistd.in.h for documentation. */ 43int 44getlogin_r (char *name, size_t size) 45{ 46#undef getlogin_r 47#if defined _WIN32 && ! defined __CYGWIN__ 48 /* Native Windows platform. */ 49 DWORD sz; 50 51 /* When size > 0x7fff, the doc says that GetUserName will fail. 52 Actually, on Windows XP SP3, it succeeds. But let's be safe, 53 for the sake of older Windows versions. */ 54 if (size > 0x7fff) 55 size = 0x7fff; 56 sz = size; 57 if (!GetUserName (name, &sz)) 58 { 59 if (GetLastError () == ERROR_INSUFFICIENT_BUFFER) 60 /* In this case, the doc says that sz contains the required size, but 61 actually, on Windows XP SP3, it contains 2 * the required size. */ 62 return ERANGE; 63 else 64 return ENOENT; 65 } 66 return 0; 67#elif HAVE_GETLOGIN_R 68 /* Platform with a getlogin_r() function. */ 69 int ret = getlogin_r (name, size); 70 71 if (ret == 0) 72 { 73 const char *nul = memchr (name, '\0', size); 74 if (nul == NULL) 75 /* name contains a truncated result. */ 76 return ERANGE; 77 if (size > 0 && nul == name + size - 1) 78 { 79 /* strlen(name) == size-1. Determine whether the untruncated result 80 would have had length size-1 or size. */ 81 char *room = (char *) malloca (size + 1); 82 if (room == NULL) 83 return ENOMEM; 84 ret = getlogin_r (room, size + 1); 85 /* The untruncated result should be the same as in the first call. */ 86 if (ret == 0 && memcmp (name, room, size) != 0) 87 /* The untruncated result would have been different. */ 88 ret = ERANGE; 89 freea (room); 90 } 91 } 92 return ret; 93#else 94 /* Platform with a getlogin() function. */ 95 char *n; 96 size_t nlen; 97 98 errno = 0; 99 n = getlogin (); 100 if (!n) 101 /* ENOENT is a reasonable errno value if getlogin returns NULL. */ 102 return (errno != 0 ? errno : ENOENT); 103 104 nlen = strlen (n); 105 if (size <= nlen) 106 return ERANGE; 107 memcpy (name, n, nlen + 1); 108 return 0; 109#endif 110} 111