xref: /freebsd/contrib/wpa/src/eap_server/eap_server_identity.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
1 /*
2  * hostapd / EAP-Identity
3  * Copyright (c) 2004-2006, 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 
15 #include "includes.h"
16 
17 #include "common.h"
18 #include "eap_i.h"
19 
20 
21 struct eap_identity_data {
22 	enum { CONTINUE, SUCCESS, FAILURE } state;
23 	int pick_up;
24 };
25 
26 
27 static void * eap_identity_init(struct eap_sm *sm)
28 {
29 	struct eap_identity_data *data;
30 
31 	data = os_zalloc(sizeof(*data));
32 	if (data == NULL)
33 		return NULL;
34 	data->state = CONTINUE;
35 
36 	return data;
37 }
38 
39 
40 static void * eap_identity_initPickUp(struct eap_sm *sm)
41 {
42 	struct eap_identity_data *data;
43 	data = eap_identity_init(sm);
44 	if (data) {
45 		data->pick_up = 1;
46 	}
47 	return data;
48 }
49 
50 
51 static void eap_identity_reset(struct eap_sm *sm, void *priv)
52 {
53 	struct eap_identity_data *data = priv;
54 	os_free(data);
55 }
56 
57 
58 static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv,
59 					     u8 id)
60 {
61 	struct eap_identity_data *data = priv;
62 	struct wpabuf *req;
63 	const char *req_data;
64 	size_t req_data_len;
65 
66 	if (sm->eapol_cb->get_eap_req_id_text) {
67 		req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx,
68 							     &req_data_len);
69 	} else {
70 		req_data = NULL;
71 		req_data_len = 0;
72 	}
73 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len,
74 			    EAP_CODE_REQUEST, id);
75 	if (req == NULL) {
76 		wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
77 			   "memory for request");
78 		data->state = FAILURE;
79 		return NULL;
80 	}
81 
82 	wpabuf_put_data(req, req_data, req_data_len);
83 
84 	return req;
85 }
86 
87 
88 static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
89 				  struct wpabuf *respData)
90 {
91 	const u8 *pos;
92 	size_t len;
93 
94 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
95 			       respData, &len);
96 	if (pos == NULL) {
97 		wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
98 		return TRUE;
99 	}
100 
101 	return FALSE;
102 }
103 
104 
105 static void eap_identity_process(struct eap_sm *sm, void *priv,
106 				 struct wpabuf *respData)
107 {
108 	struct eap_identity_data *data = priv;
109 	const u8 *pos;
110 	size_t len;
111 
112 	if (data->pick_up) {
113 		if (eap_identity_check(sm, data, respData)) {
114 			wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick "
115 				   "up already started negotiation");
116 			data->state = FAILURE;
117 			return;
118 		}
119 		data->pick_up = 0;
120 	}
121 
122 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
123 			       respData, &len);
124 	if (pos == NULL)
125 		return; /* Should not happen - frame already validated */
126 
127 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
128 	if (sm->identity)
129 		sm->update_user = TRUE;
130 	os_free(sm->identity);
131 	sm->identity = os_malloc(len ? len : 1);
132 	if (sm->identity == NULL) {
133 		data->state = FAILURE;
134 	} else {
135 		os_memcpy(sm->identity, pos, len);
136 		sm->identity_len = len;
137 		data->state = SUCCESS;
138 	}
139 }
140 
141 
142 static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
143 {
144 	struct eap_identity_data *data = priv;
145 	return data->state != CONTINUE;
146 }
147 
148 
149 static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
150 {
151 	struct eap_identity_data *data = priv;
152 	return data->state == SUCCESS;
153 }
154 
155 
156 int eap_server_identity_register(void)
157 {
158 	struct eap_method *eap;
159 	int ret;
160 
161 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
162 				      EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
163 				      "Identity");
164 	if (eap == NULL)
165 		return -1;
166 
167 	eap->init = eap_identity_init;
168 	eap->initPickUp = eap_identity_initPickUp;
169 	eap->reset = eap_identity_reset;
170 	eap->buildReq = eap_identity_buildReq;
171 	eap->check = eap_identity_check;
172 	eap->process = eap_identity_process;
173 	eap->isDone = eap_identity_isDone;
174 	eap->isSuccess = eap_identity_isSuccess;
175 
176 	ret = eap_server_method_register(eap);
177 	if (ret)
178 		eap_server_method_free(eap);
179 	return ret;
180 }
181