source: zcrypt.c @ 356465e

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