X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?p=ossec-hids.git;a=blobdiff_plain;f=src%2Fos_auth%2Fmain-server.c;fp=src%2Fos_auth%2Fmain-server.c;h=f782f552f1a75e64ed1b2f26999545ea495c3d3d;hp=acf91eec779925d371f97cbc520cfbd714f81899;hb=3f728675941dc69d4e544d3a880a56240a6e394a;hpb=927951d1c1ad45ba9e7325f07d996154a91c911b diff --git a/src/os_auth/main-server.c b/src/os_auth/main-server.c old mode 100755 new mode 100644 index acf91ee..f782f55 --- a/src/os_auth/main-server.c +++ b/src/os_auth/main-server.c @@ -1,5 +1,3 @@ -/* @(#) $Id$ */ - /* Copyright (C) 2010 Trend Micro Inc. * All rights reserved. * @@ -24,37 +22,112 @@ * */ +#ifndef LIBOPENSSL_ENABLED + +#include +#include +int main() +{ + printf("ERROR: Not compiled. Missing OpenSSL support.\n"); + exit(0); +} + +#else -#include "shared.h" +#include #include "auth.h" +#include "os_crypto/md5/md5_op.h" /* TODO: Pulled this value out of the sky, may or may not be sane */ -int POOL_SIZE = 512; +#define POOL_SIZE 512 + +/* Prototypes */ +static void help_authd(void) __attribute((noreturn)); +static int ssl_error(const SSL *ssl, int ret); +static void clean_exit(SSL_CTX *ctx, int sock) __attribute__((noreturn)); + -/* ossec-reportd - Runs manual reports. */ -void report_help() +/* Print help statement */ +static void help_authd() { + print_header(); + print_out(" %s: -[Vhdti] [-g group] [-D dir] [-p port] [-c ciphers] [-v path] [-x path] [-k path]", ARGV0); + print_out(" -V Version and license message"); + print_out(" -h This help message"); + print_out(" -d Execute in debug mode. This parameter"); + print_out(" can be specified multiple times"); + print_out(" to increase the debug level."); + print_out(" -t Test configuration"); + print_out(" -f Run in foreground."); + print_out(" -i Use client's source IP address"); + print_out(" -g Group to run as (default: %s)", GROUPGLOBAL); + print_out(" -D Directory to chroot into (default: %s)", DEFAULTDIR); + print_out(" -p Manager port (default: %s)", DEFAULT_PORT); + print_out(" -n Disable shared password authentication (not recommended).\n"); + print_out(" -c SSL cipher list (default: %s)", DEFAULT_CIPHERS); + print_out(" -v Full path to CA certificate used to verify clients"); + print_out(" -x Full path to server certificate"); + print_out(" -k Full path to server key"); + print_out(" "); + exit(1); } -#ifndef USE_OPENSSL -int main() +/* Generates a random and temporary shared pass to be used by the agents. */ +char *__generatetmppass() { - printf("ERROR: Not compiled. Missing OpenSSL support.\n"); - exit(0); + int rand1; + int rand2; + char *rand3; + char *rand4; + os_md5 md1; + os_md5 md3; + os_md5 md4; + char *fstring = NULL; + char str1[STR_SIZE +1]; + char *muname = NULL; + + #ifndef WIN32 + #ifdef __OpenBSD__ + srandomdev(); + #else + srandom(time(0) + getpid() + getppid()); + #endif + #else + srandom(time(0) + getpid()); + #endif + + rand1 = random(); + rand2 = random(); + + rand3 = GetRandomNoise(); + rand4 = GetRandomNoise(); + + OS_MD5_Str(rand3, md3); + OS_MD5_Str(rand4, md4); + + muname = getuname(); + + snprintf(str1, STR_SIZE, "%d%d%s%d%s%s",(int)time(0), rand1, muname, rand2, md3, md4); + OS_MD5_Str(str1, md1); + fstring = strdup(md1); + free(rand3); + free(rand4); + if(muname) { + free(muname); + } + return(fstring); } -#else /* Function to use with SSL on non blocking socket, - to know if SSL operation failed for good */ -int ssl_error(const SSL* ssl, int ret) + * to know if SSL operation failed for good + */ +static int ssl_error(const SSL *ssl, int ret) { - if (ret <= 0) - { - switch (SSL_get_error(ssl, ret)) - { + if (ret <= 0) { + switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: - usleep(100*1000); + usleep(100 * 1000); return (0); default: merror("%s: ERROR: SSL Error (%d)", ARGV0, ret); @@ -66,53 +139,65 @@ int ssl_error(const SSL* ssl, int ret) return (0); } -void clean_exit(SSL_CTX* ctx, int sock) +static void clean_exit(SSL_CTX *ctx, int sock) { SSL_CTX_free(ctx); close(sock); exit(0); } +/* Exit handler */ +static void cleanup(); + + + int main(int argc, char **argv) { FILE *fp; - // Bucket to keep pids in. + char *authpass = NULL; + /* Bucket to keep pids in */ int process_pool[POOL_SIZE]; - // Count of pids we are wait()ing on. + /* Count of pids we are wait()ing on */ int c = 0, test_config = 0, use_ip_address = 0, pid = 0, status, i = 0, active_processes = 0; - int gid = 0, client_sock = 0, sock = 0, port = 1515, ret = 0; - char *dir = DEFAULTDIR; - char *user = USER; - char *group = GROUPGLOBAL; - // TODO: implement or delete - char *cfg __attribute__((unused)) = DEFAULTCPATH; - char buf[4096 +1]; + int use_pass = 1; + int run_foreground = 0; + gid_t gid; + int client_sock = 0, sock = 0, portnum, ret = 0; + char *port = DEFAULT_PORT; + char *ciphers = DEFAULT_CIPHERS; + const char *dir = DEFAULTDIR; + const char *group = GROUPGLOBAL; + const char *server_cert = NULL; + const char *server_key = NULL; + const char *ca_cert = NULL; + char buf[4096 + 1]; SSL_CTX *ctx; SSL *ssl; - char srcip[IPSIZE +1]; - struct sockaddr_in _nc; + char srcip[IPSIZE + 1]; + struct sockaddr_storage _nc; socklen_t _ncl; + fd_set fdsave, fdwork; /* select() work areas */ + int fdmax; /* max socket number + 1 */ + OSNetInfo *netinfo; /* bound network sockets */ + int esc = 0; /* while() escape flag */ - - /* Initializing some variables */ + /* Initialize some variables */ memset(srcip, '\0', IPSIZE + 1); - memset(process_pool, 0x0, POOL_SIZE); - + memset(process_pool, 0x0, POOL_SIZE * sizeof(*process_pool)); bio_err = 0; + OS_PassEmptyKeyfile(); - /* Setting the name */ + /* Set the name */ OS_SetName(ARGV0); - /* add an option to use the ip on the socket to tie the name to a - specific address */ - while((c = getopt(argc, argv, "Vdhiu:g:D:c:m:p:")) != -1) - { - switch(c){ + + while ((c = getopt(argc, argv, "Vdhtfig:D:m:p:c:v:x:k:n")) != -1) { + switch (c) { case 'V': print_version(); break; case 'h': - report_help(); + help_authd(); break; case 'd': nowDebug(); @@ -120,126 +205,198 @@ int main(int argc, char **argv) case 'i': use_ip_address = 1; break; - case 'u': - if(!optarg) - ErrorExit("%s: -u needs an argument",ARGV0); - user = optarg; - break; case 'g': - if(!optarg) - ErrorExit("%s: -g needs an argument",ARGV0); + if (!optarg) { + ErrorExit("%s: -g needs an argument", ARGV0); + } group = optarg; break; case 'D': - if(!optarg) - ErrorExit("%s: -D needs an argument",ARGV0); + if (!optarg) { + ErrorExit("%s: -D needs an argument", ARGV0); + } dir = optarg; break; - case 'c': - if(!optarg) - ErrorExit("%s: -c needs an argument",ARGV0); - cfg = optarg; - break; case 't': test_config = 1; break; + case 'f': + run_foreground = 1; + break; + case 'n': + use_pass = 0; + break; case 'p': - if(!optarg) - ErrorExit("%s: -%c needs an argument",ARGV0, c); - port = atoi(optarg); - if(port <= 0 || port >= 65536) - { + if (!optarg) { + ErrorExit("%s: -%c needs an argument", ARGV0, c); + } + portnum = atoi(optarg); + if (portnum <= 0 || portnum >= 65536) { ErrorExit("%s: Invalid port: %s", ARGV0, optarg); } + port = optarg; + break; + case 'c': + if (!optarg) { + ErrorExit("%s: -%c needs an argument", ARGV0, c); + } + ciphers = optarg; + break; + case 'v': + if (!optarg) { + ErrorExit("%s: -%c needs an argument", ARGV0, c); + } + ca_cert = optarg; + break; + case 'x': + if (!optarg) { + ErrorExit("%s: -%c needs an argument", ARGV0, c); + } + server_cert = optarg; + break; + case 'k': + if (!optarg) { + ErrorExit("%s: -%c needs an argument", ARGV0, c); + } + server_key = optarg; break; default: - report_help(); + help_authd(); break; } - } - /* Starting daemon -- NB: need to double fork and setsid */ - debug1(STARTED_MSG,ARGV0); + /* Start daemon -- NB: need to double fork and setsid */ + debug1(STARTED_MSG, ARGV0); /* Check if the user/group given are valid */ gid = Privsep_GetGroup(group); - if(gid < 0) - ErrorExit(USER_ERROR,ARGV0,user,group); - + if (gid == (gid_t) - 1) { + ErrorExit(USER_ERROR, ARGV0, "", group); + } + if (!run_foreground) { + nowDaemon(); + goDaemon(); + } + + /* Create PID files */ + if (CreatePID(ARGV0, getpid()) < 0) { + ErrorExit(PID_ERROR, ARGV0); + } /* Exit here if test config is set */ - if(test_config) + if (test_config) { exit(0); - + } /* Privilege separation */ - if(Privsep_SetGroup(gid) < 0) - ErrorExit(SETGID_ERROR,ARGV0,group); - - - /* chrooting -- TODO: this isn't a chroot. Should also close - unneeded open file descriptors (like stdin/stdout)*/ - chdir(dir); - + if (Privsep_SetGroup(gid) < 0) { + ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno)); + } + /* chroot -- TODO: this isn't a chroot. Should also close + * unneeded open file descriptors (like stdin/stdout) + */ + if (chdir(dir) == -1) { + ErrorExit(CHDIR_ERROR, ARGV0, dir, errno, strerror(errno)); + } /* Signal manipulation */ StartSIG(ARGV0); - /* Creating PID files */ - if(CreatePID(ARGV0, getpid()) < 0) - ErrorExit(PID_ERROR,ARGV0); + /* Create PID files */ + if (CreatePID(ARGV0, getpid()) < 0) { + ErrorExit(PID_ERROR, ARGV0); + } + + atexit(cleanup); /* Start up message */ verbose(STARTUP_MSG, ARGV0, (int)getpid()); + if (use_pass) { + + /* Checking if there is a custom password file */ + fp = fopen(AUTHDPASS_PATH, "r"); + buf[0] = '\0'; + if (fp) { + buf[4096] = '\0'; + char *ret = fgets(buf, 4095, fp); + + if (ret && strlen(buf) > 2) { + /* Remove newline */ + buf[strlen(buf) - 1] = '\0'; + authpass = strdup(buf); + } + + fclose(fp); + } + + if (buf[0] != '\0') + verbose("Accepting connections. Using password specified on file: %s",AUTHDPASS_PATH); + else { + /* Getting temporary pass. */ + authpass = __generatetmppass(); + verbose("Accepting connections. Random password chosen for agent authentication: %s", authpass); + } + } else { + verbose("Accepting connections. No password required (not recommended)"); + } - fp = fopen(KEYSFILE_PATH,"a"); - if(!fp) - { + /* Getting SSL cert. */ + + fp = fopen(KEYSFILE_PATH, "a"); + if (!fp) { merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH); exit(1); } + fclose(fp); - - /* Starting SSL */ - ctx = os_ssl_keys(0, dir); - if(!ctx) - { + /* Start SSL */ + ctx = os_ssl_keys(1, dir, ciphers, server_cert, server_key, ca_cert); + if (!ctx) { merror("%s: ERROR: SSL error. Exiting.", ARGV0); exit(1); } - - /* Connecting via TCP */ - sock = OS_Bindporttcp(port, NULL, 0); - if(sock <= 0) - { - merror("%s: Unable to bind to port %d", ARGV0, port); + /* Connect via TCP */ + netinfo = OS_Bindporttcp(port, NULL); + if (netinfo->status < 0) { + merror("%s: Unable to bind to port %s", ARGV0, port); exit(1); } - fcntl(sock, F_SETFL, O_NONBLOCK); + + /* initialize select() save area */ + fdsave = netinfo->fdset; + fdmax = netinfo->fdmax; /* value preset to max fd + 1 */ debug1("%s: DEBUG: Going into listening mode.", ARGV0); - while(1) - { - // no need to completely pin the cpu, 100ms should be fast enough - usleep(100*1000); + /* Setup random */ + srandom_init(); + + /* Chroot */ +/* + if (Privsep_Chroot(dir) < 0) + ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno)); - // Only check process-pool if we have active processes - if(active_processes > 0){ - for (i = 0; i < POOL_SIZE; i++) - { + nowChroot(); +*/ + + while (1) { + /* No need to completely pin the cpu, 100ms should be fast enough */ + usleep(100 * 1000); + + /* Only check process-pool if we have active processes */ + if (active_processes > 0) { + for (i = 0; i < POOL_SIZE; i++) { int rv = 0; status = 0; - if (process_pool[i]) - { + if (process_pool[i]) { rv = waitpid(process_pool[i], &status, WNOHANG); - if (rv != 0){ + if (rv != 0) { debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]); process_pool[i] = 0; active_processes = active_processes - 1; @@ -250,163 +407,195 @@ int main(int argc, char **argv) memset(&_nc, 0, sizeof(_nc)); _ncl = sizeof(_nc); - if((client_sock = accept(sock, (struct sockaddr *) &_nc, &_ncl)) > 0){ - if (active_processes >= POOL_SIZE) - { - merror("%s: Error: Max concurrency reached. Unable to fork", ARGV0); - break; - } - pid = fork(); - if(pid) - { - active_processes = active_processes + 1; - close(client_sock); - for (i = 0; i < POOL_SIZE; i++) - { - if (! process_pool[i]) - { - process_pool[i] = pid; + fdwork = fdsave; + if (select (fdmax, &fdwork, NULL, NULL, NULL) < 0) { + ErrorExit("ERROR: Call to os_auth select() failed, errno %d - %s", + errno, strerror (errno)); + } + + /* read through socket list for active socket */ + for (sock = 0; sock <= fdmax; sock++) { + if (FD_ISSET (sock, &fdwork)) { + if ((client_sock = accept(sock, (struct sockaddr *) &_nc, &_ncl)) > 0) { + if (active_processes >= POOL_SIZE) { + merror("%s: Error: Max concurrency reached. Unable to fork", ARGV0); + esc = 1; /* exit while(1) loop */ break; } - } - } - else - { - strncpy(srcip, inet_ntoa(_nc.sin_addr),IPSIZE -1); - char *agentname = NULL; - ssl = SSL_new(ctx); - SSL_set_fd(ssl, client_sock); - - do - { - ret = SSL_accept(ssl); - - if (ssl_error(ssl, ret)) - clean_exit(ctx, client_sock); - - } while (ret <= 0); - - verbose("%s: INFO: New connection from %s", ARGV0, srcip); - - do - { - ret = SSL_read(ssl, buf, sizeof(buf)); - - if (ssl_error(ssl, ret)) - clean_exit(ctx, client_sock); - - } while (ret <= 0); - - int parseok = 0; - if(strncmp(buf, "OSSEC A:'", 9) == 0) - { - char *tmpstr = buf; - agentname = tmpstr + 9; - tmpstr += 9; - while(*tmpstr != '\0') - { - if(*tmpstr == '\'') - { - *tmpstr = '\0'; - verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip); - parseok = 1; - break; + pid = fork(); + if (pid) { + active_processes = active_processes + 1; + close(client_sock); + for (i = 0; i < POOL_SIZE; i++) { + if (! process_pool[i]) { + process_pool[i] = pid; + break; + } } - tmpstr++; - } - } - if(parseok == 0) - { - merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip); - } - else - { - int acount = 2; - char fname[2048 +1]; - char response[2048 +1]; - char *finalkey = NULL; - response[2048] = '\0'; - fname[2048] = '\0'; - if(!OS_IsValidName(agentname)) - { - merror("%s: ERROR: Invalid agent name: %s from %s", ARGV0, agentname, srcip); - snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname); - ret = SSL_write(ssl, response, strlen(response)); - snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); - ret = SSL_write(ssl, response, strlen(response)); - sleep(1); - exit(0); - } - - - /* Checking for a duplicated names. */ - strncpy(fname, agentname, 2048); - while(NameExist(fname)) - { - snprintf(fname, 2048, "%s%d", agentname, acount); - acount++; - if(acount > 256) - { - merror("%s: ERROR: Invalid agent name %s (duplicated)", ARGV0, agentname); - snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname); - ret = SSL_write(ssl, response, strlen(response)); - snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); + } else { + satop((struct sockaddr *) &_nc, srcip, IPSIZE); + char *agentname = NULL; + ssl = SSL_new(ctx); + SSL_set_fd(ssl, client_sock); + + do { + ret = SSL_accept(ssl); + + if (ssl_error(ssl, ret)) { + clean_exit(ctx, client_sock); + } + + } while (ret <= 0); + verbose("%s: INFO: New connection from %s", ARGV0, srcip); + buf[0] = '\0'; + + do { + ret = SSL_read(ssl, buf, sizeof(buf)); + + if (ssl_error(ssl, ret)) { + clean_exit(ctx, client_sock); + } + + } while (ret <= 0); + + int parseok = 0; + char *tmpstr = buf; + + /* Checking for shared password authentication. */ + if(authpass) { + /* Format is pretty simple: OSSEC PASS: PASS WHATEVERACTION */ + if (strncmp(tmpstr, "OSSEC PASS: ", 12) == 0) { + tmpstr = tmpstr + 12; + + if (strlen(tmpstr) > strlen(authpass) && strncmp(tmpstr, authpass, strlen(authpass)) == 0) { + tmpstr += strlen(authpass); + + if (*tmpstr == ' ') { + tmpstr++; + parseok = 1; + } + } + } + if (parseok == 0) { + merror("%s: ERROR: Invalid password provided by %s. Closing connection.", ARGV0, srcip); + SSL_CTX_free(ctx); + close(client_sock); + exit(0); + } + } + + /* Checking for action A (add agent) */ + parseok = 0; + if (strncmp(tmpstr, "OSSEC A:'", 9) == 0) { + agentname = tmpstr + 9; + tmpstr += 9; + while (*tmpstr != '\0') { + if (*tmpstr == '\'') { + *tmpstr = '\0'; + verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip); + parseok = 1; + break; + } + tmpstr++; + } + } + if (parseok == 0) { + merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip); + } else { + int acount = 2; + char fname[2048 + 1]; + char response[2048 + 1]; + char *finalkey = NULL; + response[2048] = '\0'; + fname[2048] = '\0'; + if (!OS_IsValidName(agentname)) { + merror("%s: ERROR: Invalid agent name: %s from %s", ARGV0, agentname, srcip); + snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname); + SSL_write(ssl, response, strlen(response)); + snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); + SSL_write(ssl, response, strlen(response)); + sleep(1); + exit(0); + } + + /* Check for duplicate names */ + strncpy(fname, agentname, 2048); + while (NameExist(fname)) { + snprintf(fname, 2048, "%s%d", agentname, acount); + acount++; + if (acount > 256) { + merror("%s: ERROR: Invalid agent name %s (duplicated)", ARGV0, agentname); + snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname); + SSL_write(ssl, response, strlen(response)); + snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); + SSL_write(ssl, response, strlen(response)); + sleep(1); + exit(0); + } + } + agentname = fname; + + /* Check for duplicate IP addresses */ + char *check_ip_address = NULL; + check_ip_address = IPExist(srcip); + if(check_ip_address) { + merror("%s: ERROR: Invalid IP address %s (duplicated)", ARGV0, check_ip_address); + snprintf(response, 2048, "ERROR: Invalid IP address: %s\n\n", check_ip_address); + SSL_write(ssl, response, strlen(response)); + snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); + SSL_write(ssl, response, strlen(response)); + sleep(1); + exit(0); + } + + /* Add the new agent */ + if (use_ip_address) { + finalkey = OS_AddNewAgent(agentname, srcip, NULL); + } else { + finalkey = OS_AddNewAgent(agentname, NULL, NULL); + } + if (!finalkey) { + merror("%s: ERROR: Unable to add agent: %s (internal error)", ARGV0, agentname); + snprintf(response, 2048, "ERROR: Internal manager error adding agent: %s\n\n", agentname); + SSL_write(ssl, response, strlen(response)); + snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); + SSL_write(ssl, response, strlen(response)); + sleep(1); + exit(0); + } + + snprintf(response, 2048, "OSSEC K:'%s'\n\n", finalkey); + verbose("%s: INFO: Agent key generated for %s (requested by %s)", ARGV0, agentname, srcip); ret = SSL_write(ssl, response, strlen(response)); - sleep(1); - exit(0); + if (ret < 0) { + merror("%s: ERROR: SSL write error (%d)", ARGV0, ret); + merror("%s: ERROR: Agen key not saved for %s", ARGV0, agentname); + ERR_print_errors_fp(stderr); + } else { + verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip); + } } - } - agentname = fname; - - - /* Adding the new agent. */ - if (use_ip_address) - { - finalkey = OS_AddNewAgent(agentname, srcip, NULL, NULL); - } - else - { - finalkey = OS_AddNewAgent(agentname, NULL, NULL, NULL); - } - if(!finalkey) - { - merror("%s: ERROR: Unable to add agent: %s (internal error)", ARGV0, agentname); - snprintf(response, 2048, "ERROR: Internal manager error adding agent: %s\n\n", agentname); - ret = SSL_write(ssl, response, strlen(response)); - snprintf(response, 2048, "ERROR: Unable to add agent.\n\n"); - ret = SSL_write(ssl, response, strlen(response)); - sleep(1); - exit(0); - } - - - snprintf(response, 2048,"OSSEC K:'%s'\n\n", finalkey); - verbose("%s: INFO: Agent key generated for %s (requested by %s)", ARGV0, agentname, srcip); - ret = SSL_write(ssl, response, strlen(response)); - if(ret < 0) - { - merror("%s: ERROR: SSL write error (%d)", ARGV0, ret); - merror("%s: ERROR: Agen key not saved for %s", ARGV0, agentname); - ERR_print_errors_fp(stderr); - } - else - { - verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip); + + clean_exit(ctx, client_sock); } } + } /* if active socket */ + } /* for() loop on available sockets */ - clean_exit(ctx, client_sock); - } - } - } + /* check for while() escape flag */ + if (esc == 1) + break; + } /* while(1) loop for messages */ - /* Shutdown the socket */ + /* Shut down the socket */ clean_exit(ctx, sock); return (0); } - -#endif -/* EOF */ +/* Exit handler */ +static void cleanup() { + DeletePID(ARGV0); +} +#endif /* LIBOPENSSL_ENABLED */