1 /* Copyright (C) 2010 Trend Micro Inc.
2 * All rights reserved.
3 *
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
7 * Foundation
8 *
9 * In addition, as a special exception, the copyright holders give
10 * permission to link the code of portions of this program with the
11 * OpenSSL library under certain conditions as described in each
12 * individual source file, and distribute linked combinations
13 * including the two.
14 *
15 * You must obey the GNU General Public License in all respects
16 * for all of the code used other than OpenSSL. If you modify
17 * file(s) with this exception, you may extend this exception to your
18 * version of the file(s), but you are not obligated to do so. If you
19 * do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source
21 * files in the program, then also delete it here.
22 *
23 */
24
25 #include <errno.h>
26 #include <string.h>
27 #include "shared.h"
28 #include "check_cert.h"
29
30 #ifndef LIBOPENSSL_ENABLED
31
main()32 int main()
33 {
34 printf("ERROR: Not compiled. Missing OpenSSL support.\n");
35 exit(0);
36 }
37
38 #else
39
40 #include <openssl/ssl.h>
41 #include "auth.h"
42
43 static void help_agent_auth(void) __attribute__((noreturn));
44
45 /* Print help statement */
help_agent_auth()46 static void help_agent_auth()
47 {
48 print_header();
49 print_out(" %s: -[Vhdt] [-g group] [-D dir] [-m IP address] [-p port] [-A name] [-c ciphers] [-v path] [-x path] [-k path]", ARGV0);
50 print_out(" -V Version and license message");
51 print_out(" -h This help message");
52 print_out(" -d Execute in debug mode. This parameter");
53 print_out(" can be specified multiple times");
54 print_out(" to increase the debug level.");
55 print_out(" -t Test configuration");
56 print_out(" -g <group> Group to run as (default: %s)", GROUPGLOBAL);
57 print_out(" -D <dir> Directory to chroot into (default: %s)", DEFAULTDIR);
58 print_out(" -m <addr> Manager IP address");
59 print_out(" -p <port> Manager port (default: %s)", DEFAULT_PORT);
60 print_out(" -A <name> Agent name (default: hostname)");
61 print_out(" -c SSL cipher list (default: %s)", DEFAULT_CIPHERS);
62 print_out(" -v <path> Full path to CA certificate used to verify the server");
63 print_out(" -x <path> Full path to agent certificate");
64 print_out(" -k <path> Full path to agent key");
65 print_out(" -P <path> Authorization password file [default: /var/ossec/etc/authd.pass");
66 print_out(" ");
67 exit(1);
68 }
69
main(int argc,char ** argv)70 int main(int argc, char **argv)
71 {
72 int key_added = 0;
73 int c;
74 int test_config = 0;
75 int authenticate = 0;
76 #ifndef WIN32
77 gid_t gid = 0;
78 #endif
79
80 int sock = 0, portnum, ret = 0;
81 char *port = DEFAULT_PORT;
82 char *ciphers = DEFAULT_CIPHERS;
83 const char *dir = DEFAULTDIR;
84 const char *group = GROUPGLOBAL;
85 char *authpass = NULL;
86 const char *manager = NULL;
87 const char *agentname = NULL;
88 const char *agent_cert = NULL;
89 const char *agent_key = NULL;
90 const char *ca_cert = NULL;
91 char lhostname[512 + 1];
92 char buf[4096 + 1];
93 SSL_CTX *ctx;
94 SSL *ssl;
95 BIO *sbio;
96 bio_err = 0;
97 buf[4096] = '\0';
98
99 #ifdef WIN32
100 WSADATA wsaData;
101 #endif
102
103 /* Set the name */
104 OS_SetName(ARGV0);
105
106 while ((c = getopt(argc, argv, "Vdhtg:m:p:A:c:v:x:k:D:P:")) != -1) {
107 switch (c) {
108 case 'V':
109 print_version();
110 break;
111 case 'h':
112 help_agent_auth();
113 break;
114 case 'd':
115 nowDebug();
116 break;
117 case 'g':
118 if (!optarg) {
119 ErrorExit("%s: -g needs an argument", ARGV0);
120 }
121 group = optarg;
122 break;
123 case 'D':
124 if (!optarg) {
125 ErrorExit("%s: -g needs an argument", ARGV0);
126 }
127 dir = optarg;
128 break;
129 case 't':
130 test_config = 1;
131 break;
132 case 'm':
133 if (!optarg) {
134 ErrorExit("%s: -%c needs an argument", ARGV0, c);
135 }
136 manager = optarg;
137 break;
138 case 'A':
139 if (!optarg) {
140 ErrorExit("%s: -%c needs an argument", ARGV0, c);
141 }
142 agentname = optarg;
143 break;
144 case 'p':
145 if (!optarg) {
146 ErrorExit("%s: -%c needs an argument", ARGV0, c);
147 }
148 portnum = atoi(optarg);
149 if (portnum <= 0 || portnum >= 65536) {
150 ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
151 }
152 port = optarg;
153 break;
154 case 'c':
155 if (!optarg) {
156 ErrorExit("%s: -%c needs an argument", ARGV0, c);
157 }
158 ciphers = optarg;
159 break;
160 case 'v':
161 if (!optarg) {
162 ErrorExit("%s: -%c needs an argument", ARGV0, c);
163 }
164 ca_cert = optarg;
165 break;
166 case 'x':
167 if (!optarg) {
168 ErrorExit("%s: -%c needs an argument", ARGV0, c);
169 }
170 agent_cert = optarg;
171 break;
172 case 'k':
173 if (!optarg) {
174 ErrorExit("%s: -%c needs an argument", ARGV0, c);
175 }
176 agent_key = optarg;
177 break;
178 case 'P':
179 if (!optarg) {
180 ErrorExit("%s: -%c needs an argument", ARGV0, c);
181 }
182 authpass = optarg;
183 authenticate++;
184 break;
185 default:
186 help_agent_auth();
187 break;
188 }
189 }
190
191 /* Start daemon */
192 debug1(STARTED_MSG, ARGV0);
193
194 #ifndef WIN32
195 /* Check if the user/group given are valid */
196 gid = Privsep_GetGroup(group);
197 if (gid == (gid_t) - 1) {
198 ErrorExit(USER_ERROR, ARGV0, "", group);
199 }
200
201 /* Exit here if test config is set */
202 if (test_config) {
203 exit(0);
204 }
205
206 /* Privilege separation */
207 if (Privsep_SetGroup(gid) < 0) {
208 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
209 }
210
211 /* Signal manipulation */
212 StartSIG(ARGV0);
213
214 /* Create PID files */
215 if (CreatePID(ARGV0, getpid()) < 0) {
216 ErrorExit(PID_ERROR, ARGV0);
217 }
218 #else
219 /* Initialize Windows socket stuff */
220 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
221 ErrorExit("%s: WSAStartup() failed", ARGV0);
222 }
223 #endif /* WIN32 */
224
225 /* Start up message */
226 verbose(STARTUP_MSG, ARGV0, (int)getpid());
227
228 if (agentname == NULL) {
229 lhostname[512] = '\0';
230 if (gethostname(lhostname, 512 - 1) != 0) {
231 merror("%s: ERROR: Unable to extract hostname. Custom agent name not set.", ARGV0);
232 exit(1);
233 }
234 agentname = lhostname;
235 }
236
237 /* Start SSL */
238 ctx = os_ssl_keys(0, dir, ciphers, agent_cert, agent_key, ca_cert);
239 if (!ctx) {
240 merror("%s: ERROR: SSL error. Exiting.", ARGV0);
241 exit(1);
242 }
243
244 if (!manager) {
245 merror("%s: ERROR: Manager IP not set.", ARGV0);
246 exit(1);
247 }
248
249 /* Checking if there is a custom password file */
250 if (authpass != NULL && authenticate > 0) {
251 FILE *fp;
252 fp = fopen(authpass, "r");
253 if(!fp) {
254 fprintf(stderr, "Cannot open %s: %s\n", authpass, strerror(errno));
255 exit(1);
256 }
257 buf[0] = '\0';
258
259 if (fp) {
260 buf[4096] = '\0';
261 fgets(buf, 4095, fp);
262
263 if (strlen(buf) > 2) {
264 authpass = strndup(buf, 32);
265 if(!authpass) {
266 fprintf(stderr, "Could not set the authpass: %s", strerror(errno));
267 exit(1);
268 }
269 }
270
271 fclose(fp);
272 printf("INFO: Using specified password.\n");
273 }
274 }
275 if (!authpass) {
276 printf("WARN: No authentication password provided. Insecure mode started.\n");
277 }
278
279 /* Connect via TCP */
280 sock = OS_ConnectTCP(port, manager);
281 if (sock <= 0) {
282 merror("%s: Unable to connect to %s:%s", ARGV0, manager, port);
283 exit(1);
284 }
285
286 /* Connect the SSL socket */
287 ssl = SSL_new(ctx);
288 sbio = BIO_new_socket(sock, BIO_NOCLOSE);
289 SSL_set_bio(ssl, sbio, sbio);
290
291 ret = SSL_connect(ssl);
292 if (ret <= 0) {
293 ERR_print_errors_fp(stderr);
294 merror("%s: ERROR: SSL error (%d). Exiting.", ARGV0, ret);
295 exit(1);
296 }
297
298 printf("INFO: Connected to %s:%s\n", manager, port);
299
300 /* Additional verification of the manager's certificate if a hostname
301 * rather than an IP address is given on the command line. Could change
302 * this to do the additional validation on IP addresses as well if needed.
303 */
304 if (ca_cert) {
305 printf("INFO: Verifying manager's certificate\n");
306 if (check_x509_cert(ssl, manager) != VERIFY_TRUE) {
307 debug1("%s: DEBUG: Unable to verify server certificate.", ARGV0);
308 exit(1);
309 }
310 }
311
312 printf("INFO: Using agent name as: %s\n", agentname);
313
314 memset(buf, 0, sizeof(buf));
315 if (authpass) {
316 snprintf(buf, 2048, "OSSEC PASS: %s OSSEC A:'%s'\n", authpass, agentname);
317 }
318 else {
319 snprintf(buf, 2048, "OSSEC A:'%s'\n", agentname);
320 }
321
322 ret = SSL_write(ssl, buf, strlen(buf));
323 if (ret < 0) {
324 printf("SSL write error (unable to send message.)\n");
325 ERR_print_errors_fp(stderr);
326 exit(1);
327 }
328
329 printf("INFO: Send request to manager. Waiting for reply.\n");
330
331 while (1) {
332 ret = SSL_read(ssl, buf, sizeof(buf) - 1);
333 switch (SSL_get_error(ssl, ret)) {
334 case SSL_ERROR_NONE:
335 buf[ret] = '\0';
336 if (strncmp(buf, "ERROR", 5) == 0) {
337 char *tmpstr;
338 tmpstr = strchr(buf, '\n');
339 if (tmpstr) {
340 *tmpstr = '\0';
341 }
342 printf("%s (from manager)\n", buf);
343 } else if (strncmp(buf, "OSSEC K:'", 9) == 0) {
344 char *key;
345 char *tmpstr;
346 char **entry;
347 printf("INFO: Received response with agent key\n");
348
349 key = buf;
350 key += 9;
351 tmpstr = strchr(key, '\'');
352 if (!tmpstr) {
353 printf("ERROR: Invalid key received. Closing connection.\n");
354 exit(1);
355 }
356 *tmpstr = '\0';
357 entry = OS_StrBreak(' ', key, 4);
358 if (!OS_IsValidID(entry[0]) || !OS_IsValidName(entry[1]) ||
359 !OS_IsValidName(entry[2]) || !OS_IsValidName(entry[3])) {
360 printf("ERROR: Invalid key received (2). Closing connection.\n");
361 exit(1);
362 }
363
364 {
365 FILE *fp;
366 fp = fopen(KEYSFILE_PATH, "w");
367 if (!fp) {
368 printf("ERROR: Unable to open key file: %s", KEYSFILE_PATH);
369 exit(1);
370 }
371 fprintf(fp, "%s\n", key);
372 fclose(fp);
373 }
374 key_added = 1;
375 printf("INFO: Valid key created. Finished.\n");
376 }
377 break;
378 case SSL_ERROR_ZERO_RETURN:
379 case SSL_ERROR_SYSCALL:
380 if (key_added == 0) {
381 printf("ERROR: Unable to create key. Either wrong password or connection not accepted by the manager.\n");
382 }
383 printf("INFO: Connection closed.\n");
384 exit(0);
385 break;
386 default:
387 printf("ERROR: SSL read (unable to receive message)\n");
388 exit(1);
389 break;
390 }
391
392 }
393
394 /* Shut down the socket */
395 if (key_added == 0) {
396 printf("ERROR: Unable to create key. Either wrong password or connection not accepted by the manager.\n");
397 }
398 SSL_CTX_free(ctx);
399 close(sock);
400
401 exit(0);
402 }
403
404 #endif /* LIBOPENSSL_ENABLED */
405