master-settings.c revision 27cd7a142ed0bb77cb87294d475c73250c84affe
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainenstatic bool master_settings_verify(void *_set, pool_t pool,
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen const char **error_r);
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainenextern struct setting_parser_info service_setting_parser_info;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen { type, #name, offsetof(struct file_listener_settings, name), NULL }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenstatic struct setting_define file_listener_setting_defines[] = {
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainenstatic struct file_listener_settings file_listener_default_settings = {
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainenstatic struct setting_parser_info file_listener_setting_parser_info = {
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen MEMBER(defines) file_listener_setting_defines,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen MEMBER(defaults) &file_listener_default_settings,
7bd3f5614e0dd2324dd1015f084de72c0b069a1aTimo Sirainen MEMBER(struct_size) sizeof(struct file_listener_settings)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen { type, #name, offsetof(struct inet_listener_settings, name), NULL }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenstatic struct setting_define inet_listener_setting_defines[] = {
e6d7d19c328e7043ad35d5a52c1617bde915a16fTimo Sirainenstatic struct inet_listener_settings inet_listener_default_settings = {
538c58fc95200fcc5e91abdda8b912b574a2f968Timo Sirainenstatic struct setting_parser_info inet_listener_setting_parser_info = {
b99f3f908d51f4d1f7628bdf2cc6100cd8587656Timo Sirainen MEMBER(defines) inet_listener_setting_defines,
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen MEMBER(defaults) &inet_listener_default_settings,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen MEMBER(struct_size) sizeof(struct inet_listener_settings)
7de1c472fd23ddac6b4dc5cbeee6fa6a8418b071Timo Sirainen { type, #name, offsetof(struct service_settings, name), NULL }
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainen { SET_DEFLIST, name, offsetof(struct service_settings, field), defines }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic struct setting_define service_setting_defines[] = {
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenstatic struct service_settings service_default_settings = {
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainenstruct setting_parser_info service_setting_parser_info = {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen MEMBER(parent_offset) offsetof(struct service_settings, master_set),
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen MEMBER(type_offset) offsetof(struct service_settings, name),
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen MEMBER(struct_size) sizeof(struct service_settings)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen { type, #name, offsetof(struct master_settings, name), NULL }
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen { SET_DEFLIST, name, offsetof(struct master_settings, field), defines }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic struct setting_define master_setting_defines[] = {
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen DEFLIST(services, "service", &service_setting_parser_info),
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic struct master_settings master_default_settings = {
68b3667c9ee95951d7c3e03b19b2d37abbaa5736Timo Sirainenstruct setting_parser_info master_setting_parser_info = {
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen MEMBER(struct_size) sizeof(struct master_settings),
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen/* <settings checks> */
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainenstatic void fix_file_listener_paths(ARRAY_TYPE(file_listener_settings) *l,
b32de04eb77234b25e2e411884a2503a1bf3c255Phil Carmody unsigned int i, count;
b32de04eb77234b25e2e411884a2503a1bf3c255Phil Carmody for (i = 0; i < count; i++) {
b32de04eb77234b25e2e411884a2503a1bf3c255Phil Carmody sets[i]->path = p_strconcat(pool, base_dir, "/",
dfdd228ab20092705da0e8812b3cd0a039319375Timo Sirainenmaster_settings_verify(void *_set, pool_t pool, const char **error_r)
dfdd228ab20092705da0e8812b3cd0a039319375Timo Sirainen unsigned int i, j, count;
458b283a2f3db6e5aff20b4df1bbd18ada3900ddTimo Sirainen *error_r = "first_valid_uid can't be larger than last_valid_uid";
070df93a3014ad4b2eb8754af65128c9f9a72e4ePhil Carmody *error_r = "first_valid_gid can't be larger than last_valid_gid";
74896b89e1d82819d710f9322cf7c9e72d5841adPhil Carmody /* check that we have at least one service. the actual service
74896b89e1d82819d710f9322cf7c9e72d5841adPhil Carmody structure validity is checked later while creating them. */
aba9cc9bf97576c0ca653d4e218567e617061029Phil Carmody for (i = 0; i < count; i++) {
aba9cc9bf97576c0ca653d4e218567e617061029Phil Carmody struct service_settings *service = services[i];
89b7d6ce9266288c156e3513f5798680f1e33572Phil Carmody "Service #%d is missing name", i);
53e0e6889bf659b86e4c7d2e83e27d69fd9d6bcbPhil Carmody *error_r = t_strconcat("Unknown service type: ",
1df526903ed039e8ff966a223c43b8d04eddf3c7Phil Carmody for (j = 0; j < i; j++) {
1df526903ed039e8ff966a223c43b8d04eddf3c7Phil Carmody if (strcmp(service->name, services[j]->name) == 0) {
53e0e6889bf659b86e4c7d2e83e27d69fd9d6bcbPhil Carmody "Duplicate service name: %s",
4e6629cb5d5e7f67d5023eda540105d32df5f2baPhil Carmody for (i = 0; i < count; i++) {
89b7d6ce9266288c156e3513f5798680f1e33572Phil Carmody struct service_settings *service = services[i];
53e0e6889bf659b86e4c7d2e83e27d69fd9d6bcbPhil Carmody if (*service->chroot != '/' && *service->chroot != '\0') {
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen "drop_priv_before_exec=yes can't be "
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen if (service->process_min_avail > service->process_limit) {
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen "process_min_avail is higher than process_limit",
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen fix_file_listener_paths(&service->unix_listeners,
1e2887ae909d9817cc43a7e40ecb50508419f7edTimo Sirainen fix_file_listener_paths(&service->fifo_listeners,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen set->protocols_split = p_strsplit(pool, set->protocols, " ");
1e2887ae909d9817cc43a7e40ecb50508419f7edTimo Sirainen/* </settings checks> */
1e2887ae909d9817cc43a7e40ecb50508419f7edTimo Sirainenlogin_want_core_dumps(const struct master_settings *set, gid_t *gid_r)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen unsigned int i, count;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen for (i = 0; i < count; i++) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (strcmp(services[i]->type, "auth-source") == 0 &&
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen strstr(services[i]->name, "-login") != NULL) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (strstr(services[i]->executable, " -D") != NULL)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen (void)get_uidgid(services[i]->user, &uid, gid_r, &error);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen (void)get_gid(services[i]->group, gid_r, &error);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainensettings_have_auth_unix_listeners_in(const struct master_settings *set,
4b89231f4ec9cc69f4aea715e1d34f405c7e317dTimo Sirainen const char *dir)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen struct file_listener_settings *const *u;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen for (i = 0; i < count; i++) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen array_is_created(&services[i]->unix_listeners)) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen u = array_get(&services[i]->unix_listeners, &count2);
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen for (j = 0; j < count2; j++) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if (strncmp(u[j]->path, dir, strlen(dir)) == 0)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenstatic void unlink_sockets(const char *path, const char *prefix)
b99f3f908d51f4d1f7628bdf2cc6100cd8587656Timo Sirainen if (strncmp(dp->d_name, prefix, prefix_len) != 0)
bddd52cb7f3e5a894c080f60750aa76b5aeaf103Timo Sirainen /* try to avoid unlinking sockets if someone's already
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen listening in them. do this only at startup, because
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen when SIGHUPing a child process might catch the new
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen connection before it notices that it's supposed
a28a6267f48971117dec958b160deefd14ebb7a6Timo Sirainen to die. null_fd == -1 check is a bit kludgy, but works.. */
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen "Socket already exists: %s",
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen if (unlink(str_c(str)) < 0 && errno != ENOENT)
b9ec0443d7d8afebfe61c17a9d692d6fad30c276Timo Sirainenbool master_settings_do_fixes(const struct master_settings *set)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* since base dir is under /var/run by default, it may have been
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (mkdir_parents(set->base_dir, 0777) < 0 && errno != EEXIST) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("mkdir(%s) failed: %m", set->base_dir);
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen /* allow base_dir to be a symlink, so don't use lstat() */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("stat(%s) failed: %m", set->base_dir);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_error("%s is not a directory", set->base_dir);
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainen /* Make sure our permanent state directory exists */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (mkdir_parents(PKG_STATEDIR, 0750) < 0 && errno != EEXIST) {
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen i_error("mkdir(%s) failed: %m", PKG_STATEDIR);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* remove auth worker sockets left by unclean exits */
51920d00fa50edf7b2e9b1019288d64b7abee7f3Timo Sirainen unlink_sockets(set->base_dir, "auth-worker.");
be8c8479f918875eda871c5685ab2b4067228e26Phil Carmody login_dir = t_strconcat(set->base_dir, "/login", NULL);
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen if (settings_have_auth_unix_listeners_in(set, login_dir)) {
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen /* we are not using external authentication, so make sure the
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen login directory exists with correct permissions and it's
be8c8479f918875eda871c5685ab2b4067228e26Phil Carmody empty. with external auth we wouldn't want to delete
be8c8479f918875eda871c5685ab2b4067228e26Phil Carmody existing sockets or break the permissions required by the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth server. */
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen mode_t mode = login_want_core_dumps(set, &gid) ? 0770 : 0750;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen safe_mkdir(login_dir, mode, master_uid, gid) == 0) {
3342badd8c69adff34db589fb0a221ace5996212Timo Sirainen i_warning("Corrected permissions for login directory "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* still make sure that login directory exists */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (mkdir(login_dir, 0755) < 0 && errno != EEXIST) {
fd2118e34f4d1d65cffdccc40d74dda931fae81eTimo Sirainen empty_dir = t_strconcat(set->base_dir, "/empty", NULL);
fd2118e34f4d1d65cffdccc40d74dda931fae81eTimo Sirainen if (safe_mkdir(empty_dir, 0755, master_uid, getegid()) == 0) {
fd2118e34f4d1d65cffdccc40d74dda931fae81eTimo Sirainen i_warning("Corrected permissions for empty directory "