eap_tnc.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * EAP server method: EAP-TNC (Trusted Network Connect)
  3. * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "base64.h"
  17. #include "eap_i.h"
  18. #include "tncs.h"
  19. struct eap_tnc_data {
  20. enum { START, CONTINUE, RECOMMENDATION, DONE, FAIL } state;
  21. enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
  22. struct tncs_data *tncs;
  23. };
  24. /* EAP-TNC Flags */
  25. #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
  26. #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
  27. #define EAP_TNC_FLAGS_START 0x20
  28. #define EAP_TNC_VERSION_MASK 0x07
  29. #define EAP_TNC_VERSION 1
  30. static void * eap_tnc_init(struct eap_sm *sm)
  31. {
  32. struct eap_tnc_data *data;
  33. data = os_zalloc(sizeof(*data));
  34. if (data == NULL)
  35. return NULL;
  36. data->state = START;
  37. data->tncs = tncs_init();
  38. if (data->tncs == NULL) {
  39. os_free(data);
  40. return NULL;
  41. }
  42. return data;
  43. }
  44. static void eap_tnc_reset(struct eap_sm *sm, void *priv)
  45. {
  46. struct eap_tnc_data *data = priv;
  47. tncs_deinit(data->tncs);
  48. os_free(data);
  49. }
  50. static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
  51. struct eap_tnc_data *data, u8 id)
  52. {
  53. struct wpabuf *req;
  54. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
  55. id);
  56. if (req == NULL) {
  57. wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
  58. "request");
  59. data->state = FAIL;
  60. return NULL;
  61. }
  62. wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
  63. data->state = CONTINUE;
  64. return req;
  65. }
  66. static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
  67. struct eap_tnc_data *data, u8 id)
  68. {
  69. struct wpabuf *req;
  70. u8 *rpos, *rpos1, *start;
  71. size_t rlen;
  72. char *start_buf, *end_buf;
  73. size_t start_len, end_len;
  74. size_t imv_len;
  75. imv_len = tncs_total_send_len(data->tncs);
  76. start_buf = tncs_if_tnccs_start(data->tncs);
  77. if (start_buf == NULL)
  78. return NULL;
  79. start_len = os_strlen(start_buf);
  80. end_buf = tncs_if_tnccs_end();
  81. if (end_buf == NULL) {
  82. os_free(start_buf);
  83. return NULL;
  84. }
  85. end_len = os_strlen(end_buf);
  86. rlen = 1 + start_len + imv_len + end_len;
  87. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, rlen,
  88. EAP_CODE_REQUEST, id);
  89. if (req == NULL) {
  90. os_free(start_buf);
  91. os_free(end_buf);
  92. return NULL;
  93. }
  94. start = wpabuf_put(req, 0);
  95. wpabuf_put_u8(req, EAP_TNC_VERSION);
  96. wpabuf_put_data(req, start_buf, start_len);
  97. os_free(start_buf);
  98. rpos1 = wpabuf_put(req, 0);
  99. rpos = tncs_copy_send_buf(data->tncs, rpos1);
  100. wpabuf_put(req, rpos - rpos1);
  101. wpabuf_put_data(req, end_buf, end_len);
  102. os_free(end_buf);
  103. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", start, rlen);
  104. return req;
  105. }
  106. static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
  107. struct eap_tnc_data *data,
  108. u8 id)
  109. {
  110. switch (data->recommendation) {
  111. case ALLOW:
  112. data->state = DONE;
  113. break;
  114. case ISOLATE:
  115. data->state = FAIL;
  116. /* TODO: support assignment to a different VLAN */
  117. break;
  118. case NO_ACCESS:
  119. data->state = FAIL;
  120. break;
  121. case NO_RECOMMENDATION:
  122. data->state = DONE;
  123. break;
  124. default:
  125. wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
  126. return NULL;
  127. }
  128. return eap_tnc_build(sm, data, id);
  129. }
  130. static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
  131. {
  132. struct eap_tnc_data *data = priv;
  133. switch (data->state) {
  134. case START:
  135. tncs_init_connection(data->tncs);
  136. return eap_tnc_build_start(sm, data, id);
  137. case CONTINUE:
  138. return eap_tnc_build(sm, data, id);
  139. case RECOMMENDATION:
  140. return eap_tnc_build_recommendation(sm, data, id);
  141. case DONE:
  142. case FAIL:
  143. return NULL;
  144. }
  145. return NULL;
  146. }
  147. static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
  148. struct wpabuf *respData)
  149. {
  150. const u8 *pos;
  151. size_t len;
  152. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
  153. &len);
  154. if (pos == NULL || len == 0) {
  155. wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
  156. return TRUE;
  157. }
  158. if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
  159. wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
  160. *pos & EAP_TNC_VERSION_MASK);
  161. return TRUE;
  162. }
  163. if (*pos & EAP_TNC_FLAGS_START) {
  164. wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
  165. return TRUE;
  166. }
  167. return FALSE;
  168. }
  169. static void eap_tnc_process(struct eap_sm *sm, void *priv,
  170. struct wpabuf *respData)
  171. {
  172. struct eap_tnc_data *data = priv;
  173. const u8 *pos;
  174. size_t len;
  175. enum tncs_process_res res;
  176. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
  177. if (pos == NULL || len == 0)
  178. return; /* Should not happen; message already verified */
  179. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", pos, len);
  180. if (len == 1 && (data->state == DONE || data->state == FAIL)) {
  181. wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
  182. "message");
  183. return;
  184. }
  185. res = tncs_process_if_tnccs(data->tncs, pos + 1, len - 1);
  186. switch (res) {
  187. case TNCCS_RECOMMENDATION_ALLOW:
  188. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
  189. data->state = RECOMMENDATION;
  190. data->recommendation = ALLOW;
  191. break;
  192. case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
  193. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
  194. data->state = RECOMMENDATION;
  195. data->recommendation = NO_RECOMMENDATION;
  196. break;
  197. case TNCCS_RECOMMENDATION_ISOLATE:
  198. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
  199. data->state = RECOMMENDATION;
  200. data->recommendation = ISOLATE;
  201. break;
  202. case TNCCS_RECOMMENDATION_NO_ACCESS:
  203. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
  204. data->state = RECOMMENDATION;
  205. data->recommendation = NO_ACCESS;
  206. break;
  207. case TNCCS_PROCESS_ERROR:
  208. wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
  209. data->state = FAIL;
  210. break;
  211. default:
  212. break;
  213. }
  214. }
  215. static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
  216. {
  217. struct eap_tnc_data *data = priv;
  218. return data->state == DONE;
  219. }
  220. static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
  221. {
  222. struct eap_tnc_data *data = priv;
  223. return data->state == DONE;
  224. }
  225. int eap_server_tnc_register(void)
  226. {
  227. struct eap_method *eap;
  228. int ret;
  229. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  230. EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
  231. if (eap == NULL)
  232. return -1;
  233. eap->init = eap_tnc_init;
  234. eap->reset = eap_tnc_reset;
  235. eap->buildReq = eap_tnc_buildReq;
  236. eap->check = eap_tnc_check;
  237. eap->process = eap_tnc_process;
  238. eap->isDone = eap_tnc_isDone;
  239. eap->isSuccess = eap_tnc_isSuccess;
  240. ret = eap_server_method_register(eap);
  241. if (ret)
  242. eap_server_method_free(eap);
  243. return ret;
  244. }