[PATCH] updated GSSAPI client split
Alexey Mahotkin <[email protected]>
| Newsgroups | gmane.comp.version-control.cvs.bugs |
|---|---|
| Message-ID | <[email protected]> |
[ Several more little things split out. Needs all of the above patches. ] TODO: recv_bytes() probably needs to be moved to socket-client.c too, but that could be done later. Kerberos later, and split in at least four pieces. 2003-05-07 Alexey Mahotkin <[email protected]> Move GSSAPI client stuff from client.c to gssapi-client.[ch]; move GSSAPI buffers from server.c to gssapi-client.[ch]; compile gssapi-client.c only if GSSAPI is found by configure; move global `gcontext' variable to gssapi-client.c and use a simple wrapper initialize_gssapi_buffers() in client.c to hide accesses to it; acinclude.m4 | 2 configure.in | 3 src/Makefile.am | 5 src/client.c | 182 ----------------------------- src/client.h | 15 -- src/gssapi-client.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gssapi-client.h | 38 ++++++ src/server.c | 135 ---------------------- 8 files changed, 372 insertions(+), 325 deletions(-) --- ccvs/acinclude.m4~gssapi-client Wed May 7 21:50:48 2003 +++ ccvs-alexm/acinclude.m4 Wed May 7 21:52:12 2003 @@ -102,6 +102,8 @@ if test x$acx_gssapi_cv_gssapi != xno; t [Define if you have GSSAPI with Kerberos version 5 available.]) CPPFLAGS=$CPPFLAGS$GSSAPI_INCLUDES + client_objects="$client_objects gssapi-client.o" + # locate any other headers dnl We don't use HAVE_KRB5_H anywhere, but including it here might make it dnl easier to spot errors by reading configure output --- ccvs/configure.in~gssapi-client Wed May 7 21:50:48 2003 +++ ccvs-alexm/configure.in Wed May 7 21:50:56 2003 @@ -312,6 +312,9 @@ dnl just added libnsl above if we found AC_SEARCH_LIBS(gethostbyname, netinet) +AC_SUBST(client_objects) + + dnl dnl begin --with-* dnl --- ccvs/src/client.c~gssapi-client Wed May 7 21:50:48 2003 +++ ccvs-alexm/src/client.c Wed May 7 21:58:09 2003 @@ -30,6 +30,8 @@ #include "socket-client.h" #include "rsh-client.h" +#include "gssapi-client.h" + # if HAVE_KERBEROS # include <krb.h> @@ -45,17 +47,6 @@ static Key_schedule sched; # endif /* HAVE_KERBEROS */ -# ifdef HAVE_GSSAPI - -# include "xgssapi.h" - -/* This is needed for GSSAPI encryption. */ -static gss_ctx_id_t gcontext; - -static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *)); - -# endif /* HAVE_GSSAPI */ - static void add_prune_candidate PROTO((char *)); /* All the commands. */ @@ -3623,156 +3614,6 @@ start_tcp_server (root, to_server_p, fro #endif /* HAVE_KERBEROS */ -#ifdef HAVE_GSSAPI - -/* Receive a given number of bytes. */ - -static void -recv_bytes (sock, buf, need) - int sock; - char *buf; - int need; -{ - while (need > 0) - { - int got; - - got = recv (sock, buf, need, 0); - if (got <= 0) - error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, - got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); - - buf += got; - need -= got; - } -} - -/* Connect to the server using GSSAPI authentication. */ - -/* FIXME - * - * This really needs to be rewritten to use a buffer and not a socket. - * This would enable gserver to work with the SSL code I'm about to commit - * since the SSL connection is going to look like a FIFO and not a socket. - * - * I think, basically, it will need to use buf_output and buf_read directly - * since I don't think there is a read_bytes function - only read_line. - * - * recv_bytes could then be removed too. - * - * Besides, I added some cruft to reenable the socket which shouldn't be - * there. This would also enable its removal. - */ -#define BUFSIZE 1024 -static int -connect_to_gserver (root, sock, hostinfo) - cvsroot_t *root; - int sock; - struct hostent *hostinfo; -{ - char *str; - char buf[BUFSIZE]; - gss_buffer_desc *tok_in_ptr, tok_in, tok_out; - OM_uint32 stat_min, stat_maj; - gss_name_t server_name; - - str = "BEGIN GSSAPI REQUEST\012"; - - if (send (sock, str, strlen (str), 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - - if (strlen (hostinfo->h_name) > BUFSIZE - 5) - error (1, 0, "Internal error: hostname exceeds length of buffer"); - sprintf (buf, "cvs@%s", hostinfo->h_name); - tok_in.length = strlen (buf); - tok_in.value = buf; - gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE, - &server_name); - - tok_in_ptr = GSS_C_NO_BUFFER; - gcontext = GSS_C_NO_CONTEXT; - - do - { - stat_maj = gss_init_sec_context (&stat_min, GSS_C_NO_CREDENTIAL, - &gcontext, server_name, - GSS_C_NULL_OID, - (GSS_C_MUTUAL_FLAG - | GSS_C_REPLAY_FLAG), - 0, NULL, tok_in_ptr, NULL, &tok_out, - NULL, NULL); - if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED) - { - OM_uint32 message_context; - OM_uint32 new_stat_min; - - message_context = 0; - gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, - GSS_C_NULL_OID, &message_context, &tok_out); - error (0, 0, "GSSAPI authentication failed: %s", - (char *) tok_out.value); - - message_context = 0; - gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, - GSS_C_NULL_OID, &message_context, &tok_out); - error (1, 0, "GSSAPI authentication failed: %s", - (char *) tok_out.value); - } - - if (tok_out.length == 0) - { - tok_in.length = 0; - } - else - { - char cbuf[2]; - int need; - - cbuf[0] = (tok_out.length >> 8) & 0xff; - cbuf[1] = tok_out.length & 0xff; - if (send (sock, cbuf, 2, 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - if (send (sock, tok_out.value, tok_out.length, 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - - recv_bytes (sock, cbuf, 2); - need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); - - if (need > sizeof buf) - { - int got; - - /* This usually means that the server sent us an error - message. Read it byte by byte and print it out. - FIXME: This is a terrible error handling strategy. - However, even if we fix the server, we will still - want to do this to work with older servers. */ - buf[0] = cbuf[0]; - buf[1] = cbuf[1]; - got = recv (sock, buf + 2, sizeof buf - 2, 0); - if (got < 0) - error (1, 0, "recv() from server %s: %s", - root->hostname, SOCK_STRERROR (SOCK_ERRNO)); - buf[got + 2] = '\0'; - if (buf[got + 1] == '\n') - buf[got + 1] = '\0'; - error (1, 0, "error from server %s: %s", root->hostname, - buf); - } - - recv_bytes (sock, buf, need); - tok_in.length = need; - } - - tok_in.value = buf; - tok_in_ptr = &tok_in; - } - while (stat_maj == GSS_S_CONTINUE_NEEDED); - - return 1; -} - -#endif /* HAVE_GSSAPI */ static int send_variable_proc PROTO ((Node *, void *)); @@ -4051,14 +3892,7 @@ start_server () if (! supported_request ("Gssapi-encrypt")) error (1, 0, "This server does not support encryption"); send_to_server ("Gssapi-encrypt\012", 0); - global_to_server = cvs_gssapi_wrap_buffer_initialize (global_to_server, 0, - gcontext, - ((BUFMEMERRPROC) - NULL)); - global_from_server = cvs_gssapi_wrap_buffer_initialize (global_from_server, 1, - gcontext, - ((BUFMEMERRPROC) - NULL)); + initialize_gssapi_buffers(&global_to_server, &global_from_server); cvs_gssapi_encrypt = 1; } else @@ -4124,14 +3958,8 @@ start_server () error (1, 0, "This server does not support stream authentication"); send_to_server ("Gssapi-authenticate\012", 0); - global_to_server = cvs_gssapi_wrap_buffer_initialize (global_to_server, 0, - gcontext, - ((BUFMEMERRPROC) - NULL)); - global_from_server = cvs_gssapi_wrap_buffer_initialize (global_from_server, 1, - gcontext, - ((BUFMEMERRPROC) - NULL)); + initialize_gssapi_buffers(&global_to_server, &global_from_server); + } else error (1, 0, "Stream authentication is only supported when using GSSAPI"); --- ccvs/src/client.h~gssapi-client Wed May 7 21:50:48 2003 +++ ccvs-alexm/src/client.h Wed May 7 21:50:56 2003 @@ -37,22 +37,7 @@ extern struct buffer *krb_encrypt_buffer # endif /* HAVE_KERBEROS */ -# ifdef HAVE_GSSAPI - -/* Set this to turn on GSSAPI encryption. */ -extern int cvs_gssapi_encrypt; - -# endif /* HAVE_GSSAPI */ - # endif /* ENCRYPTION */ - -# ifdef HAVE_GSSAPI - -/* We can't declare the arguments without including gssapi.h, and I - don't want to do that in every file. */ -extern struct buffer *cvs_gssapi_wrap_buffer_initialize (); - -# endif /* HAVE_GSSAPI */ #endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */ --- /dev/null Wed Jan 1 02:48:46 2003 +++ ccvs-alexm/src/gssapi-client.c Wed May 7 22:08:03 2003 @@ -0,0 +1,317 @@ +/* CVS GSSAPI client stuff. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + + +#include <config.h> + +#include "cvs.h" + +#include "buffer.h" +#include "socket-client.h" +#include "gssapi-client.h" + +/* This is needed for GSSAPI encryption. */ +gss_ctx_id_t gcontext; + +# ifdef ENCRYPTION +/* Whether to encrypt GSSAPI communication. We use a global variable + like this because we use the same buffer type (gssapi_wrap) to + handle both authentication and encryption, and we don't want + multiple instances of that buffer in the communication stream. */ +int cvs_gssapi_encrypt; +# endif + + +/* Receive a given number of bytes. */ + +static void +recv_bytes (sock, buf, need) + int sock; + char *buf; + int need; +{ + while (need > 0) + { + int got; + + got = recv (sock, buf, need, 0); + if (got <= 0) + error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, + got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); + + buf += got; + need -= got; + } +} + +/* Connect to the server using GSSAPI authentication. */ + +/* FIXME + * + * This really needs to be rewritten to use a buffer and not a socket. + * This would enable gserver to work with the SSL code I'm about to commit + * since the SSL connection is going to look like a FIFO and not a socket. + * + * I think, basically, it will need to use buf_output and buf_read directly + * since I don't think there is a read_bytes function - only read_line. + * + * recv_bytes could then be removed too. + * + * Besides, I added some cruft to reenable the socket which shouldn't be + * there. This would also enable its removal. + */ +#define BUFSIZE 1024 +int +connect_to_gserver (root, sock, hostinfo) + cvsroot_t *root; + int sock; + struct hostent *hostinfo; +{ + char *str; + char buf[BUFSIZE]; + gss_buffer_desc *tok_in_ptr, tok_in, tok_out; + OM_uint32 stat_min, stat_maj; + gss_name_t server_name; + + str = "BEGIN GSSAPI REQUEST\012"; + + if (send (sock, str, strlen (str), 0) < 0) + error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); + + if (strlen (hostinfo->h_name) > BUFSIZE - 5) + error (1, 0, "Internal error: hostname exceeds length of buffer"); + sprintf (buf, "cvs@%s", hostinfo->h_name); + tok_in.length = strlen (buf); + tok_in.value = buf; + gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE, + &server_name); + + tok_in_ptr = GSS_C_NO_BUFFER; + gcontext = GSS_C_NO_CONTEXT; + + do + { + stat_maj = gss_init_sec_context (&stat_min, GSS_C_NO_CREDENTIAL, + &gcontext, server_name, + GSS_C_NULL_OID, + (GSS_C_MUTUAL_FLAG + | GSS_C_REPLAY_FLAG), + 0, NULL, tok_in_ptr, NULL, &tok_out, + NULL, NULL); + if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED) + { + OM_uint32 message_context; + OM_uint32 new_stat_min; + + message_context = 0; + gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, + GSS_C_NULL_OID, &message_context, &tok_out); + error (0, 0, "GSSAPI authentication failed: %s", + (char *) tok_out.value); + + message_context = 0; + gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, + GSS_C_NULL_OID, &message_context, &tok_out); + error (1, 0, "GSSAPI authentication failed: %s", + (char *) tok_out.value); + } + + if (tok_out.length == 0) + { + tok_in.length = 0; + } + else + { + char cbuf[2]; + int need; + + cbuf[0] = (tok_out.length >> 8) & 0xff; + cbuf[1] = tok_out.length & 0xff; + if (send (sock, cbuf, 2, 0) < 0) + error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); + if (send (sock, tok_out.value, tok_out.length, 0) < 0) + error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); + + recv_bytes (sock, cbuf, 2); + need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); + + if (need > sizeof buf) + { + int got; + + /* This usually means that the server sent us an error + message. Read it byte by byte and print it out. + FIXME: This is a terrible error handling strategy. + However, even if we fix the server, we will still + want to do this to work with older servers. */ + buf[0] = cbuf[0]; + buf[1] = cbuf[1]; + got = recv (sock, buf + 2, sizeof buf - 2, 0); + if (got < 0) + error (1, 0, "recv() from server %s: %s", + root->hostname, SOCK_STRERROR (SOCK_ERRNO)); + buf[got + 2] = '\0'; + if (buf[got + 1] == '\n') + buf[got + 1] = '\0'; + error (1, 0, "error from server %s: %s", root->hostname, + buf); + } + + recv_bytes (sock, buf, need); + tok_in.length = need; + } + + tok_in.value = buf; + tok_in_ptr = &tok_in; + } + while (stat_maj == GSS_S_CONTINUE_NEEDED); + + return 1; +} + + +/* A buffer interface using GSSAPI. It is built on top of a + packetizing buffer. */ + +/* This structure is the closure field of the GSSAPI translation + routines. */ + +struct cvs_gssapi_wrap_data +{ + /* The GSSAPI context. */ + gss_ctx_id_t gcontext; +}; + +static int cvs_gssapi_wrap_input PROTO((void *, const char *, char *, int)); +static int cvs_gssapi_wrap_output PROTO((void *, const char *, char *, int, + int *)); + +/* Create a GSSAPI wrapping buffer. We use a packetizing buffer with + GSSAPI wrapping routines. */ + +struct buffer * +cvs_gssapi_wrap_buffer_initialize (buf, input, gcontext, memory) + struct buffer *buf; + int input; + gss_ctx_id_t gcontext; + void (*memory) PROTO((struct buffer *)); +{ + struct cvs_gssapi_wrap_data *gd; + + gd = (struct cvs_gssapi_wrap_data *) xmalloc (sizeof *gd); + gd->gcontext = gcontext; + + return (packetizing_buffer_initialize + (buf, + input ? cvs_gssapi_wrap_input : NULL, + input ? NULL : cvs_gssapi_wrap_output, + gd, + memory)); +} + +/* Unwrap data using GSSAPI. */ + +static int +cvs_gssapi_wrap_input (fnclosure, input, output, size) + void *fnclosure; + const char *input; + char *output; + int size; +{ + struct cvs_gssapi_wrap_data *gd = + (struct cvs_gssapi_wrap_data *) fnclosure; + gss_buffer_desc inbuf, outbuf; + OM_uint32 stat_min; + int conf; + + inbuf.value = (void *) input; + inbuf.length = size; + + if (gss_unwrap (&stat_min, gd->gcontext, &inbuf, &outbuf, &conf, NULL) + != GSS_S_COMPLETE) + { + error (1, 0, "gss_unwrap failed"); + } + + if (outbuf.length > size) + abort (); + + memcpy (output, outbuf.value, outbuf.length); + + /* The real packet size is stored in the data, so we don't need to + remember outbuf.length. */ + + gss_release_buffer (&stat_min, &outbuf); + + return 0; +} + +/* Wrap data using GSSAPI. */ + +static int +cvs_gssapi_wrap_output (fnclosure, input, output, size, translated) + void *fnclosure; + const char *input; + char *output; + int size; + int *translated; +{ + struct cvs_gssapi_wrap_data *gd = + (struct cvs_gssapi_wrap_data *) fnclosure; + gss_buffer_desc inbuf, outbuf; + OM_uint32 stat_min; + int conf_req, conf; + + inbuf.value = (void *) input; + inbuf.length = size; + +#ifdef ENCRYPTION + conf_req = cvs_gssapi_encrypt; +#else + conf_req = 0; +#endif + + if (gss_wrap (&stat_min, gd->gcontext, conf_req, GSS_C_QOP_DEFAULT, + &inbuf, &conf, &outbuf) != GSS_S_COMPLETE) + error (1, 0, "gss_wrap failed"); + + /* The packetizing buffer only permits us to add 100 bytes. + FIXME: I don't know what, if anything, is guaranteed by GSSAPI. + This may need to be increased for a different GSSAPI + implementation, or we may need a different algorithm. */ + if (outbuf.length > size + 100) + abort (); + + memcpy (output, outbuf.value, outbuf.length); + + *translated = outbuf.length; + + gss_release_buffer (&stat_min, &outbuf); + + return 0; +} + +void +initialize_gssapi_buffers (to_server_p, from_server_p) + struct buffer **to_server_p; + struct buffer **from_server_p; +{ + *to_server_p = cvs_gssapi_wrap_buffer_initialize (*to_server_p, 0, + gcontext, + ((BUFMEMERRPROC) + NULL)); + + *from_server_p = cvs_gssapi_wrap_buffer_initialize (*from_server_p, 1, + gcontext, + ((BUFMEMERRPROC) + NULL)); +} --- /dev/null Wed Jan 1 02:48:46 2003 +++ ccvs-alexm/src/gssapi-client.h Wed May 7 22:03:56 2003 @@ -0,0 +1,38 @@ +/* CVS GSSAPI client stuff. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + + +#ifndef GSSAPI_CLIENT_H__ +#define GSSAPI_CLIENT_H__ + +#include "xgssapi.h" + +#include "socket-client.h" + +/* Set this to turn on GSSAPI encryption. */ +extern int cvs_gssapi_encrypt; + +extern gss_ctx_id_t gcontext; + +/* We can't declare the arguments without including gssapi.h, and I + don't want to do that in every file. */ +struct buffer* cvs_gssapi_wrap_buffer_initialize PROTO((struct buffer *buf, + int input, + gss_ctx_id_t gcontext, + void (*memory) PROTO((struct buffer *)))); + +int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *)); + +extern void initialize_gssapi_buffers PROTO((struct buffer **to_server_p, + struct buffer **from_server_p)); + +#endif --- ccvs/src/Makefile.am~gssapi-client Wed May 7 21:50:48 2003 +++ ccvs-alexm/src/Makefile.am Wed May 7 21:50:56 2003 @@ -94,7 +94,10 @@ cvs_SOURCES = \ update.h \ watch.h -cvs_LDADD = \ +EXTRA_cvs_SOURCES = gssapi-client.c gssapi-client.h + +cvs_DEPENDENCIES = @client_objects@ +cvs_LDADD = @client_objects@ \ ../diff/libdiff.a \ ../lib/libcvs.a \ ../zlib/libz.a --- ccvs/src/server.c~gssapi-client Wed May 7 21:50:49 2003 +++ ccvs-alexm/src/server.c Wed May 7 21:50:56 2003 @@ -17,6 +17,9 @@ #include "buffer.h" #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) + +#include "gssapi-client.h" + # ifdef HAVE_GSSAPI /* This stuff isn't included solely with SERVER_SUPPORT since some of these * functions (encryption & the like) get compiled with or without server @@ -38,13 +41,6 @@ static void gserver_authenticate_connect /* Whether we are already wrapping GSSAPI communication. */ static int cvs_gssapi_wrapping; -# ifdef ENCRYPTION -/* Whether to encrypt GSSAPI communication. We use a global variable - like this because we use the same buffer type (gssapi_wrap) to - handle both authentication and encryption, and we don't want - multiple instances of that buffer in the communication stream. */ -int cvs_gssapi_encrypt; -# endif # endif /* HAVE_GSSAPI */ #endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */ @@ -5974,131 +5970,6 @@ int cvsencrypt; /* This global variable is non-zero if the users requests stream authentication on the command line. */ int cvsauthenticate; - -#ifdef HAVE_GSSAPI - -/* An buffer interface using GSSAPI. This is built on top of a - packetizing buffer. */ - -/* This structure is the closure field of the GSSAPI translation - routines. */ - -struct cvs_gssapi_wrap_data -{ - /* The GSSAPI context. */ - gss_ctx_id_t gcontext; -}; - -static int cvs_gssapi_wrap_input PROTO((void *, const char *, char *, int)); -static int cvs_gssapi_wrap_output PROTO((void *, const char *, char *, int, - int *)); - -/* Create a GSSAPI wrapping buffer. We use a packetizing buffer with - GSSAPI wrapping routines. */ - -struct buffer * -cvs_gssapi_wrap_buffer_initialize (buf, input, gcontext, memory) - struct buffer *buf; - int input; - gss_ctx_id_t gcontext; - void (*memory) PROTO((struct buffer *)); -{ - struct cvs_gssapi_wrap_data *gd; - - gd = (struct cvs_gssapi_wrap_data *) xmalloc (sizeof *gd); - gd->gcontext = gcontext; - - return (packetizing_buffer_initialize - (buf, - input ? cvs_gssapi_wrap_input : NULL, - input ? NULL : cvs_gssapi_wrap_output, - gd, - memory)); -} - -/* Unwrap data using GSSAPI. */ - -static int -cvs_gssapi_wrap_input (fnclosure, input, output, size) - void *fnclosure; - const char *input; - char *output; - int size; -{ - struct cvs_gssapi_wrap_data *gd = - (struct cvs_gssapi_wrap_data *) fnclosure; - gss_buffer_desc inbuf, outbuf; - OM_uint32 stat_min; - int conf; - - inbuf.value = (void *) input; - inbuf.length = size; - - if (gss_unwrap (&stat_min, gd->gcontext, &inbuf, &outbuf, &conf, NULL) - != GSS_S_COMPLETE) - { - error (1, 0, "gss_unwrap failed"); - } - - if (outbuf.length > size) - abort (); - - memcpy (output, outbuf.value, outbuf.length); - - /* The real packet size is stored in the data, so we don't need to - remember outbuf.length. */ - - gss_release_buffer (&stat_min, &outbuf); - - return 0; -} - -/* Wrap data using GSSAPI. */ - -static int -cvs_gssapi_wrap_output (fnclosure, input, output, size, translated) - void *fnclosure; - const char *input; - char *output; - int size; - int *translated; -{ - struct cvs_gssapi_wrap_data *gd = - (struct cvs_gssapi_wrap_data *) fnclosure; - gss_buffer_desc inbuf, outbuf; - OM_uint32 stat_min; - int conf_req, conf; - - inbuf.value = (void *) input; - inbuf.length = size; - -#ifdef ENCRYPTION - conf_req = cvs_gssapi_encrypt; -#else - conf_req = 0; -#endif - - if (gss_wrap (&stat_min, gd->gcontext, conf_req, GSS_C_QOP_DEFAULT, - &inbuf, &conf, &outbuf) != GSS_S_COMPLETE) - error (1, 0, "gss_wrap failed"); - - /* The packetizing buffer only permits us to add 100 bytes. - FIXME: I don't know what, if anything, is guaranteed by GSSAPI. - This may need to be increased for a different GSSAPI - implementation, or we may need a different algorithm. */ - if (outbuf.length > size + 100) - abort (); - - memcpy (output, outbuf.value, outbuf.length); - - *translated = outbuf.length; - - gss_release_buffer (&stat_min, &outbuf); - - return 0; -} - -#endif /* HAVE_GSSAPI */ #ifdef ENCRYPTION _ --alexm