tncs.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. /*
  2. * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
  3. * Copyright (c) 2007-2008, 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. #include <dlfcn.h>
  10. #include "common.h"
  11. #include "base64.h"
  12. #include "common/tnc.h"
  13. #include "tncs.h"
  14. #include "eap_common/eap_tlv_common.h"
  15. #include "eap_common/eap_defs.h"
  16. /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
  17. * needed.. */
  18. #ifndef TNC_CONFIG_FILE
  19. #define TNC_CONFIG_FILE "/etc/tnc_config"
  20. #endif /* TNC_CONFIG_FILE */
  21. #define IF_TNCCS_START \
  22. "<?xml version=\"1.0\"?>\n" \
  23. "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
  24. "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
  25. "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
  26. "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
  27. "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
  28. #define IF_TNCCS_END "\n</TNCCS-Batch>"
  29. /* TNC IF-IMV */
  30. struct tnc_if_imv {
  31. struct tnc_if_imv *next;
  32. char *name;
  33. char *path;
  34. void *dlhandle; /* from dlopen() */
  35. TNC_IMVID imvID;
  36. TNC_MessageTypeList supported_types;
  37. size_t num_supported_types;
  38. /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
  39. TNC_Result (*Initialize)(
  40. TNC_IMVID imvID,
  41. TNC_Version minVersion,
  42. TNC_Version maxVersion,
  43. TNC_Version *pOutActualVersion);
  44. TNC_Result (*NotifyConnectionChange)(
  45. TNC_IMVID imvID,
  46. TNC_ConnectionID connectionID,
  47. TNC_ConnectionState newState);
  48. TNC_Result (*ReceiveMessage)(
  49. TNC_IMVID imvID,
  50. TNC_ConnectionID connectionID,
  51. TNC_BufferReference message,
  52. TNC_UInt32 messageLength,
  53. TNC_MessageType messageType);
  54. TNC_Result (*SolicitRecommendation)(
  55. TNC_IMVID imvID,
  56. TNC_ConnectionID connectionID);
  57. TNC_Result (*BatchEnding)(
  58. TNC_IMVID imvID,
  59. TNC_ConnectionID connectionID);
  60. TNC_Result (*Terminate)(TNC_IMVID imvID);
  61. TNC_Result (*ProvideBindFunction)(
  62. TNC_IMVID imvID,
  63. TNC_TNCS_BindFunctionPointer bindFunction);
  64. };
  65. #define TNC_MAX_IMV_ID 10
  66. struct tncs_data {
  67. struct tncs_data *next;
  68. struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
  69. TNC_ConnectionID connectionID;
  70. unsigned int last_batchid;
  71. enum IMV_Action_Recommendation recommendation;
  72. int done;
  73. struct conn_imv {
  74. u8 *imv_send;
  75. size_t imv_send_len;
  76. enum IMV_Action_Recommendation recommendation;
  77. int recommendation_set;
  78. } imv_data[TNC_MAX_IMV_ID];
  79. char *tncs_message;
  80. };
  81. struct tncs_global {
  82. struct tnc_if_imv *imv;
  83. TNC_ConnectionID next_conn_id;
  84. struct tncs_data *connections;
  85. };
  86. static struct tncs_global *tncs_global_data = NULL;
  87. static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
  88. {
  89. struct tnc_if_imv *imv;
  90. if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
  91. return NULL;
  92. imv = tncs_global_data->imv;
  93. while (imv) {
  94. if (imv->imvID == imvID)
  95. return imv;
  96. imv = imv->next;
  97. }
  98. return NULL;
  99. }
  100. static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
  101. {
  102. struct tncs_data *tncs;
  103. if (tncs_global_data == NULL)
  104. return NULL;
  105. tncs = tncs_global_data->connections;
  106. while (tncs) {
  107. if (tncs->connectionID == connectionID)
  108. return tncs;
  109. tncs = tncs->next;
  110. }
  111. wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
  112. (unsigned long) connectionID);
  113. return NULL;
  114. }
  115. /* TNCS functions that IMVs can call */
  116. TNC_Result TNC_TNCS_ReportMessageTypes(
  117. TNC_IMVID imvID,
  118. TNC_MessageTypeList supportedTypes,
  119. TNC_UInt32 typeCount)
  120. {
  121. TNC_UInt32 i;
  122. struct tnc_if_imv *imv;
  123. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
  124. "typeCount=%lu)",
  125. (unsigned long) imvID, (unsigned long) typeCount);
  126. for (i = 0; i < typeCount; i++) {
  127. wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
  128. i, supportedTypes[i]);
  129. }
  130. imv = tncs_get_imv(imvID);
  131. if (imv == NULL)
  132. return TNC_RESULT_INVALID_PARAMETER;
  133. os_free(imv->supported_types);
  134. imv->supported_types =
  135. os_malloc(typeCount * sizeof(TNC_MessageType));
  136. if (imv->supported_types == NULL)
  137. return TNC_RESULT_FATAL;
  138. os_memcpy(imv->supported_types, supportedTypes,
  139. typeCount * sizeof(TNC_MessageType));
  140. imv->num_supported_types = typeCount;
  141. return TNC_RESULT_SUCCESS;
  142. }
  143. TNC_Result TNC_TNCS_SendMessage(
  144. TNC_IMVID imvID,
  145. TNC_ConnectionID connectionID,
  146. TNC_BufferReference message,
  147. TNC_UInt32 messageLength,
  148. TNC_MessageType messageType)
  149. {
  150. struct tncs_data *tncs;
  151. unsigned char *b64;
  152. size_t b64len;
  153. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
  154. "connectionID=%lu messageType=%lu)",
  155. imvID, connectionID, messageType);
  156. wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
  157. message, messageLength);
  158. if (tncs_get_imv(imvID) == NULL)
  159. return TNC_RESULT_INVALID_PARAMETER;
  160. tncs = tncs_get_conn(connectionID);
  161. if (tncs == NULL)
  162. return TNC_RESULT_INVALID_PARAMETER;
  163. b64 = base64_encode(message, messageLength, &b64len);
  164. if (b64 == NULL)
  165. return TNC_RESULT_FATAL;
  166. os_free(tncs->imv_data[imvID].imv_send);
  167. tncs->imv_data[imvID].imv_send_len = 0;
  168. tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
  169. if (tncs->imv_data[imvID].imv_send == NULL) {
  170. os_free(b64);
  171. return TNC_RESULT_OTHER;
  172. }
  173. tncs->imv_data[imvID].imv_send_len =
  174. os_snprintf((char *) tncs->imv_data[imvID].imv_send,
  175. b64len + 100,
  176. "<IMC-IMV-Message><Type>%08X</Type>"
  177. "<Base64>%s</Base64></IMC-IMV-Message>",
  178. (unsigned int) messageType, b64);
  179. os_free(b64);
  180. return TNC_RESULT_SUCCESS;
  181. }
  182. TNC_Result TNC_TNCS_RequestHandshakeRetry(
  183. TNC_IMVID imvID,
  184. TNC_ConnectionID connectionID,
  185. TNC_RetryReason reason)
  186. {
  187. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
  188. /* TODO */
  189. return TNC_RESULT_SUCCESS;
  190. }
  191. TNC_Result TNC_TNCS_ProvideRecommendation(
  192. TNC_IMVID imvID,
  193. TNC_ConnectionID connectionID,
  194. TNC_IMV_Action_Recommendation recommendation,
  195. TNC_IMV_Evaluation_Result evaluation)
  196. {
  197. struct tncs_data *tncs;
  198. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
  199. "connectionID=%lu recommendation=%lu evaluation=%lu)",
  200. (unsigned long) imvID, (unsigned long) connectionID,
  201. (unsigned long) recommendation, (unsigned long) evaluation);
  202. if (tncs_get_imv(imvID) == NULL)
  203. return TNC_RESULT_INVALID_PARAMETER;
  204. tncs = tncs_get_conn(connectionID);
  205. if (tncs == NULL)
  206. return TNC_RESULT_INVALID_PARAMETER;
  207. tncs->imv_data[imvID].recommendation = recommendation;
  208. tncs->imv_data[imvID].recommendation_set = 1;
  209. return TNC_RESULT_SUCCESS;
  210. }
  211. TNC_Result TNC_TNCS_GetAttribute(
  212. TNC_IMVID imvID,
  213. TNC_ConnectionID connectionID,
  214. TNC_AttributeID attribureID,
  215. TNC_UInt32 bufferLength,
  216. TNC_BufferReference buffer,
  217. TNC_UInt32 *pOutValueLength)
  218. {
  219. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
  220. /* TODO */
  221. return TNC_RESULT_SUCCESS;
  222. }
  223. TNC_Result TNC_TNCS_SetAttribute(
  224. TNC_IMVID imvID,
  225. TNC_ConnectionID connectionID,
  226. TNC_AttributeID attribureID,
  227. TNC_UInt32 bufferLength,
  228. TNC_BufferReference buffer)
  229. {
  230. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
  231. /* TODO */
  232. return TNC_RESULT_SUCCESS;
  233. }
  234. TNC_Result TNC_TNCS_BindFunction(
  235. TNC_IMVID imvID,
  236. char *functionName,
  237. void **pOutFunctionPointer)
  238. {
  239. wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
  240. "functionName='%s')", (unsigned long) imvID, functionName);
  241. if (tncs_get_imv(imvID) == NULL)
  242. return TNC_RESULT_INVALID_PARAMETER;
  243. if (pOutFunctionPointer == NULL)
  244. return TNC_RESULT_INVALID_PARAMETER;
  245. if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
  246. *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
  247. else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
  248. *pOutFunctionPointer = TNC_TNCS_SendMessage;
  249. else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
  250. 0)
  251. *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
  252. else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
  253. 0)
  254. *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
  255. else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
  256. *pOutFunctionPointer = TNC_TNCS_GetAttribute;
  257. else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
  258. *pOutFunctionPointer = TNC_TNCS_SetAttribute;
  259. else
  260. *pOutFunctionPointer = NULL;
  261. return TNC_RESULT_SUCCESS;
  262. }
  263. static void * tncs_get_sym(void *handle, char *func)
  264. {
  265. void *fptr;
  266. fptr = dlsym(handle, func);
  267. return fptr;
  268. }
  269. static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
  270. {
  271. void *handle = imv->dlhandle;
  272. /* Mandatory IMV functions */
  273. imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
  274. if (imv->Initialize == NULL) {
  275. wpa_printf(MSG_ERROR, "TNC: IMV does not export "
  276. "TNC_IMV_Initialize");
  277. return -1;
  278. }
  279. imv->SolicitRecommendation = tncs_get_sym(
  280. handle, "TNC_IMV_SolicitRecommendation");
  281. if (imv->SolicitRecommendation == NULL) {
  282. wpa_printf(MSG_ERROR, "TNC: IMV does not export "
  283. "TNC_IMV_SolicitRecommendation");
  284. return -1;
  285. }
  286. imv->ProvideBindFunction =
  287. tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
  288. if (imv->ProvideBindFunction == NULL) {
  289. wpa_printf(MSG_ERROR, "TNC: IMV does not export "
  290. "TNC_IMV_ProvideBindFunction");
  291. return -1;
  292. }
  293. /* Optional IMV functions */
  294. imv->NotifyConnectionChange =
  295. tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
  296. imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
  297. imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
  298. imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
  299. return 0;
  300. }
  301. static int tncs_imv_initialize(struct tnc_if_imv *imv)
  302. {
  303. TNC_Result res;
  304. TNC_Version imv_ver;
  305. wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
  306. imv->name);
  307. res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
  308. TNC_IFIMV_VERSION_1, &imv_ver);
  309. wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
  310. (unsigned long) res, (unsigned long) imv_ver);
  311. return res == TNC_RESULT_SUCCESS ? 0 : -1;
  312. }
  313. static int tncs_imv_terminate(struct tnc_if_imv *imv)
  314. {
  315. TNC_Result res;
  316. if (imv->Terminate == NULL)
  317. return 0;
  318. wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
  319. imv->name);
  320. res = imv->Terminate(imv->imvID);
  321. wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
  322. (unsigned long) res);
  323. return res == TNC_RESULT_SUCCESS ? 0 : -1;
  324. }
  325. static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
  326. {
  327. TNC_Result res;
  328. wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
  329. "IMV '%s'", imv->name);
  330. res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
  331. wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
  332. (unsigned long) res);
  333. return res == TNC_RESULT_SUCCESS ? 0 : -1;
  334. }
  335. static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
  336. TNC_ConnectionID conn,
  337. TNC_ConnectionState state)
  338. {
  339. TNC_Result res;
  340. if (imv->NotifyConnectionChange == NULL)
  341. return 0;
  342. wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
  343. " for IMV '%s'", (int) state, imv->name);
  344. res = imv->NotifyConnectionChange(imv->imvID, conn, state);
  345. wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
  346. (unsigned long) res);
  347. return res == TNC_RESULT_SUCCESS ? 0 : -1;
  348. }
  349. static int tncs_load_imv(struct tnc_if_imv *imv)
  350. {
  351. if (imv->path == NULL) {
  352. wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
  353. return -1;
  354. }
  355. wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
  356. imv->name, imv->path);
  357. imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
  358. if (imv->dlhandle == NULL) {
  359. wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
  360. imv->name, imv->path, dlerror());
  361. return -1;
  362. }
  363. if (tncs_imv_resolve_funcs(imv) < 0) {
  364. wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
  365. return -1;
  366. }
  367. if (tncs_imv_initialize(imv) < 0 ||
  368. tncs_imv_provide_bind_function(imv) < 0) {
  369. wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
  370. return -1;
  371. }
  372. return 0;
  373. }
  374. static void tncs_free_imv(struct tnc_if_imv *imv)
  375. {
  376. os_free(imv->name);
  377. os_free(imv->path);
  378. os_free(imv->supported_types);
  379. }
  380. static void tncs_unload_imv(struct tnc_if_imv *imv)
  381. {
  382. tncs_imv_terminate(imv);
  383. if (imv->dlhandle)
  384. dlclose(imv->dlhandle);
  385. tncs_free_imv(imv);
  386. }
  387. static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
  388. {
  389. size_t i;
  390. unsigned int vendor, subtype;
  391. if (imv == NULL || imv->supported_types == NULL)
  392. return 0;
  393. vendor = type >> 8;
  394. subtype = type & 0xff;
  395. for (i = 0; i < imv->num_supported_types; i++) {
  396. unsigned int svendor, ssubtype;
  397. svendor = imv->supported_types[i] >> 8;
  398. ssubtype = imv->supported_types[i] & 0xff;
  399. if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
  400. (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
  401. return 1;
  402. }
  403. return 0;
  404. }
  405. static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
  406. const u8 *msg, size_t len)
  407. {
  408. struct tnc_if_imv *imv;
  409. TNC_Result res;
  410. wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
  411. for (imv = tncs->imv; imv; imv = imv->next) {
  412. if (imv->ReceiveMessage == NULL ||
  413. !tncs_supported_type(imv, type))
  414. continue;
  415. wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
  416. imv->name);
  417. res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
  418. (TNC_BufferReference) msg, len,
  419. type);
  420. wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
  421. (unsigned long) res);
  422. }
  423. }
  424. static void tncs_batch_ending(struct tncs_data *tncs)
  425. {
  426. struct tnc_if_imv *imv;
  427. TNC_Result res;
  428. for (imv = tncs->imv; imv; imv = imv->next) {
  429. if (imv->BatchEnding == NULL)
  430. continue;
  431. wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
  432. imv->name);
  433. res = imv->BatchEnding(imv->imvID, tncs->connectionID);
  434. wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
  435. (unsigned long) res);
  436. }
  437. }
  438. static void tncs_solicit_recommendation(struct tncs_data *tncs)
  439. {
  440. struct tnc_if_imv *imv;
  441. TNC_Result res;
  442. for (imv = tncs->imv; imv; imv = imv->next) {
  443. if (tncs->imv_data[imv->imvID].recommendation_set)
  444. continue;
  445. wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
  446. "IMV '%s'", imv->name);
  447. res = imv->SolicitRecommendation(imv->imvID,
  448. tncs->connectionID);
  449. wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
  450. (unsigned long) res);
  451. }
  452. }
  453. void tncs_init_connection(struct tncs_data *tncs)
  454. {
  455. struct tnc_if_imv *imv;
  456. int i;
  457. for (imv = tncs->imv; imv; imv = imv->next) {
  458. tncs_imv_notify_connection_change(
  459. imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
  460. tncs_imv_notify_connection_change(
  461. imv, tncs->connectionID,
  462. TNC_CONNECTION_STATE_HANDSHAKE);
  463. }
  464. for (i = 0; i < TNC_MAX_IMV_ID; i++) {
  465. os_free(tncs->imv_data[i].imv_send);
  466. tncs->imv_data[i].imv_send = NULL;
  467. tncs->imv_data[i].imv_send_len = 0;
  468. }
  469. }
  470. size_t tncs_total_send_len(struct tncs_data *tncs)
  471. {
  472. int i;
  473. size_t len = 0;
  474. for (i = 0; i < TNC_MAX_IMV_ID; i++)
  475. len += tncs->imv_data[i].imv_send_len;
  476. if (tncs->tncs_message)
  477. len += os_strlen(tncs->tncs_message);
  478. return len;
  479. }
  480. u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
  481. {
  482. int i;
  483. for (i = 0; i < TNC_MAX_IMV_ID; i++) {
  484. if (tncs->imv_data[i].imv_send == NULL)
  485. continue;
  486. os_memcpy(pos, tncs->imv_data[i].imv_send,
  487. tncs->imv_data[i].imv_send_len);
  488. pos += tncs->imv_data[i].imv_send_len;
  489. os_free(tncs->imv_data[i].imv_send);
  490. tncs->imv_data[i].imv_send = NULL;
  491. tncs->imv_data[i].imv_send_len = 0;
  492. }
  493. if (tncs->tncs_message) {
  494. size_t len = os_strlen(tncs->tncs_message);
  495. os_memcpy(pos, tncs->tncs_message, len);
  496. pos += len;
  497. os_free(tncs->tncs_message);
  498. tncs->tncs_message = NULL;
  499. }
  500. return pos;
  501. }
  502. char * tncs_if_tnccs_start(struct tncs_data *tncs)
  503. {
  504. char *buf = os_malloc(1000);
  505. if (buf == NULL)
  506. return NULL;
  507. tncs->last_batchid++;
  508. os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
  509. return buf;
  510. }
  511. char * tncs_if_tnccs_end(void)
  512. {
  513. char *buf = os_malloc(100);
  514. if (buf == NULL)
  515. return NULL;
  516. os_snprintf(buf, 100, IF_TNCCS_END);
  517. return buf;
  518. }
  519. static int tncs_get_type(char *start, unsigned int *type)
  520. {
  521. char *pos = os_strstr(start, "<Type>");
  522. if (pos == NULL)
  523. return -1;
  524. pos += 6;
  525. *type = strtoul(pos, NULL, 16);
  526. return 0;
  527. }
  528. static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
  529. {
  530. char *pos, *pos2;
  531. unsigned char *decoded;
  532. pos = os_strstr(start, "<Base64>");
  533. if (pos == NULL)
  534. return NULL;
  535. pos += 8;
  536. pos2 = os_strstr(pos, "</Base64>");
  537. if (pos2 == NULL)
  538. return NULL;
  539. *pos2 = '\0';
  540. decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
  541. decoded_len);
  542. *pos2 = '<';
  543. if (decoded == NULL) {
  544. wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
  545. }
  546. return decoded;
  547. }
  548. static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
  549. {
  550. enum IMV_Action_Recommendation rec;
  551. struct tnc_if_imv *imv;
  552. TNC_ConnectionState state;
  553. char *txt;
  554. wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
  555. if (tncs->done)
  556. return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
  557. tncs_solicit_recommendation(tncs);
  558. /* Select the most restrictive recommendation */
  559. rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
  560. for (imv = tncs->imv; imv; imv = imv->next) {
  561. TNC_IMV_Action_Recommendation irec;
  562. irec = tncs->imv_data[imv->imvID].recommendation;
  563. if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
  564. rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
  565. if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
  566. rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
  567. rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
  568. if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
  569. rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
  570. rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
  571. }
  572. wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
  573. tncs->recommendation = rec;
  574. tncs->done = 1;
  575. txt = NULL;
  576. switch (rec) {
  577. case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
  578. case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
  579. txt = "allow";
  580. state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
  581. break;
  582. case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
  583. txt = "isolate";
  584. state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
  585. break;
  586. case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
  587. txt = "none";
  588. state = TNC_CONNECTION_STATE_ACCESS_NONE;
  589. break;
  590. default:
  591. state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
  592. break;
  593. }
  594. if (txt) {
  595. os_free(tncs->tncs_message);
  596. tncs->tncs_message = os_zalloc(200);
  597. if (tncs->tncs_message) {
  598. os_snprintf(tncs->tncs_message, 199,
  599. "<TNCC-TNCS-Message><Type>%08X</Type>"
  600. "<XML><TNCCS-Recommendation type=\"%s\">"
  601. "</TNCCS-Recommendation></XML>"
  602. "</TNCC-TNCS-Message>",
  603. TNC_TNCCS_RECOMMENDATION, txt);
  604. }
  605. }
  606. for (imv = tncs->imv; imv; imv = imv->next) {
  607. tncs_imv_notify_connection_change(imv, tncs->connectionID,
  608. state);
  609. }
  610. switch (rec) {
  611. case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
  612. return TNCCS_RECOMMENDATION_ALLOW;
  613. case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
  614. return TNCCS_RECOMMENDATION_NO_ACCESS;
  615. case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
  616. return TNCCS_RECOMMENDATION_ISOLATE;
  617. case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
  618. return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
  619. default:
  620. return TNCCS_PROCESS_ERROR;
  621. }
  622. }
  623. enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
  624. const u8 *msg, size_t len)
  625. {
  626. char *buf, *start, *end, *pos, *pos2, *payload;
  627. unsigned int batch_id;
  628. unsigned char *decoded;
  629. size_t decoded_len;
  630. buf = dup_binstr(msg, len);
  631. if (buf == NULL)
  632. return TNCCS_PROCESS_ERROR;
  633. start = os_strstr(buf, "<TNCCS-Batch ");
  634. end = os_strstr(buf, "</TNCCS-Batch>");
  635. if (start == NULL || end == NULL || start > end) {
  636. os_free(buf);
  637. return TNCCS_PROCESS_ERROR;
  638. }
  639. start += 13;
  640. while (*start == ' ')
  641. start++;
  642. *end = '\0';
  643. pos = os_strstr(start, "BatchId=");
  644. if (pos == NULL) {
  645. os_free(buf);
  646. return TNCCS_PROCESS_ERROR;
  647. }
  648. pos += 8;
  649. if (*pos == '"')
  650. pos++;
  651. batch_id = atoi(pos);
  652. wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
  653. batch_id);
  654. if (batch_id != tncs->last_batchid + 1) {
  655. wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
  656. "%u (expected %u)",
  657. batch_id, tncs->last_batchid + 1);
  658. os_free(buf);
  659. return TNCCS_PROCESS_ERROR;
  660. }
  661. tncs->last_batchid = batch_id;
  662. while (*pos != '\0' && *pos != '>')
  663. pos++;
  664. if (*pos == '\0') {
  665. os_free(buf);
  666. return TNCCS_PROCESS_ERROR;
  667. }
  668. pos++;
  669. payload = start;
  670. /*
  671. * <IMC-IMV-Message>
  672. * <Type>01234567</Type>
  673. * <Base64>foo==</Base64>
  674. * </IMC-IMV-Message>
  675. */
  676. while (*start) {
  677. char *endpos;
  678. unsigned int type;
  679. pos = os_strstr(start, "<IMC-IMV-Message>");
  680. if (pos == NULL)
  681. break;
  682. start = pos + 17;
  683. end = os_strstr(start, "</IMC-IMV-Message>");
  684. if (end == NULL)
  685. break;
  686. *end = '\0';
  687. endpos = end;
  688. end += 18;
  689. if (tncs_get_type(start, &type) < 0) {
  690. *endpos = '<';
  691. start = end;
  692. continue;
  693. }
  694. wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
  695. decoded = tncs_get_base64(start, &decoded_len);
  696. if (decoded == NULL) {
  697. *endpos = '<';
  698. start = end;
  699. continue;
  700. }
  701. tncs_send_to_imvs(tncs, type, decoded, decoded_len);
  702. os_free(decoded);
  703. start = end;
  704. }
  705. /*
  706. * <TNCC-TNCS-Message>
  707. * <Type>01234567</Type>
  708. * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
  709. * <Base64>foo==</Base64>
  710. * </TNCC-TNCS-Message>
  711. */
  712. start = payload;
  713. while (*start) {
  714. unsigned int type;
  715. char *xml, *xmlend, *endpos;
  716. pos = os_strstr(start, "<TNCC-TNCS-Message>");
  717. if (pos == NULL)
  718. break;
  719. start = pos + 19;
  720. end = os_strstr(start, "</TNCC-TNCS-Message>");
  721. if (end == NULL)
  722. break;
  723. *end = '\0';
  724. endpos = end;
  725. end += 20;
  726. if (tncs_get_type(start, &type) < 0) {
  727. *endpos = '<';
  728. start = end;
  729. continue;
  730. }
  731. wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
  732. type);
  733. /* Base64 OR XML */
  734. decoded = NULL;
  735. xml = NULL;
  736. xmlend = NULL;
  737. pos = os_strstr(start, "<XML>");
  738. if (pos) {
  739. pos += 5;
  740. pos2 = os_strstr(pos, "</XML>");
  741. if (pos2 == NULL) {
  742. *endpos = '<';
  743. start = end;
  744. continue;
  745. }
  746. xmlend = pos2;
  747. xml = pos;
  748. } else {
  749. decoded = tncs_get_base64(start, &decoded_len);
  750. if (decoded == NULL) {
  751. *endpos = '<';
  752. start = end;
  753. continue;
  754. }
  755. }
  756. if (decoded) {
  757. wpa_hexdump_ascii(MSG_MSGDUMP,
  758. "TNC: TNCC-TNCS-Message Base64",
  759. decoded, decoded_len);
  760. os_free(decoded);
  761. }
  762. if (xml) {
  763. wpa_hexdump_ascii(MSG_MSGDUMP,
  764. "TNC: TNCC-TNCS-Message XML",
  765. (unsigned char *) xml,
  766. xmlend - xml);
  767. }
  768. start = end;
  769. }
  770. os_free(buf);
  771. tncs_batch_ending(tncs);
  772. if (tncs_total_send_len(tncs) == 0)
  773. return tncs_derive_recommendation(tncs);
  774. return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
  775. }
  776. static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
  777. int *error)
  778. {
  779. struct tnc_if_imv *imv;
  780. char *pos, *pos2;
  781. if (id >= TNC_MAX_IMV_ID) {
  782. wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
  783. return NULL;
  784. }
  785. imv = os_zalloc(sizeof(*imv));
  786. if (imv == NULL) {
  787. *error = 1;
  788. return NULL;
  789. }
  790. imv->imvID = id;
  791. pos = start;
  792. wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
  793. if (pos + 1 >= end || *pos != '"') {
  794. wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
  795. "(no starting quotation mark)", start);
  796. os_free(imv);
  797. return NULL;
  798. }
  799. pos++;
  800. pos2 = pos;
  801. while (pos2 < end && *pos2 != '"')
  802. pos2++;
  803. if (pos2 >= end) {
  804. wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
  805. "(no ending quotation mark)", start);
  806. os_free(imv);
  807. return NULL;
  808. }
  809. *pos2 = '\0';
  810. wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
  811. imv->name = os_strdup(pos);
  812. pos = pos2 + 1;
  813. if (pos >= end || *pos != ' ') {
  814. wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
  815. "(no space after name)", start);
  816. os_free(imv);
  817. return NULL;
  818. }
  819. pos++;
  820. wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
  821. imv->path = os_strdup(pos);
  822. return imv;
  823. }
  824. static int tncs_read_config(struct tncs_global *global)
  825. {
  826. char *config, *end, *pos, *line_end;
  827. size_t config_len;
  828. struct tnc_if_imv *imv, *last;
  829. int id = 0;
  830. last = NULL;
  831. config = os_readfile(TNC_CONFIG_FILE, &config_len);
  832. if (config == NULL) {
  833. wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
  834. "file '%s'", TNC_CONFIG_FILE);
  835. return -1;
  836. }
  837. end = config + config_len;
  838. for (pos = config; pos < end; pos = line_end + 1) {
  839. line_end = pos;
  840. while (*line_end != '\n' && *line_end != '\r' &&
  841. line_end < end)
  842. line_end++;
  843. *line_end = '\0';
  844. if (os_strncmp(pos, "IMV ", 4) == 0) {
  845. int error = 0;
  846. imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
  847. if (error)
  848. return -1;
  849. if (imv) {
  850. if (last == NULL)
  851. global->imv = imv;
  852. else
  853. last->next = imv;
  854. last = imv;
  855. }
  856. }
  857. }
  858. os_free(config);
  859. return 0;
  860. }
  861. struct tncs_data * tncs_init(void)
  862. {
  863. struct tncs_data *tncs;
  864. if (tncs_global_data == NULL)
  865. return NULL;
  866. tncs = os_zalloc(sizeof(*tncs));
  867. if (tncs == NULL)
  868. return NULL;
  869. tncs->imv = tncs_global_data->imv;
  870. tncs->connectionID = tncs_global_data->next_conn_id++;
  871. tncs->next = tncs_global_data->connections;
  872. tncs_global_data->connections = tncs;
  873. return tncs;
  874. }
  875. void tncs_deinit(struct tncs_data *tncs)
  876. {
  877. int i;
  878. struct tncs_data *prev, *conn;
  879. if (tncs == NULL)
  880. return;
  881. for (i = 0; i < TNC_MAX_IMV_ID; i++)
  882. os_free(tncs->imv_data[i].imv_send);
  883. prev = NULL;
  884. conn = tncs_global_data->connections;
  885. while (conn) {
  886. if (conn == tncs) {
  887. if (prev)
  888. prev->next = tncs->next;
  889. else
  890. tncs_global_data->connections = tncs->next;
  891. break;
  892. }
  893. prev = conn;
  894. conn = conn->next;
  895. }
  896. os_free(tncs->tncs_message);
  897. os_free(tncs);
  898. }
  899. int tncs_global_init(void)
  900. {
  901. struct tnc_if_imv *imv;
  902. if (tncs_global_data)
  903. return 0;
  904. tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
  905. if (tncs_global_data == NULL)
  906. return -1;
  907. if (tncs_read_config(tncs_global_data) < 0) {
  908. wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
  909. goto failed;
  910. }
  911. for (imv = tncs_global_data->imv; imv; imv = imv->next) {
  912. if (tncs_load_imv(imv)) {
  913. wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
  914. imv->name);
  915. goto failed;
  916. }
  917. }
  918. return 0;
  919. failed:
  920. tncs_global_deinit();
  921. return -1;
  922. }
  923. void tncs_global_deinit(void)
  924. {
  925. struct tnc_if_imv *imv, *prev;
  926. if (tncs_global_data == NULL)
  927. return;
  928. imv = tncs_global_data->imv;
  929. while (imv) {
  930. tncs_unload_imv(imv);
  931. prev = imv;
  932. imv = imv->next;
  933. os_free(prev);
  934. }
  935. os_free(tncs_global_data);
  936. tncs_global_data = NULL;
  937. }
  938. struct wpabuf * tncs_build_soh_request(void)
  939. {
  940. struct wpabuf *buf;
  941. /*
  942. * Build a SoH Request TLV (to be used inside SoH EAP Extensions
  943. * Method)
  944. */
  945. buf = wpabuf_alloc(8 + 4);
  946. if (buf == NULL)
  947. return NULL;
  948. /* Vendor-Specific TLV (Microsoft) - SoH Request */
  949. wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
  950. wpabuf_put_be16(buf, 8); /* Length */
  951. wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
  952. wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
  953. wpabuf_put_be16(buf, 0); /* Length */
  954. return buf;
  955. }
  956. struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
  957. int *failure)
  958. {
  959. wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
  960. *failure = 0;
  961. /* TODO: return MS-SoH Response TLV */
  962. return NULL;
  963. }