diff options
Diffstat (limited to 'uidswap.c')
-rw-r--r-- | uidswap.c | 101 |
1 files changed, 64 insertions, 37 deletions
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$OpenBSD: uidswap.c,v 1.13 2001/01/21 19:06:01 markus Exp $"); | 15 | RCSID("$OpenBSD: uidswap.c,v 1.14 2001/04/06 21:00:16 markus Exp $"); |
16 | 16 | ||
17 | #include "log.h" | 17 | #include "log.h" |
18 | #include "uidswap.h" | 18 | #include "uidswap.h" |
@@ -26,57 +26,80 @@ RCSID("$OpenBSD: uidswap.c,v 1.13 2001/01/21 19:06:01 markus Exp $"); | |||
26 | * POSIX saved uids or not. | 26 | * POSIX saved uids or not. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS) | ||
30 | /* Lets assume that posix saved ids also work with seteuid, even though that | 29 | /* Lets assume that posix saved ids also work with seteuid, even though that |
31 | is not part of the posix specification. */ | 30 | is not part of the posix specification. */ |
32 | #define SAVED_IDS_WORK_WITH_SETEUID | 31 | |
33 | /* Saved effective uid. */ | 32 | /* Saved effective uid. */ |
34 | static uid_t saved_euid = 0; | 33 | static int privileged = 0; |
35 | #endif | 34 | static int temporarily_use_uid_effective = 0; |
36 | 35 | static uid_t saved_euid = 0; | |
36 | static gid_t saved_egid; | ||
37 | static gid_t saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX]; | ||
38 | static int saved_egroupslen = -1, user_groupslen = -1; | ||
39 | |||
37 | /* | 40 | /* |
38 | * Temporarily changes to the given uid. If the effective user | 41 | * Temporarily changes to the given uid. If the effective user |
39 | * id is not root, this does nothing. This call cannot be nested. | 42 | * id is not root, this does nothing. This call cannot be nested. |
40 | */ | 43 | */ |
41 | void | 44 | void |
42 | temporarily_use_uid(uid_t uid) | 45 | temporarily_use_uid(struct passwd *pw) |
43 | { | 46 | { |
44 | #ifdef SAVED_IDS_WORK_WITH_SETEUID | 47 | /* Save the current euid, and egroups. */ |
45 | /* Save the current euid. */ | 48 | saved_euid = geteuid(); |
46 | saved_euid = geteuid(); | 49 | debug("temporarily_use_uid: %d/%d (e=%d)", |
47 | 50 | pw->pw_uid, pw->pw_gid, saved_euid); | |
48 | /* Set the effective uid to the given (unprivileged) uid. */ | 51 | if (saved_euid != 0) { |
49 | if (seteuid(uid) == -1) | 52 | privileged = 0; |
50 | debug("seteuid %u: %.100s", (u_int) uid, strerror(errno)); | 53 | return; |
51 | #else /* SAVED_IDS_WORK_WITH_SETEUID */ | 54 | } |
52 | /* Propagate the privileged uid to all of our uids. */ | 55 | privileged = 1; |
53 | if (setuid(geteuid()) < 0) | 56 | temporarily_use_uid_effective = 1; |
54 | debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno)); | 57 | saved_egid = getegid(); |
55 | 58 | saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups); | |
56 | /* Set the effective uid to the given (unprivileged) uid. */ | 59 | if (saved_egroupslen < 0) |
57 | if (seteuid(uid) == -1) | 60 | fatal("getgroups: %.100s", strerror(errno)); |
58 | debug("seteuid %u: %.100s", (u_int) uid, strerror(errno)); | 61 | |
59 | #endif /* SAVED_IDS_WORK_WITH_SETEUID */ | 62 | /* set and save the user's groups */ |
63 | if (user_groupslen == -1) { | ||
64 | if (initgroups(pw->pw_name, pw->pw_gid) < 0) | ||
65 | fatal("initgroups: %s: %.100s", pw->pw_name, | ||
66 | strerror(errno)); | ||
67 | user_groupslen = getgroups(NGROUPS_MAX, user_groups); | ||
68 | if (user_groupslen < 0) | ||
69 | fatal("getgroups: %.100s", strerror(errno)); | ||
70 | } | ||
71 | /* Set the effective uid to the given (unprivileged) uid. */ | ||
72 | if (setgroups(user_groupslen, user_groups) < 0) | ||
73 | fatal("setgroups: %.100s", strerror(errno)); | ||
74 | pw->pw_gid = pw->pw_gid; | ||
75 | if (setegid(pw->pw_gid) < 0) | ||
76 | fatal("setegid %u: %.100s", (u_int) pw->pw_gid, | ||
77 | strerror(errno)); | ||
78 | if (seteuid(pw->pw_uid) == -1) | ||
79 | fatal("seteuid %u: %.100s", (u_int) pw->pw_uid, | ||
80 | strerror(errno)); | ||
60 | } | 81 | } |
61 | 82 | ||
62 | /* | 83 | /* |
63 | * Restores to the original uid. | 84 | * Restores to the original uid. |
64 | */ | 85 | */ |
65 | void | 86 | void |
66 | restore_uid(void) | 87 | restore_uid(void) |
67 | { | 88 | { |
68 | #ifdef SAVED_IDS_WORK_WITH_SETEUID | 89 | debug("restore_uid"); |
90 | /* it's a no-op unless privileged */ | ||
91 | if (!privileged) | ||
92 | return; | ||
93 | if (!temporarily_use_uid_effective) | ||
94 | fatal("restore_uid: temporarily_use_uid not effective"); | ||
69 | /* Set the effective uid back to the saved uid. */ | 95 | /* Set the effective uid back to the saved uid. */ |
70 | if (seteuid(saved_euid) < 0) | 96 | if (seteuid(saved_euid) < 0) |
71 | debug("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); | 97 | fatal("seteuid %u: %.100s", (u_int) saved_euid, strerror(errno)); |
72 | #else /* SAVED_IDS_WORK_WITH_SETEUID */ | 98 | if (setgroups(saved_egroupslen, saved_egroups) < 0) |
73 | /* | 99 | fatal("setgroups: %.100s", strerror(errno)); |
74 | * We are unable to restore the real uid to its unprivileged value. | 100 | if (setegid(saved_egid) < 0) |
75 | * Propagate the real uid (usually more privileged) to effective uid | 101 | fatal("setegid %u: %.100s", (u_int) saved_egid, strerror(errno)); |
76 | * as well. | 102 | temporarily_use_uid_effective = 0; |
77 | */ | ||
78 | setuid(getuid()); | ||
79 | #endif /* SAVED_IDS_WORK_WITH_SETEUID */ | ||
80 | } | 103 | } |
81 | 104 | ||
82 | /* | 105 | /* |
@@ -84,8 +107,12 @@ restore_uid(void) | |||
84 | * called while temporarily_use_uid is effective. | 107 | * called while temporarily_use_uid is effective. |
85 | */ | 108 | */ |
86 | void | 109 | void |
87 | permanently_set_uid(uid_t uid) | 110 | permanently_set_uid(struct passwd *pw) |
88 | { | 111 | { |
89 | if (setuid(uid) < 0) | 112 | if (temporarily_use_uid_effective) |
90 | debug("setuid %u: %.100s", (u_int) uid, strerror(errno)); | 113 | fatal("restore_uid: temporarily_use_uid effective"); |
114 | if (setuid(pw->pw_uid) < 0) | ||
115 | fatal("setuid %u: %.100s", (u_int) pw->pw_uid, strerror(errno)); | ||
116 | if (setgid(pw->pw_gid) < 0) | ||
117 | fatal("setgid %u: %.100s", (u_int) pw->pw_gid, strerror(errno)); | ||
91 | } | 118 | } |