payload: Use common prefixes for all payload type identifiers
[strongswan.git] / src / libcharon / sa / ikev2 / authenticators / eap_authenticator.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2006-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "eap_authenticator.h"
18
19 #include <daemon.h>
20 #include <sa/ikev2/keymat_v2.h>
21 #include <sa/eap/eap_method.h>
22 #include <encoding/payloads/auth_payload.h>
23 #include <encoding/payloads/eap_payload.h>
24
25 typedef struct private_eap_authenticator_t private_eap_authenticator_t;
26
27 /**
28 * Private data of an eap_authenticator_t object.
29 */
30 struct private_eap_authenticator_t {
31
32 /**
33 * Public authenticator_t interface.
34 */
35 eap_authenticator_t public;
36
37 /**
38 * Assigned IKE_SA
39 */
40 ike_sa_t *ike_sa;
41
42 /**
43 * others nonce to include in AUTH calculation
44 */
45 chunk_t received_nonce;
46
47 /**
48 * our nonce to include in AUTH calculation
49 */
50 chunk_t sent_nonce;
51
52 /**
53 * others IKE_SA_INIT message data to include in AUTH calculation
54 */
55 chunk_t received_init;
56
57 /**
58 * our IKE_SA_INIT message data to include in AUTH calculation
59 */
60 chunk_t sent_init;
61
62 /**
63 * Reserved bytes of ID payload
64 */
65 char reserved[3];
66
67 /**
68 * Current EAP method processing
69 */
70 eap_method_t *method;
71
72 /**
73 * MSK used to build and verify auth payload
74 */
75 chunk_t msk;
76
77 /**
78 * EAP authentication method completed successfully
79 */
80 bool eap_complete;
81
82 /**
83 * Set if we require mutual EAP due EAP-only authentication
84 */
85 bool require_mutual;
86
87 /**
88 * authentication payload verified successfully
89 */
90 bool auth_complete;
91
92 /**
93 * generated EAP payload
94 */
95 eap_payload_t *eap_payload;
96
97 /**
98 * EAP identity of peer
99 */
100 identification_t *eap_identity;
101 };
102
103 /**
104 * load an EAP method
105 */
106 static eap_method_t *load_method(private_eap_authenticator_t *this,
107 eap_type_t type, u_int32_t vendor, eap_role_t role)
108 {
109 identification_t *server, *peer, *aaa;
110 auth_cfg_t *auth;
111
112 if (role == EAP_SERVER)
113 {
114 server = this->ike_sa->get_my_id(this->ike_sa);
115 peer = this->ike_sa->get_other_id(this->ike_sa);
116 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
117 }
118 else
119 {
120 server = this->ike_sa->get_other_id(this->ike_sa);
121 peer = this->ike_sa->get_my_id(this->ike_sa);
122 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
123 }
124 if (this->eap_identity)
125 {
126 peer = this->eap_identity;
127 }
128 aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY);
129 if (aaa)
130 {
131 server = aaa;
132 }
133 return charon->eap->create_instance(charon->eap, type, vendor,
134 role, server, peer);
135 }
136
137 /**
138 * Initiate EAP conversation as server
139 */
140 static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
141 bool do_identity)
142 {
143 auth_cfg_t *auth;
144 eap_type_t type;
145 identification_t *id;
146 u_int32_t vendor;
147 eap_payload_t *out;
148 char *action;
149
150 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
151
152 /* initiate EAP-Identity exchange if required */
153 if (!this->eap_identity && do_identity)
154 {
155 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
156 if (id)
157 {
158 if (id->get_type(id) == ID_ANY)
159 {
160 this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
161 if (this->method)
162 {
163 if (this->method->initiate(this->method, &out) == NEED_MORE)
164 {
165 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)",
166 eap_type_names, EAP_IDENTITY,
167 this->method->get_identifier(this->method));
168 return out;
169 }
170 this->method->destroy(this->method);
171 }
172 DBG1(DBG_IKE, "EAP-Identity request configured, "
173 "but not supported");
174 }
175 else
176 {
177 DBG1(DBG_IKE, "using configured EAP-Identity %Y", id);
178 this->eap_identity = id->clone(id);
179 }
180 }
181 }
182 /* invoke real EAP method */
183 type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
184 vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
185 action = "loading";
186 this->method = load_method(this, type, vendor, EAP_SERVER);
187 if (this->method)
188 {
189 action = "initiating";
190 if (this->method->initiate(this->method, &out) == NEED_MORE)
191 {
192 type = this->method->get_type(this->method, &vendor);
193 if (vendor)
194 {
195 DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)",
196 type, vendor, out->get_identifier(out));
197 }
198 else
199 {
200 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names,
201 type, out->get_identifier(out));
202 }
203 return out;
204 }
205 /* type might have changed for virtual methods */
206 type = this->method->get_type(this->method, &vendor);
207 }
208 if (vendor)
209 {
210 DBG1(DBG_IKE, "%s EAP vendor type %d-%d method failed",
211 action, type, vendor);
212 }
213 else
214 {
215 DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type);
216 }
217 return eap_payload_create_code(EAP_FAILURE, 0);
218 }
219
220 /**
221 * Replace the existing EAP-Identity in other auth config
222 */
223 static void replace_eap_identity(private_eap_authenticator_t *this)
224 {
225 identification_t *eap_identity;
226 auth_cfg_t *cfg;
227
228 eap_identity = this->eap_identity->clone(this->eap_identity);
229 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
230 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity);
231 }
232
233 /**
234 * Handle EAP exchange as server
235 */
236 static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
237 eap_payload_t *in)
238 {
239 eap_type_t type, received_type, conf_type;
240 u_int32_t vendor, received_vendor, conf_vendor;
241 eap_payload_t *out;
242 auth_cfg_t *auth;
243
244 if (in->get_code(in) != EAP_RESPONSE)
245 {
246 DBG1(DBG_IKE, "received %N, sending %N",
247 eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
248 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
249 }
250
251 type = this->method->get_type(this->method, &vendor);
252 received_type = in->get_type(in, &received_vendor);
253 if (type != received_type || vendor != received_vendor)
254 {
255 if (received_vendor == 0 && received_type == EAP_NAK)
256 {
257 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
258 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
259 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
260 if ((type == EAP_IDENTITY && !vendor) ||
261 (type == conf_type && vendor == conf_vendor))
262 {
263 DBG1(DBG_IKE, "received %N, sending %N",
264 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
265 return eap_payload_create_code(EAP_FAILURE,
266 in->get_identifier(in));
267 }
268 /* virtual methods handle NAKs in process() */
269 }
270 else
271 {
272 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
273 eap_code_names, EAP_FAILURE);
274 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
275 }
276 }
277
278 switch (this->method->process(this->method, in, &out))
279 {
280 case NEED_MORE:
281 return out;
282 case SUCCESS:
283 if (!vendor && type == EAP_IDENTITY)
284 {
285 chunk_t data;
286
287 if (this->method->get_msk(this->method, &data) == SUCCESS)
288 {
289 this->eap_identity = identification_create_from_data(data);
290 DBG1(DBG_IKE, "received EAP identity '%Y'",
291 this->eap_identity);
292 replace_eap_identity(this);
293 }
294 /* restart EAP exchange, but with real method */
295 this->method->destroy(this->method);
296 return server_initiate_eap(this, FALSE);
297 }
298 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
299 {
300 this->msk = chunk_clone(this->msk);
301 }
302 if (vendor)
303 {
304 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
305 "%sMSK established", type, vendor,
306 this->msk.ptr ? "" : "no ");
307 }
308 else
309 {
310 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
311 eap_type_names, type, this->msk.ptr ? "" : "no ");
312 }
313 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
314 TRUE);
315 this->eap_complete = TRUE;
316 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
317 case FAILED:
318 default:
319 /* type might have changed for virtual methods */
320 type = this->method->get_type(this->method, &vendor);
321 if (vendor)
322 {
323 DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
324 "peer %Y", type, vendor,
325 this->ike_sa->get_other_id(this->ike_sa));
326 }
327 else
328 {
329 DBG1(DBG_IKE, "EAP method %N failed for peer %Y",
330 eap_type_names, type,
331 this->ike_sa->get_other_id(this->ike_sa));
332 }
333 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
334 }
335 }
336
337 /**
338 * Processing method for a peer
339 */
340 static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
341 eap_payload_t *in)
342 {
343 eap_type_t type, conf_type;
344 u_int32_t vendor, conf_vendor;
345 auth_cfg_t *auth;
346 eap_payload_t *out;
347 identification_t *id;
348
349 type = in->get_type(in, &vendor);
350
351 if (!vendor && type == EAP_IDENTITY)
352 {
353 DESTROY_IF(this->eap_identity);
354 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
355 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
356 if (!id || id->get_type(id) == ID_ANY)
357 {
358 id = this->ike_sa->get_my_id(this->ike_sa);
359 }
360 DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'",
361 eap_type_names, type, in->get_identifier(in), id);
362 this->eap_identity = id->clone(id);
363
364 this->method = load_method(this, type, vendor, EAP_PEER);
365 if (this->method)
366 {
367 if (this->method->process(this->method, in, &out) == SUCCESS)
368 {
369 this->method->destroy(this->method);
370 this->method = NULL;
371 return out;
372 }
373 this->method->destroy(this->method);
374 this->method = NULL;
375 }
376 /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
377 * EAP method (types 3-253, 255) */
378 DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
379 eap_type_names, type);
380 return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE);
381 }
382 if (this->method == NULL)
383 {
384 if (vendor)
385 {
386 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ",
387 "(id 0x%02X)", type, vendor, in->get_identifier(in));
388 }
389 else
390 {
391 DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
392 eap_type_names, type, in->get_identifier(in));
393 }
394 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
395 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
396 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
397 if (conf_type != EAP_NAK &&
398 (conf_type != type || conf_vendor != vendor))
399 {
400 if (conf_vendor)
401 {
402 DBG1(DBG_IKE, "requesting EAP method %d-%d, sending EAP_NAK",
403 conf_type, conf_vendor);
404 }
405 else
406 {
407 DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK",
408 eap_type_names, conf_type);
409 }
410 return eap_payload_create_nak(in->get_identifier(in), conf_type,
411 conf_vendor, in->is_expanded(in));
412 }
413 this->method = load_method(this, type, vendor, EAP_PEER);
414 if (!this->method)
415 {
416 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
417 return eap_payload_create_nak(in->get_identifier(in), 0, 0,
418 in->is_expanded(in));
419 }
420 }
421
422 type = this->method->get_type(this->method, &vendor);
423
424 if (this->method->process(this->method, in, &out) == NEED_MORE)
425 { /* client methods should never return SUCCESS */
426 return out;
427 }
428
429 if (vendor)
430 {
431 DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
432 }
433 else
434 {
435 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
436 }
437 return NULL;
438 }
439
440 /**
441 * Verify AUTH payload
442 */
443 static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
444 chunk_t nonce, chunk_t init)
445 {
446 auth_payload_t *auth_payload;
447 chunk_t auth_data, recv_auth_data;
448 identification_t *other_id;
449 auth_cfg_t *auth;
450 keymat_v2_t *keymat;
451
452 auth_payload = (auth_payload_t*)message->get_payload(message,
453 PLV2_AUTH);
454 if (!auth_payload)
455 {
456 DBG1(DBG_IKE, "AUTH payload missing");
457 return FALSE;
458 }
459 other_id = this->ike_sa->get_other_id(this->ike_sa);
460 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
461 if (!keymat->get_psk_sig(keymat, TRUE, init, nonce,
462 this->msk, other_id, this->reserved, &auth_data))
463 {
464 return FALSE;
465 }
466 recv_auth_data = auth_payload->get_data(auth_payload);
467 if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
468 {
469 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
470 this->msk.ptr ? "" : "out");
471 chunk_free(&auth_data);
472 return FALSE;
473 }
474 chunk_free(&auth_data);
475
476 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
477 other_id, auth_class_names, AUTH_CLASS_EAP);
478 this->auth_complete = TRUE;
479 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
480 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
481 return TRUE;
482 }
483
484 /**
485 * Build AUTH payload
486 */
487 static bool build_auth(private_eap_authenticator_t *this, message_t *message,
488 chunk_t nonce, chunk_t init)
489 {
490 auth_payload_t *auth_payload;
491 identification_t *my_id;
492 chunk_t auth_data;
493 keymat_v2_t *keymat;
494
495 my_id = this->ike_sa->get_my_id(this->ike_sa);
496 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
497
498 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
499 my_id, auth_class_names, AUTH_CLASS_EAP);
500
501 if (!keymat->get_psk_sig(keymat, FALSE, init, nonce,
502 this->msk, my_id, this->reserved, &auth_data))
503 {
504 return FALSE;
505 }
506 auth_payload = auth_payload_create();
507 auth_payload->set_auth_method(auth_payload, AUTH_PSK);
508 auth_payload->set_data(auth_payload, auth_data);
509 message->add_payload(message, (payload_t*)auth_payload);
510 chunk_free(&auth_data);
511 return TRUE;
512 }
513
514 METHOD(authenticator_t, process_server, status_t,
515 private_eap_authenticator_t *this, message_t *message)
516 {
517 eap_payload_t *eap_payload;
518
519 if (this->eap_complete)
520 {
521 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
522 {
523 return FAILED;
524 }
525 return NEED_MORE;
526 }
527
528 if (!this->method)
529 {
530 this->eap_payload = server_initiate_eap(this, TRUE);
531 }
532 else
533 {
534 eap_payload = (eap_payload_t*)message->get_payload(message,
535 PLV2_EAP);
536 if (!eap_payload)
537 {
538 return FAILED;
539 }
540 this->eap_payload = server_process_eap(this, eap_payload);
541 }
542 return NEED_MORE;
543 }
544
545 METHOD(authenticator_t, build_server, status_t,
546 private_eap_authenticator_t *this, message_t *message)
547 {
548 if (this->eap_payload)
549 {
550 eap_code_t code;
551
552 code = this->eap_payload->get_code(this->eap_payload);
553 message->add_payload(message, (payload_t*)this->eap_payload);
554 this->eap_payload = NULL;
555 if (code == EAP_FAILURE)
556 {
557 return FAILED;
558 }
559 return NEED_MORE;
560 }
561 if (this->eap_complete && this->auth_complete &&
562 build_auth(this, message, this->received_nonce, this->sent_init))
563 {
564 return SUCCESS;
565 }
566 return FAILED;
567 }
568
569 METHOD(authenticator_t, process_client, status_t,
570 private_eap_authenticator_t *this, message_t *message)
571 {
572 eap_payload_t *eap_payload;
573
574 if (this->eap_complete)
575 {
576 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
577 {
578 return FAILED;
579 }
580 if (this->require_mutual && !this->method->is_mutual(this->method))
581 { /* we require mutual authentication due to EAP-only */
582 u_int32_t vendor;
583
584 DBG1(DBG_IKE, "EAP-only authentication requires a mutual and "
585 "MSK deriving EAP method, but %N is not",
586 eap_type_names, this->method->get_type(this->method, &vendor));
587 return FAILED;
588 }
589 return SUCCESS;
590 }
591
592 eap_payload = (eap_payload_t*)message->get_payload(message,
593 PLV2_EAP);
594 if (eap_payload)
595 {
596 switch (eap_payload->get_code(eap_payload))
597 {
598 case EAP_REQUEST:
599 {
600 this->eap_payload = client_process_eap(this, eap_payload);
601 if (this->eap_payload)
602 {
603 return NEED_MORE;
604 }
605 return FAILED;
606 }
607 case EAP_SUCCESS:
608 {
609 eap_type_t type;
610 u_int32_t vendor;
611 auth_cfg_t *cfg;
612
613 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
614 {
615 this->msk = chunk_clone(this->msk);
616 }
617 type = this->method->get_type(this->method, &vendor);
618 if (vendor)
619 {
620 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
621 "%sMSK established", type, vendor,
622 this->msk.ptr ? "" : "no ");
623 }
624 else
625 {
626 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
627 eap_type_names, type, this->msk.ptr ? "" : "no ");
628 }
629 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
630 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
631 if (vendor)
632 {
633 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
634 }
635 this->eap_complete = TRUE;
636 return NEED_MORE;
637 }
638 case EAP_FAILURE:
639 default:
640 {
641 DBG1(DBG_IKE, "received %N, EAP authentication failed",
642 eap_code_names, eap_payload->get_code(eap_payload));
643 return FAILED;
644 }
645 }
646 }
647 return FAILED;
648 }
649
650 METHOD(authenticator_t, build_client, status_t,
651 private_eap_authenticator_t *this, message_t *message)
652 {
653 if (this->eap_payload)
654 {
655 message->add_payload(message, (payload_t*)this->eap_payload);
656 this->eap_payload = NULL;
657 return NEED_MORE;
658 }
659 if (this->eap_complete &&
660 build_auth(this, message, this->received_nonce, this->sent_init))
661 {
662 return NEED_MORE;
663 }
664 return NEED_MORE;
665 }
666
667 METHOD(authenticator_t, is_mutual, bool,
668 private_eap_authenticator_t *this)
669 {
670 if (this->method)
671 {
672 u_int32_t vendor;
673
674 if (this->method->get_type(this->method, &vendor) != EAP_IDENTITY ||
675 vendor != 0)
676 {
677 return this->method->is_mutual(this->method);
678 }
679 }
680 /* we don't know yet, but insist on it after EAP is complete */
681 this->require_mutual = TRUE;
682 return TRUE;
683 }
684
685 METHOD(authenticator_t, destroy, void,
686 private_eap_authenticator_t *this)
687 {
688 DESTROY_IF(this->method);
689 DESTROY_IF(this->eap_payload);
690 DESTROY_IF(this->eap_identity);
691 chunk_free(&this->msk);
692 free(this);
693 }
694
695 /*
696 * Described in header.
697 */
698 eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
699 chunk_t received_nonce, chunk_t sent_nonce,
700 chunk_t received_init, chunk_t sent_init,
701 char reserved[3])
702 {
703 private_eap_authenticator_t *this;
704
705 INIT(this,
706 .public = {
707 .authenticator = {
708 .build = _build_client,
709 .process = _process_client,
710 .is_mutual = _is_mutual,
711 .destroy = _destroy,
712 },
713 },
714 .ike_sa = ike_sa,
715 .received_init = received_init,
716 .received_nonce = received_nonce,
717 .sent_init = sent_init,
718 .sent_nonce = sent_nonce,
719 );
720 memcpy(this->reserved, reserved, sizeof(this->reserved));
721
722 return &this->public;
723 }
724
725 /*
726 * Described in header.
727 */
728 eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
729 chunk_t received_nonce, chunk_t sent_nonce,
730 chunk_t received_init, chunk_t sent_init,
731 char reserved[3])
732 {
733 private_eap_authenticator_t *this;
734
735 INIT(this,
736 .public = {
737 .authenticator = {
738 .build = _build_server,
739 .process = _process_server,
740 .is_mutual = _is_mutual,
741 .destroy = _destroy,
742 },
743 },
744 .ike_sa = ike_sa,
745 .received_init = received_init,
746 .received_nonce = received_nonce,
747 .sent_init = sent_init,
748 .sent_nonce = sent_nonce,
749 );
750 memcpy(this->reserved, reserved, sizeof(this->reserved));
751
752 return &this->public;
753 }