LCOV - code coverage report
Current view: top level - app/shared - fd_sys_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 23 86 26.7 %
Date: 2025-03-20 12:08:36 Functions: 2 4 50.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_sys_util.h"
       3             : 
       4             : #include <pwd.h>
       5             : #include <errno.h>
       6             : #include <stdlib.h> /* getenv */
       7             : #include <time.h>
       8             : #include <unistd.h>
       9             : #include <sys/syscall.h>
      10             : #include <sys/mman.h>
      11             : #include <sys/wait.h>
      12             : 
      13             : void __attribute__((noreturn))
      14           0 : fd_sys_util_exit_group( int code ) {
      15           0 :   syscall( SYS_exit_group, code );
      16           0 :   for(;;);
      17           0 : }
      18             : 
      19             : int
      20             : fd_sys_util_nanosleep( uint secs,
      21           0 :                        uint nanos ) {
      22           0 :   struct timespec ts = { .tv_sec = secs, .tv_nsec = nanos };
      23           0 :   struct timespec rem;
      24           0 :   while( FD_UNLIKELY( -1==nanosleep( &ts, &rem ) ) ) {
      25           0 :     if( FD_LIKELY( errno==EINTR ) ) ts = rem;
      26           0 :     else return -1;
      27           0 :   }
      28           0 :   return 0;
      29           0 : }
      30             : 
      31             : char const *
      32           3 : fd_sys_util_login_user( void ) {
      33           3 :   char * name = getenv( "SUDO_USER" );
      34           3 :   if( FD_UNLIKELY( name ) ) return name;
      35             : 
      36           0 :   name = getenv( "LOGNAME" );
      37           0 :   if( FD_LIKELY( name ) ) return name;
      38             : 
      39           0 :   name = getenv( "USER" );
      40           0 :   if( FD_LIKELY( name ) ) return name;
      41             : 
      42           0 :   name = getenv( "LNAME" );
      43           0 :   if( FD_LIKELY( name ) ) return name;
      44             : 
      45           0 :   name = getenv( "USERNAME" );
      46           0 :   if( FD_LIKELY( name ) ) return name;
      47             : 
      48           0 :   name = getlogin();
      49           0 :   if( FD_UNLIKELY( !name && (errno==ENXIO || errno==ENOTTY) ) ) return NULL;
      50           0 :   else if( FD_UNLIKELY( !name ) ) FD_LOG_ERR(( "getlogin failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      51           0 :   return name;
      52           0 : }
      53             : 
      54             : int
      55             : fd_sys_util_user_to_uid( char const * user,
      56             :                          uint *       uid,
      57           3 :                          uint *       gid ) {
      58           3 :   uint * results = mmap( NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0 );
      59           3 :   if( FD_UNLIKELY( results==MAP_FAILED ) ) return -1;
      60             : 
      61           3 :   results[ 0 ] = UINT_MAX;
      62           3 :   results[ 1 ] = UINT_MAX;
      63             : 
      64             :   /* This is extremely unfortunate.  We just want to call getpwnam but
      65             :      on various glibc it can open `/var/lib/sss/mc/passwd` and then not
      66             :      close it.  We could go and find this file descriptor and close it
      67             :      for the library, but that is a bit of a hack.  Instead we fork a
      68             :      new process to call getpwnam and then exit.
      69             : 
      70             :      We could try just reading /etc/passwd here instead, but the glibc
      71             :      getpwnam implementation does a lot of things we need, including
      72             :      potentially reading from NCSD or SSSD. */
      73             : 
      74           3 :   pid_t pid = fork();
      75           3 :   if( FD_UNLIKELY( -1==pid ) ) {
      76           0 :     munmap( results, 4096 );
      77           0 :     return -1;
      78           0 :   }
      79             : 
      80           3 :   if( FD_LIKELY( !pid ) ) {
      81           0 :     char buf[ 16384 ];
      82           0 :     struct passwd pwd;
      83           0 :     struct passwd * result;
      84           0 :     int error = getpwnam_r( user, &pwd, buf, sizeof(buf), &result );
      85           0 :     if( FD_UNLIKELY( error ) ) {
      86           0 :       if( FD_LIKELY( error==ENOENT || error==ESRCH ) ) {
      87           0 :         FD_LOG_WARNING(( "configuration file wants firedancer to run as user `%s` but it does not exist", user ));
      88           0 :         fd_sys_util_exit_group( 1 );
      89           0 :       } else {
      90           0 :         FD_LOG_WARNING(( "could not get user id for `%s` (%i-%s)", user, errno, fd_io_strerror( errno ) ));
      91           0 :         fd_sys_util_exit_group( 1 );
      92           0 :       }
      93           0 :     }
      94           0 :     if( FD_UNLIKELY( !result ) ) {
      95           0 :       FD_LOG_WARNING(( "configuration file wants firedancer to run as user `%s` but it does not exist", user ));
      96           0 :       fd_sys_util_exit_group( 1 );
      97           0 :     }
      98             : 
      99           0 :     results[ 0 ] = pwd.pw_uid;
     100           0 :     results[ 1 ] = pwd.pw_gid;
     101           0 :     fd_sys_util_exit_group( 0 );
     102           3 :   } else {
     103           3 :     int wstatus;
     104           3 :     if( FD_UNLIKELY( -1==waitpid( pid, &wstatus, 0 ) ) ) return -1;
     105           3 :     if( FD_UNLIKELY( WIFSIGNALED( wstatus ) ) ) {
     106           0 :       FD_LOG_WARNING(( "uid fetch process terminated by signal %i-%s", WTERMSIG( wstatus ), fd_io_strsignal( WTERMSIG( wstatus ) ) ));
     107           0 :       munmap( results, 4096 );
     108           0 :       errno = EINTR;
     109           0 :       return -1;
     110           0 :     }
     111           3 :     if( FD_UNLIKELY( WEXITSTATUS( wstatus ) ) ) {
     112           0 :       FD_LOG_WARNING(( "uid fetch process exited with status %i", WEXITSTATUS( wstatus ) ));
     113           0 :       munmap( results, 4096 );
     114           0 :       errno = EINTR;
     115           0 :       return -1;
     116           0 :     }
     117           3 :   }
     118             : 
     119           3 :   if( FD_UNLIKELY( results[ 0 ]==UINT_MAX || results[ 1 ]==UINT_MAX ) ) {
     120           0 :     munmap( results, 4096 );
     121           0 :     errno = ENOENT;
     122           0 :     return -1;
     123           0 :   }
     124             : 
     125           3 :   *uid = results[ 0 ];
     126           3 :   *gid = results[ 1 ];
     127             : 
     128           3 :   if( FD_UNLIKELY( -1==munmap( results, 4096 ) ) ) return -1;
     129             : 
     130           3 :   return 0;
     131           3 : }

Generated by: LCOV version 1.14