@@ -33,7 +33,6 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
33
33
DEBUG (SSSDBG_FUNC_DATA ,
34
34
"Trying to become user [%" SPRIuid "][%" SPRIgid "].\n" , uid , gid );
35
35
36
- /* skip call if we already are the requested user */
37
36
cuid = geteuid ();
38
37
if (uid == cuid ) {
39
38
DEBUG (SSSDBG_FUNC_DATA , "Already user [%" SPRIuid "].\n" , uid );
@@ -49,7 +48,6 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
49
48
goto done ;
50
49
}
51
50
52
- /* change GID so that root cannot be regained (changes saved GID too) */
53
51
ret = setresgid (gid , gid , gid );
54
52
if (ret == -1 ) {
55
53
ret = errno ;
@@ -58,8 +56,6 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
58
56
goto done ;
59
57
}
60
58
61
- /* change UID so that root cannot be regained (changes saved UID too) */
62
- /* this call also takes care of dropping CAP_SETUID, so this is a PNR */
63
59
ret = setresuid (uid , uid , (keep_set_uid ? -1 : uid ));
64
60
if (ret == -1 ) {
65
61
ret = errno ;
@@ -69,6 +65,9 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
69
65
}
70
66
71
67
done :
68
+ /* clears permitted set as well, so even if suid allows to set
69
+ * euid back to 0 this wouldn't regain any capabilities
70
+ */
72
71
sss_drop_all_caps ();
73
72
74
73
return ret ;
@@ -134,55 +133,49 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
134
133
ssc -> gid = mygid ;
135
134
}
136
135
137
- /* if we are regaining root, set EUID first so that we have CAP_SETUID back,
138
- * and the other calls work too, otherwise call it last so that we can
139
- * change groups before we loose CAP_SETUID */
140
- if (uid == 0 ) {
141
- ret = setresuid (0 , 0 , 0 );
142
- if (ret == -1 ) {
143
- ret = errno ;
144
- DEBUG (SSSDBG_CRIT_FAILURE ,
145
- "setresuid failed [%d][%s].\n" , ret , strerror (ret ));
146
- goto done ;
147
- }
148
- }
149
-
150
- /* TODO: use libcap-ng if we need to get/set capabilities too? */
151
-
152
-
153
- /* try to setgroups first should always work if CAP_SETUID is set,
154
- * otherwise it will always fail, failure is not critical though as
155
- * generally we only really care about UID and at most primary GID */
136
+ /* 'man capabilities':
137
+ * - If the effective user ID is changed from 0 to nonzero,
138
+ * then all capabilities are cleared from the effective set.
139
+ *
140
+ * - If the effective user ID is changed from nonzero to 0,
141
+ * then the permitted set is copied to the effective set.
142
+ *
143
+ * The above means that behavior depends on if SSSD service user
144
+ * is 'root' or 'sssd'.
145
+ * Manage effective capabilities explicitly to avoid euid change
146
+ * effects.
147
+ */
148
+
149
+ sss_set_cap_effective (CAP_SETGID , true); /* if this fails then next op fails anyway */
156
150
ret = setgroups (num_gids , gids );
157
151
if (ret == -1 ) {
158
152
ret = errno ;
159
- DEBUG (SSSDBG_TRACE_FUNC ,
153
+ DEBUG (SSSDBG_OP_FAILURE ,
160
154
"setgroups failed [%d][%s].\n" , ret , strerror (ret ));
155
+ goto done ;
161
156
}
162
-
163
- /* change GID now, (leaves saved GID to current, so we can restore) */
164
157
ret = setresgid (-1 , gid , -1 );
165
158
if (ret == -1 ) {
166
159
ret = errno ;
167
- DEBUG (SSSDBG_CRIT_FAILURE ,
160
+ DEBUG (SSSDBG_OP_FAILURE ,
168
161
"setresgid failed [%d][%s].\n" , ret , strerror (ret ));
169
162
goto done ;
170
163
}
171
164
172
- if (uid != 0 ) {
173
- /* change UID, (leaves saved UID to current, so we can restore) */
174
- ret = setresuid (-1 , uid , -1 );
175
- if (ret == -1 ) {
176
- ret = errno ;
177
- DEBUG (SSSDBG_CRIT_FAILURE ,
178
- "setresuid failed [%d][%s].\n" , ret , strerror (ret ));
179
- goto done ;
180
- }
165
+ sss_set_cap_effective (CAP_SETUID , true);
166
+ ret = setresuid (-1 , uid , -1 );
167
+ if (ret == -1 ) {
168
+ ret = errno ;
169
+ DEBUG (SSSDBG_OP_FAILURE ,
170
+ "setresuid failed [%d][%s].\n" , ret , strerror (ret ));
171
+ goto done ;
181
172
}
182
173
183
174
ret = 0 ;
184
175
185
176
done :
177
+ sss_set_cap_effective (CAP_SETGID , false);
178
+ sss_set_cap_effective (CAP_SETUID , false); /* might be no-op but don't bother */
186
179
if (ret ) {
187
180
/* attempt to restore creds first */
188
181
restore_creds (ssc );
0 commit comments