From 4eb716b7571dd678aafc60d8f70e801b61e27e26 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 9 Mar 2025 10:16:58 +0100 Subject: [PATCH] getlogin: Work around musl bug. * lib/unistd.in.h (getlogin): Consider REPLACE_GETLOGIN. * lib/getlogin.c: Change license header to GPL. (getlogin): Add implementation for Linux. * m4/getlogin.m4 (gl_FUNC_GETLOGIN): Test whether getlogin works. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize REPLACE_GETLOGIN. * modules/unistd-h (Makefile.am): Substitute REPLACE_GETLOGIN. * modules/getlogin (Depends-on): Add readutmp. (configure.ac): Consider REPLACE_GETLOGIN. (License): Change to GPL. * tests/test-getlogin.c (main): Add another test. --- ChangeLog | 14 ++++++ lib/getlogin.c | 99 ++++++++++++++++++++++++++++++++++++++++--- lib/unistd.in.h | 14 +++++- m4/getlogin.m4 | 49 ++++++++++++++++++++- m4/unistd_h.m4 | 3 +- modules/getlogin | 6 ++- modules/unistd-h | 1 + tests/test-getlogin.c | 6 +++ 8 files changed, 180 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 62e5213e03..6bb1ab5554 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2025-03-09 Bruno Haible + + getlogin: Work around musl bug. + * lib/unistd.in.h (getlogin): Consider REPLACE_GETLOGIN. + * lib/getlogin.c: Change license header to GPL. + (getlogin): Add implementation for Linux. + * m4/getlogin.m4 (gl_FUNC_GETLOGIN): Test whether getlogin works. + * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize REPLACE_GETLOGIN. + * modules/unistd-h (Makefile.am): Substitute REPLACE_GETLOGIN. + * modules/getlogin (Depends-on): Add readutmp. + (configure.ac): Consider REPLACE_GETLOGIN. + (License): Change to GPL. + * tests/test-getlogin.c (main): Add another test. + 2025-03-03 Bruno Haible vasprintf-posix, vasprintf-gnu: Fix module description. diff --git a/lib/getlogin.c b/lib/getlogin.c index 72c25acbc7..4772111567 100644 --- a/lib/getlogin.c +++ b/lib/getlogin.c @@ -3,19 +3,19 @@ Copyright (C) 2010-2025 Free Software Foundation, Inc. This file 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. + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. This file 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. + GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License + You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* Written by Bruno Haible, 2010. */ +/* Written by Bruno Haible, 2010, 2025. */ #include @@ -30,15 +30,102 @@ # define GetUserName GetUserNameA #endif +#if defined __linux__ || defined __ANDROID__ +# include +# include +# include +# include +# include +# include "readutmp.h" +#endif + char * getlogin (void) { #if defined _WIN32 && ! defined __CYGWIN__ + /* Native Windows platform. */ static char login_name[1024]; DWORD sz = sizeof (login_name); if (GetUserName (login_name, &sz)) return login_name; +#elif defined __linux__ || defined __ANDROID__ + /* Linux. */ + { + /* Read the login uid from the /proc file system. */ + int fd = open ("/proc/self/loginuid", O_RDONLY); + if (fd >= 0) + { + char buf[20 + 1]; + int n = read (fd, buf, sizeof (buf) - 1); + if (n > 0) + { + buf[n] = '\0'; + char *endptr; + unsigned long uid = strtoul (buf, &endptr, 10); + if (endptr == buf + n && uid != (uid_t) -1) + { + /* Convert the uid to a user name. */ + struct passwd *p = getpwuid (uid); + if (p != NULL && strlen (p->pw_name) < 64) + { + static char resultbuf[64]; + strcpy (resultbuf, p->pw_name); + close (fd); + return resultbuf; + } + } + } + close (fd); + } + } + { + /* Find the tty connected to the current process. */ + char *tty = ttyname (STDIN_FILENO); + if (tty != NULL) + { + /* Try to see to which user it is allocated, via utmp. */ + if (strncmp (tty, "/dev/tty", 8) == 0) + { + idx_t n; + STRUCT_UTMP *entries; + if (read_utmp (UTMP_FILE, &n, &entries, READ_UTMP_USER_PROCESS) + == 0) + { + idx_t i; + for (i = 0; i < n; i++) + if (strcmp (entries[i].ut_line, tty + 5) == 0) + { + if (strlen (entries[i].ut_user) < 64) + { + static char resultbuf[64]; + strcpy (resultbuf, entries[i].ut_user); + free (entries); + return resultbuf; + } + break; + } + free (entries); + } + } + /* Fallback for systems which don't maintain an utmp database + or for ttys that are not recorded in that the utmp database: + Look at the owner of that tty. */ + struct stat statbuf; + if (stat (tty, &statbuf) >= 0) + { + uid_t uid = statbuf.st_uid; + /* Convert the uid to a user name. */ + struct passwd *p = getpwuid (uid); + if (p != NULL && strlen (p->pw_name) < 64) + { + static char resultbuf[64]; + strcpy (resultbuf, p->pw_name); + return resultbuf; + } + } + } + } #endif return NULL; } diff --git a/lib/unistd.in.h b/lib/unistd.in.h index 3f96e10d7e..23d2d53c95 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -1362,11 +1362,21 @@ _GL_WARN_ON_USE (gethostname, "gethostname is unportable - " ${LOGNAME-$USER} on Unix platforms, $USERNAME on native Windows platforms. */ -# if !@HAVE_DECL_GETLOGIN@ +# if @REPLACE_GETLOGIN@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define getlogin rpl_getlogin +# endif +_GL_FUNCDECL_RPL (getlogin, char *, (void), ); +_GL_CXXALIAS_RPL (getlogin, char *, (void)); +# else +# if !@HAVE_DECL_GETLOGIN@ _GL_FUNCDECL_SYS (getlogin, char *, (void), ); -# endif +# endif _GL_CXXALIAS_SYS (getlogin, char *, (void)); +# endif +# if __GLIBC__ >= 2 _GL_CXXALIASWARN (getlogin); +# endif #elif defined GNULIB_POSIXCHECK # undef getlogin # if HAVE_RAW_DECL_GETLOGIN diff --git a/m4/getlogin.m4 b/m4/getlogin.m4 index e876fad5ea..7f1f07319d 100644 --- a/m4/getlogin.m4 +++ b/m4/getlogin.m4 @@ -1,5 +1,5 @@ # getlogin.m4 -# serial 7 +# serial 8 dnl Copyright (C) 2010-2025 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -16,6 +16,53 @@ AC_DEFUN([gl_FUNC_GETLOGIN], AC_CHECK_FUNCS_ONCE([getlogin]) if test $ac_cv_func_getlogin = no; then HAVE_GETLOGIN=0 + else + dnl On musl libc, getlogin returns getenv ("LOGNAME"). + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_CACHE_CHECK([whether getlogin works], + [gl_cv_func_getlogin_works], + [ + dnl Initial guess, used when cross-compiling. +changequote(,)dnl + case "$host_os" in + # Guess no on musl libc. + *-musl* | midipix*) gl_cv_func_getlogin_works="guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_getlogin_works="guessing yes" ;; + esac +changequote([,])dnl + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#include +#if !HAVE_DECL_GETLOGIN +extern +# ifdef __cplusplus +"C" +# endif +char *getlogin (void); +#endif +int +main (void) +{ + int result = 0; + char *buf; + + putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke"); + buf = getlogin (); + if (buf != NULL && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0) + result |= 1; + return result; +}]])], + [gl_cv_func_getlogin_works=yes], + [gl_cv_func_getlogin_works=no], + [:]) + ]) + case "$gl_cv_func_getlogin_works" in + *yes) ;; + *) REPLACE_GETLOGIN=1 ;; + esac fi ]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index 2c08d65e0d..6ec16286ef 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -1,5 +1,5 @@ # unistd_h.m4 -# serial 96 +# serial 97 dnl Copyright (C) 2006-2025 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -244,6 +244,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME]) REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE]) REPLACE_GETENTROPY=0; AC_SUBST([REPLACE_GETENTROPY]) + REPLACE_GETLOGIN=0; AC_SUBST([REPLACE_GETLOGIN]) REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R]) REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS]) REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE]) diff --git a/modules/getlogin b/modules/getlogin index 8725a7031e..7acee58a81 100644 --- a/modules/getlogin +++ b/modules/getlogin @@ -7,10 +7,12 @@ m4/getlogin.m4 Depends-on: unistd-h +readutmp [test $HAVE_GETLOGIN = 0 || test $REPLACE_GETLOGIN = 1] configure.ac: gl_FUNC_GETLOGIN -gl_CONDITIONAL([GL_COND_OBJ_GETLOGIN], [test $HAVE_GETLOGIN = 0]) +gl_CONDITIONAL([GL_COND_OBJ_GETLOGIN], + [test $HAVE_GETLOGIN = 0 || test $REPLACE_GETLOGIN = 1]) gl_UNISTD_MODULE_INDICATOR([getlogin]) AC_REQUIRE([gl_LIB_GETLOGIN]) @@ -26,7 +28,7 @@ Link: $(GETLOGIN_LIB) License: -LGPLv2+ +GPL Maintainer: all diff --git a/modules/unistd-h b/modules/unistd-h index af7fda5944..d2bafb789e 100644 --- a/modules/unistd-h +++ b/modules/unistd-h @@ -200,6 +200,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \ -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \ -e 's|@''REPLACE_GETENTROPY''@|$(REPLACE_GETENTROPY)|g' \ + -e 's|@''REPLACE_GETLOGIN''@|$(REPLACE_GETLOGIN)|g' \ -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \ -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \ -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \ diff --git a/tests/test-getlogin.c b/tests/test-getlogin.c index 1b980a152d..431844bd71 100644 --- a/tests/test-getlogin.c +++ b/tests/test-getlogin.c @@ -41,5 +41,11 @@ main (void) #endif test_getlogin_result (buf, err); + /* Check that getlogin() does not merely return getenv ("LOGNAME"). */ + putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke"); + buf = getlogin (); + ASSERT (!(buf != NULL + && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0)); + return test_exit_status; } -- 2.39.5