int main(int argc, char **argv) { FILE *fp; // Bucket to keep pids in. int process_pool[POOL_SIZE]; // 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]; SSL_CTX *ctx; SSL *ssl; char srcip[IPSIZE +1]; struct sockaddr_in _nc; socklen_t _ncl; /* Initializing some variables */ memset(srcip, '\0', IPSIZE + 1); memset(process_pool, 0x0, POOL_SIZE); bio_err = 0; /* Setting 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){ case 'V': print_version(); break; case 'h': report_help(); break; case 'd': nowDebug(); break; 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); group = optarg; break; case 'D': 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 'p': if(!optarg) ErrorExit("%s: -%c needs an argument",ARGV0, c); port = atoi(optarg); if(port <= 0 || port >= 65536) { ErrorExit("%s: Invalid port: %s", ARGV0, optarg); } break; default: report_help(); break; } } /* Starting 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); /* Exit here if test config is set */ 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); /* Signal manipulation */ StartSIG(ARGV0); /* Creating PID files */ if(CreatePID(ARGV0, getpid()) < 0) ErrorExit(PID_ERROR,ARGV0); /* Start up message */ verbose(STARTUP_MSG, ARGV0, (int)getpid()); fp = fopen(KEYSFILE_PATH,"a"); if(!fp) { merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH); exit(1); } /* Starting SSL */ ctx = os_ssl_keys(0, dir); 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); exit(1); } fcntl(sock, F_SETFL, O_NONBLOCK); 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); // 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]) { rv = waitpid(process_pool[i], &status, WNOHANG); if (rv != 0){ debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]); process_pool[i] = 0; active_processes = active_processes - 1; } } } } 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; 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; } 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"); ret = SSL_write(ssl, response, strlen(response)); sleep(1); exit(0); } } 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); } } } /* Shutdown the socket */ clean_exit(ctx, sock); return (0); }
int main(int argc, char **argv) { FILE *fp; char *authpass = NULL; /* Bucket to keep pids in */ int process_pool[POOL_SIZE]; /* 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 use_pass = 1; int force_antiquity = -1; char *id_exist; gid_t gid; int client_sock = 0, sock = 0, port = DEFAULT_PORT, ret = 0; 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; socklen_t _ncl; /* Initialize some variables */ memset(srcip, '\0', IPSIZE + 1); memset(process_pool, 0x0, POOL_SIZE * sizeof(*process_pool)); bio_err = 0; /* Set the name */ OS_SetName(ARGV0); while ((c = getopt(argc, argv, "Vdhtig:D:m:p:v:x:k:nf:")) != -1) { char *end; switch (c) { case 'V': print_version(); break; case 'h': help_authd(); break; case 'd': nowDebug(); break; case 'i': use_ip_address = 1; break; case 'g': if (!optarg) { ErrorExit("%s: -g needs an argument", ARGV0); } group = optarg; break; case 'D': if (!optarg) { ErrorExit("%s: -D needs an argument", ARGV0); } dir = optarg; break; case 't': test_config = 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) { ErrorExit("%s: Invalid port: %s", ARGV0, 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; case 'f': if (!optarg) ErrorExit("%s: -%c needs an argument", ARGV0, c); force_antiquity = strtol(optarg, &end, 10); if (optarg == end || force_antiquity < 0) ErrorExit("%s: Invalid number for -f", ARGV0); break; default: help_authd(); break; } } /* 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 == (gid_t) - 1) { ErrorExit(USER_ERROR, ARGV0, "", group); } /* Exit here if test config is set */ if (test_config) { exit(0); } /* Privilege separation */ 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); /* Create PID files */ if (CreatePID(ARGV0, getpid()) < 0) { ErrorExit(PID_ERROR, ARGV0); } /* 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 insecure connections. No password required (not recommended)"); /* 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); /* Start SSL */ ctx = os_ssl_keys(1, dir, server_cert, server_key, ca_cert); if (!ctx) { merror("%s: ERROR: SSL error. Exiting.", ARGV0); exit(1); } /* Connect via TCP */ sock = OS_Bindporttcp(port, NULL, 0); if (sock <= 0) { merror("%s: Unable to bind to port %d", ARGV0, port); exit(1); } fcntl(sock, F_SETFL, O_NONBLOCK); debug1("%s: DEBUG: Going into listening mode.", ARGV0); /* Setup random */ srandom_init(); /* Chroot */ if (Privsep_Chroot(dir) < 0) ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno)); 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]) { rv = waitpid(process_pool[i], &status, WNOHANG); if (rv != 0) { debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]); process_pool[i] = 0; active_processes = active_processes - 1; } } } } 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; 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); 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: "******"%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 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); 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 duplicated IP */ if (use_ip_address) { id_exist = IPExist(srcip); if (id_exist) { if (force_antiquity >= 0) { double antiquity = OS_AgentAntiquity(id_exist); if (antiquity >= force_antiquity || antiquity < 0) { /* TODO: Backup info-agent, syscheck and rootcheck */ OS_RemoveAgent(id_exist); } else { /* TODO: Send alert */ merror("%s: ERROR: Duplicated IP %s (another active)", ARGV0, srcip); snprintf(response, 2048, "ERROR: Duplicated IP: %s\n\n", srcip); 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); } } else { merror("%s: ERROR: Duplicated IP %s", ARGV0, srcip); snprintf(response, 2048, "ERROR: Duplicated IP: %s\n\n", srcip); 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)); 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); } } } /* Shut down the socket */ clean_exit(ctx, sock); return (0); }
/* Bulk generate client keys from file */ int k_bulkload(const char *cmdbulk) { int i = 1; FILE *fp, *infp; char str1[STR_SIZE + 1]; char str2[STR_SIZE + 1]; os_md5 md1; os_md5 md2; char line[FILE_SIZE + 1]; char name[FILE_SIZE + 1]; char id[FILE_SIZE + 1]; char ip[FILE_SIZE + 1]; char delims[] = ","; char *token = NULL; /* Check if we can open the input file */ printf("Opening: [%s]\n", cmdbulk); infp = fopen(cmdbulk, "r"); if (!infp) { perror("Failed."); ErrorExit(FOPEN_ERROR, ARGV0, cmdbulk, errno, strerror(errno)); } /* Check if we can open the auth_file */ fp = fopen(AUTH_FILE, "a"); if (!fp) { ErrorExit(FOPEN_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno)); } fclose(fp); while (fgets(line, FILE_SIZE - 1, infp) != NULL) { os_ip c_ip; c_ip.ip = NULL; if (1 >= strlen(trimwhitespace(line))) { continue; } memset(ip, '\0', FILE_SIZE + 1); token = strtok(line, delims); strncpy(ip, trimwhitespace(token), FILE_SIZE - 1); memset(name, '\0', FILE_SIZE + 1); token = strtok(NULL, delims); strncpy(name, trimwhitespace(token), FILE_SIZE - 1); #ifndef WIN32 if (chmod(AUTH_FILE, 0440) == -1) { ErrorExit(CHMOD_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno)); } #endif /* Set time 2 */ time2 = time(0); srandom_init(); rand1 = random(); /* Zero strings */ memset(str1, '\0', STR_SIZE + 1); memset(str2, '\0', STR_SIZE + 1); /* Check the name */ if (!OS_IsValidName(name)) { printf(INVALID_NAME, name); continue; } /* Search for name -- no duplicates */ if (NameExist(name)) { printf(ADD_ERROR_NAME, name); continue; } if (!OS_IsValidIP(ip, &c_ip)) { printf(IP_ERROR, ip); continue; } /* Default ID */ i = MAX_AGENTS + 32512; snprintf(id, 8, "%03d", i); while (!IDExist(id)) { i--; snprintf(id, 8, "%03d", i); /* No key present, use id 0 */ if (i <= 0) { i = 0; break; } } snprintf(id, 8, "%03d", i + 1); if (!OS_IsValidID(id)) { printf(INVALID_ID, id); goto cleanup; } /* Search for ID KEY -- no duplicates */ if (IDExist(id)) { printf(NO_DEFAULT, i + 1); goto cleanup; } printf(AGENT_INFO, id, name, ip); fflush(stdout); time3 = time(0); rand2 = random(); fp = fopen(AUTH_FILE, "a"); if (!fp) { ErrorExit(FOPEN_ERROR, ARGV0, KEYS_FILE, errno, strerror(errno)); } #ifndef WIN32 if (chmod(AUTH_FILE, 0440) == -1) { ErrorExit(CHMOD_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno)); } #endif /* Random 1: Time took to write the agent information * Random 2: Time took to choose the action * Random 3: All of this + time + pid * Random 4: MD5 all of this + the name, key and IP * Random 5: Final key */ snprintf(str1, STR_SIZE, "%d%s%d", (int)(time3 - time2), name, (int)rand1); snprintf(str2, STR_SIZE, "%d%s%s%d", (int)(time2 - time1), ip, id, (int)rand2); OS_MD5_Str(str1, md1); OS_MD5_Str(str2, md2); snprintf(str1, STR_SIZE, "%s%d%d%d", md1, (int)getpid(), (int)random(), (int)time3); OS_MD5_Str(str1, md1); fprintf(fp, "%s %s %s %s%s\n", id, name, c_ip.ip, md1, md2); fclose(fp); printf(AGENT_ADD); restart_necessary = 1; cleanup: free(c_ip.ip); }; fclose(infp); return (0); }
int add_agent() { int i = 1; FILE *fp; char str1[STR_SIZE + 1]; char str2[STR_SIZE + 1]; os_md5 md1; os_md5 md2; char *user_input; char *_name; char *_id; char *_ip; char name[FILE_SIZE + 1]; char id[FILE_SIZE + 1]; char ip[FILE_SIZE + 1]; os_ip *c_ip; /* Check if we can open the auth_file */ fp = fopen(AUTH_FILE, "a"); if (!fp) { ErrorExit(FOPEN_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno)); } fclose(fp); /* Allocate for c_ip */ os_calloc(1, sizeof(os_ip), c_ip); #ifndef WIN32 if (chmod(AUTH_FILE, 0440) == -1) { ErrorExit(CHMOD_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno)); } #endif /* Set time 2 */ time2 = time(0); rand1 = random(); /* Zero strings */ memset(str1, '\0', STR_SIZE + 1); memset(str2, '\0', STR_SIZE + 1); printf(ADD_NEW); /* Get the name */ memset(name, '\0', FILE_SIZE + 1); do { printf(ADD_NAME); fflush(stdout); /* Read the agent's name from user environment. If it is invalid * we should force user to provide a name from input device. */ _name = getenv("OSSEC_AGENT_NAME"); if (_name == NULL || NameExist(_name) || !OS_IsValidName(_name)) { _name = read_from_user(); } if (strcmp(_name, QUIT) == 0) { return (0); } strncpy(name, _name, FILE_SIZE - 1); /* Check the name */ if (!OS_IsValidName(name)) { printf(INVALID_NAME, name); } /* Search for name -- no duplicates */ if (NameExist(name)) { printf(ADD_ERROR_NAME, name); } } while (NameExist(name) || !OS_IsValidName(name)); /* Get IP */ memset(ip, '\0', FILE_SIZE + 1); do { printf(ADD_IP); fflush(stdout); /* Read IP address from user's environment. If that IP is invalid, * force user to provide IP from input device */ _ip = getenv("OSSEC_AGENT_IP"); if (_ip == NULL || !OS_IsValidIP(_ip, c_ip)) { _ip = read_from_user(); } /* Quit */ if (strcmp(_ip, QUIT) == 0) { return (0); } strncpy(ip, _ip, FILE_SIZE - 1); if (!OS_IsValidIP(ip, c_ip)) { printf(IP_ERROR, ip); _ip = NULL; } } while (!_ip); do { /* Default ID */ i = MAX_AGENTS + 32512; snprintf(id, 8, "%03d", i); while (!IDExist(id)) { i--; snprintf(id, 8, "%03d", i); /* No key present, use id 0 */ if (i <= 0) { i = 0; break; } } snprintf(id, 8, "%03d", i + 1); /* Get ID */ printf(ADD_ID, id); fflush(stdout); /* Get Agent ID from environment. If 0, use default ID. If null, * get from user input. If value from environment is invalid, * we force user to specify an ID from the terminal. Otherwise, * our program goes to infinite loop. */ _id = getenv("OSSEC_AGENT_ID"); if (_id == NULL || IDExist(_id) || !OS_IsValidID(_id)) { _id = read_from_user(); } /* If user specified 0 as Agent ID, he meant use default value. * NOTE: a bad condition can cause infinite loop. */ if (strcmp(_id, "0") == 0) { strncpy(_id, id, FILE_SIZE - 1); } /* Quit */ if (strcmp(_id, QUIT) == 0) { return (0); } if (_id[0] != '\0') { strncpy(id, _id, FILE_SIZE - 1); } if (!OS_IsValidID(id)) { printf(INVALID_ID, id); } /* Search for ID KEY -- no duplicates */ if (IDExist(id)) { printf(ADD_ERROR_ID, id); } } while (IDExist(id) || !OS_IsValidID(id)); printf(AGENT_INFO, id, name, ip); fflush(stdout); do { printf(ADD_CONFIRM); /* Confirmation by an environment variable. The valid value is y/Y. * If the user provides anything other string, it is considered as * n/N; please note that the old code only accepts y/Y/n/N. So if * the variable OSSEC_ACTION_CONFIRMED is 'foobar', the program will * go into an infinite loop. */ user_input = getenv("OSSEC_ACTION_CONFIRMED"); if (user_input == NULL) { user_input = read_from_user(); } /* If user accepts to add */ if (user_input[0] == 'y' || user_input[0] == 'Y') { time3 = time(0); rand2 = random(); fp = fopen(AUTH_FILE, "a"); if (!fp) { ErrorExit(FOPEN_ERROR, ARGV0, KEYS_FILE, errno, strerror(errno)); } #ifndef WIN32 chmod(AUTH_FILE, 0440); #endif /* Random 1: Time took to write the agent information * Random 2: Time took to choose the action * Random 3: All of this + time + pid * Random 4: Md5 all of this + the name, key and IP * Random 5: Final key */ snprintf(str1, STR_SIZE, "%d%s%d", (int)(time3 - time2), name, (int)rand1); snprintf(str2, STR_SIZE, "%d%s%s%d", (int)(time2 - time1), ip, id, (int)rand2); OS_MD5_Str(str1, md1); OS_MD5_Str(str2, md2); snprintf(str1, STR_SIZE, "%s%d%d%d", md1, (int)getpid(), (int)random(), (int)time3); OS_MD5_Str(str1, md1); fprintf(fp, "%s %s %s %s%s\n", id, name, c_ip->ip, md1, md2); fclose(fp); printf(AGENT_ADD); restart_necessary = 1; break; } else { /* if(user_input[0] == 'n' || user_input[0] == 'N') */ printf(ADD_NOT); break; } } while (1); return (0); }
int main(int argc, char **argv) { int key_added = 0; int c; int test_config = 0; int auto_method = 0; #ifndef WIN32 gid_t gid = 0; #endif int sock = 0, port = DEFAULT_PORT, ret = 0; const char *dir = DEFAULTDIR; const char *group = GROUPGLOBAL; char *authpass = NULL; const char *manager = NULL; const char *ipaddress = NULL; const char *agentname = NULL; const char *agent_cert = NULL; const char *agent_key = NULL; const char *ca_cert = NULL; char lhostname[512 + 1]; char buf[4096 + 1]; SSL_CTX *ctx; SSL *ssl; BIO *sbio; bio_err = 0; buf[4096] = '\0'; #ifdef WIN32 WSADATA wsaData; #endif /* Set the name */ OS_SetName(ARGV0); while ((c = getopt(argc, argv, "Vdhtg:m:p:A:v:x:k:D:P:a")) != -1) { switch (c) { case 'V': print_version(); break; case 'h': help_agent_auth(); break; case 'd': nowDebug(); break; case 'g': if (!optarg) { ErrorExit("%s: -g needs an argument", ARGV0); } group = optarg; break; case 'D': if (!optarg) { ErrorExit("%s: -g needs an argument", ARGV0); } dir = optarg; break; case 't': test_config = 1; break; case 'm': if (!optarg) { ErrorExit("%s: -%c needs an argument", ARGV0, c); } manager = optarg; break; case 'A': if (!optarg) { ErrorExit("%s: -%c needs an argument", ARGV0, c); } agentname = optarg; break; case 'p': if (!optarg) { ErrorExit("%s: -%c needs an argument", ARGV0, c); } port = atoi(optarg); if (port <= 0 || port >= 65536) { ErrorExit("%s: Invalid port: %s", ARGV0, 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); } agent_cert = optarg; break; case 'k': if (!optarg) { ErrorExit("%s: -%c needs an argument", ARGV0, c); } agent_key = optarg; break; case 'P': if (!optarg) ErrorExit("%s: -%c needs an argument", ARGV0, c); authpass = optarg; break; case 'a': auto_method = 1; break; default: help_agent_auth(); break; } } /* Start daemon */ debug1(STARTED_MSG, ARGV0); #ifndef WIN32 /* Check if the user/group given are valid */ gid = Privsep_GetGroup(group); if (gid == (gid_t) - 1) { ErrorExit(USER_ERROR, ARGV0, "", group); } /* Exit here if test config is set */ if (test_config) { exit(0); } /* Privilege separation */ if (Privsep_SetGroup(gid) < 0) { ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno)); } /* Signal manipulation */ StartSIG(ARGV0); /* Create PID files */ if (CreatePID(ARGV0, getpid()) < 0) { ErrorExit(PID_ERROR, ARGV0); } #else /* Initialize Windows socket stuff */ if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { ErrorExit("%s: WSAStartup() failed", ARGV0); } #endif /* WIN32 */ /* Start up message */ verbose(STARTUP_MSG, ARGV0, (int)getpid()); if (agentname == NULL) { lhostname[512] = '\0'; if (gethostname(lhostname, 512 - 1) != 0) { merror("%s: ERROR: Unable to extract hostname. Custom agent name not set.", ARGV0); exit(1); } agentname = lhostname; } #ifdef LEGACY_SSL auto_method = 1; merror("WARN: TLS v1.2 method-forcing disabled. This program was compiled to use SSL/TLS auto-negotiation."); #endif /* Start SSL */ ctx = os_ssl_keys(0, dir, agent_cert, agent_key, ca_cert, auto_method); if (!ctx) { merror("%s: ERROR: SSL error. Exiting.", ARGV0); exit(1); } if (!manager) { merror("%s: ERROR: Manager IP not set.", ARGV0); exit(1); } /* Check to see if the manager to connect to was specified as an IP address * or hostname on the command line. If it was given as a hostname then ensure * the hostname is preserved so that certificate verification can be done. */ if (!(ipaddress = OS_GetHost(manager, 3))) { merror("%s: Could not resolve hostname: %s\n", ARGV0, manager); exit(1); } /* Checking if there is a custom password file */ if (authpass == NULL) { FILE *fp; fp = fopen(AUTHDPASS_PATH, "r"); buf[0] = '\0'; if (fp) { buf[4096] = '\0'; char *ret = fgets(buf, 4095, fp); if (ret && strlen(buf) > 2) { authpass = buf; } fclose(fp); printf("INFO: Using password specified on file: %s\n", AUTHDPASS_PATH); } } if (!authpass) { printf("WARN: No authentication password provided.\n"); } /* Connect via TCP */ sock = OS_ConnectTCP(port, ipaddress, 0); if (sock <= 0) { merror("%s: Unable to connect to %s:%d", ARGV0, ipaddress, port); exit(1); } /* Connect the SSL socket */ ssl = SSL_new(ctx); sbio = BIO_new_socket(sock, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio); ret = SSL_connect(ssl); if (ret <= 0) { ERR_print_errors_fp(stderr); merror("%s: ERROR: SSL error (%d). Exiting.", ARGV0, ret); exit(1); } printf("INFO: Connected to %s:%d\n", ipaddress, port); /* Additional verification of the manager's certificate if a hostname * rather than an IP address is given on the command line. Could change * this to do the additional validation on IP addresses as well if needed. */ if (ca_cert) { printf("INFO: Verifing manager's certificate\n"); if (check_x509_cert(ssl, manager) != VERIFY_TRUE) { debug1("%s: DEBUG: Unable to verify server certificate.", ARGV0); exit(1); } } printf("INFO: Using agent name as: %s\n", agentname); if (authpass) { snprintf(buf, 2048, "OSSEC PASS: %s OSSEC A:'%s'\n", authpass, agentname); } else { snprintf(buf, 2048, "OSSEC A:'%s'\n", agentname); } ret = SSL_write(ssl, buf, strlen(buf)); if (ret < 0) { printf("SSL write error (unable to send message.)\n"); ERR_print_errors_fp(stderr); exit(1); } printf("INFO: Send request to manager. Waiting for reply.\n"); while (1) { ret = SSL_read(ssl, buf, sizeof(buf) - 1); switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_NONE: buf[ret] = '\0'; if (strncmp(buf, "ERROR", 5) == 0) { char *tmpstr; tmpstr = strchr(buf, '\n'); if (tmpstr) { *tmpstr = '\0'; } printf("%s (from manager)\n", buf); } else if (strncmp(buf, "OSSEC K:'", 9) == 0) { char *key; char *tmpstr; char **entry; printf("INFO: Received response with agent key\n"); key = buf; key += 9; tmpstr = strchr(key, '\''); if (!tmpstr) { printf("ERROR: Invalid key received. Closing connection.\n"); exit(1); } *tmpstr = '\0'; entry = OS_StrBreak(' ', key, 4); if (!OS_IsValidID(entry[0]) || !OS_IsValidName(entry[1]) || !OS_IsValidName(entry[2]) || !OS_IsValidName(entry[3])) { printf("ERROR: Invalid key received (2). Closing connection.\n"); exit(1); } { FILE *fp; fp = fopen(KEYSFILE_PATH, "w"); if (!fp) { printf("ERROR: Unable to open key file: %s", KEYSFILE_PATH); exit(1); } fprintf(fp, "%s\n", key); fclose(fp); } key_added = 1; printf("INFO: Valid key created. Finished.\n"); } break; case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SYSCALL: if (key_added == 0) { printf("ERROR: Unable to create key. Either wrong password or connection not accepted by the manager.\n"); } printf("INFO: Connection closed.\n"); exit(0); break; default: printf("ERROR: SSL read (unable to receive message)\n"); exit(1); break; } } /* Shut down the socket */ if (key_added == 0) { printf("ERROR: Unable to create key. Either wrong password or connection not accepted by the manager.\n"); } SSL_CTX_free(ctx); close(sock); exit(0); }
int main(int argc, char **argv) { int c, test_config = 0; #ifndef WIN32 int gid = 0; #endif int sock = 0, port = 1515, ret = 0; char *dir = DEFAULTDIR; char *user = USER; char *group = GROUPGLOBAL; char *cfg = DEFAULTCPATH; char *manager = NULL; char *agentname = NULL; char lhostname[512 + 1]; char buf[2048 +1]; SSL_CTX *ctx; SSL *ssl; BIO *sbio; bio_err = 0; buf[2048] = '\0'; /* Setting the name */ OS_SetName(ARGV0); while((c = getopt(argc, argv, "Vdhu:g:D:c:m:p:A:")) != -1) { switch(c) { case 'V': print_version(); break; case 'h': report_help(); break; case 'd': nowDebug(); 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); group=optarg; break; case 'D': 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 'm': if(!optarg) ErrorExit("%s: -%c needs an argument",ARGV0, c); manager = optarg; break; case 'A': if(!optarg) ErrorExit("%s: -%c needs an argument",ARGV0, c); agentname = optarg; break; case 'p': if(!optarg) ErrorExit("%s: -%c needs an argument",ARGV0, c); port = atoi(optarg); if(port <= 0 || port >= 65536) { ErrorExit("%s: Invalid port: %s", ARGV0, optarg); } break; default: report_help(); break; } } /* Starting daemon */ debug1(STARTED_MSG,ARGV0); #ifndef WIN32 /* Check if the user/group given are valid */ gid = Privsep_GetGroup(group); if(gid < 0) ErrorExit(USER_ERROR,ARGV0,user,group); /* Privilege separation */ if(Privsep_SetGroup(gid) < 0) ErrorExit(SETGID_ERROR,ARGV0,group); /* Signal manipulation */ StartSIG(ARGV0); /* Creating PID files */ if(CreatePID(ARGV0, getpid()) < 0) ErrorExit(PID_ERROR,ARGV0); #endif /* Start up message */ verbose(STARTUP_MSG, ARGV0, (int)getpid()); if(agentname == NULL) { lhostname[512] = '\0'; if(gethostname(lhostname, 512 -1) != 0) { merror("%s: ERROR: Unable to extract hostname. Custom agent name not set.", ARGV0); exit(1); } agentname = lhostname; } /* Starting SSL */ ctx = os_ssl_keys(1, NULL); if(!ctx) { merror("%s: ERROR: SSL error. Exiting.", ARGV0); exit(1); } if(!manager) { merror("%s: ERROR: Manager IP not set.", ARGV0); exit(1); } /* Check to see if manager is an IP */ int is_ip = 1; struct sockaddr_in iptest; memset(&iptest, 0, sizeof(iptest)); if(inet_pton(AF_INET, manager, &iptest.sin_addr) != 1) is_ip = 0; /* This is not an IPv4 address */ /* Not IPv4, IPv6 maybe? */ if(is_ip == 0) { struct sockaddr_in6 iptest6; memset(&iptest6, 0, sizeof(iptest6)); if(inet_pton(AF_INET6, manager, &iptest6.sin6_addr) != 1) is_ip = 0; else is_ip = 1; /* This is an IPv6 address */ } /* If it isn't an ip, try to resolve the IP */ if(is_ip == 0) { char *ipaddress; ipaddress = OS_GetHost(manager, 3); if(ipaddress != NULL) strncpy(manager, ipaddress, 16); else { printf("Could not resolve hostname: %s\n", manager); return(1); } } /* Connecting via TCP */ sock = OS_ConnectTCP(port, manager, 0); if(sock <= 0) { merror("%s: Unable to connect to %s:%d", ARGV0, manager, port); exit(1); } /* Connecting the SSL socket */ ssl = SSL_new(ctx); sbio = BIO_new_socket(sock, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio); ret = SSL_connect(ssl); if(ret <= 0) { ERR_print_errors_fp(stderr); merror("%s: ERROR: SSL error (%d). Exiting.", ARGV0, ret); exit(1); } printf("INFO: Connected to %s:%d\n", manager, port); printf("INFO: Using agent name as: %s\n", agentname); snprintf(buf, 2048, "OSSEC A:'%s'\n", agentname); ret = SSL_write(ssl, buf, strlen(buf)); if(ret < 0) { printf("SSL write error (unable to send message.)\n"); ERR_print_errors_fp(stderr); exit(1); } printf("INFO: Send request to manager. Waiting for reply.\n"); while(1) { ret = SSL_read(ssl,buf,sizeof(buf) -1); switch(SSL_get_error(ssl,ret)) { case SSL_ERROR_NONE: buf[ret] = '\0'; if(strncmp(buf, "ERROR", 5) == 0) { char *tmpstr; tmpstr = strchr(buf, '\n'); if(tmpstr) *tmpstr = '\0'; printf("%s (from manager)\n", buf); } else if(strncmp(buf, "OSSEC K:'",9) == 0) { char *key; char *tmpstr; char **entry; printf("INFO: Received response with agent key\n"); key = buf; key += 9; tmpstr = strchr(key, '\''); if(!tmpstr) { printf("ERROR: Invalid key received. Closing connection.\n"); exit(1); } *tmpstr = '\0'; entry = OS_StrBreak(' ', key, 4); if(!OS_IsValidID(entry[0]) || !OS_IsValidName(entry[1]) || !OS_IsValidName(entry[2]) || !OS_IsValidName(entry[3])) { printf("ERROR: Invalid key received (2). Closing connection.\n"); exit(1); } { FILE *fp; fp = fopen(KEYSFILE_PATH,"w"); if(!fp) { printf("ERROR: Unable to open key file: %s", KEYSFILE_PATH); exit(1); } fprintf(fp, "%s\n", key); fclose(fp); } printf("INFO: Valid key created. Finished.\n"); } break; case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SYSCALL: printf("INFO: Connection closed.\n"); exit(0); break; default: printf("ERROR: SSL read (unable to receive message)\n"); exit(1); break; } } /* Shutdown the socket */ SSL_CTX_free(ctx); close(sock); exit(0); }