static void exec_child(struct master_service_connection *conn, const char *const *args) { unsigned int i, socket_count; if (dup2(conn->fd, STDIN_FILENO) < 0) i_fatal("dup2() failed: %m"); if (dup2(conn->fd, STDOUT_FILENO) < 0) i_fatal("dup2() failed: %m"); /* close all fds */ socket_count = master_service_get_socket_count(master_service); for (i = 0; i < socket_count; i++) { if (close(MASTER_LISTEN_FD_FIRST + i) < 0) i_error("close(listener) failed: %m"); } if (close(MASTER_STATUS_FD) < 0) i_error("close(status) failed: %m"); if (close(conn->fd) < 0) i_error("close(conn->fd) failed: %m"); for (; *args != NULL; args++) array_append(&exec_args, args, 1); array_append_zero(&exec_args); env_clean(); args = array_idx(&exec_args, 0); execvp_const(args[0], args); }
static void run_cmd(struct dsync_cmd_context *ctx, const char *const *args) { int fd_in[2], fd_out[2], fd_err[2]; if (pipe(fd_in) < 0 || pipe(fd_out) < 0 || pipe(fd_err) < 0) i_fatal("pipe() failed: %m"); ctx->remote_pid = fork(); switch (ctx->remote_pid) { case -1: i_fatal("fork() failed: %m"); case 0: /* child, which will execute the proxy server. stdin/stdout goes to pipes which we'll pass to proxy client. */ if (dup2(fd_in[0], STDIN_FILENO) < 0 || dup2(fd_out[1], STDOUT_FILENO) < 0 || dup2(fd_err[1], STDERR_FILENO) < 0) i_fatal("dup2() failed: %m"); i_close_fd(&fd_in[0]); i_close_fd(&fd_in[1]); i_close_fd(&fd_out[0]); i_close_fd(&fd_out[1]); i_close_fd(&fd_err[0]); i_close_fd(&fd_err[1]); execvp_const(args[0], args); default: /* parent */ break; } i_close_fd(&fd_in[0]); i_close_fd(&fd_out[1]); i_close_fd(&fd_err[1]); ctx->fd_in = fd_out[0]; ctx->fd_out = fd_in[1]; ctx->fd_err = fd_err[0]; if (ctx->remote_user_prefix) { const char *prefix = t_strdup_printf("%s\n", ctx->ctx.cur_username); if (write_full(ctx->fd_out, prefix, strlen(prefix)) < 0) i_fatal("write(remote out) failed: %m"); } fd_set_nonblock(ctx->fd_err, TRUE); ctx->err_stream = i_stream_create_fd(ctx->fd_err, IO_BLOCK_SIZE, FALSE); i_stream_set_return_partial_line(ctx->err_stream, TRUE); }
static void client_connected(struct master_service_connection *conn) { enum mail_storage_service_flags flags = MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS; string_t *instr, *keys; const char **args, *key, *value, *error, *version_line, *data_line; struct mail_storage_service_ctx *service_ctx; struct mail_storage_service_input input; struct mail_storage_service_user *user; char buf[1024]; unsigned int i, socket_count; int fd = -1; ssize_t ret; alarm(SCRIPT_LOGIN_READ_TIMEOUT_SECS); net_set_nonblock(conn->fd, FALSE); instr = t_str_new(1024); ret = fd_read(conn->fd, buf, sizeof(buf), &fd); while (ret > 0) { str_append_n(instr, buf, ret); if (buf[ret-1] == '\n' && strchr(str_c(instr), '\n')[1] != '\0') { str_truncate(instr, str_len(instr)-1); break; } ret = read(conn->fd, buf, sizeof(buf)); } version_line = str_c(instr); data_line = strchr(version_line, '\n'); if (data_line != NULL) version_line = t_strdup_until(version_line, data_line++); else version_line = NULL; if (ret > 0 || version_line != NULL) { if (version_line == NULL || !version_string_verify(version_line, "script-login", SCRIPT_LOGIN_PROTOCOL_VERSION_MAJOR)) { i_fatal("Client not compatible with this binary " "(connecting to wrong socket?)"); } } if (ret <= 0) { if (ret < 0) i_fatal("read() failed: %m"); else i_fatal("read() failed: disconnected"); } if (fd == -1) i_fatal("client fd not received"); alarm(0); /* put everything to environment */ env_clean(); keys = t_str_new(256); args = t_strsplit_tab(data_line); if (str_array_length(args) < 3) i_fatal("Missing input fields"); i = 0; memset(&input, 0, sizeof(input)); input.module = "mail"; /* need to get mail_uid, mail_gid */ input.service = "script-login"; (void)net_addr2ip(args[i++], &input.local_ip); (void)net_addr2ip(args[i++], &input.remote_ip); input.username = args[i++]; input.userdb_fields = args + i; env_put(t_strconcat("LOCAL_IP=", net_ip2addr(&input.local_ip), NULL)); env_put(t_strconcat("IP=", net_ip2addr(&input.remote_ip), NULL)); env_put(t_strconcat("USER="******"%s ", key); } } env_put(t_strconcat(ENV_USERDB_KEYS"=", str_c(keys), NULL)); master_service_init_log(master_service, t_strdup_printf("script-login(%s): ", input.username)); if (drop_to_userdb_privileges) { service_ctx = mail_storage_service_init(master_service, NULL, flags); if (mail_storage_service_lookup(service_ctx, &input, &user, &error) <= 0) i_fatal("%s", error); mail_storage_service_restrict_setenv(service_ctx, user); /* we can't exec anything in a chroot */ env_remove("RESTRICT_CHROOT"); restrict_access_by_env(getenv("HOME"), TRUE); } if (dup2(fd, STDIN_FILENO) < 0) i_fatal("dup2() failed: %m"); if (dup2(fd, STDOUT_FILENO) < 0) i_fatal("dup2() failed: %m"); if (close(fd) < 0) i_fatal("close() failed: %m"); if (conn->fd != SCRIPT_COMM_FD) { if (dup2(conn->fd, SCRIPT_COMM_FD) < 0) i_fatal("dup2() failed: %m"); if (close(conn->fd) < 0) i_fatal("close() failed: %m"); } /* close all listener sockets */ socket_count = master_service_get_socket_count(master_service); for (i = 0; i < socket_count; i++) { if (close(MASTER_LISTEN_FD_FIRST + i) < 0) i_error("close(listener) failed: %m"); } if (close(MASTER_STATUS_FD) < 0) i_error("close(status) failed: %m"); execvp_const(exec_args[0], exec_args); }
static void exec_child (const char *bin_path, const char *const *args, const char *const *envs, int in_fd, int out_fd, int *extra_fds, bool drop_stderr) { ARRAY_TYPE(const_string) exec_args; /* Setup stdin/stdout */ if ( in_fd < 0 ) { in_fd = open("/dev/null", O_RDONLY); if ( in_fd == -1 ) i_fatal("open(/dev/null) failed: %m"); } if ( out_fd < 0 ) { out_fd = open("/dev/null", O_WRONLY); if ( out_fd == -1 ) i_fatal("open(/dev/null) failed: %m"); } if ( dup2(in_fd, STDIN_FILENO) < 0 ) i_fatal("dup2(stdin) failed: %m"); if ( dup2(out_fd, STDOUT_FILENO) < 0 ) i_fatal("dup2(stdout) failed: %m"); if ( close(in_fd) < 0 ) i_error("close(in_fd) failed: %m"); if ( (out_fd != in_fd) && close(out_fd) < 0 ) i_error("close(out_fd) failed: %m"); /* Drop stderr if requested */ if ( drop_stderr ) { int err_fd = open("/dev/null", O_WRONLY); if ( err_fd == -1 ) i_fatal("open(/dev/null) failed: %m"); if ( dup2(err_fd, STDERR_FILENO) < 0 ) i_fatal("dup2(stderr) failed: %m"); if ( close(err_fd) < 0 ) i_error("close(err_fd) failed: %m"); } /* Setup extra fds */ if ( extra_fds != NULL ) { for (; *extra_fds != -1; extra_fds += 2 ) { if ( dup2(extra_fds[0], extra_fds[1]) < 0 ) i_fatal("dup2(extra_fd=%d) failed: %m", extra_fds[1]); if ( close(extra_fds[0]) < 0 ) i_error("close(extra_fd=%d) failed: %m", extra_fds[1]); } } /* Compose argv */ t_array_init(&exec_args, 16); array_append(&exec_args, &bin_path, 1); if ( args != NULL ) { for (; *args != NULL; args++) array_append(&exec_args, args, 1); } (void)array_append_space(&exec_args); /* Setup environment */ env_clean(); if ( envs != NULL ) { for (; *envs != NULL; envs++) env_put(*envs); } /* Execute */ args = array_idx(&exec_args, 0); execvp_const(args[0], args); }