1 /* 2 * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions 3 * Copyright (c) 2004-2006, Jouni Malinen <j (at) 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 #include "eap_tls_common.h" 20 #include "config_ssid.h" 21 #include "md5.h" 22 #include "sha1.h" 23 #include "tls.h" 24 #include "config.h" 25 26 static int eap_tls_check_blob(struct eap_sm *sm, const char **name, 27 const u8 **data, size_t *data_len) 28 { 29 const struct wpa_config_blob *blob; 30 31 if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) 32 return 0; 33 34 blob = eap_get_config_blob(sm, *name + 7); 35 if (blob == NULL) { 36 wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " 37 "found", __func__, *name + 7); 38 return -1; 39 } 40 *name = NULL; 41 *data = blob->data; 42 *data_len = blob->len; 43 44 return 0; 45 } 46 47 48 static void eap_tls_params_from_conf1(struct tls_connection_params *params, 49 struct wpa_ssid *config) 50 { 51 params->ca_cert = (char *) config->ca_cert; 52 params->ca_path = (char *) config->ca_path; 53 params->client_cert = (char *) config->client_cert; 54 params->private_key = (char *) config->private_key; 55 params->private_key_passwd = (char *) config->private_key_passwd; 56 params->dh_file = (char *) config->dh_file; 57 params->subject_match = (char *) config->subject_match; 58 params->altsubject_match = (char *) config->altsubject_match; 59 params->engine_id = config->engine_id; 60 params->pin = config->pin; 61 params->key_id = config->key_id; 62 } 63 64 65 static void eap_tls_params_from_conf2(struct tls_connection_params *params, 66 struct wpa_ssid *config) 67 { 68 params->ca_cert = (char *) config->ca_cert2; 69 params->ca_path = (char *) config->ca_path2; 70 params->client_cert = (char *) config->client_cert2; 71 params->private_key = (char *) config->private_key2; 72 params->private_key_passwd = (char *) config->private_key2_passwd; 73 params->dh_file = (char *) config->dh_file2; 74 params->subject_match = (char *) config->subject_match2; 75 params->altsubject_match = (char *) config->altsubject_match2; 76 } 77 78 79 static int eap_tls_params_from_conf(struct eap_sm *sm, 80 struct eap_ssl_data *data, 81 struct tls_connection_params *params, 82 struct wpa_ssid *config, int phase2) 83 { 84 os_memset(params, 0, sizeof(*params)); 85 params->engine = config->engine; 86 if (phase2) 87 eap_tls_params_from_conf2(params, config); 88 else 89 eap_tls_params_from_conf1(params, config); 90 params->tls_ia = data->tls_ia; 91 92 93 if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, 94 ¶ms->ca_cert_blob_len) || 95 eap_tls_check_blob(sm, ¶ms->client_cert, 96 ¶ms->client_cert_blob, 97 ¶ms->client_cert_blob_len) || 98 eap_tls_check_blob(sm, ¶ms->private_key, 99 ¶ms->private_key_blob, 100 ¶ms->private_key_blob_len) || 101 eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, 102 ¶ms->dh_blob_len)) { 103 wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); 104 return -1; 105 } 106 107 return 0; 108 } 109 110 111 static int eap_tls_init_connection(struct eap_sm *sm, 112 struct eap_ssl_data *data, 113 struct wpa_ssid *config, 114 struct tls_connection_params *params) 115 { 116 int res; 117 118 data->conn = tls_connection_init(sm->ssl_ctx); 119 if (data->conn == NULL) { 120 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 121 "connection"); 122 return -1; 123 } 124 125 res = tls_connection_set_params(sm->ssl_ctx, data->conn, params); 126 if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { 127 /* At this point with the pkcs11 engine the PIN might be wrong. 128 * We reset the PIN in the configuration to be sure to not use 129 * it again and the calling function must request a new one */ 130 os_free(config->pin); 131 config->pin = NULL; 132 } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { 133 wpa_printf(MSG_INFO, "TLS: Failed to load private key"); 134 /* We don't know exactly but maybe the PIN was wrong, 135 * so ask for a new one. */ 136 os_free(config->pin); 137 config->pin = NULL; 138 eap_sm_request_pin(sm); 139 sm->ignore = TRUE; 140 return -1; 141 } else if (res) { 142 wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " 143 "parameters"); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 151 /** 152 * eap_tls_ssl_init - Initialize shared TLS functionality 153 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 154 * @data: Data for TLS processing 155 * @config: Pointer to the network configuration 156 * Returns: 0 on success, -1 on failure 157 * 158 * This function is used to initialize shared TLS functionality for EAP-TLS, 159 * EAP-PEAP, EAP-TTLS, and EAP-FAST. 160 */ 161 int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 162 struct wpa_ssid *config) 163 { 164 int ret = -1; 165 struct tls_connection_params params; 166 167 if (config == NULL) 168 return -1; 169 170 data->eap = sm; 171 data->phase2 = sm->init_phase2; 172 if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < 173 0) 174 goto done; 175 176 if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) 177 goto done; 178 179 data->tls_out_limit = config->fragment_size; 180 if (data->phase2) { 181 /* Limit the fragment size in the inner TLS authentication 182 * since the outer authentication with EAP-PEAP does not yet 183 * support fragmentation */ 184 if (data->tls_out_limit > 100) 185 data->tls_out_limit -= 100; 186 } 187 188 if (config->phase1 && 189 os_strstr(config->phase1, "include_tls_length=1")) { 190 wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " 191 "unfragmented packets"); 192 data->include_tls_length = 1; 193 } 194 195 ret = 0; 196 197 done: 198 return ret; 199 } 200 201 202 /** 203 * eap_tls_ssl_deinit - Deinitialize shared TLS functionality 204 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 205 * @data: Data for TLS processing 206 * 207 * This function deinitializes shared TLS functionality that was initialized 208 * with eap_tls_ssl_init(). 209 */ 210 void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 211 { 212 tls_connection_deinit(sm->ssl_ctx, data->conn); 213 os_free(data->tls_in); 214 os_free(data->tls_out); 215 } 216 217 218 /** 219 * eap_tls_derive_key - Derive a key based on TLS session data 220 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 221 * @data: Data for TLS processing 222 * @label: Label string for deriving the keys, e.g., "client EAP encryption" 223 * @len: Length of the key material to generate (usually 64 for MSK) 224 * Returns: Pointer to allocated key on success or %NULL on failure 225 * 226 * This function uses TLS-PRF to generate pseudo-random data based on the TLS 227 * session data (client/server random and master key). Each key type may use a 228 * different label to bind the key usage into the generated material. 229 * 230 * The caller is responsible for freeing the returned buffer. 231 */ 232 u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 233 const char *label, size_t len) 234 { 235 struct tls_keys keys; 236 u8 *rnd = NULL, *out; 237 238 out = os_malloc(len); 239 if (out == NULL) 240 return NULL; 241 242 /* First, try to use TLS library function for PRF, if available. */ 243 if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == 244 0) 245 return out; 246 247 /* 248 * TLS library did not support key generation, so get the needed TLS 249 * session parameters and use an internal implementation of TLS PRF to 250 * derive the key. 251 */ 252 if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) 253 goto fail; 254 255 if (keys.client_random == NULL || keys.server_random == NULL || 256 keys.master_key == NULL) 257 goto fail; 258 259 rnd = os_malloc(keys.client_random_len + keys.server_random_len); 260 if (rnd == NULL) 261 goto fail; 262 os_memcpy(rnd, keys.client_random, keys.client_random_len); 263 os_memcpy(rnd + keys.client_random_len, keys.server_random, 264 keys.server_random_len); 265 266 if (tls_prf(keys.master_key, keys.master_key_len, 267 label, rnd, keys.client_random_len + 268 keys.server_random_len, out, len)) 269 goto fail; 270 271 os_free(rnd); 272 return out; 273 274 fail: 275 os_free(out); 276 os_free(rnd); 277 return NULL; 278 } 279 280 281 /** 282 * eap_tls_data_reassemble - Reassemble TLS data 283 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 284 * @data: Data for TLS processing 285 * @in_data: Next incoming TLS segment 286 * @in_len: Length of in_data 287 * @out_len: Variable for returning output data length 288 * @need_more_input: Variable for returning whether more input data is needed 289 * to reassemble this TLS packet 290 * Returns: Pointer to output data, %NULL on error or when more data is needed 291 * for the full message (in which case, *need_more_input is also set to 1). 292 * 293 * This function reassembles TLS fragments. Caller must not free the returned 294 * data buffer since an internal pointer to it is maintained. 295 */ 296 const u8 * eap_tls_data_reassemble( 297 struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data, 298 size_t in_len, size_t *out_len, int *need_more_input) 299 { 300 u8 *buf; 301 302 *need_more_input = 0; 303 304 if (data->tls_in_left > in_len || data->tls_in) { 305 if (data->tls_in_len + in_len == 0) { 306 os_free(data->tls_in); 307 data->tls_in = NULL; 308 data->tls_in_len = 0; 309 wpa_printf(MSG_WARNING, "SSL: Invalid reassembly " 310 "state: tls_in_left=%lu tls_in_len=%lu " 311 "in_len=%lu", 312 (unsigned long) data->tls_in_left, 313 (unsigned long) data->tls_in_len, 314 (unsigned long) in_len); 315 return NULL; 316 } 317 if (data->tls_in_len + in_len > 65536) { 318 /* Limit length to avoid rogue servers from causing 319 * large memory allocations. */ 320 os_free(data->tls_in); 321 data->tls_in = NULL; 322 data->tls_in_len = 0; 323 wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" 324 " over 64 kB)"); 325 return NULL; 326 } 327 buf = os_realloc(data->tls_in, data->tls_in_len + in_len); 328 if (buf == NULL) { 329 os_free(data->tls_in); 330 data->tls_in = NULL; 331 data->tls_in_len = 0; 332 wpa_printf(MSG_INFO, "SSL: Could not allocate memory " 333 "for TLS data"); 334 return NULL; 335 } 336 os_memcpy(buf + data->tls_in_len, in_data, in_len); 337 data->tls_in = buf; 338 data->tls_in_len += in_len; 339 if (in_len > data->tls_in_left) { 340 wpa_printf(MSG_INFO, "SSL: more data than TLS message " 341 "length indicated"); 342 data->tls_in_left = 0; 343 return NULL; 344 } 345 data->tls_in_left -= in_len; 346 if (data->tls_in_left > 0) { 347 wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " 348 "data", (unsigned long) data->tls_in_left); 349 *need_more_input = 1; 350 return NULL; 351 } 352 } else { 353 data->tls_in_left = 0; 354 data->tls_in = os_malloc(in_len ? in_len : 1); 355 if (data->tls_in == NULL) 356 return NULL; 357 os_memcpy(data->tls_in, in_data, in_len); 358 data->tls_in_len = in_len; 359 } 360 361 *out_len = data->tls_in_len; 362 return data->tls_in; 363 } 364 365 366 static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, 367 const u8 *in_data, size_t in_len, 368 u8 **out_data, size_t *out_len) 369 { 370 const u8 *msg; 371 size_t msg_len; 372 int need_more_input; 373 u8 *appl_data; 374 size_t appl_data_len; 375 376 msg = eap_tls_data_reassemble(sm, data, in_data, in_len, 377 &msg_len, &need_more_input); 378 if (msg == NULL) 379 return need_more_input ? 1 : -1; 380 381 /* Full TLS message reassembled - continue handshake processing */ 382 if (data->tls_out) { 383 /* This should not happen.. */ 384 wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - pending " 385 "tls_out data even though tls_out_len = 0"); 386 os_free(data->tls_out); 387 WPA_ASSERT(data->tls_out == NULL); 388 } 389 appl_data = NULL; 390 data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, 391 msg, msg_len, 392 &data->tls_out_len, 393 &appl_data, &appl_data_len); 394 395 /* Clear reassembled input data (if the buffer was needed). */ 396 data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; 397 os_free(data->tls_in); 398 data->tls_in = NULL; 399 400 if (appl_data && 401 tls_connection_established(sm->ssl_ctx, data->conn) && 402 !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 403 wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data", 404 appl_data, appl_data_len); 405 *out_data = appl_data; 406 *out_len = appl_data_len; 407 return 2; 408 } 409 410 os_free(appl_data); 411 412 return 0; 413 } 414 415 416 static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, 417 int peap_version, u8 id, int ret, 418 u8 **out_data, size_t *out_len) 419 { 420 size_t len; 421 u8 *pos, *flags; 422 int more_fragments, length_included; 423 424 wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " 425 "%lu bytes)", 426 (unsigned long) data->tls_out_len - data->tls_out_pos, 427 (unsigned long) data->tls_out_len); 428 429 len = data->tls_out_len - data->tls_out_pos; 430 if (len > data->tls_out_limit) { 431 more_fragments = 1; 432 len = data->tls_out_limit; 433 wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " 434 "will follow", (unsigned long) len); 435 } else 436 more_fragments = 0; 437 438 length_included = data->tls_out_pos == 0 && 439 (data->tls_out_len > data->tls_out_limit || 440 data->include_tls_length); 441 442 *out_data = (u8 *) 443 eap_msg_alloc(EAP_VENDOR_IETF, eap_type, out_len, 444 1 + length_included * 4 + len, EAP_CODE_RESPONSE, 445 id, &pos); 446 if (*out_data == NULL) 447 return -1; 448 449 flags = pos++; 450 *flags = peap_version; 451 if (more_fragments) 452 *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 453 if (length_included) { 454 *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 455 WPA_PUT_BE32(pos, data->tls_out_len); 456 pos += 4; 457 } 458 459 os_memcpy(pos, &data->tls_out[data->tls_out_pos], len); 460 data->tls_out_pos += len; 461 462 if (!more_fragments) { 463 data->tls_out_len = 0; 464 data->tls_out_pos = 0; 465 os_free(data->tls_out); 466 data->tls_out = NULL; 467 } 468 469 return ret; 470 } 471 472 473 /** 474 * eap_tls_process_helper - Process TLS handshake message 475 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 476 * @data: Data for TLS processing 477 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 478 * @peap_version: Version number for EAP-PEAP/TTLS 479 * @id: EAP identifier for the response 480 * @in_data: Message received from the server 481 * @in_len: Length of in_data 482 * @out_data: Buffer for returning a pointer to the response message 483 * @out_len: Buffer for returning the length of the response message 484 * Returns: 0 on success, 1 if more input data is needed, or -1 on failure 485 * 486 * This function can be used to process TLS handshake messages. It reassembles 487 * the received fragments and uses a TLS library to process the messages. The 488 * response data from the TLS library is fragmented to suitable output messages 489 * that the caller can send out. 490 * 491 * out_data is used to return the response message if the return value of this 492 * function is 0 or -1. In case of failure, the message is likely a TLS alarm 493 * message. The caller is responsible for freeing the allocated buffer if 494 * *out_data is not %NULL. 495 */ 496 int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, 497 EapType eap_type, int peap_version, 498 u8 id, const u8 *in_data, size_t in_len, 499 u8 **out_data, size_t *out_len) 500 { 501 int ret = 0; 502 503 WPA_ASSERT(data->tls_out_len == 0 || in_len == 0); 504 *out_len = 0; 505 *out_data = NULL; 506 507 if (data->tls_out_len == 0) { 508 /* No more data to send out - expect to receive more data from 509 * the AS. */ 510 int res = eap_tls_process_input(sm, data, in_data, in_len, 511 out_data, out_len); 512 if (res) 513 return res; 514 } 515 516 if (data->tls_out == NULL) { 517 data->tls_out_len = 0; 518 return -1; 519 } 520 521 if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 522 wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 523 "report error"); 524 ret = -1; 525 /* TODO: clean pin if engine used? */ 526 } 527 528 if (data->tls_out_len == 0) { 529 /* TLS negotiation should now be complete since all other cases 530 * needing more data should have been caught above based on 531 * the TLS Message Length field. */ 532 wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); 533 os_free(data->tls_out); 534 data->tls_out = NULL; 535 return 1; 536 } 537 538 return eap_tls_process_output(data, eap_type, peap_version, id, ret, 539 out_data, out_len); 540 } 541 542 543 /** 544 * eap_tls_build_ack - Build a TLS ACK frames 545 * @data: Data for TLS processing 546 * @respDataLen: Buffer for returning the length of the response message 547 * @id: EAP identifier for the response 548 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 549 * @peap_version: Version number for EAP-PEAP/TTLS 550 * Returns: Pointer to allocated ACK frames or %NULL on failure 551 */ 552 u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id, 553 EapType eap_type, int peap_version) 554 { 555 struct eap_hdr *resp; 556 u8 *pos; 557 558 resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, respDataLen, 559 1, EAP_CODE_RESPONSE, id, &pos); 560 if (resp == NULL) 561 return NULL; 562 wpa_printf(MSG_DEBUG, "SSL: Building ACK"); 563 *pos = peap_version; /* Flags */ 564 return (u8 *) resp; 565 } 566 567 568 /** 569 * eap_tls_reauth_init - Re-initialize shared TLS for session resumption 570 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 571 * @data: Data for TLS processing 572 * Returns: 0 on success, -1 on failure 573 */ 574 int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) 575 { 576 os_free(data->tls_in); 577 data->tls_in = NULL; 578 data->tls_in_len = data->tls_in_left = data->tls_in_total = 0; 579 os_free(data->tls_out); 580 data->tls_out = NULL; 581 data->tls_out_len = data->tls_out_pos = 0; 582 583 return tls_connection_shutdown(sm->ssl_ctx, data->conn); 584 } 585 586 587 /** 588 * eap_tls_status - Get TLS status 589 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 590 * @data: Data for TLS processing 591 * @buf: Buffer for status information 592 * @buflen: Maximum buffer length 593 * @verbose: Whether to include verbose status information 594 * Returns: Number of bytes written to buf. 595 */ 596 int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf, 597 size_t buflen, int verbose) 598 { 599 char name[128]; 600 int len = 0, ret; 601 602 if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) { 603 ret = os_snprintf(buf + len, buflen - len, 604 "EAP TLS cipher=%s\n", name); 605 if (ret < 0 || (size_t) ret >= buflen - len) 606 return len; 607 len += ret; 608 } 609 610 return len; 611 } 612 613 614 /** 615 * eap_tls_process_init - Initial validation and processing of EAP requests 616 * @sm: Pointer to EAP state machine allocated with eap_sm_init() 617 * @data: Data for TLS processing 618 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) 619 * @ret: Return values from EAP request validation and processing 620 * @reqData: EAP request to be processed (eapReqData) 621 * @reqDataLen: Length of the EAP request 622 * @len: Buffer for returning length of the remaining payload 623 * @flags: Buffer for returning TLS flags 624 * Returns: Buffer to payload after TLS flags and length or %NULL on failure 625 */ 626 const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data, 627 EapType eap_type, struct eap_method_ret *ret, 628 const u8 *reqData, size_t reqDataLen, 629 size_t *len, u8 *flags) 630 { 631 const u8 *pos; 632 size_t left; 633 unsigned int tls_msg_len; 634 635 if (tls_get_errors(sm->ssl_ctx)) { 636 wpa_printf(MSG_INFO, "SSL: TLS errors detected"); 637 ret->ignore = TRUE; 638 return NULL; 639 } 640 641 pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, reqDataLen, 642 &left); 643 if (pos == NULL) { 644 ret->ignore = TRUE; 645 return NULL; 646 } 647 *flags = *pos++; 648 left--; 649 wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " 650 "Flags 0x%02x", (unsigned long) reqDataLen, *flags); 651 if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 652 if (left < 4) { 653 wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 654 "length"); 655 ret->ignore = TRUE; 656 return NULL; 657 } 658 tls_msg_len = WPA_GET_BE32(pos); 659 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 660 tls_msg_len); 661 if (data->tls_in_left == 0) { 662 data->tls_in_total = tls_msg_len; 663 data->tls_in_left = tls_msg_len; 664 os_free(data->tls_in); 665 data->tls_in = NULL; 666 data->tls_in_len = 0; 667 } 668 pos += 4; 669 left -= 4; 670 } 671 672 ret->ignore = FALSE; 673 ret->methodState = METHOD_MAY_CONT; 674 ret->decision = DECISION_FAIL; 675 ret->allowNotifications = TRUE; 676 677 *len = (size_t) left; 678 return pos; 679 } 680