tncc.c
Go to the documentation of this file.
00001 /*
00002  * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
00003  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 #ifndef CONFIG_NATIVE_WINDOWS
00017 #include <dlfcn.h>
00018 #endif /* CONFIG_NATIVE_WINDOWS */
00019 
00020 #include "common.h"
00021 #include "base64.h"
00022 #include "tncc.h"
00023 #include "eap_common/eap_tlv_common.h"
00024 #include "eap_common/eap_defs.h"
00025 
00026 
00027 #ifdef UNICODE
00028 #define TSTR "%S"
00029 #else /* UNICODE */
00030 #define TSTR "%s"
00031 #endif /* UNICODE */
00032 
00033 
00034 #define TNC_CONFIG_FILE "/etc/tnc_config"
00035 #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
00036 #define IF_TNCCS_START \
00037 "<?xml version=\"1.0\"?>\n" \
00038 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
00039 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
00040 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
00041 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
00042 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
00043 #define IF_TNCCS_END "\n</TNCCS-Batch>"
00044 
00045 /* TNC IF-IMC */
00046 
00047 typedef unsigned long TNC_UInt32;
00048 typedef unsigned char *TNC_BufferReference;
00049 
00050 typedef TNC_UInt32 TNC_IMCID;
00051 typedef TNC_UInt32 TNC_ConnectionID;
00052 typedef TNC_UInt32 TNC_ConnectionState;
00053 typedef TNC_UInt32 TNC_RetryReason;
00054 typedef TNC_UInt32 TNC_MessageType;
00055 typedef TNC_MessageType *TNC_MessageTypeList;
00056 typedef TNC_UInt32 TNC_VendorID;
00057 typedef TNC_UInt32 TNC_MessageSubtype;
00058 typedef TNC_UInt32 TNC_Version;
00059 typedef TNC_UInt32 TNC_Result;
00060 
00061 typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
00062         TNC_IMCID imcID,
00063         char *functionName,
00064         void **pOutfunctionPointer);
00065 
00066 #define TNC_RESULT_SUCCESS 0
00067 #define TNC_RESULT_NOT_INITIALIZED 1
00068 #define TNC_RESULT_ALREADY_INITIALIZED 2
00069 #define TNC_RESULT_NO_COMMON_VERSION 3
00070 #define TNC_RESULT_CANT_RETRY 4
00071 #define TNC_RESULT_WONT_RETRY 5
00072 #define TNC_RESULT_INVALID_PARAMETER 6
00073 #define TNC_RESULT_CANT_RESPOND 7
00074 #define TNC_RESULT_ILLEGAL_OPERATION 8
00075 #define TNC_RESULT_OTHER 9
00076 #define TNC_RESULT_FATAL 10
00077 
00078 #define TNC_CONNECTION_STATE_CREATE 0
00079 #define TNC_CONNECTION_STATE_HANDSHAKE 1
00080 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
00081 #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
00082 #define TNC_CONNECTION_STATE_ACCESS_NONE 4
00083 #define TNC_CONNECTION_STATE_DELETE 5
00084 
00085 #define TNC_IFIMC_VERSION_1 1
00086 
00087 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
00088 #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
00089 
00090 /* TNCC-TNCS Message Types */
00091 #define TNC_TNCCS_RECOMMENDATION                0x00000001
00092 #define TNC_TNCCS_ERROR                         0x00000002
00093 #define TNC_TNCCS_PREFERREDLANGUAGE             0x00000003
00094 #define TNC_TNCCS_REASONSTRINGS                 0x00000004
00095 
00096 
00097 /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
00098 enum {
00099         SSOH_MS_MACHINE_INVENTORY = 1,
00100         SSOH_MS_QUARANTINE_STATE = 2,
00101         SSOH_MS_PACKET_INFO = 3,
00102         SSOH_MS_SYSTEMGENERATED_IDS = 4,
00103         SSOH_MS_MACHINENAME = 5,
00104         SSOH_MS_CORRELATIONID = 6,
00105         SSOH_MS_INSTALLED_SHVS = 7,
00106         SSOH_MS_MACHINE_INVENTORY_EX = 8
00107 };
00108 
00109 struct tnc_if_imc {
00110         struct tnc_if_imc *next;
00111         char *name;
00112         char *path;
00113         void *dlhandle; /* from dlopen() */
00114         TNC_IMCID imcID;
00115         TNC_ConnectionID connectionID;
00116         TNC_MessageTypeList supported_types;
00117         size_t num_supported_types;
00118         u8 *imc_send;
00119         size_t imc_send_len;
00120 
00121         /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
00122         TNC_Result (*Initialize)(
00123                 TNC_IMCID imcID,
00124                 TNC_Version minVersion,
00125                 TNC_Version maxVersion,
00126                 TNC_Version *pOutActualVersion);
00127         TNC_Result (*NotifyConnectionChange)(
00128                 TNC_IMCID imcID,
00129                 TNC_ConnectionID connectionID,
00130                 TNC_ConnectionState newState);
00131         TNC_Result (*BeginHandshake)(
00132                 TNC_IMCID imcID,
00133                 TNC_ConnectionID connectionID);
00134         TNC_Result (*ReceiveMessage)(
00135                 TNC_IMCID imcID,
00136                 TNC_ConnectionID connectionID,
00137                 TNC_BufferReference messageBuffer,
00138                 TNC_UInt32 messageLength,
00139                 TNC_MessageType messageType);
00140         TNC_Result (*BatchEnding)(
00141                 TNC_IMCID imcID,
00142                 TNC_ConnectionID connectionID);
00143         TNC_Result (*Terminate)(TNC_IMCID imcID);
00144         TNC_Result (*ProvideBindFunction)(
00145                 TNC_IMCID imcID,
00146                 TNC_TNCC_BindFunctionPointer bindFunction);
00147 };
00148 
00149 struct tncc_data {
00150         struct tnc_if_imc *imc;
00151         unsigned int last_batchid;
00152 };
00153 
00154 #define TNC_MAX_IMC_ID 10
00155 static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
00156 
00157 
00158 /* TNCC functions that IMCs can call */
00159 
00160 TNC_Result TNC_TNCC_ReportMessageTypes(
00161         TNC_IMCID imcID,
00162         TNC_MessageTypeList supportedTypes,
00163         TNC_UInt32 typeCount)
00164 {
00165         TNC_UInt32 i;
00166         struct tnc_if_imc *imc;
00167 
00168         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
00169                    "typeCount=%lu)",
00170                    (unsigned long) imcID, (unsigned long) typeCount);
00171 
00172         for (i = 0; i < typeCount; i++) {
00173                 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
00174                            i, supportedTypes[i]);
00175         }
00176 
00177         if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
00178                 return TNC_RESULT_INVALID_PARAMETER;
00179 
00180         imc = tnc_imc[imcID];
00181         os_free(imc->supported_types);
00182         imc->supported_types =
00183                 os_malloc(typeCount * sizeof(TNC_MessageTypeList));
00184         if (imc->supported_types == NULL)
00185                 return TNC_RESULT_FATAL;
00186         os_memcpy(imc->supported_types, supportedTypes,
00187                   typeCount * sizeof(TNC_MessageTypeList));
00188         imc->num_supported_types = typeCount;
00189 
00190         return TNC_RESULT_SUCCESS;
00191 }
00192 
00193 
00194 TNC_Result TNC_TNCC_SendMessage(
00195         TNC_IMCID imcID,
00196         TNC_ConnectionID connectionID,
00197         TNC_BufferReference message,
00198         TNC_UInt32 messageLength,
00199         TNC_MessageType messageType)
00200 {
00201         struct tnc_if_imc *imc;
00202         unsigned char *b64;
00203         size_t b64len;
00204 
00205         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
00206                    "connectionID=%lu messageType=%lu)",
00207                    imcID, connectionID, messageType);
00208         wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
00209                           message, messageLength);
00210 
00211         if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
00212                 return TNC_RESULT_INVALID_PARAMETER;
00213 
00214         b64 = base64_encode(message, messageLength, &b64len);
00215         if (b64 == NULL)
00216                 return TNC_RESULT_FATAL;
00217 
00218         imc = tnc_imc[imcID];
00219         os_free(imc->imc_send);
00220         imc->imc_send_len = 0;
00221         imc->imc_send = os_zalloc(b64len + 100);
00222         if (imc->imc_send == NULL) {
00223                 os_free(b64);
00224                 return TNC_RESULT_OTHER;
00225         }
00226 
00227         imc->imc_send_len =
00228                 os_snprintf((char *) imc->imc_send, b64len + 100,
00229                             "<IMC-IMV-Message><Type>%08X</Type>"
00230                             "<Base64>%s</Base64></IMC-IMV-Message>",
00231                             (unsigned int) messageType, b64);
00232 
00233         os_free(b64);
00234 
00235         return TNC_RESULT_SUCCESS;
00236 }
00237 
00238 
00239 TNC_Result TNC_TNCC_RequestHandshakeRetry(
00240         TNC_IMCID imcID,
00241         TNC_ConnectionID connectionID,
00242         TNC_RetryReason reason)
00243 {
00244         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
00245 
00246         if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
00247                 return TNC_RESULT_INVALID_PARAMETER;
00248 
00249         /*
00250          * TODO: trigger a call to eapol_sm_request_reauth(). This would
00251          * require that the IMC continues to be loaded in memory afer
00252          * authentication..
00253          */
00254 
00255         return TNC_RESULT_SUCCESS;
00256 }
00257 
00258 
00259 TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
00260                                const char *message)
00261 {
00262         wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
00263                    "severity==%lu message='%s')",
00264                    imcID, severity, message);
00265         return TNC_RESULT_SUCCESS;
00266 }
00267 
00268 
00269 TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
00270                                 const char *message)
00271 {
00272         wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
00273                    "connectionID==%lu message='%s')",
00274                    imcID, connectionID, message);
00275         return TNC_RESULT_SUCCESS;
00276 }
00277 
00278 
00279 TNC_Result TNC_TNCC_BindFunction(
00280         TNC_IMCID imcID,
00281         char *functionName,
00282         void **pOutfunctionPointer)
00283 {
00284         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
00285                    "functionName='%s')", (unsigned long) imcID, functionName);
00286 
00287         if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
00288                 return TNC_RESULT_INVALID_PARAMETER;
00289 
00290         if (pOutfunctionPointer == NULL)
00291                 return TNC_RESULT_INVALID_PARAMETER;
00292 
00293         if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
00294                 *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
00295         else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
00296                 *pOutfunctionPointer = TNC_TNCC_SendMessage;
00297         else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
00298                  0)
00299                 *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
00300         else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
00301                 *pOutfunctionPointer = TNC_9048_LogMessage;
00302         else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
00303                 *pOutfunctionPointer = TNC_9048_UserMessage;
00304         else
00305                 *pOutfunctionPointer = NULL;
00306 
00307         return TNC_RESULT_SUCCESS;
00308 }
00309 
00310 
00311 static void * tncc_get_sym(void *handle, char *func)
00312 {
00313         void *fptr;
00314 
00315 #ifdef CONFIG_NATIVE_WINDOWS
00316 #ifdef _WIN32_WCE
00317         fptr = GetProcAddressA(handle, func);
00318 #else /* _WIN32_WCE */
00319         fptr = GetProcAddress(handle, func);
00320 #endif /* _WIN32_WCE */
00321 #else /* CONFIG_NATIVE_WINDOWS */
00322         fptr = dlsym(handle, func);
00323 #endif /* CONFIG_NATIVE_WINDOWS */
00324 
00325         return fptr;
00326 }
00327 
00328 
00329 static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
00330 {
00331         void *handle = imc->dlhandle;
00332 
00333         /* Mandatory IMC functions */
00334         imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
00335         if (imc->Initialize == NULL) {
00336                 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
00337                            "TNC_IMC_Initialize");
00338                 return -1;
00339         }
00340 
00341         imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
00342         if (imc->BeginHandshake == NULL) {
00343                 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
00344                            "TNC_IMC_BeginHandshake");
00345                 return -1;
00346         }
00347 
00348         imc->ProvideBindFunction =
00349                 tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
00350         if (imc->ProvideBindFunction == NULL) {
00351                 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
00352                            "TNC_IMC_ProvideBindFunction");
00353                 return -1;
00354         }
00355 
00356         /* Optional IMC functions */
00357         imc->NotifyConnectionChange =
00358                 tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
00359         imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
00360         imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
00361         imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
00362 
00363         return 0;
00364 }
00365 
00366 
00367 static int tncc_imc_initialize(struct tnc_if_imc *imc)
00368 {
00369         TNC_Result res;
00370         TNC_Version imc_ver;
00371 
00372         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
00373                    imc->name);
00374         res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
00375                               TNC_IFIMC_VERSION_1, &imc_ver);
00376         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
00377                    (unsigned long) res, (unsigned long) imc_ver);
00378 
00379         return res == TNC_RESULT_SUCCESS ? 0 : -1;
00380 }
00381 
00382 
00383 static int tncc_imc_terminate(struct tnc_if_imc *imc)
00384 {
00385         TNC_Result res;
00386 
00387         if (imc->Terminate == NULL)
00388                 return 0;
00389 
00390         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
00391                    imc->name);
00392         res = imc->Terminate(imc->imcID);
00393         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
00394                    (unsigned long) res);
00395 
00396         return res == TNC_RESULT_SUCCESS ? 0 : -1;
00397 }
00398 
00399 
00400 static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
00401 {
00402         TNC_Result res;
00403 
00404         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
00405                    "IMC '%s'", imc->name);
00406         res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
00407         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
00408                    (unsigned long) res);
00409 
00410         return res == TNC_RESULT_SUCCESS ? 0 : -1;
00411 }
00412 
00413 
00414 static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
00415                                              TNC_ConnectionState state)
00416 {
00417         TNC_Result res;
00418 
00419         if (imc->NotifyConnectionChange == NULL)
00420                 return 0;
00421 
00422         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
00423                    " for IMC '%s'", (int) state, imc->name);
00424         res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
00425                                           state);
00426         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
00427                    (unsigned long) res);
00428 
00429         return res == TNC_RESULT_SUCCESS ? 0 : -1;
00430 }
00431 
00432 
00433 static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
00434 {
00435         TNC_Result res;
00436 
00437         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
00438                    "'%s'", imc->name);
00439         res = imc->BeginHandshake(imc->imcID, imc->connectionID);
00440         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
00441                    (unsigned long) res);
00442 
00443         return res == TNC_RESULT_SUCCESS ? 0 : -1;
00444 }
00445 
00446 
00447 static int tncc_load_imc(struct tnc_if_imc *imc)
00448 {
00449         if (imc->path == NULL) {
00450                 wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
00451                 return -1;
00452         }
00453 
00454         wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
00455                    imc->name, imc->path);
00456 #ifdef CONFIG_NATIVE_WINDOWS
00457 #ifdef UNICODE
00458         {
00459                 TCHAR *lib = wpa_strdup_tchar(imc->path);
00460                 if (lib == NULL)
00461                         return -1;
00462                 imc->dlhandle = LoadLibrary(lib);
00463                 os_free(lib);
00464         }
00465 #else /* UNICODE */
00466         imc->dlhandle = LoadLibrary(imc->path);
00467 #endif /* UNICODE */
00468         if (imc->dlhandle == NULL) {
00469                 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
00470                            imc->name, imc->path, (int) GetLastError());
00471                 return -1;
00472         }
00473 #else /* CONFIG_NATIVE_WINDOWS */
00474         imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
00475         if (imc->dlhandle == NULL) {
00476                 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
00477                            imc->name, imc->path, dlerror());
00478                 return -1;
00479         }
00480 #endif /* CONFIG_NATIVE_WINDOWS */
00481 
00482         if (tncc_imc_resolve_funcs(imc) < 0) {
00483                 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
00484                 return -1;
00485         }
00486 
00487         if (tncc_imc_initialize(imc) < 0 ||
00488             tncc_imc_provide_bind_function(imc) < 0) {
00489                 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
00490                 return -1;
00491         }
00492 
00493         return 0;
00494 }
00495 
00496 
00497 static void tncc_unload_imc(struct tnc_if_imc *imc)
00498 {
00499         tncc_imc_terminate(imc);
00500         tnc_imc[imc->imcID] = NULL;
00501 
00502         if (imc->dlhandle) {
00503 #ifdef CONFIG_NATIVE_WINDOWS
00504                 FreeLibrary(imc->dlhandle);
00505 #else /* CONFIG_NATIVE_WINDOWS */
00506                 dlclose(imc->dlhandle);
00507 #endif /* CONFIG_NATIVE_WINDOWS */
00508         }
00509         os_free(imc->name);
00510         os_free(imc->path);
00511         os_free(imc->supported_types);
00512         os_free(imc->imc_send);
00513 }
00514 
00515 
00516 static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
00517 {
00518         size_t i;
00519         unsigned int vendor, subtype;
00520 
00521         if (imc == NULL || imc->supported_types == NULL)
00522                 return 0;
00523 
00524         vendor = type >> 8;
00525         subtype = type & 0xff;
00526 
00527         for (i = 0; i < imc->num_supported_types; i++) {
00528                 unsigned int svendor, ssubtype;
00529                 svendor = imc->supported_types[i] >> 8;
00530                 ssubtype = imc->supported_types[i] & 0xff;
00531                 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
00532                     (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
00533                         return 1;
00534         }
00535 
00536         return 0;
00537 }
00538 
00539 
00540 static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
00541                               const u8 *msg, size_t len)
00542 {
00543         struct tnc_if_imc *imc;
00544         TNC_Result res;
00545 
00546         wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
00547 
00548         for (imc = tncc->imc; imc; imc = imc->next) {
00549                 if (imc->ReceiveMessage == NULL ||
00550                     !tncc_supported_type(imc, type))
00551                         continue;
00552 
00553                 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
00554                            imc->name);
00555                 res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
00556                                           (TNC_BufferReference) msg, len,
00557                                           type);
00558                 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
00559                            (unsigned long) res);
00560         }
00561 }
00562 
00563 
00564 void tncc_init_connection(struct tncc_data *tncc)
00565 {
00566         struct tnc_if_imc *imc;
00567 
00568         for (imc = tncc->imc; imc; imc = imc->next) {
00569                 tncc_imc_notify_connection_change(
00570                         imc, TNC_CONNECTION_STATE_CREATE);
00571                 tncc_imc_notify_connection_change(
00572                         imc, TNC_CONNECTION_STATE_HANDSHAKE);
00573 
00574                 os_free(imc->imc_send);
00575                 imc->imc_send = NULL;
00576                 imc->imc_send_len = 0;
00577 
00578                 tncc_imc_begin_handshake(imc);
00579         }
00580 }
00581 
00582 
00583 size_t tncc_total_send_len(struct tncc_data *tncc)
00584 {
00585         struct tnc_if_imc *imc;
00586 
00587         size_t len = 0;
00588         for (imc = tncc->imc; imc; imc = imc->next)
00589                 len += imc->imc_send_len;
00590         return len;
00591 }
00592 
00593 
00594 u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
00595 {
00596         struct tnc_if_imc *imc;
00597 
00598         for (imc = tncc->imc; imc; imc = imc->next) {
00599                 if (imc->imc_send == NULL)
00600                         continue;
00601 
00602                 os_memcpy(pos, imc->imc_send, imc->imc_send_len);
00603                 pos += imc->imc_send_len;
00604                 os_free(imc->imc_send);
00605                 imc->imc_send = NULL;
00606                 imc->imc_send_len = 0;
00607         }
00608 
00609         return pos;
00610 }
00611 
00612 
00613 char * tncc_if_tnccs_start(struct tncc_data *tncc)
00614 {
00615         char *buf = os_malloc(1000);
00616         if (buf == NULL)
00617                 return NULL;
00618         tncc->last_batchid++;
00619         os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
00620         return buf;
00621 }
00622 
00623 
00624 char * tncc_if_tnccs_end(void)
00625 {
00626         char *buf = os_malloc(100);
00627         if (buf == NULL)
00628                 return NULL;
00629         os_snprintf(buf, 100, IF_TNCCS_END);
00630         return buf;
00631 }
00632 
00633 
00634 static void tncc_notify_recommendation(struct tncc_data *tncc,
00635                                        enum tncc_process_res res)
00636 {
00637         TNC_ConnectionState state;
00638         struct tnc_if_imc *imc;
00639 
00640         switch (res) {
00641         case TNCCS_RECOMMENDATION_ALLOW:
00642                 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
00643                 break;
00644         case TNCCS_RECOMMENDATION_NONE:
00645                 state = TNC_CONNECTION_STATE_ACCESS_NONE;
00646                 break;
00647         case TNCCS_RECOMMENDATION_ISOLATE:
00648                 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
00649                 break;
00650         default:
00651                 state = TNC_CONNECTION_STATE_ACCESS_NONE;
00652                 break;
00653         }
00654 
00655         for (imc = tncc->imc; imc; imc = imc->next)
00656                 tncc_imc_notify_connection_change(imc, state);
00657 }
00658 
00659 
00660 static int tncc_get_type(char *start, unsigned int *type)
00661 {
00662         char *pos = os_strstr(start, "<Type>");
00663         if (pos == NULL)
00664                 return -1;
00665         pos += 6;
00666         *type = strtoul(pos, NULL, 16);
00667         return 0;
00668 }
00669 
00670 
00671 static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
00672 {
00673         char *pos, *pos2;
00674         unsigned char *decoded;
00675 
00676         pos = os_strstr(start, "<Base64>");
00677         if (pos == NULL)
00678                 return NULL;
00679 
00680         pos += 8;
00681         pos2 = os_strstr(pos, "</Base64>");
00682         if (pos2 == NULL)
00683                 return NULL;
00684         *pos2 = '\0';
00685 
00686         decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
00687                                 decoded_len);
00688         *pos2 = '<';
00689         if (decoded == NULL) {
00690                 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
00691         }
00692 
00693         return decoded;
00694 }
00695 
00696 
00697 static enum tncc_process_res tncc_get_recommendation(char *start)
00698 {
00699         char *pos, *pos2, saved;
00700         int recom;
00701 
00702         pos = os_strstr(start, "<TNCCS-Recommendation ");
00703         if (pos == NULL)
00704                 return TNCCS_RECOMMENDATION_ERROR;
00705 
00706         pos += 21;
00707         pos = os_strstr(pos, " type=");
00708         if (pos == NULL)
00709                 return TNCCS_RECOMMENDATION_ERROR;
00710         pos += 6;
00711 
00712         if (*pos == '"')
00713                 pos++;
00714 
00715         pos2 = pos;
00716         while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
00717                 pos2++;
00718 
00719         if (*pos2 == '\0')
00720                 return TNCCS_RECOMMENDATION_ERROR;
00721 
00722         saved = *pos2;
00723         *pos2 = '\0';
00724         wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
00725 
00726         recom = TNCCS_RECOMMENDATION_ERROR;
00727         if (os_strcmp(pos, "allow") == 0)
00728                 recom = TNCCS_RECOMMENDATION_ALLOW;
00729         else if (os_strcmp(pos, "none") == 0)
00730                 recom = TNCCS_RECOMMENDATION_NONE;
00731         else if (os_strcmp(pos, "isolate") == 0)
00732                 recom = TNCCS_RECOMMENDATION_ISOLATE;
00733 
00734         *pos2 = saved;
00735 
00736         return recom;
00737 }
00738 
00739 
00740 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
00741                                             const u8 *msg, size_t len)
00742 {
00743         char *buf, *start, *end, *pos, *pos2, *payload;
00744         unsigned int batch_id;
00745         unsigned char *decoded;
00746         size_t decoded_len;
00747         enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
00748         int recommendation_msg = 0;
00749 
00750         buf = os_malloc(len + 1);
00751         if (buf == NULL)
00752                 return TNCCS_PROCESS_ERROR;
00753 
00754         os_memcpy(buf, msg, len);
00755         buf[len] = '\0';
00756         start = os_strstr(buf, "<TNCCS-Batch ");
00757         end = os_strstr(buf, "</TNCCS-Batch>");
00758         if (start == NULL || end == NULL || start > end) {
00759                 os_free(buf);
00760                 return TNCCS_PROCESS_ERROR;
00761         }
00762 
00763         start += 13;
00764         while (*start == ' ')
00765                 start++;
00766         *end = '\0';
00767 
00768         pos = os_strstr(start, "BatchId=");
00769         if (pos == NULL) {
00770                 os_free(buf);
00771                 return TNCCS_PROCESS_ERROR;
00772         }
00773 
00774         pos += 8;
00775         if (*pos == '"')
00776                 pos++;
00777         batch_id = atoi(pos);
00778         wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
00779                    batch_id);
00780         if (batch_id != tncc->last_batchid + 1) {
00781                 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
00782                            "%u (expected %u)",
00783                            batch_id, tncc->last_batchid + 1);
00784                 os_free(buf);
00785                 return TNCCS_PROCESS_ERROR;
00786         }
00787         tncc->last_batchid = batch_id;
00788 
00789         while (*pos != '\0' && *pos != '>')
00790                 pos++;
00791         if (*pos == '\0') {
00792                 os_free(buf);
00793                 return TNCCS_PROCESS_ERROR;
00794         }
00795         pos++;
00796         payload = start;
00797 
00798         /*
00799          * <IMC-IMV-Message>
00800          * <Type>01234567</Type>
00801          * <Base64>foo==</Base64>
00802          * </IMC-IMV-Message>
00803          */
00804 
00805         while (*start) {
00806                 char *endpos;
00807                 unsigned int type;
00808 
00809                 pos = os_strstr(start, "<IMC-IMV-Message>");
00810                 if (pos == NULL)
00811                         break;
00812                 start = pos + 17;
00813                 end = os_strstr(start, "</IMC-IMV-Message>");
00814                 if (end == NULL)
00815                         break;
00816                 *end = '\0';
00817                 endpos = end;
00818                 end += 18;
00819 
00820                 if (tncc_get_type(start, &type) < 0) {
00821                         *endpos = '<';
00822                         start = end;
00823                         continue;
00824                 }
00825                 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
00826 
00827                 decoded = tncc_get_base64(start, &decoded_len);
00828                 if (decoded == NULL) {
00829                         *endpos = '<';
00830                         start = end;
00831                         continue;
00832                 }
00833 
00834                 tncc_send_to_imcs(tncc, type, decoded, decoded_len);
00835 
00836                 os_free(decoded);
00837 
00838                 start = end;
00839         }
00840 
00841         /*
00842          * <TNCC-TNCS-Message>
00843          * <Type>01234567</Type>
00844          * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
00845          * <Base64>foo==</Base64>
00846          * </TNCC-TNCS-Message>
00847          */
00848 
00849         start = payload;
00850         while (*start) {
00851                 unsigned int type;
00852                 char *xml, *xmlend, *endpos;
00853 
00854                 pos = os_strstr(start, "<TNCC-TNCS-Message>");
00855                 if (pos == NULL)
00856                         break;
00857                 start = pos + 19;
00858                 end = os_strstr(start, "</TNCC-TNCS-Message>");
00859                 if (end == NULL)
00860                         break;
00861                 *end = '\0';
00862                 endpos = end;
00863                 end += 20;
00864 
00865                 if (tncc_get_type(start, &type) < 0) {
00866                         *endpos = '<';
00867                         start = end;
00868                         continue;
00869                 }
00870                 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
00871                            type);
00872 
00873                 /* Base64 OR XML */
00874                 decoded = NULL;
00875                 xml = NULL;
00876                 xmlend = NULL;
00877                 pos = os_strstr(start, "<XML>");
00878                 if (pos) {
00879                         pos += 5;
00880                         pos2 = os_strstr(pos, "</XML>");
00881                         if (pos2 == NULL) {
00882                                 *endpos = '<';
00883                                 start = end;
00884                                 continue;
00885                         }
00886                         xmlend = pos2;
00887                         xml = pos;
00888                 } else {
00889                         decoded = tncc_get_base64(start, &decoded_len);
00890                         if (decoded == NULL) {
00891                                 *endpos = '<';
00892                                 start = end;
00893                                 continue;
00894                         }
00895                 }
00896 
00897                 if (decoded) {
00898                         wpa_hexdump_ascii(MSG_MSGDUMP,
00899                                           "TNC: TNCC-TNCS-Message Base64",
00900                                           decoded, decoded_len);
00901                         os_free(decoded);
00902                 }
00903 
00904                 if (xml) {
00905                         wpa_hexdump_ascii(MSG_MSGDUMP,
00906                                           "TNC: TNCC-TNCS-Message XML",
00907                                           (unsigned char *) xml,
00908                                           xmlend - xml);
00909                 }
00910 
00911                 if (type == TNC_TNCCS_RECOMMENDATION && xml) {
00912                         /*
00913                          * <TNCCS-Recommendation type="allow">
00914                          * </TNCCS-Recommendation>
00915                          */
00916                         *xmlend = '\0';
00917                         res = tncc_get_recommendation(xml);
00918                         *xmlend = '<';
00919                         recommendation_msg = 1;
00920                 }
00921 
00922                 start = end;
00923         }
00924 
00925         os_free(buf);
00926 
00927         if (recommendation_msg)
00928                 tncc_notify_recommendation(tncc, res);
00929 
00930         return res;
00931 }
00932 
00933 
00934 #ifdef CONFIG_NATIVE_WINDOWS
00935 static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
00936 {
00937         HKEY hk, hk2;
00938         LONG ret;
00939         DWORD i;
00940         struct tnc_if_imc *imc, *last;
00941         int j;
00942 
00943         last = tncc->imc;
00944         while (last && last->next)
00945                 last = last->next;
00946 
00947         ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
00948                            &hk);
00949         if (ret != ERROR_SUCCESS)
00950                 return 0;
00951 
00952         for (i = 0; ; i++) {
00953                 TCHAR name[255], *val;
00954                 DWORD namelen, buflen;
00955 
00956                 namelen = 255;
00957                 ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
00958                                    NULL);
00959 
00960                 if (ret == ERROR_NO_MORE_ITEMS)
00961                         break;
00962 
00963                 if (ret != ERROR_SUCCESS) {
00964                         wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
00965                                    (unsigned int) ret);
00966                         break;
00967                 }
00968 
00969                 if (namelen >= 255)
00970                         namelen = 255 - 1;
00971                 name[namelen] = '\0';
00972 
00973                 wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
00974 
00975                 ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
00976                 if (ret != ERROR_SUCCESS) {
00977                         wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
00978                                    "'", name);
00979                         continue;
00980                 }
00981 
00982                 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
00983                                       &buflen);
00984                 if (ret != ERROR_SUCCESS) {
00985                         wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
00986                                    "IMC key '" TSTR "'", name);
00987                         RegCloseKey(hk2);
00988                         continue;
00989                 }
00990 
00991                 val = os_malloc(buflen);
00992                 if (val == NULL) {
00993                         RegCloseKey(hk2);
00994                         continue;
00995                 }
00996 
00997                 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
00998                                       (LPBYTE) val, &buflen);
00999                 if (ret != ERROR_SUCCESS) {
01000                         os_free(val);
01001                         RegCloseKey(hk2);
01002                         continue;
01003                 }
01004 
01005                 RegCloseKey(hk2);
01006 
01007                 wpa_unicode2ascii_inplace(val);
01008                 wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
01009 
01010                 for (j = 0; j < TNC_MAX_IMC_ID; j++) {
01011                         if (tnc_imc[j] == NULL)
01012                                 break;
01013                 }
01014                 if (j >= TNC_MAX_IMC_ID) {
01015                         wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
01016                         os_free(val);
01017                         continue;
01018                 }
01019 
01020                 imc = os_zalloc(sizeof(*imc));
01021                 if (imc == NULL) {
01022                         os_free(val);
01023                         break;
01024                 }
01025 
01026                 imc->imcID = j;
01027 
01028                 wpa_unicode2ascii_inplace(name);
01029                 imc->name = os_strdup((char *) name);
01030                 imc->path = os_strdup((char *) val);
01031 
01032                 os_free(val);
01033 
01034                 if (last == NULL)
01035                         tncc->imc = imc;
01036                 else
01037                         last->next = imc;
01038                 last = imc;
01039 
01040                 tnc_imc[imc->imcID] = imc;
01041         }
01042 
01043         RegCloseKey(hk);
01044 
01045         return 0;
01046 }
01047 
01048 
01049 static int tncc_read_config(struct tncc_data *tncc)
01050 {
01051         if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
01052             tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
01053                 return -1;
01054         return 0;
01055 }
01056 
01057 #else /* CONFIG_NATIVE_WINDOWS */
01058 
01059 static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
01060 {
01061         struct tnc_if_imc *imc;
01062         char *pos, *pos2;
01063         int i;
01064 
01065         for (i = 0; i < TNC_MAX_IMC_ID; i++) {
01066                 if (tnc_imc[i] == NULL)
01067                         break;
01068         }
01069         if (i >= TNC_MAX_IMC_ID) {
01070                 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
01071                 return NULL;
01072         }
01073 
01074         imc = os_zalloc(sizeof(*imc));
01075         if (imc == NULL) {
01076                 *error = 1;
01077                 return NULL;
01078         }
01079 
01080         imc->imcID = i;
01081 
01082         pos = start;
01083         wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
01084         if (pos + 1 >= end || *pos != '"') {
01085                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
01086                            "(no starting quotation mark)", start);
01087                 os_free(imc);
01088                 return NULL;
01089         }
01090 
01091         pos++;
01092         pos2 = pos;
01093         while (pos2 < end && *pos2 != '"')
01094                 pos2++;
01095         if (pos2 >= end) {
01096                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
01097                            "(no ending quotation mark)", start);
01098                 os_free(imc);
01099                 return NULL;
01100         }
01101         *pos2 = '\0';
01102         wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
01103         imc->name = os_strdup(pos);
01104 
01105         pos = pos2 + 1;
01106         if (pos >= end || *pos != ' ') {
01107                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
01108                            "(no space after name)", start);
01109                 os_free(imc->name);
01110                 os_free(imc);
01111                 return NULL;
01112         }
01113 
01114         pos++;
01115         wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
01116         imc->path = os_strdup(pos);
01117         tnc_imc[imc->imcID] = imc;
01118 
01119         return imc;
01120 }
01121 
01122 
01123 static int tncc_read_config(struct tncc_data *tncc)
01124 {
01125         char *config, *end, *pos, *line_end;
01126         size_t config_len;
01127         struct tnc_if_imc *imc, *last;
01128 
01129         last = NULL;
01130 
01131         config = os_readfile(TNC_CONFIG_FILE, &config_len);
01132         if (config == NULL) {
01133                 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
01134                            "file '%s'", TNC_CONFIG_FILE);
01135                 return -1;
01136         }
01137 
01138         end = config + config_len;
01139         for (pos = config; pos < end; pos = line_end + 1) {
01140                 line_end = pos;
01141                 while (*line_end != '\n' && *line_end != '\r' &&
01142                        line_end < end)
01143                         line_end++;
01144                 *line_end = '\0';
01145 
01146                 if (os_strncmp(pos, "IMC ", 4) == 0) {
01147                         int error = 0;
01148 
01149                         imc = tncc_parse_imc(pos + 4, line_end, &error);
01150                         if (error)
01151                                 return -1;
01152                         if (imc) {
01153                                 if (last == NULL)
01154                                         tncc->imc = imc;
01155                                 else
01156                                         last->next = imc;
01157                                 last = imc;
01158                         }
01159                 }
01160         }
01161 
01162         os_free(config);
01163 
01164         return 0;
01165 }
01166 
01167 #endif /* CONFIG_NATIVE_WINDOWS */
01168 
01169 
01170 struct tncc_data * tncc_init(void)
01171 {
01172         struct tncc_data *tncc;
01173         struct tnc_if_imc *imc;
01174 
01175         tncc = os_zalloc(sizeof(*tncc));
01176         if (tncc == NULL)
01177                 return NULL;
01178 
01179         /* TODO:
01180          * move loading and Initialize() to a location that is not
01181          *    re-initialized for every EAP-TNC session (?)
01182          */
01183 
01184         if (tncc_read_config(tncc) < 0) {
01185                 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
01186                 goto failed;
01187         }
01188 
01189         for (imc = tncc->imc; imc; imc = imc->next) {
01190                 if (tncc_load_imc(imc)) {
01191                         wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
01192                                    imc->name);
01193                         goto failed;
01194                 }
01195         }
01196 
01197         return tncc;
01198 
01199 failed:
01200         tncc_deinit(tncc);
01201         return NULL;
01202 }
01203 
01204 
01205 void tncc_deinit(struct tncc_data *tncc)
01206 {
01207         struct tnc_if_imc *imc, *prev;
01208 
01209         imc = tncc->imc;
01210         while (imc) {
01211                 tncc_unload_imc(imc);
01212 
01213                 prev = imc;
01214                 imc = imc->next;
01215                 os_free(prev);
01216         }
01217 
01218         os_free(tncc);
01219 }
01220 
01221 
01222 static struct wpabuf * tncc_build_soh(int ver)
01223 {
01224         struct wpabuf *buf;
01225         u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
01226         u8 correlation_id[24];
01227         /* TODO: get correct name */
01228         char *machinename = "wpa_supplicant@w1.fi";
01229 
01230         if (os_get_random(correlation_id, sizeof(correlation_id)))
01231                 return NULL;
01232         wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
01233                     correlation_id, sizeof(correlation_id));
01234 
01235         buf = wpabuf_alloc(200);
01236         if (buf == NULL)
01237                 return NULL;
01238 
01239         /* Vendor-Specific TLV (Microsoft) - SoH */
01240         wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
01241         tlv_len = wpabuf_put(buf, 2); /* Length */
01242         wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
01243         wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
01244         tlv_len2 = wpabuf_put(buf, 2); /* Length */
01245 
01246         /* SoH Header */
01247         wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
01248         outer_len = wpabuf_put(buf, 2);
01249         wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
01250         wpabuf_put_be16(buf, ver); /* Inner Type */
01251         inner_len = wpabuf_put(buf, 2);
01252 
01253         if (ver == 2) {
01254                 /* SoH Mode Sub-Header */
01255                 /* Outer Type */
01256                 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
01257                 wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
01258                 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
01259                 /* Value: */
01260                 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
01261                 wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
01262                 wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
01263         }
01264 
01265         /* SSoH TLV */
01266         /* System-Health-Id */
01267         wpabuf_put_be16(buf, 0x0002); /* Type */
01268         wpabuf_put_be16(buf, 4); /* Length */
01269         wpabuf_put_be32(buf, 79616);
01270         /* Vendor-Specific Attribute */
01271         wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
01272         ssoh_len = wpabuf_put(buf, 2);
01273         wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
01274 
01275         /* MS-Packet-Info */
01276         wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
01277         /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
01278          * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
01279          * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
01280          * would not be in the specified location.
01281          * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
01282          */
01283         wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
01284 
01285         /* MS-Machine-Inventory */
01286         /* TODO: get correct values; 0 = not applicable for OS */
01287         wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
01288         wpabuf_put_be32(buf, 0); /* osVersionMajor */
01289         wpabuf_put_be32(buf, 0); /* osVersionMinor */
01290         wpabuf_put_be32(buf, 0); /* osVersionBuild */
01291         wpabuf_put_be16(buf, 0); /* spVersionMajor */
01292         wpabuf_put_be16(buf, 0); /* spVersionMinor */
01293         wpabuf_put_be16(buf, 0); /* procArch */
01294 
01295         /* MS-MachineName */
01296         wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
01297         wpabuf_put_be16(buf, os_strlen(machinename) + 1);
01298         wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
01299 
01300         /* MS-CorrelationId */
01301         wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
01302         wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
01303 
01304         /* MS-Quarantine-State */
01305         wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
01306         wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
01307         wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
01308         wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
01309         wpabuf_put_be16(buf, 1); /* urlLenInBytes */
01310         wpabuf_put_u8(buf, 0); /* null termination for the url */
01311 
01312         /* MS-Machine-Inventory-Ex */
01313         wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
01314         wpabuf_put_be32(buf, 0); /* Reserved
01315                                   * (note: Windows XP SP3 uses 0xdecafbad) */
01316         wpabuf_put_u8(buf, 1); /* ProductType: Client */
01317 
01318         /* Update SSoH Length */
01319         end = wpabuf_put(buf, 0);
01320         WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
01321 
01322         /* TODO: SoHReportEntry TLV (zero or more) */
01323 
01324         /* Update length fields */
01325         end = wpabuf_put(buf, 0);
01326         WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
01327         WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
01328         WPA_PUT_BE16(outer_len, end - outer_len - 2);
01329         WPA_PUT_BE16(inner_len, end - inner_len - 2);
01330 
01331         return buf;
01332 }
01333 
01334 
01335 struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
01336 {
01337         const u8 *pos;
01338 
01339         wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
01340 
01341         if (len < 12)
01342                 return NULL;
01343 
01344         /* SoH Request */
01345         pos = data;
01346 
01347         /* TLV Type */
01348         if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
01349                 return NULL;
01350         pos += 2;
01351 
01352         /* Length */
01353         if (WPA_GET_BE16(pos) < 8)
01354                 return NULL;
01355         pos += 2;
01356 
01357         /* Vendor_Id */
01358         if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
01359                 return NULL;
01360         pos += 4;
01361 
01362         /* TLV Type */
01363         if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
01364                 return NULL;
01365 
01366         wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
01367 
01368         return tncc_build_soh(2);
01369 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:36