From bf489daffc4902db3a9eb95d485fd867ac1ea524 Mon Sep 17 00:00:00 2001 From: Nate Straz Date: Tue, 13 Sep 2005 16:01:28 +0000 Subject: Flatten the qarsh tree. --- Makefile | 44 +++ btime.c | 111 +++++++ btime.h | 10 + btime/Makefile | 48 --- btime/btime.c | 111 ------- btime/btime.h | 10 - btime/btime_int.h | 12 - btime/btimec.c | 28 -- btime/btimed.c | 271 ---------------- btime_int.h | 12 + btimec.c | 28 ++ btimed.c | 271 ++++++++++++++++ qacp.c | 382 +++++++++++++++++++++++ qarsh.c | 365 ++++++++++++++++++++++ qarsh/Makefile | 34 --- qarsh/qacp.c | 382 ----------------------- qarsh/qarsh.c | 365 ---------------------- qarsh/qarsh_packet.c | 850 --------------------------------------------------- qarsh/qarsh_packet.h | 129 -------- qarsh/qarshd.c | 315 ------------------- qarsh/sockutil.c | 119 -------- qarsh/sockutil.h | 8 - qarsh_packet.c | 850 +++++++++++++++++++++++++++++++++++++++++++++++++++ qarsh_packet.h | 129 ++++++++ qarshd.c | 315 +++++++++++++++++++ sockutil.c | 119 ++++++++ sockutil.h | 8 + 27 files changed, 2644 insertions(+), 2682 deletions(-) create mode 100644 Makefile create mode 100644 btime.c create mode 100644 btime.h delete mode 100644 btime/Makefile delete mode 100644 btime/btime.c delete mode 100644 btime/btime.h delete mode 100644 btime/btime_int.h delete mode 100644 btime/btimec.c delete mode 100644 btime/btimed.c create mode 100644 btime_int.h create mode 100644 btimec.c create mode 100644 btimed.c create mode 100644 qacp.c create mode 100644 qarsh.c delete mode 100644 qarsh/Makefile delete mode 100644 qarsh/qacp.c delete mode 100644 qarsh/qarsh.c delete mode 100644 qarsh/qarsh_packet.c delete mode 100644 qarsh/qarsh_packet.h delete mode 100644 qarsh/qarshd.c delete mode 100644 qarsh/sockutil.c delete mode 100644 qarsh/sockutil.h create mode 100644 qarsh_packet.c create mode 100644 qarsh_packet.h create mode 100644 qarshd.c create mode 100644 sockutil.c create mode 100644 sockutil.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..55b6c97 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ + +.PHONY: clean clobber uninstall + +CFLAGS := -Wall -g -I/usr/include/libxml2 +LOADLIBES := -lxml2 + +COMMON := qarsh_packet.c sockutil.c + +all: qarshd qarsh qacp btimed btimec + +qarshd: qarshd.c $(COMMON) +qarsh: qarsh.c $(COMMON) +qacp: qacp.c $(COMMON) +btimed: btimed.c +btimec: btimec.c btime.c + +install: qarsh qarshd + @echo Installing qarsh daemon and client + install -d ${STSDIR}/bin/ + install qacp ${STSDIR}/bin + install qarsh ${STSDIR}/bin + install qarshd ${STSDIR}/bin + + @echo "Installing btime deamon and test client" + @install -d ${STSDIR}/bin/ + @install btimed ${STSDIR}/bin + @install btimec ${STSDIR}/bin + +uninstall: + ${UNINSTALL} qacp ${STSDIR}/bin + ${UNINSTALL} qarsh ${STSDIR}/bin + ${UNINSTALL} qarshd ${STSDIR}/bin + ${UNINSTALL} btimed ${STSDIR}/bin + ${UNINSTALL} btimec ${STSDIR}/bin + +clean: + /bin/rm -f *.o + +clobber: + /bin/rm -f qacp + /bin/rm -f qarsh + /bin/rm -f qarshd + /bin/rm -f btimec + /bin/rm -f btimed diff --git a/btime.c b/btime.c new file mode 100644 index 0000000..f22c08b --- /dev/null +++ b/btime.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "btime_int.h" + +/* + * btime -- + * + * Return the boot time of a remote host if that host is running the + * btimed deamon. + * + * Returns: + * btime, or 0 on failure. + */ + +unsigned int +btime(const char *host) +{ + int sd; + char msg[BTIME_MSGLEN]; + struct sockaddr_in serv_addr; + struct sockaddr_in my_addr; + int serv_addr_len; + struct hostent *hostent; + in_addr_t inaddr; + unsigned int btime; + ssize_t nbytes; + int retry; + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + fprintf(stderr, "Could not create socket: %s\n", + strerror(errno)); + return 0; + } + + memset(&serv_addr, 0, sizeof serv_addr); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(BTIME_PORT); + + if ((inaddr = inet_addr(host)) != INADDR_NONE) { + memcpy(&serv_addr.sin_addr, &inaddr, sizeof inaddr); + } else { + if ((hostent = gethostbyname(host)) == NULL) { + return 0; + } + + memcpy(&serv_addr.sin_addr, hostent->h_addr, hostent->h_length); + } + + memset(&my_addr, 0, sizeof my_addr); + my_addr.sin_family = AF_INET; + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + my_addr.sin_port = htons(0); + if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + fprintf(stderr, "Could not bind to local address: %s\n", + strerror(errno)); + return 0; + } + + memset(msg, 0, BTIME_MSGLEN); + for (retry = 0; retry < MAX_RETRY; retry++) { + serv_addr_len = sizeof serv_addr; + if ((nbytes = sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) { + if (errno == EAGAIN) { + usleep(retry * 100); + } else { + /* Non EAGAIN error... */ + break; + } + } else { + break; + } + } + + + memset(msg, 0, BTIME_MSGLEN); + for (retry = 0; retry < MAX_RETRY; retry++) { + serv_addr_len = sizeof serv_addr; + if ((nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&serv_addr, &serv_addr_len)) < 0) { + if (errno == EAGAIN) { + usleep(retry * 100); + } else { + /* Non EAGAIN error... */ + break; + } + } else { + break; + } + } + + if (nbytes == 0) { + btime = 0; + } else { + btime = strtoul(msg, (char **)NULL, 10); + } + + close(sd); + + return btime; +} diff --git a/btime.h b/btime.h new file mode 100644 index 0000000..41d3e39 --- /dev/null +++ b/btime.h @@ -0,0 +1,10 @@ +/* + * btime.h -- + */ + +#ifndef __BTIME_H +#define __BTIME_H + +extern unsigned int btime(const char *host); + +#endif /* __BTIME_H */ diff --git a/btime/Makefile b/btime/Makefile deleted file mode 100644 index 6a2a454..0000000 --- a/btime/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -include ../../make/defines.mk - -.PHONY: clean clobber uninstall - -CC = gcc -AR = ar -#CFLAGS += -g - -all: libbtime.a btimed btimec - -btimed: btimed.c btime_int.h - $(CC) $(CFLAGS) -o btimed btimed.c - -btimec: btimec.c libbtime.a - $(CC) $(CFLAGS) -L. -o btimec btimec.c -lbtime - -libbtime.a: btime.c btime_int.h - $(CC) $(CFLAGS) -c btime.c - $(AR) -rc libbtime.a btime.o - -install: btimed btimec libbtime.a - @echo "Installing btime deamon and test client" - @install -d ${STSDIR}/bin/ - @install btimed ${STSDIR}/bin - @install btimec ${STSDIR}/bin - - @echo "Installing btime library" - @install -d ${STSDIR}/lib/ - @install libbtime.a ${STSDIR}/lib - - @echo "Installing btime header" - @install -d ${STSDIR}/include/ - @install btime.h ${STSDIR}/include - - -uninstall: - ${UNINSTALL} btimed ${STSDIR}/bin - ${UNINSTALL} btimec ${STSDIR}/bin - - -clean: - /bin/rm -f *.o - -clobber: - /bin/rm -f btimec - /bin/rm -f btimed - /bin/rm -f *.a *.o - diff --git a/btime/btime.c b/btime/btime.c deleted file mode 100644 index f22c08b..0000000 --- a/btime/btime.c +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "btime_int.h" - -/* - * btime -- - * - * Return the boot time of a remote host if that host is running the - * btimed deamon. - * - * Returns: - * btime, or 0 on failure. - */ - -unsigned int -btime(const char *host) -{ - int sd; - char msg[BTIME_MSGLEN]; - struct sockaddr_in serv_addr; - struct sockaddr_in my_addr; - int serv_addr_len; - struct hostent *hostent; - in_addr_t inaddr; - unsigned int btime; - ssize_t nbytes; - int retry; - - if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "Could not create socket: %s\n", - strerror(errno)); - return 0; - } - - memset(&serv_addr, 0, sizeof serv_addr); - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(BTIME_PORT); - - if ((inaddr = inet_addr(host)) != INADDR_NONE) { - memcpy(&serv_addr.sin_addr, &inaddr, sizeof inaddr); - } else { - if ((hostent = gethostbyname(host)) == NULL) { - return 0; - } - - memcpy(&serv_addr.sin_addr, hostent->h_addr, hostent->h_length); - } - - memset(&my_addr, 0, sizeof my_addr); - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - my_addr.sin_port = htons(0); - if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { - fprintf(stderr, "Could not bind to local address: %s\n", - strerror(errno)); - return 0; - } - - memset(msg, 0, BTIME_MSGLEN); - for (retry = 0; retry < MAX_RETRY; retry++) { - serv_addr_len = sizeof serv_addr; - if ((nbytes = sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, - (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) { - if (errno == EAGAIN) { - usleep(retry * 100); - } else { - /* Non EAGAIN error... */ - break; - } - } else { - break; - } - } - - - memset(msg, 0, BTIME_MSGLEN); - for (retry = 0; retry < MAX_RETRY; retry++) { - serv_addr_len = sizeof serv_addr; - if ((nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, - (struct sockaddr *)&serv_addr, &serv_addr_len)) < 0) { - if (errno == EAGAIN) { - usleep(retry * 100); - } else { - /* Non EAGAIN error... */ - break; - } - } else { - break; - } - } - - if (nbytes == 0) { - btime = 0; - } else { - btime = strtoul(msg, (char **)NULL, 10); - } - - close(sd); - - return btime; -} diff --git a/btime/btime.h b/btime/btime.h deleted file mode 100644 index 41d3e39..0000000 --- a/btime/btime.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * btime.h -- - */ - -#ifndef __BTIME_H -#define __BTIME_H - -extern unsigned int btime(const char *host); - -#endif /* __BTIME_H */ diff --git a/btime/btime_int.h b/btime/btime_int.h deleted file mode 100644 index b2cafcd..0000000 --- a/btime/btime_int.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * btime_int.h -- - */ - -#ifndef __BTIME_INT_H -#define __BTIME_INT_H - -#define BTIME_PORT 23456 -#define BTIME_MSGLEN 128 -#define MAX_RETRY 5 - -#endif /* __BTIME_INT_H */ diff --git a/btime/btimec.c b/btime/btimec.c deleted file mode 100644 index 02c29bc..0000000 --- a/btime/btimec.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * btimec.c -- - * - * Example program for libbtime - */ - -#include -#include - -#include "btime.h" - -int -main(int argc, char **argv) -{ - unsigned int bt; - char *btimedhost; - - if (argc != 2) { - fprintf(stderr, "USAGE: %s \n", argv[0]); - exit(2); - } - - btimedhost = argv[1]; - bt = btime(btimedhost); - printf("%s: %u\n", btimedhost, bt); - - exit(0); -} diff --git a/btime/btimed.c b/btime/btimed.c deleted file mode 100644 index 259c8aa..0000000 --- a/btime/btimed.c +++ /dev/null @@ -1,271 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "btime_int.h" - -static void (*btimed_error)(int level, const char *fmt, ...); - -static void btimed(void); -static unsigned int get_btime(void); -static int daemon_init(void); -static void btimed_perror(int level, const char *fmt, ...); -static void sigchld_hdlr(int sig); -static void usage(const char *progname); - - -int -main(int argc, char **argv) -{ - struct sigaction sa; - int debug = 0; - int c; - - while ((c = getopt(argc, argv, "hd")) != -1) { - switch (c) { - case 'd': - debug = 1; - break; - case 'h': - case '?': - default: - usage(argv[0]); - exit(2); - } - } - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = sigchld_hdlr; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - sigaction(SIGCHLD, &sa, NULL); - - if (debug) { - btimed_error = btimed_perror; - } else { - btimed_error = syslog; - daemon_init(); - } - - btimed(); - - return 0; -} - - -/* - *--------------------------------------------------------------------------- - * - * btimed -- - * - * The main loop of the deamon. It listens on its well know port for - * messages, responds to the request via a child process. - * - * Returns: - * Never returns. - * - * Side effects: - * Child processes are created. - *--------------------------------------------------------------------------- - */ - -static void -btimed(void) -{ - int sd; - char msg[BTIME_MSGLEN]; - struct sockaddr_in cli_addr; - int cli_addr_len; - struct sockaddr_in my_addr; - pid_t pid; - ssize_t nbytes; - - if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - btimed_error(LOG_ERR, "Could not create socket: %s\n", - strerror(errno)); - exit(1); - } - - memset(&my_addr, 0, sizeof my_addr); - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - my_addr.sin_port = htons(BTIME_PORT); - if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { - btimed_error(LOG_ERR, "Could not bind to local address: %s\n", - strerror(errno)); - exit(1); - } - - for (;;) { - memset(&cli_addr, 0, sizeof cli_addr); - cli_addr_len = sizeof cli_addr; - nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_WAITALL, - (struct sockaddr *)&cli_addr, &cli_addr_len); - - if ((pid = fork()) < 0) { - btimed_error(LOG_ERR, "Could not fork(): %s\n", strerror(errno)); - exit(1); - } - - if (pid == 0) { - memset(msg, 0, BTIME_MSGLEN); - sprintf(msg, "%u\n", get_btime()); - sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, - (struct sockaddr *)&cli_addr, cli_addr_len); - - exit(0); - } - } - - close(sd); -} - - - -/* - *--------------------------------------------------------------------------- - * - * get_btime -- - * - * Return machine's boot time. - * - * Returns: - * 0 on failure - * non-zero on success. - * - *--------------------------------------------------------------------------- - */ - -static unsigned int -get_btime(void) -{ - FILE *statf; - char line[1024]; - unsigned int btime = 0; - - if ((statf = fopen("/proc/stat", "r")) == NULL) { - btimed_error(LOG_ERR, "/proc/stat open failure: %s\n", - strerror(errno)); - exit(1); - } - - while (fgets(line, 1024, statf) != NULL) { - if (strstr(line, "btime") != NULL) { - sscanf(line, "%*s%u", &btime); - } - - } - - fclose(statf); - - return btime; -} - - -/* - *--------------------------------------------------------------------------- - * - * daemon_init -- - * - * Set up a basic daemon environment - * - * Returns: - * 0 on success - * non-zero on failure. - * - * Side effects: - * All fds are closed and process is now a session leader. - * - *--------------------------------------------------------------------------- - */ - -static int -daemon_init(void) -{ - pid_t pid; - int fd; - int maxfd = sysconf(_SC_OPEN_MAX); - - if ((pid = fork()) < 0) { - return(-1); - } else if (pid != 0) { - exit(0); /* Exit in parent */ - } - - /* - * Child sets up daemon environment - */ - - setsid(); /* Become session leader */ - chdir("/"); - umask(0); - for (fd = 0; fd < maxfd; fd++) { - close(fd); - } - errno = 0; /* probably set to EBADFD from above loop, reset */ - - openlog("btimed", LOG_PID, LOG_USER); - - return 0; -} - - -/* - *--------------------------------------------------------------------------- - * - * btimed_perror -- - * - * Print error messages to stderr, level is not used, it is there - * to have the same calling args as syslog(3) so we can use either - * based on debug level. - * - * Returns: - * NA - * - * Side effects: - * None - *--------------------------------------------------------------------------- - */ - -static void -btimed_perror(int level, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - - -static void -sigchld_hdlr(int sig) -{ - int status; - - wait(&status); - return; -} - - -static void -usage(const char *progname) -{ - fprintf(stderr, "Usage: %s [OPTION]...\n" - "-h\tPrint this help and exit.\n" - "-d\tDon't daemonize, send output to stderr.\n", - progname); - - return; -} diff --git a/btime_int.h b/btime_int.h new file mode 100644 index 0000000..b2cafcd --- /dev/null +++ b/btime_int.h @@ -0,0 +1,12 @@ +/* + * btime_int.h -- + */ + +#ifndef __BTIME_INT_H +#define __BTIME_INT_H + +#define BTIME_PORT 23456 +#define BTIME_MSGLEN 128 +#define MAX_RETRY 5 + +#endif /* __BTIME_INT_H */ diff --git a/btimec.c b/btimec.c new file mode 100644 index 0000000..02c29bc --- /dev/null +++ b/btimec.c @@ -0,0 +1,28 @@ +/* + * btimec.c -- + * + * Example program for libbtime + */ + +#include +#include + +#include "btime.h" + +int +main(int argc, char **argv) +{ + unsigned int bt; + char *btimedhost; + + if (argc != 2) { + fprintf(stderr, "USAGE: %s \n", argv[0]); + exit(2); + } + + btimedhost = argv[1]; + bt = btime(btimedhost); + printf("%s: %u\n", btimedhost, bt); + + exit(0); +} diff --git a/btimed.c b/btimed.c new file mode 100644 index 0000000..259c8aa --- /dev/null +++ b/btimed.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "btime_int.h" + +static void (*btimed_error)(int level, const char *fmt, ...); + +static void btimed(void); +static unsigned int get_btime(void); +static int daemon_init(void); +static void btimed_perror(int level, const char *fmt, ...); +static void sigchld_hdlr(int sig); +static void usage(const char *progname); + + +int +main(int argc, char **argv) +{ + struct sigaction sa; + int debug = 0; + int c; + + while ((c = getopt(argc, argv, "hd")) != -1) { + switch (c) { + case 'd': + debug = 1; + break; + case 'h': + case '?': + default: + usage(argv[0]); + exit(2); + } + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigchld_hdlr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + sigaction(SIGCHLD, &sa, NULL); + + if (debug) { + btimed_error = btimed_perror; + } else { + btimed_error = syslog; + daemon_init(); + } + + btimed(); + + return 0; +} + + +/* + *--------------------------------------------------------------------------- + * + * btimed -- + * + * The main loop of the deamon. It listens on its well know port for + * messages, responds to the request via a child process. + * + * Returns: + * Never returns. + * + * Side effects: + * Child processes are created. + *--------------------------------------------------------------------------- + */ + +static void +btimed(void) +{ + int sd; + char msg[BTIME_MSGLEN]; + struct sockaddr_in cli_addr; + int cli_addr_len; + struct sockaddr_in my_addr; + pid_t pid; + ssize_t nbytes; + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + btimed_error(LOG_ERR, "Could not create socket: %s\n", + strerror(errno)); + exit(1); + } + + memset(&my_addr, 0, sizeof my_addr); + my_addr.sin_family = AF_INET; + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + my_addr.sin_port = htons(BTIME_PORT); + if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + btimed_error(LOG_ERR, "Could not bind to local address: %s\n", + strerror(errno)); + exit(1); + } + + for (;;) { + memset(&cli_addr, 0, sizeof cli_addr); + cli_addr_len = sizeof cli_addr; + nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_WAITALL, + (struct sockaddr *)&cli_addr, &cli_addr_len); + + if ((pid = fork()) < 0) { + btimed_error(LOG_ERR, "Could not fork(): %s\n", strerror(errno)); + exit(1); + } + + if (pid == 0) { + memset(msg, 0, BTIME_MSGLEN); + sprintf(msg, "%u\n", get_btime()); + sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&cli_addr, cli_addr_len); + + exit(0); + } + } + + close(sd); +} + + + +/* + *--------------------------------------------------------------------------- + * + * get_btime -- + * + * Return machine's boot time. + * + * Returns: + * 0 on failure + * non-zero on success. + * + *--------------------------------------------------------------------------- + */ + +static unsigned int +get_btime(void) +{ + FILE *statf; + char line[1024]; + unsigned int btime = 0; + + if ((statf = fopen("/proc/stat", "r")) == NULL) { + btimed_error(LOG_ERR, "/proc/stat open failure: %s\n", + strerror(errno)); + exit(1); + } + + while (fgets(line, 1024, statf) != NULL) { + if (strstr(line, "btime") != NULL) { + sscanf(line, "%*s%u", &btime); + } + + } + + fclose(statf); + + return btime; +} + + +/* + *--------------------------------------------------------------------------- + * + * daemon_init -- + * + * Set up a basic daemon environment + * + * Returns: + * 0 on success + * non-zero on failure. + * + * Side effects: + * All fds are closed and process is now a session leader. + * + *--------------------------------------------------------------------------- + */ + +static int +daemon_init(void) +{ + pid_t pid; + int fd; + int maxfd = sysconf(_SC_OPEN_MAX); + + if ((pid = fork()) < 0) { + return(-1); + } else if (pid != 0) { + exit(0); /* Exit in parent */ + } + + /* + * Child sets up daemon environment + */ + + setsid(); /* Become session leader */ + chdir("/"); + umask(0); + for (fd = 0; fd < maxfd; fd++) { + close(fd); + } + errno = 0; /* probably set to EBADFD from above loop, reset */ + + openlog("btimed", LOG_PID, LOG_USER); + + return 0; +} + + +/* + *--------------------------------------------------------------------------- + * + * btimed_perror -- + * + * Print error messages to stderr, level is not used, it is there + * to have the same calling args as syslog(3) so we can use either + * based on debug level. + * + * Returns: + * NA + * + * Side effects: + * None + *--------------------------------------------------------------------------- + */ + +static void +btimed_perror(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +static void +sigchld_hdlr(int sig) +{ + int status; + + wait(&status); + return; +} + + +static void +usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [OPTION]...\n" + "-h\tPrint this help and exit.\n" + "-d\tDon't daemonize, send output to stderr.\n", + progname); + + return; +} diff --git a/qacp.c b/qacp.c new file mode 100644 index 0000000..aa3f22e --- /dev/null +++ b/qacp.c @@ -0,0 +1,382 @@ +/* + * QA Remote Copy - client side + * + * Copy a file to, or from, server. + * + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "sockutil.h" +#include "qarsh_packet.h" + +#define QARSHD_CONTROL_PORT 5008 +#define QARSH_MINPORT 5010 + +/* Globals */ +int qacp_fd = -1; /* The control connection to qacpd */ + +void +usage() +{ +/* printf("usage: qacp: [-r] [[user@]host1:]file1 [...] " */ + /* "[[user@]host2:]file2\n"); */ + + /* For now, only simple cmdlines */ + fprintf(stderr, "usage:\n\t%s\n\t%s\n", + "qacp [ ...] [user@]host:", + "qacp [user@]host: [[user@]host: ...] "); +} + +char * +copyargs(char **argv) +{ + int cc; + char **ap, *p; + char *args; + + cc = 0; + for (ap = argv; *ap; ++ap) + cc += strlen(*ap) + 1; + if (cc == 0) return NULL; + args = malloc(cc); + if (!args) { + perror("qacp: malloc failed in copyargs"); + exit(1); + } + for (p = args, ap = argv; *ap; ++ap) { + for (p = strcpy(p, *ap); *p; ++p); + if (ap[1]) + *p++ = ' '; + } + return args; +} + +void +set_remote_user(char *user, char *group) +{ + struct qa_packet *qp; + + qp = make_qp_setuser(user, group); + qp->qp_seq = 1; + send_packet(qacp_fd, qp); + qpfree(qp); + qp = recv_packet(qacp_fd); + if (qp && qp->qp_type == QP_RETURNCODE + && qp->qp_returncode.qp_rc == -1) { + + fprintf(stderr, "Remote side failed, %s\n", + qp->qp_returncode.qp_strerror); + close(qacp_fd); + exit(125); + } +} + +void +qacp_sendonefile(const char *host, const char *srcfile, const char *destfile) +{ + struct qa_packet *qp; + struct sockaddr_in daddr; + socklen_t dlen; + int fd; + int sd; + int outsd; + int port; + ssize_t nbytes; + off_t offset = 0; + struct stat sb; + + /* Recall that the packet types are qarshd-centric, so if we want + * to send a file to the host running qarshd we have to tell + * qarshd to recv a file. */ + + if ((fd = open(srcfile, O_RDONLY)) <0) { + fprintf(stderr, "Could not open %s: %s\n", srcfile, strerror(errno)); + close(qacp_fd); + exit(errno); + } + + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Could not stat %s: %s\n", srcfile, strerror(errno)); + close(qacp_fd); + exit(errno); + } + + sd = bind_any(QARSH_MINPORT); + port = getsockport(sd); + + qp = make_qp_recvfile(destfile, port, sb.st_size, sb.st_mode); + qp->qp_seq = 1; + send_packet(qacp_fd, qp); + qpfree(qp); + + dlen = sizeof daddr; + outsd = accept(sd, (struct sockaddr *) &daddr, &dlen); + + nbytes = sendfile(outsd, fd, &offset, sb.st_size); + + close(sd); + close(outsd); + close(fd); + + /* Await our return code from qarshd */ + qp = recv_packet(qacp_fd); + if (qp && qp->qp_type == QP_RETURNCODE + && qp->qp_returncode.qp_rc == -1) { + fprintf(stderr, "Remote side failed, %s\n", + qp->qp_returncode.qp_strerror); + close(qacp_fd); + exit(125); + } + + return; +} + +void +qacp_recvonefile(const char *host, const char *srcfile, const char *destfile) +{ + struct qa_packet *qp; + + /* Recall that the packet types are qarshd-centric, so if we want + * to recv a file from the host running qarshd we have to tell + * qarshd to send a file. */ + + qp = make_qp_sendfile(srcfile, 88, 8888); + qp->qp_seq = 1; + send_packet(qacp_fd, qp); + qpfree(qp); + + return; +} + + +struct qp_rstat_pkt * +qacp_rstat(const char *rmtpath, int *rstaterrno) +{ + struct qa_packet *qp; + struct qp_rstat_pkt *rstatp; + + qp = make_qp_rstat(rmtpath, NULL); + send_packet(qacp_fd, qp); + qpfree(qp); + + qp = recv_packet(qacp_fd); + if (qp) { + if (qp->qp_type == QP_RSTAT) { + rstatp = malloc(sizeof *rstatp); + rstatp->qp_path = strdup(qp->qp_rstat.qp_path); + rstatp->qp_st_mode = qp->qp_rstat.qp_st_mode; + rstatp->qp_st_uid = qp->qp_rstat.qp_st_uid; + rstatp->qp_st_gid = qp->qp_rstat.qp_st_gid; + rstatp->qp_st_size = qp->qp_rstat.qp_st_size; + *rstaterrno = 0; + } else if (qp->qp_type == QP_RETURNCODE) { + rstatp = NULL; + *rstaterrno = qp->qp_returncode.qp_errno; + } + + qpfree(qp); + } + + return rstatp; +} + +int +recvfiles(char **argv, int argc, short recursive, short quiet) +{ + puts("recvfiles() NA"); + return 0; +} + + +int +sendfiles(char **argv, int argc, short recursive, short quiet) +{ + char *cp; + char *rhost = NULL; + char *ruser = NULL; + char *rgrp = NULL; + struct passwd *pw; + int file; + char *rmtpath; + char *destpath; + char *tmpstr; + char *lbnp; /* local file basename */ + char *rdnp; /* remote path dirname */ + struct qp_rstat_pkt *rstatp; + int rstaterrno; + + + if (strchr(argv[argc-1], ':') == NULL) { + fprintf(stderr, "%s is not a valid remote host:file string\n", + argv[argc-1]); + return -1; + } + + rhost = strdup(argv[argc-1]); + cp = strchr(rhost, ':'); + *cp = '\0'; + + /* Grab any user/group info */ + if ((cp = strchr(rhost, '@'))) { + ruser = rhost; + rhost = cp+1; + *cp = '\0'; + } + + if (ruser && (cp = strchr(ruser, '.'))) { + rgrp = cp+1; + *cp = '\0'; + } + + if (!(pw = getpwuid(getuid()))) { + fprintf(stderr, "qacp: unknown user id.\n"); + return -1; + } + + if (ruser == NULL) { + ruser = strdup(pw->pw_name); + } + + qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT); + if (qacp_fd == -1) { + if (errno == 0) { + fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", + rhost, QARSHD_CONTROL_PORT, h_errno, hstrerror(h_errno)); + } else { + fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", + rhost, QARSHD_CONTROL_PORT, errno, strerror(errno)); + } + return -1; + } + + set_remote_user(ruser, rgrp); + + cp = strdup(argv[argc-1]); + cp = strchr(argv[argc-1], ':'); + cp++; + rmtpath = strdup(cp); + + rstatp = qacp_rstat(rmtpath, &rstaterrno); + + for (file = optind; file < (argc - 1); file++) { + tmpstr = strdup(argv[file]); + lbnp = strdup(basename(tmpstr)); + free(tmpstr); + + if (rstatp) { + /* + * If rmtpath is a dir, then we tack on the + * local files basename. + */ + if (S_ISDIR(rstatp->qp_st_mode)) { + destpath = malloc(strlen(rmtpath) + strlen(lbnp) + 2); + strcpy(destpath, rmtpath); + strcat(destpath, "/"); + strcat(destpath, lbnp); + } + + /* It rmtpath is a file, then we leave it as is */ + if (S_ISREG(rstatp->qp_st_mode)) { + destpath = strdup(rmtpath); + } + } else { + /* rmtpath does not exist, check if the dirname does */ + tmpstr = strdup(rmtpath); + rdnp = strdup(dirname(tmpstr)); + free(tmpstr); + + rstatp = qacp_rstat(rdnp, &rstaterrno); + if (rstatp) { + /* Ok, the dir exists, i.e. rmtpath is /tmp/foo + * and the first rstat was an error. Now we know + * that /tmp exists, we leave destpath == rmtpath. + */ + destpath = strdup(rmtpath); + } else { + fprintf(stderr, "%s:%s - %s\n", rhost, rmtpath, + strerror(rstaterrno)); + return -1; + } + } + + if (!quiet) { + printf("%-40.40s -> %s:%s\n", argv[file], rhost, destpath); + } + + qacp_sendonefile(rhost, argv[file], destpath); + + free(lbnp); + free(destpath); + } + + return 0; +} + + +int +main(int argc, char *argv[]) +{ + int c; + short recursive=0; + short quiet=0; + int eflag; + + while ((c = getopt(argc, argv, "+rq")) != -1) { + switch (c) { + case 'r': + recursive = 1; + break; + case 'q': + quiet = 1; + break; + case '?': + default: + printf("Unknown option %c\n", (char)optopt); + usage(); + exit(1); + } + } + + if (argv[optind + 1] == NULL) { + usage(); + exit(2); + } + + eflag = 0; + /* If last arg has a ':' then we are sending files */ + if (strchr(argv[argc-1], ':') != NULL) { + if (sendfiles(argv, argc, recursive, quiet) < 0) { + eflag++; + } + } else { + if (recvfiles(argv, argc, recursive, quiet) < 0) { + eflag++; + } + } + + close(qacp_fd); + + if (eflag) { + exit(1); + } + + exit(0); +} diff --git a/qarsh.c b/qarsh.c new file mode 100644 index 0000000..b0c4aab --- /dev/null +++ b/qarsh.c @@ -0,0 +1,365 @@ +/* + * QA Remote Shell - client side + * + * Run a command on the server with lots of wizz-bang options + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "sockutil.h" +#include "qarsh_packet.h" + +#define QARSH_MINPORT 5010 + +/* Globals */ +int qarsh_fd = -1; /* The control connection to qarshd */ +int signal_to_send = 0; +int sigs_to_propogate[] = { SIGINT, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2 }; +sigset_t pselect_sigmask; + +void +usage() +{ + printf("qarsh: [user[.group]@]hostname cmdline ...\n"); +} + +char * +copyargs(char **argv) +{ + int cc; + char **ap, *p; + char *args; + + cc = 0; + for (ap = argv; *ap; ++ap) + cc += strlen(*ap) + 1; + if (cc == 0) return NULL; + args = malloc(cc); + if (!args) { + perror("qarsh: malloc failed in copyargs"); + exit(1); + } + for (p = args, ap = argv; *ap; ++ap) { + for (p = strcpy(p, *ap); *p; ++p); + if (ap[1]) + *p++ = ' '; + } + return args; +} + +void +sig_handler(int sig) +{ + signal_to_send = sig; +} + +void +setup_signals(void) +{ + struct sigaction sa; + sigset_t sigmask; + int i, n; + + n = sizeof sigs_to_propogate / sizeof *sigs_to_propogate; + sigemptyset(&sigmask); + for (i = 0; i < n; i++) { + sigaddset(&sigmask, sigs_to_propogate[i]); + } + sigprocmask(SIG_BLOCK, &sigmask, &pselect_sigmask); + sa.sa_handler = sig_handler; + sa.sa_mask = sigmask; + sa.sa_flags = SA_RESTART; + for (i = 0; i < n; i++) { + sigaction(sigs_to_propogate[i], &sa, NULL); + } +} + +void +set_remote_user(char *user, char *group) +{ + struct qa_packet *qp; + + qp = make_qp_setuser(user, group); + qp->qp_seq = 1; + send_packet(qarsh_fd, qp); + qpfree(qp); + qp = recv_packet(qarsh_fd); + if (qp && qp->qp_type == QP_RETURNCODE + && qp->qp_returncode.qp_rc == -1) { + + fprintf(stderr, "Remote side failed, %s\n", + qp->qp_returncode.qp_strerror); + close(qarsh_fd); + exit(125); + } +} + +int +run_remote_cmd(char *cmdline) +{ + struct qa_packet *qp; + char *buf; + int bufsize; + int rc; + int p_in, p_out, p_err; /* Port numbers */ + int l_in, l_out, l_err; /* listening sockets */ + int c_in, c_out, c_err; /* client sockets */ + fd_set readfds, testfds; + int nset; + struct sockaddr_in caddr; + socklen_t clen; + + l_in = bind_any(QARSH_MINPORT); + p_in = getsockport(l_in); + l_out = bind_any(QARSH_MINPORT); + p_out = getsockport(l_out); + l_err = bind_any(QARSH_MINPORT); + p_err = getsockport(l_err); + + qp = make_qp_runcmd(cmdline, p_in, p_out, p_err); + qp->qp_seq = 1; + send_packet(qarsh_fd, qp); + qpfree(qp); + + /* Get the stdin, stdout, and stderr connections up before we do work */ + FD_ZERO(&readfds); + FD_SET(l_in, &readfds); + FD_SET(l_out, &readfds); + FD_SET(l_err, &readfds); + c_in = c_out = c_err = 0; + + do { + testfds = readfds; + nset = select(FD_SETSIZE, &testfds, NULL, NULL, NULL); + + if (FD_ISSET(l_in, &testfds)) { + clen = sizeof caddr; + c_in = accept(l_in, (struct sockaddr *)&caddr, &clen); + if (c_in == -1) { + fprintf(stderr, + "accept of l_in failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + if (FD_ISSET(l_out, &testfds)) { + clen = sizeof caddr; + c_out = accept(l_out, (struct sockaddr *)&caddr, &clen); + if (c_out == -1) { + fprintf(stderr, + "accept of l_out failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + if (FD_ISSET(l_err, &testfds)) { + clen = sizeof caddr; + c_err = accept(l_err, (struct sockaddr *)&caddr, &clen); + if (c_err == -1) { + fprintf(stderr, + "accept of l_err failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + } while (c_in == 0 || c_out == 0 || c_err == 0); + close(l_in); + close(l_out); + close(l_err); + l_in = l_out = l_err = -1; + + /* Now we can start doing some real work */ + + FD_ZERO(&readfds); + FD_SET(qarsh_fd, &readfds); + FD_SET(c_out, &readfds); + FD_SET(c_err, &readfds); + FD_SET(fileno(stdin), &readfds); + /* Setup signal handling stuff so we can propogate signals */ + setup_signals(); + + if (fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) != 0) { + fprintf(stderr, + "fcntl stdin O_NONBLOCK failed, %d: %s\n", + errno, strerror(errno)); + } + buf = malloc(1024); + memset(buf, 0, 1024); + + for (;;) { + testfds = readfds; + memset(buf, 0, 1024); + + nset = pselect(FD_SETSIZE, &testfds, NULL, NULL, NULL, + &pselect_sigmask); + if (nset == -1 && errno == EINTR) { + /* Only test signals */ + if (signal_to_send) { + qp = make_qp_kill(signal_to_send); + send_packet(qarsh_fd, qp); + qpfree(qp); + signal_to_send = 0; + } + } else if (nset > 0) { + if (nset && FD_ISSET(fileno(stdin), &testfds)) { + bufsize = read(fileno(stdin), buf, 1024); + if (bufsize > 0) { + write(c_in, buf, bufsize); + } else if (bufsize == 0) { + FD_CLR(fileno(stdin), &readfds); + close(fileno(stdin)); + close(c_in); + c_in = 0; + } + nset--; + } + if (nset && c_out && FD_ISSET(c_out, &testfds)) { + bufsize = read(c_out, buf, 1024); + if (bufsize > 0) { + write(fileno(stdout), buf, bufsize); + } else if (bufsize == 0) { + FD_CLR(c_out, &readfds); + close(c_out); + c_out = 0; + } + nset--; + } + if (nset && c_err && FD_ISSET(c_err, &testfds)) { + bufsize = read(c_err, buf, 1024); + if (bufsize > 0) { + write(fileno(stderr), buf, bufsize); + } else if (bufsize == 0) { + FD_CLR(c_err, &readfds); + close(c_err); + c_err = 0; + } + nset--; + } + if (nset && FD_ISSET(qarsh_fd, &testfds)) { + qp = recv_packet(qarsh_fd); + + /* dump_qp(qp); */ + if (qp && qp->qp_type == QP_CMDEXIT) { + break; + } + nset--; + } + } + } + if (c_out) close(c_out); + if (c_err) close(c_err); + if (qp == NULL) { + fprintf(stderr, "Remote command exited with unknown state\n"); + free(buf); + return 127; + } + if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) { + rc = 128 + WTERMSIG(qp->qp_cmdexit.qp_status); + } else { + rc = WEXITSTATUS(qp->qp_cmdexit.qp_status); + } + qpfree(qp); + free(buf); + return rc; +} + +int +main(int argc, char *argv[]) +{ + + int c; + int port = 5008; + char *host; + char *remuser = NULL; + char *remgroup = NULL; + char *args; + struct passwd *pw; + int ret; + + openlog("qarsh", LOG_PID, LOG_DAEMON); + + while ((c = getopt(argc, argv, "+p:l:g:")) != -1) { + switch (c) { + case 'l': + remuser = strdup(optarg); + break; + case 'g': + remgroup = strdup(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case '?': + default: + printf("Unknown option %c\n", (char)optopt); + usage(); + exit(1); + } } + + if ((host = argv[optind++]) == NULL) { + usage(); + exit(1); + } + /* check for user and group in form [user[.group]@]hostname */ + { + char *sp; + + if ((sp = strchr(host, '@'))) { + remuser = host; + host = sp+1; + *sp = '\0'; + } + if (remuser && (sp = strchr(remuser, '.'))) { + remgroup = sp+1; + *sp = '\0'; + } + } + if (!(pw = getpwuid(getuid()))) { + fprintf(stderr, "qarsh: unknown user id.\n"); + exit(1); + } + if (remuser == NULL) { + remuser = strdup(pw->pw_name); + } + + argc -= optind; + argv += optind; + if ((args = copyargs(argv)) == NULL) { + usage(); + exit(1); + } + qarsh_fd = connect_to_host(host, port); + if (qarsh_fd == -1) { + if (errno == 0) { + fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", + host, port, h_errno, hstrerror(h_errno)); + } else { + fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", + host, port, errno, strerror(errno)); + } + return 127; + } + + set_remote_user(remuser, remgroup); + + ret = run_remote_cmd(args); + close(qarsh_fd); + free(args); + return ret; +} diff --git a/qarsh/Makefile b/qarsh/Makefile deleted file mode 100644 index 762b756..0000000 --- a/qarsh/Makefile +++ /dev/null @@ -1,34 +0,0 @@ - -include ../../make/defines.mk -.PHONY: clean clobber uninstall - -CFLAGS := -Wall -g -I/usr/include/libxml2 -LOADLIBES := -lxml2 - -COMMON := qarsh_packet.c sockutil.c - -all: qarshd qarsh qacp - -qarshd: qarshd.c $(COMMON) -qarsh: qarsh.c $(COMMON) -qacp: qacp.c $(COMMON) - -install: qarsh qarshd - @echo Installing qarsh daemon and client - install -d ${STSDIR}/bin/ - install qacp ${STSDIR}/bin - install qarsh ${STSDIR}/bin - install qarshd ${STSDIR}/bin - -uninstall: - ${UNINSTALL} qacp ${STSDIR}/bin - ${UNINSTALL} qarsh ${STSDIR}/bin - ${UNINSTALL} qarshd ${STSDIR}/bin - -clean: - /bin/rm -f *.o - -clobber: - /bin/rm -f qacp - /bin/rm -f qarsh - /bin/rm -f qarshd diff --git a/qarsh/qacp.c b/qarsh/qacp.c deleted file mode 100644 index aa3f22e..0000000 --- a/qarsh/qacp.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * QA Remote Copy - client side - * - * Copy a file to, or from, server. - * - * - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "sockutil.h" -#include "qarsh_packet.h" - -#define QARSHD_CONTROL_PORT 5008 -#define QARSH_MINPORT 5010 - -/* Globals */ -int qacp_fd = -1; /* The control connection to qacpd */ - -void -usage() -{ -/* printf("usage: qacp: [-r] [[user@]host1:]file1 [...] " */ - /* "[[user@]host2:]file2\n"); */ - - /* For now, only simple cmdlines */ - fprintf(stderr, "usage:\n\t%s\n\t%s\n", - "qacp [ ...] [user@]host:", - "qacp [user@]host: [[user@]host: ...] "); -} - -char * -copyargs(char **argv) -{ - int cc; - char **ap, *p; - char *args; - - cc = 0; - for (ap = argv; *ap; ++ap) - cc += strlen(*ap) + 1; - if (cc == 0) return NULL; - args = malloc(cc); - if (!args) { - perror("qacp: malloc failed in copyargs"); - exit(1); - } - for (p = args, ap = argv; *ap; ++ap) { - for (p = strcpy(p, *ap); *p; ++p); - if (ap[1]) - *p++ = ' '; - } - return args; -} - -void -set_remote_user(char *user, char *group) -{ - struct qa_packet *qp; - - qp = make_qp_setuser(user, group); - qp->qp_seq = 1; - send_packet(qacp_fd, qp); - qpfree(qp); - qp = recv_packet(qacp_fd); - if (qp && qp->qp_type == QP_RETURNCODE - && qp->qp_returncode.qp_rc == -1) { - - fprintf(stderr, "Remote side failed, %s\n", - qp->qp_returncode.qp_strerror); - close(qacp_fd); - exit(125); - } -} - -void -qacp_sendonefile(const char *host, const char *srcfile, const char *destfile) -{ - struct qa_packet *qp; - struct sockaddr_in daddr; - socklen_t dlen; - int fd; - int sd; - int outsd; - int port; - ssize_t nbytes; - off_t offset = 0; - struct stat sb; - - /* Recall that the packet types are qarshd-centric, so if we want - * to send a file to the host running qarshd we have to tell - * qarshd to recv a file. */ - - if ((fd = open(srcfile, O_RDONLY)) <0) { - fprintf(stderr, "Could not open %s: %s\n", srcfile, strerror(errno)); - close(qacp_fd); - exit(errno); - } - - if (fstat(fd, &sb) < 0) { - fprintf(stderr, "Could not stat %s: %s\n", srcfile, strerror(errno)); - close(qacp_fd); - exit(errno); - } - - sd = bind_any(QARSH_MINPORT); - port = getsockport(sd); - - qp = make_qp_recvfile(destfile, port, sb.st_size, sb.st_mode); - qp->qp_seq = 1; - send_packet(qacp_fd, qp); - qpfree(qp); - - dlen = sizeof daddr; - outsd = accept(sd, (struct sockaddr *) &daddr, &dlen); - - nbytes = sendfile(outsd, fd, &offset, sb.st_size); - - close(sd); - close(outsd); - close(fd); - - /* Await our return code from qarshd */ - qp = recv_packet(qacp_fd); - if (qp && qp->qp_type == QP_RETURNCODE - && qp->qp_returncode.qp_rc == -1) { - fprintf(stderr, "Remote side failed, %s\n", - qp->qp_returncode.qp_strerror); - close(qacp_fd); - exit(125); - } - - return; -} - -void -qacp_recvonefile(const char *host, const char *srcfile, const char *destfile) -{ - struct qa_packet *qp; - - /* Recall that the packet types are qarshd-centric, so if we want - * to recv a file from the host running qarshd we have to tell - * qarshd to send a file. */ - - qp = make_qp_sendfile(srcfile, 88, 8888); - qp->qp_seq = 1; - send_packet(qacp_fd, qp); - qpfree(qp); - - return; -} - - -struct qp_rstat_pkt * -qacp_rstat(const char *rmtpath, int *rstaterrno) -{ - struct qa_packet *qp; - struct qp_rstat_pkt *rstatp; - - qp = make_qp_rstat(rmtpath, NULL); - send_packet(qacp_fd, qp); - qpfree(qp); - - qp = recv_packet(qacp_fd); - if (qp) { - if (qp->qp_type == QP_RSTAT) { - rstatp = malloc(sizeof *rstatp); - rstatp->qp_path = strdup(qp->qp_rstat.qp_path); - rstatp->qp_st_mode = qp->qp_rstat.qp_st_mode; - rstatp->qp_st_uid = qp->qp_rstat.qp_st_uid; - rstatp->qp_st_gid = qp->qp_rstat.qp_st_gid; - rstatp->qp_st_size = qp->qp_rstat.qp_st_size; - *rstaterrno = 0; - } else if (qp->qp_type == QP_RETURNCODE) { - rstatp = NULL; - *rstaterrno = qp->qp_returncode.qp_errno; - } - - qpfree(qp); - } - - return rstatp; -} - -int -recvfiles(char **argv, int argc, short recursive, short quiet) -{ - puts("recvfiles() NA"); - return 0; -} - - -int -sendfiles(char **argv, int argc, short recursive, short quiet) -{ - char *cp; - char *rhost = NULL; - char *ruser = NULL; - char *rgrp = NULL; - struct passwd *pw; - int file; - char *rmtpath; - char *destpath; - char *tmpstr; - char *lbnp; /* local file basename */ - char *rdnp; /* remote path dirname */ - struct qp_rstat_pkt *rstatp; - int rstaterrno; - - - if (strchr(argv[argc-1], ':') == NULL) { - fprintf(stderr, "%s is not a valid remote host:file string\n", - argv[argc-1]); - return -1; - } - - rhost = strdup(argv[argc-1]); - cp = strchr(rhost, ':'); - *cp = '\0'; - - /* Grab any user/group info */ - if ((cp = strchr(rhost, '@'))) { - ruser = rhost; - rhost = cp+1; - *cp = '\0'; - } - - if (ruser && (cp = strchr(ruser, '.'))) { - rgrp = cp+1; - *cp = '\0'; - } - - if (!(pw = getpwuid(getuid()))) { - fprintf(stderr, "qacp: unknown user id.\n"); - return -1; - } - - if (ruser == NULL) { - ruser = strdup(pw->pw_name); - } - - qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT); - if (qacp_fd == -1) { - if (errno == 0) { - fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", - rhost, QARSHD_CONTROL_PORT, h_errno, hstrerror(h_errno)); - } else { - fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", - rhost, QARSHD_CONTROL_PORT, errno, strerror(errno)); - } - return -1; - } - - set_remote_user(ruser, rgrp); - - cp = strdup(argv[argc-1]); - cp = strchr(argv[argc-1], ':'); - cp++; - rmtpath = strdup(cp); - - rstatp = qacp_rstat(rmtpath, &rstaterrno); - - for (file = optind; file < (argc - 1); file++) { - tmpstr = strdup(argv[file]); - lbnp = strdup(basename(tmpstr)); - free(tmpstr); - - if (rstatp) { - /* - * If rmtpath is a dir, then we tack on the - * local files basename. - */ - if (S_ISDIR(rstatp->qp_st_mode)) { - destpath = malloc(strlen(rmtpath) + strlen(lbnp) + 2); - strcpy(destpath, rmtpath); - strcat(destpath, "/"); - strcat(destpath, lbnp); - } - - /* It rmtpath is a file, then we leave it as is */ - if (S_ISREG(rstatp->qp_st_mode)) { - destpath = strdup(rmtpath); - } - } else { - /* rmtpath does not exist, check if the dirname does */ - tmpstr = strdup(rmtpath); - rdnp = strdup(dirname(tmpstr)); - free(tmpstr); - - rstatp = qacp_rstat(rdnp, &rstaterrno); - if (rstatp) { - /* Ok, the dir exists, i.e. rmtpath is /tmp/foo - * and the first rstat was an error. Now we know - * that /tmp exists, we leave destpath == rmtpath. - */ - destpath = strdup(rmtpath); - } else { - fprintf(stderr, "%s:%s - %s\n", rhost, rmtpath, - strerror(rstaterrno)); - return -1; - } - } - - if (!quiet) { - printf("%-40.40s -> %s:%s\n", argv[file], rhost, destpath); - } - - qacp_sendonefile(rhost, argv[file], destpath); - - free(lbnp); - free(destpath); - } - - return 0; -} - - -int -main(int argc, char *argv[]) -{ - int c; - short recursive=0; - short quiet=0; - int eflag; - - while ((c = getopt(argc, argv, "+rq")) != -1) { - switch (c) { - case 'r': - recursive = 1; - break; - case 'q': - quiet = 1; - break; - case '?': - default: - printf("Unknown option %c\n", (char)optopt); - usage(); - exit(1); - } - } - - if (argv[optind + 1] == NULL) { - usage(); - exit(2); - } - - eflag = 0; - /* If last arg has a ':' then we are sending files */ - if (strchr(argv[argc-1], ':') != NULL) { - if (sendfiles(argv, argc, recursive, quiet) < 0) { - eflag++; - } - } else { - if (recvfiles(argv, argc, recursive, quiet) < 0) { - eflag++; - } - } - - close(qacp_fd); - - if (eflag) { - exit(1); - } - - exit(0); -} diff --git a/qarsh/qarsh.c b/qarsh/qarsh.c deleted file mode 100644 index b0c4aab..0000000 --- a/qarsh/qarsh.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * QA Remote Shell - client side - * - * Run a command on the server with lots of wizz-bang options - * - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "sockutil.h" -#include "qarsh_packet.h" - -#define QARSH_MINPORT 5010 - -/* Globals */ -int qarsh_fd = -1; /* The control connection to qarshd */ -int signal_to_send = 0; -int sigs_to_propogate[] = { SIGINT, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2 }; -sigset_t pselect_sigmask; - -void -usage() -{ - printf("qarsh: [user[.group]@]hostname cmdline ...\n"); -} - -char * -copyargs(char **argv) -{ - int cc; - char **ap, *p; - char *args; - - cc = 0; - for (ap = argv; *ap; ++ap) - cc += strlen(*ap) + 1; - if (cc == 0) return NULL; - args = malloc(cc); - if (!args) { - perror("qarsh: malloc failed in copyargs"); - exit(1); - } - for (p = args, ap = argv; *ap; ++ap) { - for (p = strcpy(p, *ap); *p; ++p); - if (ap[1]) - *p++ = ' '; - } - return args; -} - -void -sig_handler(int sig) -{ - signal_to_send = sig; -} - -void -setup_signals(void) -{ - struct sigaction sa; - sigset_t sigmask; - int i, n; - - n = sizeof sigs_to_propogate / sizeof *sigs_to_propogate; - sigemptyset(&sigmask); - for (i = 0; i < n; i++) { - sigaddset(&sigmask, sigs_to_propogate[i]); - } - sigprocmask(SIG_BLOCK, &sigmask, &pselect_sigmask); - sa.sa_handler = sig_handler; - sa.sa_mask = sigmask; - sa.sa_flags = SA_RESTART; - for (i = 0; i < n; i++) { - sigaction(sigs_to_propogate[i], &sa, NULL); - } -} - -void -set_remote_user(char *user, char *group) -{ - struct qa_packet *qp; - - qp = make_qp_setuser(user, group); - qp->qp_seq = 1; - send_packet(qarsh_fd, qp); - qpfree(qp); - qp = recv_packet(qarsh_fd); - if (qp && qp->qp_type == QP_RETURNCODE - && qp->qp_returncode.qp_rc == -1) { - - fprintf(stderr, "Remote side failed, %s\n", - qp->qp_returncode.qp_strerror); - close(qarsh_fd); - exit(125); - } -} - -int -run_remote_cmd(char *cmdline) -{ - struct qa_packet *qp; - char *buf; - int bufsize; - int rc; - int p_in, p_out, p_err; /* Port numbers */ - int l_in, l_out, l_err; /* listening sockets */ - int c_in, c_out, c_err; /* client sockets */ - fd_set readfds, testfds; - int nset; - struct sockaddr_in caddr; - socklen_t clen; - - l_in = bind_any(QARSH_MINPORT); - p_in = getsockport(l_in); - l_out = bind_any(QARSH_MINPORT); - p_out = getsockport(l_out); - l_err = bind_any(QARSH_MINPORT); - p_err = getsockport(l_err); - - qp = make_qp_runcmd(cmdline, p_in, p_out, p_err); - qp->qp_seq = 1; - send_packet(qarsh_fd, qp); - qpfree(qp); - - /* Get the stdin, stdout, and stderr connections up before we do work */ - FD_ZERO(&readfds); - FD_SET(l_in, &readfds); - FD_SET(l_out, &readfds); - FD_SET(l_err, &readfds); - c_in = c_out = c_err = 0; - - do { - testfds = readfds; - nset = select(FD_SETSIZE, &testfds, NULL, NULL, NULL); - - if (FD_ISSET(l_in, &testfds)) { - clen = sizeof caddr; - c_in = accept(l_in, (struct sockaddr *)&caddr, &clen); - if (c_in == -1) { - fprintf(stderr, - "accept of l_in failed, %d: %s\n", - errno, strerror(errno)); - continue; - } - } - if (FD_ISSET(l_out, &testfds)) { - clen = sizeof caddr; - c_out = accept(l_out, (struct sockaddr *)&caddr, &clen); - if (c_out == -1) { - fprintf(stderr, - "accept of l_out failed, %d: %s\n", - errno, strerror(errno)); - continue; - } - } - if (FD_ISSET(l_err, &testfds)) { - clen = sizeof caddr; - c_err = accept(l_err, (struct sockaddr *)&caddr, &clen); - if (c_err == -1) { - fprintf(stderr, - "accept of l_err failed, %d: %s\n", - errno, strerror(errno)); - continue; - } - } - } while (c_in == 0 || c_out == 0 || c_err == 0); - close(l_in); - close(l_out); - close(l_err); - l_in = l_out = l_err = -1; - - /* Now we can start doing some real work */ - - FD_ZERO(&readfds); - FD_SET(qarsh_fd, &readfds); - FD_SET(c_out, &readfds); - FD_SET(c_err, &readfds); - FD_SET(fileno(stdin), &readfds); - /* Setup signal handling stuff so we can propogate signals */ - setup_signals(); - - if (fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) != 0) { - fprintf(stderr, - "fcntl stdin O_NONBLOCK failed, %d: %s\n", - errno, strerror(errno)); - } - buf = malloc(1024); - memset(buf, 0, 1024); - - for (;;) { - testfds = readfds; - memset(buf, 0, 1024); - - nset = pselect(FD_SETSIZE, &testfds, NULL, NULL, NULL, - &pselect_sigmask); - if (nset == -1 && errno == EINTR) { - /* Only test signals */ - if (signal_to_send) { - qp = make_qp_kill(signal_to_send); - send_packet(qarsh_fd, qp); - qpfree(qp); - signal_to_send = 0; - } - } else if (nset > 0) { - if (nset && FD_ISSET(fileno(stdin), &testfds)) { - bufsize = read(fileno(stdin), buf, 1024); - if (bufsize > 0) { - write(c_in, buf, bufsize); - } else if (bufsize == 0) { - FD_CLR(fileno(stdin), &readfds); - close(fileno(stdin)); - close(c_in); - c_in = 0; - } - nset--; - } - if (nset && c_out && FD_ISSET(c_out, &testfds)) { - bufsize = read(c_out, buf, 1024); - if (bufsize > 0) { - write(fileno(stdout), buf, bufsize); - } else if (bufsize == 0) { - FD_CLR(c_out, &readfds); - close(c_out); - c_out = 0; - } - nset--; - } - if (nset && c_err && FD_ISSET(c_err, &testfds)) { - bufsize = read(c_err, buf, 1024); - if (bufsize > 0) { - write(fileno(stderr), buf, bufsize); - } else if (bufsize == 0) { - FD_CLR(c_err, &readfds); - close(c_err); - c_err = 0; - } - nset--; - } - if (nset && FD_ISSET(qarsh_fd, &testfds)) { - qp = recv_packet(qarsh_fd); - - /* dump_qp(qp); */ - if (qp && qp->qp_type == QP_CMDEXIT) { - break; - } - nset--; - } - } - } - if (c_out) close(c_out); - if (c_err) close(c_err); - if (qp == NULL) { - fprintf(stderr, "Remote command exited with unknown state\n"); - free(buf); - return 127; - } - if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) { - rc = 128 + WTERMSIG(qp->qp_cmdexit.qp_status); - } else { - rc = WEXITSTATUS(qp->qp_cmdexit.qp_status); - } - qpfree(qp); - free(buf); - return rc; -} - -int -main(int argc, char *argv[]) -{ - - int c; - int port = 5008; - char *host; - char *remuser = NULL; - char *remgroup = NULL; - char *args; - struct passwd *pw; - int ret; - - openlog("qarsh", LOG_PID, LOG_DAEMON); - - while ((c = getopt(argc, argv, "+p:l:g:")) != -1) { - switch (c) { - case 'l': - remuser = strdup(optarg); - break; - case 'g': - remgroup = strdup(optarg); - break; - case 'p': - port = atoi(optarg); - break; - case '?': - default: - printf("Unknown option %c\n", (char)optopt); - usage(); - exit(1); - } } - - if ((host = argv[optind++]) == NULL) { - usage(); - exit(1); - } - /* check for user and group in form [user[.group]@]hostname */ - { - char *sp; - - if ((sp = strchr(host, '@'))) { - remuser = host; - host = sp+1; - *sp = '\0'; - } - if (remuser && (sp = strchr(remuser, '.'))) { - remgroup = sp+1; - *sp = '\0'; - } - } - if (!(pw = getpwuid(getuid()))) { - fprintf(stderr, "qarsh: unknown user id.\n"); - exit(1); - } - if (remuser == NULL) { - remuser = strdup(pw->pw_name); - } - - argc -= optind; - argv += optind; - if ((args = copyargs(argv)) == NULL) { - usage(); - exit(1); - } - qarsh_fd = connect_to_host(host, port); - if (qarsh_fd == -1) { - if (errno == 0) { - fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", - host, port, h_errno, hstrerror(h_errno)); - } else { - fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", - host, port, errno, strerror(errno)); - } - return 127; - } - - set_remote_user(remuser, remgroup); - - ret = run_remote_cmd(args); - close(qarsh_fd); - free(args); - return ret; -} diff --git a/qarsh/qarsh_packet.c b/qarsh/qarsh_packet.c deleted file mode 100644 index 76fadf1..0000000 --- a/qarsh/qarsh_packet.c +++ /dev/null @@ -1,850 +0,0 @@ - -#include -#include -#include - -#include -#include - -#include "qarsh_packet.h" - -/* Prototypes */ -static char *get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query); - -int parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp); -int parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp); - -void string_qp_hello(xmlNodePtr node, struct qa_packet *qp); -void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp); -void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp); -void string_qp_ack(xmlNodePtr node, struct qa_packet *qp); -void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp); -void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp); -void string_qp_kill(xmlNodePtr node, struct qa_packet *qp); -void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp); -void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp); -void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp); - -void free_qp_hello(struct qa_packet *qp); -void free_qp_returncode(struct qa_packet *qp); -void free_qp_runcmd(struct qa_packet *qp); -void free_qp_setuser(struct qa_packet *qp); -void free_qp_recvfile(struct qa_packet *qp); -void free_qp_sendfile(struct qa_packet *qp); -void free_qp_rstat(struct qa_packet *qp); - -void dump_qp_ack(struct qa_packet *qp); -void dump_qp_runcmd(struct qa_packet *qp); -void dump_qp_returncode(struct qa_packet *qp); -void dump_qp_cmdexit(struct qa_packet *qp); -void dump_qp_setuser(struct qa_packet *qp); -void dump_qp_kill(struct qa_packet *qp); -void dump_qp_recvfile(struct qa_packet *qp); -void dump_qp_sendfile(struct qa_packet *qp); -void dump_qp_rstat(struct qa_packet *qp); - - -struct packet_internals { - char *pi_name; - int (*pi_parse)(xmlXPathContextPtr ctxt, struct qa_packet *qp); - void (*pi_string)(xmlNodePtr node, struct qa_packet *qp); - void (*pi_free)(struct qa_packet *qp); - void (*pi_dump)(struct qa_packet *qp); -} qa_pi[] = { - { - .pi_name = "", - .pi_parse = NULL, - .pi_string = NULL, - .pi_free = NULL, - .pi_dump = NULL - - }, { - .pi_name = "hello", - .pi_parse = parse_qp_hello, - .pi_string = string_qp_hello, - .pi_free = free_qp_hello - }, { - .pi_name = "returncode", - .pi_parse = parse_qp_returncode, - .pi_string = string_qp_returncode, - .pi_free = free_qp_returncode, - .pi_dump = dump_qp_returncode - }, { - .pi_name = "runcmd", - .pi_parse = parse_qp_runcmd, - .pi_string = string_qp_runcmd, - .pi_free = free_qp_runcmd, - .pi_dump = dump_qp_runcmd - }, { - .pi_name = "ack", - .pi_parse = parse_qp_ack, - .pi_string = string_qp_ack, - .pi_free = NULL, - .pi_dump = dump_qp_ack - }, { - .pi_name = "cmdexit", - .pi_parse = parse_qp_cmdexit, - .pi_string = string_qp_cmdexit, - .pi_free = NULL, - .pi_dump = dump_qp_cmdexit - }, { - .pi_name = "setuser", - .pi_parse = parse_qp_setuser, - .pi_string = string_qp_setuser, - .pi_free = free_qp_setuser, - .pi_dump = dump_qp_setuser - }, { - .pi_name = "kill", - .pi_parse = parse_qp_kill, - .pi_string = string_qp_kill, - .pi_free = NULL, - .pi_dump = dump_qp_kill - }, { - .pi_name = "recvfile", - .pi_parse = parse_qp_recvfile, - .pi_string = string_qp_recvfile, - .pi_free = free_qp_recvfile, - .pi_dump = dump_qp_recvfile - }, { - .pi_name = "sendfile", - .pi_parse = parse_qp_sendfile, - .pi_string = string_qp_sendfile, - .pi_free = free_qp_sendfile, - .pi_dump = dump_qp_sendfile - }, { - .pi_name = "rstat", - .pi_parse = parse_qp_rstat, - .pi_string = string_qp_rstat, - .pi_free = free_qp_rstat, - .pi_dump = dump_qp_rstat - } -}; - -#define QP_TYPES (sizeof qa_pi / sizeof *qa_pi) -#define QP_NAME(n) qa_pi[n].pi_name - - -/* XML Strings */ -const xmlChar *QP_QARSH_XML = (xmlChar *)"qarsh"; -const xmlChar *QP_PACKET_XML = (xmlChar *)"packet"; -const xmlChar *QP_TYPE_XML = (xmlChar *)"type"; -const xmlChar *QP_PARAM_XML = (xmlChar *)"param"; -const xmlChar *QP_NAME_XML = (xmlChar *)"name"; -const xmlChar *QP_SEQ_XML = (xmlChar *)"seq"; - -enum qa_packet_type -parse_packet_type(char *s) -{ - int i; - for (i = 0; i < QP_TYPES; i++) { - if (strcasecmp(s, QP_NAME(i)) == 0) { - return (enum qa_packet_type)i; - } - } - return QP_INVALID; -} - -char * -qp_packet_type(enum qa_packet_type t) -{ - return QP_NAME(t); -} - - -/* - * Packet parsing functions - */ -int -parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - qp->qp_hello.qp_greeting = get_xpath_string(ctxt, - "param[@name='greeting']"); - return 0; -} - -int -parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - s = get_xpath_string(ctxt, "param[@name='rc']"); - qp->qp_returncode.qp_rc = atoi(s); - free(s); - s = get_xpath_string(ctxt, "param[@name='errno']"); - qp->qp_returncode.qp_errno = atoi(s); - free(s); - qp->qp_returncode.qp_strerror = get_xpath_string(ctxt, - "param[@name='strerror']"); - return 0; -} - -int -parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - qp->qp_runcmd.qp_cmdline = get_xpath_string(ctxt, - "param[@name='cmdline']"); - s = get_xpath_string(ctxt, "param[@name='stdin']"); - qp->qp_runcmd.qp_stdin_port = atoi(s); - free(s); - s = get_xpath_string(ctxt, "param[@name='stdout']"); - qp->qp_runcmd.qp_stdout_port = atoi(s); - free(s); - s = get_xpath_string(ctxt, "param[@name='stderr']"); - qp->qp_runcmd.qp_stderr_port = atoi(s); - free(s); - return 0; -} - -int -parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - s = get_xpath_string(ctxt, "param[@name='type']"); - qp->qp_ack.qp_ack_type = parse_packet_type(s); - free(s); - s = get_xpath_string(ctxt, "param[@name='seq']"); - qp->qp_ack.qp_ack_seq = atoi(s); - free(s); - return 0; -} - -int -parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - - s = get_xpath_string(ctxt, "param[@name='status']"); - qp->qp_cmdexit.qp_status = atoi(s); - free(s); - return 0; -} - -int -parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - qp->qp_setuser.qp_user = get_xpath_string(ctxt, "param[@name='user']"); - qp->qp_setuser.qp_group = get_xpath_string(ctxt, "param[@name='group']"); - return 0; -} - -int -parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - - s = get_xpath_string(ctxt, "param[@name='signal']"); - qp->qp_kill.qp_sig = atoi(s); - free(s); - return 0; -} - -int -parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - - qp->qp_recvfile.qp_path = get_xpath_string(ctxt, "param[@name='path']"); - - s = get_xpath_string(ctxt, "param[@name='if_port']"); - qp->qp_recvfile.qp_if_port = atoi(s); - free(s); - - s = get_xpath_string(ctxt, "param[@name='count']"); - qp->qp_recvfile.qp_count = atoi(s); - free(s); - - s = get_xpath_string(ctxt, "param[@name='mode']"); - qp->qp_recvfile.qp_mode = atoi(s); - free(s); - - return 0; -} - -int -parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - - qp->qp_sendfile.qp_path = get_xpath_string(ctxt, "param[@name='path']"); - s = get_xpath_string(ctxt, "param[@name='of_port']"); - qp->qp_sendfile.qp_of_port = atoi(s); - free(s); - s = get_xpath_string(ctxt, "param[@name='count']"); - qp->qp_sendfile.qp_count = atoi(s); - free(s); - return 0; -} - -int -parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp) -{ - char *s; - - qp->qp_rstat.qp_path = get_xpath_string(ctxt, "param[@name='path']"); - - s = get_xpath_string(ctxt, "param[@name='st_mode']"); - qp->qp_rstat.qp_st_mode = atoi(s); - free(s); - - s = get_xpath_string(ctxt, "param[@name='st_uid']"); - qp->qp_rstat.qp_st_uid = atoi(s); - free(s); - - s = get_xpath_string(ctxt, "param[@name='st_gid']"); - qp->qp_rstat.qp_st_gid = atoi(s); - free(s); - - s = get_xpath_string(ctxt, "param[@name='st_size']"); - qp->qp_rstat.qp_st_size = atol(s); - free(s); - - return 0; -} - - -struct qa_packet * -parse_packet(xmlXPathContextPtr ctxt) -{ - struct qa_packet *qp = NULL; - char *s; - - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - s = get_xpath_string(ctxt, "@type"); - qp->qp_type = parse_packet_type(s); - free(s); - s = get_xpath_string(ctxt, "@seq"); - qp->qp_seq = atoi(s); - free(s); - - if (qa_pi[qp->qp_type].pi_parse) - qa_pi[qp->qp_type].pi_parse(ctxt, qp); - else { - printf("Packet type %s not implemented yet\n", s); - free(qp); - qp = NULL; - } - return qp; -} - -struct qa_packet * -parse_packets(char *buf, int n) -{ - xmlDocPtr doc; - xmlXPathContextPtr context; - xmlXPathObjectPtr obj = NULL; - struct qa_packet *qp = NULL; - - doc = xmlParseMemory(buf, n); - - /* If we can't parse the packet, we don't care about it */ - if (doc == NULL) return NULL; - - context = xmlXPathNewContext(doc); - obj = xmlXPathEvalExpression((xmlChar *)"//packet", context); - if (obj == NULL) { - printf("didn't find anything\n"); - goto free_context; - } - if (obj->type != XPATH_NODESET || obj->nodesetval->nodeNr == 0) { - printf("didn't find anything\n"); - goto free_obj; - } - if (obj->nodesetval->nodeNr > 1) { - printf("One packet at a time please!\n"); - } - context->node = xmlXPathNodeSetItem(obj->nodesetval, 0); - qp = parse_packet(context); - -free_obj: - xmlXPathFreeObject(obj); -free_context: - xmlXPathFreeContext(context); - xmlFreeDoc(doc); - return qp; -} - - -static char * -get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query) -{ - xmlXPathObjectPtr obj = NULL; - char querystr[512]; - char *ret; - - snprintf(querystr, 512, "string(%s)", xpath_query); - obj = xmlXPathEvalExpression((xmlChar *)querystr, ctxt); - - if (obj == NULL) return NULL; - if (obj->type != XPATH_STRING) { - xmlXPathFreeObject(obj); - return NULL; - } - - ret = strdup((char *)obj->stringval); - xmlXPathFreeObject(obj); - return ret; -} - -/* - * Packet serialization functions - * - * for converting structs to XML - */ -xmlNodePtr -make_param(char *name, char *value) -{ - xmlNodePtr param = xmlNewNode(NULL, QP_PARAM_XML); - xmlNewProp(param, QP_NAME_XML, (xmlChar *)name); - xmlNodeSetContent(param, xmlEncodeSpecialChars(NULL, (xmlChar *)value)); - return param; -} - -void string_qp_hello(xmlNodePtr node, struct qa_packet *qp) -{ - xmlAddChild(node, make_param("greeting", qp->qp_hello.qp_greeting)); -} -void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_rc); - xmlAddChild(node, make_param("rc", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_errno); - xmlAddChild(node, make_param("errno", tmpstr)); - xmlAddChild(node, make_param("strerror", qp->qp_returncode.qp_strerror)); -} -void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - xmlAddChild(node, make_param("cmdline", qp->qp_runcmd.qp_cmdline)); - snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdin_port); - xmlAddChild(node, make_param("stdin", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdout_port); - xmlAddChild(node, make_param("stdout", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stderr_port); - xmlAddChild(node, make_param("stderr", tmpstr)); -} -void string_qp_ack(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - xmlAddChild(node, make_param("type", - QP_NAME(qp->qp_ack.qp_ack_type))); - snprintf(tmpstr, 32, "%d", qp->qp_ack.qp_ack_seq); - xmlAddChild(node, make_param("seq", tmpstr)); -} - -void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_pid); - xmlAddChild(node, make_param("pid", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_status); - xmlAddChild(node, make_param("status", tmpstr)); -} - -void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp) -{ - xmlAddChild(node, make_param("user", qp->qp_setuser.qp_user)); - if (qp->qp_setuser.qp_group) { - xmlAddChild(node, make_param("group", qp->qp_setuser.qp_group)); - } -} - -void string_qp_kill(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - snprintf(tmpstr, 32, "%d", qp->qp_kill.qp_sig); - xmlAddChild(node, make_param("signal", tmpstr)); -} - -void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - xmlAddChild(node, make_param("path", qp->qp_recvfile.qp_path)); - - snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_if_port); - xmlAddChild(node, make_param("if_port", tmpstr)); - - snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_count); - xmlAddChild(node, make_param("count", tmpstr)); - - snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_mode); - xmlAddChild(node, make_param("mode", tmpstr)); -} - -void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - xmlAddChild(node, make_param("path", qp->qp_sendfile.qp_path)); - snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_of_port); - xmlAddChild(node, make_param("of_port", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_count); - xmlAddChild(node, make_param("count", tmpstr)); -} - -void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp) -{ - char tmpstr[32]; - - xmlAddChild(node, make_param("path", qp->qp_rstat.qp_path)); - snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_mode); - xmlAddChild(node, make_param("st_mode", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_uid); - xmlAddChild(node, make_param("st_uid", tmpstr)); - snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_gid); - xmlAddChild(node, make_param("st_gid", tmpstr)); - snprintf(tmpstr, 32, "%ld", qp->qp_rstat.qp_st_size); - xmlAddChild(node, make_param("st_size", tmpstr)); -} - -/* Must pass in a pointer, but not a malloc'ed pointer */ -char * -qptostr(struct qa_packet *qp, char **qpstr, int *qpsize) -{ - xmlDocPtr doc; - xmlNodePtr node; - char tmpstr[32]; - - if (qp->qp_type == QP_INVALID) return NULL; - - doc = xmlNewDoc((xmlChar *)XML_DEFAULT_VERSION); - - /* Add */ - node = xmlNewDocNode(doc, NULL, QP_QARSH_XML, NULL); - xmlDocSetRootElement(doc, node); - - /* Add */ - node = xmlNewChild(node, NULL, QP_PACKET_XML, NULL); - xmlNewProp(node, QP_TYPE_XML, (xmlChar *)QP_NAME(qp->qp_type)); - snprintf(tmpstr, 32, "%d", qp->qp_seq); - xmlNewProp(node, QP_SEQ_XML, (xmlChar *)tmpstr); - - if (qa_pi[qp->qp_type].pi_string) { - qa_pi[qp->qp_type].pi_string(node, qp); - } - xmlDocDumpMemory(doc, (xmlChar **)qpstr, qpsize); - xmlFreeDoc(doc); - return *qpstr; -} - -/* - * Packet construction functions - */ -struct qa_packet * -make_qp_hello(char *greeting) -{ - struct qa_packet *qp; - - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_HELLO; - qp->qp_hello.qp_greeting = strdup(greeting); - - return qp; -} - -struct qa_packet * -make_qp_returncode(int rc, int eno, char *strerr) -{ - struct qa_packet *qp; - - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_RETURNCODE; - qp->qp_returncode.qp_rc = rc; - qp->qp_returncode.qp_errno = eno; - qp->qp_returncode.qp_strerror = strdup(strerr); - - return qp; -} - -struct qa_packet * -make_qp_ack(enum qa_packet_type t, int i) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_ACK; - qp->qp_ack.qp_ack_type = t; - qp->qp_ack.qp_ack_seq = i; - - return qp; -} - -struct qa_packet * -make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_RUNCMD; - qp->qp_runcmd.qp_cmdline = strdup(cmdline); - qp->qp_runcmd.qp_stdin_port = p_in; - qp->qp_runcmd.qp_stdout_port = p_out; - qp->qp_runcmd.qp_stderr_port = p_err; - - return qp; -} - -struct qa_packet * -make_qp_cmdexit(pid_t pid, int status) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_CMDEXIT; - qp->qp_cmdexit.qp_pid = pid; - qp->qp_cmdexit.qp_status = status; - - return qp; -} - -struct qa_packet * -make_qp_setuser(char *user, char *group) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_SETUSER; - qp->qp_setuser.qp_user = strdup(user); - if (group) qp->qp_setuser.qp_group = strdup(group); - - return qp; -} - -struct qa_packet * -make_qp_kill(int sig) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_KILL; - qp->qp_kill.qp_sig = sig; - - return qp; -} - -struct qa_packet * -make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_RECVFILE; - qp->qp_recvfile.qp_path = strdup(path); - qp->qp_recvfile.qp_if_port = if_port; - qp->qp_recvfile.qp_count = count; - qp->qp_recvfile.qp_mode = mode; - - return qp; -} - -struct qa_packet * -make_qp_sendfile(const char *path, int of_port, size_t count) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_SENDFILE; - qp->qp_sendfile.qp_path = strdup(path); - qp->qp_sendfile.qp_of_port = of_port; - qp->qp_sendfile.qp_count = count; - return qp; -} - -struct qa_packet * -make_qp_rstat(const char *path, const struct stat *sb) -{ - struct qa_packet *qp; - qp = malloc(sizeof *qp); - assert(qp); - memset(qp, 0, sizeof *qp); - - qp->qp_type = QP_RSTAT; - qp->qp_rstat.qp_path = strdup(path); - if (sb) { - qp->qp_rstat.qp_st_mode = sb->st_mode; - qp->qp_rstat.qp_st_uid = sb->st_uid; - qp->qp_rstat.qp_st_gid = sb->st_gid; - qp->qp_rstat.qp_st_size = sb->st_size; - } - return qp; -} - -/* - * Packet deallocation functions - */ -#define condfree(x) if (x) { free(x); } -void -free_qp_hello(struct qa_packet *qp) -{ - condfree(qp->qp_hello.qp_greeting); -} - -void -free_qp_returncode(struct qa_packet *qp) -{ - condfree(qp->qp_returncode.qp_strerror); -} -void -free_qp_runcmd(struct qa_packet *qp) -{ - condfree(qp->qp_runcmd.qp_cmdline); -} - -void -free_qp_setuser(struct qa_packet *qp) -{ - condfree(qp->qp_setuser.qp_user); - condfree(qp->qp_setuser.qp_group); -} - -void -free_qp_recvfile(struct qa_packet *qp) -{ - condfree(qp->qp_recvfile.qp_path); -} - -void -free_qp_sendfile(struct qa_packet *qp) -{ - condfree(qp->qp_sendfile.qp_path); -} - -void -free_qp_rstat(struct qa_packet *qp) -{ - condfree(qp->qp_rstat.qp_path); -} - - -void -qpfree(struct qa_packet *qp) -{ - if (qp) { - if (qa_pi[qp->qp_type].pi_free) { - qa_pi[qp->qp_type].pi_free(qp); - } - free(qp); - } -} -#undef condfree - -/* - * Packet printing functions - * - * For printing out packets for debugging purposes - */ -void -dump_qp_ack(struct qa_packet *qp) -{ - printf("\t%s #%d\n", QP_NAME(qp->qp_ack.qp_ack_type), - qp->qp_ack.qp_ack_seq); -} - -void -dump_qp_runcmd(struct qa_packet *qp) -{ - printf("\tcmdline: %s\n", qp->qp_runcmd.qp_cmdline); -} - -void -dump_qp_returncode(struct qa_packet *qp) -{ - printf("\trc: %d\n", qp->qp_returncode.qp_rc); -} - -void -dump_qp_cmdexit(struct qa_packet *qp) -{ - if (WIFEXITED(qp->qp_cmdexit.qp_status)) { - printf("\texited: %d\n", WEXITSTATUS(qp->qp_cmdexit.qp_status)); - } else if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) { - printf("\tsignaled: %d\n", WTERMSIG(qp->qp_cmdexit.qp_status)); - } else { - printf("\tstatus: %d\n", qp->qp_cmdexit.qp_status); - } -} - -void -dump_qp_setuser(struct qa_packet *qp) -{ - printf("\tuser: %s\n", qp->qp_setuser.qp_user); - printf("\tgroup: %s\n", qp->qp_setuser.qp_group); -} - -void -dump_qp_kill(struct qa_packet *qp) -{ - printf("\tsig: %d\n", qp->qp_kill.qp_sig); -} - -void -dump_qp_recvfile(struct qa_packet *qp) -{ - printf("\tpath: %s\n", qp->qp_recvfile.qp_path); - printf("\tif_port: %d\n", qp->qp_recvfile.qp_if_port); - printf("\tcount: %d\n", qp->qp_recvfile.qp_count); - printf("\tmode: %o\n", qp->qp_recvfile.qp_mode); -} - -void -dump_qp_sendfile(struct qa_packet *qp) -{ - printf("\tpath: %s\n", qp->qp_sendfile.qp_path); - printf("\tof_port: %d\n", qp->qp_sendfile.qp_of_port); - printf("\tcount: %d\n", qp->qp_sendfile.qp_count); -} - -void -dump_qp_rstat(struct qa_packet *qp) -{ - printf("\tpath: %s\n", qp->qp_rstat.qp_path); - printf("\tst_mode: %o\n", qp->qp_rstat.qp_st_mode); - printf("\tst_uid: %d\n", qp->qp_rstat.qp_st_uid); - printf("\tst_gid: %d\n", qp->qp_rstat.qp_st_gid); - printf("\tst_size: %ld\n", qp->qp_rstat.qp_st_size); -} - -void -dump_qp(struct qa_packet *qp) -{ - printf("%s #%d\n", QP_NAME(qp->qp_type), qp->qp_seq); - if (qa_pi[qp->qp_type].pi_dump) { - qa_pi[qp->qp_type].pi_dump(qp); - } -} diff --git a/qarsh/qarsh_packet.h b/qarsh/qarsh_packet.h deleted file mode 100644 index c4316fd..0000000 --- a/qarsh/qarsh_packet.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef _QARSH_PACKET_H -# define _QARSH_PACKET_H 1 - -#include -#include - -#define QARSH_MAX_PACKET_SIZE 32*1024 - -enum qa_packet_type { - QP_INVALID = 0, - QP_HELLO = 1, - QP_RETURNCODE = 2, - QP_RUNCMD = 3, - QP_ACK = 4, - QP_CMDEXIT = 5, - QP_SETUSER = 6, - QP_KILL = 7, - QP_RECVFILE = 8, - QP_SENDFILE = 9, - QP_RSTAT = 10 -}; - -struct qp_hello_pkt { - char *qp_greeting; -}; - -struct qp_returncode_pkt { - int qp_rc; - int qp_errno; - char *qp_strerror; -}; - -struct qp_runcmd_pkt { - char *qp_cmdline; - int qp_stdin_port; - int qp_stdout_port; - int qp_stderr_port; -}; - -/* General packet for acknowledging a command worked */ -struct qp_ack_pkt { - enum qa_packet_type qp_ack_type; - int qp_ack_seq; -}; - -struct qp_cmdexit_pkt { - pid_t qp_pid; - int qp_status; -}; - -struct qp_setuser_pkt { - char *qp_user; - char *qp_group; -}; - -struct qp_kill_pkt { - int qp_sig; -}; - -struct qp_recvfile_pkt { - char *qp_path; - mode_t qp_mode; - int qp_if_port; - size_t qp_count; -}; - -struct qp_sendfile_pkt { - char *qp_path; - int qp_of_port; - size_t qp_count; -}; - -struct qp_rstat_pkt { - char *qp_path; - mode_t qp_st_mode; - uid_t qp_st_uid; - gid_t qp_st_gid; - off_t qp_st_size; -}; - - -#define QP_VERSION 1 - -struct qa_packet { - enum qa_packet_type qp_type; - int qp_seq; /* Sequence number for this packet */ - union { - struct qp_hello_pkt hello; - struct qp_returncode_pkt returncode; - struct qp_runcmd_pkt runcmd; - struct qp_ack_pkt ack; - struct qp_cmdexit_pkt cmdexit; - struct qp_setuser_pkt setuser; - struct qp_kill_pkt kill; - struct qp_recvfile_pkt recvfile; - struct qp_sendfile_pkt sendfile; - struct qp_rstat_pkt rstat; - } qp_u; -}; - -#define qp_hello qp_u.hello -#define qp_returncode qp_u.returncode -#define qp_runcmd qp_u.runcmd -#define qp_ack qp_u.ack -#define qp_cmdexit qp_u.cmdexit -#define qp_setuser qp_u.setuser -#define qp_kill qp_u.kill -#define qp_recvfile qp_u.recvfile -#define qp_sendfile qp_u.sendfile -#define qp_rstat qp_u.rstat - -/* Prototypes */ -char *qp_packet_type(enum qa_packet_type t); -struct qa_packet *parse_packets(char *buf, int n); -struct qa_packet *make_qp_hello(char *greeting); -struct qa_packet *make_qp_returncode(int rc, int eno, char *strerr); -struct qa_packet *make_qp_ack(enum qa_packet_type t, int i); -struct qa_packet *make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err); -struct qa_packet *make_qp_cmdexit(pid_t pid, int status); -struct qa_packet *make_qp_setuser(char *user, char *group); -struct qa_packet *make_qp_kill(int sig); -struct qa_packet *make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode); -struct qa_packet *make_qp_sendfile(const char *path, int of_port, size_t count); -struct qa_packet *make_qp_rstat(const char *path, const struct stat *sb); -char *qptostr(struct qa_packet *qp, char **qpstr, int *qpsize); -void qpfree(struct qa_packet *qp); -void dump_qp(struct qa_packet *qp); - -#endif /* !_QARSH_PACKET_H */ diff --git a/qarsh/qarshd.c b/qarsh/qarshd.c deleted file mode 100644 index ee9e556..0000000 --- a/qarsh/qarshd.c +++ /dev/null @@ -1,315 +0,0 @@ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "sockutil.h" -#include "qarsh_packet.h" - -/* - * QA Remote Shell Daemon - */ - - -/* Globals */ -struct sockaddr_in peername; -int child_exitted = 0; - -int -setup_user(char *user, char *group) -{ - struct passwd *pw; - struct group *grp; - - if ((pw = getpwnam(user)) == NULL) { - syslog(LOG_WARNING, "User \"%s\" not found\n", user); - return 0; - } - - if (group && (grp = getgrnam(group))) { - setgid(grp->gr_gid); - initgroups(pw->pw_name, grp->gr_gid); - } else { - setgid(pw->pw_gid); - initgroups(pw->pw_name, pw->pw_gid); - } - /* setuid is last so we can still do setgid and initgroups */ - setuid(pw->pw_uid); - return 1; -} - -void -sig_handler(int sig) -{ - if (sig == SIGCHLD) child_exitted++; -} - -pid_t -run_cmd(const char *cmd, int p_in, int p_out, int p_err) -{ - pid_t pid; - int new_in, new_out, new_err; - - syslog(LOG_INFO, "Running cmdline: %s\n", cmd); - if ((pid = fork()) < 0) { - syslog(LOG_WARNING, - "Could not fork() in run_cmd(): %s\n", strerror(errno)); - exit(1); - } - - if (pid == 0) { /* child */ - setpgrp(); - - /* Connect stdin, stdout, and stderr to qarsh */ - new_in = connect_to_peer(&peername, p_in); - if (new_in == -1) syslog(LOG_WARNING, "connect to new_in failed"); - dup2(new_in, fileno(stdin)); - new_out = connect_to_peer(&peername, p_out); - if (new_out == -1) syslog(LOG_WARNING, "connect to new_out failed"); - dup2(new_out, fileno(stdout)); - new_err = connect_to_peer(&peername, p_err); - if (new_err == -1) syslog(LOG_WARNING, "connect to new_err failed"); - dup2(new_err, fileno(stderr)); - - execlp("sh", "sh", "-c", cmd, NULL); - printf("exec of %s failed: %d, %s\n", cmd, errno, strerror(errno)); - exit(127); - } - return pid; -} - -ssize_t -recvfile(const char *path, int if_port, size_t count, mode_t mode) -{ - int sd; - int ofd; - char buf[BUFSIZ]; - ssize_t nread; - ssize_t nwrote; - ssize_t nleft; - - /* Read count bytes from ifd (sd after we connect), - * write into file @ path - */ - - sd = connect_to_peer(&peername, if_port); - if (sd == -1) { - syslog(LOG_WARNING, "connect to if_port failed\n"); - return -1; - } - - if ((ofd = open(path, O_TRUNC|O_CREAT|O_WRONLY, mode)) < 0) { - syslog(LOG_WARNING, "Could not open %s to recv file: %s\n", - path, strerror(errno)); - return -1; - } - - fchmod(ofd, mode); - - nleft = count; - while (nleft > 0) { - nread = read(sd, buf, BUFSIZ); - if (nread < 0) { - return nread; - } else if (nread == 0) { /* EOF */ - break; - } - - nwrote = write(ofd, buf, nread); - nleft -= nread; - } - - if (nleft != 0) { - unlink(path); - syslog(LOG_WARNING, "Short file transfer in recvfile(), " - "%d bytes lost, wanted %d\n", nleft, count); - } - - close(sd); - close(ofd); - - return count - nleft; -} - -struct qa_packet * -rstat(const char *path) -{ - struct stat sb; - struct qa_packet *rp; - - if (stat(path, &sb) < 0) { - rp = make_qp_returncode(-1, errno, strerror(errno)); - } else { - rp = make_qp_rstat(path, &sb); - } - - return rp; -} - -void -handle_packets(int infd) -{ - fd_set rfds; - int nfd; - struct timespec timeout; - struct qa_packet *qp = NULL, *rp = NULL; - sigset_t sigmask, orig_sigmask; - struct sigaction sa; - - pid_t child_pid = 0; - int child_status; - ssize_t nbytes; - - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigmask, &orig_sigmask); - sa.sa_handler = sig_handler; - sa.sa_mask = sigmask; - sa.sa_flags = SA_RESTART; - sigaction(SIGCHLD, &sa, NULL); - - for (;;) { - FD_SET(infd, &rfds); - timeout.tv_sec = 3; - - nfd = pselect(infd+1, &rfds, NULL, NULL, &timeout, &orig_sigmask); - - if (child_exitted) { - waitpid(child_pid, &child_status, 0); - child_exitted--; - rp = make_qp_cmdexit(child_pid, child_status); - send_packet(fileno(stdout), rp); - qpfree(rp); - } - - if (nfd < 0) { - if (errno == EINTR) { - /* signals handled above here */ - continue; - } else { - syslog(LOG_ERR, "select errno %d, %s\n", - errno, strerror(errno)); - } - } else if (nfd > 0) { - qp = recv_packet(infd); - if (qp == NULL) { - syslog(LOG_INFO, "That's enough\n"); - break; - } - switch (qp->qp_type) { - case QP_KILL: - if (child_pid) { - - syslog(LOG_INFO, "Sending child %d signal %d", - child_pid, qp->qp_kill.qp_sig); - kill(child_pid * -1, qp->qp_kill.qp_sig); - } - break; - case QP_SETUSER: - if (setup_user(qp->qp_setuser.qp_user, - qp->qp_setuser.qp_group) == 0) { - rp = make_qp_returncode(-1, 0, "User not found"); - } else { - rp = make_qp_ack(QP_SETUSER, 1); - } - send_packet(fileno(stdout), rp); - qpfree(rp); - break; - case QP_RUNCMD: - child_pid = run_cmd(qp->qp_runcmd.qp_cmdline, - qp->qp_runcmd.qp_stdin_port, - qp->qp_runcmd.qp_stdout_port, - qp->qp_runcmd.qp_stderr_port); - break; - case QP_RECVFILE: - syslog(LOG_INFO, "Got a QP_RECVFILE with path = %s, " - "ifd = %d, count = %d, mode = %o\n", - qp->qp_recvfile.qp_path, - qp->qp_recvfile.qp_if_port, - qp->qp_recvfile.qp_count, - qp->qp_recvfile.qp_mode); - nbytes = recvfile(qp->qp_recvfile.qp_path, - qp->qp_recvfile.qp_if_port, - qp->qp_recvfile.qp_count, - qp->qp_recvfile.qp_mode); - if (nbytes < 0) { - rp = make_qp_returncode(-1, errno, strerror(errno)); - } else if (nbytes < qp->qp_recvfile.qp_count) { - char tmpstr[512]; - sprintf(tmpstr, "Excpected %d, wrote %d\n", - qp->qp_recvfile.qp_count, nbytes); - rp = make_qp_returncode(-1, 0, tmpstr); - } else { - rp = make_qp_returncode(0, 0, "Transfer Complete"); - } - send_packet(fileno(stdout), rp); - qpfree(rp); - break; - case QP_SENDFILE: - syslog(LOG_INFO, "Got a QP_SENDFILE with path = %s, " - "ofd = %d, count = %d\n", - qp->qp_sendfile.qp_path, - qp->qp_sendfile.qp_of_port, - qp->qp_sendfile.qp_count); - break; - case QP_RSTAT: - syslog(LOG_INFO, "Got a QP_RSTAT with path = %s\n", - qp->qp_rstat.qp_path); - rp = rstat(qp->qp_rstat.qp_path); - send_packet(fileno(stdout), rp); - qpfree(rp); - break; - default: - syslog(LOG_WARNING, - "Packet type %s unimplemented", - qp_packet_type(qp->qp_type)); - } - } else { - syslog(LOG_DEBUG, "Nothing to do\n"); - } - - } -} - -int -main(int argc, char *argv[]) -{ - int ch; - socklen_t peernamelen; - - openlog("qarshd", LOG_PID, LOG_DAEMON); - - while ((ch = getopt(argc, argv, "")) != -1) { - switch (ch) { - case '?': - default: - printf("unknown option '%c'\n", optopt); - exit(1); - } - } - - /* daemon initialization */ - peernamelen = sizeof peername; - getpeername(0, (struct sockaddr *)&peername, &peernamelen); - syslog(LOG_INFO, "Talking to peer %s:%d", - inet_ntoa(peername.sin_addr), ntohs(peername.sin_port)); - /* Start reading packets from stdin */ - handle_packets(0); - - return 0; -} diff --git a/qarsh/sockutil.c b/qarsh/sockutil.c deleted file mode 100644 index b84e456..0000000 --- a/qarsh/sockutil.c +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qarsh_packet.h" - -/* Some generic socket related functions to make things easier */ - -int -getsockport(int sd) -{ - struct sockaddr_in addr; - socklen_t addrlen; - - addrlen = sizeof addr; - if (getsockname(sd, (struct sockaddr *)&addr, &addrlen) == 0) { - return ntohs(addr.sin_port); - } else { - return -1; - } -} - -int -bind_any(int minport) -{ - int sd; - struct sockaddr_in addr; - - sd = socket(AF_INET, SOCK_STREAM, 0); - if (sd == -1) return -1; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - do { - addr.sin_port = htons(minport++); - } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); - if (listen(sd, 0) == -1) { - syslog(LOG_WARNING, "listen error %d, %s", errno, - strerror(errno)); - } - return sd; -} - -int -connect_to_host(char *hostname, int port) -{ - struct hostent *h; - struct sockaddr_in haddr; - int sd; - - if ((h = gethostbyname(hostname)) == NULL) { - return -1; - } - haddr.sin_family = h->h_addrtype; - haddr.sin_port = htons(port); - memcpy(&haddr.sin_addr, h->h_addr, h->h_length); - - sd = socket(PF_INET, SOCK_STREAM, 0); - if (sd == -1) return -1; - if (connect(sd, (struct sockaddr *)&haddr, sizeof haddr) == -1) { - return -1; - } - return sd; -} - -int -connect_to_peer(struct sockaddr_in *peer, int port) -{ - struct sockaddr_in in_peer; - int sd; - - in_peer.sin_family = AF_INET; - in_peer.sin_port = htons(port); - in_peer.sin_addr = peer->sin_addr; - - sd = socket(PF_INET, SOCK_STREAM, 0); - if (sd == -1) return -1; - if (connect(sd, (struct sockaddr *)&in_peer, sizeof in_peer) == -1) { - return -1; - } - return sd; -} - - -struct qa_packet * -recv_packet(int fd) -{ - char *packetbuf; - int packetsize; - struct qa_packet *qp = NULL; - - packetbuf = malloc(QARSH_MAX_PACKET_SIZE); - memset(packetbuf, 0, QARSH_MAX_PACKET_SIZE); - - packetsize = read(fd, packetbuf, QARSH_MAX_PACKET_SIZE); - if (packetsize > 0) { - qp = parse_packets(packetbuf, packetsize); - } - free(packetbuf); - return qp; -} - -int -send_packet(int fd, struct qa_packet *qp) -{ - char *packetbuf; - int packetsize; - - packetbuf = malloc(1024); - memset(packetbuf, 0, 1024); - packetbuf = qptostr(qp, &packetbuf, &packetsize); - - return write(fd, packetbuf, packetsize); -} diff --git a/qarsh/sockutil.h b/qarsh/sockutil.h deleted file mode 100644 index 6e4b8dd..0000000 --- a/qarsh/sockutil.h +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int getsockport(int sd); -int bind_any(int minport); -int connect_to_host(char *hostname, int port); -int connect_to_peer(struct sockaddr_in *peer, int port); -struct qa_packet * recv_packet(int fd); -int send_packet(int fd, struct qa_packet *qp); diff --git a/qarsh_packet.c b/qarsh_packet.c new file mode 100644 index 0000000..76fadf1 --- /dev/null +++ b/qarsh_packet.c @@ -0,0 +1,850 @@ + +#include +#include +#include + +#include +#include + +#include "qarsh_packet.h" + +/* Prototypes */ +static char *get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query); + +int parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp); +int parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp); + +void string_qp_hello(xmlNodePtr node, struct qa_packet *qp); +void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp); +void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp); +void string_qp_ack(xmlNodePtr node, struct qa_packet *qp); +void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp); +void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp); +void string_qp_kill(xmlNodePtr node, struct qa_packet *qp); +void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp); +void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp); +void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp); + +void free_qp_hello(struct qa_packet *qp); +void free_qp_returncode(struct qa_packet *qp); +void free_qp_runcmd(struct qa_packet *qp); +void free_qp_setuser(struct qa_packet *qp); +void free_qp_recvfile(struct qa_packet *qp); +void free_qp_sendfile(struct qa_packet *qp); +void free_qp_rstat(struct qa_packet *qp); + +void dump_qp_ack(struct qa_packet *qp); +void dump_qp_runcmd(struct qa_packet *qp); +void dump_qp_returncode(struct qa_packet *qp); +void dump_qp_cmdexit(struct qa_packet *qp); +void dump_qp_setuser(struct qa_packet *qp); +void dump_qp_kill(struct qa_packet *qp); +void dump_qp_recvfile(struct qa_packet *qp); +void dump_qp_sendfile(struct qa_packet *qp); +void dump_qp_rstat(struct qa_packet *qp); + + +struct packet_internals { + char *pi_name; + int (*pi_parse)(xmlXPathContextPtr ctxt, struct qa_packet *qp); + void (*pi_string)(xmlNodePtr node, struct qa_packet *qp); + void (*pi_free)(struct qa_packet *qp); + void (*pi_dump)(struct qa_packet *qp); +} qa_pi[] = { + { + .pi_name = "", + .pi_parse = NULL, + .pi_string = NULL, + .pi_free = NULL, + .pi_dump = NULL + + }, { + .pi_name = "hello", + .pi_parse = parse_qp_hello, + .pi_string = string_qp_hello, + .pi_free = free_qp_hello + }, { + .pi_name = "returncode", + .pi_parse = parse_qp_returncode, + .pi_string = string_qp_returncode, + .pi_free = free_qp_returncode, + .pi_dump = dump_qp_returncode + }, { + .pi_name = "runcmd", + .pi_parse = parse_qp_runcmd, + .pi_string = string_qp_runcmd, + .pi_free = free_qp_runcmd, + .pi_dump = dump_qp_runcmd + }, { + .pi_name = "ack", + .pi_parse = parse_qp_ack, + .pi_string = string_qp_ack, + .pi_free = NULL, + .pi_dump = dump_qp_ack + }, { + .pi_name = "cmdexit", + .pi_parse = parse_qp_cmdexit, + .pi_string = string_qp_cmdexit, + .pi_free = NULL, + .pi_dump = dump_qp_cmdexit + }, { + .pi_name = "setuser", + .pi_parse = parse_qp_setuser, + .pi_string = string_qp_setuser, + .pi_free = free_qp_setuser, + .pi_dump = dump_qp_setuser + }, { + .pi_name = "kill", + .pi_parse = parse_qp_kill, + .pi_string = string_qp_kill, + .pi_free = NULL, + .pi_dump = dump_qp_kill + }, { + .pi_name = "recvfile", + .pi_parse = parse_qp_recvfile, + .pi_string = string_qp_recvfile, + .pi_free = free_qp_recvfile, + .pi_dump = dump_qp_recvfile + }, { + .pi_name = "sendfile", + .pi_parse = parse_qp_sendfile, + .pi_string = string_qp_sendfile, + .pi_free = free_qp_sendfile, + .pi_dump = dump_qp_sendfile + }, { + .pi_name = "rstat", + .pi_parse = parse_qp_rstat, + .pi_string = string_qp_rstat, + .pi_free = free_qp_rstat, + .pi_dump = dump_qp_rstat + } +}; + +#define QP_TYPES (sizeof qa_pi / sizeof *qa_pi) +#define QP_NAME(n) qa_pi[n].pi_name + + +/* XML Strings */ +const xmlChar *QP_QARSH_XML = (xmlChar *)"qarsh"; +const xmlChar *QP_PACKET_XML = (xmlChar *)"packet"; +const xmlChar *QP_TYPE_XML = (xmlChar *)"type"; +const xmlChar *QP_PARAM_XML = (xmlChar *)"param"; +const xmlChar *QP_NAME_XML = (xmlChar *)"name"; +const xmlChar *QP_SEQ_XML = (xmlChar *)"seq"; + +enum qa_packet_type +parse_packet_type(char *s) +{ + int i; + for (i = 0; i < QP_TYPES; i++) { + if (strcasecmp(s, QP_NAME(i)) == 0) { + return (enum qa_packet_type)i; + } + } + return QP_INVALID; +} + +char * +qp_packet_type(enum qa_packet_type t) +{ + return QP_NAME(t); +} + + +/* + * Packet parsing functions + */ +int +parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + qp->qp_hello.qp_greeting = get_xpath_string(ctxt, + "param[@name='greeting']"); + return 0; +} + +int +parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + s = get_xpath_string(ctxt, "param[@name='rc']"); + qp->qp_returncode.qp_rc = atoi(s); + free(s); + s = get_xpath_string(ctxt, "param[@name='errno']"); + qp->qp_returncode.qp_errno = atoi(s); + free(s); + qp->qp_returncode.qp_strerror = get_xpath_string(ctxt, + "param[@name='strerror']"); + return 0; +} + +int +parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + qp->qp_runcmd.qp_cmdline = get_xpath_string(ctxt, + "param[@name='cmdline']"); + s = get_xpath_string(ctxt, "param[@name='stdin']"); + qp->qp_runcmd.qp_stdin_port = atoi(s); + free(s); + s = get_xpath_string(ctxt, "param[@name='stdout']"); + qp->qp_runcmd.qp_stdout_port = atoi(s); + free(s); + s = get_xpath_string(ctxt, "param[@name='stderr']"); + qp->qp_runcmd.qp_stderr_port = atoi(s); + free(s); + return 0; +} + +int +parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + s = get_xpath_string(ctxt, "param[@name='type']"); + qp->qp_ack.qp_ack_type = parse_packet_type(s); + free(s); + s = get_xpath_string(ctxt, "param[@name='seq']"); + qp->qp_ack.qp_ack_seq = atoi(s); + free(s); + return 0; +} + +int +parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + + s = get_xpath_string(ctxt, "param[@name='status']"); + qp->qp_cmdexit.qp_status = atoi(s); + free(s); + return 0; +} + +int +parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + qp->qp_setuser.qp_user = get_xpath_string(ctxt, "param[@name='user']"); + qp->qp_setuser.qp_group = get_xpath_string(ctxt, "param[@name='group']"); + return 0; +} + +int +parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + + s = get_xpath_string(ctxt, "param[@name='signal']"); + qp->qp_kill.qp_sig = atoi(s); + free(s); + return 0; +} + +int +parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + + qp->qp_recvfile.qp_path = get_xpath_string(ctxt, "param[@name='path']"); + + s = get_xpath_string(ctxt, "param[@name='if_port']"); + qp->qp_recvfile.qp_if_port = atoi(s); + free(s); + + s = get_xpath_string(ctxt, "param[@name='count']"); + qp->qp_recvfile.qp_count = atoi(s); + free(s); + + s = get_xpath_string(ctxt, "param[@name='mode']"); + qp->qp_recvfile.qp_mode = atoi(s); + free(s); + + return 0; +} + +int +parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + + qp->qp_sendfile.qp_path = get_xpath_string(ctxt, "param[@name='path']"); + s = get_xpath_string(ctxt, "param[@name='of_port']"); + qp->qp_sendfile.qp_of_port = atoi(s); + free(s); + s = get_xpath_string(ctxt, "param[@name='count']"); + qp->qp_sendfile.qp_count = atoi(s); + free(s); + return 0; +} + +int +parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp) +{ + char *s; + + qp->qp_rstat.qp_path = get_xpath_string(ctxt, "param[@name='path']"); + + s = get_xpath_string(ctxt, "param[@name='st_mode']"); + qp->qp_rstat.qp_st_mode = atoi(s); + free(s); + + s = get_xpath_string(ctxt, "param[@name='st_uid']"); + qp->qp_rstat.qp_st_uid = atoi(s); + free(s); + + s = get_xpath_string(ctxt, "param[@name='st_gid']"); + qp->qp_rstat.qp_st_gid = atoi(s); + free(s); + + s = get_xpath_string(ctxt, "param[@name='st_size']"); + qp->qp_rstat.qp_st_size = atol(s); + free(s); + + return 0; +} + + +struct qa_packet * +parse_packet(xmlXPathContextPtr ctxt) +{ + struct qa_packet *qp = NULL; + char *s; + + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + s = get_xpath_string(ctxt, "@type"); + qp->qp_type = parse_packet_type(s); + free(s); + s = get_xpath_string(ctxt, "@seq"); + qp->qp_seq = atoi(s); + free(s); + + if (qa_pi[qp->qp_type].pi_parse) + qa_pi[qp->qp_type].pi_parse(ctxt, qp); + else { + printf("Packet type %s not implemented yet\n", s); + free(qp); + qp = NULL; + } + return qp; +} + +struct qa_packet * +parse_packets(char *buf, int n) +{ + xmlDocPtr doc; + xmlXPathContextPtr context; + xmlXPathObjectPtr obj = NULL; + struct qa_packet *qp = NULL; + + doc = xmlParseMemory(buf, n); + + /* If we can't parse the packet, we don't care about it */ + if (doc == NULL) return NULL; + + context = xmlXPathNewContext(doc); + obj = xmlXPathEvalExpression((xmlChar *)"//packet", context); + if (obj == NULL) { + printf("didn't find anything\n"); + goto free_context; + } + if (obj->type != XPATH_NODESET || obj->nodesetval->nodeNr == 0) { + printf("didn't find anything\n"); + goto free_obj; + } + if (obj->nodesetval->nodeNr > 1) { + printf("One packet at a time please!\n"); + } + context->node = xmlXPathNodeSetItem(obj->nodesetval, 0); + qp = parse_packet(context); + +free_obj: + xmlXPathFreeObject(obj); +free_context: + xmlXPathFreeContext(context); + xmlFreeDoc(doc); + return qp; +} + + +static char * +get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query) +{ + xmlXPathObjectPtr obj = NULL; + char querystr[512]; + char *ret; + + snprintf(querystr, 512, "string(%s)", xpath_query); + obj = xmlXPathEvalExpression((xmlChar *)querystr, ctxt); + + if (obj == NULL) return NULL; + if (obj->type != XPATH_STRING) { + xmlXPathFreeObject(obj); + return NULL; + } + + ret = strdup((char *)obj->stringval); + xmlXPathFreeObject(obj); + return ret; +} + +/* + * Packet serialization functions + * + * for converting structs to XML + */ +xmlNodePtr +make_param(char *name, char *value) +{ + xmlNodePtr param = xmlNewNode(NULL, QP_PARAM_XML); + xmlNewProp(param, QP_NAME_XML, (xmlChar *)name); + xmlNodeSetContent(param, xmlEncodeSpecialChars(NULL, (xmlChar *)value)); + return param; +} + +void string_qp_hello(xmlNodePtr node, struct qa_packet *qp) +{ + xmlAddChild(node, make_param("greeting", qp->qp_hello.qp_greeting)); +} +void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_rc); + xmlAddChild(node, make_param("rc", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_errno); + xmlAddChild(node, make_param("errno", tmpstr)); + xmlAddChild(node, make_param("strerror", qp->qp_returncode.qp_strerror)); +} +void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + xmlAddChild(node, make_param("cmdline", qp->qp_runcmd.qp_cmdline)); + snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdin_port); + xmlAddChild(node, make_param("stdin", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdout_port); + xmlAddChild(node, make_param("stdout", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stderr_port); + xmlAddChild(node, make_param("stderr", tmpstr)); +} +void string_qp_ack(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + xmlAddChild(node, make_param("type", + QP_NAME(qp->qp_ack.qp_ack_type))); + snprintf(tmpstr, 32, "%d", qp->qp_ack.qp_ack_seq); + xmlAddChild(node, make_param("seq", tmpstr)); +} + +void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_pid); + xmlAddChild(node, make_param("pid", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_status); + xmlAddChild(node, make_param("status", tmpstr)); +} + +void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp) +{ + xmlAddChild(node, make_param("user", qp->qp_setuser.qp_user)); + if (qp->qp_setuser.qp_group) { + xmlAddChild(node, make_param("group", qp->qp_setuser.qp_group)); + } +} + +void string_qp_kill(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + snprintf(tmpstr, 32, "%d", qp->qp_kill.qp_sig); + xmlAddChild(node, make_param("signal", tmpstr)); +} + +void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + xmlAddChild(node, make_param("path", qp->qp_recvfile.qp_path)); + + snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_if_port); + xmlAddChild(node, make_param("if_port", tmpstr)); + + snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_count); + xmlAddChild(node, make_param("count", tmpstr)); + + snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_mode); + xmlAddChild(node, make_param("mode", tmpstr)); +} + +void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + xmlAddChild(node, make_param("path", qp->qp_sendfile.qp_path)); + snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_of_port); + xmlAddChild(node, make_param("of_port", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_count); + xmlAddChild(node, make_param("count", tmpstr)); +} + +void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp) +{ + char tmpstr[32]; + + xmlAddChild(node, make_param("path", qp->qp_rstat.qp_path)); + snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_mode); + xmlAddChild(node, make_param("st_mode", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_uid); + xmlAddChild(node, make_param("st_uid", tmpstr)); + snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_gid); + xmlAddChild(node, make_param("st_gid", tmpstr)); + snprintf(tmpstr, 32, "%ld", qp->qp_rstat.qp_st_size); + xmlAddChild(node, make_param("st_size", tmpstr)); +} + +/* Must pass in a pointer, but not a malloc'ed pointer */ +char * +qptostr(struct qa_packet *qp, char **qpstr, int *qpsize) +{ + xmlDocPtr doc; + xmlNodePtr node; + char tmpstr[32]; + + if (qp->qp_type == QP_INVALID) return NULL; + + doc = xmlNewDoc((xmlChar *)XML_DEFAULT_VERSION); + + /* Add */ + node = xmlNewDocNode(doc, NULL, QP_QARSH_XML, NULL); + xmlDocSetRootElement(doc, node); + + /* Add */ + node = xmlNewChild(node, NULL, QP_PACKET_XML, NULL); + xmlNewProp(node, QP_TYPE_XML, (xmlChar *)QP_NAME(qp->qp_type)); + snprintf(tmpstr, 32, "%d", qp->qp_seq); + xmlNewProp(node, QP_SEQ_XML, (xmlChar *)tmpstr); + + if (qa_pi[qp->qp_type].pi_string) { + qa_pi[qp->qp_type].pi_string(node, qp); + } + xmlDocDumpMemory(doc, (xmlChar **)qpstr, qpsize); + xmlFreeDoc(doc); + return *qpstr; +} + +/* + * Packet construction functions + */ +struct qa_packet * +make_qp_hello(char *greeting) +{ + struct qa_packet *qp; + + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_HELLO; + qp->qp_hello.qp_greeting = strdup(greeting); + + return qp; +} + +struct qa_packet * +make_qp_returncode(int rc, int eno, char *strerr) +{ + struct qa_packet *qp; + + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_RETURNCODE; + qp->qp_returncode.qp_rc = rc; + qp->qp_returncode.qp_errno = eno; + qp->qp_returncode.qp_strerror = strdup(strerr); + + return qp; +} + +struct qa_packet * +make_qp_ack(enum qa_packet_type t, int i) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_ACK; + qp->qp_ack.qp_ack_type = t; + qp->qp_ack.qp_ack_seq = i; + + return qp; +} + +struct qa_packet * +make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_RUNCMD; + qp->qp_runcmd.qp_cmdline = strdup(cmdline); + qp->qp_runcmd.qp_stdin_port = p_in; + qp->qp_runcmd.qp_stdout_port = p_out; + qp->qp_runcmd.qp_stderr_port = p_err; + + return qp; +} + +struct qa_packet * +make_qp_cmdexit(pid_t pid, int status) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_CMDEXIT; + qp->qp_cmdexit.qp_pid = pid; + qp->qp_cmdexit.qp_status = status; + + return qp; +} + +struct qa_packet * +make_qp_setuser(char *user, char *group) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_SETUSER; + qp->qp_setuser.qp_user = strdup(user); + if (group) qp->qp_setuser.qp_group = strdup(group); + + return qp; +} + +struct qa_packet * +make_qp_kill(int sig) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_KILL; + qp->qp_kill.qp_sig = sig; + + return qp; +} + +struct qa_packet * +make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_RECVFILE; + qp->qp_recvfile.qp_path = strdup(path); + qp->qp_recvfile.qp_if_port = if_port; + qp->qp_recvfile.qp_count = count; + qp->qp_recvfile.qp_mode = mode; + + return qp; +} + +struct qa_packet * +make_qp_sendfile(const char *path, int of_port, size_t count) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_SENDFILE; + qp->qp_sendfile.qp_path = strdup(path); + qp->qp_sendfile.qp_of_port = of_port; + qp->qp_sendfile.qp_count = count; + return qp; +} + +struct qa_packet * +make_qp_rstat(const char *path, const struct stat *sb) +{ + struct qa_packet *qp; + qp = malloc(sizeof *qp); + assert(qp); + memset(qp, 0, sizeof *qp); + + qp->qp_type = QP_RSTAT; + qp->qp_rstat.qp_path = strdup(path); + if (sb) { + qp->qp_rstat.qp_st_mode = sb->st_mode; + qp->qp_rstat.qp_st_uid = sb->st_uid; + qp->qp_rstat.qp_st_gid = sb->st_gid; + qp->qp_rstat.qp_st_size = sb->st_size; + } + return qp; +} + +/* + * Packet deallocation functions + */ +#define condfree(x) if (x) { free(x); } +void +free_qp_hello(struct qa_packet *qp) +{ + condfree(qp->qp_hello.qp_greeting); +} + +void +free_qp_returncode(struct qa_packet *qp) +{ + condfree(qp->qp_returncode.qp_strerror); +} +void +free_qp_runcmd(struct qa_packet *qp) +{ + condfree(qp->qp_runcmd.qp_cmdline); +} + +void +free_qp_setuser(struct qa_packet *qp) +{ + condfree(qp->qp_setuser.qp_user); + condfree(qp->qp_setuser.qp_group); +} + +void +free_qp_recvfile(struct qa_packet *qp) +{ + condfree(qp->qp_recvfile.qp_path); +} + +void +free_qp_sendfile(struct qa_packet *qp) +{ + condfree(qp->qp_sendfile.qp_path); +} + +void +free_qp_rstat(struct qa_packet *qp) +{ + condfree(qp->qp_rstat.qp_path); +} + + +void +qpfree(struct qa_packet *qp) +{ + if (qp) { + if (qa_pi[qp->qp_type].pi_free) { + qa_pi[qp->qp_type].pi_free(qp); + } + free(qp); + } +} +#undef condfree + +/* + * Packet printing functions + * + * For printing out packets for debugging purposes + */ +void +dump_qp_ack(struct qa_packet *qp) +{ + printf("\t%s #%d\n", QP_NAME(qp->qp_ack.qp_ack_type), + qp->qp_ack.qp_ack_seq); +} + +void +dump_qp_runcmd(struct qa_packet *qp) +{ + printf("\tcmdline: %s\n", qp->qp_runcmd.qp_cmdline); +} + +void +dump_qp_returncode(struct qa_packet *qp) +{ + printf("\trc: %d\n", qp->qp_returncode.qp_rc); +} + +void +dump_qp_cmdexit(struct qa_packet *qp) +{ + if (WIFEXITED(qp->qp_cmdexit.qp_status)) { + printf("\texited: %d\n", WEXITSTATUS(qp->qp_cmdexit.qp_status)); + } else if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) { + printf("\tsignaled: %d\n", WTERMSIG(qp->qp_cmdexit.qp_status)); + } else { + printf("\tstatus: %d\n", qp->qp_cmdexit.qp_status); + } +} + +void +dump_qp_setuser(struct qa_packet *qp) +{ + printf("\tuser: %s\n", qp->qp_setuser.qp_user); + printf("\tgroup: %s\n", qp->qp_setuser.qp_group); +} + +void +dump_qp_kill(struct qa_packet *qp) +{ + printf("\tsig: %d\n", qp->qp_kill.qp_sig); +} + +void +dump_qp_recvfile(struct qa_packet *qp) +{ + printf("\tpath: %s\n", qp->qp_recvfile.qp_path); + printf("\tif_port: %d\n", qp->qp_recvfile.qp_if_port); + printf("\tcount: %d\n", qp->qp_recvfile.qp_count); + printf("\tmode: %o\n", qp->qp_recvfile.qp_mode); +} + +void +dump_qp_sendfile(struct qa_packet *qp) +{ + printf("\tpath: %s\n", qp->qp_sendfile.qp_path); + printf("\tof_port: %d\n", qp->qp_sendfile.qp_of_port); + printf("\tcount: %d\n", qp->qp_sendfile.qp_count); +} + +void +dump_qp_rstat(struct qa_packet *qp) +{ + printf("\tpath: %s\n", qp->qp_rstat.qp_path); + printf("\tst_mode: %o\n", qp->qp_rstat.qp_st_mode); + printf("\tst_uid: %d\n", qp->qp_rstat.qp_st_uid); + printf("\tst_gid: %d\n", qp->qp_rstat.qp_st_gid); + printf("\tst_size: %ld\n", qp->qp_rstat.qp_st_size); +} + +void +dump_qp(struct qa_packet *qp) +{ + printf("%s #%d\n", QP_NAME(qp->qp_type), qp->qp_seq); + if (qa_pi[qp->qp_type].pi_dump) { + qa_pi[qp->qp_type].pi_dump(qp); + } +} diff --git a/qarsh_packet.h b/qarsh_packet.h new file mode 100644 index 0000000..c4316fd --- /dev/null +++ b/qarsh_packet.h @@ -0,0 +1,129 @@ +#ifndef _QARSH_PACKET_H +# define _QARSH_PACKET_H 1 + +#include +#include + +#define QARSH_MAX_PACKET_SIZE 32*1024 + +enum qa_packet_type { + QP_INVALID = 0, + QP_HELLO = 1, + QP_RETURNCODE = 2, + QP_RUNCMD = 3, + QP_ACK = 4, + QP_CMDEXIT = 5, + QP_SETUSER = 6, + QP_KILL = 7, + QP_RECVFILE = 8, + QP_SENDFILE = 9, + QP_RSTAT = 10 +}; + +struct qp_hello_pkt { + char *qp_greeting; +}; + +struct qp_returncode_pkt { + int qp_rc; + int qp_errno; + char *qp_strerror; +}; + +struct qp_runcmd_pkt { + char *qp_cmdline; + int qp_stdin_port; + int qp_stdout_port; + int qp_stderr_port; +}; + +/* General packet for acknowledging a command worked */ +struct qp_ack_pkt { + enum qa_packet_type qp_ack_type; + int qp_ack_seq; +}; + +struct qp_cmdexit_pkt { + pid_t qp_pid; + int qp_status; +}; + +struct qp_setuser_pkt { + char *qp_user; + char *qp_group; +}; + +struct qp_kill_pkt { + int qp_sig; +}; + +struct qp_recvfile_pkt { + char *qp_path; + mode_t qp_mode; + int qp_if_port; + size_t qp_count; +}; + +struct qp_sendfile_pkt { + char *qp_path; + int qp_of_port; + size_t qp_count; +}; + +struct qp_rstat_pkt { + char *qp_path; + mode_t qp_st_mode; + uid_t qp_st_uid; + gid_t qp_st_gid; + off_t qp_st_size; +}; + + +#define QP_VERSION 1 + +struct qa_packet { + enum qa_packet_type qp_type; + int qp_seq; /* Sequence number for this packet */ + union { + struct qp_hello_pkt hello; + struct qp_returncode_pkt returncode; + struct qp_runcmd_pkt runcmd; + struct qp_ack_pkt ack; + struct qp_cmdexit_pkt cmdexit; + struct qp_setuser_pkt setuser; + struct qp_kill_pkt kill; + struct qp_recvfile_pkt recvfile; + struct qp_sendfile_pkt sendfile; + struct qp_rstat_pkt rstat; + } qp_u; +}; + +#define qp_hello qp_u.hello +#define qp_returncode qp_u.returncode +#define qp_runcmd qp_u.runcmd +#define qp_ack qp_u.ack +#define qp_cmdexit qp_u.cmdexit +#define qp_setuser qp_u.setuser +#define qp_kill qp_u.kill +#define qp_recvfile qp_u.recvfile +#define qp_sendfile qp_u.sendfile +#define qp_rstat qp_u.rstat + +/* Prototypes */ +char *qp_packet_type(enum qa_packet_type t); +struct qa_packet *parse_packets(char *buf, int n); +struct qa_packet *make_qp_hello(char *greeting); +struct qa_packet *make_qp_returncode(int rc, int eno, char *strerr); +struct qa_packet *make_qp_ack(enum qa_packet_type t, int i); +struct qa_packet *make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err); +struct qa_packet *make_qp_cmdexit(pid_t pid, int status); +struct qa_packet *make_qp_setuser(char *user, char *group); +struct qa_packet *make_qp_kill(int sig); +struct qa_packet *make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode); +struct qa_packet *make_qp_sendfile(const char *path, int of_port, size_t count); +struct qa_packet *make_qp_rstat(const char *path, const struct stat *sb); +char *qptostr(struct qa_packet *qp, char **qpstr, int *qpsize); +void qpfree(struct qa_packet *qp); +void dump_qp(struct qa_packet *qp); + +#endif /* !_QARSH_PACKET_H */ diff --git a/qarshd.c b/qarshd.c new file mode 100644 index 0000000..ee9e556 --- /dev/null +++ b/qarshd.c @@ -0,0 +1,315 @@ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "sockutil.h" +#include "qarsh_packet.h" + +/* + * QA Remote Shell Daemon + */ + + +/* Globals */ +struct sockaddr_in peername; +int child_exitted = 0; + +int +setup_user(char *user, char *group) +{ + struct passwd *pw; + struct group *grp; + + if ((pw = getpwnam(user)) == NULL) { + syslog(LOG_WARNING, "User \"%s\" not found\n", user); + return 0; + } + + if (group && (grp = getgrnam(group))) { + setgid(grp->gr_gid); + initgroups(pw->pw_name, grp->gr_gid); + } else { + setgid(pw->pw_gid); + initgroups(pw->pw_name, pw->pw_gid); + } + /* setuid is last so we can still do setgid and initgroups */ + setuid(pw->pw_uid); + return 1; +} + +void +sig_handler(int sig) +{ + if (sig == SIGCHLD) child_exitted++; +} + +pid_t +run_cmd(const char *cmd, int p_in, int p_out, int p_err) +{ + pid_t pid; + int new_in, new_out, new_err; + + syslog(LOG_INFO, "Running cmdline: %s\n", cmd); + if ((pid = fork()) < 0) { + syslog(LOG_WARNING, + "Could not fork() in run_cmd(): %s\n", strerror(errno)); + exit(1); + } + + if (pid == 0) { /* child */ + setpgrp(); + + /* Connect stdin, stdout, and stderr to qarsh */ + new_in = connect_to_peer(&peername, p_in); + if (new_in == -1) syslog(LOG_WARNING, "connect to new_in failed"); + dup2(new_in, fileno(stdin)); + new_out = connect_to_peer(&peername, p_out); + if (new_out == -1) syslog(LOG_WARNING, "connect to new_out failed"); + dup2(new_out, fileno(stdout)); + new_err = connect_to_peer(&peername, p_err); + if (new_err == -1) syslog(LOG_WARNING, "connect to new_err failed"); + dup2(new_err, fileno(stderr)); + + execlp("sh", "sh", "-c", cmd, NULL); + printf("exec of %s failed: %d, %s\n", cmd, errno, strerror(errno)); + exit(127); + } + return pid; +} + +ssize_t +recvfile(const char *path, int if_port, size_t count, mode_t mode) +{ + int sd; + int ofd; + char buf[BUFSIZ]; + ssize_t nread; + ssize_t nwrote; + ssize_t nleft; + + /* Read count bytes from ifd (sd after we connect), + * write into file @ path + */ + + sd = connect_to_peer(&peername, if_port); + if (sd == -1) { + syslog(LOG_WARNING, "connect to if_port failed\n"); + return -1; + } + + if ((ofd = open(path, O_TRUNC|O_CREAT|O_WRONLY, mode)) < 0) { + syslog(LOG_WARNING, "Could not open %s to recv file: %s\n", + path, strerror(errno)); + return -1; + } + + fchmod(ofd, mode); + + nleft = count; + while (nleft > 0) { + nread = read(sd, buf, BUFSIZ); + if (nread < 0) { + return nread; + } else if (nread == 0) { /* EOF */ + break; + } + + nwrote = write(ofd, buf, nread); + nleft -= nread; + } + + if (nleft != 0) { + unlink(path); + syslog(LOG_WARNING, "Short file transfer in recvfile(), " + "%d bytes lost, wanted %d\n", nleft, count); + } + + close(sd); + close(ofd); + + return count - nleft; +} + +struct qa_packet * +rstat(const char *path) +{ + struct stat sb; + struct qa_packet *rp; + + if (stat(path, &sb) < 0) { + rp = make_qp_returncode(-1, errno, strerror(errno)); + } else { + rp = make_qp_rstat(path, &sb); + } + + return rp; +} + +void +handle_packets(int infd) +{ + fd_set rfds; + int nfd; + struct timespec timeout; + struct qa_packet *qp = NULL, *rp = NULL; + sigset_t sigmask, orig_sigmask; + struct sigaction sa; + + pid_t child_pid = 0; + int child_status; + ssize_t nbytes; + + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigmask, &orig_sigmask); + sa.sa_handler = sig_handler; + sa.sa_mask = sigmask; + sa.sa_flags = SA_RESTART; + sigaction(SIGCHLD, &sa, NULL); + + for (;;) { + FD_SET(infd, &rfds); + timeout.tv_sec = 3; + + nfd = pselect(infd+1, &rfds, NULL, NULL, &timeout, &orig_sigmask); + + if (child_exitted) { + waitpid(child_pid, &child_status, 0); + child_exitted--; + rp = make_qp_cmdexit(child_pid, child_status); + send_packet(fileno(stdout), rp); + qpfree(rp); + } + + if (nfd < 0) { + if (errno == EINTR) { + /* signals handled above here */ + continue; + } else { + syslog(LOG_ERR, "select errno %d, %s\n", + errno, strerror(errno)); + } + } else if (nfd > 0) { + qp = recv_packet(infd); + if (qp == NULL) { + syslog(LOG_INFO, "That's enough\n"); + break; + } + switch (qp->qp_type) { + case QP_KILL: + if (child_pid) { + + syslog(LOG_INFO, "Sending child %d signal %d", + child_pid, qp->qp_kill.qp_sig); + kill(child_pid * -1, qp->qp_kill.qp_sig); + } + break; + case QP_SETUSER: + if (setup_user(qp->qp_setuser.qp_user, + qp->qp_setuser.qp_group) == 0) { + rp = make_qp_returncode(-1, 0, "User not found"); + } else { + rp = make_qp_ack(QP_SETUSER, 1); + } + send_packet(fileno(stdout), rp); + qpfree(rp); + break; + case QP_RUNCMD: + child_pid = run_cmd(qp->qp_runcmd.qp_cmdline, + qp->qp_runcmd.qp_stdin_port, + qp->qp_runcmd.qp_stdout_port, + qp->qp_runcmd.qp_stderr_port); + break; + case QP_RECVFILE: + syslog(LOG_INFO, "Got a QP_RECVFILE with path = %s, " + "ifd = %d, count = %d, mode = %o\n", + qp->qp_recvfile.qp_path, + qp->qp_recvfile.qp_if_port, + qp->qp_recvfile.qp_count, + qp->qp_recvfile.qp_mode); + nbytes = recvfile(qp->qp_recvfile.qp_path, + qp->qp_recvfile.qp_if_port, + qp->qp_recvfile.qp_count, + qp->qp_recvfile.qp_mode); + if (nbytes < 0) { + rp = make_qp_returncode(-1, errno, strerror(errno)); + } else if (nbytes < qp->qp_recvfile.qp_count) { + char tmpstr[512]; + sprintf(tmpstr, "Excpected %d, wrote %d\n", + qp->qp_recvfile.qp_count, nbytes); + rp = make_qp_returncode(-1, 0, tmpstr); + } else { + rp = make_qp_returncode(0, 0, "Transfer Complete"); + } + send_packet(fileno(stdout), rp); + qpfree(rp); + break; + case QP_SENDFILE: + syslog(LOG_INFO, "Got a QP_SENDFILE with path = %s, " + "ofd = %d, count = %d\n", + qp->qp_sendfile.qp_path, + qp->qp_sendfile.qp_of_port, + qp->qp_sendfile.qp_count); + break; + case QP_RSTAT: + syslog(LOG_INFO, "Got a QP_RSTAT with path = %s\n", + qp->qp_rstat.qp_path); + rp = rstat(qp->qp_rstat.qp_path); + send_packet(fileno(stdout), rp); + qpfree(rp); + break; + default: + syslog(LOG_WARNING, + "Packet type %s unimplemented", + qp_packet_type(qp->qp_type)); + } + } else { + syslog(LOG_DEBUG, "Nothing to do\n"); + } + + } +} + +int +main(int argc, char *argv[]) +{ + int ch; + socklen_t peernamelen; + + openlog("qarshd", LOG_PID, LOG_DAEMON); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + case '?': + default: + printf("unknown option '%c'\n", optopt); + exit(1); + } + } + + /* daemon initialization */ + peernamelen = sizeof peername; + getpeername(0, (struct sockaddr *)&peername, &peernamelen); + syslog(LOG_INFO, "Talking to peer %s:%d", + inet_ntoa(peername.sin_addr), ntohs(peername.sin_port)); + /* Start reading packets from stdin */ + handle_packets(0); + + return 0; +} diff --git a/sockutil.c b/sockutil.c new file mode 100644 index 0000000..b84e456 --- /dev/null +++ b/sockutil.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qarsh_packet.h" + +/* Some generic socket related functions to make things easier */ + +int +getsockport(int sd) +{ + struct sockaddr_in addr; + socklen_t addrlen; + + addrlen = sizeof addr; + if (getsockname(sd, (struct sockaddr *)&addr, &addrlen) == 0) { + return ntohs(addr.sin_port); + } else { + return -1; + } +} + +int +bind_any(int minport) +{ + int sd; + struct sockaddr_in addr; + + sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd == -1) return -1; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + do { + addr.sin_port = htons(minport++); + } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + if (listen(sd, 0) == -1) { + syslog(LOG_WARNING, "listen error %d, %s", errno, + strerror(errno)); + } + return sd; +} + +int +connect_to_host(char *hostname, int port) +{ + struct hostent *h; + struct sockaddr_in haddr; + int sd; + + if ((h = gethostbyname(hostname)) == NULL) { + return -1; + } + haddr.sin_family = h->h_addrtype; + haddr.sin_port = htons(port); + memcpy(&haddr.sin_addr, h->h_addr, h->h_length); + + sd = socket(PF_INET, SOCK_STREAM, 0); + if (sd == -1) return -1; + if (connect(sd, (struct sockaddr *)&haddr, sizeof haddr) == -1) { + return -1; + } + return sd; +} + +int +connect_to_peer(struct sockaddr_in *peer, int port) +{ + struct sockaddr_in in_peer; + int sd; + + in_peer.sin_family = AF_INET; + in_peer.sin_port = htons(port); + in_peer.sin_addr = peer->sin_addr; + + sd = socket(PF_INET, SOCK_STREAM, 0); + if (sd == -1) return -1; + if (connect(sd, (struct sockaddr *)&in_peer, sizeof in_peer) == -1) { + return -1; + } + return sd; +} + + +struct qa_packet * +recv_packet(int fd) +{ + char *packetbuf; + int packetsize; + struct qa_packet *qp = NULL; + + packetbuf = malloc(QARSH_MAX_PACKET_SIZE); + memset(packetbuf, 0, QARSH_MAX_PACKET_SIZE); + + packetsize = read(fd, packetbuf, QARSH_MAX_PACKET_SIZE); + if (packetsize > 0) { + qp = parse_packets(packetbuf, packetsize); + } + free(packetbuf); + return qp; +} + +int +send_packet(int fd, struct qa_packet *qp) +{ + char *packetbuf; + int packetsize; + + packetbuf = malloc(1024); + memset(packetbuf, 0, 1024); + packetbuf = qptostr(qp, &packetbuf, &packetsize); + + return write(fd, packetbuf, packetsize); +} diff --git a/sockutil.h b/sockutil.h new file mode 100644 index 0000000..6e4b8dd --- /dev/null +++ b/sockutil.h @@ -0,0 +1,8 @@ +#include + +int getsockport(int sd); +int bind_any(int minport); +int connect_to_host(char *hostname, int port); +int connect_to_peer(struct sockaddr_in *peer, int port); +struct qa_packet * recv_packet(int fd); +int send_packet(int fd, struct qa_packet *qp); -- cgit