gss.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:24k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: gss.c,v 1.48.4.2 1998/10/09 16:14:13 steve Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "threads.h"
  11. #include "buffer.h"
  12. #include "addr.h"
  13. #include "msg.h"
  14. #include "gss.h"
  15. #include "log.h"
  16. #ifdef HAVE_LIBGSSAPI_KRB5
  17. #include <gssapi/gssapi.h>
  18. #include <gssapi/gssapi_generic.h>
  19. #ifdef OLD_KERBEROS
  20. #define PREFIX "rcmd/"
  21. #else
  22. #define PREFIX "rcmd@"
  23. #endif
  24. #define GENCAP_VERS    0
  25. #define GENCAP_MTYP    1
  26. #define GENCAP_EOFF    2
  27. #define SETVERS(x, y) ((x)[0] = (u_char)(y))
  28. #define SETMTYP(x, y) ((x)[1] = (u_char)(y))
  29. #define SETELEN(x, y) do { u_short us = htons((short)(y)); memcpy((char *)((x)+GENCAP_EOFF), &us, sizeof(short)); } while (0)
  30. #define GETELEN(x, y) do { memcpy(&(y), (char *)((x)+GENCAP_EOFF), sizeof(short)); (y) = ntohs((y));              } while (0)
  31. #define ENCAP_NONE     0x00
  32. #define ENCAP_INTEG    0x01
  33. #define ENCAP_CONF     0x02
  34. #ifndef GSSAPI_TIMEOUT
  35. #define GSSAPI_TIMEOUT 15
  36. #endif
  37. IFTHREADED(static MUTEX_T krb_mutex = MUTEX_INITIALIZER;)
  38. IFTHREADED(extern MUTEX_T gh_mutex;)
  39. IFTHREADED(extern MUTEX_T env_mutex;)
  40. /* Where we'll keep the stuff associated with this authentication method...  */
  41. struct gssinfo {
  42.     int options;
  43.     gss_ctx_id_t context;
  44. };
  45. typedef struct gssinfo GssInfo;
  46. /* Display all the info we can about code (w/type type).                     */
  47. static void DisplayStatus(int code, int type) {
  48.     OM_uint32 maj_stat, min_stat, msg_ctx = 0;
  49.     gss_buffer_desc msg;
  50.     for (;;) {
  51. maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg);
  52. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: error: %s", (char *)msg.value); 
  53. (void) gss_release_buffer(&min_stat, &msg);
  54. if (!msg_ctx) break;
  55.     }
  56. }
  57. /* Simple routine to pull out the error codes from major & minor or ioerr.   */
  58. static void lsGssapiDisplayError(int major, int minor, int ioerr) {
  59.     if (ioerr) {
  60. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: io-error: %m");
  61.     } else {
  62. DisplayStatus(major, GSS_C_GSS_CODE);
  63. DisplayStatus(minor, GSS_C_MECH_CODE);
  64.     }
  65. }
  66. /* Find out the service name we'll need later.  Use the peer's name if we    */
  67. /* aren't a server, or our name if we are.  Either way, get the name of the  */
  68. /* person on the "server" end of fd.                                         */
  69. int lsGssapiServiceName(S5IOHandle fd, int server, gss_name_t *nameptr) {
  70.     int len = sizeof(S5NetAddr);
  71.     OM_uint32 status, trash;
  72.     char domain[MAXNAMELEN];
  73.     gss_buffer_desc buf;
  74.     struct hostent *hp;
  75.     S5NetAddr na;
  76.     
  77.     *domain = '';
  78.     if ((server  && REAL(getsockname)(fd, &na.sa, &len) < 0) ||
  79. (!server && REAL(getpeername)(fd, &na.sa, &len) < 0)) {
  80. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to get service name: %m");
  81. return -1;
  82.     }
  83.     
  84.     MUTEX_LOCK(gh_mutex);
  85.     if (!(hp = gethostbyaddr(lsAddr2Ptr(&na), lsAddrAddrSize(&na), na.sa.sa_family))) {
  86. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to Reverse Map peer name");
  87. MUTEX_UNLOCK(gh_mutex);
  88. return -1;
  89.     }
  90.     /* Try hacking it into a fully qualified domain name, although I doubt   */
  91.     /* it will work.  Actually who knows.                                    */
  92. #ifdef HAVE_GETDOMAINNAME
  93.     if (!strchr(hp->h_name, '.')) getdomainname(domain, MAXNAMELEN);
  94. #endif
  95.     if (!(buf.value = (char *)calloc(strlen(PREFIX) + strlen(hp->h_name) + strlen(domain) + 2, 1))) {
  96. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to allocate space for peer name");
  97. MUTEX_UNLOCK(gh_mutex);
  98. return -1;
  99.     }
  100.     strcat(strcpy(buf.value, PREFIX), hp->h_name);
  101.     MUTEX_UNLOCK(gh_mutex);    
  102.     if (*domain != '') strcat(strcat(buf.value, "."), domain);
  103.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "GSS: Importing name: %s", buf.value);
  104.     buf.length = strlen(buf.value);
  105. #ifdef OLD_KERBEROS
  106.     status = gss_import_name(&trash, &buf, GSS_C_NULL_OID, nameptr);
  107. #else
  108.     status = gss_import_name(&trash, &buf, gss_nt_service_name, nameptr);
  109. #endif
  110.     gss_release_buffer(&trash, &buf);
  111.     if (status != GSS_S_COMPLETE) {
  112. lsGssapiDisplayError(status, trash, 0);
  113. return -1;
  114.     } 
  115.     return 0;
  116. }
  117. #define GSSAPI_IOFLAGS S5_IOFLAGS_NBYTES|S5_IOFLAGS_TIMED|S5_IOFLAGS_RESTART
  118. static int RecvToken(S5IOHandle fd, u_char type, gss_buffer_t tok, OM_uint32 *trash) {
  119.     double timerm = (double)GSSAPI_TIMEOUT;
  120.     char buf[4], *token = NULL;
  121.     u_short len;
  122.     int rval;
  123.     /* Recv the header...                                                    */
  124.     if ((rval = S5IORecv(fd, NULL, buf, 4, 0, GSSAPI_IOFLAGS, &timerm)) != 4) {
  125. if (rval == 0) SETSOCKETERROR(ETIMEDOUT);
  126. return -1;
  127.     }
  128.     /* Validate the header...                                                */
  129.     if (buf[0] != (char)0x01 || buf[1] != (char)type) {
  130. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Bad Token");
  131. SETSOCKETERROR(EBADF);
  132. return -1;
  133.     }
  134.     GETELEN(buf, len);
  135.     /* Allocate the token.                                                   */
  136.     if (len > 0 && (token = (char *)malloc(len)) == NULL)  {
  137. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Recv Token: Malloc failed");
  138. SETSOCKETERROR(EBADF);
  139. return -1;
  140.     }
  141.     /* Recv the token itself.                                                */
  142.     if (len > 0 && (rval = S5IORecv(fd, NULL, token, len, 0, GSSAPI_IOFLAGS, &timerm)) != len) {
  143. if (rval == 0) SETSOCKETERROR(ETIMEDOUT);
  144. return -1;
  145.     }
  146.     /* Fill it in...                                                         */
  147.     tok->value  = token;
  148.     tok->length = len;
  149.     /* We're done...                                                         */
  150.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(8), 0, "GSS: Read a token of length: %d", len);
  151.     return 0;
  152. }
  153. static int SendToken(S5IOHandle fd, u_char type, gss_buffer_t tok, OM_uint32 *trash) {
  154.     double timerm = (double)GSSAPI_TIMEOUT;
  155.     u_short len = (u_short)tok->length;
  156.     char buf[4];
  157.     int sval;
  158.     /* Fill in the header.                                                   */
  159.     SETVERS(buf, 0x01);
  160.     SETMTYP(buf, type);
  161.     SETELEN(buf, len);
  162.     /* Send the header.                                                      */
  163.     if ((sval = S5IOSend(fd, NULL, buf, 4, 0, GSSAPI_IOFLAGS, &timerm)) != 4) {
  164. if (sval == 0) SETSOCKETERROR(ETIMEDOUT);
  165. return -1;
  166.     }
  167.     /* Send the token.                                                       */
  168.     if (tok->length && (sval = S5IOSend(fd, NULL, tok->value, tok->length, 0, GSSAPI_IOFLAGS, &timerm)) != tok->length) {
  169. if (sval == 0) SETSOCKETERROR(ETIMEDOUT);
  170. return -1;
  171.     }
  172.     /* We're done.                                                           */
  173.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(8), 0, "GSS: Sent a token of length: %d", tok->length);
  174.     return 0;
  175. }
  176. /* Encode ibuf into obuf...                                                  */
  177. static int lsGssapiEncodePacket(S5Packet *ibuf, S5Packet *obuf, void *context) {
  178.     GssInfo *ginfo = (GssInfo *)context;
  179.     gss_buffer_desc in, out;
  180.     OM_uint32 status, trash;
  181.     int state;
  182.     /* We can only send 2^16 bytes at a time, so only encapsulate 2^15       */
  183.     if (ibuf->len > (1 << 15)) ibuf->len = (1 << 15);
  184.     /* Initial setup...                                                      */
  185.     in.value   = ibuf->data;
  186.     in.length  = ibuf->len;
  187.     out.value  = NULL;
  188.     out.length = 0;
  189.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Encoding a message of length: %d", ibuf->len);
  190.     MUTEX_LOCK(krb_mutex);
  191.     /* Try to seal the message...XXX It would be nice to not have to malloc  */
  192.     /* & free the token, but the RFC is vague about what happens if you pass */
  193.     /* in a preallocated token & the kerberos implementation I looked at     */
  194.     /* just ignores it...                                                    */
  195.     if ((status = gss_seal(&trash, ginfo->context, ginfo->options, GSS_C_QOP_DEFAULT, &in, &state, &out)) != GSS_S_COMPLETE) {
  196. lsGssapiDisplayError(status, trash, 0);
  197. MUTEX_UNLOCK(krb_mutex);
  198. return -1;
  199.     }
  200.     MUTEX_UNLOCK(krb_mutex);
  201.     /* Make sure the message didn't get too big...                           */
  202.     if (out.length >= (1 << 16)) {
  203. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Encoded message too big to be encapsulated");
  204. gss_release_buffer(&trash, &out);
  205. return -1;
  206.     }
  207.     /* Allocate a buffer to hold the message in case we can't write it       */
  208.     /* all...XXX may want to realloc [or do nothing] if buffer is already    */
  209.     /* there [and big enough].                                               */
  210.     if ((obuf->data = (char *)malloc(out.length + 4)) == NULL) {
  211. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Out of memory when making header");
  212. gss_release_buffer(&trash, &out);
  213. return -1;
  214.     }
  215.     /* Setup the buffer...                                                   */
  216.     SETVERS(obuf->data, 0x01);
  217.     SETMTYP(obuf->data, 0x03);
  218.     SETELEN(obuf->data, out.length);
  219.     memcpy(obuf->data+4, out.value, out.length);
  220.     obuf->len = out.length + 4;
  221.     obuf->off = 0;
  222.     gss_release_buffer(&trash, &out);
  223.     /* We're done...                                                         */
  224.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done encoding message, output length: %d", obuf->len);
  225.     return ibuf->len;
  226. }
  227. /* Decode ibuf into obuf...                                                  */
  228. static int lsGssapiDecodePacket(S5Packet *ibuf, S5Packet *obuf, void *context) {
  229.     GssInfo *ginfo = (GssInfo *)context;
  230.     gss_buffer_desc in, out;
  231.     OM_uint32 status, trash;
  232.     u_char ver, mtype;
  233.     int state, qop;
  234.     u_short elen;
  235.     /* Pull off the header...                                                */
  236.     ver   = ibuf->data[GENCAP_VERS];
  237.     mtype = ibuf->data[GENCAP_MTYP];
  238.     GETELEN(ibuf->data, elen);
  239.     if ((ibuf->off - 4 != elen) || (ver != 0x01) || (mtype != 0x03)) {
  240. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Bad header on packet, ignoring.");
  241. return -1;
  242.     }
  243.     /* Setup the gss buffers.                                                */
  244.     in.value   = ibuf->data + 4;
  245.     in.length  = ibuf->off  - 4;
  246.     out.value  = NULL;
  247.     out.length = 0;
  248.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Decoding a message of length: %d", ibuf->off);
  249.     MUTEX_LOCK(krb_mutex);
  250.     /* Try to unseal the message...                                          */
  251.     if ((status = gss_unseal(&trash, ginfo->context, &in, &out, &state, &qop)) != GSS_S_COMPLETE) {
  252. lsGssapiDisplayError(status, trash, 0);
  253. MUTEX_UNLOCK(krb_mutex);
  254. return -1;
  255.     }
  256.     
  257.     MUTEX_UNLOCK(krb_mutex);
  258.     /* It worked, so we're done -- just copy out the pointer and the length. */
  259.     if ((obuf->data = (char *)malloc(out.length)) == NULL) {
  260. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Out of memory when copying data");
  261. gss_release_buffer(&trash, &out);
  262. return -1;
  263.     }
  264.     memcpy(obuf->data, out.value, out.length);
  265.     obuf->len  = out.length;
  266.     obuf->off  = 0;
  267.     
  268.     gss_release_buffer(&trash, &out);
  269.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done decoding message, output length: %d", obuf->len);
  270.     return obuf->len;
  271. }
  272. /* Encode or decode ibuf into obuf.                                          */
  273. static int lsGssapiCodePacket(S5Packet *ibuf, S5Packet *obuf, int direction, void *context) {
  274.     if (direction == S5_ENCODE) {
  275. return lsGssapiEncodePacket(ibuf, obuf, context);
  276.     } else {
  277. return lsGssapiDecodePacket(ibuf, obuf, context);
  278.     }
  279. }
  280. /* Check to see if a whole encapsulated packet is available...               */
  281. static int lsGssapiCheckPacket(S5Packet *buf, void *context) {
  282.     int len;
  283.     u_short tmp;
  284.     if (!buf->data) return 4;
  285.     if ((len = buf->len - 4) < 0) return -len;
  286.     GETELEN(buf->data, tmp);
  287.     if (len < tmp) return tmp - len;
  288.     return 0;
  289. }
  290. /* Cleanup the context we created...                                         */
  291. static int lsGssapiCleanContext(void *context) {
  292.     if (context) {
  293. OM_uint32 mstatus;
  294. MUTEX_LOCK(krb_mutex);
  295. gss_delete_sec_context(&mstatus, &((GssInfo *)context)->context, NULL);
  296. MUTEX_UNLOCK(krb_mutex);
  297. free(context);
  298.     }
  299.     return 1;
  300. }
  301. /* The GSS-API authentication method (kerberos5) for the client...           */
  302. int lsGssapiCliAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *name) {
  303.     OM_uint32 status, trash, junk, ret_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
  304.     gss_buffer_desc sendtok, recvtok, *token_ptr = GSS_C_NO_BUFFER;
  305.     gss_ctx_id_t context = GSS_C_NO_CONTEXT;
  306.     u_char enc = ENCAP_NONE;
  307.     gss_name_t server;
  308. #if defined(sun) && defined(__svr4__)
  309.     S5IOHandle junksd = S5InvalidIOHandle;
  310. #endif
  311.     int ioerr = 0;
  312.     recvtok.value  = NULL;
  313.     recvtok.length = 0;
  314.     sendtok.value  = NULL;
  315.     sendtok.length = 0;
  316.     MUTEX_LOCK(krb_mutex);
  317.     /* Find out the name of the service we'll be authenticating with...      */
  318.     if (lsGssapiServiceName(fd, 0, &server) < 0) {
  319. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Failed to determine service name");
  320. MUTEX_UNLOCK(krb_mutex);
  321. return AUTH_FAIL;
  322.     }
  323.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Imported name");
  324.     /* As long as we need to keep sending some context info, and there's no  */
  325.     /* errors, keep sending it...                                            */
  326.     for (;;) {
  327. status = gss_init_sec_context(&trash, GSS_C_NO_CREDENTIAL, &context, server,
  328.       GSS_C_NULL_OID, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
  329.       0, NULL, token_ptr, NULL, &sendtok, &ret_flags,
  330.       NULL);
  331. if (token_ptr != GSS_C_NO_BUFFER) gss_release_buffer(&junk, &recvtok);
  332. if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
  333.     gss_release_buffer(&junk, &sendtok);
  334.     break;
  335. }
  336. if (sendtok.length != 0) {
  337.     if ((ioerr = (SendToken(fd, 0x01, &sendtok, &trash) < 0))) {
  338. gss_release_buffer(&junk, &sendtok);
  339. break;
  340.     }
  341. }
  342. gss_release_buffer(&junk, &sendtok);
  343. if (status != GSS_S_CONTINUE_NEEDED)                             break;
  344. if ((ioerr = (RecvToken(fd, 0x01, &recvtok, &trash) < 0)))       break;
  345. token_ptr = &recvtok;
  346.     }
  347.     /* Solaris has a bug in dup function so we dup here to grab the socket   */
  348.     /* used by gssapi.      */
  349. #if defined(sun) && defined(__svr4__)
  350.     if (junksd == S5InvalidIOHandle) junksd = REAL(dup)(STDERR_FILENO);
  351.     else REAL(dup2)(STDERR_FILENO, junksd);
  352. #endif
  353.     /* We're done with the server's name, so we can release it.              */
  354.     gss_release_name(status?&junk:&trash, &server);
  355.     /* Make sure there wasn't an error...                                    */
  356.     if (ioerr || status != GSS_S_COMPLETE) {
  357. lsGssapiDisplayError(status, trash, ioerr);
  358. gss_delete_sec_context(&trash, &context, NULL);
  359. MUTEX_UNLOCK(krb_mutex);
  360.         return AUTH_FAIL;
  361.     }
  362.     /* Find out what kind of encapsulation we can/should do.                 */
  363.     MUTEX_LOCK(env_mutex);
  364.     if      ((ret_flags & GSS_C_CONF_FLAG)  &&  getenv("SOCKS5_ENCRYPT"))  enc = ENCAP_CONF;
  365.     else if ((ret_flags & GSS_C_INTEG_FLAG) && !getenv("SOCKS5_NOINTCHK")) enc = ENCAP_INTEG;
  366.     MUTEX_UNLOCK(env_mutex);
  367.     sendtok.value  = &enc;
  368.     sendtok.length = 1;
  369.     /* Send the server a message asking to do that method...                 */
  370.     if (SendToken(fd, 0x02, &sendtok, &trash) < 0) {
  371. lsGssapiDisplayError(0, 0, 1);
  372. gss_delete_sec_context(&trash, &context, NULL);
  373. MUTEX_UNLOCK(krb_mutex);
  374.         return AUTH_FAIL;
  375.     }
  376.     /* Find out what the server thinks we should do...                       */
  377.     if (RecvToken(fd, 0x02, &recvtok, &trash) < 0) {
  378. lsGssapiDisplayError(0, 0, 1);
  379. gss_delete_sec_context(&trash, &context, NULL);
  380. MUTEX_UNLOCK(krb_mutex);
  381.         return AUTH_FAIL;
  382.     }
  383.     enc = *(char *)recvtok.value;
  384.     gss_release_buffer(&trash, &recvtok);
  385.     /* If we'll be doing some kind of encapsulation, store the type and the  */
  386.     /* context.                                                              */
  387.     if (enc != 0x00) {
  388. ainfo->context = (void *)malloc(sizeof(GssInfo));
  389. if (!ainfo->context) {
  390.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Malloc failed");
  391.     gss_delete_sec_context(&trash, &context, NULL);
  392.     MUTEX_UNLOCK(krb_mutex);
  393.     return AUTH_FAIL;
  394. }
  395. ((GssInfo *)ainfo->context)->options = (enc == ENCAP_CONF)?1:0;
  396. ((GssInfo *)ainfo->context)->context = context;
  397. ainfo->clean  = lsGssapiCleanContext;
  398. ainfo->check  = lsGssapiCheckPacket;
  399. ainfo->encode = lsGssapiCodePacket;
  400.     } else {
  401. /* Otherwise delete the context...                                   */
  402. gss_delete_sec_context(&trash, &context, NULL);
  403.     }
  404.     /* We're done, so we can return...                                       */
  405.     MUTEX_UNLOCK(krb_mutex);
  406.     return AUTH_OK;
  407. }
  408. /* The GSS-API authentication method (kerberos5) for the server...           */
  409. int lsGssapiSrvAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *name) {
  410.     gss_cred_id_t creds  = GSS_C_NO_CREDENTIAL;
  411.     gss_ctx_id_t context = GSS_C_NO_CONTEXT;
  412.     gss_buffer_desc sendtok, recvtok;
  413.     OM_uint32 status, trash, junk, rflags;
  414.     gss_name_t client, server;
  415.     gss_OID doid;
  416.     u_char enc;
  417.     int ioerr;
  418.     recvtok.value  = NULL;
  419.     recvtok.length = 0;
  420.     sendtok.value  = NULL;
  421.     sendtok.length = 0;
  422.     MUTEX_LOCK(krb_mutex);
  423.     /* Find the name of the service we'll be using...                        */
  424.     if (lsGssapiServiceName(fd, 1, &server) < 0) {
  425. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Failed to determine service name");
  426. MUTEX_UNLOCK(krb_mutex);
  427. return AUTH_FAIL;
  428.     }
  429.     /* Acquire the initial credentials...                                    */
  430.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Imported name");
  431.     status = gss_acquire_cred(&trash, server, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &creds, NULL, NULL);
  432.     gss_release_name(&trash, &server);
  433.     /* Make sure everythings OK.                                             */
  434.     if (status != GSS_S_COMPLETE) {
  435. lsGssapiDisplayError(status, trash, 0);
  436. gss_delete_sec_context(&trash, &context, NULL);
  437. MUTEX_UNLOCK(krb_mutex);
  438. return AUTH_FAIL;
  439.     }
  440.     /* Keep accepting tokens and handling them as until we're done or        */
  441.     /* there's an error...                                                   */
  442.     for (;;) {
  443. if ((ioerr = RecvToken(fd, 0x01, &recvtok, &trash)) < 0)         break;
  444. status = gss_accept_sec_context(&trash, (gss_ctx_id_t *)&context, creds,
  445. &recvtok, GSS_C_NO_CHANNEL_BINDINGS,
  446. &client, &doid, &sendtok, &rflags, NULL,
  447. NULL);
  448. gss_release_buffer(&junk, &recvtok);
  449. if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
  450.     gss_release_buffer(&junk, &sendtok);
  451.     break;
  452. }
  453. if (sendtok.length != 0) {
  454.     if ((ioerr = SendToken(fd, 0x01, &sendtok, &trash)) < 0) {
  455.   gss_release_buffer(&junk, &sendtok);
  456.         break;
  457.     }
  458. }
  459. gss_release_buffer(&junk, &sendtok);
  460. if (status != GSS_S_CONTINUE_NEEDED)                             break;
  461.     }
  462.     /* Find out if we're done or if there was an error...If so, handle it.   */
  463.     if (ioerr || status != GSS_S_COMPLETE) {
  464. lsGssapiDisplayError(status, trash, ioerr);
  465. gss_delete_sec_context(&trash, &context, NULL);
  466. MUTEX_UNLOCK(krb_mutex);
  467. return AUTH_FAIL;
  468.     }
  469.     
  470.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done Authenticating; Displaying Name");
  471.     /* Get the name into a somewhat readable form.                           */
  472.     if ((status = gss_display_name(&trash, client, &sendtok, &doid)) != GSS_S_COMPLETE) {
  473. lsGssapiDisplayError(status, trash, 0);
  474. gss_delete_sec_context(&trash, &context, NULL);
  475. MUTEX_UNLOCK(krb_mutex);
  476. return AUTH_FAIL;
  477.     }
  478.     /* Copy the name into the space that was provided...                     */
  479.     if (sendtok.length >= S5_USERNAME_SIZE) sendtok.length = S5_USERNAME_SIZE-1;
  480.     strncpy(name, sendtok.value, sendtok.length);
  481.     gss_release_buffer(&trash, &sendtok);
  482.     /* Find out what the client wants to do encapsulation wise.              */
  483.     if (RecvToken(fd, 0x02, &recvtok, &trash) < 0) {
  484. lsGssapiDisplayError(0, 0, 1);
  485. gss_delete_sec_context(&trash, &context, NULL);
  486. MUTEX_UNLOCK(krb_mutex);
  487. return AUTH_FAIL;
  488.     }
  489.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Client asked for encapsulation #%d", (int)*(char *)recvtok.value);
  490.     MUTEX_LOCK(env_mutex);
  491.     if (getenv("SOCKS5_FORCE_ENCRYPT")) *(char *)recvtok.value = ENCAP_CONF;
  492.     MUTEX_UNLOCK(env_mutex);
  493.     /* Make sure we can do what we've decided we need to do...               */
  494.     if (*(char *)recvtok.value == ENCAP_INTEG && !(rflags & GSS_C_INTEG_FLAG)) {
  495. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Underlying Mechansim does not support plain integrity checking -- trying encryption");
  496. *(char *)recvtok.value = ENCAP_CONF;
  497.     }
  498.     if (*(char *)recvtok.value == ENCAP_CONF && !(rflags & GSS_C_CONF_FLAG)) {
  499. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Underlying Mechansim does not support encryption");
  500. gss_delete_sec_context(&trash, &context, NULL);
  501. MUTEX_UNLOCK(krb_mutex);
  502. return AUTH_FAIL;
  503.     }
  504.     /* Send back the decided encapsulation methode to the client.            */
  505.     enc = *(char *)recvtok.value;
  506.     if (SendToken(fd, 0x02, &recvtok, &trash) < 0) {
  507. lsGssapiDisplayError(0, 0, 1);
  508. gss_delete_sec_context(&trash, &context, NULL);
  509. MUTEX_UNLOCK(krb_mutex);
  510. return AUTH_FAIL;
  511.     }
  512.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Server Chose encapsulation #%d", enc);
  513.     gss_release_buffer(&trash, &recvtok);
  514.     /* As long as we're doing some kind of encapsulation, keep a context     */
  515.     /* around with the gssapi context in it and a byte saying what           */
  516.     /* encapsulation we will be doing.                                       */
  517.     if (enc != 0x00) {
  518. ainfo->context = (void *)malloc(sizeof(GssInfo));
  519. if (!ainfo->context) {
  520.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Malloc failed");
  521.     gss_delete_sec_context(&trash, &context, NULL);
  522.     MUTEX_UNLOCK(krb_mutex);
  523.     return AUTH_FAIL;
  524. }
  525. ((GssInfo *)ainfo->context)->options = (enc == ENCAP_CONF)?1:0;
  526. ((GssInfo *)ainfo->context)->context = context;
  527. ainfo->clean  = lsGssapiCleanContext;
  528. ainfo->check  = lsGssapiCheckPacket;
  529. ainfo->encode = lsGssapiCodePacket;
  530.     } else {
  531. /* Otherwise, get rid of the context, we won't need it anymore...    */
  532. gss_delete_sec_context(&trash, &context, NULL);
  533.     }
  534.     /* Everything's ok, so unlock the mutex and return...                    */
  535.     MUTEX_UNLOCK(krb_mutex);
  536.     return AUTH_OK;
  537. }
  538. #else
  539. /* Without Kerberos, we don't do anything.                                   */
  540. int lsGssapiCliAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *namep) {
  541.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Not compiled");
  542.     return AUTH_FAIL;
  543. }
  544. int lsGssapiSrvAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *namep) {
  545.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Not compiled");
  546.     return AUTH_FAIL;
  547. }
  548. #endif