diff --git a/conserver/client.h b/conserver/client.h index 66f4e65..84344b1 100644 --- a/conserver/client.h +++ b/conserver/client.h @@ -89,6 +89,7 @@ typedef struct client { /* Connection Information: */ FLAG confirmed; /* confirm state */ CLIENTSTATE cState; /* state needing confirmation */ char cOption; /* option initiating the confirmation */ + size_t tokenSize; /* buffer size for GSSAPI token */ } CONSCLIENT; extern void Replay(CONSENT *, CONSFILE *, unsigned short); diff --git a/conserver/group.c b/conserver/group.c index 0c5435b..5f5fe67 100644 --- a/conserver/group.c +++ b/conserver/group.c @@ -1964,13 +1964,19 @@ int AttemptGSSAPI(CONSCLIENT *pCL) { int nr, ret = 0; - char buf[1024]; + char *buf = NULL; gss_buffer_desc sendtok, recvtok, dbuf; gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT; OM_uint32 stmaj, stmin, mctx, dmin; gss_name_t user = 0; - if ((nr = FileRead(pCL->fd, buf, sizeof(buf))) <= 0) { + buf = malloc(pCL->tokenSize); + if (buf == NULL) { + Error("Unable to allocate a buffer for GSSAPI token"); + return -1; + } + if ((nr = FileRead(pCL->fd, buf, pCL->tokenSize)) <= 0) { + free(buf); return nr; } recvtok.value = buf; @@ -2009,6 +2015,8 @@ AttemptGSSAPI(CONSCLIENT *pCL) Error("GSSAPI didn't work, %*s", dbuf.length, dbuf.value); ret = -1; } + + free(buf); return ret; } #endif @@ -3097,12 +3105,31 @@ DoClientRead(GRPENT *pGE, CONSCLIENT *pCLServing) } #endif #if HAVE_GSSAPI +#define MAX_GSSAPI_TOKSIZE 64*1024 } else if (pCLServing->iState == S_IDENT && strcmp(pcCmd, "gssapi") == 0) { - FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); - /* Change the I/O mode right away, we'll do the read - * and accept when the select gets back to us */ - pCLServing->ioState = INGSSACCEPT; + if (pcArgs == (char *)0) { + FileWrite(pCLServing->fd, FLAGFALSE, + "gssapi requires argument\r\n", -1); + } else { + FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1); + /* Read the token size but limit it to 64K, + * that's practical limit for GSSAPI krb5 mechanism. + * + * The client connection will be rejected for large + * requests as server will not be able to parse + * incomplete ASN.1 but this is intentional. */ + pCLServing->tokenSize = (size_t) strtol(pcArgs, NULL, 10); + if (pCLServing->tokenSize > MAX_GSSAPI_TOKSIZE) { + FileWrite(pCLServing->fd, FLAGFALSE, + "gssapi token size too large\r\n", -1); + pCLServing->tokenSize = MAX_GSSAPI_TOKSIZE; + } + + /* Change the I/O mode right away, we'll do the read + * and accept when the select gets back to us */ + pCLServing->ioState = INGSSACCEPT; + } #endif } else if (pCLServing->iState == S_IDENT && strcmp(pcCmd, "login") == 0) { diff --git a/console/console.c b/console/console.c index 39daf03..087250a 100644 --- a/console/console.c +++ b/console/console.c @@ -167,11 +167,12 @@ AttemptSSL(CONSFILE *pcf) #endif #if HAVE_GSSAPI +#define MAX_GSSAPI_TOKSIZE 64*1024 gss_name_t gss_server_name = GSS_C_NO_NAME; gss_ctx_id_t secctx = GSS_C_NO_CONTEXT; gss_buffer_desc mytok = GSS_C_EMPTY_BUFFER; -int +size_t CanGetGSSContext(const char *servername) { char namestr[128]; @@ -208,18 +209,22 @@ CanGetGSSContext(const char *servername) } int -AttemptGSSAPI(CONSFILE *pcf) +AttemptGSSAPI(CONSFILE *pcf, size_t toksize) { OM_uint32 stmaj, stmin; gss_buffer_desc servertok; - char buf[1024]; + char *buf = NULL; int nr; int ret; + buf = malloc(toksize); + if (buf == NULL) { + return -1; + } FileSetQuoteIAC(pcf, FLAGFALSE); FileWrite(pcf, FLAGFALSE, mytok.value, mytok.length); FileSetQuoteIAC(pcf, FLAGTRUE); - nr = FileRead(pcf, buf, sizeof(buf)); + nr = FileRead(pcf, buf, toksize); servertok.length = nr; servertok.value = buf; @@ -233,6 +238,7 @@ AttemptGSSAPI(CONSFILE *pcf) ret = (stmaj == GSS_S_COMPLETE); gss_release_name(&stmin, &gss_server_name); + free(buf); return ret; } #endif @@ -1586,7 +1592,7 @@ DoCmds(char *master, char *pports, int cmdi) char *pcopy; char *serverName; #if HAVE_GSSAPI - int toksize; + size_t toksize; #endif if ((pcopy = ports = StrDup(pports)) == (char *)0) @@ -1671,10 +1677,16 @@ DoCmds(char *master, char *pports, int cmdi) #endif #if HAVE_GSSAPI if ((toksize = CanGetGSSContext(server)) > 0) { + if (toksize > MAX_GSSAPI_TOKSIZE) { + Error("Maximum support GSSAPI token size is %lu, " + "GSSAPI context creation reported %lu. " + "Server will reject authentication.", + MAX_GSSAPI_TOKSIZE, toksize); + } FilePrint(pcf, FLAGFALSE, "gssapi %d\r\n", toksize); t = ReadReply(pcf, FLAGFALSE); if (strcmp(t, "ok\r\n") == 0) { - if (AttemptGSSAPI(pcf)) { + if (AttemptGSSAPI(pcf, toksize)) { goto gssapi_logged_me_in; } }