awips2/nativeLib/decrypt_file/decrypt_file.c
2017-04-21 18:33:55 -06:00

268 lines
12 KiB
C

/* -----------------------------------------------------------------------------
File name:
decrypt_file.c
Compilation:
cc -D_GNU_SOURCE -o decrypt_file decrypt_file.c
Requirements:
- cruft must be installed
- the decryption key must be in ~/.key
File description:
This program attempts to decrypt a stream of data that has been encrypted
with cruft.
This program reads data from stdin. It assumes that there is some kind of
header before the start of the cruft header that must be stripped, though
it will still work if there is no header.
If the cruft header is not found within the first 128 bytes, then the input
data is simply copied to the output file since decryption is not needed. If
a cruft header is found, then the data is piped to cruft for decryption and
is written to the file name matching the template specified on the command line.
This program takes one argument: the output file name template that is used
by the mkstemp system call to open a file with a unique file name. The
string (".XXXXXX") is appended by this program as required by mkstemp.
Any program looking for files to process that are output by this program
should look at the file permissions before attempting a read. When this
program has finished writing the output file, it will change permissions to
0666.
Command line:
decrypt_file <output_file_name>
Author:
Brian M. Rapp 03/19/2009
----------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#define MAX_BUF_SIZE 4096 // This must not be greater than PIPE_BUF
// as defined in the kernel header file
// /usr/src/linux/include/linux/limits.h
#define HDR_DEPTH 128 // The cruft header must occur within 128
// bytes of the beginning of the file.
#define ENCRYPT_PROGRAM "cruft" // The code may require modification if
// a different decryption tool is used.
#define INSERT_PROGRAM "pqinsert" // LDM tool to insert data into the product
// queue
#define CRUFT_HDR_SIZE 9 // Cruft header length (see cruft_hdr below)
#define SBN_HDR_SIZE 24 // Length of the SBN header
#define WMO_HDR_SIZE 21 // Length of the WMO header (TTAAii CCCC DDHHMM\r\r\n)
#define OPEN_FILE_PERMS (S_IRUSR | S_IWUSR)
#define DONE_FILE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#define DIR_PERMS 0777 // the permissions for the directories created
#define DECRYPT_FLAG_OFFSET 5 // Offset to NWSTG CCB encryption flag
char *progname;
char cruft_hdr[] = {253, 253, 253, 253, 253, 253, 253, 253, 253};
/* -------------------------------------------------------------------------- */
void usage (char *exename) {
//fprintf (stderr, "Usage: %s output_file_path feed_type\n", exename); // no feed_type
fprintf (stderr, "Usage: %s output_file_path \n", exename);
}
/* -------------------------------------------------------------------------- */
int main (int argc, char **argv) {
char *out_template; // Input as the file name template from the command
// line. This is modified by mkstemp to the output
// file name.
int out_fd; // Output file descriptor returned by call to mkstemp
FILE *out_pipe; // File pointer returned by call to popen for decryption
size_t len; // Length of buffers read from STDIN
size_t wlen; // Length of the write buffer
size_t count; // Number of items written by calls to fwrite
char file_buf[MAX_BUF_SIZE]; // Input buffer from STDIN
char *hdr_ptr; // Pointer to start of cruft header within file_buf
char command_line[128]; // Command line for starting cruft via popen
char pqinsert_line[128]; // PQInsert Line
char *sbn_hdr_ptr; // Pointer to the start of the 24-byte SBN header in each product
char *slash_ptr; // pointer for the slashes in the path
progname = argv[0]; // Get the program name
if (argc != 2) { // Only 1 parameter - the template for the output file name.
usage (argv[0]);
exit (1);
}
len = (size_t) strlen (argv[1]) + 7 + 1; // Allocate 7 extra bytes for the ".XXXXXX"
// plus 1 for the terminating nul
if ((out_template = malloc (len)) == NULL) { // Try to malloc memory for output file name
fprintf (stderr, "%s: Error \"%s\" while allocating memory for output template -- exiting\n",
progname, strerror (errno));
exit (errno);
}
sprintf (out_template, "%s.XXXXXX", argv[1]); // Output file name template
// the reasons the DIR_PERMS are 777 is because of NFS permission issues with mkdir
// make sure all of the intervening directories in out_template actually exist
slash_ptr = strchr ( out_template, '/' );
while ( slash_ptr != NULL )
{
*slash_ptr = '\0'; // truncate at the slash
if ( strlen( out_template ) > 0 ) // corner case with a leading slash
{
if ( mkdir ( out_template, DIR_PERMS ) == - 1 && errno != EEXIST )
{
// it failed but not because the directory already exists
fprintf ( stderr, "mkdir errno %d\n", errno );
if ( errno == EPERM )
{
fprintf ( stderr, "mkdir permission error\n" );
}
exit (errno);
}
}
*slash_ptr = '/'; // put the slash back
++slash_ptr;
slash_ptr = strchr ( slash_ptr, '/' ); // find the next slash
}
if ((out_fd = mkstemp (out_template)) == -1) { // Create and open a unique temporary file for output
fprintf (stderr, "%s: Error \"%s\" creating temporary file for template %s -- exiting\n",
progname, strerror (errno), out_template);
exit (errno);
}
// Try to read some data from STDIN
if ((len = read (STDIN_FILENO, file_buf, MAX_BUF_SIZE)) < 0) { // Error if read return negative value -- clean up
fprintf (stderr, "%s: Error \"%s\" reading from STDIN -- exiting\n",
progname, strerror (errno));
close (out_fd);
unlink (out_template);
exit (errno);
} else if (len == 0) { // Input data stream is empty -- clean up
fprintf (stderr, "%s: File is empty -- ignoring\n", progname);
close (out_fd);
unlink (out_template);
exit (0);
}
// If we're here, then we read some bytes from STDIN.
// If the input buffer is less than 128 bytes, then only search through the number of bytes read
if ((hdr_ptr = memmem (file_buf, (len < HDR_DEPTH) ? len : HDR_DEPTH, cruft_hdr, CRUFT_HDR_SIZE)) == NULL) {
// then there is no cruft header within the first HDR_DEPTH bytes
if ((wlen = write (out_fd, file_buf, len)) != len) { // Try to write the input buffer to the output file
fprintf (stderr, "%s: Error \"%s\" writing to %s -- exiting\n", progname, strerror (errno), out_template);
close (out_fd);
unlink (out_template);
exit (errno);
}
// Read the rest of the input data and write it to the output file, exit on error
while ((len = read (STDIN_FILENO, file_buf, MAX_BUF_SIZE)) > 0) {
if ((wlen = write (out_fd, file_buf, len)) != len) {
fprintf (stderr, "%s: Error \"%s\" writing to %s -- exiting\n", progname, strerror (errno), out_template);
close (out_fd);
unlink (out_template);
exit (errno);
}
}
if (len < 0) { // Uh oh, there was an error reading from STDIN
fprintf (stderr, "%s: Error \"%s\" reading from STDIN -- exiting\n",
progname, strerror (errno));
close (out_fd);
unlink (out_template);
exit (errno);
}
close (out_fd); // Close the output file
} else { // Found a cruft header
// Write the 24-byte SBN header to the output file before closing it. Cruft will append to this file.
sbn_hdr_ptr = hdr_ptr - (WMO_HDR_SIZE + SBN_HDR_SIZE);
// Change compression flag from 'E' to 'U'
if (file_buf[0] == 0x40) {
if (file_buf[DECRYPT_FLAG_OFFSET] == 'E') {
file_buf[DECRYPT_FLAG_OFFSET] = 'U';
}
}
if ((wlen = write (out_fd, sbn_hdr_ptr, SBN_HDR_SIZE)) != SBN_HDR_SIZE) {
fprintf (stderr, "%s: Error \"%s\" writing SBN header to %s -- exiting\n", progname, strerror (errno), out_template);
close (out_fd);
unlink (out_template);
exit (errno);
}
close (out_fd);
if (chmod (out_template, OPEN_FILE_PERMS) < 0) { // Set file perms to 0600 so cruft can write to it.
fprintf (stderr, "%s: Error \"%s\" changing file permissions on %s to %od\n",
progname, strerror (errno), out_template, DONE_FILE_PERMS);
}
sprintf (command_line, "%s >> %s", ENCRYPT_PROGRAM, out_template); // Create pipe command line
if ((out_pipe = popen (command_line, "w")) == NULL) { // Try to open pipe for output to cruft
fprintf (stderr, "%s: Error \"%s\" while attempting to open pipe to %s -- exiting\n",
progname, strerror (errno), command_line);
unlink (out_template); // Clean up mess
exit (errno);
}
wlen = file_buf + len - hdr_ptr; // Calculate the length of the output buffer from the start of the cruft header
if ((count = fwrite (hdr_ptr, wlen, 1, out_pipe)) != 1) { // Try to pipe the output buffer to cruft
fprintf (stderr, "%s: Error \"%s\" writing to output pipe -- only wrote %d items exiting\n",
progname, strerror (errno), (int) count);
fclose (out_pipe);
unlink (out_template); // Clean up mess
exit (errno);
}
while ((len = read (STDIN_FILENO, file_buf, MAX_BUF_SIZE)) > 0) {
if ((count = fwrite (file_buf, len, 1, out_pipe)) != 1) {
fprintf (stderr, "%s: Error \"%s\" writing to output pipe -- only wrote %d items exiting\n",
progname, strerror (errno), (int) count);
fclose (out_pipe);
unlink (out_template); // Clean up mess
exit (errno);
}
}
if (len < 0) { // Uh oh, there was an error reading from STDIN
fprintf (stderr, "%s: Error \"%s\" reading from STDIN -- exiting\n", progname, strerror (errno));
fclose (out_pipe);
unlink (out_template); // Clean up the mess
exit (errno);
}
fclose (out_pipe);
sprintf(pqinsert_line, "%s %s", INSERT_PROGRAM, out_template);
if((system(pqinsert_line)) > 0) {
fprintf (stderr, "%s: Error \"%s\" running pqinsert -- file not inserted into data stream\n", progname, strerror (errno));
}
}
// Change file permissions on output file to 0666 as a signal to anyone watching that the file is available for access now
if (chmod (out_template, DONE_FILE_PERMS) < 0) {
fprintf (stderr, "%s: Error \"%s\" changing file permissions on %s to %od\n", progname, strerror (errno), out_template, DONE_FILE_PERMS);
}
exit (0);
}