restrict-access.c revision 30abcf7cbda58078b3bf8b85bbd1e1df6c17d5a3
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenvoid restrict_access_set_env(const char *user, uid_t uid, gid_t gid,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen env_put(t_strconcat("RESTRICT_USER=", user, NULL));
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (chroot_dir != NULL && *chroot_dir != '\0')
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen env_put(t_strconcat("RESTRICT_CHROOT=", chroot_dir, NULL));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen env_put(t_strdup_printf("RESTRICT_SETUID=%s", dec2str(uid)));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen env_put(t_strdup_printf("RESTRICT_SETGID=%s", dec2str(gid)));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (extra_groups != NULL && *extra_groups != '\0') {
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen env_put(t_strdup_printf("RESTRICT_GID_FIRST=%s",
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen env_put(t_strdup_printf("RESTRICT_GID_LAST=%s",
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic gid_t *get_groups_list(unsigned int *gid_count_r)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* @UNSAFE */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if ((ret = getgroups(gid_count, gid_list)) < 0)
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainenstatic bool drop_restricted_groups(gid_t *gid_list, unsigned int *gid_count,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* @UNSAFE */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen const char *env;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen unsigned int i, used;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen first_valid = env == NULL ? 0 : (gid_t)strtoul(env, NULL, 10);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen last_valid = env == NULL ? (gid_t)-1 : (gid_t)strtoul(env, NULL, 10);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen (last_valid == (gid_t)-1 || gid_list[i] <= last_valid)) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_fatal("unknown group name in extra_groups: %s", name);
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainenstatic void fix_groups_list(const char *extra_groups, gid_t egid,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen bool preserve_existing, bool *have_root_group)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (!drop_restricted_groups(gid_list, &gid_count,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* nothing dropped, no extra groups to grant. */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* nothing to do */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* Some OSes don't like an empty groups list,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen so use the effective GID as the only one. */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen gid_list[0] = egid != (gid_t)-1 ? egid : getegid();
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* @UNSAFE: add extra groups to gids list */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen gid_list2 = t_new(gid_t, gid_count + str_array_length(tmp));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen memcpy(gid_list2, gid_list, gid_count * sizeof(gid_t));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_fatal("setgroups(%s) failed: Too many extra groups",
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenvoid restrict_access_by_env(bool disallow_root)
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen const char *env;
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen bool is_root, have_root_group, preserve_groups = FALSE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* set the primary group */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen gid = env == NULL || *env == '\0' ? (gid_t)-1 :
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (gid != (gid_t)-1 && (gid != getgid() || gid != getegid())) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen i_fatal("setgid(%s) failed with euid=%s, egid=%s: %m",
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* set system user's groups */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* add extra groups. if we set system user's groups, drop the
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen restricted groups at the same time. */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* chrooting */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* kludge: localtime() must be called before chroot(),
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen or the timezone isn't known */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen /* uid last */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen uid = env == NULL || *env == '\0' ? 0 : (uid_t)strtoul(env, NULL, 10);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* verify that we actually dropped the privileges */
f5a24412980cb19b07cb0cd12dba75886f281875Timo Sirainen if (setuid(0) == 0) {
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen if ((!have_root_group || (env != NULL && atoi(env) != 0)) && uid != 0) {
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen if (getgid() == 0 || getegid() == 0 || setgid(0) == 0) {
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen i_fatal("We couldn't drop root group privileges "
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen /* clear the environment, so we don't fail if we get back here */