master-settings.c revision f11de734327a7a4db80a16a493df0020d9bd4f16
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#include "common.h"
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#include "array.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "env-util.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "istream.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "str.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "mkdir-parents.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "safe-mkdir.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "settings-parser.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "master-settings.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include <stddef.h>
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include <dirent.h>
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include <unistd.h>
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include <sys/stat.h>
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include <sys/wait.h>
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallynstatic bool master_settings_verify(void *_set, pool_t pool,
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn const char **error_r);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynextern struct setting_parser_info service_setting_parser_info;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#undef DEF
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#define DEF(type, name) \
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser { type, #name, offsetof(struct file_listener_settings, name), NULL }
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct setting_define file_listener_setting_defines[] = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, path),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, mode),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, user),
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn DEF(SET_STR, group),
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn SETTING_DEFINE_LIST_END
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn};
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallynstatic struct file_listener_settings file_listener_default_settings = {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(path) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(mode) 0600,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(user) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(group) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct setting_parser_info file_listener_setting_parser_info = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(defines) file_listener_setting_defines,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(defaults) &file_listener_default_settings,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(parent) &service_setting_parser_info,
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn MEMBER(parent_offset) (size_t)-1,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(type_offset) (size_t)-1,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(struct_size) sizeof(struct file_listener_settings)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#undef DEF
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn#define DEF(type, name) \
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn { type, #name, offsetof(struct inet_listener_settings, name), NULL }
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
4759162d078d86628956cae4846c6efccf548e67Serge Hallynstatic struct setting_define inet_listener_setting_defines[] = {
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber DEF(SET_STR, address),
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn DEF(SET_UINT, port),
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn DEF(SET_BOOL, ssl),
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn SETTING_DEFINE_LIST_END
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber};
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct inet_listener_settings inet_listener_default_settings = {
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber MEMBER(address) "*",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(port) 0,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(ssl) FALSE
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber};
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct setting_parser_info inet_listener_setting_parser_info = {
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn MEMBER(defines) inet_listener_setting_defines,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(defaults) &inet_listener_default_settings,
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber MEMBER(parent) &service_setting_parser_info,
9313e1e628160ca64f9e7fcec6500056c9a0725fStéphane Graber MEMBER(parent_offset) (size_t)-1,
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn MEMBER(type_offset) (size_t)-1,
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn MEMBER(struct_size) sizeof(struct inet_listener_settings)
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn};
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#undef DEF
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn#undef DEFLIST
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#define DEF(type, name) \
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn { type, #name, offsetof(struct service_settings, name), NULL }
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn#define DEFLIST(field, name, defines) \
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn { SET_DEFLIST, name, offsetof(struct service_settings, field), defines }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct setting_define service_setting_defines[] = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, name),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, protocol),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, type),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, executable),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, user),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, group),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, privileged_group),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, extra_groups),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, chroot),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, auth_dest_service),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_BOOL, drop_priv_before_exec),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, process_limit),
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn DEF(SET_UINT, client_limit),
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber DEF(SET_UINT, vsz_limit),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber DEFLIST(unix_listeners, "unix_listener",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &file_listener_setting_parser_info),
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber DEFLIST(fifo_listeners, "fifo_listener",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &file_listener_setting_parser_info),
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber DEFLIST(inet_listeners, "inet_listener",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &inet_listener_setting_parser_info),
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn SETTING_DEFINE_LIST_END
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn};
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct service_settings service_default_settings = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(master_set) NULL,
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn MEMBER(name) "",
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber MEMBER(protocol) "",
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber MEMBER(type) "",
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber MEMBER(executable) "",
4d7bcfb638c5c4907e8539aa09d41bb1de08a097Serge Hallyn MEMBER(user) "",
bf7d76cf3ae180820c0a29e0bfbaa97c20ce6a3dSerge Hallyn MEMBER(group) "",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(privileged_group) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(extra_groups) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(chroot) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(auth_dest_service) "",
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn MEMBER(drop_priv_before_exec) FALSE,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(process_limit) (unsigned int)-1,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(client_limit) 0,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(vsz_limit) 256,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn MEMBER(unix_listeners) ARRAY_INIT,
542939c31bb73bab55f2fd71243b98f5559597d1Stéphane Graber MEMBER(fifo_listeners) ARRAY_INIT,
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn MEMBER(inet_listeners) ARRAY_INIT
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn};
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn
5ff337745e4a705293b056ab58f6ea7a92cabbc8Stéphane Graberstruct setting_parser_info service_setting_parser_info = {
542939c31bb73bab55f2fd71243b98f5559597d1Stéphane Graber MEMBER(defines) service_setting_defines,
5ff337745e4a705293b056ab58f6ea7a92cabbc8Stéphane Graber MEMBER(defaults) &service_default_settings,
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn MEMBER(parent) &master_setting_parser_info,
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn MEMBER(dynamic_parsers) NULL,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(parent_offset) offsetof(struct service_settings, master_set),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(type_offset) offsetof(struct service_settings, name),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(struct_size) sizeof(struct service_settings)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn#undef DEF
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn#define DEF(type, name) \
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn { type, #name, offsetof(struct master_auth_settings, name), NULL }
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallynstatic struct setting_define master_auth_setting_defines[] = {
840295ff4cf11da0938a19f99fef8a1525de8106Stéphane Graber DEF(SET_BOOL, debug),
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn SETTING_DEFINE_LIST_END
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn};
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moserstatic struct master_auth_settings master_auth_default_settings = {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(debug) FALSE
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstruct setting_parser_info master_auth_setting_parser_info = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(defines) master_auth_setting_defines,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(defaults) &master_auth_default_settings,
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(parent) &master_setting_parser_info,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(dynamic_parsers) NULL,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(parent_offset) (size_t)-1,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(type_offset) (size_t)-1,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(struct_size) sizeof(struct master_auth_settings)
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn};
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#undef DEF
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#undef DEFLIST
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#define DEF(type, name) \
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser { type, #name, offsetof(struct master_settings, name), NULL }
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#define DEFLIST(field, name, defines) \
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser { SET_DEFLIST, name, offsetof(struct master_settings, field), defines }
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moserstatic struct setting_define master_setting_defines[] = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, base_dir),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, libexec_dir),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_STR, protocols),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, default_process_limit),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, default_client_limit),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_BOOL, version_ignore),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_BOOL, mail_debug),
ed4616b1cfbc84dd01caa8546d813e8c5d482921Christian Bühler
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, first_valid_uid),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, last_valid_uid),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, first_valid_gid),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DEF(SET_UINT, last_valid_gid),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn DEFLIST(services, "service", &service_setting_parser_info),
b8bced69a80a8be95fdbbb6b4e9ad7fa85464b1eSerge Hallyn DEFLIST(auths, "auth", &master_auth_setting_parser_info),
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn SETTING_DEFINE_LIST_END
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic struct master_settings master_default_settings = {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(base_dir) PKG_RUNDIR,
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn MEMBER(libexec_dir) PKG_LIBEXECDIR,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(protocols) "imap pop3 lmtp",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(default_process_limit) 100,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn MEMBER(default_client_limit) 1000,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn MEMBER(version_ignore) FALSE,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(mail_debug) FALSE,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(first_valid_uid) 500,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn MEMBER(last_valid_uid) 0,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn MEMBER(first_valid_gid) 1,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn MEMBER(last_valid_gid) 0,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn MEMBER(services) ARRAY_INIT,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn MEMBER(auths) ARRAY_INIT
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn};
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallynstruct setting_parser_info master_setting_parser_info = {
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn MEMBER(defines) master_setting_defines,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(defaults) &master_default_settings,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(parent) NULL,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(parent_offset) (size_t)-1,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(type_offset) (size_t)-1,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser MEMBER(struct_size) sizeof(struct master_settings),
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn MEMBER(check_func) master_settings_verify
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn};
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn/* <settings checks> */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic void fix_file_listener_paths(ARRAY_TYPE(file_listener_settings) *l,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn pool_t pool, const char *base_dir)
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn{
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser struct file_listener_settings *const *sets;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser unsigned int i, count;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn if (!array_is_created(l))
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn return;
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn sets = array_get(l, &count);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn for (i = 0; i < count; i++) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (*sets[i]->path != '/') {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn sets[i]->path = p_strconcat(pool, base_dir, "/",
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber sets[i]->path, NULL);
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graberstatic bool
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Grabermaster_settings_verify(void *_set, pool_t pool, const char **error_r)
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber{
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber struct master_settings *set = _set;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber struct service_settings *const *services;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber unsigned int i, j, count;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber if (set->last_valid_uid != 0 &&
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber set->first_valid_uid > set->last_valid_uid) {
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber *error_r = "first_valid_uid can't be larger than last_valid_uid";
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber return FALSE;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber }
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber if (set->last_valid_gid != 0 &&
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber set->first_valid_gid > set->last_valid_gid) {
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber *error_r = "first_valid_gid can't be larger than last_valid_gid";
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber return FALSE;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber }
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* check that we have at least one service. the actual service
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn structure validity is checked later while creating them. */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn services = array_get(&set->services, &count);
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn if (count == 0) {
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn *error_r = "No services defined";
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn return FALSE;
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn }
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn for (i = 0; i < count; i++) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (*services[i]->name == '\0') {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn *error_r = t_strdup_printf(
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn "Service #%d is missing name", i);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return FALSE;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (*services[i]->type != '\0' &&
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn strcmp(services[i]->type, "log") != 0 &&
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn strcmp(services[i]->type, "config") != 0 &&
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn strcmp(services[i]->type, "anvil") != 0 &&
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn strcmp(services[i]->type, "auth") != 0 &&
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn strcmp(services[i]->type, "auth-source") != 0) {
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn *error_r = t_strconcat("Unknown service type: ",
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn services[i]->type, NULL);
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn return FALSE;
853d58fdf5af0960b7b6edc9dea0fadddb8535f1Elan Ruusamäe }
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn for (j = 0; j < i; j++) {
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn if (strcmp(services[i]->name, services[j]->name) == 0) {
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn *error_r = t_strdup_printf(
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn "Duplicate service name: %s",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn services[i]->name);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return FALSE;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn for (i = 0; i < count; i++) {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (*services[i]->executable != '/') {
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn services[i]->executable =
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn p_strconcat(pool, set->libexec_dir, "/",
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn services[i]->executable, NULL);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (*services[i]->chroot != '/' &&
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn *services[i]->chroot != '\0') {
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser services[i]->chroot =
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn p_strconcat(pool, set->base_dir, "/",
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser services[i]->chroot, NULL);
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser }
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if (services[i]->drop_priv_before_exec &&
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn *services[i]->chroot != '\0') {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn *error_r = t_strdup_printf("service(%s): "
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn "drop_priv_before_exec=yes can't be "
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn "used with chroot", services[i]->name);
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn return FALSE;
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser }
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn fix_file_listener_paths(&services[i]->unix_listeners,
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn pool, set->base_dir);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn fix_file_listener_paths(&services[i]->fifo_listeners,
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn pool, set->base_dir);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn set->protocols_split = p_strsplit(pool, set->protocols, " ");
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn return TRUE;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn}
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn/* </settings checks> */
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallynstatic bool
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallynlogin_want_core_dumps(const struct master_settings *set, gid_t *gid_r)
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn{
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn struct service_settings *const *services;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn unsigned int i, count;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn const char *error;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn bool cores = FALSE;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn uid_t uid;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
edd3810e951ec1b20af761955e6100ab75a66534Serge Hallyn *gid_r = (gid_t)-1;
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn services = array_get(&set->services, &count);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn for (i = 0; i < count; i++) {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (strcmp(services[i]->type, "auth-source") == 0 &&
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn strstr(services[i]->name, "-login") != NULL) {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (strstr(services[i]->executable, " -D") != NULL)
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn cores = TRUE;
9c3bc32c5789b76b8c42b75d7625377d61e052c1Stéphane Graber (void)get_uidgid(services[i]->user, &uid, gid_r, &error);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (*services[i]->group != '\0')
9c3bc32c5789b76b8c42b75d7625377d61e052c1Stéphane Graber (void)get_gid(services[i]->group, gid_r, &error);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn return cores;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn}
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallynstatic bool
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallynsettings_have_auth_unix_listeners_in(const struct master_settings *set,
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn const char *dir)
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn{
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn struct service_settings *const *services;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn struct file_listener_settings *const *u;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn unsigned int i, j, count, count2;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn services = array_get(&set->services, &count);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn for (i = 0; i < count; i++) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (strcmp(services[i]->type, "auth") == 0 &&
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn array_is_created(&services[i]->unix_listeners)) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn u = array_get(&services[i]->unix_listeners, &count2);
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn for (j = 0; j < count2; j++) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (strncmp(u[j]->path, dir, strlen(dir)) == 0)
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser return TRUE;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn }
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn }
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn return FALSE;
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallynstatic void unlink_sockets(const char *path, const char *prefix)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn{
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn DIR *dirp;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn struct dirent *dp;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn struct stat st;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn string_t *str;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn unsigned int prefix_len;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn dirp = opendir(path);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (dirp == NULL) {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn i_error("opendir(%s) failed: %m", path);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn return;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn }
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn prefix_len = strlen(prefix);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn str = t_str_new(256);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn while ((dp = readdir(dirp)) != NULL) {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (dp->d_name[0] == '.')
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn continue;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn if (strncmp(dp->d_name, prefix, prefix_len) != 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn continue;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser str_truncate(str, 0);
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn str_printfa(str, "%s/%s", path, dp->d_name);
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber if (lstat(str_c(str), &st) < 0) {
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber if (errno != ENOENT)
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber i_error("lstat(%s) failed: %m", str_c(str));
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn continue;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (!S_ISSOCK(st.st_mode))
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn continue;
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser /* try to avoid unlinking sockets if someone's already
listening in them. do this only at startup, because
when SIGHUPing a child process might catch the new
connection before it notices that it's supposed
to die. null_fd == -1 check is a bit kludgy, but works.. */
if (null_fd == -1) {
int fd = net_connect_unix(str_c(str));
if (fd != -1 || errno != ECONNREFUSED) {
i_fatal("Dovecot is already running? "
"Socket already exists: %s",
str_c(str));
}
}
if (unlink(str_c(str)) < 0 && errno != ENOENT)
i_error("unlink(%s) failed: %m", str_c(str));
}
(void)closedir(dirp);
}
bool master_settings_do_fixes(const struct master_settings *set)
{
const char *login_dir, *empty_dir;
struct stat st;
gid_t gid;
/* since base dir is under /var/run by default, it may have been
deleted. */
if (mkdir_parents(set->base_dir, 0777) < 0 && errno != EEXIST) {
i_error("mkdir(%s) failed: %m", set->base_dir);
return FALSE;
}
/* allow base_dir to be a symlink, so don't use lstat() */
if (stat(set->base_dir, &st) < 0) {
i_error("stat(%s) failed: %m", set->base_dir);
return FALSE;
}
if (!S_ISDIR(st.st_mode)) {
i_error("%s is not a directory", set->base_dir);
return FALSE;
}
/* Make sure our permanent state directory exists */
if (mkdir_parents(PKG_STATEDIR, 0750) < 0 && errno != EEXIST) {
i_error("mkdir(%s) failed: %m", PKG_STATEDIR);
return FALSE;
}
/* remove auth worker sockets left by unclean exits */
unlink_sockets(set->base_dir, "auth-worker.");
login_dir = t_strconcat(set->base_dir, "/login", NULL);
if (settings_have_auth_unix_listeners_in(set, login_dir)) {
/* we are not using external authentication, so make sure the
login directory exists with correct permissions and it's
empty. with external auth we wouldn't want to delete
existing sockets or break the permissions required by the
auth server. */
mode_t mode = login_want_core_dumps(set, &gid) ? 0770 : 0750;
if (gid != (gid_t)-1 &&
safe_mkdir(login_dir, mode, master_uid, gid) == 0) {
i_warning("Corrected permissions for login directory "
"%s", login_dir);
}
unlink_sockets(login_dir, "");
} else {
/* still make sure that login directory exists */
if (mkdir(login_dir, 0755) < 0 && errno != EEXIST) {
i_error("mkdir(%s) failed: %m", login_dir);
return FALSE;
}
}
empty_dir = t_strconcat(set->base_dir, "/empty", NULL);
if (safe_mkdir(empty_dir, 0755, master_uid, getegid()) == 0) {
i_warning("Corrected permissions for empty directory "
"%s", empty_dir);
}
return TRUE;
}