tncs.c 27 KB

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