auth-process.c revision 657afb33796f8216c568ad813627da89970760be
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic unsigned int auth_tag;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct auth_process_group *process_groups;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void auth_process_destroy(struct auth_process *p);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid auth_process_request(struct auth_process *process, unsigned int login_pid,
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen ret = o_stream_send(process->output, str_data(str), str_len(str));
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen /* FIXME: well .. I'm not sure if it'd be better to
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen just block here. I don't think this condition should
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen happen often, so this could mean that the auth
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen process is stuck. Or that the computer is just
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen too heavily loaded. Possibility to block infinitely
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen is annoying though, so for now don't do it. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_warning("Auth process %s transmit buffer full, "
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen hash_insert(process->requests, POINTER_CAST(auth_tag), context);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenauth_process_input_user(struct auth_process *process, const char *args)
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen const char *const *list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int id;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* <id> <userid> [..] */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent corrupted USER line",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen id = (unsigned int)strtoul(list[0], NULL, 10);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_master_callback(list[1], list + 2, context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenauth_process_input_notfound(struct auth_process *process, const char *args)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int id;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenauth_process_input_spid(struct auth_process *process, const char *args)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen unsigned int pid;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server re-handshaking");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server said it's PID 0");
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (process->pid != 0 && process->pid != (pid_t)pid) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server sent invalid SPID "
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenauth_process_input_fail(struct auth_process *process, const char *args)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen unsigned int id;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* disconnected */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* buffer full */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("BUG: Auth process %s sent us more than %d "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* make sure the major version matches */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen i_error("Auth process %s not compatible with master "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "process (mixed old and new binaries?)",
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen while ((line = i_stream_next_line(process->input)) != NULL) {
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen ret = auth_process_input_user(process, line + 5);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen ret = auth_process_input_notfound(process, line + 9);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ret = auth_process_input_fail(process, line + 5);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ret = auth_process_input_spid(process, line + 5);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenauth_process_new(pid_t pid, int fd, struct auth_process_group *group)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->io = io_add(fd, IO_READ, auth_process_input, p);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->input = i_stream_create_file(fd, default_pool,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen p->requests = hash_create(default_pool, default_pool, 0, NULL, NULL);
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen handshake = t_strdup_printf("VERSION\t%u\t%u\n",
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen (void)o_stream_send_str(p->output, handshake);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic void auth_process_destroy(struct auth_process *p)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (!p->initialized && io_loop_is_running(ioloop) && !p->external) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("Auth process died too early - shutting down");
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen for (pos = &p->group->processes; *pos != NULL; pos = &(*pos)->next) {
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen if (*pos == p) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen path = t_strconcat(p->group->set->parent->defaults->login_dir,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainensocket_settings_env_put(const char *env_base, struct socket_settings *set)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen env_put(t_strdup_printf("%s=%s", env_base, set->path));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_MODE=%o", env_base, set->mode));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainenstatic int connect_auth_socket(struct auth_process_group *group,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen i_error("net_connect_unix(%s) failed: %m", path);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainenstatic int auth_process_socket_create(struct auth_settings *auth_set, pid_t pid)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen auth_set->name, pid == 0 ? NULL : dec2str(pid),
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen old_umask = umask(0117); /* we want 0660 mode for the socket */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen i_fatal("Can't listen in UNIX socket %s: %m", path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* set correct permissions */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (chown(path, master_uid, auth_set->parent->login_gid) < 0) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen i_fatal("login: chown(%s, %s, %s) failed: %m",
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainenstatic int create_auth_process(struct auth_process_group *group)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* see if this is a connect socket */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (as != NULL && strcmp(as->type, "connect") == 0)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return connect_auth_socket(group, as->master.path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* create communication to process with a socket pair */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen prefix = t_strdup_printf("auth(%s): ", group->set->name);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen prefix = t_strdup_printf("master-auth(%s): ", group->set->name);
4dd0cbd517dc5d1210956a7c3e9e1ae714451dd8Timo Sirainen /* move master communication handle to 0 */
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* set stdout to /dev/null, so anything written into it gets ignored. */
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* move login communication handle to 3. do it last so we can be
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen sure it's not closed afterwards. */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen listen_fd = group->listen_fd != -1 ? group->listen_fd :
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen auth_process_socket_create(group->set, getpid());
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen for (i = 0; i <= 3; i++)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* setup access environment */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen restrict_access_set_env(group->set->user, group->set->uid,
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen /* set other environment */
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen env_put(t_strconcat("MECHANISMS=", group->set->mechanisms, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("REALMS=", group->set->realms, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("DEFAULT_REALM=", group->set->default_realm, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("USERDB=", group->set->userdb, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("PASSDB=", group->set->passdb, NULL));
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen env_put(t_strconcat("USERNAME_CHARS=", group->set->username_chars, NULL));
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen env_put(t_strdup_printf("CACHE_SIZE=%u", group->set->cache_size));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen env_put(t_strdup_printf("CACHE_TTL=%u", group->set->cache_ttl));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen for (as = group->set->sockets, i = 1; as != NULL; as = as->next, i++) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen restrict_process_size(group->set->process_size, (unsigned int)-1);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* make sure we don't leak syslog fd, but do it last so that
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen any errors above will be logged */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen client_process_exec(group->set->executable, "");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstruct auth_process *auth_process_find(unsigned int pid)
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen for (group = process_groups; group != NULL; group = group->next) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen for (p = group->processes; p != NULL; p = p->next) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainenstatic void auth_process_group_create(struct auth_settings *auth_set)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen strcmp(auth_set->sockets->type, "connect") == 0)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* If we keep long running login processes, we want them to use
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen all the auth processes in round robin. this means we have to create
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen separate socket for all of them. So, group->listen_fd is only
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen used with login_process_per_connection. */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (auth_set->parent->defaults->login_process_per_connection)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->listen_fd = auth_process_socket_create(auth_set, 0);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic void auth_process_group_destroy(struct auth_process_group *group)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen path = t_strconcat(group->set->parent->defaults->login_dir, "/",
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic void auth_process_groups_create(struct server_settings *server)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen for (; auth_set != NULL; auth_set = auth_set->next)
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainenauth_processes_start_missing(void *context __attr_unused__)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen unsigned int count;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* first time here, create the groups */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen for (group = process_groups; group != NULL; group = group->next) {