Index: version_no.h =================================================================== RCS file: /cvs/cvsnt/version_no.h,v retrieving revision 1.1.2.112.4.23 diff -c -r1.1.2.112.4.23 version_no.h *** version_no.h 5 Jun 2012 06:47:52 -0000 1.1.2.112.4.23 --- version_no.h 9 Oct 2012 04:59:11 -0000 *************** *** 36,42 **** #include "build.h" #define CVSNT_PRODUCT_NAME " (Cally)" ! #define CVSNT_SPECIAL_BUILD "RC 4" #ifdef RC_INVOKED //#define CVSNT_SPECIAL_BUILD "Prerelease" --- 36,42 ---- #include "build.h" #define CVSNT_PRODUCT_NAME " (Cally)" ! #define CVSNT_SPECIAL_BUILD "RC 5" #ifdef RC_INVOKED //#define CVSNT_SPECIAL_BUILD "Prerelease" Index: windows-NT/cvsdiag/cvsdiag.cpp =================================================================== RCS file: /cvs/cvsnt/windows-NT/cvsdiag/cvsdiag.cpp,v retrieving revision 1.1.2.8.8.54 diff -c -r1.1.2.8.8.54 cvsdiag.cpp *** windows-NT/cvsdiag/cvsdiag.cpp 3 Oct 2012 06:36:44 -0000 1.1.2.8.8.54 --- windows-NT/cvsdiag/cvsdiag.cpp 9 Oct 2012 03:35:33 -0000 *************** *** 2338,2343 **** --- 2338,2348 ---- int tempdir_size=1024; getcvstemp(tmpdir,tempdir_size); _ftprintf(output,_T("CVS Temp directory: %s\n"),tmpdir); + _ftprintf(output,_T("CVS Default Protocol: %s\n"),get_reg_string(_T("DefaultProtocol"))); + _ftprintf(output,_T("CVS Anonymous Protocol: %s\n"),get_reg_string(_T("AnonymousProtocol"))); + _ftprintf(output,_T("CVS Anonymous Username: %s\n"),get_reg_string(_T("AnonymousUsername"))); + _ftprintf(output,_T("CVS Anonymous Force Branch: %s\n"),get_reg_string(_T("AnonForceBranch"))); + _ftprintf(output,_T("CVS Non-Anonymous Force Branch: %s\n"),get_reg_string(_T("ForceBranch"))); _ftprintf(output,_T("CA Certificate File: %s\n"),get_reg_string(_T("CertificateFile"))); _ftprintf(output,_T("Default Client Codepage: %s\n"),get_reg_string(_T("DefaultClientCodepage"))); _ftprintf(output,_T("Allowed Clients: %s\n"),get_reg_string(_T("AllowedClients"))); *************** *** 2391,2396 **** --- 2396,2402 ---- _ftprintf(output,_T("LargeQuickRead: %s\n"),get_reg_intx(_T("LargeQuickRead"),0)?_T("Yes"):_T("No")); _ftprintf(output,_T("LowMemOK: %s\n"),get_reg_intx(_T("LowMemOK"),0)?_T("Yes"):_T("No")); _ftprintf(output,_T("TrySelect: %s\n"),get_reg_intx(_T("TrySelect"),0)?_T("Yes"):_T("No")); + _ftprintf(output,_T("EnumSleep: %d\n"),get_reg_intx(_T("EnumSleep"),0)); _ftprintf(output,_T("AuthSleep: %d\n"),get_reg_intx(_T("AuthSleep"),0)); _ftprintf(output,_T("NoAuthSleep: %d\n"),get_reg_intx(_T("NoAuthSleep"),2)); _ftprintf(output,_T("RecvSleep: %d\n"),get_reg_intx(_T("RecvSleep"),0)); *************** *** 2447,2455 **** if(get_reg_intx(_T("UnicodeServer"),0)) win32_global_codepage = CP_UTF8; DWORD dwLenGCA=sizeof(comname); GetComputerName(comname, &dwLenGCA); ! _ftprintf(output,_T("This computer: %s\n"),comname); if(!isDomainMember(prefdomain)) { *prefdomain=(TCHAR)0; --- 2453,2462 ---- if(get_reg_intx(_T("UnicodeServer"),0)) win32_global_codepage = CP_UTF8; + _ftprintf(output,_T("CVS Server Name: %s\n"),get_reg_string(_T("ServerName"))); DWORD dwLenGCA=sizeof(comname); GetComputerName(comname, &dwLenGCA); ! _ftprintf(output,_T("This computer real name: %s\n"),comname); if(!isDomainMember(prefdomain)) { *prefdomain=(TCHAR)0; Index: src/cvs.h =================================================================== RCS file: /cvs/cvsnt/src/cvs.h,v retrieving revision 1.93.2.208.6.44 diff -c -r1.93.2.208.6.44 cvs.h *** src/cvs.h 3 Oct 2012 03:40:44 -0000 1.93.2.208.6.44 --- src/cvs.h 9 Oct 2012 04:40:03 -0000 *************** *** 192,197 **** --- 192,198 ---- #define CVSROOTADM_WRITERS "writers" #define CVSROOTADM_PASSWD "passwd" #define CVSROOTADM_GROUP "group" + #define CVSROOTADM_BRANCHF "branchforce" #define CVSROOTADM_CONFIG "config" #define CVSROOTADM_POSTCOMMIT "postcommit" #define CVSROOTADM_PRECOMMAND "precommand" *************** *** 439,444 **** --- 440,447 ---- extern char *CVSroot_cmdline; int perms_close(); + void get_branch_force_admin(); + const char *get_branch_force(); int verify_admin(); int verify_read(const char *dir, const char *file, const char *tag, const char **message, const char **type_message); int verify_write(const char *dir, const char *file, const char *tag, const char **message, const char **type_message); Index: src/edit.cpp =================================================================== RCS file: /cvs/cvsnt/src/edit.c,v retrieving revision 1.28.2.75.4.25 diff -c -r1.28.2.75.4.25 edit.cpp *** src/edit.cpp 8 Aug 2012 09:30:34 -0000 1.28.2.75.4.25 --- src/edit.cpp 9 Oct 2012 04:08:09 -0000 *************** *** 1449,1454 **** --- 1449,1457 ---- if (fclose (fp) < 0) error (0, errno, "cannot close %s", usersname); } + // I still think there should be an else condition here where it uses DefaultDomain when no users file exists + // like the bug_trigger does - but the bug trigger uses Bugs/DefaultDomain wheras the server would need to use + // PServer/DefaultDomain... xfree (usersname); if (line != NULL) // needs to be free() rather than xfree() since on windows xfree() may call WIN32 API Index: src/main.cpp =================================================================== RCS file: /cvs/cvsnt/src/main.c,v retrieving revision 1.71.2.151.6.93 diff -c -r1.71.2.151.6.93 main.cpp *** src/main.cpp 5 Oct 2012 04:00:58 -0000 1.71.2.151.6.93 --- src/main.cpp 9 Oct 2012 04:19:17 -0000 *************** *** 198,203 **** --- 198,207 ---- /* 0=Any, 1=Request compr., 2=Require compr. */ extern int compression_level; + extern const char *g_anonymous_user; + extern const char *g_force_branch; + extern const char *g_anon_force_branch; + extern int g_is_anonymous; extern const char *allowed_clients; extern int nowarn_fourtyone; extern int nowarn_twozero; *************** *** 798,803 **** --- 802,817 ---- read_only_server = atoi(buffer); #ifdef SERVER_SUPPORT + get_branch_force_admin(); + if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","ForceBranch",buffer,sizeof(buffer))) + g_force_branch = xstrdup(buffer); + else + g_force_branch=NULL; + if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","AnonForceBranch",buffer,sizeof(buffer))) + g_anon_force_branch = xstrdup(buffer); + if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","AnonymousUsername",buffer,sizeof(buffer))) + g_anonymous_user = xstrdup(buffer); + if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","AllowedClients",buffer,sizeof(buffer))) allowed_clients = xstrdup(buffer); if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","Warn2041",buffer,sizeof(buffer))) Index: src/mkmodules.cpp =================================================================== RCS file: /cvs/cvsnt/src/mkmodules.c,v retrieving revision 1.25.2.58.6.4 diff -c -r1.25.2.58.6.4 mkmodules.cpp *** src/mkmodules.cpp 10 Dec 2009 16:30:15 -0000 1.25.2.58.6.4 --- src/mkmodules.cpp 9 Oct 2012 04:30:51 -0000 *************** *** 629,636 **** // {"passwd", // "a %s file contains the list of users and passwords", // NULL}, ! {"group", "a %s file contains the list of groups", NULL}, {"admin", "a %s file contains the list of administrators", --- 629,642 ---- // {"passwd", // "a %s file contains the list of users and passwords", // NULL}, ! {CVSROOTADM_GROUP, "a %s file contains the list of groups", + NULL}, + {CVSROOTADM_BRANCHF, + "a %s file contains the map of users/groups to default/force branches", + NULL}, + {CVSROOTADM_USERS, + "a %s file contains the map of users to email addresses", NULL}, {"admin", "a %s file contains the list of administrators", Index: src/perms.cpp =================================================================== RCS file: /cvs/cvsnt/src/perms.cpp,v retrieving revision 1.1.2.32.4.18 diff -c -r1.1.2.32.4.18 perms.cpp *** src/perms.cpp 15 Nov 2011 05:57:02 -0000 1.1.2.32.4.18 --- src/perms.cpp 9 Oct 2012 04:51:34 -0000 *************** *** 34,42 **** --- 34,44 ---- // Acl mode: 0=none,1=compat,2=normal int acl_mode = 1; + typedef std::map branch_force_t; typedef std::map valid_groups_t; typedef std::map directory_cache_t; static valid_groups_t valid_groups; + static branch_force_t branch_force, branch_default; static directory_cache_t directory_cache; static char perms_cache_dir[_MAX_PATH] = {0}; *************** *** 335,340 **** --- 337,454 ---- } #endif } + + /* Get the list of default branches and force branches mapped to users/groups */ + void get_branch_force_admin() + { + char *filename; + char *branch_names; + char *adminname; + char *admingroup; + FILE *fp; + char *linebuf = NULL; + size_t linebuf_len = 512; + + TRACE(2,"Find all the branch default and branch force definitions and add them to the list."); + if (!branch_force.empty() || !branch_default.empty()) + return; + + filename = (char*)xmalloc (strlen (current_parsed_root->directory) + + strlen (CVSROOTADM) + + strlen (CVSROOTADM_BRANCHF) + + 10); + + // must use malloc/free since this is what lib/getdelim does + // otherwise on windows we'll try and accidentally free it with the Win32 native memory functions + linebuf = (char*)malloc (linebuf_len + 100); + + strcpy (filename, current_parsed_root->directory); + strcat (filename, "/" CVSROOTADM "/"); + strcat (filename, CVSROOTADM_BRANCHF); + + TRACE(2,"Open the admin branch_force file %s/%s",CVSROOTADM,CVSROOTADM_GROUP); + fp = CVS_FOPEN (filename, "r"); + if (fp != NULL) + { + TRACE(2,"Begin reading the admin branch_force file %s/%s",CVSROOTADM,CVSROOTADM_GROUP); + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + admingroup = cvs_strtok(linebuf, ":\n"); + if (admingroup == NULL) + continue; + branch_names = cvs_strtok(NULL, ":\n"); + if (branch_names == NULL) + continue; + + adminname = cvs_strtok(branch_names, ", \t"); + while (adminname != NULL) + { + if(*branch_names=='!') + branch_force[admingroup]=(branch_names+1); + else + branch_force[admingroup]=(branch_names); + + adminname = cvs_strtok(NULL, ", \t"); + } + + memset(linebuf,0,linebuf_len); + } + + if( linebuf != NULL ) + { + // needs to be free() rather than xfree() since on windows xfree() may call WIN32 API + free (linebuf); + linebuf = NULL; + } + if (ferror (fp)) + error (1, errno, "cannot read %s", filename); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", filename); + } + xfree(filename); + if( linebuf != NULL ) + { + // needs to be free() rather than xfree() since on windows xfree() may call WIN32 API + free (linebuf); + linebuf = NULL; + } + /* If we can't open the group file, we just don't do groups. */ + TRACE(2,"Finished reading the admin branch_force file %s/%s",CVSROOTADM,CVSROOTADM_GROUP); + } + + /* find the force_branch for the current user */ + const char *get_branch_force() + { + static const char *current_branch_force=NULL; + TRACE(2,"Find the branch force definition for the current user."); + if (branch_force.empty() || valid_groups.empty()) + return NULL; + + /*if (current_branch_force!=NULL) + xfree(current_branch_force);*/ + current_branch_force=NULL; + + branch_force_t::iterator found_force; + + for(valid_groups_t::iterator i = valid_groups.begin(); i!=valid_groups.end(); i++) + { + if (i->second==0) + TRACE(4,"Ignore the group \"%s\" because it is not valid."); + else + { + found_force = branch_force.find(i->first); + if (found_force!=branch_force.end()) + { + TRACE(4,"the group \"%s\" is valid - and has matching branch_force %s",found_force->second.c_str()); + current_branch_force=found_force->second.c_str(); + } + else + TRACE(4,"the group \"%s\" is valid - but has no matching branch_force"); + } + } + return (current_branch_force)?xstrdup(current_branch_force):current_branch_force; + } + static int verify_valid_name(const char *name) { Index: src/server.cpp =================================================================== RCS file: /cvs/cvsnt/src/server.c,v retrieving revision 1.106.2.210.6.138 diff -c -r1.106.2.210.6.138 server.cpp *** src/server.cpp 5 Oct 2012 00:14:34 -0000 1.106.2.210.6.138 --- src/server.cpp 9 Oct 2012 04:48:24 -0000 *************** *** 267,272 **** --- 267,277 ---- /* 0=Any, 1=Request compr., 2=Require compr. */ int compression_level = 0; + int g_is_anonymous=0; + const char *g_anonymous_user = NULL; + const char *g_force_branch = NULL; + const char *g_anon_force_branch = NULL; + /* Regexp of clients allowed to connect */ const char *allowed_clients = NULL; int nowarn_fourtyone = 0; *************** *** 1847,1858 **** protocol_encryption_enabled = PROTOCOL_AUTHENTICATION; } ! static void serve_directory (char *arg) { - int status; - char *repos; - - status = server_read_line (buf_from_net, &repos, (int *) NULL); if (status == 0) { if (!outside_root (repos)) --- 1852,1859 ---- protocol_encryption_enabled = PROTOCOL_AUTHENTICATION; } ! static void serve_directory_repos (char *arg, char *repos, int status) { if (status == 0) { if (!outside_root (repos)) *************** *** 1877,1882 **** --- 1878,1892 ---- } } + static void serve_directory (char *arg) + { + int status; + char *repos; + + status = server_read_line (buf_from_net, &repos, (int *) NULL); + serve_directory_repos (arg, repos, status); + } + static void serve_static_directory (char *arg) { FILE *f; *************** *** 5808,6048 **** lib.UnloadProtocol(server_protocol); } int server_active = 0; int proxy_active = 0; char * stdinbuf = 0, *stdinbuftrix[10] = {0,0,0,0,0,0,0,0,0,0}; int stdinbufcount=0; ! int server () { cvs::wildcard_filename ac; static int check_done=0; static int do_check_version; static int got_ok_client_version=0; ! const char *log = CProtocolLibrary::GetEnvironment("CVS_SERVER_LOG"); ! global_edit_bugnum_hack = 0; ! global_editors_bugnum_hack = 0; ! do_check_version =0; ! ac = serv_client_version?serv_client_version:""; ! ! if(!log) ! { ! static char logbuf[256]; ! if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","ServerLogFile",logbuf,sizeof(logbuf))) ! log = logbuf; ! } ! ! /* Ignore argc and argv. They might be from .cvsrc. */ ! if(!buf_to_net) ! buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, outbuf_memory_error); ! if(!buf_from_net) ! buf_from_net = stdio_buffer_initialize (stdin, 1, outbuf_memory_error); ! ! use_sticky_tagname=0; ! ! /* Set up logfiles, if any. */ ! if (log) ! { ! int len = strlen (log); ! char *buf = (char*)xmalloc (len + 64); ! char *p; ! FILE *fp; ! ! sprintf(buf,"%s-%d",log,(int)getpid()); ! p = buf + strlen(buf); ! ! /* Open logfiles in binary mode so that they reflect ! exactly what was transmitted and received (that is ! more important than that they be maximally ! convenient to view). */ ! strcpy (p, ".out"); ! fp = open_file (buf, "wb"); ! if (fp == NULL) ! error (0, errno, "opening to-server logfile %s", buf); ! else ! buf_to_net = log_buffer_initialize (buf_to_net, fp, 0, ! (BUFMEMERRPROC) NULL); ! ! strcpy (p, ".in"); ! fp = open_file (buf, "wb"); ! if (fp == NULL) ! error (0, errno, "opening from-server logfile %s", buf); ! else ! buf_from_net = log_buffer_initialize (buf_from_net, fp, 1, ! (BUFMEMERRPROC) NULL); ! ! xfree (buf); ! } ! ! stdout_buf = cvs_protocol_wrap_buffer_initialize(buf_to_net, 'M'); ! stderr_buf = cvs_protocol_wrap_buffer_initialize(buf_to_net, 'E'); ! ! TRACE(99,"Server start stuff"); ! /* OK, now figure out where we stash our temporary files. */ ! { ! char *p; ! ! /* The code which wants to chdir into server_temp_dir is not set ! up to deal with it being a relative path. So give an error ! for that case. */ ! if (!isabsolute (Tmpdir)) ! { ! error(1,0,"Value of %s for TMPDIR is not absolute", Tmpdir); ! } ! else ! { ! int status; ! int i = 0; ! ! server_temp_dir = (char*)xmalloc (strlen (Tmpdir) + 256); ! if (server_temp_dir == NULL) ! { ! error(1,ENOMEM,"Fatal server error, aborting."); ! } ! strcpy (server_temp_dir, Tmpdir); ! ! /* Remove a trailing slash from TMPDIR if present. */ ! p = server_temp_dir + strlen (server_temp_dir) - 1; ! if (*p == '/') ! *p = '\0'; ! ! /* ! * I wanted to use cvs-serv/PID, but then you have to worry about ! * the permissions on the cvs-serv directory being right. So ! * use cvs-servPID. ! */ ! strcat (server_temp_dir, "/cvs-serv"); ! ! p = server_temp_dir + strlen (server_temp_dir); ! sprintf (p, "%ld", (long) getpid ()); ! ! orig_server_temp_dir = server_temp_dir; ! ! TRACE(3,"Server temp dir is %s",server_temp_dir); ! ! /* Create the temporary directory, and set the mode to ! 700, to discourage random people from tampering with ! it. */ ! /* mkdir_p is a bad idea here as an incorrect server_temp_dir ! could put a directory pretty much anywhere in error.. eg. trying ! to create c:\windows\temp on Windows 7 for example. */ ! while ((status = mkdir_p(server_temp_dir, 0777)) == EEXIST) // Was mkdir_p ! { ! 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) ! { ! error(1,errno,"can't create temporary directory %s",server_temp_dir); ! } ! #ifndef CHMOD_BROKEN ! else if (chmod (server_temp_dir, S_IRWXU) < 0) ! { ! error(1,errno,"cannot change permissions on temporary directory %s", ! fn_root(server_temp_dir)); ! } ! #endif ! else if (CVS_CHDIR (server_temp_dir) < 0) ! { ! error(1,errno,"cannot change to temporary directory %s", ! fn_root(server_temp_dir)); ! } ! #ifdef _WIN32 ! if(!filenames_case_insensitive && __case_sensitive()>1) ! add_to_ci_directory_list(server_temp_dir); ! #endif ! } ! } ! ! TRACE(99,"Server register for signals"); ! #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. */ ! argument_vector_size = 1; ! argument_vector = ! (char **) xmalloc (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. ! */ ! TRACE(99,"Fatal server error, aborting. error ENOMEM Virtual memory exhausted."); ! printf ("E Fatal server error, aborting.\nerror 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 - if(current_username) - xfree(current_username); - CCvsgui::Close(EXIT_FAILURE); - exit (EXIT_FAILURE); - } ! 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] = strdup("cvs server"); - int times_through=0; - while (1) - { - char *cmd, *orig_cmd; - struct request *rq; - int status; - times_through++; - - TRACE(99,"server: read a 'server line' from client."); - status = server_read_line (buf_from_net, &cmd, (int *) NULL); - if (status == -2) - { - buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\ - error ENOMEM Virtual memory exhausted.\n"); - break; - } - TRACE(99,"server: read line status = %d cmd = '%s'.",status,(status==0)?PATCH_NULL(cmd):"bad status"); - if (status != 0) - break; - if(!*cmd) - continue; - - orig_cmd = cmd; for (rq = requests; rq->name != NULL; ++rq) if (strncmp (cmd, rq->name, strlen (rq->name)) == 0) { --- 5818,5847 ---- lib.UnloadProtocol(server_protocol); } + enum servercmd_modetype + { + scmdmNormal, scmdmPushStore, scmdmReplay + }; + typedef enum servercmd_modetype scmdmtype; + int server_active = 0; int proxy_active = 0; char * stdinbuf = 0, *stdinbuftrix[10] = {0,0,0,0,0,0,0,0,0,0}; int stdinbufcount=0; ! int servergo(char *cmd) { cvs::wildcard_filename ac; static int check_done=0; static int do_check_version; static int got_ok_client_version=0; ! struct request *rq; ! do_check_version =0; ! ac = serv_client_version?serv_client_version:""; for (rq = requests; rq->name != NULL; ++rq) if (strncmp (cmd, rq->name, strlen (rq->name)) == 0) { *************** *** 6329,6334 **** --- 6128,6574 ---- buf_append_char (buf_to_net, '\''); buf_append_char (buf_to_net, '\n'); } + return 0; + } + + int server () + { + const char *log = CProtocolLibrary::GetEnvironment("CVS_SERVER_LOG"); + global_edit_bugnum_hack = 0; + global_editors_bugnum_hack = 0; + + if(!log) + { + static char logbuf[256]; + if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","ServerLogFile",logbuf,sizeof(logbuf))) + log = logbuf; + } + + /* Ignore argc and argv. They might be from .cvsrc. */ + if(!buf_to_net) + buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, outbuf_memory_error); + if(!buf_from_net) + buf_from_net = stdio_buffer_initialize (stdin, 1, outbuf_memory_error); + + use_sticky_tagname=0; + + /* Set up logfiles, if any. */ + if (log) + { + int len = strlen (log); + char *buf = (char*)xmalloc (len + 64); + char *p; + FILE *fp; + + sprintf(buf,"%s-%d",log,(int)getpid()); + p = buf + strlen(buf); + + /* Open logfiles in binary mode so that they reflect + exactly what was transmitted and received (that is + more important than that they be maximally + convenient to view). */ + strcpy (p, ".out"); + fp = open_file (buf, "wb"); + if (fp == NULL) + error (0, errno, "opening to-server logfile %s", buf); + else + buf_to_net = log_buffer_initialize (buf_to_net, fp, 0, + (BUFMEMERRPROC) NULL); + + strcpy (p, ".in"); + fp = open_file (buf, "wb"); + if (fp == NULL) + error (0, errno, "opening from-server logfile %s", buf); + else + buf_from_net = log_buffer_initialize (buf_from_net, fp, 1, + (BUFMEMERRPROC) NULL); + + xfree (buf); + } + + stdout_buf = cvs_protocol_wrap_buffer_initialize(buf_to_net, 'M'); + stderr_buf = cvs_protocol_wrap_buffer_initialize(buf_to_net, 'E'); + + TRACE(99,"Server start stuff"); + /* OK, now figure out where we stash our temporary files. */ + { + char *p; + + /* The code which wants to chdir into server_temp_dir is not set + up to deal with it being a relative path. So give an error + for that case. */ + if (!isabsolute (Tmpdir)) + { + error(1,0,"Value of %s for TMPDIR is not absolute", Tmpdir); + } + else + { + int status; + int i = 0; + + server_temp_dir = (char*)xmalloc (strlen (Tmpdir) + 256); + if (server_temp_dir == NULL) + { + error(1,ENOMEM,"Fatal server error, aborting."); + } + strcpy (server_temp_dir, Tmpdir); + + /* Remove a trailing slash from TMPDIR if present. */ + p = server_temp_dir + strlen (server_temp_dir) - 1; + if (*p == '/') + *p = '\0'; + + /* + * I wanted to use cvs-serv/PID, but then you have to worry about + * the permissions on the cvs-serv directory being right. So + * use cvs-servPID. + */ + strcat (server_temp_dir, "/cvs-serv"); + + p = server_temp_dir + strlen (server_temp_dir); + sprintf (p, "%ld", (long) getpid ()); + + orig_server_temp_dir = server_temp_dir; + + TRACE(3,"Server temp dir is %s",server_temp_dir); + + /* Create the temporary directory, and set the mode to + 700, to discourage random people from tampering with + it. */ + /* mkdir_p is a bad idea here as an incorrect server_temp_dir + could put a directory pretty much anywhere in error.. eg. trying + to create c:\windows\temp on Windows 7 for example. */ + while ((status = mkdir_p(server_temp_dir, 0777)) == EEXIST) // Was mkdir_p + { + 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) + { + error(1,errno,"can't create temporary directory %s",server_temp_dir); + } + #ifndef CHMOD_BROKEN + else if (chmod (server_temp_dir, S_IRWXU) < 0) + { + error(1,errno,"cannot change permissions on temporary directory %s", + fn_root(server_temp_dir)); + } + #endif + else if (CVS_CHDIR (server_temp_dir) < 0) + { + error(1,errno,"cannot change to temporary directory %s", + fn_root(server_temp_dir)); + } + #ifdef _WIN32 + if(!filenames_case_insensitive && __case_sensitive()>1) + add_to_ci_directory_list(server_temp_dir); + #endif + } + } + + TRACE(99,"Server register for signals"); + #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. */ + argument_vector_size = 1; + argument_vector = + (char **) xmalloc (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. + */ + TRACE(99,"Fatal server error, aborting. error ENOMEM Virtual memory exhausted."); + printf ("E Fatal server error, aborting.\nerror 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 + if(current_username) + xfree(current_username); + + CCvsgui::Close(EXIT_FAILURE); + exit (EXIT_FAILURE); + } + + 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] = strdup("cvs server"); + std::vector servercmnds; + scmdmtype servercmd_mode; + servercmd_mode = scmdmNormal; + servercmnds.clear(); + + // we have definitely authenticated - so try and set the force branch if we don't have one already + // eventually we should also have a 'default branch' option + if (g_force_branch==NULL) + g_force_branch=get_branch_force(); + + // it would be nice to have some options here for 'smart' force/default branch names, eg: + // g_force_branch=='__cvsbuiltin_server_branch' + // g_force_branch=='__cvsbuiltin_client_branch' + + + int times_through=0; + while (1) + { + char *cmd, *orig_cmd; + int status; + int servercmd_arg, servercmd_dir, servercmd_sticky, servercmd_entry, servercmd_entryx; + int servercmd_export, servercmd_rdiff, servercmd_log, servercmd_rlog, servercmd_diff, servercmd_update, servercmd_co; + times_through++; + + TRACE(99,"server: read a 'server line' from client - line %d.",times_through); + cmd=NULL; + status = server_read_line (buf_from_net, &cmd, (int *) NULL); + if (status == -2) + { + buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\ + error ENOMEM Virtual memory exhausted.\n"); + break; + } + TRACE(99,"server: read line status = %d cmd = '%s'.",status,(status==0)?PATCH_NULL(cmd):"bad status"); + if (status != 0) + break; + if(!*cmd) + continue; + + orig_cmd = cmd; + + // what I really need to do is 'bundle' all these requests together + // until I have a verb so I can decide what to do with the arguments + // + // Argument -d + // Argument -P + // Argument -I + // Argument ! . .. core RCSLOG tags TAGS RCS SCCS .make.state .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe *.dll *.pdb *.lib *.ncb *.ilk *.exp *.suo .DS_Store _$* *$ *.lo *.pch *.idb *.class ~* + // Argument -W + // Argument *.Z -k 'b' + // Argument -u + // Argument -- + // Directory . + // /cvs/cvsnt + // Sticky TCVSNT_BRANCH_2_5_03_2382:1.1.4.1 + // Entry /version.h/1.1.2.5/Wed Nov 16 23:52:57 2011//TCVSNT_BRANCH_2_5_03_2382 + // EntryExtra /version.h/////// + // Argument version.h + // update + // + if ( (g_force_branch) || ( g_anon_force_branch && g_is_anonymous ) ) + { + servercmd_arg=servercmd_dir=servercmd_sticky=servercmd_entry=servercmd_entryx=-1; + servercmd_export=servercmd_rdiff=servercmd_rlog=servercmd_log=servercmd_diff=servercmd_update=servercmd_co=0; + if ( ((servercmd_arg=strncmp(cmd,"Argument",8))==0) || + ( ((servercmd_dir=strncmp(cmd,"Directory",9))==0) && ((cmd[9]==' ')||(cmd[9]=='\0')) ) || + ((servercmd_sticky=strncmp(cmd,"Sticky",6))==0) || + ( ((servercmd_entry=strncmp(cmd,"Entry",5))==0) && ((cmd[5]==' ')||(cmd[5]=='\0')) ) || + ((servercmd_entryx=strncmp(cmd,"EntryExtra",10))==0) ) + { + TRACE(99,"Push back command=\"%s\".",cmd); + servercmd_mode = scmdmPushStore; + servercmnds.push_back(cmd); + if ((servercmd_dir==0)&& ((cmd[9]==' ')||(cmd[9]=='\0'))) + { + int servercmd_dir_status; + char *servercmd_dir_repos; + + servercmd_dir_status = server_read_line (buf_from_net, &servercmd_dir_repos, (int *) NULL); + TRACE(99,"Push back supplementary command=\"%s\".",cmd); + servercmnds.push_back(servercmd_dir_repos); + } + //TRACE(99,"Push --- flush buffers %s%s",(stderr_buf)?"stderr ":"",(stdout_buf)?"stdout ":""); + //buf_send_output(stderr_buf); + //buf_send_output(stdout_buf); + } + else + if ( ((servercmd_export=strncmp(cmd,"export",6))==0) || + ((servercmd_rdiff=strncmp(cmd,"rdiff",5))==0) || + ((servercmd_log=strncmp(cmd,"log",3))==0) || + ((servercmd_rlog=strncmp(cmd,"rlog",4))==0) || + ((servercmd_diff=strncmp(cmd,"diff",4))==0) || + ((servercmd_update=strncmp(cmd,"update",6))==0) || + ((servercmd_co=strncmp(cmd,"co",2))==0) ) { + + + int servercmd_delete; + int servercmd_insert; + bool servercmd_branch; + /* now we traverse the stored commands looking for this we may need to 'fix' */ + servercmd_delete=-1; + servercmd_insert=-1; + servercmd_branch=false; + for (int scmdj = 0; scmdj < servercmnds.size(); scmdj++) + { + TRACE(99,"inspect command=\"%s\".",servercmnds[scmdj].c_str()); + if (strncmp(servercmnds[scmdj].c_str(),"Sticky",6)==0) + { + cvs::string branchtest, tagtest; + cvs::string stickyfix; + TRACE(99,"inspect sticky command=\"%s\".",servercmnds[scmdj].c_str()); + + cvs::sprintf(tagtest, 256, "Sticky N%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + cvs::sprintf(branchtest, 256, "Sticky T%s:",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + if ( (tagtest.compare(servercmnds[scmdj].c_str()) != 0) && + (branchtest.compare(servercmnds[scmdj].c_str()) != 0) ) + { + // need to ignore this or replace it with what we'd prefer... + TRACE(99,"inspected sticky command=\"%s\" must be deleted or replaced.",servercmnds[scmdj].c_str()); + //servercmd_delete=scmdj; + servercmd_branch=true; + cvs::sprintf(stickyfix, 256, "Sticky N%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + TRACE(99,"replacing sticky with \"%s\".",stickyfix.c_str()); + servercmnds[scmdj]=stickyfix.c_str(); + } + } + else + if (strncmp(servercmnds[scmdj].c_str(),"Argument",8)==0) + { + cvs::string argumentfix; + if (strstr(servercmnds[scmdj].c_str(),"-r:")!=NULL) { + TRACE(99,"Here is =\"%s\" but we really want to set argument -r %s:%s.",servercmnds[scmdj].c_str(),( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch,( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + cvs::sprintf(argumentfix, 256, "Argument -r%s:%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch,( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + servercmnds[scmdj]=argumentfix.c_str(); + servercmd_branch=true; + } + else + if ( (strstr(servercmnds[scmdj].c_str(),"-r")!=NULL) && ((servercmd_export==0||servercmd_co==0)) ) { + TRACE(99,"Here is =\"%s\" [co] (%s) but we really want to set argument %s.",servercmnds[scmdj].c_str(),servercmnds[scmdj+1].c_str(),( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + cvs::sprintf(argumentfix, 256, "Argument %s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + servercmnds[scmdj+1]=argumentfix.c_str(); + servercmd_branch=true; + } + else + if (strstr(servercmnds[scmdj].c_str(),"-r")!=NULL) { + TRACE(99,"Here is [non co] =\"%s\" (%s) but we really want to set argument %s.",servercmnds[scmdj].c_str(),servercmnds[scmdj+2].c_str(),( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + cvs::sprintf(argumentfix, 256, "Argument %s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + servercmnds[scmdj+2]=argumentfix.c_str(); + servercmd_branch=true; + } + else + if ( ((strstr(servercmnds[scmdj].c_str(),"-D")!=NULL) && (servercmd_co==0||servercmd_diff==0||servercmd_rdiff==0||servercmd_export==0||servercmd_update==0)) + || ((strstr(servercmnds[scmdj].c_str(),"-d")!=NULL) && (servercmd_log==0||servercmd_rlog==0)) ) { + TRACE(99,"Here is date \"%s\" but we really want to set argument -r %s:%s.",servercmnds[scmdj].c_str(),( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch,( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + cvs::sprintf(argumentfix, 256, "Argument -r%s:%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch,( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + servercmnds[scmdj]=argumentfix.c_str(); + servercmd_branch=true; + } + else + if (servercmd_insert==-1) servercmd_insert=scmdj; + } + } + if (servercmd_delete!=-1) + { + TRACE(99,"Delete playback item %d, \"%s\".",servercmd_delete,servercmnds[servercmd_delete].c_str()); + servercmnds.erase(servercmnds.begin()+servercmd_delete); + } + if (!servercmd_branch) + { + if (servercmd_insert==-1) + servercmd_insert=servercmnds.size()-1; + + cvs::string argumentinsert; + TRACE(99,"Insert playback item %d, \"%s\".",servercmd_insert,(servercmd_update==0)?"Sticky":"Argument -r"); + if (servercmd_update==0) + cvs::sprintf(argumentinsert, 256, "Sticky N%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + else + if (servercmd_export==0||servercmd_co==0) + { + cvs::sprintf(argumentinsert, 256, "Argument %s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + TRACE(99,"Insert \"%s\".",argumentinsert.c_str()); + servercmnds.insert(servercmnds.begin()+servercmd_insert,argumentinsert.c_str()); + cvs::sprintf(argumentinsert, 256, "Argument -r"); + } + else + cvs::sprintf(argumentinsert, 256, "Argument -r%s:%s",( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch,( g_anon_force_branch && g_is_anonymous )?g_anon_force_branch:g_force_branch); + TRACE(99,"Insert \"%s\".",argumentinsert.c_str()); + servercmnds.insert(servercmnds.begin()+servercmd_insert,argumentinsert.c_str()); + } + servercmd_mode = scmdmReplay; + } + else + // So things like this would be just 'passed': + // + // Valid-responses + // valid-requests + // UseUnchanged + // Root /cvs + // server-codepage + // client-version + // Valid-RcsOptions + // read-cvsignore + // read-cvswrappers + // read-cvsrc2 + // + servercmd_mode = scmdmReplay; + + if (servercmd_mode == scmdmReplay) + { + /* now we unravel the stored commands */ + TRACE(99,"Playback %lu verbs.",(unsigned long)servercmnds.size()); + for (int scmdi = 0; scmdi < servercmnds.size(); scmdi++) + { + cmd=xstrdup(servercmnds[scmdi].c_str()); + if ( ((strncmp(cmd,"Directory",9))==0) && ((cmd[9]==' ')||(cmd[9]=='\0')) ) + { + char *repos=xstrdup(servercmnds[++scmdi].c_str()); + char *cmdarg= (*(cmd+9)=='\0')?(cmd+9):(cmd+10); + TRACE(99,"play Directory %s and supplementary=\"%s\".",cmdarg,repos); + serve_directory_repos (cmdarg, repos, 0); + } + else + { + TRACE(99,"play command=\"%s\".",cmd); + servergo(cmd); + } + } + servercmnds.clear(); + servercmd_mode = scmdmNormal; + cmd=orig_cmd; + } + } + if (servercmd_mode == scmdmNormal) + { + TRACE(99,"process in realtime command=\"%s\".",cmd); + servergo(cmd); + } + xfree (orig_cmd); } *************** *** 6508,6514 **** CVS_Username = xstrdup(username); #endif #endif ! #if HAVE_PUTENV /* Set LOGNAME, USER and CVS_USER in the environment, in case they are already set to something else. */ --- 6748,6760 ---- CVS_Username = xstrdup(username); #endif #endif ! ! g_is_anonymous=0; ! if ((CVS_Username != NULL) && (g_anonymous_user != NULL)) ! if ((*CVS_Username != '\0') && (*g_anonymous_user != '\0')) ! if (strcmp(CVS_Username, g_anonymous_user)==0) ! g_is_anonymous=1; ! #if HAVE_PUTENV /* Set LOGNAME, USER and CVS_USER in the environment, in case they are already set to something else. */ *************** *** 6573,6578 **** --- 6819,6830 ---- /* Make sure our CVS_Username has been set. */ if (CVS_Username == NULL) CVS_Username = xstrdup(username); + + g_is_anonymous=0; + if ((CVS_Username != NULL) && (g_anonymous_user != NULL)) + if ((*CVS_Username != '\0') && (*g_anonymous_user != '\0')) + if (strcmp(CVS_Username, g_anonymous_user)==0) + g_is_anonymous=1; #endif #ifdef HAVE_PUTENV *************** *** 7016,7021 **** --- 7268,7278 ---- /* Set CVS_Username here, in allocated space. It might or might not be the same as host_user. */ CVS_Username = xstrdup(username); + g_is_anonymous=0; + if ((CVS_Username != NULL) && (g_anonymous_user != NULL)) + if ((*CVS_Username != '\0') && (*g_anonymous_user != '\0')) + if (strcmp(CVS_Username, g_anonymous_user)==0) + g_is_anonymous=1; } return host_user; *************** *** 7223,7228 **** --- 7480,7490 ---- else CVS_Username = xstrdup(getcaller()); TRACE(4,"Set CVS Username to \"%s\"",PATCH_NULL(CVS_Username)); + g_is_anonymous=0; + if ((CVS_Username != NULL) && (g_anonymous_user != NULL)) + if ((*CVS_Username != '\0') && (*g_anonymous_user != '\0')) + if (strcmp(CVS_Username, g_anonymous_user)==0) + g_is_anonymous=1; } else TRACE(4,"Has CVS Username"); *************** *** 7308,7313 **** --- 7570,7580 ---- } CVS_Username = xstrdup((const char *)&buf[1]); + g_is_anonymous=0; + if ((CVS_Username != NULL) && (g_anonymous_user != NULL)) + if ((*CVS_Username != '\0') && (*g_anonymous_user != '\0')) + if (strcmp(CVS_Username, g_anonymous_user)==0) + g_is_anonymous=1; xfree(buf); Index: doc/PServer.example =================================================================== RCS file: /cvs/cvsnt/doc/PServer.example,v retrieving revision 1.2.2.27.6.16 diff -c -r1.2.2.27.6.16 PServer.example *** doc/PServer.example 22 Dec 2011 07:38:55 -0000 1.2.2.27.6.16 --- doc/PServer.example 9 Oct 2012 02:37:58 -0000 *************** *** 240,245 **** --- 240,250 ---- #RemoteInitRoot=/var/tmp/repos # + # AnonForceBranch The Anonymouse user must use this branch/tag. + # + #AnonForceBranch= + + # # AnonymousUsername Username that anonymous logins are allowed with, if any. # #AnonymousUsername=cvs