Skip to content

Commit 636f01e

Browse files
UTIL: refactor switch_creds()
to simplify logic, make it more reliable doesn't matter what SSSD service user is used and rely only on permitted caps.
1 parent af9bdd6 commit 636f01e

File tree

1 file changed

+29
-36
lines changed

1 file changed

+29
-36
lines changed

src/util/become_user.c

+29-36
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
3333
DEBUG(SSSDBG_FUNC_DATA,
3434
"Trying to become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid);
3535

36-
/* skip call if we already are the requested user */
3736
cuid = geteuid();
3837
if (uid == cuid) {
3938
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)
4948
goto done;
5049
}
5150

52-
/* change GID so that root cannot be regained (changes saved GID too) */
5351
ret = setresgid(gid, gid, gid);
5452
if (ret == -1) {
5553
ret = errno;
@@ -58,8 +56,6 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
5856
goto done;
5957
}
6058

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 */
6359
ret = setresuid(uid, uid, (keep_set_uid ? -1 : uid));
6460
if (ret == -1) {
6561
ret = errno;
@@ -69,6 +65,9 @@ errno_t become_user(uid_t uid, gid_t gid, bool keep_set_uid)
6965
}
7066

7167
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+
*/
7271
sss_drop_all_caps();
7372

7473
return ret;
@@ -134,55 +133,49 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
134133
ssc->gid = mygid;
135134
}
136135

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 */
156150
ret = setgroups(num_gids, gids);
157151
if (ret == -1) {
158152
ret = errno;
159-
DEBUG(SSSDBG_TRACE_FUNC,
153+
DEBUG(SSSDBG_OP_FAILURE,
160154
"setgroups failed [%d][%s].\n", ret, strerror(ret));
155+
goto done;
161156
}
162-
163-
/* change GID now, (leaves saved GID to current, so we can restore) */
164157
ret = setresgid(-1, gid, -1);
165158
if (ret == -1) {
166159
ret = errno;
167-
DEBUG(SSSDBG_CRIT_FAILURE,
160+
DEBUG(SSSDBG_OP_FAILURE,
168161
"setresgid failed [%d][%s].\n", ret, strerror(ret));
169162
goto done;
170163
}
171164

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;
181172
}
182173

183174
ret = 0;
184175

185176
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 */
186179
if (ret) {
187180
/* attempt to restore creds first */
188181
restore_creds(ssc);

0 commit comments

Comments
 (0)