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