root/source4/heimdal/lib/roken/rkpty.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. caught_signal
  2. open_pty
  3. iscmd
  4. parse_configuration
  5. eval_parent
  6. usage
  7. main

   1 /*
   2  * Copyright (c) 2008 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "config.h"
  35 
  36 #ifndef HAVE_SYS_TYPES_H
  37 #include <sys/types.h>
  38 #endif
  39 #ifdef HAVE_SYS_WAIT_H
  40 #include <sys/wait.h>
  41 #endif
  42 #include <stdio.h>
  43 #include <stdlib.h>
  44 #include <unistd.h>
  45 #ifdef HAVE_PTY_H
  46 #include <pty.h>
  47 #endif
  48 #ifdef HAVE_UTIL_H
  49 #include <util.h>
  50 #endif
  51 
  52 #include "roken.h"
  53 #include <getarg.h>
  54 
  55 struct command {
  56     enum { CMD_EXPECT = 0, CMD_SEND, CMD_PASSWORD } type;
  57     unsigned int lineno;
  58     char *str;
  59     struct command *next;
  60 };
  61 
  62 /*
  63  *
  64  */
  65 
  66 static struct command *commands, **next = &commands;
  67 
  68 static sig_atomic_t alarmset = 0;
  69 
  70 static int timeout = 10;
  71 static int verbose;
  72 static int help_flag;
  73 static int version_flag;
  74 
  75 static int master;
  76 static int slave;
  77 static char line[256] = { 0 };
  78 
  79 static void
  80 caught_signal(int signo)
     /* [<][>][^][v][top][bottom][index][help] */
  81 {
  82     alarmset = signo;
  83 }
  84 
  85 
  86 static void
  87 open_pty(void)
     /* [<][>][^][v][top][bottom][index][help] */
  88 {
  89 #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
  90     if(openpty(&master, &slave, line, 0, 0) == 0)
  91         return;
  92 #endif /* HAVE_OPENPTY .... */
  93     /* more cases, like open /dev/ptmx, etc */
  94 
  95     exit(77);
  96 }
  97 
  98 /*
  99  *
 100  */
 101 
 102 static char *
 103 iscmd(const char *buf, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105     size_t len = strlen(s);
 106     if (strncmp(buf, s, len) != 0)
 107         return NULL;
 108     return estrdup(buf + len);
 109 }
 110 
 111 static void
 112 parse_configuration(const char *fn)
     /* [<][>][^][v][top][bottom][index][help] */
 113 {
 114     struct command *c;
 115     char s[1024];
 116     char *str;
 117     unsigned int lineno = 0;
 118     FILE *cmd;
 119 
 120     cmd = fopen(fn, "r");
 121     if (cmd == NULL)
 122         err(1, "open: %s", fn);
 123 
 124     while (fgets(s, sizeof(s),  cmd) != NULL) {
 125 
 126         s[strcspn(s, "#\n")] = '\0';
 127         lineno++;
 128 
 129         c = calloc(1, sizeof(*c));
 130         if (c == NULL)
 131             errx(1, "malloc");
 132 
 133         c->lineno = lineno;
 134         (*next) = c;
 135         next = &(c->next);
 136 
 137         if ((str = iscmd(s, "expect ")) != NULL) {
 138             c->type = CMD_EXPECT;
 139             c->str = str;
 140         } else if ((str = iscmd(s, "send ")) != NULL) {
 141             c->type = CMD_SEND;
 142             c->str = str;
 143         } else if ((str = iscmd(s, "password ")) != NULL) {
 144             c->type = CMD_PASSWORD;
 145             c->str = str;
 146         } else
 147             errx(1, "Invalid command on line %d: %s", lineno, s);
 148     }
 149 
 150     fclose(cmd);
 151 }
 152 
 153 
 154 /*
 155  *
 156  */
 157 
 158 static int
 159 eval_parent(pid_t pid)
     /* [<][>][^][v][top][bottom][index][help] */
 160 {
 161     struct command *c;
 162     char in;
 163     size_t len = 0;
 164     ssize_t sret;
 165 
 166     for (c = commands; c != NULL; c = c->next) {
 167         switch(c->type) {
 168         case CMD_EXPECT:
 169             if (verbose)
 170                 printf("[expecting %s]", c->str);
 171             len = 0;
 172             alarm(timeout);
 173             while((sret = read(master, &in, sizeof(in))) > 0) {
 174                 alarm(timeout);
 175                 printf("%c", in);
 176                 if (c->str[len] != in) {
 177                     len = 0;
 178                     continue;
 179                 }
 180                 len++;
 181                 if (c->str[len] == '\0')
 182                     break;
 183             }
 184             alarm(0);
 185             if (alarmset == SIGALRM)
 186                 errx(1, "timeout waiting for %s (line %u)",
 187                      c->str, c->lineno);
 188             else if (alarmset)
 189                 errx(1, "got a signal %d waiting for %s (line %u)",
 190                      alarmset, c->str, c->lineno);
 191             if (sret <= 0)
 192                 errx(1, "end command while waiting for %s (line %u)",
 193                      c->str, c->lineno);
 194             break;
 195         case CMD_SEND:
 196         case CMD_PASSWORD: {
 197             size_t i = 0;
 198             const char *msg = (c->type == CMD_PASSWORD) ? "****" : c->str;
 199 
 200             if (verbose)
 201                 printf("[send %s]", msg);
 202 
 203             len = strlen(c->str);
 204 
 205             while (i < len) {
 206                 if (c->str[i] == '\\' && i < len - 1) {
 207                     char ctrl;
 208                     i++;
 209                     switch(c->str[i]) {
 210                     case 'n': ctrl = '\n'; break;
 211                     case 'r': ctrl = '\r'; break;
 212                     case 't': ctrl = '\t'; break;
 213                     default:
 214                         errx(1, "unknown control char %c (line %u)",
 215                              c->str[i], c->lineno);
 216                     }
 217                     if (net_write(master, &ctrl, 1) != 1)
 218                         errx(1, "command refused input (line %u)", c->lineno);
 219                 } else {
 220                     if (net_write(master, &c->str[i], 1) != 1)
 221                         errx(1, "command refused input (line %u)", c->lineno);
 222                 }
 223                 i++;
 224             }
 225             break;
 226         }
 227         default:
 228             abort();
 229         }
 230     }
 231     while(read(master, &in, sizeof(in)) > 0)
 232         printf("%c", in);
 233 
 234     if (verbose)
 235         printf("[end of program]\n");
 236 
 237     /*
 238      * Fetch status from child
 239      */
 240     {
 241         int ret, status;
 242 
 243         ret = waitpid(pid, &status, 0);
 244         if (ret == -1)
 245             err(1, "waitpid");
 246         if (WIFEXITED(status) && WEXITSTATUS(status))
 247             return WEXITSTATUS(status);
 248         else if (WIFSIGNALED(status)) {
 249             printf("killed by signal: %d\n", WTERMSIG(status));
 250             return 1;
 251         }
 252     }
 253     return 0;
 254 }
 255 
 256 /*
 257  *
 258  */
 259 
 260 static struct getargs args[] = {
 261     { "timeout",        't', arg_integer, &timeout, "timout", "seconds" },
 262     { "verbose",        'v', arg_counter, &verbose, "verbose debugging" },
 263     { "version",        0, arg_flag,    &version_flag, "print version" },
 264     { "help",           0, arg_flag,    &help_flag, NULL }
 265 };
 266 
 267 static void
 268 usage(int ret)
     /* [<][>][^][v][top][bottom][index][help] */
 269 {
 270     arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "infile command..");
 271     exit (ret);
 272 }
 273 
 274 int
 275 main(int argc, char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 276 {
 277     int optidx = 0;
 278     pid_t pid;
 279 
 280     setprogname(argv[0]);
 281 
 282     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
 283         usage(1);
 284 
 285     if (help_flag)
 286         usage (0);
 287 
 288     if (version_flag) {
 289         fprintf (stderr, "%s from %s-%s\n", getprogname(), PACKAGE, VERSION);
 290         return 0;
 291     }
 292 
 293     argv += optidx;
 294     argc -= optidx;
 295 
 296     if (argc < 2)
 297         usage(1);
 298 
 299     parse_configuration(argv[0]);
 300 
 301     argv += 1;
 302     argc -= 1;
 303 
 304     open_pty();
 305 
 306     pid = fork();
 307     switch (pid) {
 308     case -1:
 309         err(1, "Failed to fork");
 310     case 0:
 311 
 312         if(setsid()<0)
 313             err(1, "setsid");
 314 
 315         dup2(slave, STDIN_FILENO);
 316         dup2(slave, STDOUT_FILENO);
 317         dup2(slave, STDERR_FILENO);
 318         closefrom(STDERR_FILENO + 1);
 319 
 320         execvp(argv[0], argv); /* add NULL to end of array ? */
 321         err(1, "Failed to exec: %s", argv[0]);
 322     default:
 323         close(slave);
 324         {
 325             struct sigaction sa;
 326 
 327             sa.sa_handler = caught_signal;
 328             sa.sa_flags = 0;
 329             sigemptyset (&sa.sa_mask);
 330         
 331             sigaction(SIGALRM, &sa, NULL);
 332         }
 333 
 334         return eval_parent(pid);
 335     }
 336 }

/* [<][>][^][v][top][bottom][index][help] */