int twopence_sock_recv_buffer(twopence_sock_t *sock, twopence_buf_t *bp) { unsigned int count; int n; count = twopence_buf_tailroom(bp); if (count == 0) { twopence_debug("%s: no tailroom in buffer", __func__); errno = ENOBUFS; return -1; } #if 0 /* Testing: simulate serial pipe behavior - large packets get chopped * up into 4k chunks */ if (count > 4096) count = 4096; #endif n = read(sock->fd, twopence_buf_tail(bp), count); if (n > 0) twopence_buf_advance_tail(bp, n); else if (n < 0) twopence_debug("%s: recv() returns error: %m", __func__); return n; }
void twopence_sock_free(twopence_sock_t *sock) { twopence_debug("%s(%d)\n", __func__, sock->fd); if (sock->closeit && sock->fd >= 0) close(sock->fd); twopence_queue_destroy(&sock->xmit_queue); if (sock->recv_buf) twopence_buf_free(sock->recv_buf); free(sock); }
/* * Sockets in listen mode. */ int server_listen_doio(twopence_conn_pool_t *poll, twopence_conn_t *conn) { twopence_sock_t *sock; sock = twopence_conn_accept(conn); if (sock != NULL) { twopence_conn_t *new_conn = server_new_connection(sock, &server_ops); twopence_debug("Accepted incoming connection"); twopence_conn_set_keepalive(new_conn, -1); twopence_conn_pool_add_connection(poll, new_conn); } return 0; }
bool server_run_command_send(twopence_transaction_t *trans) { twopence_trans_channel_t *channel; int status; pid_t pid; bool pending_output; pending_output = false; if ((channel = twopence_transaction_find_source(trans, TWOPENCE_STDOUT)) != NULL && !twopence_transaction_channel_is_read_eof(channel)) pending_output = true; if ((channel = twopence_transaction_find_source(trans, TWOPENCE_STDERR)) != NULL && !twopence_transaction_channel_is_read_eof(channel)) pending_output = true; if (trans->pid) { pid = waitpid(trans->pid, &status, WNOHANG); if (pid > 0) { twopence_debug("%s: process exited, status=%u\n", twopence_transaction_describe(trans), status); twopence_transaction_close_sink(trans, 0); trans->status = status; trans->pid = 0; } } if (!trans->done && trans->pid == 0 && !pending_output) { int st = trans->status; if (WIFEXITED(st)) { twopence_transaction_send_major(trans, 0); twopence_transaction_send_minor(trans, WEXITSTATUS(st)); } else if (WIFSIGNALED(st)) { if (WTERMSIG(st) == SIGALRM) { twopence_transaction_send_timeout(trans); } else { twopence_transaction_fail2(trans, EFAULT, WTERMSIG(st)); } } else { twopence_transaction_fail2(trans, EFAULT, 2); } trans->done = true; } return true; }
static bool server_change_to_home(const struct passwd *user) { const char *homedir; if ((homedir = user->pw_dir) == NULL || homedir[0] != '/') { twopence_debug("user %s has a home directory of \"%s\", substituting \"/\"", user->pw_name, user->pw_dir); homedir = "/"; } if (chdir(homedir) < 0) { twopence_log_error("Cannot change to user %s's home directory: chdir(%s) failed: %m", user->pw_name, user->pw_dir); return false; } return true; }
/* * Open the TCP socket * * Returns the file descriptor if successful, or -1 if failed */ static twopence_sock_t * __twopence_tcp_open(struct twopence_pipe_target *pipe_handle) { struct twopence_tcp_target *handle = (struct twopence_tcp_target *) pipe_handle; char *copy, *hostname, *portname = NULL; struct addrinfo hints; struct addrinfo *ai_list, *ai; int socket_fd = -1; int res; copy = hostname = twopence_strdup(handle->server_spec); if (hostname[0] == '[') { /* Something like [::1] */ char *s; for (s = ++hostname; *s != ']'; ++s) { if (*s == '\0') { twopence_log_error("tcp: cannot parse \"%s\"", handle->server_spec); free(copy); return NULL; } } *s++ = '\0'; if (*s == ':') portname = ++s; /* Any other garbage is silently ignored for now */ } else if ((portname = strchr(hostname, ':')) != NULL) *portname++ = '\0'; if (portname == NULL) portname = TWOPENCE_TCP_PORT_DEFAULT_STR; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; res = getaddrinfo(hostname, portname, &hints, &ai_list); free(copy); copy = hostname = portname = NULL; if (res != 0) { twopence_log_error("tcp: cannot resolve \"%s\": %s", handle->server_spec, gai_strerror(res)); return NULL; } twopence_debug("trying to open connection to %s", handle->server_spec); for (ai = ai_list; ai && socket_fd < 0; ai = ai->ai_next) { socket_fd = socket(ai->ai_family, SOCK_STREAM, 0); if (socket_fd <= 0) break; // Open the connection if (connect(socket_fd, ai->ai_addr, ai->ai_addrlen) < 0) { /* Okay, this address didn't work. Try the next one */ close(socket_fd); socket_fd = -1; } } freeaddrinfo(ai_list); if (socket_fd <= 0) return NULL; /* Note, we do not pass O_NONBLOCK here, but we do set O_CLOEXEC */ return twopence_sock_new_flags(socket_fd, O_RDWR | O_CLOEXEC); }
int server_open_file_as(const char *username, const char *filename, unsigned int filemode, int oflags, int *status) { struct stat stb; struct saved_ids saved_ids; struct passwd *user; int fd; if (!(user = server_get_user(username, status))) { twopence_debug("Unknown user \"%s\"\n", username); return -1; } /* If the path is not absolute, interpret it relatively to the * user's home directory */ if (filename[0] != '/') { filename = server_build_path(user->pw_dir, filename); if (filename == NULL) { twopence_log_error("Unable to build path from user %s's home \"%s\" and relative name \"%s\"\n", username, user->pw_dir, filename); *status = ENAMETOOLONG; return false; } } twopence_debug("%s(user=%s, file=%s, flags=0%0)\n", __func__, username, filename, oflags); /* We may want to have the client specify the file mode as well */ if (!strcmp(username, "root")) { fd = open(filename, oflags, filemode); if (fd < 0) *status = errno; } else { if (!server_change_hats_temporarily(user, &saved_ids, status)) return -1; fd = open(filename, oflags, filemode); if (fd < 0) *status = errno; server_restore_privileges(&saved_ids); } if (fd < 0) return -1; if (fstat(fd, &stb) < 0) { *status = errno; twopence_log_error("failed to stat \"%s\": %m", filename); close(fd); return -1; } if (!S_ISREG(stb.st_mode)) { twopence_log_error("%s: not a regular file\n", filename); *status = EISDIR; close(fd); return -1; } if (oflags != O_RDONLY && fchmod(fd, filemode) < 0) { *status = errno; twopence_log_error("failed to change file mode \"%s\" to 0%o: %m", filename, filemode); close(fd); return -1; } return fd; }