int main(void)
{
string_t *str;
- const char *user, *home, *authorized;
+ const char *user, *home, *authorized, *orig_uid;
const char *extra_env, *key, *value, *const *tmp;
bool uid_found = FALSE, gid_found = FALSE;
lib_init();
str = t_str_new(1024);
+ orig_uid = getenv("ORIG_UID");
+ /* ORIG_UID should have the auth process's UID that forked us.
+ if the checkpassword changed the UID, this could be a security hole
+ because the UID's other processes can ptrace this process and write
+ any kind of a reply to fd 4. so we can run only if:
+
+ a) INSECURE_SETUID environment is set.
+ b) process isn't ptraceable (this binary is setuid/setgid)
+ c) checkpassword didn't actually change the UID (but used
+ userdb_uid instead)
+ */
+ if (getenv("INSECURE_SETUID") == NULL &&
+ (orig_uid == NULL || strtoul(orig_uid, NULL, 10) != getuid()) &&
+ getuid() == geteuid() && getgid() == getegid()) {
+ if (orig_uid == NULL) {
+ i_error("checkpassword: ORIG_UID environment was dropped by checkpassword. "
+ "Can't verify if we're safe to run. See "
+ "http://wiki2.dovecot.org/AuthDatabase/CheckPassword#Security");
+ } else {
+ i_error("checkpassword: The checkpassword couldn't be run securely. See "
+ "http://wiki2.dovecot.org/AuthDatabase/CheckPassword#Security");
+ }
+ return 111;
+ }
+
user = getenv("USER");
if (user != NULL) {
if (strchr(user, '\t') != NULL) {
pipe, also pass some other possibly interesting information
via environment. Use UCSPI names for local/remote IPs. */
env_put("PROTO=TCP"); /* UCSPI */
+ env_put(t_strdup_printf("ORIG_UID=%s", dec2str(getuid())));
env_put(t_strconcat("SERVICE=", request->service, NULL));
if (request->local_ip.family != 0) {
env_put(t_strconcat("TCPLOCALIP=",