@@ -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,55 @@ 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
- }
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
+ if (sss_set_cap_effective (CAP_SETGID , true) != EOK ) {
150
+ ret = EPERM ;
151
+ goto done ;
148
152
}
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 */
156
153
ret = setgroups (num_gids , gids );
157
154
if (ret == -1 ) {
158
155
ret = errno ;
159
- DEBUG (SSSDBG_TRACE_FUNC ,
156
+ DEBUG (SSSDBG_OP_FAILURE ,
160
157
"setgroups failed [%d][%s].\n" , ret , strerror (ret ));
158
+ goto done ;
161
159
}
162
-
163
- /* change GID now, (leaves saved GID to current, so we can restore) */
164
160
ret = setresgid (-1 , gid , -1 );
165
161
if (ret == -1 ) {
166
162
ret = errno ;
167
- DEBUG (SSSDBG_CRIT_FAILURE ,
163
+ DEBUG (SSSDBG_OP_FAILURE ,
168
164
"setresgid failed [%d][%s].\n" , ret , strerror (ret ));
169
165
goto done ;
170
166
}
171
167
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
- }
168
+ if (sss_set_cap_effective (CAP_SETUID , true) != EOK ) {
169
+ ret = EPERM ;
170
+ goto done ;
171
+ }
172
+ ret = setresuid (-1 , uid , -1 );
173
+ if (ret == -1 ) {
174
+ ret = errno ;
175
+ DEBUG (SSSDBG_OP_FAILURE ,
176
+ "setresuid failed [%d][%s].\n" , ret , strerror (ret ));
177
+ goto done ;
181
178
}
182
179
183
180
ret = 0 ;
184
181
185
182
done :
183
+ sss_set_cap_effective (CAP_SETGID , false);
184
+ sss_set_cap_effective (CAP_SETUID , false); /* might be no-op but don't bother */
186
185
if (ret ) {
187
186
/* attempt to restore creds first */
188
187
restore_creds (ssc );
0 commit comments