head 1.9; access; symbols OPENPKG_E1_MP_HEAD:1.8 OPENPKG_E1_MP:1.8 OPENPKG_E1_MP_2_STABLE:1.8 OPENPKG_E1_FP:1.8 OPENPKG_2_STABLE_MP:1.8 OPENPKG_2_STABLE_20061018:1.8 OPENPKG_2_STABLE_20060622:1.8 OPENPKG_2_STABLE:1.8.0.4 OPENPKG_2_STABLE_BP:1.8 OPENPKG_2_5_RELEASE:1.8 OPENPKG_2_5_SOLID:1.8.0.2 OPENPKG_2_5_SOLID_BP:1.8 OPENPKG_2_4_RELEASE:1.6 OPENPKG_2_4_SOLID:1.6.0.2 OPENPKG_2_4_SOLID_BP:1.6 OPENPKG_CW_FP:1.5 OPENPKG_2_3_RELEASE:1.5 OPENPKG_2_3_SOLID:1.5.0.6 OPENPKG_2_3_SOLID_BP:1.5 OPENPKG_2_2_RELEASE:1.5 OPENPKG_2_2_SOLID:1.5.0.4 OPENPKG_2_2_SOLID_BP:1.5 OPENPKG_2_1_RELEASE:1.5 OPENPKG_2_1_SOLID:1.5.0.2 OPENPKG_2_1_SOLID_BP:1.5 OPENPKG_2_0_RELEASE:1.4 OPENPKG_2_0_SOLID:1.4.0.2 OPENPKG_2_0_SOLID_BP:1.4 OPENPKG_1_3_RELEASE:1.3.2.1 OPENPKG_1_3_SOLID:1.3.2.1.0.2 OPENPKG_1_3_SOLID_BP:1.3.2.1 OPENPKG_1_STABLE_MP:1.4 OPENPKG_1_0_SOLID:1.3.0.6 OPENPKG_1_2_SOLID:1.3.0.4 OPENPKG_1_2_SOLID_BP:1.3 OPENPKG_1_STABLE:1.3.0.2 OPENPKG_1_STABLE_BP:1.3 OPENPKG_1_1_RELEASE:1.1 OPENPKG_1_1_SOLID:1.1.0.2 OPENPKG_1_1_SOLID_BP:1.1; locks; strict; comment @# @; 1.9 date 2007.11.06.20.16.59; author rse; state Exp; branches; next 1.8; commitid B2dcRsNAarmDpyEs; 1.8 date 2005.10.05.18.08.30; author rse; state Exp; branches; next 1.7; 1.7 date 2005.10.03.13.58.48; author rse; state Exp; branches; next 1.6; 1.6 date 2005.04.08.15.04.22; author rse; state Exp; branches; next 1.5; 1.5 date 2004.06.07.14.46.39; author rse; state Exp; branches; next 1.4; 1.4 date 2003.06.30.08.40.35; author thl; state Exp; branches 1.4.2.1; next 1.3; 1.3 date 2002.12.28.12.01.59; author rse; state dead; branches 1.3.2.1 1.3.4.1 1.3.6.1; next 1.2; 1.2 date 2002.12.11.11.09.16; author rse; state Exp; branches; next 1.1; 1.1 date 2002.08.22.13.47.00; author rse; state Exp; branches 1.1.2.1; next ; 1.4.2.1 date 2004.04.14.17.46.50; author rse; state Exp; branches; next 1.4.2.2; 1.4.2.2 date 2004.05.19.19.09.33; author rse; state Exp; branches; next 1.4.2.3; 1.4.2.3 date 2004.06.11.08.12.14; author thl; state Exp; branches; next ; 1.3.2.1 date 2003.07.24.20.41.53; author rse; state Exp; branches 1.3.2.1.2.1; next ; 1.3.2.1.2.1 date 2003.12.12.16.39.13; author ms; state Exp; branches; next 1.3.2.1.2.2; 1.3.2.1.2.2 date 2004.01.07.12.49.11; author thl; state Exp; branches; next 1.3.2.1.2.3; 1.3.2.1.2.3 date 2004.01.08.12.14.31; author thl; state Exp; branches; next 1.3.2.1.2.4; 1.3.2.1.2.4 date 2004.04.14.18.10.01; author rse; state Exp; branches; next 1.3.2.1.2.5; 1.3.2.1.2.5 date 2004.05.19.19.14.15; author rse; state Exp; branches; next 1.3.2.1.2.6; 1.3.2.1.2.6 date 2004.06.11.08.12.30; author thl; state Exp; branches; next ; 1.3.4.1 date 2004.01.08.13.21.48; author thl; state Exp; branches; next ; 1.3.6.1 date 2003.01.21.15.20.53; author thl; state Exp; branches; next ; 1.1.2.1 date 2003.01.21.15.20.31; author thl; state Exp; branches; next ; desc @@ 1.9 log @apply a Debian bugfix for the CVS 1.11.x client hang problem @ text @--- src/main.c.orig Tue May 20 00:52:58 2003 +++ src/main.c Thu Jun 26 15:42:16 2003 @@@@ -16,6 +16,10 @@@@ #include "setenv.h" #include "strftime.h" #include "xgethostname.h" +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) +#include +#include +#endif const char *program_name; const char *program_path; @@@@ -557,6 +561,11 @@@@ /* `getopt_long' stores the option index here, but right now we don't use it. */ int option_index = 0; + +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) + /* OSSP fsl identification */ + openlog("cvs", 0, LOG_DAEMON); +#endif #ifdef SYSTEM_INITIALIZE /* Hook for OS-specific behavior, for example socket subsystems on ----------------------------------------------------------------------------- Fix "read hang" problem for CVS 1.11.x clients: http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/~checkout~/SOURCES/cvs-debian-zlib-read-compressed.patch?rev=1.1;content-type=text%2Fplain http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=368494 Index: src/zlib.c --- src/zlib.c.orig 3 Jun 2005 18:26:09 -0000 1.31 +++ src/zlib.c 27 Oct 2005 17:59:49 -0000 @@@@ -229,7 +229,7 @@@@ compress_buffer_input (void *closure, ch would fetch all the available bytes, and at least one byte. */ status = (*cb->buf->input) (cb->buf->closure, bd->text, - need, BUFFER_DATA_SIZE, &nread); + need ? 1 : 0, BUFFER_DATA_SIZE, &nread); if (status == -2) /* Don't try to recover from memory allcoation errors. */ @ 1.8 log @upgrading package: cvs 1.12.12 -> 1.12.13 @ text @d26 19 @ 1.7 log @upgrading package: cvs 1.12.11 -> 1.12.12 @ text @d4 2 a6 2 #include "strftime.h" #include "closeout.h" @ 1.6 log @upgrading package: cvs 1.12.9 -> 1.12.11 @ text @a3 1 #include "cvs.h" d6 1 @ 1.5 log @repair syntax @ text @d3 1 a3 3 @@@@ -14,6 +14,10 @@@@ #include d5 2 d12 3 a14 3 #ifdef HAVE_WINSOCK_H #include @@@@ -424,6 +428,11 @@@@ @ 1.4 log @add fsl support @ text @d7 1 a7 1 +#ifdef SERVER_SUPPORT && HAVE_SYSLOG_H d19 2 a20 2 +#ifdef SERVER_SUPPORT && HAVE_SYSLOG_H + /* fsl identification */ @ 1.4.2.1 log @fix security bugs (OpenPKG-SA-2004.013-cvs, CAN-2004-0180) @ text @a25 47 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.013-cvs, CAN-2004-0180) Index: src/client.c --- src/client.c.orig 2003-11-25 21:51:59.000000000 +0100 +++ src/client.c 2004-04-14 19:22:49.000000000 +0200 @@@@ -602,6 +602,19 @@@@ char *rdirp; int reposdirname_absolute; + /* For security reasons, if PATHNAME is absolute or attemps to ascend + * outside of the current sanbbox, we abort. The server should not send us + * anything but relative paths which remain inside the sandbox here. + * Anything less means a trojan CVS server could create and edit arbitrary + * files on the client. + */ + if (isabsolute (pathname) || pathname_levels (pathname) > 0) + { + error (0, 0, + "Server attempted to update a file via an invalid pathname:"); + error (1, 0, "`%s'.", pathname); + } + reposname = NULL; read_line (&reposname); assert (reposname != NULL); Index: src/modules.c --- src/modules.c.orig 2003-11-25 17:11:48.000000000 +0100 +++ src/modules.c 2004-04-14 19:22:53.000000000 +0200 @@@@ -142,6 +142,14 @@@@ if (isabsolute (mname)) error (1, 0, "Absolute module reference invalid: `%s'", mname); + /* Similarly for directories that attempt to step above the root of the + * repository. + */ + if (pathname_levels (mname) > 0) + error (1, 0, "up-level in module reference (`..') invalid: `%s'.", + mname); + + /* if this is a directory to ignore, add it to that list */ if (mname[0] == '!' && mname[1] != '\0') { @ 1.4.2.2 log @apply security bugfix (OpenPKG-SA-2004.022-cvs, CAN-2004-0396) @ text @a72 27 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.022-cvs, CAN-2004-0396) Index: src/server.c --- src/server.c.orig 2004-05-19 21:05:23.000000000 +0200 +++ src/server.c 2004-05-19 21:05:34.000000000 +0200 @@@@ -1618,7 +1618,7 @@@@ && strncmp (arg, name, cp - name) == 0) { timefield = strchr (cp + 1, '/') + 1; - if (*timefield != '=') + if (*timefield == '/') { cp = timefield + strlen (timefield); cp[1] = '\0'; @@@@ -1661,7 +1661,7 @@@@ && strncmp (arg, name, cp - name) == 0) { timefield = strchr (cp + 1, '/') + 1; - if (!(timefield[0] == 'M' && timefield[1] == '/')) + if (*timefield == '/') { cp = timefield + strlen (timefield); cp[1] = '\0'; @ 1.4.2.3 log @OpenPKG-SA-2004.027-cvs, CAN-2004-0414, CAN-2004-0416, CAN-2004-0417, CAN-2004-0418; MFC: repair syntax; MFC: TIOCNOTTY portability @ text @d7 1 a7 1 +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) d19 1 a19 1 +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) a99 657 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.027-cvs, CAN-2004-0414, CAN-2004-0416, CAN-2004-0417, CAN-2004-0418) Index: src/commit.c --- src/commit.c.orig 2004-05-11 20:22:29 +0200 +++ src/commit.c 2004-06-09 16:52:37 +0200 @@@@ -485,7 +485,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); Index: src/filesubr.c --- src/filesubr.c.orig 2004-04-27 22:35:32 +0200 +++ src/filesubr.c 2004-06-09 16:52:38 +0200 @@@@ -930,8 +930,14 @@@@ expand_wild (int argc, char **argv, int *pargc, 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]); } Index: src/history.c --- src/history.c.orig 2004-05-16 02:39:26 +0200 +++ src/history.c 2004-06-09 16:52:38 +0200 @@@@ -412,8 +412,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) { @@@@ -898,9 +901,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); } @@@@ -925,9 +932,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); @@@@ -965,9 +976,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); } Index: src/server.c --- src/server.c.orig 2004-05-18 16:21:53 +0200 +++ src/server.c 2004-06-09 16:52:39 +0200 @@@@ -886,7 +886,7 @@@@ int i; char *p; - if (lim < 0) + if (lim < 0 || lim > 10000) return; p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10); if (p == NULL) @@@@ -1582,8 +1582,7 @@@@ char *cp; char *timefield; - if (error_pending ()) - return; + if (error_pending ()) return; if (outside_dir (arg)) return; @@@@ -1597,9 +1596,28 @@@@ && strlen (arg) == cp - name && strncmp (arg, name, cp - name) == 0) { - timefield = strchr (cp + 1, '/') + 1; + if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') + { + /* We didn't find the record separator or it is followed by + * the end of the string, so just exit. + */ + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Malformed Entry encountered."); + return; + } + /* If the time field is not currently empty, then one of + * serve_modified, serve_is_modified, & serve_unchanged were + * already called for this file. We would like to ignore the + * reinvocation silently or, better yet, exit with an error + * message, but we just avoid the copy-forward and overwrite the + * value from the last invocation instead. See the comment below + * for more. + */ if (*timefield == '/') { + /* Copy forward one character. Space was allocated for this + * already in serve_entry(). */ cp = timefield + strlen (timefield); cp[1] = '\0'; while (cp > timefield) @@@@ -1607,13 +1625,46 @@@@ *cp = cp[-1]; --cp; } - *timefield = '='; } + else if (timefield[1] != '/') + { + /* Obliterate anything else in TIMEFIELD. This is again to + * support the broken CVSNT clients mentioned below, in + * conjunction with strict timestamp string boundry checking in + * time_stamp_server() from vers_ts.c & file_has_conflict() + * from subr.c, since the broken clients used to send malformed + * timestamp fields in the Entry request that they then + * depended on the subsequent Unchanged request to overwrite. + */ + char *d = timefield + 1; + if (cp = strchr (d, '/')) + { + while (*cp) + { + *d++ = *cp++; + } + *d = '\0'; + } + } + /* If *TIMEFIELD wasn't '/', we assume that it was because of + * multiple calls to Is-modified & Unchanged by the client and + * just overwrite the value from the last call. Technically, we + * should probably either ignore calls after the first or send the + * client an error, since the client/server protocol specification + * specifies that only one call to either Is-Modified or Unchanged + * is allowed, but broken versions of CVSNT (at least 2.0.34 - + * 2.0.41, reported fixed in 2.0.41a) and the WinCVS & TortoiseCVS + * clients which depend on those broken versions of CVSNT (WinCVS + * 1.3 & at least one TortoiseCVS release) rely on this behavior. + */ + *timefield = '='; break; } } } + + static void serve_is_modified (char *arg) { @@@@ -1624,8 +1675,7 @@@@ /* Have we found this file in "entries" yet. */ int found; - if (error_pending ()) - return; + if (error_pending ()) return; if (outside_dir (arg)) return; @@@@ -1640,9 +1690,28 @@@@ && strlen (arg) == cp - name && strncmp (arg, name, cp - name) == 0) { - timefield = strchr (cp + 1, '/') + 1; + if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') + { + /* We didn't find the record separator or it is followed by + * the end of the string, so just exit. + */ + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Malformed Entry encountered."); + return; + } + /* If the time field is not currently empty, then one of + * serve_modified, serve_is_modified, & serve_unchanged were + * already called for this file. We would like to ignore the + * reinvocation silently or, better yet, exit with an error + * message, but we just avoid the copy-forward and overwrite the + * value from the last invocation instead. See the comment below + * for more. + */ if (*timefield == '/') { + /* Copy forward one character. Space was allocated for this + * already in serve_entry(). */ cp = timefield + strlen (timefield); cp[1] = '\0'; while (cp > timefield) @@@@ -1650,8 +1719,19 @@@@ *cp = cp[-1]; --cp; } - *timefield = 'M'; } + /* If *TIMEFIELD wasn't '/', we assume that it was because of + * multiple calls to Is-modified & Unchanged by the client and + * just overwrite the value from the last call. Technically, we + * should probably either ignore calls after the first or send the + * client an error, since the client/server protocol specification + * specifies that only one call to either Is-Modified or Unchanged + * is allowed, but broken versions of CVSNT (at least 2.0.34 - + * 2.0.41, reported fixed in 2.0.41a) and the WinCVS & TortoiseCVS + * clients which depend on those broken versions of CVSNT (WinCVS + * 1.3 & at least one TortoiseCVS release) rely on this behavior. + */ + *timefield++ = 'M'; if (kopt != NULL) { if (alloc_pending (strlen (name) + 80)) @@@@ -1670,7 +1750,7 @@@@ { /* We got Is-modified but no Entry. Add a dummy entry. The "D" timestamp is what makes it a dummy. */ - p = (struct an_entry *) xmalloc (sizeof (struct an_entry)); + p = xmalloc (sizeof (struct an_entry)); if (p == NULL) { pending_error = ENOMEM; @@@@ -1781,8 +1797,29 @@@@ { struct an_entry *p; char *cp; + int i = 0; if (error_pending()) return; - p = (struct an_entry *) xmalloc (sizeof (struct an_entry)); + + /* Verify that the entry is well-formed. This can avoid problems later. + * At the moment we only check that the Entry contains five slashes in + * approximately the correct locations since some of the code makes + * assumptions about this. + */ + cp = arg; + if (*cp == 'D') cp++; + while (i++ < 5) + { + if (!cp || *cp != '/') + { + if (alloc_pending (80)) + sprintf (pending_error_text, + "E protocol error: Malformed Entry"); + return; + } + cp = strchr (cp + 1, '/'); + } + + p = xmalloc (sizeof (struct an_entry)); if (p == NULL) { pending_error = ENOMEM; @@@@ -2011,6 +2048,9 @@@@ { char *cp; + if (!data[0]) + goto error; + if (strchr (data, '+')) goto error; @@@@ -2143,6 +2183,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) { @@@@ -2172,6 +2220,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 = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1); @@@@ -2498,7 +2554,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) @@@@ -2553,7 +2609,7 @@@@ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0) { /* 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) @@@@ -6661,10 +6717,30 @@@@ buf_send_counted (protocol); } else -#endif +#endif /* SERVER_SUPPORT */ { + /* No MT support or we are using a local repository. */ if (strcmp (tag, "newline") == 0) cvs_output ("\n", 1); + else if (strcmp (tag, "date") == 0) + { +#ifdef SERVER_SUPPORT + if (server_active) + /* Output UTC when running as a server without MT support in + * the client since it is likely to be more meaningful than + * localtime. + */ + cvs_output (text, 0); + else +#endif /* SERVER_SUPPORT */ + { + char *date_in = xstrdup (text); + char *date = format_date_alloc (date_in); + cvs_output (date, 0); + free (date); + free (date_in); + } + } else if (text != NULL) cvs_output (text, 0); } Index: src/wrapper.c --- src/wrapper.c.orig 2004-02-18 05:46:08 +0100 +++ src/wrapper.c 2004-06-09 16:52:39 +0200 @@@@ -235,6 +235,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. @@@@ -540,9 +564,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 ); @@@@ -572,9 +595,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 ); Index: src/cvs.h --- src/cvs.h.orig 2003-12-08 20:43:00 +0100 +++ src/cvs.h 2004-06-10 19:51:52 +0200 @@@@ -40,6 +40,10 @@@@ #endif /* __attribute__ */ #include "exit.h" +#include "xsize.h" +#include "xtime.h" +static char *format_time_t (time_t unixtime); +char *format_date_alloc (char *text); #if ! STDC_HEADERS char *getenv(); Index: main.c --- src/main.c.orig 2004-06-10 20:06:09 +0200 +++ src/main.c 2004-06-10 20:08:36 +0200 @@@@ -1186,6 +1186,79 @@@@ source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); } +/* Format a date in the local timezone using format_time_t() given a date from + * an arbitrary timezone in a string. + * + * INPUT + * DATESTR A string that looks like anything get_date() can parse, e.g.: + * + * 2004-04-29 20:24:22 + * + * ERRORS + * As get_date() & format_time_t(). Prints a warning if either provide + * error return values. See RETURNS. + * + * RETURNS + * A freshly allocated string that is a copy of the input string if either + * get_date() or format_time_t() encounter an error and as format_time_t() + * otherwise. + */ +char * +format_date_alloc (char *datestr) +{ + time_t unixtime; + char *buf; + + TRACE (TRACE_FUNCTION, "format_date (%s)", datestr); + + /* Convert the date string to seconds since the epoch. */ + unixtime = get_date (datestr, NULL); + if (unixtime == (time_t)-1) + { + error (0, 0, "Can't parse date/time: `%s'.", datestr); + goto as_is; + } + + /* Get the time into a string. */ + if ((buf = format_time_t (unixtime)) == NULL) + { + error (0, 0, "Unable to reformat date `%s'.", datestr); + goto as_is; + } + + return buf; + + as_is: + return xstrdup (datestr); +} + +/* + * Format a date for the current locale. + * + * INPUT + * UNIXTIME The UNIX seconds since the epoch. + * + * RETURNS + * If my_strftime() encounters an error, this function can return NULL. + * + * Otherwise, returns a date string in ISO8601 format, e.g.: + * + * 2004-04-29 13:24:22 -0700 + * + * It is the responsibility of the caller to return of this string. + */ +static char * +format_time_t (time_t unixtime) +{ + static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")]; + /* Convert to a time in the local time zone. */ + struct tm ltm = *(gmtime (&unixtime)); + + if (strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", <m) == 0) + return NULL; + + return xstrdup (buf); +} void usage (register const char *const *cpp) { Index: xsize.h --- /dev/null 2004-06-10 20:01:31 +0200 +++ src/xsize.h 2004-06-10 20:02:42 +0200 @@@@ -0,0 +1,37 @@@@ +/* excerpt from cvs-1.12.9 */ + +#ifndef _XSIZE_H +#define _XSIZE_H + +/* Get size_t. */ +#include + +/* Get SIZE_MAX. */ +#include +#if HAVE_STDINT_H +# include +#endif +#ifndef SIZE_MAX +#define SIZE_MAX (4294967295U) +#endif + +/* 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); +} + +/* Multiplication of a count with an element size, with overflow check. */ +#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) + +#endif /* _XSIZE_H */ Index: lib/xtime.h --- /dev/null 2004-06-10 20:31:48 +0200 +++ src/xtime.h 2004-05-16 01:09:13 +0200 @@@@ -0,0 +1,57 @@@@ +/* 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. */ + +/* This file simply performs the include magic necessary for using time + * functions + */ + +#ifdef vms +# include +#else /* vms */ + +# if TIME_WITH_SYS_TIME +# include +# include +# else /* TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include +# else /* HAVE_SYS_TIME_H */ +# include +# endif /* !HAVE_SYS_TIME_H */ +# endif /* !TIME_WITH_SYS_TIME */ + +# ifdef HAVE_SYS_TIMEB_H +# include +# else /* HAVE_SYS_TIMEB_H */ +/* + * We use the obsolete `struct timeb' as part of our interface! + * Since the system doesn't have it, we define it here; + * our callers must do likewise. + * + * At the least we were using this in lib/getdate.y, but lib/system.h used to + * define it too, so maybe CVS is using it elsewhere. + */ +struct timeb { + time_t time; /* Seconds since the epoch */ + unsigned short millitm; /* Field not used */ + short timezone; /* Minutes west of GMT */ + short dstflag; /* Field not used */ +}; +# endif /* !HAVE_SYS_TIMEB_H */ + +# ifdef timezone +# undef timezone /* needed for sgi */ +# endif /* timezone */ + +# if !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) +extern long timezone; +# endif /* !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) */ + +#endif /* !vms */ @ 1.3 log @upgrade to CVS 1.11.3; upgrade RSE patches for 1.11.3 @ text @d1 17 a17 11 Index: src/server.c =================================================================== RCS file: /cvs/ccvs/src/server.c,v diff -u -d -r1.275 -r1.277 --- src/server.c 18 Jun 2002 13:35:28 -0000 1.275 +++ src/server.c 14 Aug 2002 13:21:55 -0000 1.277 @@@@ -5010,6 +5010,8 @@@@ int argc; char **argv; { + char *error_prog_name; /* Used in error messages */ d19 4 a22 44 if (argc == -1) { static const char *const msg[] = @@@@ -5165,39 +5167,18 @@@@ /* Small for testing. */ argument_vector_size = 1; argument_vector = - (char **) malloc (argument_vector_size * sizeof (char *)); - if (argument_vector == NULL) - { - /* - * Strictly speaking, we're not supposed to output anything - * now. But we're about to exit(), give it a try. - */ - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - - /* I'm doing this manually rather than via error_exit () - because I'm not sure whether we want to call server_cleanup. - Needs more investigation.... */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - exit (EXIT_FAILURE); - } - + (char **) xmalloc (argument_vector_size * sizeof (char *)); argument_count = 1; /* This gets printed if the client supports an option which the server doesn't, causing the server to print a usage message. - FIXME: probably should be using program_name here. FIXME: just a nit, I suppose, but the usage message the server prints isn't literally true--it suggests "cvs server" followed by options which are for a particular command. Might be nice to say something like "client apparently supports an option not supported by this server" or something like that instead of usage message. */ - argument_vector[0] = "cvs server"; + error_prog_name = xmalloc( strlen(program_name) + 8 ); + sprintf(error_prog_name, "%s server", program_name); + argument_vector[0] = error_prog_name; d24 2 a25 266 while (1) { @@@@ -5270,6 +5251,7 @@@@ } free (orig_cmd); } + free(error_prog_name); server_cleanup (0); return 0; } @@@@ -5419,8 +5401,8 @@@@ int found_it = 0; int namelen; - /* We don't use current_parsed_root->directory because it hasn't been set yet - * -- our `repository' argument came from the authentication + /* We don't use current_parsed_root->directory because it hasn't been + * set yet -- our `repository' argument came from the authentication * protocol, not the regular CVS protocol. */ @@@@ -5578,7 +5560,7 @@@@ { /* No cvs password found, so try /etc/passwd. */ - const char *found_passwd = NULL; + char *found_passwd = NULL; struct passwd *pw; #ifdef HAVE_GETSPNAM struct spwd *spw; Index: src/server.c =================================================================== RCS file: /cvs/ccvs/src/server.c,v diff -u -d -r1.279 -r1.280 --- src/server.c 16 Sep 2002 14:56:25 -0000 1.279 +++ src/server.c 4 Oct 2002 19:56:01 -0000 1.280 @@@@ -3213,10 +3213,13 @@@@ buf_flush (buf_to_net, 1); buf_shutdown (protocol_inbuf); buf_free (protocol_inbuf); + protocol_inbuf = NULL; buf_shutdown (stderrbuf); buf_free (stderrbuf); + stderrbuf = NULL; buf_shutdown (stdoutbuf); buf_free (stdoutbuf); + stdoutbuf = NULL; } if (errs) @@@@ -4891,9 +4894,9 @@@@ status = buf_shutdown (buf_from_net); if (status != 0) - { error (0, status, "shutting down buffer from client"); - } + buf_free (buf_from_net); + buf_from_net = NULL; } if (dont_delete_temp) @@@@ -4902,6 +4905,9 @@@@ { (void) buf_flush (buf_to_net, 1); (void) buf_shutdown (buf_to_net); + buf_free (buf_to_net); + buf_to_net = NULL; + error_use_protocol = 0; } return; } @@@@ -5003,6 +5009,9 @@@@ { (void) buf_flush (buf_to_net, 1); (void) buf_shutdown (buf_to_net); + buf_free (buf_to_net); + buf_to_net = NULL; + error_use_protocol = 0; } } @@@@ -5146,25 +5155,6 @@@@ } } -#ifdef SIGABRT - (void) SIG_register (SIGABRT, server_cleanup); -#endif -#ifdef SIGHUP - (void) SIG_register (SIGHUP, server_cleanup); -#endif -#ifdef SIGINT - (void) SIG_register (SIGINT, server_cleanup); -#endif -#ifdef SIGQUIT - (void) SIG_register (SIGQUIT, server_cleanup); -#endif -#ifdef SIGPIPE - (void) SIG_register (SIGPIPE, server_cleanup); -#endif -#ifdef SIGTERM - (void) SIG_register (SIGTERM, server_cleanup); -#endif - /* Now initialize our argument vector (for arguments from the client). */ /* Small for testing. */ @@@@ -6352,12 +6342,12 @@@@ if (len == 0) len = strlen (str); #ifdef SERVER_SUPPORT - if (error_use_protocol) + if (error_use_protocol && buf_to_net != NULL) { buf_output (saved_output, str, len); buf_copy_lines (buf_to_net, saved_output, 'M'); } - else if (server_active) + else if (server_active && protocol != NULL) { buf_output (saved_output, str, len); buf_copy_lines (protocol, saved_output, 'M'); Index: src/server.c =================================================================== RCS file: /cvs/ccvs/src/server.c,v diff -u -d -r1.280 -r1.281 --- src/server.c 4 Oct 2002 19:56:01 -0000 1.280 +++ src/server.c 25 Oct 2002 19:35:07 -0000 1.281 @@@@ -710,17 +710,7 @@@@ cause deadlock, as noted in server_cleanup. */ buf_flush (buf_to_net, 1); - /* I'm doing this manually rather than via error_exit () - because I'm not sure whether we want to call server_cleanup. - Needs more investigation.... */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - exit (EXIT_FAILURE); + error_exit (); } else if (rs->status == rs_optional) rs->status = rs_not_supported; @@@@ -5080,18 +5070,7 @@@@ printf ("E Fatal server error, aborting.\n\ error ENOMEM Virtual memory exhausted.\n"); - /* I'm doing this manually rather than via error_exit () - because I'm not sure whether we want to call server_cleanup. - Needs more investigation.... */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket - subsystems on NT and OS2 or dealing with windows - and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - exit (EXIT_FAILURE); + error_exit (); } strcpy (server_temp_dir, Tmpdir); @@@@ -5575,17 +5554,7 @@@@ printf ("E Fatal error, aborting.\n\ error 0 %s: no such user\n", username); - /* I'm doing this manually rather than via error_exit () - because I'm not sure whether we want to call server_cleanup. - Needs more investigation.... */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - exit (EXIT_FAILURE); + error_exit (); } /* Allow for dain bramaged HPUX passwd aging @@@@ -5635,16 +5604,7 @@@@ outweighs this. */ printf ("error 0 no such user %s in CVSROOT/passwd\n", username); - /* I'm doing this manually rather than via error_exit () - because I'm not sure whether we want to call server_cleanup. - Needs more investigation.... */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (EXIT_FAILURE); + error_exit (); } else { @@@@ -5901,12 +5861,8 @@@@ { printf ("E Fatal error, aborting.\n\ error %s getpeername or getsockname failed\n", strerror (errno)); -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (EXIT_FAILURE); + + error_exit (); } #ifdef SO_KEEPALIVE @@@@ -5932,12 +5888,8 @@@@ { printf ("E Fatal error, aborting.\n\ error 0 kerberos: %s\n", krb_get_err_text(status)); -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (EXIT_FAILURE); + + error_exit (); } memcpy (kblock, auth.session, sizeof (C_Block)); @@@@ -5948,12 +5900,8 @@@@ { printf ("E Fatal error, aborting.\n\ error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status)); -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (EXIT_FAILURE); + + error_exit (); } /* Switch to run as this user. */ Index: src/buffer.c =================================================================== RCS file: /cvs/ccvs/src/buffer.c,v diff -u -d -r1.19 -r1.20 --- src/buffer.c 20 May 2002 18:27:55 -0000 1.19 +++ src/buffer.c 24 Oct 2002 19:54:58 -0000 1.20 @@@@ -1392,8 +1392,7 @@@@ if (buf->input) { - if (! buf_empty_p (buf) - || getc (bc->fp) != EOF) + if ( !buf_empty_p (buf) ) { # ifdef SERVER_SUPPORT if (server_active) @ 1.3.4.1 log @relocate previous patch to standard patch file; Extracted bugfixes and security enhancement from Stable CVS 1.11.11 @ text @d1 11 a11 17 diff -Naur cvs-1.11.5.orig/cvs-1.11.5/src/modules.c cvs-1.11.5/cvs-1.11.5/src/modules.c --- src/modules.c.orig Thu Jun 21 23:23:09 2001 +++ src/modules.c Fri Dec 12 17:44:14 2003 @@@@ -159,6 +159,17 @@@@ } #endif + /* Don't process absolute directories. Anything else could be a security + * problem. Before this check was put in place: + * + * $ cvs -d:fork:/cvsroot co /foo + * cvs server: warning: cannot make directory CVS in /: Permission denied + * cvs [server aborted]: cannot make directory /foo: Permission denied + * $ + */ + if (isabsolute (mname)) + error (1, 0, "Absolute module reference invalid: `%s'", mname); d13 1 a13 2 /* if this is a directory to ignore, add it to that list */ if (mname[0] == '!' && mname[1] != '\0') d15 65 a79 13 + /* Don't process absolute directories. Anything else could be a security + * problem. Before this check was put in place: + * + * $ cvs -d:fork:/cvsroot co /foo + * cvs server: warning: cannot make directory CVS in /: Permission denied + * cvs [server aborted]: cannot make directory /foo: Permission denied + * $ + */ + if (isabsolute (mname)) + error (1, 0, "Absolute module reference invalid: `%s'", mname); + /* if this is a directory to ignore, add it to that list */ if (mname[0] == '!' && mname[1] != '\0') d81 8 a88 31 Extracted bugfixes and security enhancement from Stable CVS 1.11.11. 2003-12-18 19:11 dprice * src/: ChangeLog, server.c: * server.c (switch_to_user): SysLog attempts to root from pserver. 2003-12-18 18:38 dprice * src/: ChangeLog, sanity.sh, server.c: * server.c (switch_to_user): Don't allow CVS to run as root in pserver mode. (Original patch from Wichert Akkerman via Bradley M Kuhn .) * sanity.sh (pserver): Check for bad root error message. 2003-12-18 04:00 scjones * src/: ChangeLog, run.c: * run.c (close_on_exec): fcntl is not documented to return 0 for success (and QNX doesn't), only -1 for error. 2003-12-10 10:36 mdb * src/: ChangeLog, server.c: * server.c (template_proc): Fix broken Template protocol code. Must call send buf_send_counted() for Template files to avoid "Protocol error: uncounted data discarded" messages in some circumstances. (Problem reported by "Jim.Hyslop" .) Index: src/run.c d90 48 a137 14 RCS file: /cvs/ccvs/src/run.c,v retrieving revision 1.33 retrieving revision 1.33.6.1 diff -u -d -u -d -r1.33 -r1.33.6.1 --- src/run.c 24 Jan 2001 03:35:10 -0000 1.33 +++ src/run.c 18 Dec 2003 03:00:44 -0000 1.33.6.1 @@@@ -455,7 +455,7 @@@@ int fd; { #ifdef F_SETFD - if (fcntl (fd, F_SETFD, 1)) + if (fcntl (fd, F_SETFD, 1) == -1) error (1, errno, "can't set close-on-exec flag on %d", fd); #endif d139 42 d184 19 a202 7 retrieving revision 1.284.2.9 retrieving revision 1.284.2.12 diff -u -d -u -d -r1.284.2.9 -r1.284.2.12 --- src/server.c 3 Oct 2003 19:15:32 -0000 1.284.2.9 +++ src/server.c 18 Dec 2003 18:03:13 -0000 1.284.2.12 @@@@ -4404,6 +4404,7 @@@@ return 1; d204 86 a290 5 + buf_send_counted (protocol); if (fclose (fp) < 0) error (0, errno, "cannot close rcsinfo template file %s", template); return 0; @@@@ -5118,10 +5119,11 @@@@ d292 11 a302 29 #if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) -static void switch_to_user PROTO((const char *)); +static void switch_to_user PROTO((const char *, const char *)); static void -switch_to_user (username) +switch_to_user (cvs_username, username) + const char *cvs_username; /* Only used for error messages. */ const char *username; { struct passwd *pw; @@@@ -5138,6 +5140,20 @@@@ error_exit (); } + if (pw->pw_uid == 0) + { +#ifdef HAVE_SYSLOG_H + /* FIXME: Can the IP address of the connecting client be retrieved + * and printed here? + */ + syslog (LOG_DAEMON | LOG_ALERT, + "attempt to root from account: %s", cvs_username + ); +#endif + printf("error 0: root not allowed\n"); + error_exit (); + } d304 2 a305 5 #if HAVE_INITGROUPS if (initgroups (pw->pw_name, pw->pw_gid) < 0 # ifdef EPERM @@@@ -5735,7 +5751,7 @@@@ strcpy (Pserver_Repos, repository); d308 7 a314 8 - switch_to_user (host_user); + switch_to_user (username, host_user); free (host_user); free (tmp); free (repository); @@@@ -5928,7 +5944,7 @@@@ error (1, errno, "fwrite failed"); } d316 8 a323 6 - switch_to_user (buf); + switch_to_user ("GSSAPI", buf); printf ("I LOVE YOU\n"); fflush (stdout); @ 1.3.2.1 log @mass Merge-From-CURRENT (MFC) in preparation for OpenPKG 1.3 [class CORE only] @ text @d1 11 a11 17 --- src/main.c.orig Tue May 20 00:52:58 2003 +++ src/main.c Thu Jun 26 15:42:16 2003 @@@@ -14,6 +14,10 @@@@ #include #include "cvs.h" +#ifdef SERVER_SUPPORT && HAVE_SYSLOG_H +#include +#include +#endif #ifdef HAVE_WINSOCK_H #include @@@@ -424,6 +428,11 @@@@ /* `getopt_long' stores the option index here, but right now we don't use it. */ int option_index = 0; d13 44 a56 4 +#ifdef SERVER_SUPPORT && HAVE_SYSLOG_H + /* fsl identification */ + openlog("cvs", 0, LOG_DAEMON); +#endif d58 266 a323 2 #ifdef SYSTEM_INITIALIZE /* Hook for OS-specific behavior, for example socket subsystems on @ 1.3.2.1.2.1 log @backport fix for filesystem violation, OpenPKG-SA-2003.052 @ text @a25 20 --- src/modules.c.orig Fri Dec 12 15:47:47 2003 +++ src/modules.c Fri Dec 12 15:49:50 2003 @@@@ -157,6 +157,17 @@@@ } #endif + /* Don't process absolute directories. Anything else could be a security + * problem. Before this check was put in place: + * + * $ cvs -d:fork:/cvsroot co /foo + * cvs server: warning: cannot make directory CVS in /: Permission denied + * cvs [server aborted]: cannot make directory /foo: Permission denied + * $ + */ + if (isabsolute (mname)) + error (1, 0, "Absolute module reference invalid: `%s'", mname); + /* if this is a directory to ignore, add it to that list */ if (mname[0] == '!' && mname[1] != '\0') { @ 1.3.2.1.2.2 log @Extracted security enhancement backported from Stable CVS 1.12.5 @ text @a45 91 Extracted security enhancement backported from Stable CVS 1.12.5 2003-12-18 19:11 dprice * src/: ChangeLog, server.c: * server.c (switch_to_user): SysLog attempts to root from pserver. 2003-12-18 18:38 dprice * src/: ChangeLog, sanity.sh, server.c: * server.c (switch_to_user): Don't allow CVS to run as root in pserver mode. (Original patch from Wichert Akkerman via Bradley M Kuhn .) * sanity.sh (pserver): Check for bad root error message. Index: src/server.c --- src/server.c.orig 2004-01-07 12:37:41.000000000 +0100 +++ src/server.c 2004-01-07 12:48:37.000000000 +0100 @@@@ -5178,10 +5178,11 @@@@ #if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) -static void switch_to_user PROTO((const char *)); +static void switch_to_user PROTO((const char *cvs_username, const char *username)); static void -switch_to_user (username) +switch_to_user (cvs_username, username) + const char *cvs_username; const char *username; { struct passwd *pw; @@@@ -5198,6 +5199,20 @@@@ error_exit (); } + if (pw->pw_uid == 0) + { +#ifdef HAVE_SYSLOG_H + /* FIXME: Can the IP address of the connecting client be retrieved + * and printed here? + */ + syslog (LOG_DAEMON | LOG_ALERT, + "attempt to root from account: %s", cvs_username + ); +#endif + printf("error 0: root not allowed\n"); + exit (EXIT_FAILURE); + } + #if HAVE_INITGROUPS if (initgroups (pw->pw_name, pw->pw_gid) < 0 # ifdef EPERM @@@@ -5798,7 +5813,7 @@@@ strcpy (Pserver_Repos, repository); /* Switch to run as this user. */ - switch_to_user (host_user); + switch_to_user (username, host_user); free (host_user); free (tmp); free (repository); @@@@ -5879,7 +5894,7 @@@@ } /* Switch to run as this user. */ - switch_to_user (user); + switch_to_user ("KERBEROS", user); } #endif /* HAVE_KERBEROS */ @@@@ -5991,7 +6006,7 @@@@ error (1, errno, "fwrite failed"); } - switch_to_user (buf); + switch_to_user ("GSSAPI", buf); printf ("I LOVE YOU\n"); fflush (stdout); @@@@ -6922,7 +6937,7 @@@@ } /* Switch to run as this user. */ - switch_to_user(host_user); + switch_to_user(username, host_user); free(tmp); free(repository); free(username); @ 1.3.2.1.2.3 log @fix building without rse patch @ text @d127 9 @ 1.3.2.1.2.4 log @apply security bugfixes (OpenPKG-SA-2004.013-cvs, CAN-2004-0180) @ text @d26 20 a45 2 ============================================================================= a126 47 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.013-cvs, CAN-2004-0180) Index: src/client.c --- src/client.c.orig 2003-11-25 21:51:59.000000000 +0100 +++ src/client.c 2004-04-14 19:22:49.000000000 +0200 @@@@ -602,6 +602,19 @@@@ char *rdirp; int reposdirname_absolute; + /* For security reasons, if PATHNAME is absolute or attemps to ascend + * outside of the current sanbbox, we abort. The server should not send us + * anything but relative paths which remain inside the sandbox here. + * Anything less means a trojan CVS server could create and edit arbitrary + * files on the client. + */ + if (isabsolute (pathname) || pathname_levels (pathname) > 0) + { + error (0, 0, + "Server attempted to update a file via an invalid pathname:"); + error (1, 0, "`%s'.", pathname); + } + reposname = NULL; read_line (&reposname); assert (reposname != NULL); Index: src/modules.c --- src/modules.c.orig 2003-11-25 17:11:48.000000000 +0100 +++ src/modules.c 2004-04-14 19:22:53.000000000 +0200 @@@@ -142,6 +142,14 @@@@ if (isabsolute (mname)) error (1, 0, "Absolute module reference invalid: `%s'", mname); + /* Similarly for directories that attempt to step above the root of the + * repository. + */ + if (pathname_levels (mname) > 0) + error (1, 0, "up-level in module reference (`..') invalid: `%s'.", + mname); + + /* if this is a directory to ignore, add it to that list */ if (mname[0] == '!' && mname[1] != '\0') { @ 1.3.2.1.2.5 log @apply security bugfix (OpenPKG-SA-2004.022-cvs, CAN-2004-0396) @ text @a156 26 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.022-cvs, CAN-2004-0396) Index: src/server.c --- src/server.c.orig 2004-05-19 21:05:23.000000000 +0200 +++ src/server.c 2004-05-19 21:05:34.000000000 +0200 @@@@ -1618,7 +1618,7 @@@@ && strncmp (arg, name, cp - name) == 0) { timefield = strchr (cp + 1, '/') + 1; - if (*timefield != '=') + if (*timefield == '/') { cp = timefield + strlen (timefield); cp[1] = '\0'; @@@@ -1661,7 +1661,7 @@@@ && strncmp (arg, name, cp - name) == 0) { timefield = strchr (cp + 1, '/') + 1; - if (!(timefield[0] == 'M' && timefield[1] == '/')) + if (*timefield == '/') { cp = timefield + strlen (timefield); cp[1] = '\0'; @ 1.3.2.1.2.6 log @OpenPKG-SA-2004.027-cvs, CAN-2004-0414, CAN-2004-0416, CAN-2004-0417, CAN-2004-0418; MFC: repair syntax; MFC: TIOCNOTTY portability @ text @d7 1 a7 1 +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) d19 1 a19 1 +#if defined(SERVER_SUPPORT) && defined(HAVE_SYSLOG_H) a182 658 ============================================================================= Security Bugfixes (OpenPKG-SA-2004.027-cvs, CAN-2004-0414, CAN-2004-0416, CAN-2004-0417, CAN-2004-0418) Index: src/commit.c --- src/commit.c.orig 2004-05-11 20:22:29 +0200 +++ src/commit.c 2004-06-09 16:52:37 +0200 @@@@ -485,7 +485,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); Index: src/filesubr.c --- src/filesubr.c.orig 2004-04-27 22:35:32 +0200 +++ src/filesubr.c 2004-06-09 16:52:38 +0200 @@@@ -930,8 +930,14 @@@@ expand_wild (int argc, char **argv, int *pargc, 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]); } Index: src/history.c --- src/history.c.orig 2004-05-16 02:39:26 +0200 +++ src/history.c 2004-06-09 16:52:38 +0200 @@@@ -412,8 +412,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) { @@@@ -898,9 +901,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); } @@@@ -925,9 +932,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); @@@@ -965,9 +976,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); } Index: src/server.c --- src/server.c.orig 2004-05-18 16:21:53 +0200 +++ src/server.c 2004-06-09 16:52:39 +0200 @@@@ -886,7 +886,7 @@@@ int i; char *p; - if (lim < 0) + if (lim < 0 || lim > 10000) return; p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10); if (p == NULL) @@@@ -1582,8 +1582,7 @@@@ char *cp; char *timefield; - if (error_pending ()) - return; + if (error_pending ()) return; if (outside_dir (arg)) return; @@@@ -1597,9 +1596,28 @@@@ && strlen (arg) == cp - name && strncmp (arg, name, cp - name) == 0) { - timefield = strchr (cp + 1, '/') + 1; + if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') + { + /* We didn't find the record separator or it is followed by + * the end of the string, so just exit. + */ + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Malformed Entry encountered."); + return; + } + /* If the time field is not currently empty, then one of + * serve_modified, serve_is_modified, & serve_unchanged were + * already called for this file. We would like to ignore the + * reinvocation silently or, better yet, exit with an error + * message, but we just avoid the copy-forward and overwrite the + * value from the last invocation instead. See the comment below + * for more. + */ if (*timefield == '/') { + /* Copy forward one character. Space was allocated for this + * already in serve_entry(). */ cp = timefield + strlen (timefield); cp[1] = '\0'; while (cp > timefield) @@@@ -1607,13 +1625,46 @@@@ *cp = cp[-1]; --cp; } - *timefield = '='; } + else if (timefield[1] != '/') + { + /* Obliterate anything else in TIMEFIELD. This is again to + * support the broken CVSNT clients mentioned below, in + * conjunction with strict timestamp string boundry checking in + * time_stamp_server() from vers_ts.c & file_has_conflict() + * from subr.c, since the broken clients used to send malformed + * timestamp fields in the Entry request that they then + * depended on the subsequent Unchanged request to overwrite. + */ + char *d = timefield + 1; + if (cp = strchr (d, '/')) + { + while (*cp) + { + *d++ = *cp++; + } + *d = '\0'; + } + } + /* If *TIMEFIELD wasn't '/', we assume that it was because of + * multiple calls to Is-modified & Unchanged by the client and + * just overwrite the value from the last call. Technically, we + * should probably either ignore calls after the first or send the + * client an error, since the client/server protocol specification + * specifies that only one call to either Is-Modified or Unchanged + * is allowed, but broken versions of CVSNT (at least 2.0.34 - + * 2.0.41, reported fixed in 2.0.41a) and the WinCVS & TortoiseCVS + * clients which depend on those broken versions of CVSNT (WinCVS + * 1.3 & at least one TortoiseCVS release) rely on this behavior. + */ + *timefield = '='; break; } } } + + static void serve_is_modified (char *arg) { @@@@ -1624,8 +1675,7 @@@@ /* Have we found this file in "entries" yet. */ int found; - if (error_pending ()) - return; + if (error_pending ()) return; if (outside_dir (arg)) return; @@@@ -1640,9 +1690,28 @@@@ && strlen (arg) == cp - name && strncmp (arg, name, cp - name) == 0) { - timefield = strchr (cp + 1, '/') + 1; + if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') + { + /* We didn't find the record separator or it is followed by + * the end of the string, so just exit. + */ + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Malformed Entry encountered."); + return; + } + /* If the time field is not currently empty, then one of + * serve_modified, serve_is_modified, & serve_unchanged were + * already called for this file. We would like to ignore the + * reinvocation silently or, better yet, exit with an error + * message, but we just avoid the copy-forward and overwrite the + * value from the last invocation instead. See the comment below + * for more. + */ if (*timefield == '/') { + /* Copy forward one character. Space was allocated for this + * already in serve_entry(). */ cp = timefield + strlen (timefield); cp[1] = '\0'; while (cp > timefield) @@@@ -1650,8 +1719,19 @@@@ *cp = cp[-1]; --cp; } - *timefield = 'M'; } + /* If *TIMEFIELD wasn't '/', we assume that it was because of + * multiple calls to Is-modified & Unchanged by the client and + * just overwrite the value from the last call. Technically, we + * should probably either ignore calls after the first or send the + * client an error, since the client/server protocol specification + * specifies that only one call to either Is-Modified or Unchanged + * is allowed, but broken versions of CVSNT (at least 2.0.34 - + * 2.0.41, reported fixed in 2.0.41a) and the WinCVS & TortoiseCVS + * clients which depend on those broken versions of CVSNT (WinCVS + * 1.3 & at least one TortoiseCVS release) rely on this behavior. + */ + *timefield++ = 'M'; if (kopt != NULL) { if (alloc_pending (strlen (name) + 80)) @@@@ -1670,7 +1750,7 @@@@ { /* We got Is-modified but no Entry. Add a dummy entry. The "D" timestamp is what makes it a dummy. */ - p = (struct an_entry *) xmalloc (sizeof (struct an_entry)); + p = xmalloc (sizeof (struct an_entry)); if (p == NULL) { pending_error = ENOMEM; @@@@ -1781,8 +1797,29 @@@@ { struct an_entry *p; char *cp; + int i = 0; if (error_pending()) return; - p = (struct an_entry *) xmalloc (sizeof (struct an_entry)); + + /* Verify that the entry is well-formed. This can avoid problems later. + * At the moment we only check that the Entry contains five slashes in + * approximately the correct locations since some of the code makes + * assumptions about this. + */ + cp = arg; + if (*cp == 'D') cp++; + while (i++ < 5) + { + if (!cp || *cp != '/') + { + if (alloc_pending (80)) + sprintf (pending_error_text, + "E protocol error: Malformed Entry"); + return; + } + cp = strchr (cp + 1, '/'); + } + + p = xmalloc (sizeof (struct an_entry)); if (p == NULL) { pending_error = ENOMEM; @@@@ -2011,6 +2048,9 @@@@ { char *cp; + if (!data[0]) + goto error; + if (strchr (data, '+')) goto error; @@@@ -2143,6 +2183,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) { @@@@ -2172,6 +2220,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 = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1); @@@@ -2498,7 +2554,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) @@@@ -2553,7 +2609,7 @@@@ while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0) { /* 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) @@@@ -6661,10 +6717,30 @@@@ buf_send_counted (protocol); } else -#endif +#endif /* SERVER_SUPPORT */ { + /* No MT support or we are using a local repository. */ if (strcmp (tag, "newline") == 0) cvs_output ("\n", 1); + else if (strcmp (tag, "date") == 0) + { +#ifdef SERVER_SUPPORT + if (server_active) + /* Output UTC when running as a server without MT support in + * the client since it is likely to be more meaningful than + * localtime. + */ + cvs_output (text, 0); + else +#endif /* SERVER_SUPPORT */ + { + char *date_in = xstrdup (text); + char *date = format_date_alloc (date_in); + cvs_output (date, 0); + free (date); + free (date_in); + } + } else if (text != NULL) cvs_output (text, 0); } Index: src/wrapper.c --- src/wrapper.c.orig 2004-02-18 05:46:08 +0100 +++ src/wrapper.c 2004-06-09 16:52:39 +0200 @@@@ -235,6 +235,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. @@@@ -540,9 +564,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 ); @@@@ -572,9 +595,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 ); Index: src/cvs.h --- src/cvs.h.orig 2003-12-08 20:43:00 +0100 +++ src/cvs.h 2004-06-10 21:57:14 +0200 @@@@ -68,6 +68,11 @@@@ #endif /* STD_HEADERS */ /* End includes for functions with variable numbers of arguments */ + #include "xsize.h" + #include "xtime.h" + static char *format_time_t (time_t unixtime); + char *format_date_alloc (char *text); + #if ! STDC_HEADERS extern void exit (); extern char *getenv(); Index: main.c --- src/main.c.orig 2004-06-10 20:06:09 +0200 +++ src/main.c 2004-06-10 20:08:36 +0200 @@@@ -1186,6 +1186,79 @@@@ source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); } +/* Format a date in the local timezone using format_time_t() given a date from + * an arbitrary timezone in a string. + * + * INPUT + * DATESTR A string that looks like anything get_date() can parse, e.g.: + * + * 2004-04-29 20:24:22 + * + * ERRORS + * As get_date() & format_time_t(). Prints a warning if either provide + * error return values. See RETURNS. + * + * RETURNS + * A freshly allocated string that is a copy of the input string if either + * get_date() or format_time_t() encounter an error and as format_time_t() + * otherwise. + */ +char * +format_date_alloc (char *datestr) +{ + time_t unixtime; + char *buf; + + TRACE (TRACE_FUNCTION, "format_date (%s)", datestr); + + /* Convert the date string to seconds since the epoch. */ + unixtime = get_date (datestr, NULL); + if (unixtime == (time_t)-1) + { + error (0, 0, "Can't parse date/time: `%s'.", datestr); + goto as_is; + } + + /* Get the time into a string. */ + if ((buf = format_time_t (unixtime)) == NULL) + { + error (0, 0, "Unable to reformat date `%s'.", datestr); + goto as_is; + } + + return buf; + + as_is: + return xstrdup (datestr); +} + +/* + * Format a date for the current locale. + * + * INPUT + * UNIXTIME The UNIX seconds since the epoch. + * + * RETURNS + * If my_strftime() encounters an error, this function can return NULL. + * + * Otherwise, returns a date string in ISO8601 format, e.g.: + * + * 2004-04-29 13:24:22 -0700 + * + * It is the responsibility of the caller to return of this string. + */ +static char * +format_time_t (time_t unixtime) +{ + static char buf[sizeof ("yyyy-mm-dd HH:MM:SS -HHMM")]; + /* Convert to a time in the local time zone. */ + struct tm ltm = *(gmtime (&unixtime)); + + if (strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S %z", <m) == 0) + return NULL; + + return xstrdup (buf); +} void usage (register const char *const *cpp) { Index: xsize.h --- /dev/null 2004-06-10 20:01:31 +0200 +++ src/xsize.h 2004-06-10 20:02:42 +0200 @@@@ -0,0 +1,37 @@@@ +/* excerpt from cvs-1.12.9 */ + +#ifndef _XSIZE_H +#define _XSIZE_H + +/* Get size_t. */ +#include + +/* Get SIZE_MAX. */ +#include +#if HAVE_STDINT_H +# include +#endif +#ifndef SIZE_MAX +#define SIZE_MAX (4294967295U) +#endif + +/* 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); +} + +/* Multiplication of a count with an element size, with overflow check. */ +#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) + +#endif /* _XSIZE_H */ Index: lib/xtime.h --- /dev/null 2004-06-10 20:31:48 +0200 +++ src/xtime.h 2004-05-16 01:09:13 +0200 @@@@ -0,0 +1,57 @@@@ +/* 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. */ + +/* This file simply performs the include magic necessary for using time + * functions + */ + +#ifdef vms +# include +#else /* vms */ + +# if TIME_WITH_SYS_TIME +# include +# include +# else /* TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include +# else /* HAVE_SYS_TIME_H */ +# include +# endif /* !HAVE_SYS_TIME_H */ +# endif /* !TIME_WITH_SYS_TIME */ + +# ifdef HAVE_SYS_TIMEB_H +# include +# else /* HAVE_SYS_TIMEB_H */ +/* + * We use the obsolete `struct timeb' as part of our interface! + * Since the system doesn't have it, we define it here; + * our callers must do likewise. + * + * At the least we were using this in lib/getdate.y, but lib/system.h used to + * define it too, so maybe CVS is using it elsewhere. + */ +struct timeb { + time_t time; /* Seconds since the epoch */ + unsigned short millitm; /* Field not used */ + short timezone; /* Minutes west of GMT */ + short dstflag; /* Field not used */ +}; +# endif /* !HAVE_SYS_TIMEB_H */ + +# ifdef timezone +# undef timezone /* needed for sgi */ +# endif /* timezone */ + +# if !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) +extern long timezone; +# endif /* !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) */ + +#endif /* !vms */ @ 1.3.6.1 log @SA-2003.004-cvs; CAN-2003-0015 @ text @d1 120 a120 10 --- cvs-1.11.1p1/src/client.c.orig Tue Jan 21 13:42:34 2003 +++ cvs-1.11.1p1/src/client.c Tue Jan 21 13:42:43 2003 @@@@ -2117,7 +2117,7 @@@@ * date. Create a dummy timestamp which will never compare * equal to the timestamp of the file. */ - if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-') + if (vn[0] == '\0' || strcmp (vn, "0") == 0 || vn[0] == '-') local_timestamp = "dummy timestamp"; else if (local_timestamp == NULL) d122 6 a127 59 --- cvs-1.11.1p1/src/commit.c.orig Tue Jan 21 13:42:34 2003 +++ cvs-1.11.1p1/src/commit.c Tue Jan 21 13:42:43 2003 @@@@ -248,15 +248,7 @@@@ xfinfo.rcs = NULL; vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0); - if (vers->ts_user == NULL - && vers->vn_user != NULL - && vers->vn_user[0] == '-') - /* FIXME: If vn_user is starts with "-" but ts_user is - non-NULL, what classify_file does is print "%s should be - removed and is still there". I'm not sure what it does - then. We probably should do the same. */ - status = T_REMOVED; - else if (vers->vn_user == NULL) + if (vers->vn_user == NULL) { if (vers->ts_user == NULL) error (0, 0, "nothing known about `%s'", finfo->fullname); @@@@ -266,15 +258,28 @@@@ freevers_ts (&vers); return 1; } - else if (vers->ts_user != NULL - && vers->vn_user != NULL - && vers->vn_user[0] == '0') - /* FIXME: If vn_user is "0" but ts_user is NULL, what classify_file - does is print "new-born %s has disappeared" and removes the entry. - We probably should do the same. */ + if (vers->ts_user == NULL) + { + if (strcmp (vers->vn_user, "0") == 0) + /* This happens when one has `cvs add'ed a file, but it no + longer exists in the working directory at commit time. + FIXME: What classify_file does in this case is print + "new-born %s has disappeared" and removes the entry. + We probably should do the same. */ + status = T_ADDED; + else if (vers->vn_user[0] == '-') + status = T_REMOVED; + else + { + /* FIXME: What classify_file does in this case is print + "%s was lost". We probably should do the same. */ + freevers_ts (&vers); + return 0; + } + } + else if (strcmp (vers->vn_user, "0") == 0) status = T_ADDED; - else if (vers->ts_user != NULL - && vers->ts_rcs != NULL + else if (vers->ts_rcs != NULL && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0)) /* If we are forcing commits, pretend that the file is modified. */ --- cvs-1.11.1p1/src/server.c.orig Tue Jan 21 13:42:34 2003 +++ cvs-1.11.1p1/src/server.c Tue Jan 21 13:42:43 2003 @@@@ -977,9 +977,6 @@@@ d130 9 d140 22 a161 2 - if (dir_name != NULL) - free (dir_name); d163 27 a189 1 dir_len = strlen (dir); d191 84 a274 4 /* Check for a trailing '/'. This is not ISDIRSEP because \ in the @@@@ -994,6 +991,9 @@@@ "E protocol error: invalid directory syntax in %s", dir); return; d276 12 d289 2 a290 2 + if (dir_name != NULL) + free (dir_name); d292 32 a323 2 dir_name = malloc (strlen (server_temp_dir) + dir_len + 40); if (dir_name == NULL) @ 1.2 log @include some important server fixes from cvshome.org CVS trunk @ text @@ 1.1 log @include patch to fix communication hanging with old clients @ text @d1 314 a314 7 Fix communication hanging in communication shutdown phase, caused by at least older CVS clients (version < 1.11.2) and a semantically incorrect usage of getc() by the server. --- cvs-1.11.2.orig/src/buffer.c 2001-08-09 21:26:35.000000000 +0200 +++ cvs-1.11.2/src/buffer.c 2002-08-22 15:40:11.000000000 +0200 @@@@ -1378,8 +1378,7 @@@@ d320 1 a320 1 + if (! buf_empty_p (buf)) @ 1.1.2.1 log @SA-2003.004-cvs; CAN-2003-0015 @ text @d5 1 a5 1 --- cvs-1.11.2/src/buffer.c.orig 2001-08-09 21:26:35.000000000 +0200 a16 89 --- cvs-1.11.2/src/client.c.orig Thu Aug 9 22:27:26 2001 +++ cvs-1.11.2/src/client.c Tue Jan 21 13:25:18 2003 @@@@ -2171,7 +2171,7 @@@@ * date. Create a dummy timestamp which will never compare * equal to the timestamp of the file. */ - if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-') + if (vn[0] == '\0' || strcmp (vn, "0") == 0 || vn[0] == '-') local_timestamp = "dummy timestamp"; else if (local_timestamp == NULL) { --- cvs-1.11.2/src/commit.c.orig Fri Aug 24 19:47:02 2001 +++ cvs-1.11.2/src/commit.c Tue Jan 21 13:38:30 2003 @@@@ -248,15 +248,7 @@@@ xfinfo.rcs = NULL; vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0); - if (vers->ts_user == NULL - && vers->vn_user != NULL - && vers->vn_user[0] == '-') - /* FIXME: If vn_user is starts with "-" but ts_user is - non-NULL, what classify_file does is print "%s should be - removed and is still there". I'm not sure what it does - then. We probably should do the same. */ - status = T_REMOVED; - else if (vers->vn_user == NULL) + if (vers->vn_user == NULL) { if (vers->ts_user == NULL) error (0, 0, "nothing known about `%s'", finfo->fullname); @@@@ -266,15 +258,28 @@@@ freevers_ts (&vers); return 1; } - else if (vers->ts_user != NULL - && vers->vn_user != NULL - && vers->vn_user[0] == '0') - /* FIXME: If vn_user is "0" but ts_user is NULL, what classify_file - does is print "new-born %s has disappeared" and removes the entry. - We probably should do the same. */ + if (vers->ts_user == NULL) + { + if (strcmp (vers->vn_user, "0") == 0) + /* This happens when one has `cvs add'ed a file, but it no + longer exists in the working directory at commit time. + FIXME: What classify_file does in this case is print + "new-born %s has disappeared" and removes the entry. + We probably should do the same. */ + status = T_ADDED; + else if (vers->vn_user[0] == '-') + status = T_REMOVED; + else + { + /* FIXME: What classify_file does in this case is print + "%s was lost". We probably should do the same. */ + freevers_ts (&vers); + return 0; + } + } + else if (strcmp (vers->vn_user, "0") == 0) status = T_ADDED; - else if (vers->ts_user != NULL - && vers->ts_rcs != NULL + else if (vers->ts_rcs != NULL && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0)) /* If we are forcing commits, pretend that the file is modified. */ --- cvs-1.11.2/src/server.c.orig Tue Mar 19 20:15:45 2002 +++ cvs-1.11.2/src/server.c Tue Jan 21 13:28:34 2003 @@@@ -978,9 +978,6 @@@@ return; } - if (dir_name != NULL) - free (dir_name); - dir_len = strlen (dir); /* Check for a trailing '/'. This is not ISDIRSEP because \ in the @@@@ -995,6 +992,9 @@@@ "E protocol error: invalid directory syntax in %s", dir); return; } + + if (dir_name != NULL) + free (dir_name); dir_name = malloc (strlen (server_temp_dir) + dir_len + 40); if (dir_name == NULL) @