diff -ur /tmp/cvs-1.12.2/src/cvs.h ./src/cvs.h --- /tmp/cvs-1.12.2/src/cvs.h 2003-10-09 18:26:45.000000000 +0200 +++ ./src/cvs.h 2003-12-13 00:57:51.000000000 +0100 @@ -132,6 +132,13 @@ #define CVSADM_TEMPLATE "CVS/Template" #endif /* USE_VMS_FILENAMES */ +/* Global configuration file mapping repositories to uids. This can be + used instead of getting the unix user. This is prevents a security + problem where anyone with commit access can basically become any + user on the machine. Combined with the insecure pserver that is a + problem waiting to happen. */ +#define CVS_REPOUIDFILE "/etc/cvs-repouids" + /* This is the special directory which we use to store various extra per-directory information in the repository. It must be the same as CVSADM to avoid creating a new reserved directory name which users cannot diff -ur /tmp/cvs-1.12.2/src/server.c ./src/server.c --- /tmp/cvs-1.12.2/src/server.c 2003-10-14 18:55:56.000000000 +0200 +++ ./src/server.c 2003-12-13 01:13:31.000000000 +0100 @@ -5094,6 +5094,12 @@ exit (EXIT_FAILURE); } + if (pw->pw_uid == 0) + { + printf("error 0: root not allowed\n"); + exit (EXIT_FAILURE); + } + #if HAVE_INITGROUPS if (initgroups (pw->pw_name, pw->pw_gid) < 0 # ifdef EPERM @@ -5192,6 +5198,46 @@ } #endif +static char* +global_repo_uid(const char* repository) +{ + FILE *fp; + char *linebuf = NULL; + size_t linebuf_len; + int found_it = 0; + size_t repolen = strlen (repository); + char *user; + + fp = fopen (CVS_REPOUIDFILE, "r"); + if (fp == NULL) + { + if (!existence_error (errno)) + error (0, errno, "cannot open %s", CVS_REPOUIDFILE); + return 0; + } + + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + if ((strncmp (linebuf, repository, repolen) == 0) + && (linebuf[repolen] == ':')) + { + found_it = 1; + break; + } + } + + if (ferror (fp)) + error (0, errno, "cannot read %s", CVS_REPOUIDFILE); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVS_REPOUIDFILE); + + strtok (linebuf + repolen, "\n"); + user = xstrdup (linebuf + repolen + 1); + free (linebuf); + + return user; +} + #ifdef AUTH_SERVER_SUPPORT extern char *crypt (const char *, const char *); @@ -5262,7 +5308,7 @@ /* If found_it, then linebuf contains the information we need. */ if (found_it) { - char *found_password, *host_user_tmp; + char *found_password, *host_user_tmp, *user_override; char *non_cvsuser_portion; /* We need to make sure lines such as @@ -5317,28 +5363,36 @@ host_user_tmp = strtok (NULL, ":"); } - /* Of course, maybe there was no system user portion... */ - if (host_user_tmp == NULL) - host_user_tmp = username; - - /* 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); - retval = 1; + user_override = global_repo_uid (repository); + if (user_override) { + *host_user_ptr = user_override; + retval = 1; } else { + /* Of course, maybe there was no system user portion... */ + if (host_user_tmp == NULL) + host_user_tmp = username; + + /* 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); + retval = 1; + } + else + { #ifdef LOG_AUTHPRIV - syslog (LOG_AUTHPRIV | LOG_NOTICE, - "password mismatch for %s in %s: %s vs. %s", username, - repository, crypt(password, found_password), found_password); -#endif - *host_user_ptr = NULL; - retval = 2; + syslog (LOG_AUTHPRIV | LOG_NOTICE, + "password mismatch for %s in %s: %s vs. %s", username, + repository, crypt(password, found_password), found_password); +#endif + *host_user_ptr = NULL; + retval = 2; + } } } else /* Didn't find this user, so deny access. */