auth-process.c revision fe594abcaff07e7f69be1ce3bfcc7a62ff033e74
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (sizeof(struct auth_master_reply) + AUTH_MASTER_MAX_REPLY_DATA_SIZE)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic unsigned int auth_tag;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic struct auth_process_group *process_groups;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void auth_process_destroy(struct auth_process *p);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int handle_reply(struct auth_process *process,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const unsigned char *data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen context = hash_lookup(process->requests, POINTER_CAST(reply->tag));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_error("Auth process %s sent unrequested reply with tag %u",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* make sure the reply looks OK */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* fix the request so that all the values point to \0 terminated
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (reply->system_user_idx >= reply->data_size)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (reply->virtual_user_idx >= reply->data_size)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen hash_remove(process->requests, POINTER_CAST(reply->tag));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenvoid auth_process_request(struct auth_process *process, unsigned int login_pid,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = o_stream_send(process->output, &req, sizeof(req));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* FIXME: well .. I'm not sure if it'd be better to
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen just block here. I don't think this condition should
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen happen often, so this could mean that the auth
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen process is stuck. Or that the computer is just
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen too heavily loaded. Possibility to block infinitely
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen is annoying though, so for now don't do it. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_warning("Auth process %s transmit buffer full, "
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen hash_insert(process->requests, POINTER_CAST(req.tag), context);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const unsigned char *data;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* disconnected */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* buffer full */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_error("BUG: Auth process %s sent us more than %d "
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen "bytes of data", dec2str(p->pid), (int)MAX_INBUF_SIZE);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_fatal("Auth process sent invalid initialization "
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen "notification");
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memcpy(&p->auth_reply, data, sizeof(p->auth_reply));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_stream_skip(p->input, sizeof(p->auth_reply));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* reply is now read */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_stream_skip(p->input, p->auth_reply.data_size);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenauth_process_new(pid_t pid, int fd, struct auth_process_group *group)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen p->io = io_add(fd, IO_READ, auth_process_input, p);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen p->input = i_stream_create_file(fd, default_pool,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen p->output = o_stream_create_file(fd, default_pool,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen p->requests = hash_create(default_pool, default_pool, 0, NULL, NULL);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void auth_process_destroy(struct auth_process *p)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!p->initialized && io_loop_is_running(ioloop) && !p->external) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_error("Auth process died too early - shutting down");
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (pos = &p->group->processes; *pos != NULL; pos = &(*pos)->next) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (*pos == p) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainensocket_settings_env_put(const char *env_base, struct socket_settings *set)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strdup_printf("%s_PATH=%s", env_base, set->path));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strdup_printf("%s_MODE=%u", env_base, set->mode));
534e41e436a7546f36f61e0dc49c0c191d850f6bPhil Carmody env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int connect_auth_socket(struct auth_process_group *group,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_error("net_connect_unix(%s) failed: %m", path);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int create_auth_process(struct auth_process_group *group)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* see if this is a connect socket */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (as != NULL && strcmp(as->type, "connect") == 0)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return connect_auth_socket(group, as->master.path);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* create communication to process with a socket pair */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen prefix = t_strdup_printf("auth(%s): ", group->set->name);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen prefix = t_strdup_printf("master-auth(%s): ", group->set->name);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* move master communication handle to 0 */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* set stdout to /dev/null, so anything written into it gets ignored. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* move login communication handle to 3. do it last so we can be
534e41e436a7546f36f61e0dc49c0c191d850f6bPhil Carmody sure it's not closed afterwards. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i <= 3; i++)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* setup access environment */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen restrict_access_set_env(group->set->user, group->set->uid,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* set other environment */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("AUTH_PROCESS=", dec2str(getpid()), NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("MECHANISMS=", group->set->mechanisms, NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("REALMS=", group->set->realms, NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("DEFAULT_REALM=", group->set->default_realm, NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("USERDB=", group->set->userdb, NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen env_put(t_strconcat("PASSDB=", group->set->passdb, NULL));
00cc12d660b35bc955f97d30af660f3879b35a3cTimo Sirainen env_put(t_strconcat("USERNAME_CHARS=", group->set->username_chars, NULL));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (as = group->set->sockets, i = 1; as != NULL; as = as->next, i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen restrict_process_size(group->set->process_size, (unsigned int)-1);
030e247340315f4425d297a00b439a4df72bf70cPhil Carmody /* make sure we don't leak syslog fd, but do it last so that
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen any errors above will be logged */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* hide the path, it's ugly */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen argv[0] = strrchr(group->set->executable, '/');
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct auth_process *auth_process_find(unsigned int pid)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (group = process_groups; group != NULL; group = group->next) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (p = group->processes; p != NULL; p = p->next) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void auth_process_group_create(struct auth_settings *auth_set)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen strcmp(auth_set->sockets->type, "connect") == 0)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* create socket for listening auth requests from login */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen old_umask = umask(0117); /* we want 0660 mode for the socket */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_fatal("Can't listen in UNIX socket %s: %m", path);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* set correct permissions */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (chown(path, master_uid, auth_set->parent->login_gid) < 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_fatal("login: chown(%s, %s, %s) failed: %m",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void auth_process_group_destroy(struct auth_process_group *group)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (void)unlink(t_strconcat(group->set->parent->defaults->login_dir, "/",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_error("close(auth group %s) failed: %m", group->set->name);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void auth_process_groups_create(struct server_settings *server)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (; auth_set != NULL; auth_set = auth_set->next)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenauth_processes_start_missing(void *context __attr_unused__)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned int count;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* first time here, create the groups */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (group = process_groups; group != NULL; group = group->next) {