int pr_ctrls_flush_response(pr_ctrls_t *ctrl) { /* Sanity check */ if (!ctrl) { errno = EINVAL; return -1; } /* Make sure the callback(s) added responses */ if (ctrl->ctrls_cb_resps) { if (pr_ctrls_send_msg(ctrl->ctrls_cl->cl_fd, ctrl->ctrls_cb_retval, ctrl->ctrls_cb_resps->nelts, (char **) ctrl->ctrls_cb_resps->elts) < 0) return -1; } return 0; }
int main(int argc, char *argv[]) { unsigned char verbose = FALSE; char **respargv = NULL; const char *cmdopts = "hs:v"; register int i = 0; char *socket_file = PR_RUN_DIR "/proftpd.sock"; int sockfd = -1, optc = 0, status = 0, respargc = 0; unsigned int reqargc = 0; pool *ctl_pool = NULL; array_header *reqargv = NULL; /* Make sure we were called with at least one argument. */ if (argc-1 < 1) { fprintf(stdout, "%s: missing required arguments\n", program); exit(1); } /* Set the POSIXLY_CORRECT environment variable, so that control handlers * can themselves have optional flags. */ if (putenv("POSIXLY_CORRECT=1") < 0) { fprintf(stderr, "%s: unable to set POSIXLY_CORRECT: %s\n", program, strerror(errno)); exit(1); } opterr = 0; while ((optc = getopt(argc, argv, cmdopts)) != -1) { switch (optc) { case 'h': usage(); return 0; case 's': if (*optarg != '/') { fprintf(stderr, "%s: alternate socket path must be an absolute " "path\n", program); return 1; } socket_file = optarg; break; case 'v': verbose = TRUE; break; case '?': fprintf(stdout, "%s: unknown option: %c\n", program, (char) optopt); break; } } signal(SIGPIPE, sig_pipe); /* Allocate some memory for proftpd objects. */ ctl_pool = make_sub_pool(NULL); reqargv = make_array(ctl_pool, 0, sizeof(char *)); /* Process the command-line args into an array_header. */ for (i = optind; i < argc; i++) { if (verbose) fprintf(stdout, "%s: adding \"%s\" to reqargv\n", program, argv[i]); *((char **) push_array(reqargv)) = pstrdup(ctl_pool, argv[i]); reqargc++; } /* Don't forget to NULL-terminate the array. */ *((char **) push_array(reqargv)) = NULL; /* Open a connection to the socket maintained by mod_ctrls. */ if (verbose) fprintf(stdout, "%s: contacting server using '%s'\n", program, socket_file); sockfd = pr_ctrls_connect(socket_file); if (sockfd < 0) { fprintf(stderr, "%s: error contacting server using '%s': %s\n", program, socket_file, strerror(errno)); exit(1); } if (verbose) fprintf(stdout, "%s: sending control request\n", program); if (pr_ctrls_send_msg(sockfd, 0, reqargc, (char **) reqargv->elts) < 0) { fprintf(stderr, "%s: error sending request: %s\n", program, strerror(errno)); exit(1); } /* Read and display the responses. */ if (verbose) fprintf(stdout, "%s: receiving control response\n", program); /* Manually set errno to this value, so that if an error (like a segfault) * occurs, the error string displayed to the user is more indicative of * the cause of the lack of responses. */ errno = EPERM; if ((respargc = pr_ctrls_recv_response(ctl_pool, sockfd, &status, &respargv)) < 0) { fprintf(stdout, "%s: error receiving response: %s\n", program, strerror(errno)); exit(1); } if (respargv != NULL) { for (i = 0; i < respargc; i++) fprintf(stdout, "%s: %s\n", program, respargv[i]); } else fprintf(stdout, "%s: no response from server\n", program); destroy_pool(ctl_pool); ctl_pool = NULL; return 0; }
static int ctrls_get_creds_basic(struct sockaddr_un *sock, int cl_fd, unsigned int max_age, uid_t *uid, gid_t *gid, pid_t *pid) { pid_t cl_pid = 0; char *tmp = NULL; time_t stale_time; struct stat st; /* Check the path -- hmmm... */ PRIVS_ROOT while (stat(sock->sun_path, &st) < 0) { int xerrno = errno; if (xerrno == EINTR) { pr_signals_handle(); continue; } PRIVS_RELINQUISH pr_trace_msg(trace_channel, 2, "error: unable to stat %s: %s", sock->sun_path, strerror(xerrno)); (void) close(cl_fd); errno = xerrno; return -1; } PRIVS_RELINQUISH /* Is it a socket? */ if (pr_ctrls_issock_unix(st.st_mode) < 0) { (void) close(cl_fd); errno = ENOTSOCK; return -1; } /* Are the perms _not_ rwx------? */ if (st.st_mode & (S_IRWXG|S_IRWXO) || ((st.st_mode & S_IRWXU) != PR_CTRLS_CL_MODE)) { pr_trace_msg(trace_channel, 3, "error: unable to accept connection: incorrect mode"); (void) close(cl_fd); errno = EPERM; return -1; } /* Is it new enough? */ stale_time = time(NULL) - max_age; if (st.st_atime < stale_time || st.st_ctime < stale_time || st.st_mtime < stale_time) { char *msg = "error: stale connection"; pr_trace_msg(trace_channel, 3, "unable to accept connection: stale connection"); /* Log the times being compared, to aid in debugging this situation. */ if (st.st_atime < stale_time) { time_t age = stale_time - st.st_atime; pr_trace_msg(trace_channel, 3, "last access time of '%s' is %lu secs old (must be less than %u secs)", sock->sun_path, (unsigned long) age, max_age); } if (st.st_ctime < stale_time) { time_t age = stale_time - st.st_ctime; pr_trace_msg(trace_channel, 3, "last change time of '%s' is %lu secs old (must be less than %u secs)", sock->sun_path, (unsigned long) age, max_age); } if (st.st_mtime < stale_time) { time_t age = stale_time - st.st_mtime; pr_trace_msg(trace_channel, 3, "last modified time of '%s' is %lu secs old (must be less than %u " "secs)", sock->sun_path, (unsigned long) age, max_age); } if (pr_ctrls_send_msg(cl_fd, -1, 1, &msg) < 0) { pr_trace_msg(trace_channel, 2, "error sending message: %s", strerror(errno)); } (void) close(cl_fd); errno = ETIMEDOUT; return -1; } /* Parse the PID out of the path */ tmp = sock->sun_path; tmp += strlen("/tmp/ftp.cl"); cl_pid = atol(tmp); /* Return the IDs of the caller */ if (uid) *uid = st.st_uid; if (gid) *gid = st.st_gid; if (pid) *pid = cl_pid; return 0; }