iPXE
eap.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <byteswap.h>
31 #include <ipxe/netdevice.h>
32 #include <ipxe/eap.h>
33 
34 /** @file
35  *
36  * Extensible Authentication Protocol
37  *
38  */
39 
40 /**
41  * Transmit EAP response
42  *
43  * @v supplicant EAP supplicant
44  * @v rsp Response type data
45  * @v rsp_len Length of response type data
46  * @ret rc Return status code
47  */
48 int eap_tx_response ( struct eap_supplicant *supplicant,
49  const void *rsp, size_t rsp_len ) {
50  struct net_device *netdev = supplicant->netdev;
51  struct eap_message *msg;
52  size_t len;
53  int rc;
54 
55  /* Allocate and populate response */
56  len = ( sizeof ( *msg ) + rsp_len );
57  msg = malloc ( len );
58  if ( ! msg ) {
59  rc = -ENOMEM;
60  goto err_alloc;
61  }
62  msg->hdr.code = EAP_CODE_RESPONSE;
63  msg->hdr.id = supplicant->id;
64  msg->hdr.len = htons ( len );
65  msg->type = supplicant->type;
66  memcpy ( msg->data, rsp, rsp_len );
67  DBGC ( netdev, "EAP %s Response id %#02x type %d\n",
68  netdev->name, msg->hdr.id, msg->type );
69 
70  /* Transmit response */
71  if ( ( rc = supplicant->tx ( supplicant, msg, len ) ) != 0 ) {
72  DBGC ( netdev, "EAP %s could not transmit: %s\n",
73  netdev->name, strerror ( rc ) );
74  goto err_tx;
75  }
76 
77  err_tx:
78  free ( msg );
79  err_alloc:
80  return rc;
81 }
82 
83 /**
84  * Transmit EAP NAK
85  *
86  * @v supplicant EAP supplicant
87  * @ret rc Return status code
88  */
89 static int eap_tx_nak ( struct eap_supplicant *supplicant ) {
90  struct net_device *netdev = supplicant->netdev;
91  unsigned int max = table_num_entries ( EAP_METHODS );
92  uint8_t methods[ max + 1 /* potential EAP_TYPE_NONE */ ];
93  unsigned int count = 0;
94  struct eap_method *method;
95 
96  /* Populate methods list */
97  DBGC ( netdev, "EAP %s Nak offering types {", netdev->name );
99  if ( method->type > EAP_TYPE_NAK ) {
100  DBGC ( netdev, "%s%d",
101  ( count ? ", " : "" ), method->type );
102  methods[count++] = method->type;
103  }
104  }
105  if ( ! count )
106  methods[count++] = EAP_TYPE_NONE;
107  DBGC ( netdev, "}\n" );
108  assert ( count <= max );
109 
110  /* Transmit response */
111  supplicant->type = EAP_TYPE_NAK;
112  return eap_tx_response ( supplicant, methods, count );
113 }
114 
115 /**
116  * Handle EAP Request-Identity
117  *
118  * @v supplicant EAP supplicant
119  * @v req Request type data
120  * @v req_len Length of request type data
121  * @ret rc Return status code
122  */
123 static int eap_rx_identity ( struct eap_supplicant *supplicant,
124  const void *req, size_t req_len ) {
125  struct net_device *netdev = supplicant->netdev;
126  void *rsp;
127  int rsp_len;
128  int rc;
129 
130  /* Treat Request-Identity as blocking the link */
131  DBGC ( netdev, "EAP %s Request-Identity blocking link\n",
132  netdev->name );
133  DBGC_HDA ( netdev, 0, req, req_len );
135 
136  /* Mark EAP as in progress */
137  supplicant->flags |= EAP_FL_ONGOING;
138 
139  /* Construct response, if applicable */
141  &username_setting, &rsp );
142  if ( rsp_len < 0 ) {
143  /* We have no identity to offer, so wait until the
144  * switch times out and switches to MAC Authentication
145  * Bypass (MAB).
146  */
147  DBGC2 ( netdev, "EAP %s has no identity\n", netdev->name );
148  supplicant->flags |= EAP_FL_PASSIVE;
149  rc = 0;
150  goto no_response;
151  }
152 
153  /* Transmit response */
154  if ( ( rc = eap_tx_response ( supplicant, rsp, rsp_len ) ) != 0 )
155  goto err_tx;
156 
157  err_tx:
158  free ( rsp );
159  no_response:
160  return rc;
161 }
162 
163 /** EAP Request-Identity method */
164 struct eap_method eap_identity_method __eap_method = {
166  .rx = eap_rx_identity,
167 };
168 
169 /**
170  * Handle EAP Request
171  *
172  * @v supplicant EAP supplicant
173  * @v msg EAP request
174  * @v len Length of EAP request
175  * @ret rc Return status code
176  */
177 static int eap_rx_request ( struct eap_supplicant *supplicant,
178  const struct eap_message *msg, size_t len ) {
179  struct net_device *netdev = supplicant->netdev;
180  struct eap_method *method;
181  const void *req;
182  size_t req_len;
183 
184  /* Sanity checks */
185  if ( len < sizeof ( *msg ) ) {
186  DBGC ( netdev, "EAP %s underlength request:\n", netdev->name );
187  DBGC_HDA ( netdev, 0, msg, len );
188  return -EINVAL;
189  }
190  if ( len < ntohs ( msg->hdr.len ) ) {
191  DBGC ( netdev, "EAP %s truncated request:\n", netdev->name );
192  DBGC_HDA ( netdev, 0, msg, len );
193  return -EINVAL;
194  }
195  req = msg->data;
196  req_len = ( ntohs ( msg->hdr.len ) - sizeof ( *msg ) );
197 
198  /* Record request details */
199  supplicant->id = msg->hdr.id;
200  supplicant->type = msg->type;
201  DBGC ( netdev, "EAP %s Request id %#02x type %d\n",
202  netdev->name, msg->hdr.id, msg->type );
203 
204  /* Handle according to type */
206  if ( msg->type == method->type )
207  return method->rx ( supplicant, req, req_len );
208  }
209  DBGC ( netdev, "EAP %s requested type %d unknown:\n",
210  netdev->name, msg->type );
211  DBGC_HDA ( netdev, 0, msg, len );
212 
213  /* Send NAK if applicable */
214  if ( msg->type > EAP_TYPE_NAK )
215  return eap_tx_nak ( supplicant );
216 
217  return -ENOTSUP;
218 }
219 
220 /**
221  * Handle EAP Success
222  *
223  * @v supplicant EAP supplicant
224  * @ret rc Return status code
225  */
226 static int eap_rx_success ( struct eap_supplicant *supplicant ) {
227  struct net_device *netdev = supplicant->netdev;
228 
229  /* Mark authentication as complete */
230  supplicant->flags = EAP_FL_PASSIVE;
231 
232  /* Mark link as unblocked */
233  DBGC ( netdev, "EAP %s Success\n", netdev->name );
235 
236  return 0;
237 }
238 
239 /**
240  * Handle EAP Failure
241  *
242  * @v supplicant EAP supplicant
243  * @ret rc Return status code
244  */
245 static int eap_rx_failure ( struct eap_supplicant *supplicant ) {
246  struct net_device *netdev = supplicant->netdev;
247 
248  /* Mark authentication as complete */
249  supplicant->flags = EAP_FL_PASSIVE;
250 
251  /* Record error */
252  DBGC ( netdev, "EAP %s Failure\n", netdev->name );
253  return -EPERM;
254 }
255 
256 /**
257  * Handle EAP packet
258  *
259  * @v supplicant EAP supplicant
260  * @v data EAP packet
261  * @v len Length of EAP packet
262  * @ret rc Return status code
263  */
264 int eap_rx ( struct eap_supplicant *supplicant, const void *data,
265  size_t len ) {
266  struct net_device *netdev = supplicant->netdev;
267  const union eap_packet *eap = data;
268 
269  /* Sanity check */
270  if ( len < sizeof ( eap->hdr ) ) {
271  DBGC ( netdev, "EAP %s underlength header:\n", netdev->name );
272  DBGC_HDA ( netdev, 0, eap, len );
273  return -EINVAL;
274  }
275 
276  /* Handle according to code */
277  switch ( eap->hdr.code ) {
278  case EAP_CODE_REQUEST:
279  return eap_rx_request ( supplicant, &eap->msg, len );
280  case EAP_CODE_RESPONSE:
281  DBGC2 ( netdev, "EAP %s ignoring response\n", netdev->name );
282  return 0;
283  case EAP_CODE_SUCCESS:
284  return eap_rx_success ( supplicant );
285  case EAP_CODE_FAILURE:
286  return eap_rx_failure ( supplicant );
287  default:
288  DBGC ( netdev, "EAP %s unsupported code %d\n",
289  netdev->name, eap->hdr.code );
290  DBGC_HDA ( netdev, 0, eap, len );
291  return -ENOTSUP;
292  }
293 }
294 
295 /* Drag in objects via eap_rx() */
297 
298 /* Drag in EAP configuration */
299 REQUIRE_OBJECT ( config_eap );
#define EINVAL
Invalid argument.
Definition: errno.h:429
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EAP_TYPE_NONE
EAP "no available types" marker.
Definition: eap.h:45
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition: message.c:62
#define max(x, y)
Definition: ath.h:41
FILE_SECBOOT(PERMITTED)
struct eap_message msg
Request/response message.
Definition: eap.h:104
int fetch_raw_setting_copy(struct settings *settings, const struct setting *setting, void **data)
Fetch value of setting.
Definition: settings.c:822
static int eap_rx_failure(struct eap_supplicant *supplicant)
Handle EAP Failure.
Definition: eap.c:245
Error codes.
#define EAP_CODE_REQUEST
EAP request.
Definition: eap.h:29
struct eap_header hdr
Header.
Definition: eap.h:102
#define DBGC(...)
Definition: compiler.h:505
REQUIRING_SYMBOL(eap_rx)
An EAP supplicant.
Definition: eap.h:139
#define EAP_METHODS
EAP method table.
Definition: eap.h:194
int eap_rx(struct eap_supplicant *supplicant, const void *data, size_t len)
Handle EAP packet.
Definition: eap.c:264
#define ntohs(value)
Definition: byteswap.h:137
uint8_t method
Definition: ib_mad.h:15
EAP request/response message.
Definition: eap.h:35
uint8_t id
ID for current request/response.
Definition: eap.h:145
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:587
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
#define EAP_CODE_RESPONSE
EAP response.
Definition: eap.h:32
#define EAP_CODE_FAILURE
EAP failure.
Definition: eap.h:97
#define ENOMEM
Not enough space.
Definition: errno.h:535
uint8_t type
Type.
Definition: eap.h:180
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int eap_rx_success(struct eap_supplicant *supplicant)
Handle EAP Success.
Definition: eap.c:226
EAP packet.
Definition: eap.h:100
int eap_tx_response(struct eap_supplicant *supplicant, const void *rsp, size_t rsp_len)
Transmit EAP response.
Definition: eap.c:48
void netdev_link_block(struct net_device *netdev, unsigned long timeout)
Mark network device link as being blocked.
Definition: netdevice.c:248
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define DBGC_HDA(...)
Definition: compiler.h:506
REQUIRE_OBJECT(config_eap)
void netdev_link_unblock(struct net_device *netdev)
Mark network device link as being unblocked.
Definition: netdevice.c:263
ring len
Length.
Definition: dwmac.h:231
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static struct net_device * netdev
Definition: gdbudp.c:53
#define EAP_FL_PASSIVE
EAP supplicant is passive.
Definition: eap.h:175
static unsigned int count
Number of entries.
Definition: dwmac.h:225
#define EAP_FL_ONGOING
EAP authentication is in progress.
Definition: eap.h:165
uint64_t rsp
Definition: librm.h:153
static int eap_tx_nak(struct eap_supplicant *supplicant)
Transmit EAP NAK.
Definition: eap.c:89
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
A network device.
Definition: netdevice.h:353
unsigned char uint8_t
Definition: stdint.h:10
#define EAP_TYPE_IDENTITY
EAP identity.
Definition: eap.h:48
#define EAP_CODE_SUCCESS
EAP success.
Definition: eap.h:94
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:621
static int eap_rx_request(struct eap_supplicant *supplicant, const struct eap_message *msg, size_t len)
Handle EAP Request.
Definition: eap.c:177
#define EAP_TYPE_NAK
EAP NAK.
Definition: eap.h:51
#define EPERM
Operation not permitted.
Definition: errno.h:615
Network device management.
static int eap_rx_identity(struct eap_supplicant *supplicant, const void *req, size_t req_len)
Handle EAP Request-Identity.
Definition: eap.c:123
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
int(* tx)(struct eap_supplicant *supplicant, const void *data, size_t len)
Transmit EAP response.
Definition: eap.h:156
#define DBGC2(...)
Definition: compiler.h:522
struct eap_method eap_identity_method __eap_method
EAP Request-Identity method.
Definition: eap.c:164
uint8_t code
Code.
Definition: eap.h:21
uint8_t type
Type for current request/response.
Definition: eap.h:147
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define EAP_BLOCK_TIMEOUT
EAP link block timeout.
Definition: eap.h:118
struct net_device * netdev
Network device.
Definition: eap.h:141
String functions.
#define htons(value)
Definition: byteswap.h:136
Extensible Authentication Protocol.
uint16_t flags
Flags.
Definition: eap.h:143
#define table_num_entries(table)
Get number of entries in linker table.
Definition: tables.h:336
An EAP method.
Definition: eap.h:178