gss.c
资源名称:socks5.zip [点击查看]
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:24k
源码类别:
代理服务器
开发平台:
Unix_Linux
- /* Copyright (c) 1995,1996,1997 NEC Corporation. All rights reserved. */
- /* */
- /* The redistribution, use and modification in source or binary forms of */
- /* this software is subject to the conditions set forth in the copyright */
- /* document ("Copyright") included with this distribution. */
- /*
- * $Id: gss.c,v 1.48.4.2 1998/10/09 16:14:13 steve Exp $
- */
- #include "socks5p.h"
- #include "threads.h"
- #include "buffer.h"
- #include "addr.h"
- #include "msg.h"
- #include "gss.h"
- #include "log.h"
- #ifdef HAVE_LIBGSSAPI_KRB5
- #include <gssapi/gssapi.h>
- #include <gssapi/gssapi_generic.h>
- #ifdef OLD_KERBEROS
- #define PREFIX "rcmd/"
- #else
- #define PREFIX "rcmd@"
- #endif
- #define GENCAP_VERS 0
- #define GENCAP_MTYP 1
- #define GENCAP_EOFF 2
- #define SETVERS(x, y) ((x)[0] = (u_char)(y))
- #define SETMTYP(x, y) ((x)[1] = (u_char)(y))
- #define SETELEN(x, y) do { u_short us = htons((short)(y)); memcpy((char *)((x)+GENCAP_EOFF), &us, sizeof(short)); } while (0)
- #define GETELEN(x, y) do { memcpy(&(y), (char *)((x)+GENCAP_EOFF), sizeof(short)); (y) = ntohs((y)); } while (0)
- #define ENCAP_NONE 0x00
- #define ENCAP_INTEG 0x01
- #define ENCAP_CONF 0x02
- #ifndef GSSAPI_TIMEOUT
- #define GSSAPI_TIMEOUT 15
- #endif
- IFTHREADED(static MUTEX_T krb_mutex = MUTEX_INITIALIZER;)
- IFTHREADED(extern MUTEX_T gh_mutex;)
- IFTHREADED(extern MUTEX_T env_mutex;)
- /* Where we'll keep the stuff associated with this authentication method... */
- struct gssinfo {
- int options;
- gss_ctx_id_t context;
- };
- typedef struct gssinfo GssInfo;
- /* Display all the info we can about code (w/type type). */
- static void DisplayStatus(int code, int type) {
- OM_uint32 maj_stat, min_stat, msg_ctx = 0;
- gss_buffer_desc msg;
- for (;;) {
- maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg);
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: error: %s", (char *)msg.value);
- (void) gss_release_buffer(&min_stat, &msg);
- if (!msg_ctx) break;
- }
- }
- /* Simple routine to pull out the error codes from major & minor or ioerr. */
- static void lsGssapiDisplayError(int major, int minor, int ioerr) {
- if (ioerr) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: io-error: %m");
- } else {
- DisplayStatus(major, GSS_C_GSS_CODE);
- DisplayStatus(minor, GSS_C_MECH_CODE);
- }
- }
- /* Find out the service name we'll need later. Use the peer's name if we */
- /* aren't a server, or our name if we are. Either way, get the name of the */
- /* person on the "server" end of fd. */
- int lsGssapiServiceName(S5IOHandle fd, int server, gss_name_t *nameptr) {
- int len = sizeof(S5NetAddr);
- OM_uint32 status, trash;
- char domain[MAXNAMELEN];
- gss_buffer_desc buf;
- struct hostent *hp;
- S5NetAddr na;
- *domain = ' ';
- if ((server && REAL(getsockname)(fd, &na.sa, &len) < 0) ||
- (!server && REAL(getpeername)(fd, &na.sa, &len) < 0)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to get service name: %m");
- return -1;
- }
- MUTEX_LOCK(gh_mutex);
- if (!(hp = gethostbyaddr(lsAddr2Ptr(&na), lsAddrAddrSize(&na), na.sa.sa_family))) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to Reverse Map peer name");
- MUTEX_UNLOCK(gh_mutex);
- return -1;
- }
- /* Try hacking it into a fully qualified domain name, although I doubt */
- /* it will work. Actually who knows. */
- #ifdef HAVE_GETDOMAINNAME
- if (!strchr(hp->h_name, '.')) getdomainname(domain, MAXNAMELEN);
- #endif
- if (!(buf.value = (char *)calloc(strlen(PREFIX) + strlen(hp->h_name) + strlen(domain) + 2, 1))) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Failed to allocate space for peer name");
- MUTEX_UNLOCK(gh_mutex);
- return -1;
- }
- strcat(strcpy(buf.value, PREFIX), hp->h_name);
- MUTEX_UNLOCK(gh_mutex);
- if (*domain != ' ') strcat(strcat(buf.value, "."), domain);
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "GSS: Importing name: %s", buf.value);
- buf.length = strlen(buf.value);
- #ifdef OLD_KERBEROS
- status = gss_import_name(&trash, &buf, GSS_C_NULL_OID, nameptr);
- #else
- status = gss_import_name(&trash, &buf, gss_nt_service_name, nameptr);
- #endif
- gss_release_buffer(&trash, &buf);
- if (status != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, 0);
- return -1;
- }
- return 0;
- }
- #define GSSAPI_IOFLAGS S5_IOFLAGS_NBYTES|S5_IOFLAGS_TIMED|S5_IOFLAGS_RESTART
- static int RecvToken(S5IOHandle fd, u_char type, gss_buffer_t tok, OM_uint32 *trash) {
- double timerm = (double)GSSAPI_TIMEOUT;
- char buf[4], *token = NULL;
- u_short len;
- int rval;
- /* Recv the header... */
- if ((rval = S5IORecv(fd, NULL, buf, 4, 0, GSSAPI_IOFLAGS, &timerm)) != 4) {
- if (rval == 0) SETSOCKETERROR(ETIMEDOUT);
- return -1;
- }
- /* Validate the header... */
- if (buf[0] != (char)0x01 || buf[1] != (char)type) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Bad Token");
- SETSOCKETERROR(EBADF);
- return -1;
- }
- GETELEN(buf, len);
- /* Allocate the token. */
- if (len > 0 && (token = (char *)malloc(len)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Recv Token: Malloc failed");
- SETSOCKETERROR(EBADF);
- return -1;
- }
- /* Recv the token itself. */
- if (len > 0 && (rval = S5IORecv(fd, NULL, token, len, 0, GSSAPI_IOFLAGS, &timerm)) != len) {
- if (rval == 0) SETSOCKETERROR(ETIMEDOUT);
- return -1;
- }
- /* Fill it in... */
- tok->value = token;
- tok->length = len;
- /* We're done... */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(8), 0, "GSS: Read a token of length: %d", len);
- return 0;
- }
- static int SendToken(S5IOHandle fd, u_char type, gss_buffer_t tok, OM_uint32 *trash) {
- double timerm = (double)GSSAPI_TIMEOUT;
- u_short len = (u_short)tok->length;
- char buf[4];
- int sval;
- /* Fill in the header. */
- SETVERS(buf, 0x01);
- SETMTYP(buf, type);
- SETELEN(buf, len);
- /* Send the header. */
- if ((sval = S5IOSend(fd, NULL, buf, 4, 0, GSSAPI_IOFLAGS, &timerm)) != 4) {
- if (sval == 0) SETSOCKETERROR(ETIMEDOUT);
- return -1;
- }
- /* Send the token. */
- if (tok->length && (sval = S5IOSend(fd, NULL, tok->value, tok->length, 0, GSSAPI_IOFLAGS, &timerm)) != tok->length) {
- if (sval == 0) SETSOCKETERROR(ETIMEDOUT);
- return -1;
- }
- /* We're done. */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(8), 0, "GSS: Sent a token of length: %d", tok->length);
- return 0;
- }
- /* Encode ibuf into obuf... */
- static int lsGssapiEncodePacket(S5Packet *ibuf, S5Packet *obuf, void *context) {
- GssInfo *ginfo = (GssInfo *)context;
- gss_buffer_desc in, out;
- OM_uint32 status, trash;
- int state;
- /* We can only send 2^16 bytes at a time, so only encapsulate 2^15 */
- if (ibuf->len > (1 << 15)) ibuf->len = (1 << 15);
- /* Initial setup... */
- in.value = ibuf->data;
- in.length = ibuf->len;
- out.value = NULL;
- out.length = 0;
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Encoding a message of length: %d", ibuf->len);
- MUTEX_LOCK(krb_mutex);
- /* Try to seal the message...XXX It would be nice to not have to malloc */
- /* & free the token, but the RFC is vague about what happens if you pass */
- /* in a preallocated token & the kerberos implementation I looked at */
- /* just ignores it... */
- if ((status = gss_seal(&trash, ginfo->context, ginfo->options, GSS_C_QOP_DEFAULT, &in, &state, &out)) != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, 0);
- MUTEX_UNLOCK(krb_mutex);
- return -1;
- }
- MUTEX_UNLOCK(krb_mutex);
- /* Make sure the message didn't get too big... */
- if (out.length >= (1 << 16)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Encoded message too big to be encapsulated");
- gss_release_buffer(&trash, &out);
- return -1;
- }
- /* Allocate a buffer to hold the message in case we can't write it */
- /* all...XXX may want to realloc [or do nothing] if buffer is already */
- /* there [and big enough]. */
- if ((obuf->data = (char *)malloc(out.length + 4)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Out of memory when making header");
- gss_release_buffer(&trash, &out);
- return -1;
- }
- /* Setup the buffer... */
- SETVERS(obuf->data, 0x01);
- SETMTYP(obuf->data, 0x03);
- SETELEN(obuf->data, out.length);
- memcpy(obuf->data+4, out.value, out.length);
- obuf->len = out.length + 4;
- obuf->off = 0;
- gss_release_buffer(&trash, &out);
- /* We're done... */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done encoding message, output length: %d", obuf->len);
- return ibuf->len;
- }
- /* Decode ibuf into obuf... */
- static int lsGssapiDecodePacket(S5Packet *ibuf, S5Packet *obuf, void *context) {
- GssInfo *ginfo = (GssInfo *)context;
- gss_buffer_desc in, out;
- OM_uint32 status, trash;
- u_char ver, mtype;
- int state, qop;
- u_short elen;
- /* Pull off the header... */
- ver = ibuf->data[GENCAP_VERS];
- mtype = ibuf->data[GENCAP_MTYP];
- GETELEN(ibuf->data, elen);
- if ((ibuf->off - 4 != elen) || (ver != 0x01) || (mtype != 0x03)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Bad header on packet, ignoring.");
- return -1;
- }
- /* Setup the gss buffers. */
- in.value = ibuf->data + 4;
- in.length = ibuf->off - 4;
- out.value = NULL;
- out.length = 0;
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Decoding a message of length: %d", ibuf->off);
- MUTEX_LOCK(krb_mutex);
- /* Try to unseal the message... */
- if ((status = gss_unseal(&trash, ginfo->context, &in, &out, &state, &qop)) != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, 0);
- MUTEX_UNLOCK(krb_mutex);
- return -1;
- }
- MUTEX_UNLOCK(krb_mutex);
- /* It worked, so we're done -- just copy out the pointer and the length. */
- if ((obuf->data = (char *)malloc(out.length)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Out of memory when copying data");
- gss_release_buffer(&trash, &out);
- return -1;
- }
- memcpy(obuf->data, out.value, out.length);
- obuf->len = out.length;
- obuf->off = 0;
- gss_release_buffer(&trash, &out);
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done decoding message, output length: %d", obuf->len);
- return obuf->len;
- }
- /* Encode or decode ibuf into obuf. */
- static int lsGssapiCodePacket(S5Packet *ibuf, S5Packet *obuf, int direction, void *context) {
- if (direction == S5_ENCODE) {
- return lsGssapiEncodePacket(ibuf, obuf, context);
- } else {
- return lsGssapiDecodePacket(ibuf, obuf, context);
- }
- }
- /* Check to see if a whole encapsulated packet is available... */
- static int lsGssapiCheckPacket(S5Packet *buf, void *context) {
- int len;
- u_short tmp;
- if (!buf->data) return 4;
- if ((len = buf->len - 4) < 0) return -len;
- GETELEN(buf->data, tmp);
- if (len < tmp) return tmp - len;
- return 0;
- }
- /* Cleanup the context we created... */
- static int lsGssapiCleanContext(void *context) {
- if (context) {
- OM_uint32 mstatus;
- MUTEX_LOCK(krb_mutex);
- gss_delete_sec_context(&mstatus, &((GssInfo *)context)->context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- free(context);
- }
- return 1;
- }
- /* The GSS-API authentication method (kerberos5) for the client... */
- int lsGssapiCliAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *name) {
- OM_uint32 status, trash, junk, ret_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
- gss_buffer_desc sendtok, recvtok, *token_ptr = GSS_C_NO_BUFFER;
- gss_ctx_id_t context = GSS_C_NO_CONTEXT;
- u_char enc = ENCAP_NONE;
- gss_name_t server;
- #if defined(sun) && defined(__svr4__)
- S5IOHandle junksd = S5InvalidIOHandle;
- #endif
- int ioerr = 0;
- recvtok.value = NULL;
- recvtok.length = 0;
- sendtok.value = NULL;
- sendtok.length = 0;
- MUTEX_LOCK(krb_mutex);
- /* Find out the name of the service we'll be authenticating with... */
- if (lsGssapiServiceName(fd, 0, &server) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Failed to determine service name");
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Imported name");
- /* As long as we need to keep sending some context info, and there's no */
- /* errors, keep sending it... */
- for (;;) {
- status = gss_init_sec_context(&trash, GSS_C_NO_CREDENTIAL, &context, server,
- GSS_C_NULL_OID, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
- 0, NULL, token_ptr, NULL, &sendtok, &ret_flags,
- NULL);
- if (token_ptr != GSS_C_NO_BUFFER) gss_release_buffer(&junk, &recvtok);
- if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
- gss_release_buffer(&junk, &sendtok);
- break;
- }
- if (sendtok.length != 0) {
- if ((ioerr = (SendToken(fd, 0x01, &sendtok, &trash) < 0))) {
- gss_release_buffer(&junk, &sendtok);
- break;
- }
- }
- gss_release_buffer(&junk, &sendtok);
- if (status != GSS_S_CONTINUE_NEEDED) break;
- if ((ioerr = (RecvToken(fd, 0x01, &recvtok, &trash) < 0))) break;
- token_ptr = &recvtok;
- }
- /* Solaris has a bug in dup function so we dup here to grab the socket */
- /* used by gssapi. */
- #if defined(sun) && defined(__svr4__)
- if (junksd == S5InvalidIOHandle) junksd = REAL(dup)(STDERR_FILENO);
- else REAL(dup2)(STDERR_FILENO, junksd);
- #endif
- /* We're done with the server's name, so we can release it. */
- gss_release_name(status?&junk:&trash, &server);
- /* Make sure there wasn't an error... */
- if (ioerr || status != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, ioerr);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Find out what kind of encapsulation we can/should do. */
- MUTEX_LOCK(env_mutex);
- if ((ret_flags & GSS_C_CONF_FLAG) && getenv("SOCKS5_ENCRYPT")) enc = ENCAP_CONF;
- else if ((ret_flags & GSS_C_INTEG_FLAG) && !getenv("SOCKS5_NOINTCHK")) enc = ENCAP_INTEG;
- MUTEX_UNLOCK(env_mutex);
- sendtok.value = &enc;
- sendtok.length = 1;
- /* Send the server a message asking to do that method... */
- if (SendToken(fd, 0x02, &sendtok, &trash) < 0) {
- lsGssapiDisplayError(0, 0, 1);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Find out what the server thinks we should do... */
- if (RecvToken(fd, 0x02, &recvtok, &trash) < 0) {
- lsGssapiDisplayError(0, 0, 1);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- enc = *(char *)recvtok.value;
- gss_release_buffer(&trash, &recvtok);
- /* If we'll be doing some kind of encapsulation, store the type and the */
- /* context. */
- if (enc != 0x00) {
- ainfo->context = (void *)malloc(sizeof(GssInfo));
- if (!ainfo->context) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Malloc failed");
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- ((GssInfo *)ainfo->context)->options = (enc == ENCAP_CONF)?1:0;
- ((GssInfo *)ainfo->context)->context = context;
- ainfo->clean = lsGssapiCleanContext;
- ainfo->check = lsGssapiCheckPacket;
- ainfo->encode = lsGssapiCodePacket;
- } else {
- /* Otherwise delete the context... */
- gss_delete_sec_context(&trash, &context, NULL);
- }
- /* We're done, so we can return... */
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_OK;
- }
- /* The GSS-API authentication method (kerberos5) for the server... */
- int lsGssapiSrvAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *name) {
- gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
- gss_ctx_id_t context = GSS_C_NO_CONTEXT;
- gss_buffer_desc sendtok, recvtok;
- OM_uint32 status, trash, junk, rflags;
- gss_name_t client, server;
- gss_OID doid;
- u_char enc;
- int ioerr;
- recvtok.value = NULL;
- recvtok.length = 0;
- sendtok.value = NULL;
- sendtok.length = 0;
- MUTEX_LOCK(krb_mutex);
- /* Find the name of the service we'll be using... */
- if (lsGssapiServiceName(fd, 1, &server) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Failed to determine service name");
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Acquire the initial credentials... */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Imported name");
- status = gss_acquire_cred(&trash, server, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &creds, NULL, NULL);
- gss_release_name(&trash, &server);
- /* Make sure everythings OK. */
- if (status != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, 0);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Keep accepting tokens and handling them as until we're done or */
- /* there's an error... */
- for (;;) {
- if ((ioerr = RecvToken(fd, 0x01, &recvtok, &trash)) < 0) break;
- status = gss_accept_sec_context(&trash, (gss_ctx_id_t *)&context, creds,
- &recvtok, GSS_C_NO_CHANNEL_BINDINGS,
- &client, &doid, &sendtok, &rflags, NULL,
- NULL);
- gss_release_buffer(&junk, &recvtok);
- if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
- gss_release_buffer(&junk, &sendtok);
- break;
- }
- if (sendtok.length != 0) {
- if ((ioerr = SendToken(fd, 0x01, &sendtok, &trash)) < 0) {
- gss_release_buffer(&junk, &sendtok);
- break;
- }
- }
- gss_release_buffer(&junk, &sendtok);
- if (status != GSS_S_CONTINUE_NEEDED) break;
- }
- /* Find out if we're done or if there was an error...If so, handle it. */
- if (ioerr || status != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, ioerr);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Done Authenticating; Displaying Name");
- /* Get the name into a somewhat readable form. */
- if ((status = gss_display_name(&trash, client, &sendtok, &doid)) != GSS_S_COMPLETE) {
- lsGssapiDisplayError(status, trash, 0);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Copy the name into the space that was provided... */
- if (sendtok.length >= S5_USERNAME_SIZE) sendtok.length = S5_USERNAME_SIZE-1;
- strncpy(name, sendtok.value, sendtok.length);
- gss_release_buffer(&trash, &sendtok);
- /* Find out what the client wants to do encapsulation wise. */
- if (RecvToken(fd, 0x02, &recvtok, &trash) < 0) {
- lsGssapiDisplayError(0, 0, 1);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Client asked for encapsulation #%d", (int)*(char *)recvtok.value);
- MUTEX_LOCK(env_mutex);
- if (getenv("SOCKS5_FORCE_ENCRYPT")) *(char *)recvtok.value = ENCAP_CONF;
- MUTEX_UNLOCK(env_mutex);
- /* Make sure we can do what we've decided we need to do... */
- if (*(char *)recvtok.value == ENCAP_INTEG && !(rflags & GSS_C_INTEG_FLAG)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Underlying Mechansim does not support plain integrity checking -- trying encryption");
- *(char *)recvtok.value = ENCAP_CONF;
- }
- if (*(char *)recvtok.value == ENCAP_CONF && !(rflags & GSS_C_CONF_FLAG)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Underlying Mechansim does not support encryption");
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- /* Send back the decided encapsulation methode to the client. */
- enc = *(char *)recvtok.value;
- if (SendToken(fd, 0x02, &recvtok, &trash) < 0) {
- lsGssapiDisplayError(0, 0, 1);
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GSS: Server Chose encapsulation #%d", enc);
- gss_release_buffer(&trash, &recvtok);
- /* As long as we're doing some kind of encapsulation, keep a context */
- /* around with the gssapi context in it and a byte saying what */
- /* encapsulation we will be doing. */
- if (enc != 0x00) {
- ainfo->context = (void *)malloc(sizeof(GssInfo));
- if (!ainfo->context) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GSS: Malloc failed");
- gss_delete_sec_context(&trash, &context, NULL);
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_FAIL;
- }
- ((GssInfo *)ainfo->context)->options = (enc == ENCAP_CONF)?1:0;
- ((GssInfo *)ainfo->context)->context = context;
- ainfo->clean = lsGssapiCleanContext;
- ainfo->check = lsGssapiCheckPacket;
- ainfo->encode = lsGssapiCodePacket;
- } else {
- /* Otherwise, get rid of the context, we won't need it anymore... */
- gss_delete_sec_context(&trash, &context, NULL);
- }
- /* Everything's ok, so unlock the mutex and return... */
- MUTEX_UNLOCK(krb_mutex);
- return AUTH_OK;
- }
- #else
- /* Without Kerberos, we don't do anything. */
- int lsGssapiCliAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *namep) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Not compiled");
- return AUTH_FAIL;
- }
- int lsGssapiSrvAuth(S5IOHandle fd, S5AuthInfo *ainfo, char *namep) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "GSS: Not compiled");
- return AUTH_FAIL;
- }
- #endif