Line data Source code
1 : /*
2 : * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
3 : * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 : #ifndef CONFIG_NATIVE_WINDOWS
11 : #include <dlfcn.h>
12 : #endif /* CONFIG_NATIVE_WINDOWS */
13 :
14 : #include "common.h"
15 : #include "base64.h"
16 : #include "common/tnc.h"
17 : #include "tncc.h"
18 : #include "eap_common/eap_tlv_common.h"
19 : #include "eap_common/eap_defs.h"
20 :
21 :
22 : #ifdef UNICODE
23 : #define TSTR "%S"
24 : #else /* UNICODE */
25 : #define TSTR "%s"
26 : #endif /* UNICODE */
27 :
28 :
29 : #ifndef TNC_CONFIG_FILE
30 : #define TNC_CONFIG_FILE "/etc/tnc_config"
31 : #endif /* TNC_CONFIG_FILE */
32 : #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
33 : #define IF_TNCCS_START \
34 : "<?xml version=\"1.0\"?>\n" \
35 : "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
36 : "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
37 : "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
38 : "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
39 : "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
40 : #define IF_TNCCS_END "\n</TNCCS-Batch>"
41 :
42 : /* TNC IF-IMC */
43 :
44 : /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
45 : enum {
46 : SSOH_MS_MACHINE_INVENTORY = 1,
47 : SSOH_MS_QUARANTINE_STATE = 2,
48 : SSOH_MS_PACKET_INFO = 3,
49 : SSOH_MS_SYSTEMGENERATED_IDS = 4,
50 : SSOH_MS_MACHINENAME = 5,
51 : SSOH_MS_CORRELATIONID = 6,
52 : SSOH_MS_INSTALLED_SHVS = 7,
53 : SSOH_MS_MACHINE_INVENTORY_EX = 8
54 : };
55 :
56 : struct tnc_if_imc {
57 : struct tnc_if_imc *next;
58 : char *name;
59 : char *path;
60 : void *dlhandle; /* from dlopen() */
61 : TNC_IMCID imcID;
62 : TNC_ConnectionID connectionID;
63 : TNC_MessageTypeList supported_types;
64 : size_t num_supported_types;
65 : u8 *imc_send;
66 : size_t imc_send_len;
67 :
68 : /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
69 : TNC_Result (*Initialize)(
70 : TNC_IMCID imcID,
71 : TNC_Version minVersion,
72 : TNC_Version maxVersion,
73 : TNC_Version *pOutActualVersion);
74 : TNC_Result (*NotifyConnectionChange)(
75 : TNC_IMCID imcID,
76 : TNC_ConnectionID connectionID,
77 : TNC_ConnectionState newState);
78 : TNC_Result (*BeginHandshake)(
79 : TNC_IMCID imcID,
80 : TNC_ConnectionID connectionID);
81 : TNC_Result (*ReceiveMessage)(
82 : TNC_IMCID imcID,
83 : TNC_ConnectionID connectionID,
84 : TNC_BufferReference messageBuffer,
85 : TNC_UInt32 messageLength,
86 : TNC_MessageType messageType);
87 : TNC_Result (*BatchEnding)(
88 : TNC_IMCID imcID,
89 : TNC_ConnectionID connectionID);
90 : TNC_Result (*Terminate)(TNC_IMCID imcID);
91 : TNC_Result (*ProvideBindFunction)(
92 : TNC_IMCID imcID,
93 : TNC_TNCC_BindFunctionPointer bindFunction);
94 : };
95 :
96 : struct tncc_data {
97 : struct tnc_if_imc *imc;
98 : unsigned int last_batchid;
99 : };
100 :
101 : #define TNC_MAX_IMC_ID 10
102 : static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
103 :
104 :
105 : /* TNCC functions that IMCs can call */
106 :
107 41 : static TNC_Result TNC_TNCC_ReportMessageTypes(
108 : TNC_IMCID imcID,
109 : TNC_MessageTypeList supportedTypes,
110 : TNC_UInt32 typeCount)
111 : {
112 : TNC_UInt32 i;
113 : struct tnc_if_imc *imc;
114 :
115 41 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
116 : "typeCount=%lu)",
117 : (unsigned long) imcID, (unsigned long) typeCount);
118 :
119 82 : for (i = 0; i < typeCount; i++) {
120 41 : wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
121 41 : i, supportedTypes[i]);
122 : }
123 :
124 41 : if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
125 0 : return TNC_RESULT_INVALID_PARAMETER;
126 :
127 41 : imc = tnc_imc[imcID];
128 41 : os_free(imc->supported_types);
129 41 : imc->supported_types =
130 41 : os_malloc(typeCount * sizeof(TNC_MessageType));
131 41 : if (imc->supported_types == NULL)
132 1 : return TNC_RESULT_FATAL;
133 40 : os_memcpy(imc->supported_types, supportedTypes,
134 : typeCount * sizeof(TNC_MessageType));
135 40 : imc->num_supported_types = typeCount;
136 :
137 40 : return TNC_RESULT_SUCCESS;
138 : }
139 :
140 :
141 37 : static TNC_Result TNC_TNCC_SendMessage(
142 : TNC_IMCID imcID,
143 : TNC_ConnectionID connectionID,
144 : TNC_BufferReference message,
145 : TNC_UInt32 messageLength,
146 : TNC_MessageType messageType)
147 : {
148 : struct tnc_if_imc *imc;
149 : unsigned char *b64;
150 : size_t b64len;
151 :
152 37 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
153 : "connectionID=%lu messageType=%lu)",
154 : imcID, connectionID, messageType);
155 37 : wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
156 : message, messageLength);
157 :
158 37 : if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
159 0 : return TNC_RESULT_INVALID_PARAMETER;
160 :
161 37 : b64 = base64_encode(message, messageLength, &b64len);
162 37 : if (b64 == NULL)
163 1 : return TNC_RESULT_FATAL;
164 :
165 36 : imc = tnc_imc[imcID];
166 36 : os_free(imc->imc_send);
167 36 : imc->imc_send_len = 0;
168 36 : imc->imc_send = os_zalloc(b64len + 100);
169 36 : if (imc->imc_send == NULL) {
170 1 : os_free(b64);
171 1 : return TNC_RESULT_OTHER;
172 : }
173 :
174 35 : imc->imc_send_len =
175 35 : os_snprintf((char *) imc->imc_send, b64len + 100,
176 : "<IMC-IMV-Message><Type>%08X</Type>"
177 : "<Base64>%s</Base64></IMC-IMV-Message>",
178 : (unsigned int) messageType, b64);
179 :
180 35 : os_free(b64);
181 :
182 35 : return TNC_RESULT_SUCCESS;
183 : }
184 :
185 :
186 0 : static TNC_Result TNC_TNCC_RequestHandshakeRetry(
187 : TNC_IMCID imcID,
188 : TNC_ConnectionID connectionID,
189 : TNC_RetryReason reason)
190 : {
191 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
192 :
193 0 : if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
194 0 : return TNC_RESULT_INVALID_PARAMETER;
195 :
196 : /*
197 : * TODO: trigger a call to eapol_sm_request_reauth(). This would
198 : * require that the IMC continues to be loaded in memory afer
199 : * authentication..
200 : */
201 :
202 0 : return TNC_RESULT_SUCCESS;
203 : }
204 :
205 :
206 0 : static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
207 : const char *message)
208 : {
209 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
210 : "severity==%lu message='%s')",
211 : imcID, severity, message);
212 0 : return TNC_RESULT_SUCCESS;
213 : }
214 :
215 :
216 0 : static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
217 : TNC_ConnectionID connectionID,
218 : const char *message)
219 : {
220 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
221 : "connectionID==%lu message='%s')",
222 : imcID, connectionID, message);
223 0 : return TNC_RESULT_SUCCESS;
224 : }
225 :
226 :
227 123 : static TNC_Result TNC_TNCC_BindFunction(
228 : TNC_IMCID imcID,
229 : char *functionName,
230 : void **pOutfunctionPointer)
231 : {
232 123 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
233 : "functionName='%s')", (unsigned long) imcID, functionName);
234 :
235 123 : if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
236 0 : return TNC_RESULT_INVALID_PARAMETER;
237 :
238 123 : if (pOutfunctionPointer == NULL)
239 0 : return TNC_RESULT_INVALID_PARAMETER;
240 :
241 123 : if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
242 41 : *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
243 82 : else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
244 41 : *pOutfunctionPointer = TNC_TNCC_SendMessage;
245 41 : else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
246 : 0)
247 41 : *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
248 0 : else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
249 0 : *pOutfunctionPointer = TNC_9048_LogMessage;
250 0 : else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
251 0 : *pOutfunctionPointer = TNC_9048_UserMessage;
252 : else
253 0 : *pOutfunctionPointer = NULL;
254 :
255 123 : return TNC_RESULT_SUCCESS;
256 : }
257 :
258 :
259 574 : static void * tncc_get_sym(void *handle, char *func)
260 : {
261 : void *fptr;
262 :
263 : #ifdef CONFIG_NATIVE_WINDOWS
264 : #ifdef _WIN32_WCE
265 : fptr = GetProcAddressA(handle, func);
266 : #else /* _WIN32_WCE */
267 : fptr = GetProcAddress(handle, func);
268 : #endif /* _WIN32_WCE */
269 : #else /* CONFIG_NATIVE_WINDOWS */
270 574 : fptr = dlsym(handle, func);
271 : #endif /* CONFIG_NATIVE_WINDOWS */
272 :
273 574 : return fptr;
274 : }
275 :
276 :
277 82 : static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
278 : {
279 82 : void *handle = imc->dlhandle;
280 :
281 : /* Mandatory IMC functions */
282 82 : imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
283 82 : if (imc->Initialize == NULL) {
284 0 : wpa_printf(MSG_ERROR, "TNC: IMC does not export "
285 : "TNC_IMC_Initialize");
286 0 : return -1;
287 : }
288 :
289 82 : imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
290 82 : if (imc->BeginHandshake == NULL) {
291 0 : wpa_printf(MSG_ERROR, "TNC: IMC does not export "
292 : "TNC_IMC_BeginHandshake");
293 0 : return -1;
294 : }
295 :
296 82 : imc->ProvideBindFunction =
297 82 : tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
298 82 : if (imc->ProvideBindFunction == NULL) {
299 0 : wpa_printf(MSG_ERROR, "TNC: IMC does not export "
300 : "TNC_IMC_ProvideBindFunction");
301 0 : return -1;
302 : }
303 :
304 : /* Optional IMC functions */
305 82 : imc->NotifyConnectionChange =
306 82 : tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
307 82 : imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
308 82 : imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
309 82 : imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
310 :
311 82 : return 0;
312 : }
313 :
314 :
315 82 : static int tncc_imc_initialize(struct tnc_if_imc *imc)
316 : {
317 : TNC_Result res;
318 : TNC_Version imc_ver;
319 :
320 82 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
321 : imc->name);
322 82 : res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
323 : TNC_IFIMC_VERSION_1, &imc_ver);
324 82 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
325 : (unsigned long) res, (unsigned long) imc_ver);
326 :
327 82 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
328 : }
329 :
330 :
331 84 : static int tncc_imc_terminate(struct tnc_if_imc *imc)
332 : {
333 : TNC_Result res;
334 :
335 84 : if (imc->Terminate == NULL)
336 43 : return 0;
337 :
338 41 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
339 : imc->name);
340 41 : res = imc->Terminate(imc->imcID);
341 41 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
342 : (unsigned long) res);
343 :
344 41 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
345 : }
346 :
347 :
348 82 : static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
349 : {
350 : TNC_Result res;
351 :
352 82 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
353 : "IMC '%s'", imc->name);
354 82 : res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
355 82 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
356 : (unsigned long) res);
357 :
358 82 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
359 : }
360 :
361 :
362 148 : static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
363 : TNC_ConnectionState state)
364 : {
365 : TNC_Result res;
366 :
367 148 : if (imc->NotifyConnectionChange == NULL)
368 74 : return 0;
369 :
370 74 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
371 : " for IMC '%s'", (int) state, imc->name);
372 74 : res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
373 : state);
374 74 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
375 : (unsigned long) res);
376 :
377 74 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
378 : }
379 :
380 :
381 66 : static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
382 : {
383 : TNC_Result res;
384 :
385 66 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
386 : "'%s'", imc->name);
387 66 : res = imc->BeginHandshake(imc->imcID, imc->connectionID);
388 66 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
389 : (unsigned long) res);
390 :
391 66 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
392 : }
393 :
394 :
395 83 : static int tncc_load_imc(struct tnc_if_imc *imc)
396 : {
397 83 : if (imc->path == NULL) {
398 1 : wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
399 1 : return -1;
400 : }
401 :
402 82 : wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
403 : imc->name, imc->path);
404 : #ifdef CONFIG_NATIVE_WINDOWS
405 : #ifdef UNICODE
406 : {
407 : TCHAR *lib = wpa_strdup_tchar(imc->path);
408 : if (lib == NULL)
409 : return -1;
410 : imc->dlhandle = LoadLibrary(lib);
411 : os_free(lib);
412 : }
413 : #else /* UNICODE */
414 : imc->dlhandle = LoadLibrary(imc->path);
415 : #endif /* UNICODE */
416 : if (imc->dlhandle == NULL) {
417 : wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
418 : imc->name, imc->path, (int) GetLastError());
419 : return -1;
420 : }
421 : #else /* CONFIG_NATIVE_WINDOWS */
422 82 : imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
423 82 : if (imc->dlhandle == NULL) {
424 0 : wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
425 : imc->name, imc->path, dlerror());
426 0 : return -1;
427 : }
428 : #endif /* CONFIG_NATIVE_WINDOWS */
429 :
430 82 : if (tncc_imc_resolve_funcs(imc) < 0) {
431 0 : wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
432 0 : return -1;
433 : }
434 :
435 164 : if (tncc_imc_initialize(imc) < 0 ||
436 82 : tncc_imc_provide_bind_function(imc) < 0) {
437 1 : wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
438 1 : return -1;
439 : }
440 :
441 81 : return 0;
442 : }
443 :
444 :
445 84 : static void tncc_unload_imc(struct tnc_if_imc *imc)
446 : {
447 84 : tncc_imc_terminate(imc);
448 84 : tnc_imc[imc->imcID] = NULL;
449 :
450 84 : if (imc->dlhandle) {
451 : #ifdef CONFIG_NATIVE_WINDOWS
452 : FreeLibrary(imc->dlhandle);
453 : #else /* CONFIG_NATIVE_WINDOWS */
454 82 : dlclose(imc->dlhandle);
455 : #endif /* CONFIG_NATIVE_WINDOWS */
456 : }
457 84 : os_free(imc->name);
458 84 : os_free(imc->path);
459 84 : os_free(imc->supported_types);
460 84 : os_free(imc->imc_send);
461 84 : }
462 :
463 :
464 4 : static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
465 : {
466 : size_t i;
467 : unsigned int vendor, subtype;
468 :
469 4 : if (imc == NULL || imc->supported_types == NULL)
470 0 : return 0;
471 :
472 4 : vendor = type >> 8;
473 4 : subtype = type & 0xff;
474 :
475 4 : for (i = 0; i < imc->num_supported_types; i++) {
476 : unsigned int svendor, ssubtype;
477 4 : svendor = imc->supported_types[i] >> 8;
478 4 : ssubtype = imc->supported_types[i] & 0xff;
479 4 : if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
480 4 : (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
481 4 : return 1;
482 : }
483 :
484 0 : return 0;
485 : }
486 :
487 :
488 4 : static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
489 : const u8 *msg, size_t len)
490 : {
491 : struct tnc_if_imc *imc;
492 : TNC_Result res;
493 :
494 4 : wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
495 :
496 12 : for (imc = tncc->imc; imc; imc = imc->next) {
497 12 : if (imc->ReceiveMessage == NULL ||
498 4 : !tncc_supported_type(imc, type))
499 4 : continue;
500 :
501 4 : wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
502 : imc->name);
503 4 : res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
504 : (TNC_BufferReference) msg, len,
505 : type);
506 4 : wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
507 : (unsigned long) res);
508 : }
509 4 : }
510 :
511 :
512 33 : void tncc_init_connection(struct tncc_data *tncc)
513 : {
514 : struct tnc_if_imc *imc;
515 :
516 99 : for (imc = tncc->imc; imc; imc = imc->next) {
517 66 : tncc_imc_notify_connection_change(
518 : imc, TNC_CONNECTION_STATE_CREATE);
519 66 : tncc_imc_notify_connection_change(
520 : imc, TNC_CONNECTION_STATE_HANDSHAKE);
521 :
522 66 : os_free(imc->imc_send);
523 66 : imc->imc_send = NULL;
524 66 : imc->imc_send_len = 0;
525 :
526 66 : tncc_imc_begin_handshake(imc);
527 : }
528 33 : }
529 :
530 :
531 47 : size_t tncc_total_send_len(struct tncc_data *tncc)
532 : {
533 : struct tnc_if_imc *imc;
534 :
535 47 : size_t len = 0;
536 141 : for (imc = tncc->imc; imc; imc = imc->next)
537 94 : len += imc->imc_send_len;
538 47 : return len;
539 : }
540 :
541 :
542 44 : u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
543 : {
544 : struct tnc_if_imc *imc;
545 :
546 132 : for (imc = tncc->imc; imc; imc = imc->next) {
547 88 : if (imc->imc_send == NULL)
548 56 : continue;
549 :
550 32 : os_memcpy(pos, imc->imc_send, imc->imc_send_len);
551 32 : pos += imc->imc_send_len;
552 32 : os_free(imc->imc_send);
553 32 : imc->imc_send = NULL;
554 32 : imc->imc_send_len = 0;
555 : }
556 :
557 44 : return pos;
558 : }
559 :
560 :
561 47 : char * tncc_if_tnccs_start(struct tncc_data *tncc)
562 : {
563 47 : char *buf = os_malloc(1000);
564 47 : if (buf == NULL)
565 1 : return NULL;
566 46 : tncc->last_batchid++;
567 46 : os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
568 46 : return buf;
569 : }
570 :
571 :
572 46 : char * tncc_if_tnccs_end(void)
573 : {
574 46 : char *buf = os_malloc(100);
575 46 : if (buf == NULL)
576 1 : return NULL;
577 45 : os_snprintf(buf, 100, IF_TNCCS_END);
578 45 : return buf;
579 : }
580 :
581 :
582 8 : static void tncc_notify_recommendation(struct tncc_data *tncc,
583 : enum tncc_process_res res)
584 : {
585 : TNC_ConnectionState state;
586 : struct tnc_if_imc *imc;
587 :
588 8 : switch (res) {
589 : case TNCCS_RECOMMENDATION_ALLOW:
590 4 : state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
591 4 : break;
592 : case TNCCS_RECOMMENDATION_NONE:
593 1 : state = TNC_CONNECTION_STATE_ACCESS_NONE;
594 1 : break;
595 : case TNCCS_RECOMMENDATION_ISOLATE:
596 1 : state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
597 1 : break;
598 : default:
599 2 : state = TNC_CONNECTION_STATE_ACCESS_NONE;
600 2 : break;
601 : }
602 :
603 24 : for (imc = tncc->imc; imc; imc = imc->next)
604 16 : tncc_imc_notify_connection_change(imc, state);
605 8 : }
606 :
607 :
608 20 : static int tncc_get_type(char *start, unsigned int *type)
609 : {
610 20 : char *pos = os_strstr(start, "<Type>");
611 20 : if (pos == NULL)
612 2 : return -1;
613 18 : pos += 6;
614 18 : *type = strtoul(pos, NULL, 16);
615 18 : return 0;
616 : }
617 :
618 :
619 9 : static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
620 : {
621 : char *pos, *pos2;
622 : unsigned char *decoded;
623 :
624 9 : pos = os_strstr(start, "<Base64>");
625 9 : if (pos == NULL)
626 1 : return NULL;
627 :
628 8 : pos += 8;
629 8 : pos2 = os_strstr(pos, "</Base64>");
630 8 : if (pos2 == NULL)
631 1 : return NULL;
632 7 : *pos2 = '\0';
633 :
634 7 : decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
635 : decoded_len);
636 7 : *pos2 = '<';
637 7 : if (decoded == NULL) {
638 2 : wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
639 : }
640 :
641 7 : return decoded;
642 : }
643 :
644 :
645 8 : static enum tncc_process_res tncc_get_recommendation(char *start)
646 : {
647 : char *pos, *pos2, saved;
648 : int recom;
649 :
650 8 : pos = os_strstr(start, "<TNCCS-Recommendation ");
651 8 : if (pos == NULL)
652 1 : return TNCCS_RECOMMENDATION_ERROR;
653 :
654 7 : pos += 21;
655 7 : pos = os_strstr(pos, " type=");
656 7 : if (pos == NULL)
657 1 : return TNCCS_RECOMMENDATION_ERROR;
658 6 : pos += 6;
659 :
660 6 : if (*pos == '"')
661 6 : pos++;
662 :
663 6 : pos2 = pos;
664 43 : while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
665 31 : pos2++;
666 :
667 6 : if (*pos2 == '\0')
668 0 : return TNCCS_RECOMMENDATION_ERROR;
669 :
670 6 : saved = *pos2;
671 6 : *pos2 = '\0';
672 6 : wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
673 :
674 6 : recom = TNCCS_RECOMMENDATION_ERROR;
675 6 : if (os_strcmp(pos, "allow") == 0)
676 4 : recom = TNCCS_RECOMMENDATION_ALLOW;
677 2 : else if (os_strcmp(pos, "none") == 0)
678 1 : recom = TNCCS_RECOMMENDATION_NONE;
679 1 : else if (os_strcmp(pos, "isolate") == 0)
680 1 : recom = TNCCS_RECOMMENDATION_ISOLATE;
681 :
682 6 : *pos2 = saved;
683 :
684 6 : return recom;
685 : }
686 :
687 :
688 25 : enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
689 : const u8 *msg, size_t len)
690 : {
691 : char *buf, *start, *end, *pos, *pos2, *payload;
692 : unsigned int batch_id;
693 : unsigned char *decoded;
694 : size_t decoded_len;
695 25 : enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
696 25 : int recommendation_msg = 0;
697 :
698 25 : wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
699 : msg, len);
700 25 : buf = dup_binstr(msg, len);
701 25 : if (buf == NULL)
702 1 : return TNCCS_PROCESS_ERROR;
703 :
704 24 : start = os_strstr(buf, "<TNCCS-Batch ");
705 24 : end = os_strstr(buf, "</TNCCS-Batch>");
706 24 : if (start == NULL || end == NULL || start > end) {
707 2 : os_free(buf);
708 2 : return TNCCS_PROCESS_ERROR;
709 : }
710 :
711 22 : start += 13;
712 50 : while (*start == ' ')
713 6 : start++;
714 22 : *end = '\0';
715 :
716 22 : pos = os_strstr(start, "BatchId=");
717 22 : if (pos == NULL) {
718 1 : os_free(buf);
719 1 : return TNCCS_PROCESS_ERROR;
720 : }
721 :
722 21 : pos += 8;
723 21 : if (*pos == '"')
724 10 : pos++;
725 21 : batch_id = atoi(pos);
726 21 : wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
727 : batch_id);
728 21 : if (batch_id != tncc->last_batchid + 1) {
729 1 : wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
730 : "%u (expected %u)",
731 1 : batch_id, tncc->last_batchid + 1);
732 1 : os_free(buf);
733 1 : return TNCCS_PROCESS_ERROR;
734 : }
735 20 : tncc->last_batchid = batch_id;
736 :
737 2880 : while (*pos != '\0' && *pos != '>')
738 2840 : pos++;
739 20 : if (*pos == '\0') {
740 0 : os_free(buf);
741 0 : return TNCCS_PROCESS_ERROR;
742 : }
743 20 : pos++;
744 20 : payload = start;
745 :
746 : /*
747 : * <IMC-IMV-Message>
748 : * <Type>01234567</Type>
749 : * <Base64>foo==</Base64>
750 : * </IMC-IMV-Message>
751 : */
752 :
753 47 : while (*start) {
754 : char *endpos;
755 : unsigned int type;
756 :
757 27 : pos = os_strstr(start, "<IMC-IMV-Message>");
758 27 : if (pos == NULL)
759 39 : break;
760 8 : start = pos + 17;
761 8 : end = os_strstr(start, "</IMC-IMV-Message>");
762 8 : if (end == NULL)
763 1 : break;
764 7 : *end = '\0';
765 7 : endpos = end;
766 7 : end += 18;
767 :
768 7 : if (tncc_get_type(start, &type) < 0) {
769 1 : *endpos = '<';
770 1 : start = end;
771 4 : continue;
772 : }
773 6 : wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
774 :
775 6 : decoded = tncc_get_base64(start, &decoded_len);
776 6 : if (decoded == NULL) {
777 2 : *endpos = '<';
778 2 : start = end;
779 2 : continue;
780 : }
781 :
782 4 : tncc_send_to_imcs(tncc, type, decoded, decoded_len);
783 :
784 4 : os_free(decoded);
785 :
786 4 : start = end;
787 : }
788 :
789 : /*
790 : * <TNCC-TNCS-Message>
791 : * <Type>01234567</Type>
792 : * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
793 : * <Base64>foo==</Base64>
794 : * </TNCC-TNCS-Message>
795 : */
796 :
797 20 : start = payload;
798 53 : while (*start) {
799 : unsigned int type;
800 : char *xml, *xmlend, *endpos;
801 :
802 24 : pos = os_strstr(start, "<TNCC-TNCS-Message>");
803 24 : if (pos == NULL)
804 21 : break;
805 14 : start = pos + 19;
806 14 : end = os_strstr(start, "</TNCC-TNCS-Message>");
807 14 : if (end == NULL)
808 1 : break;
809 13 : *end = '\0';
810 13 : endpos = end;
811 13 : end += 20;
812 :
813 13 : if (tncc_get_type(start, &type) < 0) {
814 1 : *endpos = '<';
815 1 : start = end;
816 5 : continue;
817 : }
818 12 : wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
819 : type);
820 :
821 : /* Base64 OR XML */
822 12 : decoded = NULL;
823 12 : xml = NULL;
824 12 : xmlend = NULL;
825 12 : pos = os_strstr(start, "<XML>");
826 12 : if (pos) {
827 9 : pos += 5;
828 9 : pos2 = os_strstr(pos, "</XML>");
829 9 : if (pos2 == NULL) {
830 1 : *endpos = '<';
831 1 : start = end;
832 1 : continue;
833 : }
834 8 : xmlend = pos2;
835 8 : xml = pos;
836 : } else {
837 3 : decoded = tncc_get_base64(start, &decoded_len);
838 3 : if (decoded == NULL) {
839 2 : *endpos = '<';
840 2 : start = end;
841 2 : continue;
842 : }
843 : }
844 :
845 9 : if (decoded) {
846 1 : wpa_hexdump_ascii(MSG_MSGDUMP,
847 : "TNC: TNCC-TNCS-Message Base64",
848 : decoded, decoded_len);
849 1 : os_free(decoded);
850 : }
851 :
852 9 : if (xml) {
853 8 : wpa_hexdump_ascii(MSG_MSGDUMP,
854 : "TNC: TNCC-TNCS-Message XML",
855 : (unsigned char *) xml,
856 8 : xmlend - xml);
857 : }
858 :
859 9 : if (type == TNC_TNCCS_RECOMMENDATION && xml) {
860 : /*
861 : * <TNCCS-Recommendation type="allow">
862 : * </TNCCS-Recommendation>
863 : */
864 8 : *xmlend = '\0';
865 8 : res = tncc_get_recommendation(xml);
866 8 : *xmlend = '<';
867 8 : recommendation_msg = 1;
868 : }
869 :
870 9 : start = end;
871 : }
872 :
873 20 : os_free(buf);
874 :
875 20 : if (recommendation_msg)
876 8 : tncc_notify_recommendation(tncc, res);
877 :
878 20 : return res;
879 : }
880 :
881 :
882 : #ifdef CONFIG_NATIVE_WINDOWS
883 : static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
884 : {
885 : HKEY hk, hk2;
886 : LONG ret;
887 : DWORD i;
888 : struct tnc_if_imc *imc, *last;
889 : int j;
890 :
891 : last = tncc->imc;
892 : while (last && last->next)
893 : last = last->next;
894 :
895 : ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
896 : &hk);
897 : if (ret != ERROR_SUCCESS)
898 : return 0;
899 :
900 : for (i = 0; ; i++) {
901 : TCHAR name[255], *val;
902 : DWORD namelen, buflen;
903 :
904 : namelen = 255;
905 : ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
906 : NULL);
907 :
908 : if (ret == ERROR_NO_MORE_ITEMS)
909 : break;
910 :
911 : if (ret != ERROR_SUCCESS) {
912 : wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
913 : (unsigned int) ret);
914 : break;
915 : }
916 :
917 : if (namelen >= 255)
918 : namelen = 255 - 1;
919 : name[namelen] = '\0';
920 :
921 : wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
922 :
923 : ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
924 : if (ret != ERROR_SUCCESS) {
925 : wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
926 : "'", name);
927 : continue;
928 : }
929 :
930 : ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
931 : &buflen);
932 : if (ret != ERROR_SUCCESS) {
933 : wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
934 : "IMC key '" TSTR "'", name);
935 : RegCloseKey(hk2);
936 : continue;
937 : }
938 :
939 : val = os_malloc(buflen);
940 : if (val == NULL) {
941 : RegCloseKey(hk2);
942 : continue;
943 : }
944 :
945 : ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
946 : (LPBYTE) val, &buflen);
947 : if (ret != ERROR_SUCCESS) {
948 : os_free(val);
949 : RegCloseKey(hk2);
950 : continue;
951 : }
952 :
953 : RegCloseKey(hk2);
954 :
955 : wpa_unicode2ascii_inplace(val);
956 : wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
957 :
958 : for (j = 0; j < TNC_MAX_IMC_ID; j++) {
959 : if (tnc_imc[j] == NULL)
960 : break;
961 : }
962 : if (j >= TNC_MAX_IMC_ID) {
963 : wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
964 : os_free(val);
965 : continue;
966 : }
967 :
968 : imc = os_zalloc(sizeof(*imc));
969 : if (imc == NULL) {
970 : os_free(val);
971 : break;
972 : }
973 :
974 : imc->imcID = j;
975 :
976 : wpa_unicode2ascii_inplace(name);
977 : imc->name = os_strdup((char *) name);
978 : imc->path = os_strdup((char *) val);
979 :
980 : os_free(val);
981 :
982 : if (last == NULL)
983 : tncc->imc = imc;
984 : else
985 : last->next = imc;
986 : last = imc;
987 :
988 : tnc_imc[imc->imcID] = imc;
989 : }
990 :
991 : RegCloseKey(hk);
992 :
993 : return 0;
994 : }
995 :
996 :
997 : static int tncc_read_config(struct tncc_data *tncc)
998 : {
999 : if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
1000 : tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
1001 : return -1;
1002 : return 0;
1003 : }
1004 :
1005 : #else /* CONFIG_NATIVE_WINDOWS */
1006 :
1007 85 : static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
1008 : {
1009 : struct tnc_if_imc *imc;
1010 : char *pos, *pos2;
1011 : int i;
1012 :
1013 127 : for (i = 0; i < TNC_MAX_IMC_ID; i++) {
1014 127 : if (tnc_imc[i] == NULL)
1015 85 : break;
1016 : }
1017 85 : if (i >= TNC_MAX_IMC_ID) {
1018 0 : wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1019 0 : return NULL;
1020 : }
1021 :
1022 85 : imc = os_zalloc(sizeof(*imc));
1023 85 : if (imc == NULL) {
1024 1 : *error = 1;
1025 1 : return NULL;
1026 : }
1027 :
1028 84 : imc->imcID = i;
1029 :
1030 84 : pos = start;
1031 84 : wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
1032 84 : if (pos + 1 >= end || *pos != '"') {
1033 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1034 : "(no starting quotation mark)", start);
1035 0 : os_free(imc);
1036 0 : return NULL;
1037 : }
1038 :
1039 84 : pos++;
1040 84 : pos2 = pos;
1041 1050 : while (pos2 < end && *pos2 != '"')
1042 882 : pos2++;
1043 84 : if (pos2 >= end) {
1044 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1045 : "(no ending quotation mark)", start);
1046 0 : os_free(imc);
1047 0 : return NULL;
1048 : }
1049 84 : *pos2 = '\0';
1050 84 : wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1051 84 : imc->name = os_strdup(pos);
1052 :
1053 84 : pos = pos2 + 1;
1054 84 : if (pos >= end || *pos != ' ') {
1055 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1056 : "(no space after name)", start);
1057 0 : os_free(imc->name);
1058 0 : os_free(imc);
1059 0 : return NULL;
1060 : }
1061 :
1062 84 : pos++;
1063 84 : wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
1064 84 : imc->path = os_strdup(pos);
1065 84 : tnc_imc[imc->imcID] = imc;
1066 :
1067 84 : return imc;
1068 : }
1069 :
1070 :
1071 44 : static int tncc_read_config(struct tncc_data *tncc)
1072 : {
1073 : char *config, *end, *pos, *line_end;
1074 : size_t config_len;
1075 : struct tnc_if_imc *imc, *last;
1076 :
1077 44 : last = NULL;
1078 :
1079 44 : config = os_readfile(TNC_CONFIG_FILE, &config_len);
1080 44 : if (config == NULL) {
1081 1 : wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1082 : "file '%s'", TNC_CONFIG_FILE);
1083 1 : return -1;
1084 : }
1085 :
1086 43 : end = config + config_len;
1087 211 : for (pos = config; pos < end; pos = line_end + 1) {
1088 169 : line_end = pos;
1089 6759 : while (*line_end != '\n' && *line_end != '\r' &&
1090 : line_end < end)
1091 6421 : line_end++;
1092 169 : *line_end = '\0';
1093 :
1094 169 : if (os_strncmp(pos, "IMC ", 4) == 0) {
1095 85 : int error = 0;
1096 :
1097 85 : imc = tncc_parse_imc(pos + 4, line_end, &error);
1098 85 : if (error) {
1099 1 : os_free(config);
1100 1 : return -1;
1101 : }
1102 84 : if (imc) {
1103 84 : if (last == NULL)
1104 42 : tncc->imc = imc;
1105 : else
1106 42 : last->next = imc;
1107 84 : last = imc;
1108 : }
1109 : }
1110 : }
1111 :
1112 42 : os_free(config);
1113 :
1114 42 : return 0;
1115 : }
1116 :
1117 : #endif /* CONFIG_NATIVE_WINDOWS */
1118 :
1119 :
1120 46 : struct tncc_data * tncc_init(void)
1121 : {
1122 : struct tncc_data *tncc;
1123 : struct tnc_if_imc *imc;
1124 :
1125 46 : tncc = os_zalloc(sizeof(*tncc));
1126 46 : if (tncc == NULL)
1127 2 : return NULL;
1128 :
1129 : /* TODO:
1130 : * move loading and Initialize() to a location that is not
1131 : * re-initialized for every EAP-TNC session (?)
1132 : */
1133 :
1134 44 : if (tncc_read_config(tncc) < 0) {
1135 2 : wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1136 2 : goto failed;
1137 : }
1138 :
1139 123 : for (imc = tncc->imc; imc; imc = imc->next) {
1140 83 : if (tncc_load_imc(imc)) {
1141 2 : wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
1142 : imc->name);
1143 2 : goto failed;
1144 : }
1145 : }
1146 :
1147 40 : return tncc;
1148 :
1149 : failed:
1150 4 : tncc_deinit(tncc);
1151 4 : return NULL;
1152 : }
1153 :
1154 :
1155 44 : void tncc_deinit(struct tncc_data *tncc)
1156 : {
1157 : struct tnc_if_imc *imc, *prev;
1158 :
1159 44 : imc = tncc->imc;
1160 172 : while (imc) {
1161 84 : tncc_unload_imc(imc);
1162 :
1163 84 : prev = imc;
1164 84 : imc = imc->next;
1165 84 : os_free(prev);
1166 : }
1167 :
1168 44 : os_free(tncc);
1169 44 : }
1170 :
1171 :
1172 6 : static struct wpabuf * tncc_build_soh(int ver)
1173 : {
1174 : struct wpabuf *buf;
1175 : u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
1176 : u8 correlation_id[24];
1177 : /* TODO: get correct name */
1178 6 : char *machinename = "wpa_supplicant@w1.fi";
1179 :
1180 6 : if (os_get_random(correlation_id, sizeof(correlation_id)))
1181 1 : return NULL;
1182 5 : wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
1183 : correlation_id, sizeof(correlation_id));
1184 :
1185 5 : buf = wpabuf_alloc(200);
1186 5 : if (buf == NULL)
1187 1 : return NULL;
1188 :
1189 : /* Vendor-Specific TLV (Microsoft) - SoH */
1190 4 : wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1191 4 : tlv_len = wpabuf_put(buf, 2); /* Length */
1192 4 : wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1193 4 : wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
1194 4 : tlv_len2 = wpabuf_put(buf, 2); /* Length */
1195 :
1196 : /* SoH Header */
1197 4 : wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
1198 4 : outer_len = wpabuf_put(buf, 2);
1199 4 : wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1200 4 : wpabuf_put_be16(buf, ver); /* Inner Type */
1201 4 : inner_len = wpabuf_put(buf, 2);
1202 :
1203 4 : if (ver == 2) {
1204 : /* SoH Mode Sub-Header */
1205 : /* Outer Type */
1206 4 : wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1207 4 : wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
1208 4 : wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1209 : /* Value: */
1210 4 : wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1211 4 : wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
1212 4 : wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
1213 : }
1214 :
1215 : /* SSoH TLV */
1216 : /* System-Health-Id */
1217 4 : wpabuf_put_be16(buf, 0x0002); /* Type */
1218 4 : wpabuf_put_be16(buf, 4); /* Length */
1219 4 : wpabuf_put_be32(buf, 79616);
1220 : /* Vendor-Specific Attribute */
1221 4 : wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1222 4 : ssoh_len = wpabuf_put(buf, 2);
1223 4 : wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1224 :
1225 : /* MS-Packet-Info */
1226 4 : wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
1227 : /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
1228 : * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
1229 : * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
1230 : * would not be in the specified location.
1231 : * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
1232 : */
1233 4 : wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
1234 :
1235 : /* MS-Machine-Inventory */
1236 : /* TODO: get correct values; 0 = not applicable for OS */
1237 4 : wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
1238 4 : wpabuf_put_be32(buf, 0); /* osVersionMajor */
1239 4 : wpabuf_put_be32(buf, 0); /* osVersionMinor */
1240 4 : wpabuf_put_be32(buf, 0); /* osVersionBuild */
1241 4 : wpabuf_put_be16(buf, 0); /* spVersionMajor */
1242 4 : wpabuf_put_be16(buf, 0); /* spVersionMinor */
1243 4 : wpabuf_put_be16(buf, 0); /* procArch */
1244 :
1245 : /* MS-MachineName */
1246 4 : wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
1247 4 : wpabuf_put_be16(buf, os_strlen(machinename) + 1);
1248 4 : wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
1249 :
1250 : /* MS-CorrelationId */
1251 4 : wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
1252 4 : wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1253 :
1254 : /* MS-Quarantine-State */
1255 4 : wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
1256 4 : wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
1257 4 : wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
1258 4 : wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
1259 4 : wpabuf_put_be16(buf, 1); /* urlLenInBytes */
1260 4 : wpabuf_put_u8(buf, 0); /* null termination for the url */
1261 :
1262 : /* MS-Machine-Inventory-Ex */
1263 4 : wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
1264 4 : wpabuf_put_be32(buf, 0); /* Reserved
1265 : * (note: Windows XP SP3 uses 0xdecafbad) */
1266 4 : wpabuf_put_u8(buf, 1); /* ProductType: Client */
1267 :
1268 : /* Update SSoH Length */
1269 4 : end = wpabuf_put(buf, 0);
1270 4 : WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
1271 :
1272 : /* TODO: SoHReportEntry TLV (zero or more) */
1273 :
1274 : /* Update length fields */
1275 4 : end = wpabuf_put(buf, 0);
1276 4 : WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
1277 4 : WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
1278 4 : WPA_PUT_BE16(outer_len, end - outer_len - 2);
1279 4 : WPA_PUT_BE16(inner_len, end - inner_len - 2);
1280 :
1281 4 : return buf;
1282 : }
1283 :
1284 :
1285 6 : struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
1286 : {
1287 : const u8 *pos;
1288 :
1289 6 : wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
1290 :
1291 6 : if (len < 12)
1292 0 : return NULL;
1293 :
1294 : /* SoH Request */
1295 6 : pos = data;
1296 :
1297 : /* TLV Type */
1298 6 : if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
1299 0 : return NULL;
1300 6 : pos += 2;
1301 :
1302 : /* Length */
1303 6 : if (WPA_GET_BE16(pos) < 8)
1304 0 : return NULL;
1305 6 : pos += 2;
1306 :
1307 : /* Vendor_Id */
1308 6 : if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
1309 0 : return NULL;
1310 6 : pos += 4;
1311 :
1312 : /* TLV Type */
1313 6 : if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
1314 0 : return NULL;
1315 :
1316 6 : wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
1317 :
1318 6 : return tncc_build_soh(2);
1319 : }
|