summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/server.c')
-rw-r--r--contrib/cvs/src/server.c527
1 files changed, 347 insertions, 180 deletions
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index 669cad7..e1af5e4 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -183,6 +183,7 @@ static int fd_buffer_input PROTO((void *, char *, int, int, int *));
static int fd_buffer_output PROTO((void *, const char *, int, int *));
static int fd_buffer_flush PROTO((void *));
static int fd_buffer_block PROTO((void *, int));
+static int fd_buffer_shutdown PROTO((void *));
/* Initialize a buffer built on a file descriptor. FD is the file
descriptor. INPUT is nonzero if this is for input, zero if this is
@@ -204,7 +205,7 @@ fd_buffer_initialize (fd, input, memory)
input ? NULL : fd_buffer_output,
input ? NULL : fd_buffer_flush,
fd_buffer_block,
- (int (*) PROTO((void *))) NULL,
+ fd_buffer_shutdown,
memory,
n);
}
@@ -341,6 +342,16 @@ fd_buffer_block (closure, block)
return 0;
}
+/* The buffer shutdown function for a buffer built on a file descriptor. */
+
+static int
+fd_buffer_shutdown (closure)
+ void *closure;
+{
+ free (closure);
+ return 0;
+}
+
/* Populate all of the directories between BASE_DIR and its relative
subdirectory DIR with CVSADM directories. Return 0 for success or
errno value. */
@@ -738,8 +749,6 @@ serve_root (arg)
{
char *env;
char *path;
- int save_errno;
- char *arg_dup;
if (error_pending()) return;
@@ -781,14 +790,7 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
}
}
#endif
- arg_dup = malloc (strlen (arg) + 1);
- if (arg_dup == NULL)
- {
- pending_error = ENOMEM;
- return;
- }
- strcpy (arg_dup, arg);
- set_local_cvsroot (arg_dup);
+ set_local_cvsroot (arg);
/* For pserver, this will already have happened, and the call will do
nothing. But for rsh, we need to do it now. */
@@ -796,7 +798,6 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
path = malloc (strlen (CVSroot_directory)
+ sizeof (CVSROOTADM)
- + sizeof (CVSROOTADM_HISTORY)
+ 10);
if (path == NULL)
{
@@ -806,23 +807,11 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
(void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM);
if (!isaccessible (path, R_OK | X_OK))
{
- save_errno = errno;
- pending_error_text = malloc (80 + strlen (path));
- if (pending_error_text != NULL)
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (path)))
sprintf (pending_error_text, "E Cannot access %s", path);
pending_error = save_errno;
}
- (void) strcat (path, "/");
- (void) strcat (path, CVSROOTADM_HISTORY);
- if (isfile (path) && !isaccessible (path, R_OK | W_OK))
- {
- save_errno = errno;
- pending_error_text = malloc (80 + strlen (path));
- if (pending_error_text != NULL)
- sprintf (pending_error_text, "E \
-Sorry, you don't have read/write access to the history file %s", path);
- pending_error = save_errno;
- }
free (path);
#ifdef HAVE_PUTENV
@@ -1036,9 +1025,9 @@ dirswitch (dir, repos)
if (status != 0
&& status != EEXIST)
{
- pending_error = status;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot mkdir %s", dir_name);
+ pending_error = status;
return;
}
@@ -1051,17 +1040,18 @@ dirswitch (dir, repos)
status = create_adm_p (server_temp_dir, dir);
if (status != 0)
{
- pending_error = status;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot create_adm_p %s", dir_name);
+ pending_error = status;
return;
}
if ( CVS_CHDIR (dir_name) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (dir_name)))
sprintf (pending_error_text, "E cannot change to %s", dir_name);
+ pending_error = save_errno;
return;
}
/*
@@ -1070,10 +1060,14 @@ dirswitch (dir, repos)
*/
if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM)))
+ sprintf (pending_error_text,
+ "E cannot mkdir %s/%s", dir_name, CVSADM);
+ pending_error = save_errno;
return;
}
-
+
/* The following will overwrite the contents of CVSADM_REP. This
is the correct behavior -- mkdir_p may have written a
placeholder value to this file and we need to insert the
@@ -1082,12 +1076,20 @@ dirswitch (dir, repos)
f = CVS_FOPEN (CVSADM_REP, "w");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E cannot open %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s", repos) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
@@ -1100,20 +1102,32 @@ dirswitch (dir, repos)
{
if (fprintf (f, "/.") < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
}
if (fprintf (f, "\n") < 0)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error writing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
fclose (f);
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP)))
+ sprintf (pending_error_text,
+ "E error closing %s/%s", dir_name, CVSADM_REP);
+ pending_error = save_errno;
return;
}
/* We open in append mode because we don't want to clobber an
@@ -1121,16 +1135,18 @@ dirswitch (dir, repos)
f = CVS_FOPEN (CVSADM_ENT, "a");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
return;
}
}
@@ -1139,10 +1155,7 @@ static void
serve_repository (arg)
char *arg;
{
- pending_error_text = malloc (80);
- if (pending_error_text == NULL)
- pending_error = ENOMEM;
- else
+ if (alloc_pending (80))
strcpy (pending_error_text,
"E Repository request is obsolete; aborted");
return;
@@ -1158,9 +1171,8 @@ serve_directory (arg)
status = buf_read_line (buf_from_net, &repos, (int *) NULL);
if (status == 0)
{
- if (outside_root (repos))
- return;
- dirswitch (arg, repos);
+ if (!outside_root (repos))
+ dirswitch (arg, repos);
free (repos);
}
else if (status == -2)
@@ -1199,16 +1211,18 @@ serve_static_directory (arg)
f = CVS_FOPEN (CVSADM_ENTSTAT, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
+ pending_error = save_errno;
return;
}
}
@@ -1224,23 +1238,26 @@ serve_sticky (arg)
f = CVS_FOPEN (CVSADM_TAG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_TAG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG);
+ pending_error = save_errno;
return;
}
}
@@ -1299,10 +1316,10 @@ receive_partial_file (size, file)
nwrote = write (file, data, nread);
if (nwrote < 0)
{
- pending_error_text = malloc (40);
- if (pending_error_text != NULL)
- sprintf (pending_error_text, "E unable to write");
- pending_error = errno;
+ int save_errno = errno;
+ if (alloc_pending (40))
+ strcpy (pending_error_text, "E unable to write");
+ pending_error = save_errno;
/* Read and discard the file data. */
while (size > 0)
@@ -1338,10 +1355,10 @@ receive_file (size, file, gzipped)
fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text, "E cannot open %s", arg);
- pending_error = errno;
+ pending_error = save_errno;
return;
}
@@ -1407,7 +1424,7 @@ receive_file (size, file, gzipped)
goto out;
}
- if (gunzip_and_write (fd, file, filebuf, size))
+ if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
{
if (alloc_pending (80))
sprintf (pending_error_text,
@@ -1433,10 +1450,10 @@ receive_file (size, file, gzipped)
out:
if (close (fd) < 0 && !error_pending ())
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ int save_errno = errno;
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text, "E cannot close %s", arg);
- pending_error = errno;
+ pending_error = save_errno;
return;
}
}
@@ -1515,10 +1532,11 @@ serve_modified (arg)
{
sprintf (pending_error_text,
"E error reading size for %s", arg);
- pending_error = errno;
+ pending_error = status;
}
}
}
+ free (mode_text);
return;
}
if (size_text[0] == 'z')
@@ -1543,16 +1561,24 @@ serve_modified (arg)
return;
size -= nread;
}
+ free (mode_text);
return;
}
if (outside_dir (arg))
+ {
+ free (mode_text);
return;
+ }
if (size >= 0)
{
receive_file (size, arg, gzipped);
- if (error_pending ()) return;
+ if (error_pending ())
+ {
+ free (mode_text);
+ return;
+ }
}
if (checkin_time_valid)
@@ -1563,9 +1589,11 @@ serve_modified (arg)
t.modtime = t.actime = checkin_time;
if (utime (arg, &t) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (arg)))
sprintf (pending_error_text, "E cannot utime %s", arg);
+ pending_error = save_errno;
+ free (mode_text);
return;
}
checkin_time_valid = 0;
@@ -1576,8 +1604,7 @@ serve_modified (arg)
free (mode_text);
if (status)
{
- pending_error_text = malloc (40 + strlen (arg));
- if (pending_error_text)
+ if (alloc_pending (40 + strlen (arg)))
sprintf (pending_error_text,
"E cannot change mode for %s", arg);
pending_error = status;
@@ -1852,9 +1879,10 @@ server_write_entries ()
f = CVS_FOPEN (CVSADM_ENT, "a");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
for (p = entries; p != NULL;)
@@ -1863,10 +1891,11 @@ server_write_entries ()
{
if (fprintf (f, "%s\n", p->entry) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen(CVSADM_ENT)))
sprintf (pending_error_text,
"E cannot write to %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
free (p->entry);
@@ -1877,9 +1906,10 @@ server_write_entries ()
entries = NULL;
if (f != NULL && fclose (f) == EOF && !error_pending ())
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_ENT)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
+ pending_error = save_errno;
}
}
@@ -1911,8 +1941,8 @@ static void
serve_notify (arg)
char *arg;
{
- struct notify_note *new;
- char *data;
+ struct notify_note *new = NULL;
+ char *data = NULL;
int status;
if (error_pending ()) return;
@@ -1920,27 +1950,26 @@ serve_notify (arg)
if (outside_dir (arg))
return;
+ if (dir_name == NULL)
+ goto error;
+
new = (struct notify_note *) malloc (sizeof (struct notify_note));
if (new == NULL)
{
pending_error = ENOMEM;
return;
}
- if (dir_name == NULL)
- goto error;
new->dir = malloc (strlen (dir_name) + 1);
- if (new->dir == NULL)
- {
- pending_error = ENOMEM;
- return;
- }
- strcpy (new->dir, dir_name);
new->filename = malloc (strlen (arg) + 1);
- if (new->filename == NULL)
+ if (new->dir == NULL || new->filename == NULL)
{
pending_error = ENOMEM;
+ if (new->dir != NULL)
+ free (new->dir);
+ free (new);
return;
}
+ strcpy (new->dir, dir_name);
strcpy (new->filename, arg);
status = buf_read_line (buf_from_net, &data, (int *) NULL);
@@ -1966,6 +1995,9 @@ serve_notify (arg)
}
}
}
+ free (new->filename);
+ free (new->dir);
+ free (new);
}
else
{
@@ -2013,11 +2045,18 @@ serve_notify (arg)
}
return;
error:
- pending_error_text = malloc (80);
- if (pending_error_text)
+ pending_error = 0;
+ if (alloc_pending (80))
strcpy (pending_error_text,
"E Protocol error; misformed Notify request");
- pending_error = 0;
+ if (data != NULL)
+ free (data);
+ if (new != NULL)
+ {
+ free (new->filename);
+ free (new->dir);
+ free (new);
+ }
return;
}
@@ -2060,6 +2099,7 @@ server_notify ()
buf_append_char (buf_to_net, '/');
buf_output0 (buf_to_net, notify_list->filename);
buf_append_char (buf_to_net, '\n');
+ free (repos);
p = notify_list->next;
free (notify_list->filename);
@@ -2647,22 +2687,26 @@ error \n");
if (pipe (stdout_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
if (pipe (stderr_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
if (pipe (protocol_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
#ifdef SERVER_FLOWCONTROL
if (pipe (flowcontrol_pipe) < 0)
{
+ buf_output0 (buf_to_net, "E pipe failed\n");
print_error (errno);
goto error_exit;
}
@@ -2673,6 +2717,7 @@ error \n");
dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY);
if (dev_null_fd < 0)
{
+ buf_output0 (buf_to_net, "E open /dev/null failed\n");
print_error (errno);
goto error_exit;
}
@@ -2700,6 +2745,7 @@ error \n");
command_pid = fork ();
if (command_pid < 0)
{
+ buf_output0 (buf_to_net, "E fork failed\n");
print_error (errno);
goto error_exit;
}
@@ -2733,8 +2779,11 @@ error \n");
error (1, errno, "can't set up pipes");
if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
error (1, errno, "can't set up pipes");
+ close (dev_null_fd);
close (stdout_pipe[0]);
+ close (stdout_pipe[1]);
close (stderr_pipe[0]);
+ close (stderr_pipe[1]);
close (protocol_pipe[0]);
#ifdef SERVER_FLOWCONTROL
close (flowcontrol_pipe[1]);
@@ -2769,6 +2818,7 @@ error \n");
* When we exit, that will close the pipes, giving an EOF to
* the parent.
*/
+ buf_free (protocol);
exit (exitstatus);
}
@@ -2825,6 +2875,7 @@ error \n");
if (close (stdout_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2832,6 +2883,7 @@ error \n");
if (close (stderr_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2839,6 +2891,7 @@ error \n");
if (close (protocol_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2847,6 +2900,7 @@ error \n");
#ifdef SERVER_FLOWCONTROL
if (close (flowcontrol_pipe[0]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2855,6 +2909,7 @@ error \n");
if (close (dev_null_fd) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2922,6 +2977,7 @@ error \n");
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
goto error_exit;
}
@@ -2933,48 +2989,6 @@ error \n");
buf_send_output (buf_to_net);
}
- if (stdout_pipe[0] >= 0
- && (FD_ISSET (stdout_pipe[0], &readfds)))
- {
- int status;
-
- status = buf_input_data (stdoutbuf, (int *) NULL);
-
- buf_copy_lines (buf_to_net, stdoutbuf, 'M');
-
- if (status == -1)
- stdout_pipe[0] = -1;
- else if (status > 0)
- {
- print_error (status);
- goto error_exit;
- }
-
- /* What should we do with errors? syslog() them? */
- buf_send_output (buf_to_net);
- }
-
- if (stderr_pipe[0] >= 0
- && (FD_ISSET (stderr_pipe[0], &readfds)))
- {
- int status;
-
- status = buf_input_data (stderrbuf, (int *) NULL);
-
- buf_copy_lines (buf_to_net, stderrbuf, 'E');
-
- if (status == -1)
- stderr_pipe[0] = -1;
- else if (status > 0)
- {
- print_error (status);
- goto error_exit;
- }
-
- /* What should we do with errors? syslog() them? */
- buf_send_output (buf_to_net);
- }
-
if (protocol_pipe[0] >= 0
&& (FD_ISSET (protocol_pipe[0], &readfds)))
{
@@ -2985,9 +2999,13 @@ error \n");
status = buf_input_data (protocol_inbuf, &count_read);
if (status == -1)
+ {
+ close (protocol_pipe[0]);
protocol_pipe[0] = -1;
+ }
else if (status > 0)
{
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
print_error (status);
goto error_exit;
}
@@ -3024,6 +3042,56 @@ error \n");
}
}
}
+
+ if (stdout_pipe[0] >= 0
+ && (FD_ISSET (stdout_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stdoutbuf, (int *) NULL);
+
+ buf_copy_lines (buf_to_net, stdoutbuf, 'M');
+
+ if (status == -1)
+ {
+ close (stdout_pipe[0]);
+ stdout_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
+
+ if (stderr_pipe[0] >= 0
+ && (FD_ISSET (stderr_pipe[0], &readfds)))
+ {
+ int status;
+
+ status = buf_input_data (stderrbuf, (int *) NULL);
+
+ buf_copy_lines (buf_to_net, stderrbuf, 'E');
+
+ if (status == -1)
+ {
+ close (stderr_pipe[0]);
+ stderr_pipe[0] = -1;
+ }
+ else if (status > 0)
+ {
+ buf_output0 (buf_to_net, "E buf_input_data failed\n");
+ print_error (status);
+ goto error_exit;
+ }
+
+ /* What should we do with errors? syslog() them? */
+ buf_send_output (buf_to_net);
+ }
}
/*
@@ -3045,6 +3113,11 @@ error \n");
buf_output0 (buf_to_net,
"E Protocol error: uncounted data discarded\n");
+#ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[1]);
+ flowcontrol_pipe[1] = -1;
+#endif /* SERVER_FLOWCONTROL */
+
errs = 0;
while (command_pid > 0)
@@ -3099,6 +3172,12 @@ E CVS locks may need cleaning up.\n");
*/
set_block (buf_to_net);
buf_flush (buf_to_net, 1);
+ buf_shutdown (protocol_inbuf);
+ buf_free (protocol_inbuf);
+ buf_shutdown (stderrbuf);
+ buf_free (stderrbuf);
+ buf_shutdown (stdoutbuf);
+ buf_free (stdoutbuf);
}
if (errs)
@@ -3129,6 +3208,10 @@ E CVS locks may need cleaning up.\n");
close (stderr_pipe[1]);
close (stdout_pipe[0]);
close (stdout_pipe[1]);
+#ifdef SERVER_FLOWCONTROL
+ close (flowcontrol_pipe[0]);
+ close (flowcontrol_pipe[1]);
+#endif /* SERVER_FLOWCONTROL */
free_args_and_return:
/* Now free the arguments. */
@@ -3184,6 +3267,7 @@ server_pause_check()
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
return;
}
@@ -3624,23 +3708,29 @@ serve_editors (arg)
do_cvs_command ("editors", editors);
}
-static int noop PROTO ((int, char **));
+static void serve_noop PROTO ((char *));
-static int
-noop (argc, argv)
- int argc;
- char **argv;
+static void
+serve_noop (arg)
+ char *arg;
{
- return 0;
+
+ server_write_entries ();
+ if (!print_pending_error ())
+ {
+ (void) server_notify ();
+ buf_output0 (buf_to_net, "ok\n");
+ }
+ buf_flush (buf_to_net, 1);
}
-static void serve_noop PROTO ((char *));
+static void serve_version PROTO ((char *));
static void
-serve_noop (arg)
+serve_version (arg)
char *arg;
{
- do_cvs_command ("noop", noop);
+ do_cvs_command ("version", version);
}
static void serve_init PROTO ((char *));
@@ -4017,7 +4107,7 @@ CVS server internal error: unhandled case in server_updated");
if (file != NULL)
{
- buf_output (protocol, file, file_used);
+ buf_output (protocol, (char *) file, file_used);
free (file);
file = NULL;
}
@@ -4314,9 +4404,9 @@ serve_ignore (arg)
}
static int
-expand_proc (pargc, argv, where, mwhere, mfile, shorten,
+expand_proc (argc, argv, where, mwhere, mfile, shorten,
local_specified, omodule, msg)
- int *pargc;
+ int argc;
char **argv;
char *where;
char *mwhere;
@@ -4355,7 +4445,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten,
{
/* We may not need to do this anymore -- check the definition
of aliases before removing */
- if (*pargc == 1)
+ if (argc == 1)
{
buf_output0 (buf_to_net, "Module-expansion ");
if (server_dir != NULL)
@@ -4368,7 +4458,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten,
}
else
{
- for (i = 1; i < *pargc; ++i)
+ for (i = 1; i < argc; ++i)
{
buf_output0 (buf_to_net, "Module-expansion ");
if (server_dir != NULL)
@@ -4460,24 +4550,27 @@ serve_checkin_prog (arg)
f = CVS_FOPEN (CVSADM_CIPROG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text,
"E cannot write to %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_CIPROG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_CIPROG);
+ pending_error = save_errno;
return;
}
}
@@ -4503,23 +4596,26 @@ E Flag -u in modules not allowed in readonly mode");
f = CVS_FOPEN (CVSADM_UPROG, "w+");
if (f == NULL)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot open %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
if (fprintf (f, "%s\n", arg) < 0)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot write to %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
if (fclose (f) == EOF)
{
- pending_error = errno;
+ int save_errno = errno;
if (alloc_pending (80 + strlen (CVSADM_UPROG)))
sprintf (pending_error_text, "E cannot close %s", CVSADM_UPROG);
+ pending_error = save_errno;
return;
}
}
@@ -4572,7 +4668,7 @@ struct request requests[] =
REQ_LINE("Case", serve_case, 0),
REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL),
REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL),
- REQ_LINE("Global_option", serve_global_option, 0),
+ REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS),
REQ_LINE("Gzip-stream", serve_gzip_stream, 0),
REQ_LINE("wrapper-sendme-rcsOptions",
serve_wrapper_sendme_rcs_options,
@@ -4616,7 +4712,8 @@ struct request requests[] =
REQ_LINE("editors", serve_editors, 0),
REQ_LINE("init", serve_init, RQ_ROOTLESS),
REQ_LINE("annotate", serve_annotate, 0),
- REQ_LINE("noop", serve_noop, 0),
+ REQ_LINE("noop", serve_noop, RQ_ROOTLESS),
+ REQ_LINE("version", serve_version, RQ_ROOTLESS),
REQ_LINE(NULL, NULL, 0)
#undef REQ_LINE
@@ -4840,16 +4937,10 @@ server (argc, argv)
for that case. */
if (!isabsolute (Tmpdir))
{
- pending_error_text = malloc (80 + strlen (Tmpdir));
- if (pending_error_text == NULL)
- {
- pending_error = ENOMEM;
- }
- else
- {
+ if (alloc_pending (80 + strlen (Tmpdir)))
sprintf (pending_error_text,
"E Value of %s for TMPDIR is not absolute", Tmpdir);
- }
+
/* FIXME: we would like this error to be persistent, that
is, not cleared by print_pending_error. The current client
will exit as soon as it gets an error, but the protocol spec
@@ -4858,6 +4949,7 @@ server (argc, argv)
else
{
int status;
+ int i = 0;
server_temp_dir = malloc (strlen (Tmpdir) + 80);
if (server_temp_dir == NULL)
@@ -4904,12 +4996,21 @@ error ENOMEM Virtual memory exhausted.\n");
/* Create the temporary directory, and set the mode to
700, to discourage random people from tampering with
it. */
- status = mkdir_p (server_temp_dir);
- if (status != 0 && status != EEXIST)
+ while ((status = mkdir_p (server_temp_dir)) == EEXIST)
{
- if (alloc_pending (80))
- strcpy (pending_error_text,
- "E can't create temporary directory");
+ static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
+
+ if (i >= sizeof suffix - 1) break;
+ if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
+ p[0] = suffix[i++];
+ p[1] = '\0';
+ }
+ if (status != 0)
+ {
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+ "E can't create temporary directory %s",
+ server_temp_dir);
pending_error = status;
}
#ifndef CHMOD_BROKEN
@@ -4918,9 +5019,10 @@ error ENOMEM Virtual memory exhausted.\n");
if (chmod (server_temp_dir, S_IRWXU) < 0)
{
int save_errno = errno;
- if (alloc_pending (80))
- strcpy (pending_error_text, "\
-E cannot change permissions on temporary directory");
+ if (alloc_pending (80 + strlen (server_temp_dir)))
+ sprintf (pending_error_text,
+"E cannot change permissions on temporary directory %s",
+ server_temp_dir);
pending_error = save_errno;
}
}
@@ -4928,6 +5030,9 @@ E cannot change permissions on temporary directory");
}
}
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, server_cleanup);
+#endif
#ifdef SIGHUP
(void) SIG_register (SIGHUP, server_cleanup);
#endif
@@ -5107,7 +5212,7 @@ error 0 %s: no such user\n", username);
if (setgid (getegid ()) < 0)
{
/* See comments at setuid call below for more discussion. */
- printf ("error 0 setuid failed: %s\n", strerror (errno));
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
/* Don't worry about server_cleanup;
server_active isn't set yet. */
error_exit ();
@@ -5119,7 +5224,7 @@ error 0 %s: no such user\n", username);
if (setgid (pw->pw_gid) < 0)
{
/* See comments at setuid call below for more discussion. */
- printf ("error 0 setuid failed: %s\n", strerror (errno));
+ printf ("error 0 setgid failed: %s\n", strerror (errno));
/* Don't worry about server_cleanup;
server_active isn't set yet. */
error_exit ();
@@ -5144,6 +5249,12 @@ error 0 %s: no such user\n", username);
the client. */
umask (0);
+#ifdef AUTH_SERVER_SUPPORT
+ /* Make sure our CVS_Username has been set. */
+ if (CVS_Username == NULL)
+ CVS_Username = xstrdup (username);
+#endif
+
#if HAVE_PUTENV
/* Set LOGNAME and USER in the environment, in case they are
already set to something else. */
@@ -5169,14 +5280,15 @@ extern char *crypt PROTO((const char *, const char *));
/*
* 0 means no entry found for this user.
- * 1 means entry found and password matches.
+ * 1 means entry found and password matches (or found password is empty)
* 2 means entry found, but password does not match.
*
- * If success, host_user_ptr will be set to point at the system
+ * If 1, host_user_ptr will be set to point at the system
* username (i.e., the "real" identity, which may or may not be the
* CVS username) of this user; caller may free this. Global
* CVS_Username will point at an allocated copy of cvs username (i.e.,
* the username argument below).
+ * kff todo: FIXME: last sentence is not true, it applies to caller.
*/
static int
check_repository_password (username, password, repository, host_user_ptr)
@@ -5229,18 +5341,72 @@ check_repository_password (username, password, repository, host_user_ptr)
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", filename);
- /* If found_it != 0, then linebuf contains the information we need. */
+ /* If found_it, then linebuf contains the information we need. */
if (found_it)
{
char *found_password, *host_user_tmp;
+ char *non_cvsuser_portion;
+
+ /* We need to make sure lines such as
+ *
+ * "username::sysuser\n"
+ * "username:\n"
+ * "username: \n"
+ *
+ * all result in a found_password of NULL, but we also need to
+ * make sure that
+ *
+ * "username: :sysuser\n"
+ * "username: <whatever>:sysuser\n"
+ *
+ * continues to result in an impossible password. That way,
+ * an admin would be on safe ground by going in and tacking a
+ * space onto the front of a password to disable the account
+ * (a technique some people use to close accounts
+ * temporarily).
+ */
+
+ /* Make `non_cvsuser_portion' contain everything after the CVS
+ username, but null out any final newline. */
+ non_cvsuser_portion = linebuf + namelen;
+ strtok (non_cvsuser_portion, "\n");
+
+ /* If there's a colon now, we just want to inch past it. */
+ if (strchr (non_cvsuser_portion, ':') == non_cvsuser_portion)
+ non_cvsuser_portion++;
+
+ /* Okay, after this conditional chain, found_password and
+ host_user_tmp will have useful values: */
+
+ if ((non_cvsuser_portion == NULL)
+ || (strlen (non_cvsuser_portion) == 0)
+ || ((strspn (non_cvsuser_portion, " \t"))
+ == strlen (non_cvsuser_portion)))
+ {
+ found_password = NULL;
+ host_user_tmp = NULL;
+ }
+ else if (strncmp (non_cvsuser_portion, ":", 1) == 0)
+ {
+ found_password = NULL;
+ host_user_tmp = non_cvsuser_portion + 1;
+ if (strlen (host_user_tmp) == 0)
+ host_user_tmp = NULL;
+ }
+ else
+ {
+ found_password = strtok (non_cvsuser_portion, ":");
+ host_user_tmp = strtok (NULL, ":");
+ }
- strtok (linebuf, ":");
- found_password = strtok (NULL, ": \n");
- host_user_tmp = strtok (NULL, ": \n");
+ /* Of course, maybe there was no system user portion... */
if (host_user_tmp == NULL)
host_user_tmp = username;
- if (strcmp (found_password, crypt (password, found_password)) == 0)
+ /* Verify blank passwords directly, otherwise use crypt(). */
+ if ((found_password == NULL)
+ || ((strcmp (found_password, crypt (password, found_password))
+ == 0)))
{
/* Give host_user_ptr permanent storage. */
*host_user_ptr = xstrdup (host_user_tmp);
@@ -5252,7 +5418,7 @@ check_repository_password (username, password, repository, host_user_ptr)
retval = 2;
}
}
- else
+ else /* Didn't find this user, so deny access. */
{
*host_user_ptr = NULL;
retval = 0;
@@ -5335,14 +5501,14 @@ error 0 %s: no such user\n", username);
/* user exists and has a password */
host_user = ((! strcmp (found_passwd,
crypt (password, found_passwd)))
- ? username : NULL);
+ ? xstrdup (username) : NULL);
goto handle_return;
}
else if (password && *password)
{
/* user exists and has no system password, but we got
one as parameter */
- host_user = username;
+ host_user = xstrdup (username);
goto handle_return;
}
else
@@ -5472,7 +5638,7 @@ pserver_authenticate_connection ()
#endif
/* Make sure the protocol starts off on the right foot... */
- if (getline (&tmp, &tmp_allocated, stdin) < 0)
+ if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0)
/* FIXME: what? We could try writing error/eof, but chances
are the network connection is dead bidirectionally. log it
somewhere? */
@@ -5503,9 +5669,9 @@ pserver_authenticate_connection ()
/* Get the three important pieces of information in order. */
/* See above comment about error handling. */
- getline (&repository, &repository_allocated, stdin);
- getline (&username, &username_allocated, stdin);
- getline (&password, &password_allocated, stdin);
+ getline_safe (&repository, &repository_allocated, stdin, PATH_MAX);
+ getline_safe (&username, &username_allocated, stdin, PATH_MAX);
+ getline_safe (&password, &password_allocated, stdin, PATH_MAX);
/* Make them pure. */
strip_trailing_newlines (repository);
@@ -5514,7 +5680,7 @@ pserver_authenticate_connection ()
/* ... and make sure the protocol ends on the right foot. */
/* See above comment about error handling. */
- getline (&tmp, &tmp_allocated, stdin);
+ getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX);
if (strcmp (tmp,
verify_and_exit ?
"END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n")
@@ -5576,6 +5742,7 @@ pserver_authenticate_connection ()
/* Switch to run as this user. */
switch_to_user (host_user);
+ free (host_user);
free (tmp);
free (repository);
free (username);
OpenPOWER on IntegriCloud