1313#include <ctype.h>
1414#if GIT_WIN32
1515#include "win32/findfile.h"
16+ #else
17+ #include <unistd.h>
18+ #include <pwd.h>
1619#endif
1720
1821static int git_sysdir_guess_programdata_dirs (git_buf * out )
@@ -34,12 +37,63 @@ static int git_sysdir_guess_system_dirs(git_buf *out)
3437#endif
3538}
3639
40+ #ifndef GIT_WIN32
41+ static int get_passwd_home (git_buf * out , uid_t uid )
42+ {
43+ struct passwd pwd , * pwdptr ;
44+ char * buf = NULL ;
45+ long buflen ;
46+ int error ;
47+
48+ assert (out );
49+
50+ if ((buflen = sysconf (_SC_GETPW_R_SIZE_MAX )) == -1 )
51+ buflen = 1024 ;
52+
53+ do {
54+ buf = git__realloc (buf , buflen );
55+ error = getpwuid_r (uid , & pwd , buf , buflen , & pwdptr );
56+ buflen *= 2 ;
57+ } while (error == ERANGE && buflen <= 8192 );
58+
59+ if (error ) {
60+ giterr_set (GITERR_OS , "failed to get passwd entry" );
61+ goto out ;
62+ }
63+
64+ if (!pwdptr ) {
65+ giterr_set (GITERR_OS , "no passwd entry found for user" );
66+ goto out ;
67+ }
68+
69+ if ((error = git_buf_puts (out , pwdptr -> pw_dir )) < 0 )
70+ goto out ;
71+
72+ out :
73+ git__free (buf );
74+ return error ;
75+ }
76+ #endif
77+
3778static int git_sysdir_guess_global_dirs (git_buf * out )
3879{
3980#ifdef GIT_WIN32
4081 return git_win32__find_global_dirs (out );
4182#else
42- int error = git__getenv (out , "HOME" );
83+ int error ;
84+ uid_t uid , euid ;
85+
86+ uid = getuid ();
87+ euid = geteuid ();
88+
89+ /*
90+ * In case we are running setuid, use the configuration
91+ * of the effective user.
92+ */
93+ if (uid == euid )
94+ error = git__getenv (out , "HOME" );
95+ else
96+ error = get_passwd_home (out , euid );
4397
4498 if (error == GIT_ENOTFOUND ) {
4599 giterr_clear ();
@@ -57,12 +111,25 @@ static int git_sysdir_guess_xdg_dirs(git_buf *out)
57111#else
58112 git_buf env = GIT_BUF_INIT ;
59113 int error ;
60-
61- if ((error = git__getenv (& env , "XDG_CONFIG_HOME" )) == 0 )
62- error = git_buf_joinpath (out , env .ptr , "git" );
63-
64- if (error == GIT_ENOTFOUND && (error = git__getenv (& env , "HOME" )) == 0 )
65- error = git_buf_joinpath (out , env .ptr , ".config/git" );
114+ uid_t uid , euid ;
115+
116+ uid = getuid ();
117+ euid = geteuid ();
118+
119+ /*
120+ * In case we are running setuid, only look up passwd
121+ * directory of the effective user.
122+ */
123+ if (uid == euid ) {
124+ if ((error = git__getenv (& env , "XDG_CONFIG_HOME" )) == 0 )
125+ error = git_buf_joinpath (out , env .ptr , "git" );
126+
127+ if (error == GIT_ENOTFOUND && (error = git__getenv (& env , "HOME" )) == 0 )
128+ error = git_buf_joinpath (out , env .ptr , ".config/git" );
129+ } else {
130+ if ((error = get_passwd_home (& env , euid )) == 0 )
131+ error = git_buf_joinpath (out , env .ptr , ".config/git" );
132+ }
66133
67134 if (error == GIT_ENOTFOUND ) {
68135 giterr_clear ();
0 commit comments