source: zcrypt.c @ 49bc81e

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