/* * rexecd: remote exec daemon */ /* * Copyright (c) 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <errno.h> #include <string.h> #include <unistd.h> #include "rexec.h" const char usagemsg[] = "usage: rexecd\n" " rexecd -v show version\n" " rexecd -h display this help\n" " rexecd -l display (BSD) license\n" ; const char versionmsg[] = "rexecd 0.2\n"; void usage(); void version(); int main ( int argc, char * argv[] ) { int sock; int child; int tmp; int i,j; int sock2; int lineend; socklen_t *remote_host_addr_len; char buff; struct sockaddr *remote_host_addr = NULL; struct sockaddr_in *local_addr = NULL; char cmdline[REXEC_MAX_LENGTH+1]; char* cmdargs[REXEC_MAX_ARGS]; while ( (tmp = getopt(argc, argv, "hlv")) != -1 ) { switch ( tmp ) { case 'h': usage(); exit(0); case 'l': license(); exit(0); case 'v': version(); exit(0); default: usage(); exit(-1); } } local_addr = alloca(sizeof(struct sockaddr_in)); local_addr->sin_family = AF_INET; local_addr->sin_addr.s_addr = INADDR_ANY; local_addr->sin_port = REXEC_PORT; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if ( sock < 0 ) { showerror("socket"); exit(-1); } tmp = bind(sock, (struct sockaddr*)local_addr, sizeof(struct sockaddr_in)); if ( tmp < 0 ) { showerror("bind"); exit(-1); } tmp = listen(sock, 4); if ( tmp < 0 ) { showerror("listen"); exit(-1); } while ( (sock2 = accept(sock, remote_host_addr, remote_host_addr_len)) > -1 ) { if ( (child = fork()) == 0 ) { if ( (child = fork()) == 0 ) { i = 0; do { tmp = read(sock2, &buff, 1); if ( tmp < 0 ) { showerror("read"); exit(-1); } cmdline[i] = buff; i++; } while ( buff != '\n' && i < REXEC_MAX_LENGTH ); lineend = i; cmdline[lineend] = '\n'; for ( i = 0, j = 0; i < lineend-1 && j < REXEC_MAX_ARGS; j++ ) { while ( cmdline[i] == '\0' ) { i++; } if ( i < lineend-1 ) { cmdargs[j] = &(cmdline[i]); while ( cmdline[i] != '\0' ) { i++; } } } dup2(sock2, 0); dup2(sock2, 1); dup2(sock2, 2); tmp = execvp(cmdargs[0], cmdargs); if ( tmp < 0 ) { showerror("execvp"); exit(-1); } exit(0); } else { wait(&tmp); } tmp = shutdown(sock2, SHUT_RDWR); if ( tmp < 0 ) { showerror("shutdown"); exit(-1); } tmp = close(sock2); if ( tmp < 0 ) { showerror("close"); exit(-1); } exit(0); } else { usleep(200000); } } if ( sock2 < 0 ) { showerror("accept"); exit(-1); } tmp = shutdown(sock, SHUT_RDWR); if ( tmp < 0 ) { showerror("shutdown"); exit(-1); } tmp = close(sock); if ( tmp < 0 ) { showerror("close"); exit(-1); } while ( wait(&tmp) > 0 ) { } exit(0); } void usage() { write(1, usagemsg, strlen(usagemsg)); } void version() { write(1, versionmsg, strlen(versionmsg)); }