tncc.c 30 KB

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