Annotation of src/usr.bin/ssh/authfd.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2:
! 3: authfd.c
! 4:
! 5: Author: Tatu Ylonen <ylo@cs.hut.fi>
! 6:
! 7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
! 8: All rights reserved
! 9:
! 10: Created: Wed Mar 29 01:30:28 1995 ylo
! 11:
! 12: Functions for connecting the local authentication agent.
! 13:
! 14: */
! 15:
! 16: #include "includes.h"
! 17: RCSID("$Id: authfd.c,v 1.2 1999/05/04 11:58:26 bg Exp $");
! 18:
! 19: #include "ssh.h"
! 20: #include "rsa.h"
! 21: #include "authfd.h"
! 22: #include "buffer.h"
! 23: #include "bufaux.h"
! 24: #include "xmalloc.h"
! 25: #include "getput.h"
! 26:
! 27: /* Returns the number of the authentication fd, or -1 if there is none. */
! 28:
! 29: int ssh_get_authentication_fd()
! 30: {
! 31: const char *authfd, *authsocket;
! 32: int sock;
! 33: struct sockaddr_un sunaddr;
! 34:
! 35: /* Get the file descriptor number from environment. */
! 36: authfd = getenv(SSH_AUTHFD_ENV_NAME);
! 37:
! 38: /* Convert the value to an integer and return it if we got a value. */
! 39: if (authfd)
! 40: return atoi(authfd);
! 41:
! 42: authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
! 43: if (!authsocket)
! 44: return -1;
! 45:
! 46: sunaddr.sun_family = AF_UNIX;
! 47: strncpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
! 48:
! 49: sock = socket(AF_UNIX, SOCK_STREAM, 0);
! 50: if (sock < 0)
! 51: return -1;
! 52:
! 53: if (connect(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0)
! 54: {
! 55: close(sock);
! 56: return -1;
! 57: }
! 58:
! 59: return sock;
! 60: }
! 61:
! 62: /* Closes the agent socket if it should be closed (depends on how it was
! 63: obtained). The argument must have been returned by
! 64: ssh_get_authentication_fd(). */
! 65:
! 66: void ssh_close_authentication_socket(int sock)
! 67: {
! 68: if (getenv(SSH_AUTHSOCKET_ENV_NAME))
! 69: close(sock);
! 70: }
! 71:
! 72: /* Dummy alarm used to prevent waiting for connection from the
! 73: authentication agent indefinitely. */
! 74:
! 75: static RETSIGTYPE dummy_alarm_handler(int sig)
! 76: {
! 77: /* Do nothing; a cought signal will just cause accept to return. */
! 78: }
! 79:
! 80: /* Opens a socket to the authentication server. Returns the number of
! 81: that socket, or -1 if no connection could be made. */
! 82:
! 83: int ssh_get_authentication_connection_fd()
! 84: {
! 85: int authfd;
! 86: int listen_sock, sock, port, addrlen;
! 87: int old_timeout;
! 88: RETSIGTYPE (*old_handler)();
! 89: struct sockaddr_in sin;
! 90: char msg[3];
! 91:
! 92: /* Get the the socket number from the environment. This is the socket
! 93: used to obtain the real authentication socket. */
! 94: authfd = ssh_get_authentication_fd();
! 95: if (authfd == -1)
! 96: return -1;
! 97:
! 98: /* Create a local socket for listening. */
! 99: listen_sock = socket(AF_INET, SOCK_STREAM, 0);
! 100: if (listen_sock == -1)
! 101: {
! 102: ssh_close_authentication_socket(authfd);
! 103: return -1;
! 104: }
! 105:
! 106: /* Bind the socket to random unprivileged port. */
! 107: memset(&sin, 0, sizeof(sin));
! 108: sin.sin_family = AF_INET;
! 109: do
! 110: {
! 111: port = 32768 + (rand() % 30000);
! 112: sin.sin_port = htons(port);
! 113: }
! 114: while (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
! 115: errno == EADDRINUSE);
! 116:
! 117: /* Start listening for connections on the socket. */
! 118: if (listen(listen_sock, 1) < 0)
! 119: {
! 120: error("listen: %.100s", strerror(errno));
! 121: close(listen_sock);
! 122: ssh_close_authentication_socket(authfd);
! 123: return -1;
! 124: }
! 125:
! 126: /* Send a message to the authentication fd requesting the agent or its
! 127: local representative to connect to the given socket. Note that
! 128: we use send() to get the packet sent atomically (there can be several
! 129: clients trying to use the same authentication fd simultaneously). */
! 130: msg[0] = (char)SSH_AUTHFD_CONNECT;
! 131: PUT_16BIT(msg + 1, port);
! 132: if (send(authfd, msg, 3, 0) < 0)
! 133: {
! 134: shutdown(listen_sock, 2);
! 135: close(listen_sock);
! 136: ssh_close_authentication_socket(authfd);
! 137: return -1;
! 138: }
! 139:
! 140: /* Setup a timeout so we won't wait for the connection indefinitely. */
! 141: old_timeout = alarm(120);
! 142: old_handler = signal(SIGALRM, dummy_alarm_handler);
! 143:
! 144: /* Wait for the connection from the agent or its representative. */
! 145: addrlen = sizeof(sin);
! 146: sock = accept(listen_sock, (struct sockaddr *)&sin, &addrlen);
! 147:
! 148: /* Remove the alarm (restore its old values). */
! 149: alarm(old_timeout);
! 150: signal(SIGALRM, old_handler);
! 151:
! 152: /* Close the socket we used for listening. It is no longer needed.
! 153: (The authentication fd and the new connection still remain open.) */
! 154: shutdown(listen_sock, 2);
! 155: close(listen_sock);
! 156: ssh_close_authentication_socket(authfd);
! 157:
! 158: return sock;
! 159: }
! 160:
! 161: /* Opens and connects a private socket for communication with the
! 162: authentication agent. Returns the file descriptor (which must be
! 163: shut down and closed by the caller when no longer needed).
! 164: Returns NULL if an error occurred and the connection could not be
! 165: opened. */
! 166:
! 167: AuthenticationConnection *ssh_get_authentication_connection()
! 168: {
! 169: AuthenticationConnection *auth;
! 170: int sock;
! 171:
! 172: /* Get a connection to the authentication agent. */
! 173: sock = ssh_get_authentication_connection_fd();
! 174:
! 175: /* Fail if we couldn't obtain a connection. This happens if we exited
! 176: due to a timeout. */
! 177: if (sock < 0)
! 178: return NULL;
! 179:
! 180: /* Applocate the connection structure and initialize it. */
! 181: auth = xmalloc(sizeof(*auth));
! 182: auth->fd = sock;
! 183: buffer_init(&auth->packet);
! 184: buffer_init(&auth->identities);
! 185: auth->howmany = 0;
! 186:
! 187: return auth;
! 188: }
! 189:
! 190: /* Closes the connection to the authentication agent and frees any associated
! 191: memory. */
! 192:
! 193: void ssh_close_authentication_connection(AuthenticationConnection *ac)
! 194: {
! 195: buffer_free(&ac->packet);
! 196: buffer_free(&ac->identities);
! 197: close(ac->fd);
! 198: }
! 199:
! 200: /* Returns the first authentication identity held by the agent.
! 201: Returns true if an identity is available, 0 otherwise.
! 202: The caller must initialize the integers before the call, and free the
! 203: comment after a successful call (before calling ssh_get_next_identity). */
! 204:
! 205: int ssh_get_first_identity(AuthenticationConnection *auth,
! 206: int *bitsp, MP_INT *e, MP_INT *n, char **comment)
! 207: {
! 208: unsigned char msg[8192];
! 209: int len, l;
! 210:
! 211: /* Send a message to the agent requesting for a list of the identities
! 212: it can represent. */
! 213: msg[0] = 0;
! 214: msg[1] = 0;
! 215: msg[2] = 0;
! 216: msg[3] = 1;
! 217: msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
! 218: if (write(auth->fd, msg, 5) != 5)
! 219: {
! 220: error("write auth->fd: %.100s", strerror(errno));
! 221: return 0;
! 222: }
! 223:
! 224: /* Read the length of the response. XXX implement timeouts here. */
! 225: len = 4;
! 226: while (len > 0)
! 227: {
! 228: l = read(auth->fd, msg + 4 - len, len);
! 229: if (l <= 0)
! 230: {
! 231: error("read auth->fd: %.100s", strerror(errno));
! 232: return 0;
! 233: }
! 234: len -= l;
! 235: }
! 236:
! 237: /* Extract the length, and check it for sanity. (We cannot trust
! 238: authentication agents). */
! 239: len = GET_32BIT(msg);
! 240: if (len < 1 || len > 256*1024)
! 241: fatal("Authentication reply message too long: %d\n", len);
! 242:
! 243: /* Read the packet itself. */
! 244: buffer_clear(&auth->identities);
! 245: while (len > 0)
! 246: {
! 247: l = len;
! 248: if (l > sizeof(msg))
! 249: l = sizeof(msg);
! 250: l = read(auth->fd, msg, l);
! 251: if (l <= 0)
! 252: fatal("Incomplete authentication reply.");
! 253: buffer_append(&auth->identities, (char *)msg, l);
! 254: len -= l;
! 255: }
! 256:
! 257: /* Get message type, and verify that we got a proper answer. */
! 258: buffer_get(&auth->identities, (char *)msg, 1);
! 259: if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
! 260: fatal("Bad authentication reply message type: %d", msg[0]);
! 261:
! 262: /* Get the number of entries in the response and check it for sanity. */
! 263: auth->howmany = buffer_get_int(&auth->identities);
! 264: if (auth->howmany > 1024)
! 265: fatal("Too many identities in authentication reply: %d\n", auth->howmany);
! 266:
! 267: /* Return the first entry (if any). */
! 268: return ssh_get_next_identity(auth, bitsp, e, n, comment);
! 269: }
! 270:
! 271: /* Returns the next authentication identity for the agent. Other functions
! 272: can be called between this and ssh_get_first_identity or two calls of this
! 273: function. This returns 0 if there are no more identities. The caller
! 274: must free comment after a successful return. */
! 275:
! 276: int ssh_get_next_identity(AuthenticationConnection *auth,
! 277: int *bitsp, MP_INT *e, MP_INT *n, char **comment)
! 278: {
! 279: /* Return failure if no more entries. */
! 280: if (auth->howmany <= 0)
! 281: return 0;
! 282:
! 283: /* Get the next entry from the packet. These will abort with a fatal
! 284: error if the packet is too short or contains corrupt data. */
! 285: *bitsp = buffer_get_int(&auth->identities);
! 286: buffer_get_mp_int(&auth->identities, e);
! 287: buffer_get_mp_int(&auth->identities, n);
! 288: *comment = buffer_get_string(&auth->identities, NULL);
! 289:
! 290: /* Decrement the number of remaining entries. */
! 291: auth->howmany--;
! 292:
! 293: return 1;
! 294: }
! 295:
! 296: /* Generates a random challenge, sends it to the agent, and waits for response
! 297: from the agent. Returns true (non-zero) if the agent gave the correct
! 298: answer, zero otherwise. Response type selects the style of response
! 299: desired, with 0 corresponding to protocol version 1.0 (no longer supported)
! 300: and 1 corresponding to protocol version 1.1. */
! 301:
! 302: int ssh_decrypt_challenge(AuthenticationConnection *auth,
! 303: int bits, MP_INT *e, MP_INT *n, MP_INT *challenge,
! 304: unsigned char session_id[16],
! 305: unsigned int response_type,
! 306: unsigned char response[16])
! 307: {
! 308: Buffer buffer;
! 309: unsigned char buf[8192];
! 310: int len, l, i;
! 311:
! 312: /* Response type 0 is no longer supported. */
! 313: if (response_type == 0)
! 314: fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
! 315:
! 316: /* Format a message to the agent. */
! 317: buf[0] = SSH_AGENTC_RSA_CHALLENGE;
! 318: buffer_init(&buffer);
! 319: buffer_append(&buffer, (char *)buf, 1);
! 320: buffer_put_int(&buffer, bits);
! 321: buffer_put_mp_int(&buffer, e);
! 322: buffer_put_mp_int(&buffer, n);
! 323: buffer_put_mp_int(&buffer, challenge);
! 324: buffer_append(&buffer, (char *)session_id, 16);
! 325: buffer_put_int(&buffer, response_type);
! 326:
! 327: /* Get the length of the message, and format it in the buffer. */
! 328: len = buffer_len(&buffer);
! 329: PUT_32BIT(buf, len);
! 330:
! 331: /* Send the length and then the packet to the agent. */
! 332: if (write(auth->fd, buf, 4) != 4 ||
! 333: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
! 334: buffer_len(&buffer))
! 335: {
! 336: error("Error writing to authentication socket.");
! 337: error_cleanup:
! 338: buffer_free(&buffer);
! 339: return 0;
! 340: }
! 341:
! 342: /* Wait for response from the agent. First read the length of the
! 343: response packet. */
! 344: len = 4;
! 345: while (len > 0)
! 346: {
! 347: l = read(auth->fd, buf + 4 - len, len);
! 348: if (l <= 0)
! 349: {
! 350: error("Error reading response length from authentication socket.");
! 351: goto error_cleanup;
! 352: }
! 353: len -= l;
! 354: }
! 355:
! 356: /* Extract the length, and check it for sanity. */
! 357: len = GET_32BIT(buf);
! 358: if (len > 256*1024)
! 359: fatal("Authentication response too long: %d", len);
! 360:
! 361: /* Read the rest of the response in tothe buffer. */
! 362: buffer_clear(&buffer);
! 363: while (len > 0)
! 364: {
! 365: l = len;
! 366: if (l > sizeof(buf))
! 367: l = sizeof(buf);
! 368: l = read(auth->fd, buf, l);
! 369: if (l <= 0)
! 370: {
! 371: error("Error reading response from authentication socket.");
! 372: goto error_cleanup;
! 373: }
! 374: buffer_append(&buffer, (char *)buf, l);
! 375: len -= l;
! 376: }
! 377:
! 378: /* Get the type of the packet. */
! 379: buffer_get(&buffer, (char *)buf, 1);
! 380:
! 381: /* Check for agent failure message. */
! 382: if (buf[0] == SSH_AGENT_FAILURE)
! 383: {
! 384: log("Agent admitted failure to authenticate using the key.");
! 385: goto error_cleanup;
! 386: }
! 387:
! 388: /* Now it must be an authentication response packet. */
! 389: if (buf[0] != SSH_AGENT_RSA_RESPONSE)
! 390: fatal("Bad authentication response: %d", buf[0]);
! 391:
! 392: /* Get the response from the packet. This will abort with a fatal error
! 393: if the packet is corrupt. */
! 394: for (i = 0; i < 16; i++)
! 395: response[i] = buffer_get_char(&buffer);
! 396:
! 397: /* The buffer containing the packet is no longer needed. */
! 398: buffer_free(&buffer);
! 399:
! 400: /* Correct answer. */
! 401: return 1;
! 402: }
! 403:
! 404: /* Adds an identity to the authentication server. This call is not meant to
! 405: be used by normal applications. */
! 406:
! 407: int ssh_add_identity(AuthenticationConnection *auth,
! 408: RSAPrivateKey *key, const char *comment)
! 409: {
! 410: Buffer buffer;
! 411: unsigned char buf[8192];
! 412: int len, l, type;
! 413:
! 414: /* Format a message to the agent. */
! 415: buffer_init(&buffer);
! 416: buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
! 417: buffer_put_int(&buffer, key->bits);
! 418: buffer_put_mp_int(&buffer, &key->n);
! 419: buffer_put_mp_int(&buffer, &key->e);
! 420: buffer_put_mp_int(&buffer, &key->d);
! 421: buffer_put_mp_int(&buffer, &key->u);
! 422: buffer_put_mp_int(&buffer, &key->p);
! 423: buffer_put_mp_int(&buffer, &key->q);
! 424: buffer_put_string(&buffer, comment, strlen(comment));
! 425:
! 426: /* Get the length of the message, and format it in the buffer. */
! 427: len = buffer_len(&buffer);
! 428: PUT_32BIT(buf, len);
! 429:
! 430: /* Send the length and then the packet to the agent. */
! 431: if (write(auth->fd, buf, 4) != 4 ||
! 432: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
! 433: buffer_len(&buffer))
! 434: {
! 435: error("Error writing to authentication socket.");
! 436: error_cleanup:
! 437: buffer_free(&buffer);
! 438: return 0;
! 439: }
! 440:
! 441: /* Wait for response from the agent. First read the length of the
! 442: response packet. */
! 443: len = 4;
! 444: while (len > 0)
! 445: {
! 446: l = read(auth->fd, buf + 4 - len, len);
! 447: if (l <= 0)
! 448: {
! 449: error("Error reading response length from authentication socket.");
! 450: goto error_cleanup;
! 451: }
! 452: len -= l;
! 453: }
! 454:
! 455: /* Extract the length, and check it for sanity. */
! 456: len = GET_32BIT(buf);
! 457: if (len > 256*1024)
! 458: fatal("Add identity response too long: %d", len);
! 459:
! 460: /* Read the rest of the response in tothe buffer. */
! 461: buffer_clear(&buffer);
! 462: while (len > 0)
! 463: {
! 464: l = len;
! 465: if (l > sizeof(buf))
! 466: l = sizeof(buf);
! 467: l = read(auth->fd, buf, l);
! 468: if (l <= 0)
! 469: {
! 470: error("Error reading response from authentication socket.");
! 471: goto error_cleanup;
! 472: }
! 473: buffer_append(&buffer, (char *)buf, l);
! 474: len -= l;
! 475: }
! 476:
! 477: /* Get the type of the packet. */
! 478: type = buffer_get_char(&buffer);
! 479: switch (type)
! 480: {
! 481: case SSH_AGENT_FAILURE:
! 482: buffer_free(&buffer);
! 483: return 0;
! 484: case SSH_AGENT_SUCCESS:
! 485: buffer_free(&buffer);
! 486: return 1;
! 487: default:
! 488: fatal("Bad response to add identity from authentication agent: %d",
! 489: type);
! 490: }
! 491: /*NOTREACHED*/
! 492: return 0;
! 493: }
! 494:
! 495: /* Removes an identity from the authentication server. This call is not meant
! 496: to be used by normal applications. */
! 497:
! 498: int ssh_remove_identity(AuthenticationConnection *auth, RSAPublicKey *key)
! 499: {
! 500: Buffer buffer;
! 501: unsigned char buf[8192];
! 502: int len, l, type;
! 503:
! 504: /* Format a message to the agent. */
! 505: buffer_init(&buffer);
! 506: buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
! 507: buffer_put_int(&buffer, key->bits);
! 508: buffer_put_mp_int(&buffer, &key->e);
! 509: buffer_put_mp_int(&buffer, &key->n);
! 510:
! 511: /* Get the length of the message, and format it in the buffer. */
! 512: len = buffer_len(&buffer);
! 513: PUT_32BIT(buf, len);
! 514:
! 515: /* Send the length and then the packet to the agent. */
! 516: if (write(auth->fd, buf, 4) != 4 ||
! 517: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
! 518: buffer_len(&buffer))
! 519: {
! 520: error("Error writing to authentication socket.");
! 521: error_cleanup:
! 522: buffer_free(&buffer);
! 523: return 0;
! 524: }
! 525:
! 526: /* Wait for response from the agent. First read the length of the
! 527: response packet. */
! 528: len = 4;
! 529: while (len > 0)
! 530: {
! 531: l = read(auth->fd, buf + 4 - len, len);
! 532: if (l <= 0)
! 533: {
! 534: error("Error reading response length from authentication socket.");
! 535: goto error_cleanup;
! 536: }
! 537: len -= l;
! 538: }
! 539:
! 540: /* Extract the length, and check it for sanity. */
! 541: len = GET_32BIT(buf);
! 542: if (len > 256*1024)
! 543: fatal("Remove identity response too long: %d", len);
! 544:
! 545: /* Read the rest of the response in tothe buffer. */
! 546: buffer_clear(&buffer);
! 547: while (len > 0)
! 548: {
! 549: l = len;
! 550: if (l > sizeof(buf))
! 551: l = sizeof(buf);
! 552: l = read(auth->fd, buf, l);
! 553: if (l <= 0)
! 554: {
! 555: error("Error reading response from authentication socket.");
! 556: goto error_cleanup;
! 557: }
! 558: buffer_append(&buffer, (char *)buf, l);
! 559: len -= l;
! 560: }
! 561:
! 562: /* Get the type of the packet. */
! 563: type = buffer_get_char(&buffer);
! 564: switch (type)
! 565: {
! 566: case SSH_AGENT_FAILURE:
! 567: buffer_free(&buffer);
! 568: return 0;
! 569: case SSH_AGENT_SUCCESS:
! 570: buffer_free(&buffer);
! 571: return 1;
! 572: default:
! 573: fatal("Bad response to remove identity from authentication agent: %d",
! 574: type);
! 575: }
! 576: /*NOTREACHED*/
! 577: return 0;
! 578: }
! 579:
! 580: /* Removes all identities from the agent. This call is not meant
! 581: to be used by normal applications. */
! 582:
! 583: int ssh_remove_all_identities(AuthenticationConnection *auth)
! 584: {
! 585: Buffer buffer;
! 586: unsigned char buf[8192];
! 587: int len, l, type;
! 588:
! 589: /* Get the length of the message, and format it in the buffer. */
! 590: PUT_32BIT(buf, 1);
! 591: buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
! 592:
! 593: /* Send the length and then the packet to the agent. */
! 594: if (write(auth->fd, buf, 5) != 5)
! 595: {
! 596: error("Error writing to authentication socket.");
! 597: return 0;
! 598: }
! 599:
! 600: /* Wait for response from the agent. First read the length of the
! 601: response packet. */
! 602: len = 4;
! 603: while (len > 0)
! 604: {
! 605: l = read(auth->fd, buf + 4 - len, len);
! 606: if (l <= 0)
! 607: {
! 608: error("Error reading response length from authentication socket.");
! 609: return 0;
! 610: }
! 611: len -= l;
! 612: }
! 613:
! 614: /* Extract the length, and check it for sanity. */
! 615: len = GET_32BIT(buf);
! 616: if (len > 256*1024)
! 617: fatal("Remove identity response too long: %d", len);
! 618:
! 619: /* Read the rest of the response into the buffer. */
! 620: buffer_init(&buffer);
! 621: while (len > 0)
! 622: {
! 623: l = len;
! 624: if (l > sizeof(buf))
! 625: l = sizeof(buf);
! 626: l = read(auth->fd, buf, l);
! 627: if (l <= 0)
! 628: {
! 629: error("Error reading response from authentication socket.");
! 630: buffer_free(&buffer);
! 631: return 0;
! 632: }
! 633: buffer_append(&buffer, (char *)buf, l);
! 634: len -= l;
! 635: }
! 636:
! 637: /* Get the type of the packet. */
! 638: type = buffer_get_char(&buffer);
! 639: switch (type)
! 640: {
! 641: case SSH_AGENT_FAILURE:
! 642: buffer_free(&buffer);
! 643: return 0;
! 644: case SSH_AGENT_SUCCESS:
! 645: buffer_free(&buffer);
! 646: return 1;
! 647: default:
! 648: fatal("Bad response to remove identity from authentication agent: %d",
! 649: type);
! 650: }
! 651: /*NOTREACHED*/
! 652: return 0;
! 653: }
! 654:
! 655: /* Closes the connection to the authentication agent. */
! 656:
! 657: void ssh_close_authentication(AuthenticationConnection *auth)
! 658: {
! 659: /* Close the connection. */
! 660: shutdown(auth->fd, 2);
! 661: close(auth->fd);
! 662:
! 663: /* Free the buffers. */
! 664: buffer_free(&auth->packet);
! 665: buffer_free(&auth->identities);
! 666:
! 667: /* Free the connection data structure. */
! 668: xfree(auth);
! 669: }