summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/client.c')
-rw-r--r--contrib/cvs/src/client.c755
1 files changed, 380 insertions, 375 deletions
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c
index 184cf96..4773b4f 100644
--- a/contrib/cvs/src/client.c
+++ b/contrib/cvs/src/client.c
@@ -13,7 +13,7 @@
GNU General Public License for more details. */
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <assert.h>
@@ -24,68 +24,67 @@
#ifdef CLIENT_SUPPORT
-#include "md5.h"
-
-#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# else /* No winsock.h */
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-# endif /* No winsock.h */
-#endif
+# include "md5.h"
+
+# if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# else /* No winsock.h */
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# endif /* No winsock.h */
+# endif
/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls
do not set errno, but that this macro should be used to obtain an
error code. This probably doesn't make sense unless
NO_SOCKET_TO_FD is also defined. */
-#ifndef SOCK_ERRNO
-#define SOCK_ERRNO errno
-#endif
+# ifndef SOCK_ERRNO
+# define SOCK_ERRNO errno
+# endif
/* If SOCK_STRERROR is defined, then the error codes returned by
socket operations are not known to strerror, and this macro must be
used instead to convert those error codes to strings. */
-#ifndef SOCK_STRERROR
-# define SOCK_STRERROR strerror
+# ifndef SOCK_STRERROR
+# define SOCK_STRERROR strerror
-# if STDC_HEADERS
-# include <string.h>
-# endif
+# if STDC_HEADERS
+# include <string.h>
+# endif
-# ifndef strerror
+# ifndef strerror
extern char *strerror ();
-# endif
-#endif /* ! SOCK_STRERROR */
+# endif
+# endif /* ! SOCK_STRERROR */
-#if HAVE_KERBEROS
-#define CVS_PORT 1999
+# if HAVE_KERBEROS
-#include <krb.h>
+# include <krb.h>
extern char *krb_realmofhost ();
-#ifndef HAVE_KRB_GET_ERR_TEXT
-#define krb_get_err_text(status) krb_err_txt[status]
-#endif /* HAVE_KRB_GET_ERR_TEXT */
+# ifndef HAVE_KRB_GET_ERR_TEXT
+# define krb_get_err_text(status) krb_err_txt[status]
+# endif /* HAVE_KRB_GET_ERR_TEXT */
/* Information we need if we are going to use Kerberos encryption. */
static C_Block kblock;
static Key_schedule sched;
-#endif /* HAVE_KERBEROS */
+# endif /* HAVE_KERBEROS */
-#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSAPI
-# include "xgssapi.h"
+# include "xgssapi.h"
/* This is needed for GSSAPI encryption. */
static gss_ctx_id_t gcontext;
-static int connect_to_gserver PROTO((int, struct hostent *));
+static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *));
-#endif /* HAVE_GSSAPI */
+# endif /* HAVE_GSSAPI */
static void add_prune_candidate PROTO((char *));
@@ -134,9 +133,9 @@ static void handle_f PROTO((char *, int));
static void handle_notified PROTO((char *, int));
static size_t try_read_from_server PROTO ((char *, size_t));
-#endif /* CLIENT_SUPPORT */
-
-#ifdef CLIENT_SUPPORT
+
+static void auth_server PROTO ((cvsroot_t *, struct buffer *, struct buffer *,
+ int, int, struct hostent *));
/* We need to keep track of the list of directories we've sent to the
server. This list, along with the current CVSROOT, will help us
@@ -267,8 +266,11 @@ arg_should_not_be_sent_to_server (arg)
}
+
#endif /* CLIENT_SUPPORT */
-
+
+
+
#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
/* Shared with server. */
@@ -438,16 +440,9 @@ static List *ignlist = (List *) NULL;
/* Buffer to write to the server. */
static struct buffer *to_server;
-/* The stream underlying to_server, if we are using a stream. */
-static FILE *to_server_fp;
/* Buffer used to read from the server. */
static struct buffer *from_server;
-/* The stream underlying from_server, if we are using a stream. */
-static FILE *from_server_fp;
-
-/* Process ID of rsh subprocess. */
-static int rsh_pid = -1;
/* We want to be able to log data sent between us and the server. We
@@ -470,7 +465,7 @@ static int log_buffer_input PROTO((void *, char *, int, int, int *));
static int log_buffer_output PROTO((void *, const char *, int, int *));
static int log_buffer_flush PROTO((void *));
static int log_buffer_block PROTO((void *, int));
-static int log_buffer_shutdown PROTO((void *));
+static int log_buffer_shutdown PROTO((struct buffer *));
/* Create a log buffer. */
@@ -594,10 +589,10 @@ log_buffer_block (closure, block)
/* The shutdown function for a log buffer. */
static int
-log_buffer_shutdown (closure)
- void *closure;
+log_buffer_shutdown (buf)
+ struct buffer *buf;
{
- struct log_buffer *lb = (struct log_buffer *) closure;
+ struct log_buffer *lb = (struct log_buffer *) buf->closure;
int retval;
retval = buf_shutdown (lb->buf);
@@ -605,7 +600,7 @@ log_buffer_shutdown (closure)
error (0, errno, "closing log file");
return retval;
}
-
+
#ifdef NO_SOCKET_TO_FD
/* Under certain circumstances, we must communicate with the server
@@ -618,9 +613,6 @@ log_buffer_shutdown (closure)
in these cases. This is handled through the SOCK_ERRNO and
SOCK_STRERROR macros. */
-static int use_socket_style = 0;
-static int server_sock;
-
/* These routines implement a buffer structure which uses send and
recv. The buffer is always in blocking mode so we don't implement
the block routine. */
@@ -644,14 +636,17 @@ static struct buffer *socket_buffer_initialize
static int socket_buffer_input PROTO((void *, char *, int, int, int *));
static int socket_buffer_output PROTO((void *, const char *, int, int *));
static int socket_buffer_flush PROTO((void *));
+static int socket_buffer_shutdown PROTO((struct buffer *));
+
+
/* Create a buffer based on a socket. */
static struct buffer *
socket_buffer_initialize (socket, input, memory)
- int socket;
- int input;
- void (*memory) PROTO((struct buffer *));
+ int socket;
+ int input;
+ void (*memory) PROTO((struct buffer *));
{
struct socket_buffer *n;
@@ -661,11 +656,13 @@ socket_buffer_initialize (socket, input, memory)
input ? NULL : socket_buffer_output,
input ? NULL : socket_buffer_flush,
(int (*) PROTO((void *, int))) NULL,
- (int (*) PROTO((void *))) NULL,
+ socket_buffer_shutdown,
memory,
n);
}
+
+
/* The buffer input function for a buffer built on a socket. */
static int
@@ -725,6 +722,8 @@ socket_buffer_input (closure, data, need, size, got)
return 0;
}
+
+
/* The buffer output function for a buffer built on a socket. */
static int
@@ -764,6 +763,8 @@ socket_buffer_output (closure, data, have, wrote)
return 0;
}
+
+
/* The buffer flush function for a buffer built on a socket. */
/*ARGSUSED*/
@@ -775,8 +776,61 @@ socket_buffer_flush (closure)
return 0;
}
+
+
+static int
+socket_buffer_shutdown (buf)
+ struct buffer *buf;
+{
+ struct socket_buffer *n = (struct socket_buffer *) buf->closure;
+ char tmp;
+
+ /* no need to flush children of an endpoint buffer here */
+
+ if (buf->input)
+ {
+ int err = 0;
+ if (! buf_empty_p (buf)
+ || (err = recv (n->socket, &tmp, 1, 0)) > 0)
+ error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
+ else if (err == -1)
+ error (0, 0, "reading from %s: %s", current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ if (current_parsed_root->method != server_method)
+# endif
+ if (shutdown (n->socket, 0) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->input = NULL;
+ }
+ else if (buf->output)
+ {
+ /* shutdown() socket */
+# ifdef SHUTDOWN_SERVER
+ /* FIXME: Should have a SHUTDOWN_SERVER_INPUT &
+ * SHUTDOWN_SERVER_OUTPUT
+ */
+ if (current_parsed_root->method == server_method)
+ SHUTDOWN_SERVER (n->socket);
+ else
+# endif
+ if (shutdown (n->socket, 1) < 0)
+ {
+ error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+ }
+
+ buf->output = NULL;
+ }
+
+ return 0;
+}
+
#endif /* NO_SOCKET_TO_FD */
-
+
/*
* Read a line from the server. Result does not include the terminating \n.
*
@@ -3519,7 +3573,6 @@ get_server_responses ()
}
/* Get the responses and then close the connection. */
-int server_fd = -1;
/*
* Flag var; we'll set it in start_server() and not one of its
@@ -3548,79 +3601,18 @@ get_responses_and_close ()
if (client_prune_dirs)
process_prune_candidates ();
- /* The calls to buf_shutdown are currently only meaningful when we
- are using compression. First we shut down TO_SERVER. That
- tells the server that its input is finished. It then shuts
- down the buffer it is sending to us, at which point our shut
- down of FROM_SERVER will complete. */
+ /* First we shut down TO_SERVER. That tells the server that its input is
+ * finished. It then shuts down the buffer it is sending to us, at which
+ * point our shut down of FROM_SERVER will complete.
+ */
status = buf_shutdown (to_server);
if (status != 0)
- error (0, status, "shutting down buffer to server");
+ error (0, status, "shutting down buffer to server");
status = buf_shutdown (from_server);
if (status != 0)
error (0, status, "shutting down buffer from server");
-#ifdef NO_SOCKET_TO_FD
- if (use_socket_style)
- {
- if (shutdown (server_sock, 2) < 0)
- error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO));
- }
- else
-#endif /* NO_SOCKET_TO_FD */
- {
-#if defined(HAVE_KERBEROS) || defined(AUTH_CLIENT_SUPPORT)
- if (server_fd != -1)
- {
- if (shutdown (server_fd, 1) < 0)
- error (1, 0, "shutting down connection to %s: %s",
- current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
- server_fd = -1;
- /*
- * This test will always be true because we dup the descriptor
- */
- if (fileno (from_server_fp) != fileno (to_server_fp))
- {
- if (fclose (to_server_fp) != 0)
- error (1, errno,
- "closing down connection to %s",
- current_parsed_root->hostname);
- }
- }
- else
-#endif
-
-#ifdef SHUTDOWN_SERVER
- SHUTDOWN_SERVER (fileno (to_server_fp));
-#else /* ! SHUTDOWN_SERVER */
- {
-
-#ifdef START_RSH_WITH_POPEN_RW
- if (pclose (to_server_fp) == EOF)
-#else /* ! START_RSH_WITH_POPEN_RW */
- if (fclose (to_server_fp) == EOF)
-#endif /* START_RSH_WITH_POPEN_RW */
- {
- error (1, errno, "closing connection to %s",
- current_parsed_root->hostname);
- }
- }
-
- if (! buf_empty_p (from_server)
- || getc (from_server_fp) != EOF)
- error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname);
- else if (ferror (from_server_fp))
- error (0, errno, "reading from %s", current_parsed_root->hostname);
-
- fclose (from_server_fp);
-#endif /* SHUTDOWN_SERVER */
- }
-
- if (rsh_pid != -1
- && waitpid (rsh_pid, (int *) 0, 0) == -1)
- error (1, errno, "waiting for process %d", rsh_pid);
-
buf_free (to_server);
buf_free (from_server);
server_started = 0;
@@ -3635,7 +3627,7 @@ get_responses_and_close ()
}
#ifndef NO_EXT_METHOD
-static void start_rsh_server PROTO((int *, int *));
+static void start_rsh_server PROTO((cvsroot_t *, struct buffer **, struct buffer **));
#endif
int
@@ -3758,68 +3750,82 @@ get_cvs_port_number (root)
method_names[root->method]);
break;
}
+ /* NOTREACHED */
+ return -1;
}
-/* Read a line from socket SOCK. Result does not include the
- terminating linefeed. This is only used by the authentication
- protocol, which we call before we set up all the buffering stuff.
- It is possible it should use the buffers too, which would be faster
- (unlike the server, there isn't really a security issue in terms of
- separating authentication from the rest of the code).
-
- Space for the result is malloc'd and should be freed by the caller.
-
- Returns number of bytes read. */
-static int
-recv_line (sock, resultp)
- int sock;
- char **resultp;
+void
+make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock)
+ int tofd;
+ int fromfd;
+ int child_pid;
+ struct buffer **to_server;
+ struct buffer **from_server;
+ int is_sock;
{
- char *result;
- size_t input_index = 0;
- size_t result_size = 80;
-
- result = (char *) xmalloc (result_size);
+ FILE *to_server_fp;
+ FILE *from_server_fp;
- while (1)
+#ifdef NO_SOCKET_TO_FD
+ if (is_sock)
{
- char ch;
- int n;
- n = recv (sock, &ch, 1, 0);
- if (n <= 0)
- error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname,
- n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO));
-
- if (ch == '\012')
- break;
+ assert (tofd == fromfd);
+ *to_server = socket_buffer_initialize (tofd, 0,
+ (BUFMEMERRPROC) NULL);
+ *from_server = socket_buffer_initialize (tofd, 1,
+ (BUFMEMERRPROC) NULL);
+ }
+ else
+#endif /* NO_SOCKET_TO_FD */
+ {
+ /* todo: some OS's don't need these calls... */
+ close_on_exec (tofd);
+ close_on_exec (fromfd);
- result[input_index++] = ch;
- while (input_index + 1 >= result_size)
+ /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
+ fdopening the same file descriptor twice, so dup it if it is the
+ same. */
+ if (tofd == fromfd)
{
- result_size *= 2;
- result = (char *) xrealloc (result, result_size);
+ fromfd = dup (tofd);
+ if (fromfd < 0)
+ error (1, errno, "cannot dup net connection");
}
- }
- if (resultp)
- *resultp = result;
-
- /* Terminate it just for kicks, but we *can* deal with embedded NULs. */
- result[input_index] = '\0';
+ /* These will use binary mode on systems which have it. */
+ /*
+ * Also, we know that from_server is shut down second, so we pass
+ * child_pid in there. In theory, it should be stored in both
+ * buffers with a ref count...
+ */
+ to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE);
+ if (to_server_fp == NULL)
+ error (1, errno, "cannot fdopen %d for write", tofd);
+ *to_server = stdio_buffer_initialize (to_server_fp, 0, 0,
+ (BUFMEMERRPROC) NULL);
- if (resultp == NULL)
- free (result);
- return input_index;
+ from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ);
+ if (from_server_fp == NULL)
+ error (1, errno, "cannot fdopen %d for read", fromfd);
+ *from_server = stdio_buffer_initialize (from_server_fp, child_pid, 1,
+ (BUFMEMERRPROC) NULL);
+ }
}
+
+
/* Connect to a forked server process. */
void
-connect_to_forked_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+connect_to_forked_server (to_server, from_server)
+ struct buffer **to_server;
+ struct buffer **from_server;
{
+ int tofd, fromfd;
+ int child_pid;
+
/* This is pretty simple. All we need to do is choose the correct
cvs binary and call piped_child. */
@@ -3836,8 +3842,12 @@ connect_to_forked_server (tofdp, fromfdp)
{
fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]);
}
- if (! piped_child (command, tofdp, fromfdp))
+
+ child_pid = piped_child (command, &tofd, &fromfd);
+ if (child_pid < 0)
error (1, 0, "could not fork server process");
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
}
/* Connect to the authenticating server.
@@ -3853,51 +3863,113 @@ connect_to_forked_server (tofdp, fromfdp)
If we fail to connect or if access is denied, then die with fatal
error. */
void
-connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
- int *tofdp, *fromfdp;
- int verify_only;
- int do_gssapi;
+connect_to_pserver (root, to_server_p, from_server_p, verify_only, do_gssapi)
+ cvsroot_t *root;
+ struct buffer **to_server_p;
+ struct buffer **from_server_p;
+ int verify_only;
+ int do_gssapi;
{
int sock;
-#ifndef NO_SOCKET_TO_FD
- int tofd, fromfd;
-#endif
int port_number;
- char *username; /* the username we use to connect */
struct sockaddr_in client_sai;
struct hostent *hostinfo;
- char no_passwd = 0; /* gets set if no password found */
+ struct buffer *to_server, *from_server;
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
}
- port_number = get_cvs_port_number (current_parsed_root);
- hostinfo = init_sockaddr (&client_sai, current_parsed_root->hostname, port_number);
+ port_number = get_cvs_port_number (root);
+ hostinfo = init_sockaddr (&client_sai, root->hostname, port_number);
if (trace)
{
fprintf (stderr, " -> Connecting to %s(%s):%d\n",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (client_sai.sin_addr), port_number);
}
if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai))
< 0)
error (1, 0, "connect to %s(%s):%d failed: %s",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (client_sai.sin_addr),
port_number, SOCK_STRERROR (SOCK_ERRNO));
+ make_bufs_from_fds (sock, sock, 0, &to_server, &from_server, 1);
+
+ auth_server (root, to_server, from_server, verify_only, do_gssapi, hostinfo);
+
+ if (verify_only)
+ {
+ int status;
+
+ status = buf_shutdown (to_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer to server");
+ status = buf_shutdown (from_server);
+ if (status != 0)
+ error (0, status, "shutting down buffer from server");
+
+ buf_free (to_server);
+ buf_free (from_server);
+
+ /* Don't need to set server_started = 0 since we don't set it to 1
+ * until returning from this call.
+ */
+ }
+ else
+ {
+ *to_server_p = to_server;
+ *from_server_p = from_server;
+ }
+
+ return;
+}
+
+
+
+static void
+auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
+ cvsroot_t *root;
+ struct buffer *lto_server;
+ struct buffer *lfrom_server;
+ int verify_only;
+ int do_gssapi;
+ struct hostent *hostinfo;
+{
+ char *username; /* the username we use to connect */
+ char no_passwd = 0; /* gets set if no password found */
+
+ /* FIXME!!!!!!!!!!!!!!!!!!
+ *
+ * THIS IS REALLY UGLY!
+ *
+ * I'm setting the globals here so we can make calls to send_to_server &
+ * read_line. This happens again _after_ we return if we're not in
+ * verify_only mode. We should be relying on the values we passed in, but
+ * sent_to_server and read_line don't require an outside buf yet.
+ */
+ to_server = lto_server;
+ from_server = lfrom_server;
+
/* Run the authorization mini-protocol before anything else. */
if (do_gssapi)
{
#ifdef HAVE_GSSAPI
- if (! connect_to_gserver (sock, hostinfo))
+ int fd = (int) lto_server->closure;
+ struct stat s;
+
+ if (fstat (fd, &s) < 0 || !S_ISSOCK(s.st_mode))
{
- error (0, 0,
+ error (1, 0, "gserver currently only enabled for socket connections");
+ }
+
+ if (! connect_to_gserver (root, fd, hostinfo))
+ {
+ error (1, 0,
"authorization failed: server %s rejected access to %s",
- current_parsed_root->hostname, current_parsed_root->directory);
- goto rejected;
+ root->hostname, root->directory);
}
#else
error (1, 0, "This client does not support GSSAPI authentication");
@@ -3911,48 +3983,42 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
if (verify_only)
{
- begin = "BEGIN VERIFICATION REQUEST\012";
- end = "END VERIFICATION REQUEST\012";
+ begin = "BEGIN VERIFICATION REQUEST";
+ end = "END VERIFICATION REQUEST";
}
else
{
- begin = "BEGIN AUTH REQUEST\012";
- end = "END AUTH REQUEST\012";
+ begin = "BEGIN AUTH REQUEST";
+ end = "END AUTH REQUEST";
}
/* Get the password, probably from ~/.cvspass. */
password = get_cvs_password ();
- username = current_parsed_root->username ? current_parsed_root->username : getcaller();
+ username = root->username ? root->username : getcaller();
- /* Send the empty string by default. This is so anonymous CVS
- access doesn't require client to have done "cvs login". */
- if (password == NULL)
- {
- no_passwd = 1;
- password = scramble ("");
- }
+ /* Send the empty string by default. This is so anonymous CVS
+ access doesn't require client to have done "cvs login". */
+ if (password == NULL)
+ {
+ no_passwd = 1;
+ password = scramble ("");
+ }
/* Announce that we're starting the authorization protocol. */
- if (send (sock, begin, strlen (begin), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ send_to_server(begin, 0);
+ send_to_server("\012", 1);
/* Send the data the server needs. */
- if (send (sock, current_parsed_root->directory, strlen (current_parsed_root->directory), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- if (send (sock, "\012", 1, 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- if (send (sock, username, strlen (username), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- if (send (sock, "\012", 1, 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- if (send (sock, password, strlen (password), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
- if (send (sock, "\012", 1, 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ send_to_server(root->directory, 0);
+ send_to_server("\012", 1);
+ send_to_server(username, 0);
+ send_to_server("\012", 1);
+ send_to_server(password, 0);
+ send_to_server("\012", 1);
/* Announce that we're ending the authorization protocol. */
- if (send (sock, end, strlen (end), 0) < 0)
- error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
+ send_to_server(end, 0);
+ send_to_server("\012", 1);
/* Paranoia. */
memset (password, 0, strlen (password));
@@ -3964,7 +4030,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
/* Loop, getting responses from the server. */
while (1)
{
- recv_line (sock, &read_buf);
+ read_line (&read_buf);
if (strcmp (read_buf, "I HATE YOU") == 0)
{
@@ -3976,12 +4042,12 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
* can return 1 and we will not receive "I LOVE YOU" from the server, barring
* broken connections and garbled messages, of course).
*
- * i.e. This is a pserver specific error message and shoiuld be since
+ * i.e. This is a pserver specific error message and should be since
* GSSAPI doesn't use username.
*/
error (0, 0,
"authorization failed: server %s rejected access to %s for user %s",
- current_parsed_root->hostname, current_parsed_root->directory, username);
+ root->hostname, root->directory, username);
/* Output a special error message if authentication was attempted
with no password -- the user should be made aware that they may
@@ -3991,7 +4057,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
error (0, 0,
"used empty password; try \"cvs login\" with a real password");
}
- goto rejected;
+ error_exit();
}
else if (strncmp (read_buf, "E ", 2) == 0)
{
@@ -4014,7 +4080,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
/* Now output the text. */
fprintf (stderr, "%s\n", p);
- goto rejected;
+ error_exit();
}
else if (strcmp (read_buf, "I LOVE YOU") == 0)
{
@@ -4023,62 +4089,13 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
}
else
{
- /* Unrecognized response from server. */
- if (shutdown (sock, 2) < 0)
- {
- error (0, 0,
- "unrecognized auth response from %s: %s",
- current_parsed_root->hostname, read_buf);
- error (1, 0,
- "shutdown() failed, server %s: %s",
- current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- }
error (1, 0,
"unrecognized auth response from %s: %s",
- current_parsed_root->hostname, read_buf);
+ root->hostname, read_buf);
}
free (read_buf);
}
}
-
- if (verify_only)
- {
- if (shutdown (sock, 2) < 0)
- error (0, 0, "shutdown() failed, server %s: %s", current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- return;
- }
- else
- {
-#ifdef NO_SOCKET_TO_FD
- use_socket_style = 1;
- server_sock = sock;
- /* Try to break mistaken callers: */
- *tofdp = 0;
- *fromfdp = 0;
-#else /* ! NO_SOCKET_TO_FD */
- server_fd = sock;
- close_on_exec (server_fd);
- tofd = fromfd = sock;
- /* Hand them back to the caller. */
- *tofdp = tofd;
- *fromfdp = fromfd;
-#endif /* NO_SOCKET_TO_FD */
- }
-
- return;
-
- rejected:
- if (shutdown (sock, 2) < 0)
- {
- error (0, 0,
- "shutdown() failed (server %s): %s",
- current_parsed_root->hostname,
- SOCK_STRERROR (SOCK_ERRNO));
- }
-
- error_exit();
}
#endif /* AUTH_CLIENT_SUPPORT */
@@ -4090,10 +4107,12 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi)
(i.e., systems on which sockets cannot be converted to file
descriptors). The first person to try building a kerberos client
on such a system (OS/2, Windows 95, and maybe others) will have to
- make take care of this. */
+ take care of this. */
void
-start_tcp_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+start_tcp_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
int s;
const char *portenv;
@@ -4106,9 +4125,9 @@ start_tcp_server (tofdp, fromfdp)
if (s < 0)
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
- port = get_cvs_port_number (current_parsed_root);
+ port = get_cvs_port_number (root);
- hp = init_sockaddr (&sin, current_parsed_root->hostname, port);
+ hp = init_sockaddr (&sin, root->hostname, port);
hname = xmalloc (strlen (hp->h_name) + 1);
strcpy (hname, hp->h_name);
@@ -4116,13 +4135,13 @@ start_tcp_server (tofdp, fromfdp)
if (trace)
{
fprintf (stderr, " -> Connecting to %s(%s):%d\n",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (sin.sin_addr), port);
}
if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
error (1, 0, "connect to %s(%s):%d failed: %s",
- current_parsed_root->hostname,
+ root->hostname,
inet_ntoa (sin.sin_addr),
port, SOCK_STRERROR (SOCK_ERRNO));
@@ -4151,14 +4170,12 @@ start_tcp_server (tofdp, fromfdp)
memcpy (kblock, cred.session, sizeof (C_Block));
}
- server_fd = s;
- close_on_exec (server_fd);
+ close_on_exec (s);
free (hname);
/* Give caller the values it wants. */
- *tofdp = s;
- *fromfdp = s;
+ make_bufs_from_fds (s, s, 0, to_server, from_server, 1);
}
#endif /* HAVE_KERBEROS */
@@ -4189,13 +4206,29 @@ recv_bytes (sock, buf, need)
/* 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 (sock, hostinfo)
- int sock;
- struct hostent *hostinfo;
+connect_to_gserver (root, sock, hostinfo)
+ cvsroot_t *root;
+ int sock;
+ struct hostent *hostinfo;
{
char *str;
- char buf[1024];
+ char buf[BUFSIZE];
gss_buffer_desc *tok_in_ptr, tok_in, tok_out;
OM_uint32 stat_min, stat_maj;
gss_name_t server_name;
@@ -4205,6 +4238,8 @@ connect_to_gserver (sock, hostinfo)
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;
@@ -4274,11 +4309,11 @@ connect_to_gserver (sock, hostinfo)
got = recv (sock, buf + 2, sizeof buf - 2, 0);
if (got < 0)
error (1, 0, "recv() from server %s: %s",
- current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO));
+ 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", current_parsed_root->hostname,
+ error (1, 0, "error from server %s: %s", root->hostname,
buf);
}
@@ -4315,10 +4350,9 @@ send_variable_proc (node, closure)
void
start_server ()
{
- int tofd, fromfd, rootless;
+ int rootless;
char *log = getenv ("CVS_CLIENT_LOG");
-
/* Clear our static variables for this invocation. */
if (toplevel_repos != NULL)
free (toplevel_repos);
@@ -4335,22 +4369,23 @@ start_server ()
#ifdef AUTH_CLIENT_SUPPORT
case pserver_method:
- /* Toss the return value. It will die with error if anything
- goes wrong anyway. */
- connect_to_pserver (&tofd, &fromfd, 0, 0);
+ /* Toss the return value. It will die with an error message if
+ * anything goes wrong anyway.
+ */
+ connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 0);
break;
#endif
#if HAVE_KERBEROS
case kserver_method:
- start_tcp_server (&tofd, &fromfd);
+ start_tcp_server (current_parsed_root, &to_server, &from_server);
break;
#endif
#ifdef HAVE_GSSAPI
case gserver_method:
/* GSSAPI authentication is handled by the pserver. */
- connect_to_pserver (&tofd, &fromfd, 0, 1);
+ connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 1);
break;
#endif
@@ -4359,34 +4394,34 @@ start_server ()
error (0, 0, ":ext: method not supported by this port of CVS");
error (1, 0, "try :server: instead");
#else
- start_rsh_server (&tofd, &fromfd);
+ start_rsh_server (current_parsed_root, &to_server, &from_server);
#endif
break;
case server_method:
#if defined(START_SERVER)
+ {
+ int tofd, fromfd;
START_SERVER (&tofd, &fromfd, getcaller (),
current_parsed_root->username, current_parsed_root->hostname,
current_parsed_root->directory);
-# if defined (START_SERVER_RETURNS_SOCKET) && defined (NO_SOCKET_TO_FD)
- /* This is a system on which we can only write to a socket
- using send/recv. Therefore its START_SERVER needs to
- return a socket. */
- use_socket_style = 1;
- server_sock = tofd;
-# endif
-
+# ifdef START_SERVER_RETURNS_SOCKET
+ make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 1);
+# else
+ make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 0);
+# endif /* START_SERVER_RETURNS_SOCKET */
+ }
#else
/* FIXME: It should be possible to implement this portably,
like pserver, which would get rid of the duplicated code
in {vms,windows-NT,...}/startserver.c. */
- error (1, 0, "\
-the :server: access method is not supported by this port of CVS");
+ error (1, 0,
+"the :server: access method is not supported by this port of CVS");
#endif
break;
case fork_method:
- connect_to_forked_server (&tofd, &fromfd);
+ connect_to_forked_server (&to_server, &from_server);
break;
default:
@@ -4398,46 +4433,11 @@ the :server: access method is not supported by this port of CVS");
/* "Hi, I'm Darlene and I'll be your server tonight..." */
server_started = 1;
-#ifdef NO_SOCKET_TO_FD
- if (use_socket_style)
- {
- to_server = socket_buffer_initialize (server_sock, 0,
- (BUFMEMERRPROC) NULL);
- from_server = socket_buffer_initialize (server_sock, 1,
- (BUFMEMERRPROC) NULL);
- }
- else
-#endif /* NO_SOCKET_TO_FD */
- {
- /* todo: some OS's don't need these calls... */
- close_on_exec (tofd);
- close_on_exec (fromfd);
-
- /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
- fdopening the same file descriptor twice, so dup it if it is the
- same. */
- if (tofd == fromfd)
- {
- fromfd = dup (tofd);
- if (fromfd < 0)
- error (1, errno, "cannot dup net connection");
- }
-
- /* These will use binary mode on systems which have it. */
- to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE);
- if (to_server_fp == NULL)
- error (1, errno, "cannot fdopen %d for write", tofd);
- to_server = stdio_buffer_initialize (to_server_fp, 0,
- (BUFMEMERRPROC) NULL);
-
- from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ);
- if (from_server_fp == NULL)
- error (1, errno, "cannot fdopen %d for read", fromfd);
- from_server = stdio_buffer_initialize (from_server_fp, 1,
- (BUFMEMERRPROC) NULL);
- }
-
- /* Set up logfiles, if any. */
+ /* Set up logfiles, if any.
+ *
+ * We do this _after_ authentication on purpose. Wouldn't really like to
+ * worry about logging passwords...
+ */
if (log)
{
int len = strlen (log);
@@ -4763,7 +4763,7 @@ the :server: access method is not supported by this port of CVS");
implementing piped_child)... but I'm doing something else at the
moment, and wish to make only one change at a time. -Karl */
-#ifdef START_RSH_WITH_POPEN_RW
+# ifdef START_RSH_WITH_POPEN_RW
/* This is actually a crock -- it's OS/2-specific, for no one else
uses it. If I get time, I want to make piped_child and all the
@@ -4771,10 +4771,13 @@ the :server: access method is not supported by this port of CVS");
up and running, and that's most important. */
static void
-start_rsh_server (tofdp, fromfdp)
- int *tofdp, *fromfdp;
+start_rsh_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
int pipes[2];
+ int child_pid;
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
@@ -4814,19 +4817,19 @@ start_rsh_server (tofdp, fromfdp)
/* The command line starts out with rsh. */
rsh_argv[i++] = cvs_rsh;
-#ifdef RSH_NEEDS_BINARY_FLAG
+# ifdef RSH_NEEDS_BINARY_FLAG
/* "-b" for binary, under OS/2. */
rsh_argv[i++] = "-b";
-#endif /* RSH_NEEDS_BINARY_FLAG */
+# endif /* RSH_NEEDS_BINARY_FLAG */
/* Then we strcat more things on the end one by one. */
- if (current_parsed_root->username != NULL)
+ if (root->username != NULL)
{
rsh_argv[i++] = "-l";
- rsh_argv[i++] = current_parsed_root->username;
+ rsh_argv[i++] = root->username;
}
- rsh_argv[i++] = current_parsed_root->hostname;
+ rsh_argv[i++] = root->hostname;
rsh_argv[i++] = cvs_server;
rsh_argv[i++] = "server";
@@ -4842,21 +4845,21 @@ start_rsh_server (tofdp, fromfdp)
}
/* Do the deed. */
- rsh_pid = popenRW (rsh_argv, pipes);
- if (rsh_pid < 0)
+ child_pid = popenRW (rsh_argv, pipes);
+ if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
- /* Give caller the file descriptors. */
- *tofdp = pipes[0];
- *fromfdp = pipes[1];
+ /* Give caller the file descriptors in a form it can deal with. */
+ make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server, from_server, 0);
}
-#else /* ! START_RSH_WITH_POPEN_RW */
+# else /* ! START_RSH_WITH_POPEN_RW */
static void
-start_rsh_server (tofdp, fromfdp)
- int *tofdp;
- int *fromfdp;
+start_rsh_server (root, to_server, from_server)
+ cvsroot_t *root;
+ struct buffer **to_server;
+ struct buffer **from_server;
{
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
@@ -4864,6 +4867,8 @@ start_rsh_server (tofdp, fromfdp)
char *cvs_rsh = getenv ("CVS_RSH");
char *cvs_server = getenv ("CVS_SERVER");
char *command;
+ int tofd, fromfd;
+ int child_pid;
if (!cvs_rsh)
cvs_rsh = "rsh";
@@ -4874,9 +4879,7 @@ start_rsh_server (tofdp, fromfdp)
affect most rsh servers at all, and will pacify some buggy
versions of rsh that grab switches out of the middle of the
command (they're calling the GNU getopt routines incorrectly). */
- command = xmalloc (strlen (cvs_server)
- + strlen (current_parsed_root->directory)
- + 50);
+ command = xmalloc (strlen (cvs_server) + 8);
/* If you are running a very old (Nov 3, 1994, before 1.5)
* version of the server, you need to make sure that your .bashrc
@@ -4889,15 +4892,15 @@ start_rsh_server (tofdp, fromfdp)
char **p = argv;
*p++ = cvs_rsh;
- *p++ = current_parsed_root->hostname;
+ *p++ = root->hostname;
/* If the login names differ between client and server
* pass it on to rsh.
*/
- if (current_parsed_root->username != NULL)
+ if (root->username != NULL)
{
*p++ = "-l";
- *p++ = current_parsed_root->username;
+ *p++ = root->username;
}
*p++ = command;
@@ -4912,19 +4915,21 @@ start_rsh_server (tofdp, fromfdp)
fprintf (stderr, "%s ", argv[i]);
putc ('\n', stderr);
}
- rsh_pid = piped_child (argv, tofdp, fromfdp);
+ child_pid = piped_child (argv, &tofd, &fromfd);
- if (rsh_pid < 0)
+ if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
}
free (command);
+
+ make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0);
}
-#endif /* START_RSH_WITH_POPEN_RW */
+# endif /* START_RSH_WITH_POPEN_RW */
#endif /* NO_EXT_METHOD */
-
+
/* Send an argument STRING. */
void
OpenPOWER on IntegriCloud