source: zcrypt.c @ e3869df

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since e3869df was e3869df, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
Did some cleanup on zcrypt.c to make -Wall quiet Added a fileIdent to zcrypt.c Added a prototype for ZResetAuthentication to zwrite.c
  • Property mode set to 100644
File size: 16.9 KB
Line 
1/* This file is stolen and slightly modified code */
2
3/* zcrypt.c -- Read in a data stream from stdin & dump a decrypted/encrypted *
4 *   datastream.  Reads the string to make the key from from the first       *
5 *   parameter.  Encrypts or decrypts according to -d or -e flag.  (-e is    *
6 *   default.)  Will invoke zwrite if the -c option is provided for          *
7 *   encryption.  If a zephyr class is specified & the keyfile name omitted  *
8 *   the ~/.crypt-table will be checked for "crypt-classname" and then       *
9 *   "crypt-default" for the keyfile name.                                   */
10
11static const char fileIdent[] = "$Id$";
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18
19#define BASE_CODE 70
20#define LAST_CODE (BASE_CODE + 15)
21#define OUTPUT_BLOCK_SIZE 16
22
23#if defined(vax) || defined(ibm032)
24#define pid_t int
25int waitpid(pid_t pid, int *statloc, int options)
26{
27  while (wait(statloc) != pid)
28    ;
29}
30#define STDIN_FILENO 0
31#else
32#include <unistd.h>
33#endif
34#include <sys/types.h>
35#include <des.h>
36#include <zephyr/zephyr.h>
37
38#define MAX_KEY 128
39
40#ifndef TRUE
41#define TRUE -1
42#endif
43#ifndef FALSE
44#define FALSE 0
45#endif
46
47#define ZWRITE_OPT_NOAUTH     (1<<0)
48#define ZWRITE_OPT_SIGNATURE  (1<<1)
49#define ZWRITE_OPT_IGNOREVARS (1<<2)
50#define ZWRITE_OPT_VERBOSE    (1<<3)
51#define ZWRITE_OPT_QUIET      (1<<4)
52#define ZCRYPT_OPT_MESSAGE    (1<<5)
53#define ZCRYPT_OPT_IGNOREDOT  (1<<6)
54
55typedef struct
56{
57  int flags;
58  char *signature;
59  char *message;
60} ZWRITEOPTIONS;
61
62char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance);
63char *BuildArgString(char **argv, int start, int end);
64int do_encrypt(char *keystring, int zephyr, char *class, char *instance, ZWRITEOPTIONS *zoptions, char* keyfile);
65int do_decrypt(char *keystring);
66
67int des_ecb_encrypt(char [], char [], des_key_schedule, int);
68
69#define M_NONE            0
70#define M_ZEPHYR_ENCRYPT  1
71#define M_DECRYPT         2
72#define M_ENCRYPT         3
73#define M_RANDOMIZE       4
74#define M_SETKEY          5
75
76int zcrypt(int argc, char *argv[]) {
77  char *fname = NULL;
78  int error = FALSE;
79  int zephyr = FALSE;
80  char *class = NULL, *instance = NULL;
81  int mode = M_NONE;
82
83  extern int optind, opterr;
84  extern char *optarg;
85  char c;
86
87  int messageflag = FALSE;
88  ZWRITEOPTIONS zoptions;
89  zoptions.flags = 0;
90
91  while ((c = getopt(argc, argv, "ZDERSF:c:i:advqtluons:f:m")) != (char)EOF) {
92    switch(c) {
93      case 'Z':
94        /* Zephyr encrypt */
95        mode = M_ZEPHYR_ENCRYPT;
96        break;
97      case 'D':
98        /* Decrypt */
99        mode = M_DECRYPT;
100        break;
101      case 'E':
102        /* Encrypt */
103        mode = M_ENCRYPT;
104        break;
105      case 'R':
106        /* Randomize the keyfile */
107        mode = M_RANDOMIZE;
108        break;
109      case 'S':
110        /* Set a new key value from stdin */
111        mode = M_SETKEY;
112        break;
113      case 'F':
114        /* Specify the keyfile explicitly */
115        if (fname != NULL) error = TRUE;
116        fname = optarg;
117        break;
118      case 'c':
119        /* Zwrite/zcrypt: class name */
120        if (class != NULL) error = TRUE;
121        class = optarg;
122        break;
123      case 'i':
124        /* Zwrite/zcrypt: instance name */
125        if (instance != NULL) error = TRUE;
126        instance = optarg;
127        break;
128      case 'a':
129        /* Zwrite: authenticate (default) */
130        zoptions.flags &= ~ZWRITE_OPT_NOAUTH;
131        break;
132      case 'd':
133        /* Zwrite: do not authenticate */
134        zoptions.flags |= ZWRITE_OPT_NOAUTH;
135        break;
136      case 'v':
137        /* Zwrite: verbose */
138        zoptions.flags |= ZWRITE_OPT_VERBOSE;
139        break;
140      case 'q':
141        /* Zwrite: quiet */
142        zoptions.flags |= ZWRITE_OPT_QUIET;
143        break;
144      case 't':
145        /* Zwrite: no expand tabs (ignored) */
146        break;
147      case 'l':
148        /* Zwrite: ignore '.' on a line by itself (ignored) */
149        zoptions.flags |= ZCRYPT_OPT_IGNOREDOT;
150        break;
151      case 'u':
152        /* Zwrite: urgent message */
153        instance = "URGENT";
154        break;
155      case 'o':
156        /* Zwrite: ignore zephyr variables zwrite-class, zwrite-inst, */
157        /*         zwrite-opcode */
158        zoptions.flags |= ZWRITE_OPT_IGNOREVARS;
159        break;
160      case 'n':
161        /* Zwrite: prevent PING message (always used) */
162        break;
163      case 's':
164        /* Zwrite: signature */
165        zoptions.flags |= ZWRITE_OPT_SIGNATURE;
166        zoptions.signature = optarg;
167        break;
168      case 'f':
169        /* Zwrite: file system specification (ignored) */
170        break;
171      case 'm':
172        /* Message on rest of line */
173        messageflag = TRUE;
174        break;
175      case '?':
176        error = TRUE;
177        break;
178    }
179    if (error || messageflag) break;
180  }
181
182  if (class != NULL || instance != NULL) {
183    zephyr = TRUE;
184  }
185
186  if (messageflag) {
187    zoptions.flags |= ZCRYPT_OPT_MESSAGE;
188    zoptions.message = BuildArgString(argv, optind, argc);
189    if (!zoptions.message)
190    {
191      printf("Memory allocation error.\n");
192      error = TRUE;
193    }
194  } else if (optind < argc) {
195    error = TRUE;
196  }
197
198  if (mode == M_NONE) mode = (zephyr?M_ZEPHYR_ENCRYPT:M_ENCRYPT);
199
200  if (mode == M_ZEPHYR_ENCRYPT && !zephyr) error = TRUE;
201
202  if (!error && fname == NULL && (class != NULL || instance != NULL)) {
203    fname = GetZephyrVarKeyFile(argv[0], class, instance);
204  }
205
206 
207  if (error || fname == NULL) {
208    printf("Usage: %s [-Z|-D|-E|-R|-S] [-F Keyfile] [-c class] [-i instance]\n", argv[0]);
209    printf("       [-advqtluon] [-s signature] [-f arg] [-m message]\n");
210    printf("  One or more of class, instance, and keyfile must be specified.\n");
211  } else {
212    if (mode == M_RANDOMIZE) {
213      /* Choose a new, random key */
214/*
215      FILE *fkey = fopen(fname, "w");
216      if (!fkey)
217        printf("Could not open key file for writing: %s\n", fname);
218      else
219      {
220        char string[100];
221        fputs(fkey, string);
222        fclose(fkey);
223        }
224 */
225      printf("Feature not yet implemented.\n");
226    } else if (mode == M_SETKEY) {
227      /* Set a new, user-entered key */
228      char newkey[MAX_KEY];
229      FILE *fkey;
230     
231      if (isatty(0)) {
232        printf("Enter new key: ");
233        /* Really should read without echo!!! */
234        fgets(newkey, MAX_KEY - 1, stdin);
235      } else {
236        fgets(newkey, MAX_KEY - 1, stdin);
237      }
238
239      fkey = fopen(fname, "w");
240      if (!fkey) {
241        printf("Could not open key file for writing: %s\n", fname);
242      } else {
243        if (fputs(newkey, fkey) != strlen(newkey) || putc('\n', fkey) != '\n') {
244          printf("Error writing to key file.\n");
245          fclose(fkey);
246        } else {
247          fclose(fkey);
248          printf("Key update complete.\n");
249        }
250      }
251    } else {
252      /* Encrypt/decrypt */
253      FILE *fkey = fopen(fname, "r");
254      if (!fkey) {
255        printf("Could not open key file: %s\n", fname);
256      } else {
257        char keystring[MAX_KEY];
258        fgets(keystring, MAX_KEY-1, fkey);
259        if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT) {
260          do_encrypt(keystring, (mode == M_ZEPHYR_ENCRYPT), class, instance,
261                     &zoptions, fname);
262        } else {
263          do_decrypt(keystring);
264        }
265        fclose(fkey);
266      }
267    }
268  }
269
270  /* Always print the **END** message if -D is specified. */
271  if (mode == M_DECRYPT) printf("**END**\n");
272
273  exit(0);
274}
275
276int zcrypt_decrypt(char *out, char *in, char *class, char *instance) {
277  /* written by kretch for owl. */
278  /* return 0 on success, otherwise -1 */
279  char *fname, keystring[MAX_KEY], *inptr, *endptr;
280  FILE *fkey;
281  des_cblock key;
282  des_key_schedule schedule;
283  char input[8], output[9];
284  int i, c1, c2;
285 
286  fname=GetZephyrVarKeyFile("zcrypt", class, instance);
287  fkey=fopen(fname, "r");
288  if (!fkey) return(-1);
289  fgets(keystring, MAX_KEY-1, fkey);
290  fclose(fkey);
291
292  strcpy(out, "");
293
294  output[0] = '\0';    /* In case no message at all                 */
295  output[8] = '\0';    /* NULL at end will limit string length to 8 */
296
297  des_string_to_key(keystring, key);
298  des_key_sched(key, schedule);
299
300  inptr=in;
301  endptr=in+strlen(in)-1;
302  while (inptr<endptr) {
303    for (i=0; i<8; i++) {
304      c1=(inptr[0])-BASE_CODE;
305      c2=(inptr[1])-BASE_CODE;
306      input[i]=c1 * 0x10 + c2;
307      inptr+=2;
308    }
309    des_ecb_encrypt(input, output, schedule, FALSE);
310    strcat(out, output);
311  }
312
313  if (output[0]) {
314    if (output[strlen(output)-1] != '\n') {
315      strcat(out, "\n");
316    }
317  } else {
318    strcat(out, "\n");
319  }
320  return(0);
321}
322
323int zcrypt_encrypt(char *out, char *in, char *class, char *instance) {
324  return(0);
325}
326
327/* Build a space-separated string from argv from elements between start  *
328 * and end - 1.  malloc()'s the returned string. */
329char *BuildArgString(char **argv, int start, int end) {
330  int len = 1;
331  int i;
332  char *result;
333
334  /* Compute the length of the string.  (Plus 1 or 2) */
335  for (i = start; i < end; i++) {
336    len += strlen(argv[i]) + 1;
337  }
338
339  /* Allocate memory */
340  result = (char *)malloc(len);
341  if (result) {
342    /* Build the string */
343    char *ptr = result;
344    /* Start with an empty string, in case nothing is copied. */
345    *ptr = '\0';
346    /* Copy the arguments */
347    for (i = start; i < end; i++) {
348      char *temp = argv[i];
349      /* Add a space, if not the first argument */
350      if (i != start) *ptr++ = ' ';
351      /* Copy argv[i], leaving ptr pointing to the '\0' copied from temp */
352      while ((*ptr = *temp++)!=0) {
353        ptr++;
354      }
355    }
356  }
357
358  return(result);
359}
360
361#define MAX_BUFF 258
362#define MAX_SEARCH 3
363/* Find the class/instance in the .crypt-table */
364char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance) {
365  char *keyfile = NULL;
366  char varname[MAX_SEARCH][128];
367  int length[MAX_SEARCH], i;
368  char buffer[MAX_BUFF];
369  char filename[MAX_BUFF];
370  char result[MAX_SEARCH][MAX_BUFF];
371  int numsearch = 0;
372  FILE *fsearch;
373
374  /* Determine names to look for in .crypt-table */
375  if (instance) {
376    sprintf(varname[numsearch++], "crypt-%s-%s:", (class?class:"message"), 
377            instance);
378  }
379  if (class) {
380    sprintf(varname[numsearch++], "crypt-%s:", class);
381  }
382  sprintf(varname[numsearch++], "crypt-default:");
383
384  /* Setup the result array, and determine string lengths */
385  for (i = 0; i < numsearch; i++) {
386    result[i][0] = '\0';
387    length[i] = strlen(varname[i]);
388  }
389
390  /* Open~/.crypt-table */
391  sprintf(filename, "%s/.crypt-table", getenv("HOME"));
392  fsearch = fopen(filename, "r");
393  if (fsearch) {
394    /* Scan file for a match */
395    while (!feof(fsearch)) {
396      fgets(buffer, MAX_BUFF - 3, fsearch);
397      for (i = 0; i < numsearch; i++) {
398        if (strncasecmp(varname[i], buffer, length[i]) == 0) {
399          int j;
400          for (j = length[i]; buffer[j] == ' '; j++)
401            ;
402          strcpy(result[i], &buffer[j]);
403          if (*result[i]) {
404            if (result[i][strlen(result[i])-1] == '\n') {
405              result[i][strlen(result[i])-1] = '\0';
406            }
407          }
408        }
409      }
410    }
411
412    /* Pick the "best" match found */
413    keyfile = NULL;
414    for (i = 0; i < numsearch; i++) {
415      if (*result[i]) {
416        keyfile = result[i];
417        break;
418      }
419    }
420
421    if (keyfile == NULL) {
422      printf("Could not find key table entry.\n");
423    } else {
424      /* Prepare result to be returned */
425      char *temp = keyfile;
426      keyfile = (char *)malloc(strlen(temp) + 1);
427      if (keyfile) {
428        strcpy(keyfile, temp);
429      } else {
430        printf("Memory allocation error.\n");
431      }
432    }
433   
434    fclose(fsearch);
435  } else {
436    printf("Could not open key table file: %s\n", filename);
437  }
438
439  return(keyfile);
440}
441
442static pid_t zephyrpipe_pid = 0;
443
444/* Open a pipe to zwrite */
445FILE *GetZephyrPipe(char *class, char *instance, ZWRITEOPTIONS *zoptions) {
446  int fildes[2];
447  pid_t pid;
448  FILE *result;
449  char *argv[20];
450  int argc = 0;
451
452  if (pipe(fildes) < 0) return(NULL);
453  pid = fork();
454
455  if (pid < 0) {
456    /* Error: clean up */
457    close(fildes[0]);
458    close(fildes[1]);
459    result = NULL;
460  } else if (pid == 0) {
461    /* Setup child process */
462    argv[argc++] = "zwrite";
463    argv[argc++] = "-n";     /* Always send without ping */
464    if (class) {
465      argv[argc++] = "-c";
466      argv[argc++] = class;
467    }
468    if (instance) {
469      argv[argc++] = "-i";
470      argv[argc++] = instance;
471    }
472    if (zoptions->flags & ZWRITE_OPT_NOAUTH) argv[argc++] = "-d";
473    if (zoptions->flags & ZWRITE_OPT_QUIET) argv[argc++] = "-q";
474    if (zoptions->flags & ZWRITE_OPT_VERBOSE) argv[argc++] = "-v";
475    if (zoptions->flags & ZWRITE_OPT_SIGNATURE) {
476      argv[argc++] = "-s";
477      argv[argc++] = zoptions->signature;
478    }
479    argv[argc++] = "-O";
480    argv[argc++] = "crypt";
481    argv[argc] = NULL;
482    close(fildes[1]);
483    if (fildes[0] != STDIN_FILENO) {
484      if (dup2(fildes[0], STDIN_FILENO) != STDIN_FILENO) exit(0);
485      close(fildes[0]);
486    }
487    close(fildes[0]);
488    execvp(argv[0], argv);
489    printf("Exec error: could not run zwrite\n");
490    exit(0);
491  } else {
492    close(fildes[0]);
493    /* Create a FILE * for the zwrite pipe */
494    result = (FILE *)fdopen(fildes[1], "w");
495    zephyrpipe_pid = pid;
496  }
497
498  return(result);
499}
500
501/* Close the pipe to zwrite */
502void CloseZephyrPipe(FILE *pipe) {
503  fclose(pipe);
504  waitpid(zephyrpipe_pid, NULL, 0);
505  zephyrpipe_pid = 0;
506}
507
508#define MAX_RESULT 2048
509
510
511void block_to_ascii(char *output, FILE *outfile) {
512  int i;
513  for (i = 0; i < 8; i++) {
514    putc(((output[i] & 0xf0) >> 4) + BASE_CODE, outfile);
515    putc( (output[i] & 0x0f)       + BASE_CODE, outfile);
516  }
517}
518
519#define MAX_LINE 128
520
521/* Encrypt stdin, with prompt if isatty, and send to stdout, or to zwrite
522   if zephyr is set. */
523int do_encrypt(char *keystring, int zephyr, char *class, char *instance, ZWRITEOPTIONS *zoptions, char* keyfile) {
524  des_cblock key;
525  des_key_schedule schedule;
526  char input[8], output[8];
527  int size;
528  FILE *outfile = stdout;
529  int error = FALSE;
530  char *inbuff = NULL, *inptr;
531  int freein = FALSE;
532  int use_buffer = FALSE;
533  int num_blocks=0, last_block_size=0;
534
535  des_string_to_key(keystring, key);
536  des_key_sched(key, schedule);
537
538  if (zephyr) {
539    if (zoptions->flags & ZCRYPT_OPT_MESSAGE) {
540      /* Use the -m message */
541      int length;
542      inbuff = zoptions->message;     
543      length = strlen(inbuff);
544      num_blocks = (length + 7) / 8;
545      last_block_size = ((length + 7) % 8) + 1;
546      use_buffer = TRUE;
547    } else if (isatty(0)) {
548      /* tty input, so show the "Type your message now..." message */
549      if (zoptions->flags & ZCRYPT_OPT_IGNOREDOT) {
550        printf("Type your message now.  End with the end-of-file character.\n");
551      } else {
552        printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
553      }
554      use_buffer = TRUE;
555      if ((inptr = inbuff = (char *)malloc(MAX_RESULT)) == NULL) {
556        printf("Memory allocation error\n");
557        return FALSE;
558      }
559      while (inptr - inbuff < MAX_RESULT - MAX_LINE - 20) {
560        fgets(inptr, MAX_LINE, stdin);
561        if (inptr[0]) {
562          if (inptr[0] == '.' && inptr[1] == '\n' && 
563              !(zoptions->flags & ZCRYPT_OPT_IGNOREDOT)) {
564            inptr[0] = '\0';
565            break;
566          } else {
567            inptr += strlen(inptr);
568          }
569        } else {
570          break;
571        }
572      }
573      num_blocks = (inptr - inbuff + 7) / 8;
574      last_block_size = ((inptr - inbuff + 7) % 8) + 1;
575      freein = TRUE;
576    }
577
578    /* if (zephyr) */
579    outfile = GetZephyrPipe(class, instance, zoptions);
580    if (!outfile) {
581      printf("Could not run zwrite\n");
582      if (freein && inbuff) {
583        free(inbuff);
584      }
585      return(FALSE);
586    }
587  }
588
589  inptr = inbuff;
590
591  /* Encrypt the input (inbuff or stdin) and send it to outfile */
592  while (TRUE) {
593    if (use_buffer) {
594      /* Get 8 bytes from buffer */
595      if (num_blocks > 1) {
596        size = 8;
597        memcpy(input, inptr, size);
598        inptr += 8;
599        num_blocks--;
600      } else if (num_blocks == 1) {
601        size = last_block_size;
602        memcpy(input, inptr, size);
603        num_blocks--;
604      } else {
605        size = 0;
606      }
607    } else {
608      /* Get 8 bytes from stdin */
609      size = fread(input, 1, 8, stdin);
610    }
611
612    /* Check for EOF and pad the string to 8 chars, if needed */
613    if (size == 0) break;     /* END OF INPUT: BREAK FROM while LOOP! */
614     
615    if (size < 8) memset(input + size, 0, 8 - size);
616
617    /* Encrypt and output the block */
618    des_ecb_encrypt(input, output, schedule, TRUE);
619    block_to_ascii(output, outfile);
620
621    if (size < 8) break;
622  }
623
624  /* Close out the output */
625  if (!error) putc('\n', outfile);
626  if (zephyr) CloseZephyrPipe(outfile);
627
628  /* Free the input buffer, if necessary */
629  if (freein && inbuff) free(inbuff);
630
631  return(!error);
632}
633
634/* Read a half-byte from stdin, skipping invalid characters.  Returns -1
635   if at EOF or file error */
636int read_ascii_nybble() {
637  char c;
638
639  while (TRUE) {
640    if (fread(&c, 1, 1, stdin) == 0) {
641      return(-1);
642    } else if (c >= BASE_CODE && c <= LAST_CODE) {
643      return(c - BASE_CODE);
644    }
645  }
646}
647
648/* Read both halves of the byte and return the single byte.  Returns -1
649   if at EOF or file error. */
650int read_ascii_byte() {
651  int c1, c2;
652  c1 = read_ascii_nybble();
653  if (c1 >= 0) {
654    c2 = read_ascii_nybble();
655    if (c2 >= 0) {
656      return c1 * 0x10 + c2;
657    }
658  }
659  return(-1);
660}
661
662/* Read an 8-byte DES block from stdin */
663int read_ascii_block(char *input) {
664  int c, i;
665
666  for (i = 0; i < 8; i++) {
667    c = read_ascii_byte();
668    if (c < 0) return(FALSE);
669    input[i] = c;
670  }
671
672  return(TRUE);
673}
674
675/* Decrypt stdin */
676int do_decrypt(char *keystring) {
677  des_cblock key;
678  des_key_schedule schedule;
679  char input[8], output[9];
680
681  output[0] = '\0';    /* In case no message at all                 */
682  output[8] = '\0';    /* NULL at end will limit string length to 8 */
683
684  des_string_to_key(keystring, key);
685  des_key_sched(key, schedule);
686
687  while (read_ascii_block(input)) {
688    des_ecb_encrypt(input, output, schedule, FALSE);
689    printf("%s", output);
690  }
691
692  if (output[0]) {
693    if (output[strlen(output)-1] != '\n') {
694      printf("\n");
695    }
696  } else {
697    printf("\n");
698  }
699  return(0);
700}
Note: See TracBrowser for help on using the repository browser.