Index: src/gssapi-client.c =================================================================== RCS file: /cvsroot/cvs/ccvs/src/gssapi-client.c,v retrieving revision 1.9 diff -u -u -r1.9 gssapi-client.c --- src/gssapi-client.c 4 Nov 2004 21:22:27 -0000 1.9 +++ src/gssapi-client.c 20 Sep 2005 18:40:49 -0000 @@ -75,22 +75,28 @@ * 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 (cvsroot_t *root, int sock, struct hostent *hostinfo) { char *str; - char buf[BUFSIZE]; + char buf[1024]; gss_buffer_desc *tok_in_ptr, tok_in, tok_out; + gss_buffer_desc gss_status, mech_status; OM_uint32 stat_min, stat_maj; + OM_uint32 new_stat_min; gss_name_t server_name; + OM_uint32 message_context; + gss_OID actual_mech; + OM_uint32 actual_services; + char cbuf[2]; + int need; 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) + if (strlen (hostinfo->h_name) > sizeof(buf) - 5) error (1, 0, "Internal error: hostname exceeds length of buffer"); sprintf (buf, "cvs@%s", hostinfo->h_name); tok_in.length = strlen (buf); @@ -103,50 +109,77 @@ do { + /* + * Our GSS-API server compatible only with Kerberos. + * + * We made only two call gss_init_sec_context() per + * connection and one call gss_display_status() per + * messages. + * + * TODO: Strict conformity to GSS-API, see example + * . Need SPKI or + * other non Kerberos GSS-API implementation. + */ 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; + | (cvsauthenticate + ? GSS_C_INTEG_FLAG|GSS_C_REPLAY_FLAG + : 0) +# ifdef ENCRYPTION + | (cvsencrypt + ? GSS_C_CONF_FLAG + : 0) +# endif /* ENCRYPTION */ + ), + 0, GSS_C_NO_CHANNEL_BINDINGS, + tok_in_ptr, &actual_mech, &tok_out, + &actual_services, NULL); + message_context = 0; + gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, + actual_mech, &message_context, &gss_status); + message_context = 0; + gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, + actual_mech, &message_context, &mech_status); + + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d:%s", + __LINE__, (const char *) gss_status.value); + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d:%s", + __LINE__, (const char *) mech_status.value); - message_context = 0; - gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, - GSS_C_NULL_OID, &message_context, &tok_out); + if (GSS_ERROR(stat_maj)) + { error (0, 0, "GSSAPI authentication failed: %s", - (const 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); + (const char *) gss_status.value); error (1, 0, "GSSAPI authentication failed: %s", - (const char *) tok_out.value); + (const char *) mech_status.value); } - if (tok_out.length == 0) - { - tok_in.length = 0; - } - else - { - char cbuf[2]; - int need; + gss_release_buffer(&new_stat_min, &gss_status); + gss_release_buffer(&new_stat_min, &mech_status); + if (tok_out.length) + { 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)); + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d: send %d", + __LINE__, tok_out.length); + gss_release_buffer(&stat_min, &tok_out); + } + if (stat_maj & GSS_S_CONTINUE_NEEDED) + { recv_bytes (sock, cbuf, 2); need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d: recive %d", + __LINE__, need); + if (need > sizeof buf) { ssize_t got; @@ -178,13 +211,42 @@ 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); - tok_in.value = buf; - tok_in_ptr = &tok_in; + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d:%s%s%s%s", + __LINE__, + (actual_services&GSS_C_MUTUAL_FLAG) ? " GSS_C_MUTUAL_FLAG" : "", + (actual_services&GSS_C_REPLAY_FLAG) ? " GSS_C_REPLAY_FLAG" : "", + (actual_services&GSS_C_INTEG_FLAG) ? " GSS_C_INTEG_FLAG" : "", + (actual_services&GSS_C_CONF_FLAG) ? " GSS_C_CONF_FLAG" : "" + ); + +# ifdef ENCRYPTION + if (cvsencrypt && GSS_C_CONF_FLAG != (actual_services&GSS_C_CONF_FLAG)) + { + error(1, 0, "GSSAPI: traffic encryption don't agreement"); + return 0; } - while (stat_maj == GSS_S_CONTINUE_NEEDED); +# endif /* ENCRYPTION */ + if (cvsauthenticate && + (GSS_C_REPLAY_FLAG|GSS_C_INTEG_FLAG) != + (actual_services&(GSS_C_REPLAY_FLAG|GSS_C_INTEG_FLAG))) + { + error(1, 0, "GSSAPI: traffic authentication don't agreement"); + return 0; + } + if (GSS_C_MUTUAL_FLAG != (actual_services&GSS_C_MUTUAL_FLAG)) + { + error(1, 0, "GSSAPI: mutal authentication don't agreement"); + return 0; + } + TRACE (TRACE_FUNCTION, "connect_to_gserver:%d:gcontext=0x%x", + __LINE__, gcontext); return 1; } #endif /* CLIENT_SUPPORT */ Index: src/server.c =================================================================== RCS file: /cvsroot/cvs/ccvs/src/server.c,v retrieving revision 1.446 diff -u -u -r1.446 server.c --- src/server.c 8 Sep 2005 18:40:20 -0000 1.446 +++ src/server.c 20 Sep 2005 18:41:05 -0000 @@ -7362,13 +7362,17 @@ { char *hn; gss_buffer_desc tok_in, tok_out; + gss_buffer_desc gss_status, mech_status; char buf[1024]; char *credbuf; size_t credbuflen; - OM_uint32 stat_min, ret; + OM_uint32 stat_maj, stat_min, ret; + OM_uint32 new_stat_min; + OM_uint32 message_context; gss_name_t server_name, client_name; gss_cred_id_t server_creds; int nbytes; + int i; gss_OID mechid; hn = canon_host (server_hostname); @@ -7396,10 +7400,12 @@ /* The client will send us a two byte length followed by that many bytes. */ - if (fread (buf, 1, 2, stdin) != 2) + if (buf_read_data(buf_from_net, 1, &credbuf, &credbuflen) < 0) error (1, errno, "read of length failed"); - - nbytes = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); + nbytes = (*credbuf & 0xff) << 8; + if (buf_read_data(buf_from_net, 1, &credbuf, &credbuflen) < 0) + error (1, errno, "read of length failed"); + nbytes |= *credbuf & 0xff; if (nbytes <= sizeof buf) { credbuf = buf; @@ -7411,14 +7417,33 @@ credbuf = xmalloc (credbuflen); } - if (fread (credbuf, 1, nbytes, stdin) != nbytes) - error (1, errno, "read of data failed"); + for (i = 0; i < nbytes;) + { + char *b; + size_t l; + + if (buf_read_data(buf_from_net, nbytes - i, &b, &l) < 0) + error (1, errno, "read of data failed"); + memcpy(credbuf + i, b, l); + i += l; + } gcontext = GSS_C_NO_CONTEXT; tok_in.length = nbytes; tok_in.value = credbuf; - if (gss_accept_sec_context (&stat_min, + /* + * Our GSS-API server compatible only with Kerberos. + * + * We made only one call gss_init_sec_context() per + * connection and one call gss_display_status() per + * messages. + * + * TODO: Strict conformity to GSS-API, see example + * . Need SPKI or + * other non Kerberos GSS-API implementation. + */ + stat_maj = gss_accept_sec_context (&stat_min, &gcontext, /* context_handle */ server_creds, /* verifier_cred_handle */ &tok_in, /* input_token */ @@ -7428,12 +7453,33 @@ &tok_out, /* output_token */ &ret, NULL, /* ignore time_rec */ - NULL) /* ignore del_cred_handle */ - != GSS_S_COMPLETE) + NULL); /* ignore del_cred_handle */ + message_context = 0; + gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, + mechid, &message_context, &gss_status); + message_context = 0; + gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, + mechid, &message_context, &mech_status); + +# if HAVE_SYSLOG_H + syslog (LOG_DAEMON | (stat_maj != GSS_S_COMPLETE ? LOG_ERR : LOG_DEBUG), + "GSSAPI authentication failed: %s", + (const char *) gss_status.value); + syslog (LOG_DAEMON | (stat_maj != GSS_S_COMPLETE ? LOG_ERR : LOG_DEBUG), + "GSSAPI authentication failed: %s", + (const char *) mech_status.value); +# endif /* HAVE_SYSLOG_H */ + if (stat_maj != GSS_S_COMPLETE) { - error (1, 0, "could not verify credentials"); + error (0, 0, "GSSAPI authentication failed: %s", + (const char *) gss_status.value); + error (1, 0, "GSSAPI authentication failed: %s", + (const char *) mech_status.value); } + gss_release_buffer(&new_stat_min, &gss_status); + gss_release_buffer(&new_stat_min, &mech_status); + /* FIXME: Use Kerberos v5 specific code to authenticate to a user. We could instead use an authentication to access mapping. */ { @@ -7460,10 +7506,10 @@ cbuf[0] = (tok_out.length >> 8) & 0xff; cbuf[1] = tok_out.length & 0xff; - if (fwrite (cbuf, 1, 2, stdout) != 2 - || (fwrite (tok_out.value, 1, tok_out.length, stdout) - != tok_out.length)) - error (1, errno, "fwrite failed"); + buf_output(buf_to_net, cbuf, 2); + buf_output(buf_to_net, tok_out.value, tok_out.length); + if (buf_flush (buf_to_net, false)) + error (1, errno, "buf_flush failed"); } switch_to_user ("GSSAPI", buf); @@ -7471,7 +7517,8 @@ if (credbuf != buf) free (credbuf); - printf ("I LOVE YOU\n"); + buf_output0 (buf_to_net, "I LOVE YOU\n"); + buf_flush (buf_to_net, true); fflush (stdout); }