source: zcrypt.c @ d309eb3

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