1414
1515#include < dlfcn.h>
1616#include < fcntl.h>
17+ #include < grp.h>
1718#include < pwd.h>
1819#include < sys/capability.h>
1920#include < sys/fsuid.h>
2021#include < sys/types.h>
2122#include < sys/stat.h>
23+ #include < sys/syscall.h>
2224#include < unistd.h>
2325
2426// TODO: set this via library parameters.
@@ -121,6 +123,13 @@ public:
121123 return false ;
122124 }
123125
126+ // Use syscall to set supplementary groups instead of through glibc so
127+ // changes are applied to individual threads only. See nptl(7).
128+ static int ThreadSetgroups (size_t size, const gid_t *list)
129+ {
130+ return syscall (SYS_setgroups, size, list);
131+ }
132+
124133 void Init (const std::string username, XrdSysError &log)
125134 {
126135 struct passwd pwd, *result = nullptr ;
@@ -158,6 +167,24 @@ public:
158167 return ;
159168 }
160169
170+ // Get supplementary groups for user
171+ int ngroups = 16 ;
172+ std::vector<gid_t > groups (ngroups);
173+ do {
174+ int old_ngroups = ngroups;
175+ retval = getgrouplist (username.c_str (), pwd.pw_gid , groups.data (), &ngroups);
176+ if (-1 == retval && ngroups > old_ngroups) {
177+ // Too many groups. Resize buffer and try again.
178+ groups.resize (ngroups);
179+ continue ;
180+ }
181+ break ;
182+ } while (1 );
183+ if (-1 == retval) {
184+ m_log.Emsg (" UserSentry" , " Failure when looking up supplementary groups for username" , username.c_str ());
185+ return ;
186+ }
187+
161188 // Note: Capabilities need to be set per thread, so we need to do this
162189 ConfigCaps (m_log, nullptr );
163190
@@ -169,6 +196,7 @@ public:
169196 return ;
170197 }
171198 m_orig_gid = setfsgid (result->pw_gid );
199+ ThreadSetgroups (ngroups, groups.data ());
172200 }
173201
174202 ~UserSentry () {
@@ -178,6 +206,10 @@ public:
178206 if ((m_orig_gid != -1 ) && (-1 == setfsgid (m_orig_gid))) {
179207 m_log.Emsg (" UserSentry" , " Failed to return fsgid to original state" , strerror (errno));
180208 }
209+ // Clear supplementary groups
210+ // We don't need to restore the daemon's original groups, as the
211+ // *-privileged processes run without supplementary groups defined.
212+ ThreadSetgroups (0 , nullptr );
181213 }
182214
183215 bool IsValid () const {return ((m_orig_gid != -1 ) && (m_orig_uid != -1 )) || m_is_anonymous;}
0 commit comments