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