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.c532
1 files changed, 348 insertions, 184 deletions
diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c
index 63fef8c..a53dc79 100644
--- a/contrib/cvs/src/server.c
+++ b/contrib/cvs/src/server.c
@@ -187,6 +187,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
@@ -208,7 +209,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);
}
@@ -345,6 +346,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. */
@@ -742,8 +753,6 @@ serve_root (arg)
{
char *env;
char *path;
- int save_errno;
- char *arg_dup;
if (error_pending()) return;
@@ -785,14 +794,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. */
@@ -803,7 +805,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)
{
@@ -813,23 +814,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 (readonlyfs == 0 && 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
@@ -1043,9 +1032,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;
}
@@ -1058,17 +1047,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;
}
/*
@@ -1077,10 +1067,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
@@ -1089,12 +1083,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;
}
@@ -1107,20 +1109,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
@@ -1128,16 +1142,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;
}
}
@@ -1146,10 +1162,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;
@@ -1165,9 +1178,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)
@@ -1206,16 +1218,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;
}
}
@@ -1231,23 +1245,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;
}
}
@@ -1306,10 +1323,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)
@@ -1345,10 +1362,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;
}
@@ -1414,7 +1431,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,
@@ -1440,10 +1457,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;
}
}
@@ -1522,10 +1539,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')
@@ -1550,16 +1568,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)
@@ -1570,9 +1596,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;
@@ -1583,8 +1611,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;
@@ -1859,9 +1886,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;)
@@ -1870,10 +1898,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);
@@ -1884,9 +1913,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;
}
}
@@ -1918,8 +1948,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;
@@ -1927,27 +1957,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);
@@ -1973,6 +2002,9 @@ serve_notify (arg)
}
}
}
+ free (new->filename);
+ free (new->dir);
+ free (new);
}
else
{
@@ -2020,11 +2052,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;
}
@@ -2067,6 +2106,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);
@@ -2654,22 +2694,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;
}
@@ -2680,6 +2724,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;
}
@@ -2707,6 +2752,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;
}
@@ -2740,8 +2786,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]);
@@ -2776,6 +2825,7 @@ error \n");
* When we exit, that will close the pipes, giving an EOF to
* the parent.
*/
+ buf_free (protocol);
exit (exitstatus);
}
@@ -2832,6 +2882,7 @@ error \n");
if (close (stdout_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2839,6 +2890,7 @@ error \n");
if (close (stderr_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2846,6 +2898,7 @@ error \n");
if (close (protocol_pipe[1]) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2854,6 +2907,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;
}
@@ -2862,6 +2916,7 @@ error \n");
if (close (dev_null_fd) < 0)
{
+ buf_output0 (buf_to_net, "E close failed\n");
print_error (errno);
goto error_exit;
}
@@ -2929,6 +2984,7 @@ error \n");
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
goto error_exit;
}
@@ -2940,48 +2996,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)))
{
@@ -2992,9 +3006,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;
}
@@ -3031,6 +3049,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);
+ }
}
/*
@@ -3052,6 +3120,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)
@@ -3106,6 +3179,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)
@@ -3136,6 +3215,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. */
@@ -3191,6 +3274,7 @@ server_pause_check()
if (numfds < 0
&& errno != EINTR)
{
+ buf_output0 (buf_to_net, "E select failed\n");
print_error (errno);
return;
}
@@ -3631,23 +3715,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 *));
@@ -4024,7 +4114,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;
}
@@ -4321,9 +4411,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;
@@ -4362,7 +4452,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)
@@ -4375,7 +4465,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)
@@ -4467,24 +4557,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;
}
}
@@ -4510,23 +4603,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;
}
}
@@ -4579,7 +4675,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,
@@ -4623,7 +4719,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
@@ -4847,16 +4944,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
@@ -4865,6 +4956,7 @@ server (argc, argv)
else
{
int status;
+ int i = 0;
server_temp_dir = malloc (strlen (Tmpdir) + 80);
if (server_temp_dir == NULL)
@@ -4911,12 +5003,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
@@ -4925,9 +5026,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;
}
}
@@ -4935,6 +5037,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
@@ -5114,7 +5219,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 ();
@@ -5126,7 +5231,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 ();
@@ -5151,6 +5256,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. */
@@ -5176,14 +5287,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)
@@ -5236,21 +5348,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 = NULL;
- char *linebufp = linebuf;
+ 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, ":");
+ }
- strsep (&linebufp, ":");
- found_password = strsep (&linebufp, ": \n");
- if (found_password)
- host_user_tmp = strsep (&linebufp, ": \n");
+ /* Of course, maybe there was no system user portion... */
if (host_user_tmp == NULL)
host_user_tmp = username;
- if (found_password == NULL || *found_password == '\0' ||
- 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);
@@ -5262,7 +5425,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;
@@ -5348,14 +5511,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
@@ -5485,7 +5648,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? */
@@ -5516,9 +5679,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);
@@ -5527,7 +5690,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")
@@ -5589,6 +5752,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