diff options
| author | Richard M. Stallman | 1998-05-25 20:11:54 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1998-05-25 20:11:54 +0000 |
| commit | bbcac09c81753d00741a0fe29dfa8f58e409a45b (patch) | |
| tree | c420ee119172b40c96d13a5305578053057033b6 /lib-src/pop.c | |
| parent | 0d66b6f3328bb46bcf31610edb8b33dca53797ef (diff) | |
| download | emacs-bbcac09c81753d00741a0fe29dfa8f58e409a45b.tar.gz emacs-bbcac09c81753d00741a0fe29dfa8f58e409a45b.zip | |
Undo previous change.
Diffstat (limited to 'lib-src/pop.c')
| -rw-r--r-- | lib-src/pop.c | 998 |
1 files changed, 20 insertions, 978 deletions
diff --git a/lib-src/pop.c b/lib-src/pop.c index 499e8ef9164..69e6e465234 100644 --- a/lib-src/pop.c +++ b/lib-src/pop.c | |||
| @@ -161,57 +161,6 @@ static char *find_crlf _P((char *, int)); | |||
| 161 | #define KPOP_SERVICE "kpop" | 161 | #define KPOP_SERVICE "kpop" |
| 162 | #endif | 162 | #endif |
| 163 | 163 | ||
| 164 | #ifdef GSSAPI | ||
| 165 | # ifdef HAVE_GSSAPI_H | ||
| 166 | # include <gssapi.h> | ||
| 167 | # else | ||
| 168 | # include <gssapi/gssapi.h> | ||
| 169 | # endif | ||
| 170 | #define GSSAPI_SERVICE "pop" | ||
| 171 | static int pop_auth (/* popserver server, char *user, | ||
| 172 | char *host, int flags */); | ||
| 173 | static void gen_gss_error (/* char *msg, OM_uint32 major, OM_uint32 minor */); | ||
| 174 | struct _pop_gssapi | ||
| 175 | { | ||
| 176 | int gss_flags; /* encryption? integrity protection? */ | ||
| 177 | OM_uint32 max_size; /* max size we can send the server */ | ||
| 178 | gss_ctx_id_t gss_context; /* the security context */ | ||
| 179 | }; | ||
| 180 | #define GSSAPI_NOPROT 0x01 | ||
| 181 | #define GSSAPI_INTEGRITY 0x02 | ||
| 182 | #define GSSAPI_PRIVACY 0x04 | ||
| 183 | #define GSSAPI_NEEDWRAP (GSSAPI_INTEGRITY|GSSAPI_PRIVACY) | ||
| 184 | #define GSSAPI_PROTECTION (GSSAPI_NOPROT|GSSAPI_INTEGRITY|GSSAPI_PRIVACY) | ||
| 185 | #define GSSAPI_RCVBUF 1024 | ||
| 186 | #define GSSAPI_SVC_TYPE {10, "\052\206\110\206\367\022\001\002\001\004"} | ||
| 187 | #define Gssapi(data) ((struct _pop_gssapi *) (data)) | ||
| 188 | |||
| 189 | static int b64_decode (/* char *enc, gss_buffer_t dec */); | ||
| 190 | static int b64_encode (/* gss_buffer_t dec, char **enc */); | ||
| 191 | #define B64_SUCCESS 0 | ||
| 192 | #define B64_BADPARAM 1 | ||
| 193 | #define B64_BADCHAR 2 | ||
| 194 | #define B64_BADPAD 3 | ||
| 195 | #define B64_BADLEN 4 | ||
| 196 | #define B64_NOMEM 5 | ||
| 197 | static char *b64_error[] = | ||
| 198 | { | ||
| 199 | "Success", | ||
| 200 | "Bad parameters", | ||
| 201 | "Bad characters in encoding", | ||
| 202 | "Bad padding in encoding", | ||
| 203 | "Bad length", | ||
| 204 | "Out of memory" | ||
| 205 | }; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * This function is only needed if you are using the GSSAPI protection | ||
| 209 | * mechanisms; it keeps trying until it has read the requested number | ||
| 210 | * bytes from the passed-in fd. | ||
| 211 | */ | ||
| 212 | static int fullread (/* int fd, char *buf, int nbytes */); | ||
| 213 | #endif /* GSSAPI */ | ||
| 214 | |||
| 215 | char pop_error[ERROR_MAX]; | 164 | char pop_error[ERROR_MAX]; |
| 216 | int pop_debug = 0; | 165 | int pop_debug = 0; |
| 217 | 166 | ||
| @@ -320,22 +269,10 @@ pop_open (host, username, password, flags) | |||
| 320 | } | 269 | } |
| 321 | 270 | ||
| 322 | /* Determine the password */ | 271 | /* Determine the password */ |
| 323 | #if defined(KERBEROS) || defined(GSSAPI) | 272 | #ifdef KERBEROS |
| 324 | # ifdef KERBEROS | 273 | #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS)) |
| 325 | # define NO_KERBEROS POP_NO_KERBEROS | ||
| 326 | # else | ||
| 327 | # define NO_KERBEROS 0 | ||
| 328 | # endif /* KERBEROS */ | ||
| 329 | |||
| 330 | # ifdef GSSAPI | ||
| 331 | # define NO_GSSAPI POP_NO_GSSAPI | ||
| 332 | # else | ||
| 333 | # define NO_GSSAPI 0 | ||
| 334 | # endif /* GSSAPI */ | ||
| 335 | |||
| 336 | # define DONT_NEED_PASSWORD (! (flags & (NO_KERBEROS | NO_GSSAPI))) | ||
| 337 | #else | 274 | #else |
| 338 | # define DONT_NEED_PASSWORD 0 | 275 | #define DONT_NEED_PASSWORD 0 |
| 339 | #endif | 276 | #endif |
| 340 | 277 | ||
| 341 | if ((! password) && (! DONT_NEED_PASSWORD)) | 278 | if ((! password) && (! DONT_NEED_PASSWORD)) |
| @@ -351,7 +288,7 @@ pop_open (host, username, password, flags) | |||
| 351 | } | 288 | } |
| 352 | } | 289 | } |
| 353 | if (password) | 290 | if (password) |
| 354 | flags |= POP_NO_KERBEROS | (!(flags & POP_NO_NOPROT) ? POP_NO_GSSAPI : 0); | 291 | flags |= POP_NO_KERBEROS; |
| 355 | else | 292 | else |
| 356 | password = username; | 293 | password = username; |
| 357 | 294 | ||
| @@ -379,46 +316,10 @@ pop_open (host, username, password, flags) | |||
| 379 | server->buffer_size = GETLINE_MIN; | 316 | server->buffer_size = GETLINE_MIN; |
| 380 | server->in_multi = 0; | 317 | server->in_multi = 0; |
| 381 | server->trash_started = 0; | 318 | server->trash_started = 0; |
| 382 | server->extra = 0; | ||
| 383 | 319 | ||
| 384 | if (getok (server)) | 320 | if (getok (server)) |
| 385 | return (0); | 321 | return (0); |
| 386 | 322 | ||
| 387 | #ifdef GSSAPI | ||
| 388 | /* | ||
| 389 | * unless forbidden to use GSSAPI, try the GSSAPI AUTH mechanism..first. | ||
| 390 | */ | ||
| 391 | pop_error[0] = '\0'; /* so we can detect errors later... */ | ||
| 392 | if (! (flags & POP_NO_GSSAPI)) | ||
| 393 | { | ||
| 394 | int ret; | ||
| 395 | |||
| 396 | ret = pop_auth (server, username, host, flags); | ||
| 397 | if (ret == 0) | ||
| 398 | { | ||
| 399 | return (server); | ||
| 400 | } | ||
| 401 | else if (ret == -2) | ||
| 402 | { | ||
| 403 | pop_close (server); | ||
| 404 | return (0); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | #endif /* GSSAPI */ | ||
| 408 | /* | ||
| 409 | * POP_NO_NOPROT is used in the case that we want protection; if | ||
| 410 | * the authentication negotiation failed, then we want to fail now. | ||
| 411 | */ | ||
| 412 | if ((flags & POP_NO_NOPROT)) | ||
| 413 | { | ||
| 414 | pop_close (server); | ||
| 415 | #ifdef GSSAPI | ||
| 416 | if (pop_error[0] == '\0') | ||
| 417 | #endif | ||
| 418 | strcpy (pop_error, "Unable to provide protection"); | ||
| 419 | return (0); | ||
| 420 | } | ||
| 421 | |||
| 422 | /* | 323 | /* |
| 423 | * I really shouldn't use the pop_error variable like this, but.... | 324 | * I really shouldn't use the pop_error variable like this, but.... |
| 424 | */ | 325 | */ |
| @@ -1103,17 +1004,6 @@ pop_quit (server) | |||
| 1103 | 1004 | ||
| 1104 | if (server->buffer) | 1005 | if (server->buffer) |
| 1105 | free (server->buffer); | 1006 | free (server->buffer); |
| 1106 | #ifdef GSSAPI | ||
| 1107 | if (server->extra) | ||
| 1108 | { | ||
| 1109 | OM_uint32 minor; | ||
| 1110 | |||
| 1111 | if (Gssapi (server->extra)->gss_context != GSS_C_NO_CONTEXT) | ||
| 1112 | gss_delete_sec_context (&minor, &(Gssapi (server->extra)->gss_context), | ||
| 1113 | GSS_C_NO_BUFFER); | ||
| 1114 | free ((char *) server->extra); | ||
| 1115 | } | ||
| 1116 | #endif /* GSSAPI */ | ||
| 1117 | free ((char *) server); | 1007 | free ((char *) server); |
| 1118 | 1008 | ||
| 1119 | return (ret); | 1009 | return (ret); |
| @@ -1442,102 +1332,22 @@ pop_getline (server, line) | |||
| 1442 | 1332 | ||
| 1443 | while (1) | 1333 | while (1) |
| 1444 | { | 1334 | { |
| 1445 | #ifdef GSSAPI | 1335 | /* There's a "- 1" here to leave room for the null that we put |
| 1446 | /* | 1336 | at the end of the read data below. We put the null there so |
| 1447 | * We might be playing with a protected connection. If we are, then | 1337 | that find_crlf knows where to stop when we call it. */ |
| 1448 | * we need to first read a chunk of ciphertext from the server, | 1338 | if (server->data == server->buffer_size - 1) |
| 1449 | * unwrap it, and stuff it into the buffer. | ||
| 1450 | */ | ||
| 1451 | if (server->extra && | ||
| 1452 | ((Gssapi (server->extra)->gss_flags) & GSSAPI_NEEDWRAP)) | ||
| 1453 | { | 1339 | { |
| 1454 | char rcvbuf[GSSAPI_RCVBUF]; | 1340 | server->buffer_size += GETLINE_INCR; |
| 1455 | OM_uint32 major, minor, length; | 1341 | server->buffer = (char *)realloc (server->buffer, server->buffer_size); |
| 1456 | gss_buffer_desc in_tok, out_tok; | 1342 | if (! server->buffer) |
| 1457 | struct _pop_gssapi *gss_data = Gssapi (server->extra); | ||
| 1458 | |||
| 1459 | ret = fullread (server->file, (char *) &length, sizeof (length)); | ||
| 1460 | |||
| 1461 | if (ret == sizeof (length)) | ||
| 1462 | { | 1343 | { |
| 1463 | in_tok.length = ntohl (length); | 1344 | strcpy (pop_error, "Out of memory in pop_getline"); |
| 1464 | 1345 | pop_trash (server); | |
| 1465 | if (in_tok.length <= GSSAPI_RCVBUF) | 1346 | return (-1); |
| 1466 | { | ||
| 1467 | ret = fullread (server->file, rcvbuf, in_tok.length); | ||
| 1468 | |||
| 1469 | if (ret == in_tok.length) | ||
| 1470 | { | ||
| 1471 | in_tok.value = (void *) rcvbuf; | ||
| 1472 | |||
| 1473 | major = gss_unwrap (&minor, gss_data->gss_context, | ||
| 1474 | &in_tok, &out_tok, 0, 0); | ||
| 1475 | |||
| 1476 | if (major != GSS_S_COMPLETE) | ||
| 1477 | { | ||
| 1478 | pop_trash (server); | ||
| 1479 | gen_gss_error ("unwrapping", major, minor); | ||
| 1480 | return (-1); | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | while (server->data + out_tok.length >= | ||
| 1484 | server->buffer_size - 1) | ||
| 1485 | server->buffer_size += GETLINE_INCR; | ||
| 1486 | |||
| 1487 | server->buffer = (char *)realloc (server->buffer, | ||
| 1488 | server->buffer_size); | ||
| 1489 | |||
| 1490 | if (! server->buffer) | ||
| 1491 | { | ||
| 1492 | gss_release_buffer (&minor, &out_tok); | ||
| 1493 | pop_trash (server); | ||
| 1494 | strcpy (pop_error, "Out of memory in pop_getline"); | ||
| 1495 | return (-1); | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | bcopy (out_tok.value, server->buffer + server->data, | ||
| 1499 | out_tok.length); | ||
| 1500 | |||
| 1501 | ret = out_tok.length; | ||
| 1502 | |||
| 1503 | gss_release_buffer (&minor, &out_tok); | ||
| 1504 | } | ||
| 1505 | else | ||
| 1506 | ret = 0; /* force detection of unexpected EOF */ | ||
| 1507 | } | ||
| 1508 | else | ||
| 1509 | { | ||
| 1510 | pop_trash (server); | ||
| 1511 | strcpy (pop_error, "Token from server too long in pop_getline"); | ||
| 1512 | return (-1); | ||
| 1513 | } | ||
| 1514 | } | ||
| 1515 | else | ||
| 1516 | ret = 0; /* force detection of unexpected EOF */ | ||
| 1517 | } | ||
| 1518 | else | ||
| 1519 | { | ||
| 1520 | #endif /* GSSAPI */ | ||
| 1521 | /* There's a "- 1" here to leave room for the null that we put | ||
| 1522 | at the end of the read data below. We put the null there so | ||
| 1523 | that find_crlf knows where to stop when we call it. */ | ||
| 1524 | if (server->data == server->buffer_size - 1) | ||
| 1525 | { | ||
| 1526 | server->buffer_size += GETLINE_INCR; | ||
| 1527 | server->buffer = (char *)realloc (server->buffer, | ||
| 1528 | server->buffer_size); | ||
| 1529 | if (! server->buffer) | ||
| 1530 | { | ||
| 1531 | strcpy (pop_error, "Out of memory in pop_getline"); | ||
| 1532 | pop_trash (server); | ||
| 1533 | return (-1); | ||
| 1534 | } | ||
| 1535 | } | 1347 | } |
| 1536 | ret = RECV (server->file, server->buffer + server->data, | ||
| 1537 | server->buffer_size - server->data - 1, 0); | ||
| 1538 | #ifdef GSSAPI | ||
| 1539 | } | 1348 | } |
| 1540 | #endif /* GSSAPI */ | 1349 | ret = RECV (server->file, server->buffer + server->data, |
| 1350 | server->buffer_size - server->data - 1, 0); | ||
| 1541 | if (ret < 0) | 1351 | if (ret < 0) |
| 1542 | { | 1352 | { |
| 1543 | strcpy (pop_error, GETLINE_ERROR); | 1353 | strcpy (pop_error, GETLINE_ERROR); |
| @@ -1581,37 +1391,6 @@ pop_getline (server, line) | |||
| 1581 | /* NOTREACHED */ | 1391 | /* NOTREACHED */ |
| 1582 | } | 1392 | } |
| 1583 | 1393 | ||
| 1584 | #ifdef GSSAPI | ||
| 1585 | /* | ||
| 1586 | * Function: fullread | ||
| 1587 | * | ||
| 1588 | * Purpose: Just like read, but keeps trying until the specified number | ||
| 1589 | * number of bytes has been read into the buffer. This function is | ||
| 1590 | * only needed if you are using the GSSAPI protection mechanisms. | ||
| 1591 | * | ||
| 1592 | * Return value: Same as read. Pop_error is not set. | ||
| 1593 | */ | ||
| 1594 | static int | ||
| 1595 | fullread (fd, buf, nbytes) | ||
| 1596 | int fd; | ||
| 1597 | char *buf; | ||
| 1598 | int nbytes; | ||
| 1599 | { | ||
| 1600 | char *cp; | ||
| 1601 | int ret; | ||
| 1602 | |||
| 1603 | cp = buf; | ||
| 1604 | |||
| 1605 | while (nbytes > 0 && (ret = RECV (fd, cp, nbytes, 0)) > 0) | ||
| 1606 | { | ||
| 1607 | cp += ret; | ||
| 1608 | nbytes -= ret; | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | return (ret); | ||
| 1612 | } | ||
| 1613 | #endif /* GSSAPI */ | ||
| 1614 | |||
| 1615 | /* | 1394 | /* |
| 1616 | * Function: sendline | 1395 | * Function: sendline |
| 1617 | * | 1396 | * |
| @@ -1638,87 +1417,11 @@ sendline (server, line) | |||
| 1638 | #define SENDLINE_ERROR "Error writing to POP server: " | 1417 | #define SENDLINE_ERROR "Error writing to POP server: " |
| 1639 | int ret; | 1418 | int ret; |
| 1640 | 1419 | ||
| 1641 | #ifdef GSSAPI | 1420 | ret = fullwrite (server->file, line, strlen (line)); |
| 1642 | /* | 1421 | if (ret >= 0) |
| 1643 | * We might be playing with a protected connection. If we are, then we | 1422 | { /* 0 indicates that a blank line was written */ |
| 1644 | * need to build our full plaintext, parse it into chunks small enough | 1423 | ret = fullwrite (server->file, "\r\n", 2); |
| 1645 | * for the server to swallow, wrap each one, and send it over the net as | ||
| 1646 | * specified by the RFC. | ||
| 1647 | */ | ||
| 1648 | if (server->extra && ((Gssapi (server->extra)->gss_flags) & GSSAPI_NEEDWRAP)) | ||
| 1649 | { | ||
| 1650 | char *sendbuf, *ptr; | ||
| 1651 | OM_uint32 major, minor, length; | ||
| 1652 | gss_buffer_desc in_tok, out_tok; | ||
| 1653 | int len = 0, tot_len; | ||
| 1654 | struct _pop_gssapi *gss_data = Gssapi (server->extra); | ||
| 1655 | |||
| 1656 | sendbuf = malloc (strlen (line) + 3); | ||
| 1657 | |||
| 1658 | if (! sendbuf) | ||
| 1659 | { | ||
| 1660 | pop_trash (server); | ||
| 1661 | strcpy (pop_error, "Out of memory in sendline"); | ||
| 1662 | return (-1); | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | tot_len = sprintf (sendbuf, "%s\r\n", line); | ||
| 1666 | |||
| 1667 | for (ptr = sendbuf; tot_len > 0; tot_len -= len, ptr += len) | ||
| 1668 | { | ||
| 1669 | len = ((tot_len > gss_data->max_size) ? | ||
| 1670 | gss_data->max_size : tot_len); | ||
| 1671 | |||
| 1672 | in_tok.value = (void *) ptr; | ||
| 1673 | in_tok.length = len; | ||
| 1674 | |||
| 1675 | major = gss_wrap (&minor, gss_data->gss_context, | ||
| 1676 | (gss_data->gss_flags & GSSAPI_PRIVACY) ? 1 : 0, | ||
| 1677 | GSS_C_QOP_DEFAULT, &in_tok, 0, &out_tok); | ||
| 1678 | |||
| 1679 | if (major != GSS_S_COMPLETE) | ||
| 1680 | { | ||
| 1681 | free (sendbuf); | ||
| 1682 | pop_trash (server); | ||
| 1683 | gen_gss_error ("wrapping", major, minor); | ||
| 1684 | return (-1); | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | /* | ||
| 1688 | * "Once the protection mechanism is in effect, the stream of | ||
| 1689 | * command and response octets is processed into buffers of | ||
| 1690 | * ciphertext. Each buffer is transferred over the connection | ||
| 1691 | * as a stream of octets prepended with a four octet field in | ||
| 1692 | * network byte order that represents the length of the | ||
| 1693 | * following data." - RFC 1734, section 2 | ||
| 1694 | */ | ||
| 1695 | length = htonl (out_tok.length); | ||
| 1696 | ret = fullwrite (server->file, (char *) &length, sizeof (length)); | ||
| 1697 | if (ret == sizeof (length)) | ||
| 1698 | { | ||
| 1699 | ret = fullwrite (server->file, (char *) out_tok.value, | ||
| 1700 | out_tok.length); | ||
| 1701 | } | ||
| 1702 | |||
| 1703 | gss_release_buffer (&minor, &out_tok); | ||
| 1704 | |||
| 1705 | if (ret < 0) | ||
| 1706 | break; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | free (sendbuf); | ||
| 1710 | } | 1424 | } |
| 1711 | else | ||
| 1712 | { | ||
| 1713 | #endif /* GSSAPI */ | ||
| 1714 | ret = fullwrite (server->file, line, strlen (line)); | ||
| 1715 | if (ret >= 0) | ||
| 1716 | { /* 0 indicates that a blank line was written */ | ||
| 1717 | ret = fullwrite (server->file, "\r\n", 2); | ||
| 1718 | } | ||
| 1719 | #ifdef GSSAPI | ||
| 1720 | } | ||
| 1721 | #endif /* GSSAPI */ | ||
| 1722 | 1425 | ||
| 1723 | if (ret < 0) | 1426 | if (ret < 0) |
| 1724 | { | 1427 | { |
| @@ -1886,19 +1589,6 @@ pop_trash (server) | |||
| 1886 | free (server->buffer); | 1589 | free (server->buffer); |
| 1887 | server->buffer = 0; | 1590 | server->buffer = 0; |
| 1888 | } | 1591 | } |
| 1889 | #ifdef GSSAPI | ||
| 1890 | if (server->extra) | ||
| 1891 | { | ||
| 1892 | OM_uint32 minor; | ||
| 1893 | |||
| 1894 | if (Gssapi (server->extra)->gss_context != GSS_C_NO_CONTEXT) | ||
| 1895 | gss_delete_sec_context (&minor, | ||
| 1896 | &(Gssapi (server->extra)->gss_context), | ||
| 1897 | GSS_C_NO_BUFFER); | ||
| 1898 | free ((char *) server->extra); | ||
| 1899 | server->extra = 0; | ||
| 1900 | } | ||
| 1901 | #endif /* GSSAPI */ | ||
| 1902 | } | 1592 | } |
| 1903 | 1593 | ||
| 1904 | #ifdef WINDOWSNT | 1594 | #ifdef WINDOWSNT |
| @@ -1907,654 +1597,6 @@ pop_trash (server) | |||
| 1907 | #endif | 1597 | #endif |
| 1908 | } | 1598 | } |
| 1909 | 1599 | ||
| 1910 | #ifdef GSSAPI | ||
| 1911 | /* | ||
| 1912 | * Function: pop_auth | ||
| 1913 | * | ||
| 1914 | * Purpose: To perform a GSSAPI authentication handshake with a POP server. | ||
| 1915 | * If the negotiation is successful, it will return 0; otherwise, it | ||
| 1916 | * will fill in pop_error with the error message and return either -1, | ||
| 1917 | * indicating a potentially recoverable error, or -2, indicating an | ||
| 1918 | * unrecoverable error. | ||
| 1919 | * | ||
| 1920 | * Side effects: The server may choose to close the connection if the | ||
| 1921 | * handshake fails. The connection will be trashed if the error is | ||
| 1922 | * unrecoverable. | ||
| 1923 | */ | ||
| 1924 | static int | ||
| 1925 | pop_auth (server, username, host, flags) | ||
| 1926 | popserver server; | ||
| 1927 | char *username, *host; | ||
| 1928 | int flags; | ||
| 1929 | { | ||
| 1930 | int gss_flags, ret; | ||
| 1931 | char *fromserver; | ||
| 1932 | OM_uint32 max_size, t_flags; | ||
| 1933 | gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; | ||
| 1934 | gss_buffer_desc in_tok, out_tok; | ||
| 1935 | gss_name_t svc_name; | ||
| 1936 | OM_uint32 major, minor, t_minor; | ||
| 1937 | |||
| 1938 | /* calculate usable protection mechanisms */ | ||
| 1939 | gss_flags = (GSSAPI_PROTECTION & | ||
| 1940 | ~(((flags & POP_NO_NOPROT) ? GSSAPI_NOPROT : 0) | | ||
| 1941 | ((flags & POP_NO_INTEG) ? GSSAPI_INTEGRITY : 0) | | ||
| 1942 | ((flags & POP_NO_ENCRYPT) ? GSSAPI_PRIVACY : 0))); | ||
| 1943 | |||
| 1944 | if (gss_flags == 0) | ||
| 1945 | { | ||
| 1946 | strcpy (pop_error, "Unable to provide selected protection level"); | ||
| 1947 | return (-1); | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | /* import service name of pop server */ | ||
| 1951 | in_tok.value = (void *) malloc (strlen (host) + sizeof (GSSAPI_SERVICE) + 2); | ||
| 1952 | |||
| 1953 | if (! in_tok.value) | ||
| 1954 | { | ||
| 1955 | strcpy (pop_error, "Out of memory in pop_auth"); | ||
| 1956 | return (-1); | ||
| 1957 | } | ||
| 1958 | |||
| 1959 | sprintf ((char *) in_tok.value, "%s@%s", GSSAPI_SERVICE, host); | ||
| 1960 | in_tok.length = strlen ((char *) in_tok.value); | ||
| 1961 | |||
| 1962 | { | ||
| 1963 | gss_OID_desc svc_name_oid = GSSAPI_SVC_TYPE; | ||
| 1964 | |||
| 1965 | major = gss_import_name (&minor, &in_tok, &svc_name_oid, &svc_name); | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | free ((char *) in_tok.value); | ||
| 1969 | |||
| 1970 | if (major != GSS_S_COMPLETE) | ||
| 1971 | { | ||
| 1972 | gen_gss_error ("parsing name", major, minor); | ||
| 1973 | return (-1); | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | /* begin GSSAPI authentication handshake */ | ||
| 1977 | if (sendline (server, "AUTH GSSAPI") || (pop_getline (server, &fromserver) < 0)) | ||
| 1978 | { | ||
| 1979 | gss_release_name (&t_minor, &svc_name); | ||
| 1980 | return (-1); | ||
| 1981 | } | ||
| 1982 | |||
| 1983 | do | ||
| 1984 | { | ||
| 1985 | /* sanity-check server response */ | ||
| 1986 | if (strncmp (fromserver, "+ ", 2)) | ||
| 1987 | { | ||
| 1988 | gss_release_name (&t_minor, &svc_name); | ||
| 1989 | if (gss_context != GSS_C_NO_CONTEXT) | ||
| 1990 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 1991 | if (0 == strncmp (fromserver, "-ERR", 4)) | ||
| 1992 | { | ||
| 1993 | strncpy (pop_error, fromserver, ERROR_MAX); | ||
| 1994 | return (-1); | ||
| 1995 | } | ||
| 1996 | else | ||
| 1997 | { | ||
| 1998 | pop_trash (server); | ||
| 1999 | strcpy (pop_error, | ||
| 2000 | "Unexpected response from POP server in pop_auth"); | ||
| 2001 | return (-2); | ||
| 2002 | } | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | if (strlen (fromserver) > 2) | ||
| 2006 | { | ||
| 2007 | /* base 64 decode the response... */ | ||
| 2008 | ret = b64_decode (fromserver + 2, &in_tok); | ||
| 2009 | if (ret != B64_SUCCESS) | ||
| 2010 | { | ||
| 2011 | gss_release_name (&t_minor, &svc_name); | ||
| 2012 | if (gss_context != GSS_C_NO_CONTEXT) | ||
| 2013 | gss_delete_sec_context (&t_minor, &gss_context, | ||
| 2014 | GSS_C_NO_BUFFER); | ||
| 2015 | sendline (server, "*"); | ||
| 2016 | strcpy (pop_error, b64_error[ret]); | ||
| 2017 | return (-1); | ||
| 2018 | } | ||
| 2019 | } | ||
| 2020 | else | ||
| 2021 | { | ||
| 2022 | in_tok.length = 0; | ||
| 2023 | in_tok.value = 0; | ||
| 2024 | } | ||
| 2025 | |||
| 2026 | /* call init_sec_context */ | ||
| 2027 | major = gss_init_sec_context (&minor, GSS_C_NO_CREDENTIAL, &gss_context, | ||
| 2028 | svc_name, GSS_C_NULL_OID, | ||
| 2029 | GSS_C_MUTUAL_FLAG, 0, | ||
| 2030 | GSS_C_NO_CHANNEL_BINDINGS, | ||
| 2031 | in_tok.length ? & in_tok : GSS_C_NO_BUFFER, | ||
| 2032 | 0, &out_tok, 0, 0); | ||
| 2033 | |||
| 2034 | if (in_tok.length != 0) | ||
| 2035 | free ((char *) in_tok.value); | ||
| 2036 | |||
| 2037 | /* check for error */ | ||
| 2038 | if (GSS_ERROR (major)) | ||
| 2039 | { | ||
| 2040 | gss_release_name (&t_minor, &svc_name); | ||
| 2041 | if (gss_context != GSS_C_NO_CONTEXT) | ||
| 2042 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2043 | sendline (server, "*"); | ||
| 2044 | gen_gss_error ("in init_sec_context", major, minor); | ||
| 2045 | return (-1); | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | if (out_tok.length != 0) | ||
| 2049 | { | ||
| 2050 | /* base 64 encode output token, if any */ | ||
| 2051 | ret = b64_encode (&out_tok, &fromserver); | ||
| 2052 | |||
| 2053 | gss_release_buffer (&t_minor, &out_tok); | ||
| 2054 | |||
| 2055 | if (ret != B64_SUCCESS) | ||
| 2056 | { | ||
| 2057 | gss_release_name (&t_minor, &svc_name); | ||
| 2058 | if (gss_context != GSS_C_NO_CONTEXT) | ||
| 2059 | gss_delete_sec_context (&t_minor, &gss_context, | ||
| 2060 | GSS_C_NO_BUFFER); | ||
| 2061 | sendline (server, "*"); | ||
| 2062 | strcpy (pop_error, b64_error[ret]); | ||
| 2063 | return (-1); | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | /* send output token... */ | ||
| 2067 | ret = sendline (server, fromserver); | ||
| 2068 | |||
| 2069 | free (fromserver); | ||
| 2070 | } | ||
| 2071 | else | ||
| 2072 | /* empty output token... */ | ||
| 2073 | ret = sendline (server, ""); | ||
| 2074 | |||
| 2075 | /* get next token from server */ | ||
| 2076 | if (ret || (pop_getline (server, &fromserver) < 0)) | ||
| 2077 | { | ||
| 2078 | gss_release_name (&t_minor, &svc_name); | ||
| 2079 | if (gss_context != GSS_C_NO_CONTEXT) | ||
| 2080 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2081 | return (-1); | ||
| 2082 | } | ||
| 2083 | } while ((major & GSS_S_CONTINUE_NEEDED)); | ||
| 2084 | |||
| 2085 | /* release name... */ | ||
| 2086 | gss_release_name (&t_minor, &svc_name); | ||
| 2087 | |||
| 2088 | /* get final response from server */ | ||
| 2089 | if (strncmp (fromserver, "+ ", 2)) | ||
| 2090 | { | ||
| 2091 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2092 | if (0 == strncmp (fromserver, "-ERR", 4)) | ||
| 2093 | { | ||
| 2094 | strncpy (pop_error, fromserver, ERROR_MAX); | ||
| 2095 | return (-1); | ||
| 2096 | } | ||
| 2097 | else | ||
| 2098 | { | ||
| 2099 | pop_trash (server); | ||
| 2100 | strcpy (pop_error, | ||
| 2101 | "Unexpected response from POP server in pop_auth"); | ||
| 2102 | return (-2); | ||
| 2103 | } | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | /* base 64 decode... */ | ||
| 2107 | ret = b64_decode (fromserver + 2, &in_tok); | ||
| 2108 | if (ret != B64_SUCCESS) | ||
| 2109 | { | ||
| 2110 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2111 | sendline (server, "*"); | ||
| 2112 | strcpy (pop_error, b64_error[ret]); | ||
| 2113 | return (-1); | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | /* unwrap... */ | ||
| 2117 | major = gss_unwrap (&minor, gss_context, &in_tok, &out_tok, 0, 0); | ||
| 2118 | |||
| 2119 | free ((char *) in_tok.value); | ||
| 2120 | |||
| 2121 | if (major != GSS_S_COMPLETE || out_tok.length != sizeof (t_flags)) | ||
| 2122 | { | ||
| 2123 | if (out_tok.length != 0) | ||
| 2124 | gss_release_buffer (&t_minor, &out_tok); | ||
| 2125 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2126 | sendline (server, "*"); | ||
| 2127 | gen_gss_error ("in gss_unwrap", major, minor); | ||
| 2128 | return (-1); | ||
| 2129 | } | ||
| 2130 | |||
| 2131 | /* get and check flags/size */ | ||
| 2132 | bcopy ((void *) out_tok.value, (void *) &t_flags, sizeof (t_flags)); | ||
| 2133 | |||
| 2134 | gss_release_buffer (&t_minor, &out_tok); | ||
| 2135 | |||
| 2136 | max_size = ntohl (t_flags); | ||
| 2137 | |||
| 2138 | t_flags = ((max_size & 0xFF000000) >> 24) & gss_flags; | ||
| 2139 | max_size &= 0x00FFFFFF; | ||
| 2140 | |||
| 2141 | if ((t_flags & GSSAPI_PRIVACY)) | ||
| 2142 | gss_flags = GSSAPI_PRIVACY; | ||
| 2143 | |||
| 2144 | else if ((t_flags & GSSAPI_INTEGRITY)) | ||
| 2145 | gss_flags = GSSAPI_INTEGRITY; | ||
| 2146 | |||
| 2147 | else if ((t_flags & GSSAPI_NOPROT)) | ||
| 2148 | gss_flags = GSSAPI_NOPROT; | ||
| 2149 | |||
| 2150 | else | ||
| 2151 | { | ||
| 2152 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2153 | sendline (server, "*"); | ||
| 2154 | strcpy (pop_error, "Server does not provide selected protection level"); | ||
| 2155 | return (-1); | ||
| 2156 | } | ||
| 2157 | |||
| 2158 | if (max_size == 0) | ||
| 2159 | { | ||
| 2160 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2161 | sendline (server, "*"); | ||
| 2162 | strcpy (pop_error, "Bad server max length"); | ||
| 2163 | return (-1); | ||
| 2164 | } | ||
| 2165 | |||
| 2166 | if ((gss_flags & GSSAPI_NEEDWRAP)) | ||
| 2167 | { | ||
| 2168 | major = gss_wrap_size_limit (&t_minor, gss_context, | ||
| 2169 | (gss_flags & GSSAPI_PRIVACY) ? 1 : 0, | ||
| 2170 | GSS_C_QOP_DEFAULT, | ||
| 2171 | (max_size < GSSAPI_RCVBUF) ? max_size : | ||
| 2172 | GSSAPI_RCVBUF, &max_size); | ||
| 2173 | if (major != GSS_S_COMPLETE) | ||
| 2174 | { | ||
| 2175 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2176 | sendline (server, "*"); | ||
| 2177 | gen_gss_error ("getting max size", major, minor); | ||
| 2178 | return (-1); | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | /* generate return flags */ | ||
| 2183 | { | ||
| 2184 | OM_uint32 tmp; | ||
| 2185 | |||
| 2186 | tmp = (((gss_flags << 24) & 0xFF000000) | (GSSAPI_RCVBUF & 0x00FFFFFF)); | ||
| 2187 | t_flags = ntohl (tmp); | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | in_tok.length = sizeof (t_flags) + strlen (username); | ||
| 2191 | in_tok.value = (void *) malloc (in_tok.length); | ||
| 2192 | |||
| 2193 | if (! in_tok.value) | ||
| 2194 | { | ||
| 2195 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2196 | sendline (server, "*"); | ||
| 2197 | strcpy (pop_error, "Out of memory in pop_auth"); | ||
| 2198 | return (-1); | ||
| 2199 | } | ||
| 2200 | |||
| 2201 | bcopy ((void *) &t_flags, in_tok.value, sizeof (t_flags)); | ||
| 2202 | bcopy ((void *) username, | ||
| 2203 | (void *) (((char *) in_tok.value) + sizeof (t_flags)), | ||
| 2204 | in_tok.length - sizeof (t_flags)); | ||
| 2205 | |||
| 2206 | /* wrap result */ | ||
| 2207 | major = gss_wrap (&minor, gss_context, 0, GSS_C_QOP_DEFAULT, | ||
| 2208 | &in_tok, 0, &out_tok); | ||
| 2209 | |||
| 2210 | free ((char *) in_tok.value); | ||
| 2211 | |||
| 2212 | if (major != GSS_S_COMPLETE || out_tok.length == 0) | ||
| 2213 | { | ||
| 2214 | if (out_tok.length != 0) | ||
| 2215 | gss_release_buffer (&t_minor, &out_tok); | ||
| 2216 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2217 | sendline (server, "*"); | ||
| 2218 | gen_gss_error ("in gss_wrap", major, minor); | ||
| 2219 | return (-1); | ||
| 2220 | } | ||
| 2221 | |||
| 2222 | /* base 64 encode... */ | ||
| 2223 | ret = b64_encode (&out_tok, &fromserver); | ||
| 2224 | |||
| 2225 | gss_release_buffer (&t_minor, &out_tok); | ||
| 2226 | |||
| 2227 | if (ret != B64_SUCCESS) | ||
| 2228 | { | ||
| 2229 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2230 | sendline (server, "*"); | ||
| 2231 | strcpy (pop_error, b64_error[ret]); | ||
| 2232 | return (-1); | ||
| 2233 | } | ||
| 2234 | |||
| 2235 | /* send to server */ | ||
| 2236 | ret = sendline (server, fromserver); | ||
| 2237 | |||
| 2238 | free (fromserver); | ||
| 2239 | |||
| 2240 | /* see if the server likes me... */ | ||
| 2241 | if (ret || getok (server)) | ||
| 2242 | { | ||
| 2243 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2244 | return (-1); | ||
| 2245 | } | ||
| 2246 | |||
| 2247 | /* stash context */ | ||
| 2248 | { | ||
| 2249 | struct _pop_gssapi *gss_data; | ||
| 2250 | |||
| 2251 | gss_data = (struct _pop_gssapi *) malloc (sizeof (struct _pop_gssapi)); | ||
| 2252 | |||
| 2253 | if (! gss_data) | ||
| 2254 | { | ||
| 2255 | pop_trash (server); | ||
| 2256 | gss_delete_sec_context (&t_minor, &gss_context, GSS_C_NO_BUFFER); | ||
| 2257 | strcpy (pop_error, "Out of memory in pop_auth"); | ||
| 2258 | return (-2); | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | gss_data->gss_flags = gss_flags; | ||
| 2262 | gss_data->max_size = max_size; | ||
| 2263 | gss_data->gss_context = gss_context; | ||
| 2264 | |||
| 2265 | server->extra = gss_data; | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | return (0); | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | /* | ||
| 2272 | * Add as much error text to pop_error as will fit, but only put complete | ||
| 2273 | * messages | ||
| 2274 | */ | ||
| 2275 | static void | ||
| 2276 | gen_gss_error (msg, major, minor) | ||
| 2277 | char *msg; | ||
| 2278 | OM_uint32 major, minor; | ||
| 2279 | { | ||
| 2280 | char *p = pop_error, *t, *saved; | ||
| 2281 | int max = ERROR_MAX - 1; /* for \0 */ | ||
| 2282 | OM_uint32 t_minor, msg_ctx = 0; | ||
| 2283 | gss_buffer_desc gss_msg; | ||
| 2284 | |||
| 2285 | while (*msg && max) | ||
| 2286 | { | ||
| 2287 | *p++ = *msg++; | ||
| 2288 | max--; | ||
| 2289 | } | ||
| 2290 | |||
| 2291 | if (max >= 2) | ||
| 2292 | { | ||
| 2293 | saved = p; | ||
| 2294 | *p++ = ':'; | ||
| 2295 | *p++ = ' '; | ||
| 2296 | max -= 2; | ||
| 2297 | } | ||
| 2298 | else | ||
| 2299 | { | ||
| 2300 | *p = '\0'; | ||
| 2301 | return; | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | do | ||
| 2305 | { | ||
| 2306 | gss_display_status (&t_minor, major, GSS_C_GSS_CODE, GSS_C_NO_OID, | ||
| 2307 | &msg_ctx, &gss_msg); | ||
| 2308 | for (t = (char *) gss_msg.value; *t && max; max--) | ||
| 2309 | { | ||
| 2310 | *p++ = *t++; | ||
| 2311 | } | ||
| 2312 | gss_release_buffer (&t_minor, &gss_msg); | ||
| 2313 | if (max == 0) | ||
| 2314 | { | ||
| 2315 | *saved = '\0'; | ||
| 2316 | return; | ||
| 2317 | } | ||
| 2318 | } while (msg_ctx); | ||
| 2319 | |||
| 2320 | saved = p; | ||
| 2321 | |||
| 2322 | do | ||
| 2323 | { | ||
| 2324 | gss_display_status (&t_minor, minor, GSS_C_MECH_CODE, GSS_C_NO_OID, | ||
| 2325 | &msg_ctx, &gss_msg); | ||
| 2326 | for (t = (char *) gss_msg.value; *t && max; max--) | ||
| 2327 | { | ||
| 2328 | *p++ = *t++; | ||
| 2329 | } | ||
| 2330 | gss_release_buffer (&t_minor, &gss_msg); | ||
| 2331 | if (max == 0) | ||
| 2332 | { | ||
| 2333 | *saved = '\0'; | ||
| 2334 | return; | ||
| 2335 | } | ||
| 2336 | } while (msg_ctx); | ||
| 2337 | |||
| 2338 | *p = '\0'; | ||
| 2339 | return; | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | /* | ||
| 2343 | * table-based base64 decoding function; takes 4 characters from in and | ||
| 2344 | * writes from 1 to 3 bytes to out, storing the amount written in len | ||
| 2345 | */ | ||
| 2346 | static int | ||
| 2347 | b64_d (in, out, len) | ||
| 2348 | char *in, *out; | ||
| 2349 | int *len; | ||
| 2350 | { | ||
| 2351 | int decodearray[] = | ||
| 2352 | { | ||
| 2353 | 0x3e, -1, -1, -1, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, | ||
| 2354 | 0x3b, 0x3c, 0x3d, -1, -1, -1, -1, -1, -1, -1, 0x00, 0x01, | ||
| 2355 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, | ||
| 2356 | 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, | ||
| 2357 | -1, -1, -1, -1, -1, -1, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
| 2358 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, | ||
| 2359 | 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 | ||
| 2360 | }; | ||
| 2361 | |||
| 2362 | int d; | ||
| 2363 | |||
| 2364 | if (!in || !out || !len) | ||
| 2365 | return (B64_BADPARAM); | ||
| 2366 | |||
| 2367 | if (*in < '+' || *in > 'z') | ||
| 2368 | return (B64_BADCHAR); | ||
| 2369 | |||
| 2370 | d = decodearray[*(in++) - '+']; | ||
| 2371 | if (d == -1) | ||
| 2372 | return (B64_BADCHAR); | ||
| 2373 | *out = d << 2; | ||
| 2374 | |||
| 2375 | if (*in < '+' || *in > 'z') | ||
| 2376 | return (B64_BADCHAR); | ||
| 2377 | |||
| 2378 | d = decodearray[*(in++) - '+']; | ||
| 2379 | if (d == -1) | ||
| 2380 | return (B64_BADCHAR); | ||
| 2381 | *(out++) |= d >> 4; | ||
| 2382 | *out = (d & 15) << 4; | ||
| 2383 | |||
| 2384 | if (*in < '+' || *in > 'z') | ||
| 2385 | return (B64_BADCHAR); | ||
| 2386 | else if (*in == '=') | ||
| 2387 | if (*(in + 1) != '=') | ||
| 2388 | return (B64_BADPAD); | ||
| 2389 | else | ||
| 2390 | { | ||
| 2391 | *len = 1; | ||
| 2392 | return (B64_SUCCESS); | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | d = decodearray[*(in++) - '+']; | ||
| 2396 | if (d == -1) | ||
| 2397 | return (B64_BADCHAR); | ||
| 2398 | *(out++) |= d >> 2; | ||
| 2399 | *out = (d & 3) << 6; | ||
| 2400 | |||
| 2401 | if (*in < '+' || *in > 'z') | ||
| 2402 | return (B64_BADCHAR); | ||
| 2403 | else if (*in == '=') | ||
| 2404 | { | ||
| 2405 | *len = 2; | ||
| 2406 | return (B64_SUCCESS); | ||
| 2407 | } | ||
| 2408 | |||
| 2409 | d = decodearray[*in - '+']; | ||
| 2410 | if (d == -1) | ||
| 2411 | return (B64_BADCHAR); | ||
| 2412 | *out |= d; | ||
| 2413 | |||
| 2414 | *len = 3; | ||
| 2415 | return (B64_SUCCESS); | ||
| 2416 | } | ||
| 2417 | |||
| 2418 | /* | ||
| 2419 | * simple base64 encoding function that takes from 0 to 3 bytes and | ||
| 2420 | * outputs 4 encoded characters, with appropriate padding | ||
| 2421 | */ | ||
| 2422 | static int | ||
| 2423 | b64_e (in, out, len) | ||
| 2424 | unsigned char *in, *out; | ||
| 2425 | int len; | ||
| 2426 | { | ||
| 2427 | unsigned char codearray[] = | ||
| 2428 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
| 2429 | |||
| 2430 | if (!in || !out || len <= 0 || len > 3) | ||
| 2431 | return (B64_BADPARAM); | ||
| 2432 | |||
| 2433 | *(out++) = codearray[((*in) >> 2)]; | ||
| 2434 | |||
| 2435 | if (--len == 0) | ||
| 2436 | { | ||
| 2437 | *(out++) = codearray[(((*in) & 3) << 4)]; | ||
| 2438 | *(out++) = '='; | ||
| 2439 | *out = '='; | ||
| 2440 | return (B64_SUCCESS); | ||
| 2441 | } | ||
| 2442 | |||
| 2443 | *(out++) = codearray[(((*in) & 3) << 4) | ((*(in + 1)) >> 4)]; | ||
| 2444 | in++; | ||
| 2445 | |||
| 2446 | if (--len == 0) | ||
| 2447 | { | ||
| 2448 | *(out++) = codearray[(((*in) & 15) << 2)]; | ||
| 2449 | *out = '='; | ||
| 2450 | return (B64_SUCCESS); | ||
| 2451 | } | ||
| 2452 | |||
| 2453 | *(out++) = codearray[(((*in) & 15) << 2) | ((*(in + 1)) >> 6)]; | ||
| 2454 | *out = codearray[((*(in + 1)) & 63)]; | ||
| 2455 | |||
| 2456 | return (B64_SUCCESS); | ||
| 2457 | } | ||
| 2458 | |||
| 2459 | /* | ||
| 2460 | * given an input string, generate an output gss_buffer_t containing the | ||
| 2461 | * decoded data and correct length; works by repeatedly driving b64_d () | ||
| 2462 | * over the input string | ||
| 2463 | */ | ||
| 2464 | static int | ||
| 2465 | b64_decode (enc, dec) | ||
| 2466 | char *enc; | ||
| 2467 | gss_buffer_t dec; | ||
| 2468 | { | ||
| 2469 | char *tmp; | ||
| 2470 | int inlen, outlen = 0, t_len, ret; | ||
| 2471 | |||
| 2472 | if (!enc || !dec) | ||
| 2473 | return (B64_BADPARAM); | ||
| 2474 | |||
| 2475 | dec->value = 0; | ||
| 2476 | dec->length = 0; | ||
| 2477 | |||
| 2478 | inlen = strlen (enc); | ||
| 2479 | if ((inlen % 4)) | ||
| 2480 | return (B64_BADLEN); | ||
| 2481 | |||
| 2482 | dec->value = (void *) (tmp = (char *) malloc ((inlen / 4) * 3)); | ||
| 2483 | |||
| 2484 | if (! tmp) | ||
| 2485 | return (B64_NOMEM); | ||
| 2486 | |||
| 2487 | for (; inlen; inlen -= 4) | ||
| 2488 | { | ||
| 2489 | ret = b64_d (enc, tmp, &t_len); | ||
| 2490 | if (ret != B64_SUCCESS) | ||
| 2491 | { | ||
| 2492 | free ((char *) dec->value); | ||
| 2493 | dec->value = 0; | ||
| 2494 | return (ret); | ||
| 2495 | } | ||
| 2496 | else if (t_len != 3) | ||
| 2497 | { | ||
| 2498 | dec->length = outlen + t_len; | ||
| 2499 | return (B64_SUCCESS); | ||
| 2500 | } | ||
| 2501 | else | ||
| 2502 | { | ||
| 2503 | enc += 4; | ||
| 2504 | tmp += t_len; | ||
| 2505 | outlen += t_len; | ||
| 2506 | } | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | dec->length = outlen; | ||
| 2510 | return (B64_SUCCESS); | ||
| 2511 | } | ||
| 2512 | |||
| 2513 | /* | ||
| 2514 | * given a gss_buffer_t, generate an encoded string containing the data. | ||
| 2515 | * works by repeatedly driving b64_e () over the contents of the buffer_t | ||
| 2516 | */ | ||
| 2517 | static int | ||
| 2518 | b64_encode (dec, enc) | ||
| 2519 | gss_buffer_t dec; | ||
| 2520 | char **enc; | ||
| 2521 | { | ||
| 2522 | unsigned char *tmp, *in; | ||
| 2523 | int ret, len; | ||
| 2524 | |||
| 2525 | if (!dec || !enc) | ||
| 2526 | return (B64_BADPARAM); | ||
| 2527 | |||
| 2528 | in = (unsigned char *) dec->value; | ||
| 2529 | len = dec->length; | ||
| 2530 | *enc = (char *) (tmp = (unsigned char *) malloc (((len * 4) / 3) + 5)); | ||
| 2531 | |||
| 2532 | if (! tmp) | ||
| 2533 | return (B64_NOMEM); | ||
| 2534 | |||
| 2535 | do | ||
| 2536 | { | ||
| 2537 | ret = b64_e (in, tmp, len >= 3 ? 3 : len); | ||
| 2538 | if (ret != B64_SUCCESS) | ||
| 2539 | { | ||
| 2540 | free (*enc); | ||
| 2541 | *enc = 0; | ||
| 2542 | return (ret); | ||
| 2543 | } | ||
| 2544 | else | ||
| 2545 | { | ||
| 2546 | in += 3; | ||
| 2547 | tmp += 4; | ||
| 2548 | } | ||
| 2549 | } while ((len -= 3) > 0); | ||
| 2550 | |||
| 2551 | *tmp = '\0'; | ||
| 2552 | |||
| 2553 | return (B64_SUCCESS); | ||
| 2554 | } | ||
| 2555 | |||
| 2556 | #endif /* GSSAPI */ | ||
| 2557 | |||
| 2558 | /* Return a pointer to the first CRLF in IN_STRING, which can contain | 1600 | /* Return a pointer to the first CRLF in IN_STRING, which can contain |
| 2559 | embedded nulls and has LEN characters in it not including the final | 1601 | embedded nulls and has LEN characters in it not including the final |
| 2560 | null, or 0 if it does not contain one. */ | 1602 | null, or 0 if it does not contain one. */ |