source: zcrypt.c @ ac70242

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