tncc.c 31 KB

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