auth-process.c revision 6ef7e31619edfaa17ed044b45861d106a86191ef
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/* Copyright (C) 2002 Timo Sirainen */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic unsigned int auth_tag;
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic void auth_process_destroy(struct auth_process *p);
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic int create_auth_worker(struct auth_process *process, int fd);
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid auth_process_request(struct auth_process *process, unsigned int login_pid,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = o_stream_send(process->output, str_data(str), str_len(str));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* FIXME: well .. I'm not sure if it'd be better to
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng just block here. I don't think this condition should
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng happen often, so this could mean that the auth
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng process is stuck. Or that the computer is just
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng too heavily loaded. Possibility to block infinitely
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng is annoying though, so for now don't do it. */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_warning("Auth process %s transmit buffer full, "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng hash_insert(process->requests, POINTER_CAST(auth_tag), context);
da14cebe459d3275048785f25bd869cb09b5307fEric Chengauth_process_input_user(struct auth_process *process, const char *args)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *const *list;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int id;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* <id> <userid> [..] */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Auth process %s sent corrupted USER line",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng context = hash_lookup(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Auth process %s sent unrequested reply with ID "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng auth_master_callback(list[1], list + 2, context);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng hash_remove(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Chengauth_process_input_notfound(struct auth_process *process, const char *args)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int id;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng context = hash_lookup(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Auth process %s sent unrequested reply with ID "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng hash_remove(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Chengauth_process_input_spid(struct auth_process *process, const char *args)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int pid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Authentication server re-handshaking");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Authentication server said it's PID 0");
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (process->pid != 0 && process->pid != (pid_t)pid) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Authentication server sent invalid SPID "
da14cebe459d3275048785f25bd869cb09b5307fEric Chengauth_process_input_fail(struct auth_process *process, const char *args)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng const char *error;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng unsigned int id;
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey id = (unsigned int)strtoul(args, NULL, 10);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng context = hash_lookup(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Auth process %s sent unrequested reply with ID "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng hash_remove(process->requests, POINTER_CAST(id));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* disconnected */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* buffer full */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("BUG: Auth process %s sent us more than %d "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* make sure the major version matches */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng i_error("Auth process %s not compatible with master "
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "process (mixed old and new binaries?)",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng while ((line = i_stream_next_line(process->input)) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ret = auth_process_input_user(process, line + 5);
2d40c3b296fd82c4f1f14694b16f9b39d9fa0e4aPrakash Jalan ret = auth_process_input_notfound(process, line + 9);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = auth_process_input_fail(process, line + 5);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ret = auth_process_input_spid(process, line + 5);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer fd = net_accept(p->worker_listen_fd, NULL, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerauth_process_new(pid_t pid, int fd, struct auth_process_group *group)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_AUTH);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer p->io = io_add(fd, IO_READ, auth_process_input, p);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer p->input = i_stream_create_file(fd, default_pool,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer p->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer p->requests = hash_create(default_pool, default_pool, 0, NULL, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer group->set->chroot != NULL ? group->set->chroot :
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer unix_socket_create(path, 0600, group->set->uid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("Couldn't create auth worker listener");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer p->worker_io = io_add(p->worker_listen_fd, IO_READ,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer handshake = t_strdup_printf("VERSION\t%u\t%u\n",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer (void)o_stream_send_str(p->output, handshake);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void auth_process_destroy(struct auth_process *p)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!p->initialized && io_loop_is_running(ioloop) && !p->external) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_error("Auth process died too early - shutting down");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (pos = &p->group->processes; *pos != NULL; pos = &(*pos)->next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyersocket_settings_env_put(const char *env_base, struct socket_settings *set)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("%s=%s", env_base, set->path));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("%s_MODE=%o", env_base, set->mode));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic int connect_auth_socket(struct auth_process_group *group,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_error("net_connect_unix(%s) failed: %m", path);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void auth_set_environment(struct auth_settings *set)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* setup access environment */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer restrict_access_set_env(set->user, set->uid, set->gid, set->chroot,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* set other environment */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("AUTH_NAME=", set->name, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("MECHANISMS=", set->mechanisms, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("REALMS=", set->realms, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("DEFAULT_REALM=", set->default_realm, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("USERNAME_CHARS=", set->username_chars, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("CACHE_SIZE=%u", set->cache_size));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("CACHE_TTL=%u", set->cache_ttl));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (ap = set->passdbs, i = 1; ap != NULL; ap = ap->next, i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("PASSDB_%u_DRIVER=%s", i, ap->driver));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("PASSDB_%u_DENY=1", i));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (au = set->userdbs, i = 1; au != NULL; au = au->next, i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("USERDB_%u_DRIVER=%s", i, au->driver));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (as = set->sockets, i = 1; as != NULL; as = as->next, i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* Environment used by Kerberos 5 library directly */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer restrict_process_size(set->process_size, (unsigned int)-1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic int create_auth_process(struct auth_process_group *group)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* see if this is a connect socket */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (as != NULL && strcmp(as->type, "connect") == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return connect_auth_socket(group, as->master.path);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* create communication to process with a socket pair */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer prefix = t_strdup_printf("auth(%s): ", group->set->name);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer prefix = t_strdup_printf("master-auth(%s): ", group->set->name);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* move master communication handle to 0 */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* set stdout to /dev/null, so anything written into it gets ignored. */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i <= 2; i++)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("AUTH_WORKER_PATH=%s/auth-worker.%s",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer env_put(t_strdup_printf("AUTH_WORKER_MAX_COUNT=%u",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* make sure we don't leak syslog fd, but do it last so that
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer any errors above will be logged */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic int create_auth_worker(struct auth_process *process, int fd)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_AUTH_WORKER);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer prefix = t_strdup_printf("auth-worker(%s): ",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer prefix = t_strdup_printf("master-auth-worker(%s): ",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* set stdin and stdout to /dev/null, so anything written into it
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer gets ignored. */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i <= 2; i++)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* make sure we don't leak syslog fd, but do it last so that
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer any errors above will be logged */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer executable = t_strconcat(process->group->set->executable, " -w", NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstruct auth_process *auth_process_find(unsigned int pid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (group = process_groups; group != NULL; group = group->next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (p = group->processes; p != NULL; p = p->next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void auth_process_group_create(struct auth_settings *auth_set)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer strcmp(auth_set->sockets->type, "connect") == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer group->listen_fd = unix_socket_create(path, 0660, master_uid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer i_fatal("Couldn't create auth process listener");
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void auth_process_group_destroy(struct auth_process_group *group)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer path = t_strconcat(group->set->parent->defaults->login_dir, "/",
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void auth_process_groups_create(struct server_settings *server)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (; auth_set != NULL; auth_set = auth_set->next)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerauth_processes_start_missing(void *context __attr_unused__)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer unsigned int count;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* first time here, create the groups */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (group = process_groups; group != NULL; group = group->next) {