1 #define SECURITY_WIN32
2 #include <windef.h>
3 #include <sspi.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <winsock2.h>
7 #include <schannel.h>
8 #include <unistd.h>
9 #include <stdarg.h>
10 #include "headers/shared.h"
11 #include "debug_op.h"
12 #include "file_op.h"
13 #include "os_net/os_net.h"
14 #include "os_regex/os_regex.h"
15 #include "defs.h"
16 #include "addagent/manage_agents.h"
17
18 #define IO_BUFFER_SIZE 0x10000
19
report_help()20 void report_help()
21 {
22 printf("\n%s %s: Connects to the manager to extract the agent key.\n", __ossec_name, ARGV0);
23 printf("Available options:\n");
24 printf("\t-h This help message.\n");
25 printf("\t-m <manager ip> Manager IP Address.\n");
26 printf("\t-p <port> Manager port (default 1515).\n");
27 printf("\t-A <agent name> Agent name (default is the hostname).\n");
28 printf("\t-P <pass> Authorization password.\n");
29 exit(1);
30 }
31
SendSecurityToken(const int socket,SecBuffer * OutBuffers)32 void SendSecurityToken(const int socket, SecBuffer *OutBuffers)
33 {
34 int sent = 0;
35
36 if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
37 {
38 sent = send(socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
39 if (sent <= 0)
40 ErrorExit("%s: Could not send security token to server (is ossec-authd running ?)", ARGV0);
41
42 // Free Output Buffer
43 FreeContextBuffer(OutBuffers[0].pvBuffer);
44 OutBuffers[0].pvBuffer = NULL;
45 OutBuffers[0].cbBuffer = 0;
46 }
47 }
48
CreateSecureConnection(char * manager,char * port,int * socket,CtxtHandle * context,CredHandle * cred)49 void CreateSecureConnection(char *manager, char *port, int *socket, CtxtHandle *context, CredHandle *cred)
50 {
51 SECURITY_STATUS status;
52 SCHANNEL_CRED auth_cred;
53 DWORD input_flags = 0;
54 DWORD output_flags = 0;
55 DWORD read = 0;
56 DWORD total_read = 0;
57 SecBufferDesc OutBuffer;
58 SecBuffer OutBuffers[1];
59 SecBufferDesc InBuffer;
60 SecBuffer InBuffers[2];
61 PCHAR buffer = NULL;
62
63 // Get manager IP address
64
65 manager = OS_GetHost(manager, 3);
66 if (manager == NULL)
67 ErrorExit("%s: Could not resolve manager's hostname", ARGV0);
68
69
70
71 // Connect via TCP
72
73 *socket = OS_ConnectTCP(port, manager);
74
75 if (socket == 0)
76 ErrorExit("%s: Unable to connect to %s:%s", ARGV0, manager, port);
77
78
79
80 // Setting authentication credentials
81
82 ZeroMemory(&auth_cred, sizeof (auth_cred));
83 auth_cred.dwVersion = SCHANNEL_CRED_VERSION;
84 auth_cred.dwSessionLifespan = 60000;
85 auth_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_NO_SERVERNAME_CHECK;
86
87 status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &auth_cred, NULL, NULL, cred, NULL);
88 if (status != SEC_E_OK)
89 ErrorExit("%s: Could not acquire credentials (AcquireCredentialsHandle failed with error code 0x%lX", ARGV0, status);
90
91
92 //
93 // Initialize security context
94
95 OutBuffers[0].pvBuffer = NULL;
96 OutBuffers[0].BufferType = SECBUFFER_TOKEN;
97 OutBuffers[0].cbBuffer = 0;
98
99 OutBuffer.cBuffers = 1;
100 OutBuffer.pBuffers = OutBuffers;
101 OutBuffer.ulVersion = SECBUFFER_VERSION;
102
103 InBuffers[1].pvBuffer = NULL;
104 InBuffers[1].cbBuffer = 0;
105 InBuffers[1].BufferType = SECBUFFER_EMPTY;
106
107 buffer = LocalAlloc(LMEM_FIXED, IO_BUFFER_SIZE);
108 if (buffer == NULL)
109 ErrorExit("%s: out of memory !", ARGV0);
110
111 input_flags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM;
112 status = InitializeSecurityContext(cred, NULL, NULL, input_flags, 0, 0, NULL, 0, context, &OutBuffer, &output_flags, NULL);
113
114 while (status != SEC_E_OK)
115 {
116 // See if we have a token to send to the server
117 if (status == SEC_I_CONTINUE_NEEDED)
118 {
119 SendSecurityToken(*socket, OutBuffers);
120 total_read = 0;
121 }
122
123 // See if we have data to retrieve from server
124 if ((total_read == 0) || (status == SEC_E_INCOMPLETE_MESSAGE))
125 {
126 read = recv(*socket, buffer + total_read, IO_BUFFER_SIZE - total_read, 0);
127 if (read <= 0)
128 ErrorExit("%s: Could not get security token from server", ARGV0);
129
130 total_read += read;
131 }
132
133 InBuffers[0].pvBuffer = buffer;
134 InBuffers[0].cbBuffer = total_read;
135 InBuffers[0].BufferType = SECBUFFER_TOKEN;
136
137 InBuffers[1].pvBuffer = NULL;
138 InBuffers[1].cbBuffer = 0;
139 InBuffers[1].BufferType = SECBUFFER_EMPTY;
140
141 InBuffer.cBuffers = 2;
142 InBuffer.pBuffers = InBuffers;
143 InBuffer.ulVersion = SECBUFFER_VERSION;
144
145 status = InitializeSecurityContext(cred, context, NULL, input_flags, 0, 0, &InBuffer, 0, context, &OutBuffer, &output_flags, NULL);
146 }
147
148 // Send remaining tokens if any
149 SendSecurityToken(*socket, OutBuffers);
150
151 printf("INFO: Connected to %s:%s\n", manager, port);
152 LocalFree(buffer);
153 }
154
SendSecureMessage(const int socket,CtxtHandle * context,const char * format,...)155 void SendSecureMessage(const int socket, CtxtHandle *context, const char *format, ...)
156 {
157 va_list args;
158 char *buffer;
159 unsigned int buffer_length = 0;
160 unsigned int msg_length = 0;
161 int sent = 0;
162 SecPkgContext_StreamSizes sizes;
163 SECURITY_STATUS status;
164 SecBufferDesc msg;
165 SecBuffer msg_buffers[4];
166
167 va_start(args, format);
168
169 // Get sizes for given context
170 status = QueryContextAttributes(context, SECPKG_ATTR_STREAM_SIZES, &sizes);
171 if (status != SEC_E_OK)
172 ErrorExit("%s: Could not get message sizes (QueryContextAttributes failed with error code 0x%lX)", ARGV0, status);
173
174 // Construct message
175 buffer_length = sizes.cbHeader + sizes.cbMaximumMessage + sizes.cbTrailer;
176 buffer = LocalAlloc(LMEM_FIXED, buffer_length);
177 if (buffer == NULL)
178 ErrorExit("%s: out of memory !", ARGV0);
179 vsnprintf(buffer + sizes.cbHeader, buffer_length - sizes.cbHeader, format, args);
180 msg_length = strlen(buffer + sizes.cbHeader);
181
182 // Encrypt message in place
183 msg_buffers[0].pvBuffer = buffer;
184 msg_buffers[0].cbBuffer = sizes.cbHeader;
185 msg_buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
186
187 msg_buffers[1].pvBuffer = buffer + sizes.cbHeader;
188 msg_buffers[1].cbBuffer = msg_length;
189 msg_buffers[1].BufferType = SECBUFFER_DATA;
190
191 msg_buffers[2].pvBuffer = buffer + sizes.cbHeader + msg_length;
192 msg_buffers[2].cbBuffer = sizes.cbTrailer;
193 msg_buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
194
195 msg_buffers[3].BufferType = SECBUFFER_EMPTY;
196
197 msg.ulVersion = SECBUFFER_VERSION;
198 msg.cBuffers = 4;
199 msg.pBuffers = msg_buffers;
200
201 status = EncryptMessage(context, 0, &msg, 0);
202 if (status != SEC_E_OK)
203 ErrorExit("%s: Could not encrypt message (EncryptMessage failed with error code %lX)", ARGV0, status);
204
205 sent = send(socket, buffer, msg_buffers[0].cbBuffer + msg_buffers[1].cbBuffer + msg_buffers[2].cbBuffer, 0);
206 if (sent <= 0)
207 ErrorExit("%s: Could not send message to server", ARGV0);
208
209 va_end(args);
210 }
211
ReceiveSecureMessage(const int socket,CtxtHandle * context)212 char *ReceiveSecureMessage(const int socket, CtxtHandle *context)
213 {
214 char *buffer;
215 unsigned int buffer_length = 0;
216 int read = 0;
217 int i = 0;
218 char has_extra_data = 0;
219 SECURITY_STATUS status = SEC_E_INCOMPLETE_MESSAGE;
220 SecBufferDesc msg;
221 SecBuffer msg_buffers[4];
222
223 buffer = LocalAlloc(LMEM_FIXED, IO_BUFFER_SIZE);
224
225 while ((status == SEC_E_INCOMPLETE_MESSAGE) || (has_extra_data))
226 {
227 if (status == SEC_E_INCOMPLETE_MESSAGE)
228 {
229 read = recv(socket, buffer + buffer_length, IO_BUFFER_SIZE - buffer_length, 0);
230 if (read <= 0)
231 ErrorExit("%s: Could not receive message from server (or invalid password)", ARGV0);
232
233 buffer_length += read;
234 }
235
236 msg_buffers[0].pvBuffer = buffer;
237 msg_buffers[0].cbBuffer = buffer_length;
238 msg_buffers[0].BufferType = SECBUFFER_DATA;
239
240 msg_buffers[1].BufferType = SECBUFFER_EMPTY;
241 msg_buffers[2].BufferType = SECBUFFER_EMPTY;
242 msg_buffers[3].BufferType = SECBUFFER_EMPTY;
243
244 msg.ulVersion = SECBUFFER_VERSION;
245 msg.cBuffers = 4;
246 msg.pBuffers = msg_buffers;
247
248 status = DecryptMessage(context, &msg, 0, NULL);
249
250 if ((status != SEC_E_OK) && (status != SEC_E_INCOMPLETE_MESSAGE))
251 ErrorExit("%s: Could not decrypt received message (DecryptMessage failed with error code 0x%lX)", ARGV0, status);
252
253 if (status == SEC_E_OK)
254 {
255 has_extra_data = 0;
256 for (i = 1; i < 4; ++i)
257 if (msg_buffers[i].BufferType == SECBUFFER_EXTRA)
258 {
259 has_extra_data = 1;
260 memcpy(buffer, msg_buffers[i].pvBuffer, msg_buffers[i].cbBuffer);
261 buffer_length = msg_buffers[i].cbBuffer;
262 }
263 }
264 }
265
266 for (i = 1; i < 4; ++i)
267 if (msg_buffers[i].BufferType == SECBUFFER_DATA)
268 return msg_buffers[i].pvBuffer;
269
270 return NULL;
271 }
272
InstallAuthKeys(char * msg)273 void InstallAuthKeys(char *msg)
274 {
275 if (strncmp(msg, "ERROR", 5) == 0)
276 ErrorExit("%s: %s (from manager)", ARGV0, msg);
277 else if (strncmp(msg, "OSSEC K:'", 9) == 0)
278 {
279 char *key;
280 char *tmpstr;
281 char **entry;
282 FILE *fp;
283
284 printf("INFO: Received response with agent key\n");
285
286 key = msg + 9;
287 tmpstr = strchr(key, '\'');
288
289 if (!tmpstr)
290 ErrorExit("%s: Invalid key received. Closing connection.", ARGV0);
291
292 *tmpstr = '\0';
293 entry = OS_StrBreak(' ', key, 4);
294
295 if (!OS_IsValidID(entry[0]) || !OS_IsValidName(entry[1]) ||
296 !OS_IsValidName(entry[2]) || !OS_IsValidName(entry[3]))
297 ErrorExit("%s: Invalid key received (2). Closing connection.", ARGV0);
298
299 fp = fopen(KEYSFILE_PATH, "w");
300
301 if (!fp)
302 ErrorExit("%s: Unable to open key file: %s", ARGV0, KEYSFILE_PATH);
303
304 fprintf(fp, "%s\n", key);
305 fclose(fp);
306
307 printf("INFO: Valid key created. Finished.\n");
308 }
309 else
310 ErrorExit("%s: Unknown message received (%s)", ARGV0, msg);
311 }
312
DisconnectFromServer(const int socket,CtxtHandle * context,CredHandle * cred)313 void DisconnectFromServer(const int socket, CtxtHandle *context, CredHandle *cred)
314 {
315 SecBufferDesc OutBuffer;
316 SecBuffer OutBuffers[1];
317 DWORD dwType;
318 SECURITY_STATUS status;
319 DWORD input_flags;
320 DWORD output_flags;
321 int sent = 0;
322
323 dwType = SCHANNEL_SHUTDOWN;
324
325 OutBuffers[0].pvBuffer = &dwType;
326 OutBuffers[0].BufferType = SECBUFFER_TOKEN;
327 OutBuffers[0].cbBuffer = sizeof(dwType);
328
329 OutBuffer.cBuffers = 1;
330 OutBuffer.pBuffers = OutBuffers;
331 OutBuffer.ulVersion = SECBUFFER_VERSION;
332
333 status = ApplyControlToken(context, &OutBuffer);
334 if (status != SEC_E_OK)
335 ErrorExit("%s: Could not correclty close connection", ARGV0);
336
337 input_flags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM;
338 OutBuffers[0].pvBuffer = NULL;
339 OutBuffers[0].BufferType = SECBUFFER_TOKEN;
340 OutBuffers[0].cbBuffer = 0;
341
342 OutBuffer.cBuffers = 1;
343 OutBuffer.pBuffers = OutBuffers;
344 OutBuffer.ulVersion = SECBUFFER_VERSION;
345
346 status = InitializeSecurityContext(cred, context, NULL, input_flags, 0, 0, NULL, 0, context, &OutBuffer, &output_flags, NULL);
347 if (status != SEC_E_OK)
348 ErrorExit("%s: Could not correclty close connection (2)", ARGV0);
349
350 sent = send(socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
351 if (sent <= 0)
352 ErrorExit("%s: Could not correclty close connection (3)", ARGV0);
353
354 FreeContextBuffer(OutBuffers[0].pvBuffer);
355 DeleteSecurityContext(context);
356 close(socket);
357 }
358
main(int argc,char ** argv)359 int main(int argc, char **argv)
360 {
361 int error = 0;
362 int socket = 0;
363 char *port = "1515";
364 char c = 0;
365 char *manager = NULL;
366 char *agentname = NULL;
367 char hostname[512];
368 char *msg = NULL;
369 char *authpass = NULL;
370 char buf[4096 + 1] = { '\0' };
371 WSADATA wsa;
372 CtxtHandle context;
373 CredHandle cred;
374
375 /* Setting the name */
376 OS_SetName(ARGV0);
377
378 while((c = getopt(argc, argv, "hm:p:A:P:")) != -1)
379 {
380 switch(c){
381 case 'h':
382 report_help();
383 break;
384 case 'm':
385 if(!optarg)
386 ErrorExit("%s: -%c needs an argument",ARGV0, c);
387 manager = optarg;
388 break;
389 case 'A':
390 if(!optarg)
391 ErrorExit("%s: -%c needs an argument",ARGV0, c);
392 agentname = optarg;
393 break;
394 case 'p': {
395 if(!optarg)
396 ErrorExit("%s: -%c needs an argument",ARGV0, c);
397 int tmp_port;
398 tmp_port = atoi(optarg);
399 if(tmp_port <= 0 || tmp_port >= 65536)
400 {
401 ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
402 }
403 port = optarg;
404 break;
405 }
406 case 'P':
407 if (!optarg)
408 ErrorExit("%s: -%c needs an argument", ARGV0, c);
409
410 authpass = optarg;
411 break;
412 default:
413 report_help();
414 break;
415 }
416 }
417
418 // Initialize Windows Networking
419 error = WSAStartup(MAKEWORD(2, 2), &wsa);
420 if (error)
421 ErrorExit("%s: Could not initialize networking (WSAStartup failed with error code %u)", ARGV0, error);
422
423 // Determine agent_name
424 if(agentname == NULL)
425 {
426 if(gethostname(hostname, 512) != 0)
427 ErrorExit("%s: ERROR: Unable to extract hostname. Custom agent name not set.", ARGV0);
428
429 agentname = hostname;
430 }
431
432 /* Checking if there is a custom password file */
433 if (authpass == NULL) {
434 FILE *fp;
435 fp = fopen(AUTHDPASS_PATH, "r");
436 buf[0] = '\0';
437
438 if (fp) {
439 buf[4096] = '\0';
440 char *ret = fgets(buf, 4095, fp);
441
442 if (ret && strlen(buf) > 2) {
443 authpass = buf;
444 }
445
446 fclose(fp);
447 printf("INFO: Using password specified on file: %s\n", AUTHDPASS_PATH);
448 }
449 }
450 if (!authpass) {
451 printf("WARN: No authentication password provided. Insecure mode started.\n");
452
453 }
454
455 // Connect to socket and init security context
456 CreateSecureConnection(manager, port, &socket, &context, &cred);
457
458 printf("INFO: Using agent name as: %s\n", agentname);
459
460 // Send request
461
462 if (authpass)
463 SendSecureMessage(socket, &context, "OSSEC PASS: %s OSSEC A:'%s'\n", authpass, agentname);
464 else
465 SendSecureMessage(socket, &context, "OSSEC A:'%s'\n", agentname);
466
467 printf("INFO: Sent request to manager. Waiting for reply.\n");
468
469 // Get response
470 msg = ReceiveSecureMessage(socket, &context);
471
472 // Install received keys
473 InstallAuthKeys(msg);
474
475 // Disconnect
476 DisconnectFromServer(socket, &context, &cred);
477
478 return (0);
479 }
480