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