Mercurial > emacs
comparison lib-src/pop.c @ 22236:bfaacbee089a
Undo previous change.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 25 May 1998 20:11:54 +0000 |
parents | aa5d46f74b6a |
children | 8565fbac98d7 |
comparison
equal
deleted
inserted
replaced
22235:ee90e9da3a70 | 22236:bfaacbee089a |
---|---|
159 #endif | 159 #endif |
160 #ifdef KERBEROS | 160 #ifdef KERBEROS |
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 |
218 #ifndef min | 167 #ifndef min |
219 #define min(a,b) (((a) < (b)) ? (a) : (b)) | 168 #define min(a,b) (((a) < (b)) ? (a) : (b)) |
318 strcpy (pop_error, "Could not determine POP server"); | 267 strcpy (pop_error, "Could not determine POP server"); |
319 return (0); | 268 return (0); |
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)) |
342 { | 279 { |
343 if (! (flags & POP_NO_GETPASS)) | 280 if (! (flags & POP_NO_GETPASS)) |
349 strcpy (pop_error, "Could not determine POP password"); | 286 strcpy (pop_error, "Could not determine POP password"); |
350 return (0); | 287 return (0); |
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 |
358 sock = socket_connection (host, flags); | 295 sock = socket_connection (host, flags); |
359 if (sock == -1) | 296 if (sock == -1) |
377 server->data = 0; | 314 server->data = 0; |
378 server->buffer_index = 0; | 315 server->buffer_index = 0; |
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 | |
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 | 322 |
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 */ |
425 if (strlen (username) > ERROR_MAX - 6) | 326 if (strlen (username) > ERROR_MAX - 6) |
1101 close (server->file); | 1002 close (server->file); |
1102 } | 1003 } |
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); |
1120 } | 1010 } |
1121 | 1011 |
1440 server->buffer_index = 0; | 1330 server->buffer_index = 0; |
1441 } | 1331 } |
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. | 1339 { |
1450 */ | 1340 server->buffer_size += GETLINE_INCR; |
1451 if (server->extra && | 1341 server->buffer = (char *)realloc (server->buffer, server->buffer_size); |
1452 ((Gssapi (server->extra)->gss_flags) & GSSAPI_NEEDWRAP)) | 1342 if (! server->buffer) |
1453 { | |
1454 char rcvbuf[GSSAPI_RCVBUF]; | |
1455 OM_uint32 major, minor, length; | |
1456 gss_buffer_desc in_tok, out_tok; | |
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 } | 1347 } |
1515 else | 1348 } |
1516 ret = 0; /* force detection of unexpected EOF */ | 1349 ret = RECV (server->file, server->buffer + server->data, |
1517 } | 1350 server->buffer_size - server->data - 1, 0); |
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 } | |
1536 ret = RECV (server->file, server->buffer + server->data, | |
1537 server->buffer_size - server->data - 1, 0); | |
1538 #ifdef GSSAPI | |
1539 } | |
1540 #endif /* GSSAPI */ | |
1541 if (ret < 0) | 1351 if (ret < 0) |
1542 { | 1352 { |
1543 strcpy (pop_error, GETLINE_ERROR); | 1353 strcpy (pop_error, GETLINE_ERROR); |
1544 strncat (pop_error, strerror (errno), | 1354 strncat (pop_error, strerror (errno), |
1545 ERROR_MAX - sizeof (GETLINE_ERROR)); | 1355 ERROR_MAX - sizeof (GETLINE_ERROR)); |
1579 } | 1389 } |
1580 | 1390 |
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 * |
1618 * Purpose: Sends a line of text to the POP server. The line of text | 1397 * Purpose: Sends a line of text to the POP server. The line of text |
1619 * passed into this function should NOT have the carriage return | 1398 * passed into this function should NOT have the carriage return |
1636 char *line; | 1415 char *line; |
1637 { | 1416 { |
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 | 1424 } |
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 } | |
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 { |
1725 pop_trash (server); | 1428 pop_trash (server); |
1726 strcpy (pop_error, SENDLINE_ERROR); | 1429 strcpy (pop_error, SENDLINE_ERROR); |
1884 if (server->buffer) | 1587 if (server->buffer) |
1885 { | 1588 { |
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 |
1905 if (have_winsock) | 1595 if (have_winsock) |
1906 WSACleanup (); | 1596 WSACleanup (); |
1907 #endif | 1597 #endif |
1908 } | 1598 } |
1909 | |
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 | 1599 |
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. */ |
2561 | 1603 |