/* secure database * * This file is part of the CRYPTO BONE Project * File: cryptoboneexternd.c (external cryptobone daemon) * Version : 1.5 (EXTERN) * License : BSD * Date : 1 March 2023 * * Summary: * This module implements the encrypted database for the Crypto Bone. * Each entry has the following form: * key:secretvalue\n * Keys are unique and the database must not be empty. * The maximum key length is 100 characters and the character : is not allowed * inside a key. * If the secret value contains newline characters, it must be base64-encoded * before it is handed over to the database. * * In addition the cryptographic code that encrypts messages has been moved * into this daemon code. It was provided previously in a separate binary. * * Copyright (c) 2015-2023 * Ralf Senderek, Ireland. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ralf Senderek. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *****************************************************/ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cryptlib.h" #include #include "armor.h" #define DEBUG 0 #define LARGE 1 #if LARGE #define MAXINPUT 250000 #define MAXWORD 66668 /* max number of bytes for a parameter through socket */ #define PGP_MAXINPUT 50001 #else /* minimal, compatible with version 1.0.3*/ #define MAXINPUT 50000 #define MAXWORD 66668 /* max number of bytes for a parameter through socket */ #define PGP_MAXINPUT 50001 #endif #define MAX 512 #define BASEDIRECTORY "/usr/lib/cryptobone/ext" #define SOCK_PATH BASEDIRECTORY"/secrets.sock" #define DATABASEFILE BASEDIRECTORY"/database" #define DATABASEBACKUP DATABASEFILE".back" #define INTERNAL_BUFFER_SIZE MAXINPUT+1024 #define MAXBUF 2*MAXINPUT #define KEYLEN 101 #define cryptUser CRYPT_UNUSED #define MAXBOOTSECONDS 120 unsigned char plaintext[MAXINPUT] ; unsigned char input[MAXBUF]; unsigned char output[MAXBUF*4/3]; /* output holds base64 encoded data and exceeds input */ unsigned char password[KEYLEN]; int passwordLength = 0; int status; int num; unsigned char *sptr = NULL; FILE *fp; /******* BEGIN PGP functions ***********************************************************/ #define PGP_MAXBUF 2*PGP_MAXINPUT #define MAXLINE 200 #define PGP_INTERNAL_BUFFER_SIZE PGP_MAXINPUT+1024 #define BYTE unsigned char #define OUTFILE BASEDIRECTORY"/cryptobone/encryptedmessage.asc" #define PGP_VERSION "Version: Crypto Bone 1.5 with Cryptlib 3.4.5" unsigned char PGP_plaintext[PGP_MAXINPUT] ; unsigned char PGP_input[PGP_MAXBUF]; unsigned char PGP_output[PGP_MAXBUF*4/3]; /* output holds base64 encoded data and exceeds input */ unsigned char PGP_text[(PGP_MAXBUF*4/3)+1024]; /* holds armored data and format info */ unsigned char CODE[6]; /* CRC-24 code (base64-encoded) with = */ unsigned char CRC[5]; /* CRC-24 code (base64-encoded) without = */ unsigned char PGP_password[KEYLEN]; int PGP_passwordLength = 0; unsigned char FileName[KEYLEN]; /***************************************************************************************/ unsigned long crc24(int len) { #define CRC24_INIT 0xB704CE #define CRC24_POLY 0x1864CFB long crc; crc = CRC24_INIT; int i,j; j = 0; while (len--) { crc ^= (PGP_input[j]) << 16; j++; for (i = 0; i < 8; i++) { crc <<= 1; if (crc & 0x1000000){ crc ^= CRC24_POLY; } } } return crc & 0xFFFFFF; } /***************************************************************************************/ int b64encode(BYTE *dest, int *destBytes , BYTE *src, const int len){ /* * the base64encode function does not handle padding. * one or two bytes have to be processed separately if (len % 3 != 0) . * The number of encoded bytes has to be updated accordingly. * We assume that len is greater than 10 characters */ unsigned char b64char(int position){ char CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if ((position >= 0) && (position < 64)){ return CODES[position]; } return '='; } unsigned char c1, c2, c3; unsigned char c4 = '='; unsigned int byte1, byte2 = 0; if ( len < 10 ) { return -1; } if ( (len % 3) != 0 ) { if ( (len % 3) == 2 ) { byte1 = src[len-2]; byte2 = src[len-1]; /* encode two extra bytes */ status = base64encode(dest, 2*PGP_MAXBUF, destBytes, src, len-2, CRYPT_CERTTYPE_NONE); c1 = b64char( (byte1 >> 2) & 0x3F ); c2 = b64char( ((byte1 << 4) | (byte2 >> 4)) & 0x3F ); c3 = b64char( (byte2 << 2) & 0x3F ); } if ( (len % 3) == 1 ) { /* encode one extra byte */ byte1 = src[len-1]; status = base64encode(dest, 2*PGP_MAXBUF, destBytes, src, len-1, CRYPT_CERTTYPE_NONE); c1 = b64char( (byte1 >> 2) & 0x3F ); c2 = b64char( (byte1 << 4) & 0x3F ); c3 = '='; } dest[*destBytes] = c1 ; *destBytes += 1; dest[*destBytes] = c2 ; *destBytes += 1; dest[*destBytes] = c3 ; *destBytes += 1; dest[*destBytes] = c4 ; *destBytes += 1; dest[*destBytes] = '\0'; } else { /* encoding without padding */ status = base64encode(dest, 2*PGP_MAXBUF, destBytes, src, len, CRYPT_CERTTYPE_NONE); dest[*destBytes] = '\0'; } if ( *destBytes == 0 ){ syslog(LOG_NOTICE,"Error: base64 encoding failed."); return 2; } return status; } /***************************************************************************************/ int b64decode(BYTE *dest, int *destBytes , BYTE *src, const int len){ /* * the base64decode function does not handle padding, so the last * four bytes have to be processed separately. * The number of decoded bytes has to be updated accordingly. * We assume that len is greater than 14 characters */ int position(char c){ char CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (int i=0; i<64; i++){ if ( c == CODES[i] ) return i; } return -1; } unsigned int c1, c2, c3 = 0; if ( len < 14 ) { return -1; } if ( src[len-1] == '=' ) { c1 = position( src[len-4] ) ; c2 = position( src[len-3] ) ; c3 = position( src[len-2] ) ; /* decode the source minus the last 4 bytes */ status = base64decode(dest, 2*PGP_MAXBUF, destBytes, src, len-4, CRYPT_CERTTYPE_NONE); if ( src[len-2] == '=' ){ /* one byte */ dest[*destBytes] = ( ( ( c1 << 2 ) | ( c2 >> 4 ) ) & 0xFF ); *destBytes += 1; } else { /* two bytes */ dest[*destBytes] = ( ( ( c1 << 2 ) | ( c2 >> 4 ) ) & 0xFF ); *destBytes += 1; dest[*destBytes] = (unsigned char) ( ( ( c2 << 4 ) | ( c3 >> 2) ) & 0xFF ); *destBytes += 1; } dest[*destBytes] = '\0'; } else { /* decoding without padding */ status = base64decode(dest, 2*PGP_MAXBUF, destBytes, src, len, CRYPT_CERTTYPE_NONE); } if ( *destBytes == 0 ){ syslog(LOG_NOTICE,"Error: base64 decoding failed."); return 2; } return status; } /***************************************************************************************/ int pgp_encrypt(){ /* * Reads from PGP_plaintext and writes the cryptogram to PGP_input and * base64-encoded to PGP_output. * PGP_output is stored in a file "encryptedmessage.asc" */ unsigned int i = 0; int j = 0; /* must be signed */ unsigned int bytesCopied = 0; unsigned int PGP_plaintextLength = strlen(PGP_plaintext); unsigned char BYTES[10]; unsigned long crcL; if (PGP_plaintextLength >= PGP_MAXINPUT){ if (DEBUG) syslog(LOG_NOTICE,"Error: PGP_plaintext is too big."); return 2; } if (PGP_plaintextLength == 0){ if (DEBUG) syslog(LOG_NOTICE,"Error: PGP_plaintext is empty."); return 3; } CRYPT_ENVELOPE cryptEnvelope; if (DEBUG) syslog(LOG_NOTICE,"%i bytes to be encrypted: %s \n",PGP_plaintextLength, PGP_plaintext); status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_PGP ); if (DEBUG) syslog(LOG_NOTICE,"STATUS: %i \n",status); if( status != CRYPT_OK ){ if (DEBUG) syslog(LOG_NOTICE,"CryptLib: Envelope cannot be created."); return 4; } /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, PGP_INTERNAL_BUFFER_SIZE ); if (DEBUG) syslog(LOG_NOTICE,"STATUS (buffsize): %i \n",status); /* Add the password */ PGP_passwordLength = strlen(PGP_password); if (PGP_passwordLength < 20){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (PGP_passwordLength > 64){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (DEBUG) syslog(LOG_NOTICE,"Using PGP password %s of length %i\n",PGP_password,PGP_passwordLength); status = cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, PGP_password, PGP_passwordLength ); if( status != CRYPT_OK ){ if (DEBUG) syslog(LOG_NOTICE,"CryptLib: password error"); return 5; } if (DEBUG) syslog(LOG_NOTICE,"STATUS (pw): %i : (%i) \n",status, PGP_passwordLength); if (PGP_plaintextLength > 9) { cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, PGP_plaintextLength ); status = cryptPushData( cryptEnvelope, PGP_plaintext, PGP_plaintextLength, &bytesCopied ); if (DEBUG) syslog(LOG_NOTICE,"STATUS (push): %i and %i bytes pushed in \n",status,bytesCopied); status = cryptFlushData( cryptEnvelope ); if (DEBUG) syslog(LOG_NOTICE,"STATUS (flush): %i \n",status); /* create cryptogram in buffer PGP_input */ status = cryptPopData( cryptEnvelope, PGP_input, PGP_MAXBUF, &bytesCopied ); if (DEBUG) syslog(LOG_NOTICE,"STATUS: %i \n",status); if (DEBUG) syslog(LOG_NOTICE,"encrypted Buffer has %i bytes\n", bytesCopied); /* status = base64encode(PGP_output, 2*PGP_MAXBUF, &num, PGP_input, bytesCopied, CRYPT_CERTTYPE_NONE); */ status = b64encode(PGP_output, &num, PGP_input, bytesCopied); if (DEBUG) syslog(LOG_NOTICE,"in:[] %i bytes\n",(int) strlen(PGP_input)); if (DEBUG) syslog(LOG_NOTICE,"out:[%s] %i bytes\n",PGP_output, (int) strlen(PGP_output)); /* write result to file */ fp = fopen(OUTFILE,"w"); if (!fp){ syslog(LOG_NOTICE,"Error: PGP_output file is not writeable"); return 1; } else { if (DEBUG) syslog(LOG_NOTICE,"saving ... %s with %i bytes (num=%i) \n",PGP_output, (int) strlen(PGP_output),num); fputs("-----BEGIN PGP MESSAGE-----\n",fp); fputs(PGP_VERSION,fp); fputs("\n\n",fp); /* print armored block */ for ( i=0; i < strlen(PGP_output); i++ ){ if ((i>0) && (i%64 == 0)) fputs("\n",fp); fputc(PGP_output[i],fp); } fputs("\n",fp); /* calculate CRC code */ crcL = crc24(bytesCopied); for (j=2; j >= 0; j--){ BYTES[j] = (crcL%256); crcL = crcL/256; } /* cryptlib has a minimum PGP_input of 10 characters, so padding is needed */ /* fill byte 4-9 with pad */ for (int i=3; i<10; i++){ BYTES[i] = '\0'; } status = base64encode(PGP_output, 2*PGP_MAXBUF, &num, BYTES, 10, CRYPT_CERTTYPE_NONE); CODE[0] = '='; CODE[5] = '\0'; CODE[1] = PGP_output[0]; CODE[2] = PGP_output[1]; CODE[3] = PGP_output[2]; CODE[4] = PGP_output[3]; fputs(CODE,fp); fputs("\n",fp); fputs("-----END PGP MESSAGE-----\n",fp); fclose(fp); } } else { if (DEBUG) syslog(LOG_NOTICE,"Error: plain text too short. Must be at least 10 chars."); return 3; } status = cryptDestroyEnvelope( cryptEnvelope ); if( status != CRYPT_OK ){ if (DEBUG) syslog(LOG_NOTICE,"CryptLib: Envelope cannot be destroyed."); return 5; } return 0; } /***************************************************************************************/ int pgp_decrypt(){ /* * reads base64 cryptogram from PGP_output decodes to * PGP_input and writes the decrypted message to PGP_plaintext */ int bytesCopied = 0; int i; int length = 0; unsigned char BYTES[3]; unsigned char IN[17]; unsigned char OUT[13]; unsigned char testchar; unsigned long crcL; CRYPT_ENVELOPE cryptEnvelope; /* * cryptograms that are created with GnuPG need to deactivate mcd and compression * to be decryptable. (options --compress-level 0 --disable-mdc) */ /* The size of the cryptogram is limited by the size of a word that can * be read from the socket */ /* decodes PGP_output and writes the result to PGP_input */ status = b64decode(PGP_input, &num, PGP_output, strlen(PGP_output)); if (DEBUG) syslog(LOG_NOTICE,"base64: %i bytes received in PGP_input (status: %i)\n",num, status); if ( num == 0 ){ if (DEBUG) syslog(LOG_NOTICE,"Error: base64 decoding failed."); return 1; } /* check CRC code */ /* cryptlib: base64decode has a minimal PGP_input of 10, so padding is needed */ for (int i=0; i<16; i++){ IN[i] = 'A'; } IN[16] = '\0'; IN[0] = CRC[0]; IN[1] = CRC[1]; IN[2] = CRC[2]; IN[3] = CRC[3]; status = base64decode(OUT, 12, &length, IN, 16, CRYPT_CERTTYPE_NONE); /* if (DEBUG) syslog(LOG_NOTICE," PGP_input: %s status: %i [len %i] \nout: \n%s\n",IN,status,length,OUT); */ BYTES[0] = OUT[0]; BYTES[1] = OUT[1]; BYTES[2] = OUT[2]; if (DEBUG) syslog(LOG_NOTICE," CRC: %s dec [%i %i %i]\n",OUT, BYTES[0], BYTES[1], BYTES[2]); /* calculate CRC code */ crcL = crc24(num); for (i=2; i >= 0; i--){ testchar = (crcL%256); if (DEBUG) syslog(LOG_NOTICE,"%i ", testchar); if (testchar != BYTES[i]) { if (DEBUG) syslog(LOG_NOTICE,"Decryption Error: CRC is invalid."); return 1; } crcL = crcL/256; } if (strlen(PGP_input) > 1){ /* decrypt */ status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_AUTO ); /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, PGP_INTERNAL_BUFFER_SIZE ); status = cryptPushData( cryptEnvelope, PGP_input, PGP_MAXBUF, &bytesCopied ); if (DEBUG) syslog(LOG_NOTICE,"\n %i bytes PGP_input to decrypt\n", bytesCopied); PGP_passwordLength = strlen(PGP_password); if (PGP_passwordLength < 20){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (PGP_passwordLength > 64){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (DEBUG) syslog(LOG_NOTICE,"Using PGP password %s of length %i\n",PGP_password, PGP_passwordLength); cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, PGP_password, PGP_passwordLength ); status = cryptFlushData( cryptEnvelope ); if (DEBUG) syslog(LOG_NOTICE,"STATUS %i\n",status); status = cryptPopData( cryptEnvelope, PGP_plaintext, PGP_MAXBUF, &bytesCopied ); if (status != CRYPT_OK){ if (status == -32){ syslog(LOG_NOTICE,"PGP_Error: PGP_input data is corrupt."); } if (status == -33){ syslog(LOG_NOTICE,"PGP_Error: integrity check failed."); } if (DEBUG) syslog(LOG_NOTICE,"decryption status is %i \n",status); return 1; } PGP_plaintext[bytesCopied] = '\0'; if (DEBUG) syslog(LOG_NOTICE,"decryption status is %i \n",status); status = cryptDestroyEnvelope( cryptEnvelope ); if( status != CRYPT_OK ){ if (DEBUG) syslog(LOG_NOTICE,"CryptLib: Envelope cannot be destroyed."); return 5; } } return 0; } /***************************************************************************************/ char* pgp_check_crypto(){ /* * performs an unsuccessful decryption on an PGP_input buffer and reports the * ALGO used. */ char ModeInfo[4]; int Algo = 0; int Mode = 0; int Keysize = 0; int bytesCopied = 0; CRYPT_ENVELOPE cryptEnvelope; /* decodes PGP_output and writes the result to PGP_input */ status = b64decode(PGP_input, &num, PGP_output, strlen(PGP_output)); if (DEBUG) syslog(LOG_NOTICE,"base64: %i bytes received in PGP_input (status: %i) ",num ,status); if (strlen(PGP_input) > 1){ /* decrypt with wrong key */ status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_AUTO ); /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, PGP_INTERNAL_BUFFER_SIZE ); status = cryptPushData( cryptEnvelope, PGP_input, PGP_MAXBUF, &bytesCopied ); if (DEBUG) syslog(LOG_NOTICE,"PGP_CHECK: %i bytes PGP_input to decrypt\n", bytesCopied); /* use wrong key deliberately */ strlcpy(PGP_password,"12345",6); PGP_passwordLength = strlen(PGP_password); if (DEBUG) syslog(LOG_NOTICE,"Using wrong PGP password %s of length %i\n", PGP_password, PGP_passwordLength); cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, PGP_password, PGP_passwordLength ); status = cryptFlushData( cryptEnvelope ); /* check the encryption information */ status=cryptGetAttribute(cryptEnvelope, CRYPT_CTXINFO_ALGO, &Algo); status=cryptGetAttribute(cryptEnvelope, CRYPT_CTXINFO_MODE, &Mode); status=cryptGetAttribute(cryptEnvelope, CRYPT_CTXINFO_KEYSIZE, &Keysize); if (Mode == 1) strlcpy(ModeInfo,"ECB",4); if (Mode == 2) strlcpy(ModeInfo,"CBC",4); if (Mode == 3) strlcpy(ModeInfo,"CFB",4); Keysize = Keysize*8; if (DEBUG) { syslog(LOG_NOTICE,"mode: %i (%s)\n",Mode, ModeInfo); } if (DEBUG) { syslog(LOG_NOTICE,"Keysize: %i bit\n",Keysize); } if (DEBUG) { syslog(LOG_NOTICE,"ALGO: %i\n",Algo); } if (Algo == 2) { return "3DES encrypted data"; } if (Algo == 4) { return "CAST5 encrypted data"; } if (Algo == 8) { return "AES encrypted data"; } status = cryptDestroyEnvelope( cryptEnvelope ); if( status != CRYPT_OK ){ return "CryptLib_Error"; } } else { /* puts("Error: no PGP_input data."); */ return "PGP_Error"; } return "FAILED"; } /***************************************************************************************/ int analyse_text_PGP_input() { unsigned int Start = 0; unsigned int End = strlen(PGP_text); char PGP_BEGIN[30] = "-----BEGIN PGP MESSAGE-----\n"; char PGP_END[30] = "-----END PGP MESSAGE-----\n"; unsigned int i,j,length; int begin = 0; /* find the armored data in a PGP message (pgp_text) and copy to PGP_output */ /* find -----BEGIN */ length = strlen(PGP_text); i = 0; while ( (begin == 0) && (i= MAXINPUT){ return 2; } int bytesCopied = 0; int plaintextLength = strlen(plaintext); if (plaintextLength == 0){ syslog(LOG_NOTICE,"Error: plaintext is empty."); return 3; } CRYPT_ENVELOPE cryptEnvelope; status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_CRYPTLIB ); if( status != CRYPT_OK ){ syslog(LOG_NOTICE,"Error: Cryptlib enveloping."); return 3; } /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, INTERNAL_BUFFER_SIZE ); /* Add the password */ passwordLength = strlen(password); if (passwordLength < 20){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (passwordLength > 64){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (DEBUG) syslog(LOG_NOTICE,"Using password of length %i\n",passwordLength); status = cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, password, passwordLength ); cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, plaintextLength ); status = cryptPushData( cryptEnvelope, plaintext, plaintextLength, &bytesCopied ); status = cryptFlushData( cryptEnvelope ); /* create cryptogram in buffer input */ status = cryptPopData( cryptEnvelope, input, MAXBUF, &bytesCopied ); if (DEBUG) syslog(LOG_NOTICE,"encrypted Buffer has %i bytes\n", bytesCopied); if (status == CRYPT_OK){ status = base64encode(output, 2*MAXBUF, &num, input, bytesCopied, CRYPT_CERTTYPE_NONE); if (DEBUG) syslog(LOG_NOTICE,"base64 input %i bytes output %i bytes \n", bytesCopied, num); /* make backup of the database file */ FILE* fd = popen("/bin/cp "DATABASEFILE" "DATABASEBACKUP, "r"); if (fd != NULL ){ pclose(fd); if (DEBUG) syslog (LOG_NOTICE,"backup created"); newfd = open(DATABASEBACKUP,O_RDWR); fchmod(newfd,S_IRUSR | S_IWUSR); close(newfd); } /* write result to file */ fp = fopen(DATABASEFILE,"w"); if (!fp){ syslog(LOG_NOTICE,"Error: database is not available"); return 5; } else { fputs(output,fp); fclose(fp); /* change file permissions to 0600 */ newfd = open(DATABASEFILE,O_RDWR); fchmod(newfd,S_IRUSR | S_IWUSR); close(newfd); } } status = cryptDestroyEnvelope( cryptEnvelope ); if( status != CRYPT_OK ){ syslog(LOG_NOTICE,"Error: Envelope cannot be destroyed."); return 4; } return 0; } /***************************************************************************************/ int aes_decrypt(){ /* * reads base64 cryptogram from database file (output) decodes to input and * writes the decrypted message to plaintext */ if (get_masterkey() != 0){ syslog(LOG_NOTICE,"Error: no key, decryption failed."); return 4; } int bytesCopied = 0; CRYPT_ENVELOPE cryptEnvelope; /* read database file */ fp = fopen(DATABASEFILE,"r"); if (!fp){ syslog(LOG_NOTICE,"Error: database is not readable."); return 1; } else { sptr = fgets(output,MAXBUF*4/3,fp); fclose(fp); } /* decodes output and writes the result to input */ status = b64decode(input, &num, output, strlen(output)); if (DEBUG) syslog(LOG_NOTICE,"base64: %i bytes received in input (status: %i)",num, status); if ( num == 0 ){ if (DEBUG) syslog(LOG_NOTICE,"Error: base64 decoding failed."); return 1; } /* decrypt */ status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_AUTO ); /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, INTERNAL_BUFFER_SIZE ); status = cryptPushData( cryptEnvelope, input, MAXBUF, &bytesCopied ); /* Add the password */ passwordLength = strlen(password); if (passwordLength < 20){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (passwordLength > 64){ syslog(LOG_NOTICE,"Error: invalid key, encryption failed."); return 3; } if (DEBUG) syslog(LOG_NOTICE,"Using password of length %i\n",passwordLength); cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, password, passwordLength ); status = cryptFlushData( cryptEnvelope ); status = cryptPopData( cryptEnvelope, plaintext, MAXBUF, &bytesCopied ); if (status != CRYPT_OK){ //puts("Error: decryption failed."); if (status == -32){ syslog(LOG_NOTICE,"Error: database is corrupt."); } syslog(LOG_NOTICE,"Error: decryption failed status %i ",status); status = cryptDestroyEnvelope( cryptEnvelope ); return 5; } status = cryptDestroyEnvelope( cryptEnvelope ); return 0; } /***************************************************************************************/ void get_keys(char *values){ int x=0; int i=0; int begin = 1; char key[KEYLEN]; strlcpy(values,"",MAXINPUT); strlcpy(key,"",MAXINPUT); if (DEBUG) syslog(LOG_NOTICE,"get_keys: plaintext %i bytes.", (int) strlen(plaintext)); for (x=0; x 1){ snprintf(pscommand, 100, "/bin/ps -ocmd %d", parentid); FILE* fd = popen(pscommand, "r"); if (fd != NULL ){ while (fgets(line,sizeof(line),fd) != NULL) { /* /usr/lib/cryptobone is now the only place to go */ if (strstr(line,"/usr/lib/cryptobone/") != 0){ pclose(fd); /* further checking omitted, is cbcontrol started via sudo? */ return 0; } if (strstr(line,"/usr/lib64/cryptobone/") != 0){ pclose(fd); /* further checking omitted, is cbcontrol started via sudo? */ return 0; } } pclose(fd); } } } return -1; } /*************************************************************************/ void write_sock(int conn, char *val) { /* max MAXINPUT Bytes output through socket */ int numbytes = 0; numbytes = strlen(val); if ((numbytes > 0) && (numbytes < MAXINPUT)){ status = write (conn, val, numbytes); } } /*************************************************************************/ int connection_handler( int connection ){ int ucred_length = sizeof(struct ucred); struct ucred credentials; int numbytes = 0; int ret = 0; int MAXBYTES = 8192; char inbuf[MAXBYTES+5000]; /* 33*MAXBYTES > 4*MAXWORD */ char buffer[4*MAXWORD+1024+MAXBYTES]; char value[MAXINPUT]; char *strptr; char pattern[5]; char src[MAXLINE]; char Line[MAXLINE]; char NewLine[MAXLINE]; char command[100]; int pos = 0; int i = 0; int j = 0; unsigned char words[4][MAXWORD+1]; unsigned int x = 0; int POLLING = 1; int count = 0; int bytesread = 0; /* check if connection is legitimate */ ret = getsockopt(connection, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length); if ( ret > -1 ) { if (DEBUG){ syslog(LOG_NOTICE,"PID: %d",credentials.pid); syslog(LOG_NOTICE,"UID: %d",credentials.uid); } /* exit if not a root process */ if ( credentials.uid != 0 ) { syslog(LOG_NOTICE,"Alert: UID: %d tried to use the external cryptobone daemon!",credentials.uid); return -1; } if (checkparent(credentials.pid) == 0){ /* syslog(LOG_NOTICE,"LEGITIMATE ACCESS BY cbcontrol"); */ /* now analyse the socket input and start secrets function */ /* init buffer */ for (j=0; j < (4*MAXWORD)+1; j++){ buffer[j] = '\0'; } j = 0; /* read max 4*MAXWORD bytes from socket */ bytesread = 0; numbytes = 0; POLLING = 1; while (POLLING > 0){ /* blocks until input is received */ if (numbytes < (4*MAXWORD - MAXBYTES)) { bytesread = read(connection, inbuf, MAXBYTES); if (DEBUG) syslog(LOG_NOTICE,"input buffer read (%i bytes) ",bytesread); if (bytesread <= 0) { POLLING = 0; } else { /* append inbuf to buffer */ if (DEBUG) syslog(LOG_NOTICE,"append input buffer (%i bytes) ",bytesread); for (j=0; j 0){ buffer[numbytes] = '\0'; } if (DEBUG) syslog(LOG_NOTICE,"buffer (length %i bytes) numbytes: %i \n: ", (int) strlen(buffer), numbytes); /* analyse buffer input from socket, split into words */ /* * since words are limited to 66668 bytes, no secret value can * be larger than the decoded value of 50001 bytes */ /* init words */ for (i=0; i<4; i++){ for (j=0; j <= MAXWORD; j++){ words[i][j] = '\0'; } } i = 0; j = 0; while ((x < numbytes) && ( i<4 )) { if ((buffer[x] != ' ') && (buffer[x] != ' ') && (buffer[x] != '\n')) { if (j < MAXWORD) { /* skipped : perform input validation A_Z@.a-z0-9 */ words[i][j] = buffer[x]; j++; } else { /* full, force end of word */ words[i][j] = '\0'; i++; j=0; /* skip rest of word until white space is hit */ while ( (x < numbytes) && ((buffer[x] != ' ') && (buffer[x] != ' ')) ) { x++; } } x++; } else { words[i][j] = '\0'; i++; j = 0; x++; /* skip white space */ while ( (x < numbytes) && ((buffer[x] == ' ') || (buffer[x] == ' ')) ) { x++; } } } if (DEBUG) syslog(LOG_NOTICE,"Words %i %i %i %i \n: ", (int) strlen(words[0]), (int) strlen(words[1]), (int) strlen(words[2]), (int) strlen(words[3])); /* now call SECRETS.c functions */ if (strcmp(words[0],"init") == 0) { /* do not overwrite an existing database file */ fp = fopen(DATABASEFILE,"r"); if (!fp){ strlcpy(plaintext, "cryptobone:version 1.5\n", MAXINPUT); aes_encrypt(); write_sock(connection,"\nThis is the database:\n"); write_sock(connection,plaintext); } else { syslog(LOG_NOTICE,"Error (init): database file exists."); fclose(fp); } } if (strstr(words[0],"all-keys") != 0) { get_keys(output); write_sock(connection,output); } if (strstr(words[0],"write") != 0){ if (strlen(words[2]) > 0){ /* store_element key:value\n */ /* does not overwrite, if key exists */ if (has_key(words[1]) == 0) { numbytes = strlen(plaintext) + 2 + strlen(words[1]) + strlen(words[2]); if (DEBUG) syslog(LOG_NOTICE,"try writing to database %d bytes (%s)\n",numbytes,words[1]); if (numbytes < MAXINPUT){ strlcat(plaintext, words[1], MAXINPUT); strlcat(plaintext, ":", MAXINPUT); strlcat(plaintext, words[2], MAXINPUT); strlcat(plaintext, "\n", MAXINPUT); aes_encrypt(); if (DEBUG) syslog(LOG_NOTICE,"%d bytes written (%s)\n",numbytes,words[1]); write_sock(connection,"OK"); } else write_sock(connection,"FAILED"); } else write_sock(connection,"SKIPPED"); } } if (strstr(words[0],"get-element") != 0){ if (strlen(words[1]) > 0){ /* _element(); */ get_element(value, words[1]); write_sock(connection,value); } } if (strstr(words[0],"replace") != 0){ if (strlen(words[2]) > 0){ /* key, newvalue */ /* if key does not exist, create entry */ if (has_key(words[1]) == 0) { numbytes = strlen(plaintext) + 2 + strlen(words[1]) + strlen(words[2]); if (DEBUG) syslog(LOG_NOTICE,"replace: try writing to database %d bytes (%s)\n",numbytes,words[1]); if (numbytes < MAXINPUT){ strlcat(plaintext, words[1], MAXINPUT); strlcat(plaintext, ":", MAXINPUT); strlcat(plaintext, words[2], MAXINPUT); strlcat(plaintext, "\n", MAXINPUT); aes_encrypt(); if (DEBUG) syslog(LOG_NOTICE,"replace NEW: %i bytes written (%s)\n",numbytes,words[1]); write_sock(connection,"OK"); } else { if (DEBUG) syslog(LOG_NOTICE,"ERROR:replace: writing %i bytes to %s\n",numbytes,words[1]); write_sock(connection,"FAILED"); } } else { if (DEBUG) syslog(LOG_NOTICE,"replace: calling function replace_element" ); ret = replace_element(words[1], words[2]); if (ret == 0) write_sock(connection,"OK"); else write_sock(connection,"FAILED"); } } } if (strstr(words[0],"remove") != 0){ if (strlen(words[1]) > 0){ /* key */ ret = remove_element(words[1]); if (ret == 0) write_sock(connection,"OK"); else write_sock(connection,"FAILED"); } } /* end SECRETS.c functions */ /* begin OPENPGP.c functions */ if (strstr(words[0],"encrypt") != 0){ if (strlen(words[2]) > 0){ /* PGP_key */ strlcpy(PGP_password, words[2], KEYLEN); if (! ((strlen(PGP_password) >= 20) && (strlen(PGP_password) < KEYLEN))){ if (DEBUG) syslog(LOG_NOTICE,"PGP_Error: invalid encryption key. %i bytes", (int) strlen(PGP_password)); write_sock(connection,"FAILED"); return 4; } if (strlen(words[1]) > 0){ /* decrypt base64encoded message, write to PGP_plaintext */ status = b64decode(PGP_plaintext, &num, words[1], strlen(words[1])); if (status != 0) { syslog(LOG_NOTICE,"PGP_Error: base64decryption of input failed."); write_sock(connection,"FAILED"); return 2; } else { if ( num < PGP_MAXINPUT){ /* now encrypt */ PGP_plaintext[num] = '\0'; /* remove old cryptogram */ FILE* fd = popen("rm -f "OUTFILE, "r"); if (fd) pclose(fd); status = pgp_encrypt(); if (status != 0) { syslog(LOG_NOTICE,"PGP_Error: encryption failed."); write_sock(connection,"FAILED"); } else{ write_sock(connection,"ENCRYPTED"); } } else { syslog(LOG_NOTICE,"PGP_Error: decoded input too large."); write_sock(connection,"FAILED"); } } } } } if (strstr(words[0],"decrypt") != 0){ if (strlen(words[2]) > 0){ /* PGP_key */ strlcpy(PGP_password, words[2], KEYLEN); if (! ((strlen(PGP_password) >= 20) && (strlen(PGP_password) < KEYLEN))){ if (DEBUG) syslog(LOG_NOTICE,"PGP_Error: invalid encryption key. %i bytes", (int) strlen(PGP_password)); write_sock(connection,"FAILED"); return 4; } if (strlen(words[1]) > 0){ /* encrypted file name */ fp = fopen(words[1],"r"); if (!fp){ syslog(LOG_NOTICE,"PGP_Error: input file is not readable\n"); write_sock(connection,"FAILED"); return 2; } else { strlcpy(PGP_text,"",PGP_MAXBUF*4/3); while (!feof(fp)){ sptr = fgets(Line,MAXLINE,fp); /* remove \r in Line */ i = 0; j = 0; while (i < strlen(Line)){ if (Line[i] != '\r') { NewLine[j] = Line[i]; j++; } i++; } NewLine[j] = '\0'; if (!feof(fp)) strlcat(PGP_text, NewLine, PGP_MAXBUF*4/3); } fclose(fp); } status = analyse_text_PGP_input(); if (status == 0) { status = pgp_decrypt(); if ( status == 0){ /* successful decryption */ /* determine output file name from words[1] */ strlcpy(pattern,".asc",5); strlcpy(src,words[1],MAXLINE); strptr = strstr(src,pattern); pos = strptr - src; /* syslog(LOG_NOTICE,"found pos %i\n",pos); */ if (strptr != 0) { strncpy(FileName, words[1] ,pos); /* remove old plaintext file */ snprintf(command, 100, "/bin/rm -f %s", FileName); FILE* fd = popen(command, "r"); if (fd) pclose(fd); /* write result to file */ fp = fopen(FileName,"w"); if (!fp){ syslog(LOG_NOTICE,"PGP_Error: output file is not writeable"); write_sock(connection,"FAILED"); } else { if (DEBUG) syslog(LOG_NOTICE,"PGP: saving ... %s with %i bytes \n",PGP_plaintext, (int) strlen(PGP_plaintext)); fputs(PGP_plaintext,fp); fclose(fp); write_sock(connection,"DECRYPTED"); } } } else { write_sock(connection,"FAILED"); syslog(LOG_NOTICE,"PGP_Error: decryption failed."); } } else { write_sock(connection,"FAILED"); syslog(LOG_NOTICE,"PGP_Error: No valid PGP data found."); } } } } if (strstr(words[0],"check") != 0){ if (strlen(words[1]) > 0){ /* encrypted file name */ fp = fopen(words[1],"r"); if (!fp){ syslog(LOG_NOTICE,"PGP_Error: input file is not readable\n"); write_sock(connection,"FAILED"); } else { strlcpy(PGP_text,"",PGP_MAXBUF*4/3); while (!feof(fp)){ sptr = fgets(Line,MAXLINE,fp); /* remove \r in Line */ i = 0; j = 0; while (i < strlen(Line)){ if (Line[i] != '\r') { NewLine[j] = Line[i]; j++; } i++; } NewLine[j] = '\0'; if (!feof(fp)) strlcat(PGP_text, NewLine, PGP_MAXBUF*4/3); } fclose(fp); status = analyse_text_PGP_input(); if (status == 0) { write_sock(connection, pgp_check_crypto()); /* syslog(LOG_NOTICE,"%s\n",pgp_check_crypto()); */ } else { write_sock(connection,"FAILED"); syslog(LOG_NOTICE,"PGP_Error: No valid PGP data found."); } } } } /* end OPENPGP.c functions */ } } else { /* no credentials do nothing */ syslog(LOG_NOTICE,"no socket options available"); } return 0; } /*************************************************************************/ void cleanup(int sig){ syslog(LOG_NOTICE,"cleaning up ... signal %i shutdown.",sig); int i = 0; /* ZEROIZE password and plaintext */ for (i=0; i < KEYLEN; i++){ password[i] = '\0'; } for (i=0; i < MAXINPUT; i++){ plaintext[i] = '\0'; } syslog(LOG_NOTICE,"cleaning up ... zeroized memory."); unlink (SOCK_PATH); int status = cryptEnd(); if( status != CRYPT_OK ){ /* cryptlib shutdown failed */; syslog(LOG_NOTICE,"Cryptlib failed to shut down. Some sensible data may remain.\n"); } syslog(LOG_NOTICE,"cleaning up ... done."); closelog(); exit(0); } /*************************************************************************/ int hash_checked(unsigned char input[], char storedhashvalue[]){ /* returns 1, if stored hash matches sha256(input) */ int length = strlen(input); CRYPT_CONTEXT hashContext; unsigned char hash[CRYPT_MAX_HASHSIZE]; /* bytes */ unsigned char hashhexvalue[2*CRYPT_MAX_HASHSIZE]; /* hexstring */ int hashLength = 0; const char hex[16] = "0123456789abcdef"; unsigned int byte = 0; unsigned int j = 0; int match = 1; if (DEBUG) syslog(LOG_NOTICE,"in:%s [%i] hash:%s [%i]",input, (int) strlen(input),storedhashvalue, (int) strlen(storedhashvalue)); if ( strlen(input) > 0 ) { status = cryptCreateContext( &hashContext, cryptUser, CRYPT_ALGO_SHA256 ); if( status != CRYPT_OK ){ syslog(LOG_NOTICE,"error: crypt context"); return -1; } cryptEncrypt( hashContext, input, length ); cryptEncrypt( hashContext, "", 0 ); status = cryptGetAttributeString( hashContext, CRYPT_CTXINFO_HASHVALUE, hash, &hashLength ); if (DEBUG) syslog(LOG_NOTICE,"new hash len=%i ",hashLength); /*convert hash to hex string */ for(int i=0; i> 4) & 0x0F]; hashhexvalue[j+1] = hex[byte & 0x0F]; j += 2; } hashhexvalue[j] = '\0'; if (DEBUG) syslog(LOG_NOTICE,"hex hash %s [%i]",hashhexvalue, (int) strlen(hashhexvalue)); status = cryptDestroyContext( hashContext ); /* constant time compare */ match = 1; for (int i=0; i < 64; i++) { if (storedhashvalue[i] != hashhexvalue[i] ) { /* strings differ */ match = 0; } } return match; } return -1; } /*************************************************************************/ int key_connection_handler( int connection, char hashvalue[], int *success){ int ucred_length = sizeof(struct ucred); struct ucred credentials; int ret = 0; int MAXBYTES = 8192; char buffer[MAXBYTES]; int POLLING = 1; unsigned char value[MAX]; int keybytesread = 0; /* check if connection is legitimate */ ret = getsockopt(connection, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length); if ( ret > -1 ) { if (DEBUG){ syslog(LOG_NOTICE,"PID: %d",credentials.pid); syslog(LOG_NOTICE,"UID: %d",credentials.uid); } /* exit if not a root process */ if ( credentials.uid != 0 ) { syslog(LOG_NOTICE,"Alert: UID: %d tried to use the external cryptobone daemon!",credentials.uid); return -1; } /* syslog(LOG_NOTICE,"LEGITIMATE ACCESS BY cbcontrol"); */ /* read 64 bytes from socket */ POLLING = 1; while (POLLING > 0){ keybytesread = read(connection, buffer, MAX); if (DEBUG) syslog(LOG_NOTICE,"key read bytes: [%i]",keybytesread); if (keybytesread > 0) { /* copy first 64 bytes from buffer */ strlcpy(value,buffer,65); value[keybytesread-1] = '\0'; } if (keybytesread <= 0) { POLLING = 0; } } if (DEBUG) syslog(LOG_NOTICE,"key read value=%s [%i]",value, (int) strlen(value)); ret = hash_checked(value,hashvalue); if (ret == 1) { strlcpy(password,value,41); *success = 1; return 0; } } *success = 0; return 0; } /*************************************************************************/ int main(void) { struct sockaddr_un address, client; int sock = 0; /* my socket */ int connection = 0; /* client's socket */ int ret = 0; socklen_t address_length = sizeof(struct sockaddr_un); int keyavailable = 0; char storedhash[66]; /* signal processing */ signal(SIGTERM,cleanup); umask(0177); sock = socket(AF_UNIX, SOCK_STREAM, 0); if ( sock < 0 ) { /* error */ printf("Error: Cannot create socket.\n"); exit(1); } unlink (SOCK_PATH); memset(&address, 0, sizeof(struct sockaddr_un)); memset(&client, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; client.sun_family = AF_UNIX; snprintf(address.sun_path, strlen(SOCK_PATH)+1, SOCK_PATH); ret = bind(sock, (struct sockaddr *) &address, sizeof(struct sockaddr_un)); if ( ret != 0 ) { /* error */ printf( "Error: Cannot bind to socket.\n"); exit(1); } /* listen for exactly one connection */ ret = listen (sock, 1); if ( ret != 0 ) { /* error */ printf( "Error: Listening on socket failed.\n"); exit(1); } /* Our process ID and Session ID */ pid_t pid, sid; /* Fork off the parent process */ pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } /* Exit the parent process. */ if (pid > 0) { exit(EXIT_SUCCESS); } /* Open any logs here */ /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { /* Log the failure */ exit(EXIT_FAILURE); } if ((chdir("/")) < 0) { /* Log the failure */ exit(EXIT_FAILURE); } /* Close out the standard file descriptors */ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); /* NO TERMINAL AFTER THIS POINT */ /* Daemon-specific initialization goes here */ openlog ("cryptoboneextern_daemon", LOG_PID, LOG_DAEMON); /* log successful start of daemon */ syslog(LOG_NOTICE,"external cryptobone daemon started by user %d. Ready for connections.",getuid()); /* read the master key's stored hash value */ fp = fopen(BASEDIRECTORY"/masterkey.hash","r"); if (!fp){ syslog(LOG_NOTICE,"Master key hash is missing."); exit(2); } else { sptr = fgets(storedhash,65,fp); fclose(fp); storedhash[64] = '\0'; if (DEBUG) syslog(LOG_NOTICE,"stored hash value=%s len=%i",storedhash, (int) strlen(storedhash)); } /* prepare the encryption engine */ status = cryptInit(); if( status != CRYPT_OK ){ /* cryptlib initialisation failed */; syslog(LOG_NOTICE,"CryptLib initialisation failed."); exit(2); } /* loop until the master password has arrived via the socket */ syslog(LOG_NOTICE,"waiting for a master key ..."); while ( keyavailable == 0 ) { /* wait for connection */ connection = accept(sock,(struct sockaddr *) &client, &address_length); if ( connection > -1){ if (DEBUG) syslog(LOG_NOTICE, "Master Key Connected."); key_connection_handler(connection, storedhash, &keyavailable); close(connection); } else { syslog(LOG_NOTICE,"failed socket connection [%i] while waiting ...",connection); syslog(LOG_NOTICE,"socket error: [%s]",strerror(errno)); } syslog(LOG_NOTICE,"master key available: %i",keyavailable); } syslog(LOG_NOTICE,"Master key is active"); /* check if the database exists, create a new one if not */ FILE *fptr = fopen(DATABASEFILE, "r"); if (! fptr) { syslog(LOG_NOTICE,"database INITIALISATION necessary!"); strlcpy(plaintext, "cryptobone:version 1.5\n", MAXINPUT); aes_encrypt(); } else { syslog(LOG_NOTICE,"database exists!"); fclose(fptr); } /* restore the database */ if (aes_decrypt() == 0){ syslog(LOG_NOTICE,"database decrypted successfully!"); } else { syslog(LOG_NOTICE,"Cannot decrypt cryptobone database!"); status = cryptEnd(); if( status != CRYPT_OK ){ /* cryptlib shutdown failed */; syslog(LOG_NOTICE,"Cryptlib failed to shut down. Some sensible data may remain.\n"); } closelog(); exit(2); } /* cryptAddRandom does NOT WORK in a daemon !!! * cryptAddRandom( NULL, CRYPT_RANDOM_SLOWPOLL ); */ /* The Big Loop */ while (1) { /* wait for connection */ connection = accept(sock,(struct sockaddr *) &client, &address_length); if ( connection > -1){ /* syslog(LOG_NOTICE, "Connected."); */ connection_handler(connection); close(connection); } } cleanup(9); return 0; }