--- /dev/null
+diff -urN cvs-nserver-1.11.1.52.org/acinclude.m4 cvs-nserver-1.11.1.52/acinclude.m4
+--- cvs-nserver-1.11.1.52.org/acinclude.m4 2004-06-11 15:13:22.806441712 +0200
++++ cvs-nserver-1.11.1.52/acinclude.m4 2004-06-11 15:14:12.949818760 +0200
+@@ -229,3 +229,85 @@
+ AC_SEARCH_LIBS([gss_import_name], [gssapi_krb5 gssapi])
+ fi
+ ])dnl
++
++
++
++# size_max.m4 serial 2
++dnl Copyright (C) 2003 Free Software Foundation, Inc.
++dnl This file is free software, distributed under the terms of the GNU
++dnl General Public License. As a special exception to the GNU General
++dnl Public License, this file may be distributed as part of a program
++dnl that contains a configuration script generated by Autoconf, under
++dnl the same distribution terms as the rest of that program.
++
++dnl From Bruno Haible.
++
++AC_DEFUN([gl_SIZE_MAX],
++[
++ AC_CHECK_HEADERS(stdint.h)
++ dnl First test whether the system already has SIZE_MAX.
++ AC_MSG_CHECKING([for SIZE_MAX])
++ result=
++ AC_EGREP_CPP([Found it], [
++#include <limits.h>
++#if HAVE_STDINT_H
++#include <stdint.h>
++#endif
++#ifdef SIZE_MAX
++Found it
++#endif
++], result=yes)
++ if test -z "$result"; then
++ dnl Define it ourselves. Here we assume that the type 'size_t' is not wider
++ dnl than the type 'unsigned long'.
++ dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr',
++ dnl which is guaranteed to work from LONG_MIN to LONG_MAX.
++ _AC_COMPUTE_INT([~(size_t)0 / 10], res_hi,
++ [#include <stddef.h>], result=?)
++ _AC_COMPUTE_INT([~(size_t)0 % 10], res_lo,
++ [#include <stddef.h>], result=?)
++ _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint,
++ [#include <stddef.h>], result=?)
++ if test "$fits_in_uint" = 1; then
++ dnl Even though SIZE_MAX fits in an unsigned int, it must be of type
++ dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'.
++ AC_TRY_COMPILE([#include <stddef.h>
++ extern size_t foo;
++ extern unsigned long foo;
++ ], [], fits_in_uint=0)
++ fi
++ if test -z "$result"; then
++ if test "$fits_in_uint" = 1; then
++ result="$res_hi$res_lo"U
++ else
++ result="$res_hi$res_lo"UL
++ fi
++ else
++ dnl Shouldn't happen, but who knows...
++ result='~(size_t)0'
++ fi
++ fi
++ AC_MSG_RESULT([$result])
++ if test "$result" != yes; then
++ AC_DEFINE_UNQUOTED([SIZE_MAX], [$result],
++ [Define as the maximum value of type 'size_t', if the system doesn't define it.])
++ fi
++])
++
++
++
++# xsize.m4 serial 3
++dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
++dnl This file is free software, distributed under the terms of the GNU
++dnl General Public License. As a special exception to the GNU General
++dnl Public License, this file may be distributed as part of a program
++dnl that contains a configuration script generated by Autoconf, under
++dnl the same distribution terms as the rest of that program.
++
++AC_DEFUN([gl_XSIZE],
++[
++ dnl Prerequisites of lib/xsize.h.
++ AC_REQUIRE([gl_SIZE_MAX])
++ AC_REQUIRE([AC_C_INLINE])
++ AC_CHECK_HEADERS(stdint.h)
++])
+diff -urN cvs-nserver-1.11.1.52.org/config.h.in cvs-nserver-1.11.1.52/config.h.in
+--- cvs-nserver-1.11.1.52.org/config.h.in 2004-06-11 15:13:22.807441560 +0200
++++ cvs-nserver-1.11.1.52/config.h.in 2004-06-11 15:15:19.522698144 +0200
+@@ -9,6 +9,10 @@
+ clients. */
+ #undef SERVER_SUPPORT
+
++/* Define as the maximum value of type 'size_t', if the system doesn't define
+++ it. */
++#undef SIZE_MAX
++
+ /* Define if you want to use the password authenticated server. */
+ #undef AUTH_SERVER_SUPPORT
+
+@@ -377,6 +381,12 @@
+ /* Define to `int' if <sys/types.h> doesn't define. */
+ #undef gid_t
+
++/* Define to `__inline__' or `__inline' if that's what the C compiler
++ calls it, or to nothing if 'inline' is not supported under any name. */
++#ifndef __cplusplus
++#undef inline
++#endif
++
+ /* Define to `int' if <sys/types.h> does not define. */
+ #undef mode_t
+
+diff -urN cvs-nserver-1.11.1.52.org/configure.in cvs-nserver-1.11.1.52/configure.in
+--- cvs-nserver-1.11.1.52.org/configure.in 2004-06-11 15:13:22.811440952 +0200
++++ cvs-nserver-1.11.1.52/configure.in 2004-06-11 15:16:03.298043280 +0200
+@@ -121,6 +121,8 @@
+ AC_TYPE_SIZE_T
+ AC_TYPE_SIGNAL
+
++gl_XSIZE
++
+ AC_STRUCT_ST_BLKSIZE
+ AC_STRUCT_ST_RDEV
+ AC_REPLACE_FUNCS(mkdir rename strstr dup2 strerror valloc waitpid memmove strtoul)
+diff -urN cvs-nserver-1.11.1.52.org/lib/Makefile.am cvs-nserver-1.11.1.52/lib/Makefile.am
+--- cvs-nserver-1.11.1.52.org/lib/Makefile.am 2004-06-11 15:13:22.873431528 +0200
++++ cvs-nserver-1.11.1.52/lib/Makefile.am 2004-06-11 15:16:50.173917064 +0200
+@@ -83,6 +83,9 @@
+ build_lib.com \
+ xgssapi.h
+
++# For the xsize module from GNULIB.
++libcvs_a_SOURCES += xsize.h
++
+ # for backwards compatibility with the old makefiles
+ realclean: maintainer-clean
+ .PHONY: realclean
+diff -urN cvs-nserver-1.11.1.52.org/lib/Makefile.in cvs-nserver-1.11.1.52/lib/Makefile.in
+--- cvs-nserver-1.11.1.52.org/lib/Makefile.in 2004-06-11 15:13:22.874431376 +0200
++++ cvs-nserver-1.11.1.52/lib/Makefile.in 2004-06-11 15:14:13.013809032 +0200
+@@ -128,6 +128,8 @@
+ # Also should look into unifying regular expression matching in CVS
+ # with the diff library (perhaps to have the caller, CVS, do the
+ # matching?)
++
++# For the xsize module from GNULIB.
+ libcvs_a_SOURCES = \
+ argmatch.c \
+ ftruncate.c \
+@@ -151,8 +153,8 @@
+ system.h \
+ wait.h \
+ xselect.h \
+- xtime.h
+-
++ xtime.h\
++xsize.h
+ libcvs_a_LIBADD = @LIBOBJS@
+
+ EXTRA_DIST = \
+diff -urN cvs-nserver-1.11.1.52.org/lib/xsize.h cvs-nserver-1.11.1.52/lib/xsize.h
+--- cvs-nserver-1.11.1.52.org/lib/xsize.h 1970-01-01 01:00:00.000000000 +0100
++++ cvs-nserver-1.11.1.52/lib/xsize.h 2004-06-11 15:14:13.015808728 +0200
+@@ -0,0 +1,108 @@
++/* xsize.h -- Checked size_t computations.
++
++ Copyright (C) 2003 Free Software Foundation, Inc.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2, or (at your option)
++ any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software Foundation,
++ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++#ifndef _XSIZE_H
++#define _XSIZE_H
++
++/* Get size_t. */
++#include <stddef.h>
++
++/* Get SIZE_MAX. */
++#include <limits.h>
++#if HAVE_STDINT_H
++# include <stdint.h>
++#endif
++
++/* The size of memory objects is often computed through expressions of
++ type size_t. Example:
++ void* p = malloc (header_size + n * element_size).
++ These computations can lead to overflow. When this happens, malloc()
++ returns a piece of memory that is way too small, and the program then
++ crashes while attempting to fill the memory.
++ To avoid this, the functions and macros in this file check for overflow.
++ The convention is that SIZE_MAX represents overflow.
++ malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
++ implementation that uses mmap --, it's recommended to use size_overflow_p()
++ or size_in_bounds_p() before invoking malloc().
++ The example thus becomes:
++ size_t size = xsum (header_size, xtimes (n, element_size));
++ void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
++*/
++
++/* Convert an arbitrary value >= 0 to type size_t. */
++#define xcast_size_t(N) \
++ ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
++
++/* Sum of two sizes, with overflow check. */
++static inline size_t
++#if __GNUC__ >= 3
++__attribute__ ((__pure__))
++#endif
++xsum (size_t size1, size_t size2)
++{
++ size_t sum = size1 + size2;
++ return (sum >= size1 ? sum : SIZE_MAX);
++}
++
++/* Sum of three sizes, with overflow check. */
++static inline size_t
++#if __GNUC__ >= 3
++__attribute__ ((__pure__))
++#endif
++xsum3 (size_t size1, size_t size2, size_t size3)
++{
++ return xsum (xsum (size1, size2), size3);
++}
++
++/* Sum of four sizes, with overflow check. */
++static inline size_t
++#if __GNUC__ >= 3
++__attribute__ ((__pure__))
++#endif
++xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
++{
++ return xsum (xsum (xsum (size1, size2), size3), size4);
++}
++
++/* Maximum of two sizes, with overflow check. */
++static inline size_t
++#if __GNUC__ >= 3
++__attribute__ ((__pure__))
++#endif
++xmax (size_t size1, size_t size2)
++{
++ /* No explicit check is needed here, because for any n:
++ max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
++ return (size1 >= size2 ? size1 : size2);
++}
++
++/* Multiplication of a count with an element size, with overflow check.
++ The count must be >= 0 and the element size must be > 0.
++ This is a macro, not an inline function, so that it works correctly even
++ when N is of a wider tupe and N > SIZE_MAX. */
++#define xtimes(N, ELSIZE) \
++ ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
++
++/* Check for overflow. */
++#define size_overflow_p(SIZE) \
++ ((SIZE) == SIZE_MAX)
++/* Check against overflow. */
++#define size_in_bounds_p(SIZE) \
++ ((SIZE) != SIZE_MAX)
++
++#endif /* _XSIZE_H */
+diff -urN cvs-nserver-1.11.1.52.org/src/commit.c cvs-nserver-1.11.1.52/src/commit.c
+--- cvs-nserver-1.11.1.52.org/src/commit.c 2004-06-11 15:13:22.631468312 +0200
++++ cvs-nserver-1.11.1.52/src/commit.c 2004-06-11 15:14:13.030806448 +0200
+@@ -476,7 +476,12 @@
+ operate on, and only work with those files in the future.
+ This saves time--we don't want to search the file system
+ of the working directory twice. */
+- find_args.argv = (char **) xmalloc (find_args.argc * sizeof (char **));
++ if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
++ {
++ find_args.argc = 0;
++ return 0;
++ }
++ find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **)));
+ find_args.argc = 0;
+ walklist (find_args.ulist, copy_ulist, &find_args);
+
+diff -urN cvs-nserver-1.11.1.52.org/src/cvs.h cvs-nserver-1.11.1.52/src/cvs.h
+--- cvs-nserver-1.11.1.52.org/src/cvs.h 2004-06-11 15:13:22.711456152 +0200
++++ cvs-nserver-1.11.1.52/src/cvs.h 2004-06-11 15:14:13.039805080 +0200
+@@ -37,6 +37,10 @@
+ #include "popen.h"
+ #endif
+
++/* Begin GNULIB headers. */
++#include "xsize.h"
++/* End GNULIB headers. */
++
+ #ifdef STDC_HEADERS
+ #include <stdlib.h>
+ #else
+diff -urN cvs-nserver-1.11.1.52.org/src/filesubr.c cvs-nserver-1.11.1.52/src/filesubr.c
+--- cvs-nserver-1.11.1.52.org/src/filesubr.c 2004-06-11 15:13:22.638467248 +0200
++++ cvs-nserver-1.11.1.52/src/filesubr.c 2004-06-11 15:14:13.042804624 +0200
+@@ -925,8 +925,14 @@
+ char ***pargv;
+ {
+ int i;
++ if (size_overflow_p (xtimes (argc, sizeof (char *)))) {
++ *pargc = 0;
++ *pargv = NULL;
++ error (0, 0, "expand_wild: too many arguments");
++ return;
++ }
+ *pargc = argc;
+- *pargv = (char **) xmalloc (argc * sizeof (char *));
++ *pargv = xmalloc (xtimes (argc, sizeof (char *)));
+ for (i = 0; i < argc; ++i)
+ (*pargv)[i] = xstrdup (argv[i]);
+ }
+diff -urN cvs-nserver-1.11.1.52.org/src/history.c cvs-nserver-1.11.1.52/src/history.c
+--- cvs-nserver-1.11.1.52.org/src/history.c 2004-06-11 15:13:22.642466640 +0200
++++ cvs-nserver-1.11.1.52/src/history.c 2004-06-11 15:14:13.046804016 +0200
+@@ -417,8 +417,11 @@
+ working = 1;
+ break;
+ case 'X': /* Undocumented debugging flag */
++#ifdef DEBUG
+ histfile = optarg;
++#endif
+ break;
++
+ case 'D': /* Since specified date */
+ if (*since_rev || *since_tag || *backto)
+ {
+@@ -900,9 +903,13 @@
+ {
+ if (user_count == user_max)
+ {
+- user_max += USER_INCREMENT;
+- user_list = (char **) xrealloc ((char *) user_list,
+- (int) user_max * sizeof (char *));
++ user_max = xsum (user_max, USER_INCREMENT);
++ if (size_overflow_p (xtimes (user_max, sizeof (char *))))
++ {
++ error (0, 0, "save_user: too many users");
++ return;
++ }
++ user_list = xrealloc (user_list, xtimes (user_max, sizeof (char *)));
+ }
+ user_list[user_count++] = xstrdup (name);
+ }
+@@ -930,9 +937,13 @@
+
+ if (file_count == file_max)
+ {
+- file_max += FILE_INCREMENT;
+- file_list = (struct file_list_str *) xrealloc ((char *) file_list,
+- file_max * sizeof (*fl));
++ file_max = xsum (file_max, FILE_INCREMENT);
++ if (size_overflow_p (xtimes (file_max, sizeof (*fl))))
++ {
++ error (0, 0, "save_file: too many files");
++ return;
++ }
++ file_list = xrealloc (file_list, xtimes (file_max, sizeof (*fl)));
+ }
+ fl = &file_list[file_count++];
+ fl->l_file = cp = xmalloc (strlen (dir) + strlen (name) + 2);
+@@ -971,9 +982,13 @@
+ {
+ if (mod_count == mod_max)
+ {
+- mod_max += MODULE_INCREMENT;
+- mod_list = (char **) xrealloc ((char *) mod_list,
+- mod_max * sizeof (char *));
++ mod_max = xsum (mod_max, MODULE_INCREMENT);
++ if (size_overflow_p (xtimes (mod_max, sizeof (char *))))
++ {
++ error (0, 0, "save_module: too many modules");
++ return;
++ }
++ mod_list = xrealloc (mod_list, xtimes (mod_max, sizeof (char *)));
+ }
+ mod_list[mod_count++] = xstrdup (module);
+ }
+diff -urN cvs-nserver-1.11.1.52.org/src/server.c cvs-nserver-1.11.1.52/src/server.c
+--- cvs-nserver-1.11.1.52.org/src/server.c 2004-06-11 15:13:22.702457520 +0200
++++ cvs-nserver-1.11.1.52/src/server.c 2004-06-11 15:20:44.835243120 +0200
+@@ -914,7 +914,7 @@
+ int i;
+ char *p;
+
+- if (lim < 0)
++ if (lim < 0 || lim > 10000)
+ return;
+ p = malloc (strlen (server_temp_dir) + 2 * lim + 10);
+ if (p == NULL)
+@@ -1977,6 +1977,9 @@
+ {
+ char *cp;
+
++ if (!data[0])
++ goto error;
++
+ if (strchr (data, '+'))
+ goto error;
+
+@@ -2108,6 +2111,14 @@
+ char *p;
+
+ if (error_pending()) return;
++
++ if (argument_count >= 10000)
++ {
++ if (alloc_pending (80))
++ sprintf (pending_error_text,
++ "E Protocol error: too many arguments");
++ return;
++ }
+
+ if (argument_vector_size <= argument_count + 1)
+ {
+@@ -2139,6 +2150,14 @@
+ char *p;
+
+ if (error_pending()) return;
++
++ if (argument_count <= 1)
++ {
++ if (alloc_pending (80))
++ sprintf (pending_error_text,
++ "E Protocol error: called argumentx without prior call to argument");
++ return;
++ }
+
+ p = argument_vector[argument_count - 1];
+ p = realloc (p, strlen (p) + 1 + strlen (arg) + 1);
+@@ -2496,7 +2515,7 @@
+ save some code here... -kff */
+
+ /* Chop newline by hand, for strcmp()'s sake. */
+- if (linebuf[num_red - 1] == '\n')
++ if (num_red > 0 && linebuf[num_red - 1] == '\n')
+ linebuf[num_red - 1] = '\0';
+
+ if (strcmp (linebuf, CVS_Username) == 0)
+diff -urN cvs-nserver-1.11.1.52.org/src/wrapper.c cvs-nserver-1.11.1.52/src/wrapper.c
+--- cvs-nserver-1.11.1.52.org/src/wrapper.c 2004-06-11 15:13:22.708456608 +0200
++++ cvs-nserver-1.11.1.52/src/wrapper.c 2004-06-11 15:14:13.083798392 +0200
+@@ -252,6 +252,30 @@
+ #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
+
+ /*
++ * Remove fmt str specifier other than %% or %s. And allow
++ * only max_s %s specifiers
++ */
++wrap_clean_fmt_str(char *fmt, int max_s)
++{
++ while (*fmt) {
++ if (fmt[0] == '%' && fmt[1])
++ {
++ if (fmt[1] == '%')
++ fmt++;
++ else
++ if (fmt[1] == 's' && max_s > 0)
++ {
++ max_s--;
++ fmt++;
++ } else
++ *fmt = ' ';
++ }
++ fmt++;
++ }
++ return;
++}
++
++/*
+ * Open a file and read lines, feeding each line to a line parser. Arrange
+ * for keeping a temporary list of wrappers at the end, if the "temp"
+ * argument is set.
+@@ -575,9 +599,8 @@
+ args = xmalloc (strlen (e->tocvsFilter)
+ + strlen (fileName)
+ + strlen (buf));
+- /* FIXME: sprintf will blow up if the format string contains items other
+- than %s, or contains too many %s's. We should instead be parsing
+- e->tocvsFilter ourselves and giving a real error. */
++
++ wrap_clean_fmt_str(e->tocvsFilter, 2);
+ sprintf (args, e->tocvsFilter, fileName, buf);
+ run_setup (args);
+ run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY );
+@@ -609,9 +632,8 @@
+
+ args = xmalloc (strlen (e->fromcvsFilter)
+ + strlen (fileName));
+- /* FIXME: sprintf will blow up if the format string contains items other
+- than %s, or contains too many %s's. We should instead be parsing
+- e->fromcvsFilter ourselves and giving a real error. */
++
++ wrap_clean_fmt_str(e->fromcvsFilter, 1);
+ sprintf (args, e->fromcvsFilter, fileName);
+ run_setup (args);
+ run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );