Home | History | Annotate | Line # | Download | only in src
      1 /* This program is free software; you can redistribute it and/or modify
      2    it under the terms of the GNU General Public License as published by
      3    the Free Software Foundation; either version 2, or (at your option)
      4    any later version.
      5 
      6    This program is distributed in the hope that it will be useful,
      7    but WITHOUT ANY WARRANTY; without even the implied warranty of
      8    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      9    GNU General Public License for more details.  */
     10 #include <sys/cdefs.h>
     11 __RCSID("$NetBSD: server.c,v 1.8 2016/05/17 14:00:09 christos Exp $");
     12 
     13 #include "cvs.h"
     14 
     15 /* CVS */
     16 #include "edit.h"
     17 #include "fileattr.h"
     18 #include "watch.h"
     19 
     20 /* GNULIB */
     21 #include "buffer.h"
     22 #include "getline.h"
     23 #include "getnline.h"
     24 
     25 int server_active = 0;
     26 
     27 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
     28 
     29 # include "log-buffer.h"
     30 # include "ms-buffer.h"
     31 #endif	/* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */
     32 
     33 #if defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT)
     34 # include "canon-host.h"
     35 # include "gssapi-client.h"
     36 
     37 /* This stuff isn't included solely with SERVER_SUPPORT since some of these
     38  * functions (encryption & the like) get compiled with or without server
     39  * support.
     40  *
     41  * FIXME - They should be in a different file.
     42  */
     43 /* We use Kerberos 5 routines to map the GSSAPI credential to a user
     44    name.  */
     45 # include <krb5.h>
     46 
     47 static void gserver_authenticate_connection (void);
     48 
     49 /* Whether we are already wrapping GSSAPI communication.  */
     50 static int cvs_gssapi_wrapping;
     51 
     52 #endif	/* defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT) */
     53 
     54 #ifdef SERVER_SUPPORT
     55 
     56 extern char *server_hostname;
     57 
     58 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
     59 #   include <sys/socket.h>
     60 # endif
     61 
     62 # ifdef HAVE_SYSLOG_H
     63 #   include <syslog.h>
     64 #   ifndef LOG_DAEMON   /* for ancient syslogs */
     65 #     define LOG_DAEMON 0
     66 #   endif
     67 # endif /* HAVE_SYSLOG_H */
     68 
     69 # ifdef HAVE_KERBEROS
     70 #   include <netinet/in.h>
     71 #   include <krb.h>
     72 #   ifndef HAVE_KRB_GET_ERR_TEXT
     73 #     define krb_get_err_text(status) krb_err_txt[status]
     74 #   endif
     75 
     76 /* Information we need if we are going to use Kerberos encryption.  */
     77 static C_Block kblock;
     78 static Key_schedule sched;
     79 
     80 # endif /* HAVE_KERBEROS */
     81 
     82 /* for select */
     83 # include "xselect.h"
     84 
     85 # ifndef O_NONBLOCK
     86 #   define O_NONBLOCK O_NDELAY
     87 # endif
     88 
     89 /* For initgroups().  */
     90 # if HAVE_INITGROUPS
     91 #   include <grp.h>
     92 # endif /* HAVE_INITGROUPS */
     93 
     94 # ifdef AUTH_SERVER_SUPPORT
     95 
     96 #   ifdef HAVE_GETSPNAM
     97 #     include <shadow.h>
     98 #   endif
     99 
    100 /* The cvs username sent by the client, which might or might not be
    101    the same as the system username the server eventually switches to
    102    run as.  CVS_Username gets set iff password authentication is
    103    successful. */
    104 char *CVS_Username = NULL;
    105 
    106 /* Used to check that same repos is transmitted in pserver auth and in
    107    later CVS protocol.  Exported because root.c also uses. */
    108 static char *Pserver_Repos = NULL;
    109 
    110 # endif /* AUTH_SERVER_SUPPORT */
    111 
    112 # ifdef HAVE_PAM
    113 #   if defined(HAVE_SECURITY_PAM_APPL_H)
    114 #     include <security/pam_appl.h>
    115 #   elif defined(HAVE_PAM_PAM_APPL_H)
    116 #     include <pam/pam_appl.h>
    117 #   endif
    118 
    119 static pam_handle_t *pamh = NULL;
    120 
    121 static char *pam_username;
    122 static char *pam_password;
    123 # endif /* HAVE_PAM */
    124 
    125 
    126 
    127 /* While processing requests, this buffer accumulates data to be sent to
    128    the client, and then once we are in do_cvs_command, we use it
    129    for all the data to be sent.  */
    130 static struct buffer *buf_to_net;
    131 
    132 /* This buffer is used to read input from the client.  */
    133 static struct buffer *buf_from_net;
    134 
    135 
    136 
    137 # ifdef PROXY_SUPPORT
    138 /* These are the secondary log buffers so that we can disable them after
    139  * creation, when it is determined that they are unneeded, regardless of what
    140  * other filters have been prepended to the buffer chain.
    141  */
    142 static struct buffer *proxy_log;
    143 static struct buffer *proxy_log_out;
    144 
    145 /* Set while we are reprocessing a log so that we can avoid sending responses
    146  * to some requests twice.
    147  */
    148 static bool reprocessing;
    149 # endif /* PROXY_SUPPORT */
    150 
    151 
    152 
    153 /* Arguments storage for `Argument' & `Argumentx' requests.  */
    154 static int argument_count;
    155 static char **argument_vector;
    156 static int argument_vector_size;
    157 
    158 #define MAXARGS 1000000		/* arbitrary limit */
    159 
    160 /*
    161  * This is where we stash stuff we are going to use.  Format string
    162  * which expects a single directory within it, starting with a slash.
    163  */
    164 static char *server_temp_dir;
    165 
    166 /* This is the original value of server_temp_dir, before any possible
    167    changes inserted by serve_max_dotdot.  */
    168 static char *orig_server_temp_dir;
    169 
    170 /* Nonzero if we should keep the temp directory around after we exit.  */
    171 static int dont_delete_temp;
    172 
    173 static void server_write_entries (void);
    174 
    175 cvsroot_t *referrer;
    176 
    177 
    178 
    179 /* Populate all of the directories between BASE_DIR and its relative
    180    subdirectory DIR with CVSADM directories.  Return 0 for success or
    181    errno value.  */
    182 static int
    183 create_adm_p (char *base_dir, char *dir)
    184 {
    185     char *dir_where_cvsadm_lives, *dir_to_register, *p, *tmp;
    186     int retval, done;
    187     FILE *f;
    188 
    189     if (strcmp (dir, ".") == 0)
    190 	return 0;			/* nothing to do */
    191 
    192     /* Allocate some space for our directory-munging string. */
    193     p = xmalloc (strlen (dir) + 1);
    194     if (p == NULL)
    195 	return ENOMEM;
    196 
    197     dir_where_cvsadm_lives = xmalloc (strlen (base_dir) + strlen (dir) + 100);
    198     if (dir_where_cvsadm_lives == NULL)
    199     {
    200 	free (p);
    201 	return ENOMEM;
    202     }
    203 
    204     /* Allocate some space for the temporary string in which we will
    205        construct filenames. */
    206     tmp = xmalloc (strlen (base_dir) + strlen (dir) + 100);
    207     if (tmp == NULL)
    208     {
    209 	free (p);
    210 	free (dir_where_cvsadm_lives);
    211 	return ENOMEM;
    212     }
    213 
    214 
    215     /* We make several passes through this loop.  On the first pass,
    216        we simply create the CVSADM directory in the deepest directory.
    217        For each subsequent pass, we try to remove the last path
    218        element from DIR, create the CVSADM directory in the remaining
    219        pathname, and register the subdirectory in the newly created
    220        CVSADM directory. */
    221 
    222     retval = done = 0;
    223 
    224     strcpy (p, dir);
    225     strcpy (dir_where_cvsadm_lives, base_dir);
    226     strcat (dir_where_cvsadm_lives, "/");
    227     strcat (dir_where_cvsadm_lives, p);
    228     dir_to_register = NULL;
    229 
    230     while (1)
    231     {
    232 	/* Create CVSADM. */
    233 	(void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM);
    234 	if ((CVS_MKDIR (tmp, 0777) < 0) && (errno != EEXIST))
    235 	{
    236 	    retval = errno;
    237 	    goto finish;
    238 	}
    239 
    240 	/* Create CVSADM_REP. */
    241 	(void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_REP);
    242 	if (! isfile (tmp))
    243 	{
    244 	    /* Use Emptydir as the placeholder until the client sends
    245 	       us the real value.  This code is similar to checkout.c
    246 	       (emptydir_name), but the code below returns errors
    247 	       differently.  */
    248 
    249 	    char *empty;
    250 	    empty = xmalloc (strlen (current_parsed_root->directory)
    251 			    + sizeof (CVSROOTADM)
    252 			    + sizeof (CVSNULLREPOS)
    253 			    + 3);
    254 	    if (! empty)
    255 	    {
    256 		retval = ENOMEM;
    257 		goto finish;
    258 	    }
    259 
    260 	    /* Create the directory name. */
    261 	    (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory,
    262 			    CVSROOTADM, CVSNULLREPOS);
    263 
    264 	    /* Create the directory if it doesn't exist. */
    265 	    if (! isfile (empty))
    266 	    {
    267 		mode_t omask;
    268 		omask = umask (cvsumask);
    269 		if (CVS_MKDIR (empty, 0777) < 0)
    270 		{
    271 		    retval = errno;
    272 		    free (empty);
    273 		    goto finish;
    274 		}
    275 		(void) umask (omask);
    276 	    }
    277 
    278 	    f = CVS_FOPEN (tmp, "w");
    279 	    if (f == NULL)
    280 	    {
    281 		retval = errno;
    282 		free (empty);
    283 		goto finish;
    284 	    }
    285 	    /* Write the directory name to CVSADM_REP. */
    286 	    if (fprintf (f, "%s\n", empty) < 0)
    287 	    {
    288 		retval = errno;
    289 		fclose (f);
    290 		free (empty);
    291 		goto finish;
    292 	    }
    293 	    if (fclose (f) == EOF)
    294 	    {
    295 		retval = errno;
    296 		free (empty);
    297 		goto finish;
    298 	    }
    299 
    300 	    /* Clean up after ourselves. */
    301 	    free (empty);
    302 	}
    303 
    304 	/* Create CVSADM_ENT.  We open in append mode because we
    305 	   don't want to clobber an existing Entries file.  */
    306 	(void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_ENT);
    307 	f = CVS_FOPEN (tmp, "a");
    308 	if (f == NULL)
    309 	{
    310 	    retval = errno;
    311 	    goto finish;
    312 	}
    313 	if (fclose (f) == EOF)
    314 	{
    315 	    retval = errno;
    316 	    goto finish;
    317 	}
    318 
    319 	if (dir_to_register != NULL)
    320 	{
    321 	    /* FIXME: Yes, this results in duplicate entries in the
    322 	       Entries.Log file, but it doesn't currently matter.  We
    323 	       might need to change this later on to make sure that we
    324 	       only write one entry.  */
    325 
    326 	    Subdir_Register (NULL, dir_where_cvsadm_lives, dir_to_register);
    327 	}
    328 
    329 	if (done)
    330 	    break;
    331 
    332 	dir_to_register = strrchr (p, '/');
    333 	if (dir_to_register == NULL)
    334 	{
    335 	    dir_to_register = p;
    336 	    strcpy (dir_where_cvsadm_lives, base_dir);
    337 	    done = 1;
    338 	}
    339 	else
    340 	{
    341 	    *dir_to_register = '\0';
    342 	    dir_to_register++;
    343 	    strcpy (dir_where_cvsadm_lives, base_dir);
    344 	    strcat (dir_where_cvsadm_lives, "/");
    345 	    strcat (dir_where_cvsadm_lives, p);
    346 	}
    347     }
    348 
    349   finish:
    350     free (tmp);
    351     free (dir_where_cvsadm_lives);
    352     free (p);
    353     return retval;
    354 }
    355 
    356 
    357 
    358 /*
    359  * Make directory DIR, including all intermediate directories if necessary.
    360  * Returns 0 for success or errno code.
    361  */
    362 static int
    363 mkdir_p (char *dir)
    364 {
    365     char *p;
    366     char *q = xmalloc (strlen (dir) + 1);
    367     int retval;
    368 
    369     if (q == NULL)
    370 	return ENOMEM;
    371 
    372     retval = 0;
    373 
    374     /*
    375      * Skip over leading slash if present.  We won't bother to try to
    376      * make '/'.
    377      */
    378     p = dir + 1;
    379     while (1)
    380     {
    381 	while (*p != '/' && *p != '\0')
    382 	    ++p;
    383 	if (*p == '/')
    384 	{
    385 	    strncpy (q, dir, p - dir);
    386 	    q[p - dir] = '\0';
    387 	    if (q[p - dir - 1] != '/'  &&  CVS_MKDIR (q, 0777) < 0)
    388 	    {
    389 		int saved_errno = errno;
    390 
    391 		if (saved_errno != EEXIST
    392 		    && ((saved_errno != EACCES && saved_errno != EROFS)
    393 			|| !isdir (q)))
    394 		{
    395 		    retval = saved_errno;
    396 		    goto done;
    397 		}
    398 	    }
    399 	    ++p;
    400 	}
    401 	else
    402 	{
    403 	    if (CVS_MKDIR (dir, 0777) < 0)
    404 		retval = errno;
    405 	    goto done;
    406 	}
    407     }
    408   done:
    409     free (q);
    410     return retval;
    411 }
    412 
    413 
    414 
    415 /*
    416  * Print the error response for error code STATUS.  The caller is
    417  * reponsible for making sure we get back to the command loop without
    418  * any further output occuring.
    419  * Must be called only in contexts where it is OK to send output.
    420  */
    421 static void
    422 print_error (int status)
    423 {
    424     char *msg;
    425     char tmpstr[80];
    426 
    427     buf_output0 (buf_to_net, "error  ");
    428     msg = strerror (status);
    429     if (msg == NULL)
    430     {
    431        sprintf (tmpstr, "unknown error %d", status);
    432        msg = tmpstr;
    433     }
    434     buf_output0 (buf_to_net, msg);
    435     buf_append_char (buf_to_net, '\n');
    436 
    437     buf_flush (buf_to_net, 0);
    438 }
    439 
    440 
    441 
    442 static int pending_error;
    443 /*
    444  * Malloc'd text for pending error.  Each line must start with "E ".  The
    445  * last line should not end with a newline.
    446  */
    447 static char *pending_error_text;
    448 static char *pending_warning_text;
    449 
    450 /* If an error is pending, print it and return 1.  If not, return 0.
    451    Also prints pending warnings, but this does not affect the return value.
    452    Must be called only in contexts where it is OK to send output.  */
    453 static int
    454 print_pending_error (void)
    455 {
    456     /* Check this case first since it usually means we are out of memory and
    457      * the buffer output routines might try and allocate memory.
    458      */
    459     if (!pending_error_text && pending_error)
    460     {
    461 	print_error (pending_error);
    462 	pending_error = 0;
    463 	return 1;
    464     }
    465 
    466     if (pending_warning_text)
    467     {
    468 	buf_output0 (buf_to_net, pending_warning_text);
    469 	buf_append_char (buf_to_net, '\n');
    470 	buf_flush (buf_to_net, 0);
    471 
    472 	free (pending_warning_text);
    473 	pending_warning_text = NULL;
    474     }
    475 
    476     if (pending_error_text)
    477     {
    478 	buf_output0 (buf_to_net, pending_error_text);
    479 	buf_append_char (buf_to_net, '\n');
    480 	if (pending_error)
    481 	    print_error (pending_error);
    482 	else
    483 	    buf_output0 (buf_to_net, "error  \n");
    484 
    485 	buf_flush (buf_to_net, 0);
    486 
    487 	pending_error = 0;
    488 	free (pending_error_text);
    489 	pending_error_text = NULL;
    490 	return 1;
    491     }
    492 
    493     return 0;
    494 }
    495 
    496 
    497 
    498 /* Is an error pending?  */
    499 # define error_pending() (pending_error || pending_error_text)
    500 # define warning_pending() (pending_warning_text)
    501 
    502 /* Allocate SIZE bytes for pending_error_text and return nonzero
    503    if we could do it.  */
    504 static inline int
    505 alloc_pending_internal (char **dest, size_t size)
    506 {
    507     *dest = malloc (size);
    508     if (!*dest)
    509     {
    510 	pending_error = ENOMEM;
    511 	return 0;
    512     }
    513     return 1;
    514 }
    515 
    516 
    517 
    518 /* Allocate SIZE bytes for pending_error_text and return nonzero
    519    if we could do it.  */
    520 static int
    521 alloc_pending (size_t size)
    522 {
    523     if (error_pending ())
    524 	/* Probably alloc_pending callers will have already checked for
    525 	   this case.  But we might as well handle it if they don't, I
    526 	   guess.  */
    527 	return 0;
    528     return alloc_pending_internal (&pending_error_text, size);
    529 }
    530 
    531 
    532 
    533 /* Allocate SIZE bytes for pending_error_text and return nonzero
    534    if we could do it.  */
    535 static int
    536 alloc_pending_warning (size_t size)
    537 {
    538     if (warning_pending ())
    539 	/* Warnings can be lost here.  */
    540 	return 0;
    541     return alloc_pending_internal (&pending_warning_text, size);
    542 }
    543 
    544 
    545 
    546 static int
    547 supported_response (char *name)
    548 {
    549     struct response *rs;
    550 
    551     for (rs = responses; rs->name != NULL; ++rs)
    552 	if (strcmp (rs->name, name) == 0)
    553 	    return rs->status == rs_supported;
    554     error (1, 0, "internal error: testing support for unknown response?");
    555     /* NOTREACHED */
    556     return 0;
    557 }
    558 
    559 
    560 
    561 /*
    562  * Return true if we need to relay write requests to a primary server
    563  * and false otherwise.
    564  *
    565  * NOTES
    566  *
    567  *   - primarily handles :ext: method as this seems most likely to be used in
    568  *     practice.
    569  *
    570  *   - :fork: method is handled for testing.
    571  *
    572  *   - Could handle pserver too, but would have to store the password
    573  *     the client sent us.
    574  *
    575  *
    576  * GLOBALS
    577  *   config->PrimaryServer
    578  *                        The parsed setting from CVSROOT/config, if any, or
    579  *                        NULL, otherwise.
    580  *   current_parsed_root  The current repository.
    581  *
    582  * RETURNS
    583  *   true                 If this server is configured as a secondary server.
    584  *   false                Otherwise.
    585  */
    586 static inline bool
    587 isProxyServer (void)
    588 {
    589     /***
    590      *** The following is done as a series of if/return combinations an an
    591      *** optimization.
    592      ***/
    593 
    594     /* If there is no primary server defined in CVSROOT/config, then we can't
    595      * be a secondary.
    596      */
    597     if (!config || !config->PrimaryServer) return false;
    598 
    599     /* The directory must not match for all methods.  */
    600     if (current_parsed_root && !isSamePath (config->PrimaryServer->directory,
    601 		     current_parsed_root->directory))
    602 	return true;
    603 
    604     /* Only the directory is important for fork.  */
    605     if (config->PrimaryServer->method == fork_method)
    606 	return false;
    607 
    608     /* Must be :ext: method, then.  This is enforced when CVSROOT/config is
    609      * parsed.
    610      */
    611     assert (config->PrimaryServer->isremote);
    612 
    613     if (isThisHost (config->PrimaryServer->hostname))
    614 	return false;
    615 
    616     return true;
    617 }
    618 
    619 
    620 
    621 static void
    622 serve_valid_responses (char *arg)
    623 {
    624     char *p = arg;
    625     char *q;
    626     struct response *rs;
    627 
    628 # ifdef PROXY_SUPPORT
    629     /* Process this in the first pass since the data it gathers can be used
    630      * prior to a `Root' request.
    631      */
    632     if (reprocessing) return;
    633 # endif /* PROXY_SUPPORT */
    634 
    635     do
    636     {
    637 	q = strchr (p, ' ');
    638 	if (q != NULL)
    639 	    *q++ = '\0';
    640 	for (rs = responses; rs->name != NULL; ++rs)
    641 	{
    642 	    if (strcmp (rs->name, p) == 0)
    643 		break;
    644 	}
    645 	if (rs->name == NULL)
    646 	    /*
    647 	     * It is a response we have never heard of (and thus never
    648 	     * will want to use).  So don't worry about it.
    649 	     */
    650 	    ;
    651 	else
    652 	    rs->status = rs_supported;
    653 	p = q;
    654     } while (q != NULL);
    655     for (rs = responses; rs->name != NULL; ++rs)
    656     {
    657 	if (rs->status == rs_essential)
    658 	{
    659 	    buf_output0 (buf_to_net, "E response `");
    660 	    buf_output0 (buf_to_net, rs->name);
    661 	    buf_output0 (buf_to_net, "' not supported by client\nerror  \n");
    662 
    663 	    /* FIXME: This call to buf_flush could conceivably
    664 	       cause deadlock, as noted in server_cleanup.  */
    665 	    buf_flush (buf_to_net, 1);
    666 
    667 	    exit (EXIT_FAILURE);
    668 	}
    669 	else if (rs->status == rs_optional)
    670 	    rs->status = rs_not_supported;
    671     }
    672 }
    673 
    674 
    675 
    676 /*
    677  * Process IDs of the subprocess, or negative if that subprocess
    678  * does not exist.
    679  */
    680 static pid_t command_pid;
    681 
    682 static void
    683 outbuf_memory_error (struct buffer *buf)
    684 {
    685     static const char msg[] = "E Fatal server error\n\
    686 error ENOMEM Virtual memory exhausted.\n";
    687     if (command_pid > 0)
    688 	kill (command_pid, SIGTERM);
    689 
    690     /*
    691      * We have arranged things so that printing this now either will
    692      * be valid, or the "E fatal error" line will get glommed onto the
    693      * end of an existing "E" or "M" response.
    694      */
    695 
    696     /* If this gives an error, not much we could do.  syslog() it?  */
    697     if (write (STDOUT_FILENO, msg, sizeof (msg) - 1) == -1)
    698     	exit(EXIT_FAILURE);
    699 # ifdef HAVE_SYSLOG_H
    700     syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted");
    701 # endif /* HAVE_SYSLOG_H */
    702     exit (EXIT_FAILURE);
    703 }
    704 
    705 
    706 
    707 static void
    708 input_memory_error (struct buffer *buf)
    709 {
    710     outbuf_memory_error (buf);
    711 }
    712 
    713 
    714 
    715 # ifdef PROXY_SUPPORT
    716 /* This function rewinds the net connection using the write proxy log file.
    717  *
    718  * GLOBALS
    719  *   proxy_log	The buffer object containing the write proxy log.
    720  *
    721  * RETURNS
    722  *   Nothing.
    723  */
    724 static void
    725 rewind_buf_from_net (void)
    726 {
    727     struct buffer *log;
    728 
    729     assert (proxy_log);
    730 
    731     /* Free the arguments since we processed some of them in the first pass.
    732      */
    733     {
    734 	/* argument_vector[0] is a dummy argument, we don't mess with
    735 	 * it.
    736 	 */
    737 	char **cp;
    738 	for (cp = argument_vector + 1;
    739 	     cp < argument_vector + argument_count;
    740 	     ++cp)
    741 	    free (*cp);
    742 
    743 	argument_count = 1;
    744     }
    745 
    746     log = log_buffer_rewind (proxy_log);
    747     proxy_log = NULL;
    748     /* Dispose of any read but unused data in the net buffer since it will
    749      * already be in the log.
    750      */
    751     buf_free_data (buf_from_net);
    752     buf_from_net = ms_buffer_initialize (outbuf_memory_error, log,
    753 					 buf_from_net);
    754     reprocessing = true;
    755 }
    756 # endif /* PROXY_SUPPORT */
    757 
    758 
    759 
    760 char *gConfigPath;
    761 
    762 
    763 
    764 /*
    765  * This request cannot be ignored by a potential secondary since it is used to
    766  * determine if we _are_ a secondary.
    767  */
    768 static void
    769 serve_root (char *arg)
    770 {
    771     char *path;
    772 
    773     TRACE (TRACE_FUNCTION, "serve_root (%s)", arg ? arg : "(null)");
    774 
    775     /* Don't process this twice or when errors are pending.  */
    776     if (error_pending()
    777 # ifdef PROXY_SUPPORT
    778 	|| reprocessing
    779 # endif /* PROXY_SUPPORT */
    780        ) return;
    781 
    782     if (!ISABSOLUTE (arg))
    783     {
    784 	if (alloc_pending (80 + strlen (arg)))
    785 	    sprintf (pending_error_text,
    786 		     "E Root %s must be an absolute pathname", arg);
    787 	return;
    788     }
    789 
    790     /* Sending "Root" twice is invalid.
    791 
    792        The other way to handle a duplicate Root requests would be as a
    793        request to clear out all state and start over as if it was a
    794        new connection.  Doing this would cause interoperability
    795        headaches, so it should be a different request, if there is
    796        any reason why such a feature is needed.  */
    797     if (current_parsed_root != NULL)
    798     {
    799 	if (alloc_pending (80 + strlen (arg)))
    800 	    sprintf (pending_error_text,
    801 		     "E Protocol error: Duplicate Root request, for %s", arg);
    802 	return;
    803     }
    804 
    805     /* Set original_parsed_root here, not because it can be changed in the
    806      * client Redirect sense, but so we don't have to switch in code that
    807      * runs in both modes to decide which to print.
    808      */
    809     original_parsed_root = current_parsed_root = local_cvsroot (arg);
    810 
    811 # ifdef AUTH_SERVER_SUPPORT
    812     if (Pserver_Repos != NULL)
    813     {
    814 	if (strcmp (Pserver_Repos, current_parsed_root->directory) != 0)
    815 	{
    816 	    if (alloc_pending (80 + strlen (Pserver_Repos)
    817 			       + strlen (current_parsed_root->directory)))
    818 		/* The explicitness is to aid people who are writing clients.
    819 		   I don't see how this information could help an
    820 		   attacker.  */
    821 		sprintf (pending_error_text, "\
    822 E Protocol error: Root says \"%s\" but pserver says \"%s\"",
    823 			 current_parsed_root->directory, Pserver_Repos);
    824 	    return;
    825 	}
    826     }
    827 # endif
    828 
    829     /* For pserver, this will already have happened, and the call will do
    830        nothing.  But for rsh, we need to do it now.  */
    831     config = get_root_allow_config (current_parsed_root->directory,
    832 				    gConfigPath);
    833 
    834 # ifdef PROXY_SUPPORT
    835     /* At this point we have enough information to determine if we are a
    836      * secondary server or not.
    837      */
    838     if (proxy_log && !isProxyServer ())
    839     {
    840 	/* Else we are not a secondary server.  There is no point in
    841 	 * reprocessing since we handle all the requests we can receive
    842 	 * before `Root' as we receive them.  But close the logs.
    843 	 */
    844 	log_buffer_closelog (proxy_log);
    845 	log_buffer_closelog (proxy_log_out);
    846 	proxy_log = NULL;
    847 	/*
    848 	 * Don't need this.  We assume it when proxy_log == NULL.
    849 	 *
    850 	 *   proxy_log_out = NULL;
    851 	 */
    852     }
    853 # endif /* PROXY_SUPPORT */
    854 
    855     /* Now set the TMPDIR environment variable.  If it was set in the config
    856      * file, we now know it.
    857      */
    858     push_env_temp_dir ();
    859 
    860     /* OK, now figure out where we stash our temporary files.  */
    861     {
    862 	char *p;
    863 
    864 	/* The code which wants to chdir into server_temp_dir is not set
    865 	 * up to deal with it being a relative path.  So give an error
    866 	 * for that case.
    867 	 */
    868 	if (!ISABSOLUTE (get_cvs_tmp_dir ()))
    869 	{
    870 	    if (alloc_pending (80 + strlen (get_cvs_tmp_dir ())))
    871 		sprintf (pending_error_text,
    872 			 "E Value of %s for TMPDIR is not absolute",
    873 			 get_cvs_tmp_dir ());
    874 
    875 	    /* FIXME: we would like this error to be persistent, that
    876 	     * is, not cleared by print_pending_error.  The current client
    877 	     * will exit as soon as it gets an error, but the protocol spec
    878 	     * does not require a client to do so.
    879 	     */
    880 	}
    881 	else
    882 	{
    883 	    int status;
    884 	    int i = 0;
    885 
    886 	    server_temp_dir = xmalloc (strlen (get_cvs_tmp_dir ()) + 80);
    887 	    if (!server_temp_dir)
    888 	    {
    889 		/* Strictly speaking, we're not supposed to output anything
    890 		 * now.  But we're about to exit(), give it a try.
    891 		 */
    892 		printf ("E Fatal server error, aborting.\n\
    893 error ENOMEM Virtual memory exhausted.\n");
    894 
    895 		exit (EXIT_FAILURE);
    896 	    }
    897 	    strcpy (server_temp_dir, get_cvs_tmp_dir ());
    898 
    899 	    /* Remove a trailing slash from TMPDIR if present.  */
    900 	    p = server_temp_dir + strlen (server_temp_dir) - 1;
    901 	    if (*p == '/')
    902 		*p = '\0';
    903 
    904 	    /* I wanted to use cvs-serv/PID, but then you have to worry about
    905 	     * the permissions on the cvs-serv directory being right.  So
    906 	     * use cvs-servPID.
    907 	     */
    908 	    strcat (server_temp_dir, "/cvs-serv");
    909 
    910 	    p = server_temp_dir + strlen (server_temp_dir);
    911 	    sprintf (p, "%ld", (long) getpid ());
    912 
    913 	    orig_server_temp_dir = server_temp_dir;
    914 
    915 	    /* Create the temporary directory, and set the mode to
    916 	     * 700, to discourage random people from tampering with
    917 	     * it.
    918 	     */
    919 	    while ((status = mkdir_p (server_temp_dir)) == EEXIST)
    920 	    {
    921 		static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
    922 
    923 		if (i >= sizeof suffix - 1) break;
    924 		if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
    925 		p[0] = suffix[i++];
    926 		p[1] = '\0';
    927 	    }
    928 	    if (status)
    929 	    {
    930 		if (alloc_pending (80 + strlen (server_temp_dir)))
    931 		    sprintf (pending_error_text,
    932 			    "E can't create temporary directory %s",
    933 			    server_temp_dir);
    934 		pending_error = status;
    935 	    }
    936 #ifndef CHMOD_BROKEN
    937 	    else if (chmod (server_temp_dir, S_IRWXU) < 0)
    938 	    {
    939 		int save_errno = errno;
    940 		if (alloc_pending (80 + strlen (server_temp_dir)))
    941 		    sprintf (pending_error_text,
    942 "E cannot change permissions on temporary directory %s",
    943 			     server_temp_dir);
    944 		pending_error = save_errno;
    945 	    }
    946 #endif
    947 	    else if (CVS_CHDIR (server_temp_dir) < 0)
    948 	    {
    949 		int save_errno = errno;
    950 		if (alloc_pending (80 + strlen (server_temp_dir)))
    951 		    sprintf (pending_error_text,
    952 "E cannot change to temporary directory %s",
    953 			     server_temp_dir);
    954 		pending_error = save_errno;
    955 	    }
    956 	}
    957     }
    958 
    959     /* Now that we have a config, verify our compression level.  Since
    960      * most clients do not send Gzip-stream requests until after the root
    961      * request, wait until the first request following Root to verify that
    962      * compression is being used when level 0 is not allowed.
    963      */
    964     if (gzip_level)
    965     {
    966 	bool forced = false;
    967 
    968 	if (gzip_level < config->MinCompressionLevel)
    969 	{
    970 	    gzip_level = config->MinCompressionLevel;
    971 	    forced = true;
    972 	}
    973 
    974 	if (gzip_level > config->MaxCompressionLevel)
    975 	{
    976 	    gzip_level = config->MaxCompressionLevel;
    977 	    forced = true;
    978 	}
    979 
    980 	if (forced && !quiet
    981 	    && alloc_pending_warning (120 + strlen (program_name)))
    982 	    sprintf (pending_warning_text,
    983 "E %s server: Forcing compression level %d (allowed: %zu <= z <= %zu).",
    984 		     program_name, gzip_level, config->MinCompressionLevel,
    985 		     config->MaxCompressionLevel);
    986     }
    987 
    988     /* cvsacl patch */
    989     parse_aclconfig (current_parsed_root->directory);
    990 
    991     if (!nolock)
    992     {
    993     path = xmalloc (strlen (current_parsed_root->directory)
    994 		   + sizeof (CVSROOTADM)
    995 		   + 2);
    996     if (path == NULL)
    997     {
    998 	pending_error = ENOMEM;
    999 	return;
   1000     }
   1001     (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
   1002     if (!isaccessible (path, R_OK | X_OK))
   1003     {
   1004 	int save_errno = errno;
   1005 	if (alloc_pending (80 + strlen (path)))
   1006 	    sprintf (pending_error_text, "E Cannot access %s", path);
   1007 	pending_error = save_errno;
   1008     }
   1009     free (path);
   1010     }
   1011 
   1012     setenv (CVSROOT_ENV, current_parsed_root->directory, 1);
   1013 }
   1014 
   1015 
   1016 
   1017 static int max_dotdot_limit = 0;
   1018 
   1019 /* Is this pathname OK to recurse into when we are running as the server?
   1020    If not, call error() with a fatal error.  */
   1021 void
   1022 server_pathname_check (char *path)
   1023 {
   1024     TRACE (TRACE_FUNCTION, "server_pathname_check (%s)",
   1025 	   path ? path : "(null)");
   1026 
   1027     /* An absolute pathname is almost surely a path on the *client* machine,
   1028        and is unlikely to do us any good here.  It also is probably capable
   1029        of being a security hole in the anonymous readonly case.  */
   1030     if (ISABSOLUTE (path))
   1031 	/* Giving an error is actually kind of a cop-out, in the sense
   1032 	   that it would be nice for "cvs co -d /foo/bar/baz" to work.
   1033 	   A quick fix in the server would be requiring Max-dotdot of
   1034 	   at least one if pathnames are absolute, and then putting
   1035 	   /abs/foo/bar/baz in the temp dir beside the /d/d/d stuff.
   1036 	   A cleaner fix in the server might be to decouple the
   1037 	   pathnames we pass back to the client from pathnames in our
   1038 	   temp directory (this would also probably remove the need
   1039 	   for Max-dotdot).  A fix in the client would have the client
   1040 	   turn it into "cd /foo/bar; cvs co -d baz" (more or less).
   1041 	   This probably has some problems with pathnames which appear
   1042 	   in messages.  */
   1043 	error ( 1, 0,
   1044 		"absolute pathnames invalid for server (specified `%s')",
   1045 		path );
   1046     if (pathname_levels (path) > max_dotdot_limit)
   1047     {
   1048 	/* Similar to the ISABSOLUTE case in security implications.  */
   1049 	error (0, 0, "protocol error: `%s' contains more leading ..", path);
   1050 	error (1, 0, "than the %d which Max-dotdot specified",
   1051 	       max_dotdot_limit);
   1052     }
   1053 }
   1054 
   1055 
   1056 
   1057 /* Is file or directory REPOS an absolute pathname within the
   1058    current_parsed_root->directory?  If yes, return 0.  If no, set pending_error
   1059    and return 1.  */
   1060 static int
   1061 outside_root (char *repos)
   1062 {
   1063     size_t repos_len = strlen (repos);
   1064     size_t root_len = strlen (current_parsed_root->directory);
   1065 
   1066     /* ISABSOLUTE (repos) should always be true, but
   1067        this is a good security precaution regardless. -DRP
   1068      */
   1069     if (!ISABSOLUTE (repos))
   1070     {
   1071 	if (alloc_pending (repos_len + 80))
   1072 	    sprintf (pending_error_text, "\
   1073 E protocol error: %s is not absolute", repos);
   1074 	return 1;
   1075     }
   1076 
   1077     if (repos_len < root_len
   1078 	|| strncmp (current_parsed_root->directory, repos, root_len) != 0)
   1079     {
   1080     not_within:
   1081 	if (alloc_pending (strlen (current_parsed_root->directory)
   1082 			   + strlen (repos)
   1083 			   + 80))
   1084 	    sprintf (pending_error_text, "\
   1085 E protocol error: directory '%s' not within root '%s'",
   1086 		     repos, current_parsed_root->directory);
   1087 	return 1;
   1088     }
   1089     if (repos_len > root_len)
   1090     {
   1091 	if (repos[root_len] != '/')
   1092 	    goto not_within;
   1093 	if (pathname_levels (repos + root_len + 1) > 0)
   1094 	    goto not_within;
   1095     }
   1096     return 0;
   1097 }
   1098 
   1099 
   1100 
   1101 /* Is file or directory FILE outside the current directory (that is, does
   1102    it contain '/')?  If no, return 0.  If yes, set pending_error
   1103    and return 1.  */
   1104 static int
   1105 outside_dir (char *file)
   1106 {
   1107     if (strchr (file, '/') != NULL)
   1108     {
   1109 	if (alloc_pending (strlen (file)
   1110 			   + 80))
   1111 	    sprintf (pending_error_text, "\
   1112 E protocol error: directory '%s' not within current directory",
   1113 		     file);
   1114 	return 1;
   1115     }
   1116     return 0;
   1117 }
   1118 
   1119 
   1120 
   1121 /*
   1122  * Add as many directories to the temp directory as the client tells us it
   1123  * will use "..", so we never try to access something outside the temp
   1124  * directory via "..".
   1125  */
   1126 static void
   1127 serve_max_dotdot (char *arg)
   1128 {
   1129     int lim = atoi (arg);
   1130     int i;
   1131     char *p;
   1132 
   1133 #ifdef PROXY_SUPPORT
   1134     if (proxy_log) return;
   1135 #endif /* PROXY_SUPPORT */
   1136 
   1137     if (lim < 0 || lim > MAXARGS)
   1138 	return;
   1139     p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10);
   1140     if (p == NULL)
   1141     {
   1142 	pending_error = ENOMEM;
   1143 	return;
   1144     }
   1145     strcpy (p, server_temp_dir);
   1146     for (i = 0; i < lim; ++i)
   1147 	strcat (p, "/d");
   1148     if (server_temp_dir != orig_server_temp_dir)
   1149 	free (server_temp_dir);
   1150     server_temp_dir = p;
   1151     max_dotdot_limit = lim;
   1152 }
   1153 
   1154 
   1155 
   1156 static char *gDirname;
   1157 static char *gupdate_dir;
   1158 
   1159 static void
   1160 dirswitch (char *dir, char *repos)
   1161 {
   1162     int status;
   1163     FILE *f;
   1164     size_t dir_len;
   1165 
   1166     TRACE (TRACE_FUNCTION, "dirswitch (%s, %s)", dir ? dir : "(null)",
   1167 	   repos ? repos : "(null)");
   1168 
   1169     server_write_entries ();
   1170 
   1171     if (error_pending()) return;
   1172 
   1173     /* Check for bad directory name.
   1174 
   1175        FIXME: could/should unify these checks with server_pathname_check
   1176        except they need to report errors differently.  */
   1177     if (ISABSOLUTE (dir))
   1178     {
   1179 	if (alloc_pending (80 + strlen (dir)))
   1180 	    sprintf ( pending_error_text,
   1181 		      "E absolute pathnames invalid for server (specified `%s')",
   1182 		      dir);
   1183 	return;
   1184     }
   1185     if (pathname_levels (dir) > max_dotdot_limit)
   1186     {
   1187 	if (alloc_pending (80 + strlen (dir)))
   1188 	    sprintf (pending_error_text,
   1189 		     "E protocol error: `%s' has too many ..", dir);
   1190 	return;
   1191     }
   1192 
   1193     dir_len = strlen (dir);
   1194 
   1195     /* Check for a trailing '/'.  This is not ISSLASH because \ in the
   1196        protocol is an ordinary character, not a directory separator (of
   1197        course, it is perhaps unwise to use it in directory names, but that
   1198        is another issue).  */
   1199     if (dir_len > 0
   1200 	&& dir[dir_len - 1] == '/')
   1201     {
   1202 	if (alloc_pending (80 + dir_len))
   1203 	    sprintf (pending_error_text,
   1204 		     "E protocol error: invalid directory syntax in %s", dir);
   1205 	return;
   1206     }
   1207 
   1208     if (gDirname != NULL)
   1209 	free (gDirname);
   1210     if (gupdate_dir != NULL)
   1211 	free (gupdate_dir);
   1212 
   1213     if (!strcmp (dir, "."))
   1214 	gupdate_dir = xstrdup ("");
   1215     else
   1216 	gupdate_dir = xstrdup (dir);
   1217 
   1218     gDirname = xmalloc (strlen (server_temp_dir) + dir_len + 40);
   1219     if (gDirname == NULL)
   1220     {
   1221 	pending_error = ENOMEM;
   1222 	return;
   1223     }
   1224 
   1225     strcpy (gDirname, server_temp_dir);
   1226     strcat (gDirname, "/");
   1227     strcat (gDirname, dir);
   1228 
   1229     status = mkdir_p (gDirname);
   1230     if (status != 0
   1231 	&& status != EEXIST)
   1232     {
   1233 	if (alloc_pending (80 + strlen (gDirname)))
   1234 	    sprintf (pending_error_text, "E cannot mkdir %s", gDirname);
   1235 	pending_error = status;
   1236 	return;
   1237     }
   1238 
   1239     /* We need to create adm directories in all path elements because
   1240        we want the server to descend them, even if the client hasn't
   1241        sent the appropriate "Argument xxx" command to match the
   1242        already-sent "Directory xxx" command.  See recurse.c
   1243        (start_recursion) for a big discussion of this.  */
   1244 
   1245     status = create_adm_p (server_temp_dir, dir);
   1246     if (status != 0)
   1247     {
   1248 	if (alloc_pending (80 + strlen (gDirname)))
   1249 	    sprintf (pending_error_text, "E cannot create_adm_p %s", gDirname);
   1250 	pending_error = status;
   1251 	return;
   1252     }
   1253 
   1254     if ( CVS_CHDIR (gDirname) < 0)
   1255     {
   1256 	int save_errno = errno;
   1257 	if (alloc_pending (80 + strlen (gDirname)))
   1258 	    sprintf (pending_error_text, "E cannot change to %s", gDirname);
   1259 	pending_error = save_errno;
   1260 	return;
   1261     }
   1262     /*
   1263      * This is pretty much like calling Create_Admin, but Create_Admin doesn't
   1264      * report errors in the right way for us.
   1265      */
   1266     if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
   1267     {
   1268 	int save_errno = errno;
   1269 	if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM)))
   1270 	    sprintf (pending_error_text,
   1271 		     "E cannot mkdir %s/%s", gDirname, CVSADM);
   1272 	pending_error = save_errno;
   1273 	return;
   1274     }
   1275 
   1276     /* The following will overwrite the contents of CVSADM_REP.  This
   1277        is the correct behavior -- mkdir_p may have written a
   1278        placeholder value to this file and we need to insert the
   1279        correct value. */
   1280 
   1281     f = CVS_FOPEN (CVSADM_REP, "w");
   1282     if (f == NULL)
   1283     {
   1284 	int save_errno = errno;
   1285 	if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
   1286 	    sprintf (pending_error_text,
   1287 		     "E cannot open %s/%s", gDirname, CVSADM_REP);
   1288 	pending_error = save_errno;
   1289 	return;
   1290     }
   1291     if (fprintf (f, "%s", repos) < 0)
   1292     {
   1293 	int save_errno = errno;
   1294 	if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
   1295 	    sprintf (pending_error_text,
   1296 		     "E error writing %s/%s", gDirname, CVSADM_REP);
   1297 	pending_error = save_errno;
   1298 	fclose (f);
   1299 	return;
   1300     }
   1301     /* Non-remote CVS handles a module representing the entire tree
   1302        (e.g., an entry like ``world -a .'') by putting /. at the end
   1303        of the Repository file, so we do the same.  */
   1304     if (strcmp (dir, ".") == 0
   1305 	&& current_parsed_root != NULL
   1306 	&& current_parsed_root->directory != NULL
   1307 	&& strcmp (current_parsed_root->directory, repos) == 0)
   1308     {
   1309 	if (fprintf (f, "/.") < 0)
   1310 	{
   1311 	    int save_errno = errno;
   1312 	    if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
   1313 		sprintf (pending_error_text,
   1314 			 "E error writing %s/%s", gDirname, CVSADM_REP);
   1315 	    pending_error = save_errno;
   1316 	    fclose (f);
   1317 	    return;
   1318 	}
   1319     }
   1320     if (fprintf (f, "\n") < 0)
   1321     {
   1322 	int save_errno = errno;
   1323 	if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
   1324 	    sprintf (pending_error_text,
   1325 		     "E error writing %s/%s", gDirname, CVSADM_REP);
   1326 	pending_error = save_errno;
   1327 	fclose (f);
   1328 	return;
   1329     }
   1330     if (fclose (f) == EOF)
   1331     {
   1332 	int save_errno = errno;
   1333 	if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
   1334 	    sprintf (pending_error_text,
   1335 		     "E error closing %s/%s", gDirname, CVSADM_REP);
   1336 	pending_error = save_errno;
   1337 	return;
   1338     }
   1339     /* We open in append mode because we don't want to clobber an
   1340        existing Entries file.  */
   1341     f = CVS_FOPEN (CVSADM_ENT, "a");
   1342     if (f == NULL)
   1343     {
   1344 	int save_errno = errno;
   1345 	if (alloc_pending (80 + strlen (CVSADM_ENT)))
   1346 	    sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
   1347 	pending_error = save_errno;
   1348 	return;
   1349     }
   1350     if (fclose (f) == EOF)
   1351     {
   1352 	int save_errno = errno;
   1353 	if (alloc_pending (80 + strlen (CVSADM_ENT)))
   1354 	    sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
   1355 	pending_error = save_errno;
   1356 	return;
   1357     }
   1358 }
   1359 
   1360 
   1361 
   1362 static void
   1363 serve_repository (char *arg)
   1364 {
   1365 # ifdef PROXY_SUPPORT
   1366     assert (!proxy_log);
   1367 # endif /* PROXY_SUPPORT */
   1368 
   1369     if (alloc_pending (80))
   1370 	strcpy (pending_error_text,
   1371 		"E Repository request is obsolete; aborted");
   1372     return;
   1373 }
   1374 
   1375 
   1376 
   1377 static void
   1378 serve_directory (char *arg)
   1379 {
   1380     int status;
   1381     char *repos;
   1382 
   1383     TRACE (TRACE_FUNCTION, "serve_directory (%s)", arg ? arg : "(null)");
   1384 
   1385 
   1386     /* The data needs to be read into the secondary log regardless, but
   1387      * processing of anything other than errors is skipped until later.
   1388      */
   1389     status = buf_read_line (buf_from_net, &repos, NULL);
   1390     if (status == 0)
   1391     {
   1392 	if (!ISABSOLUTE (repos))
   1393 	{
   1394 	    /* Make absolute.
   1395 	     *
   1396 	     * FIXME: This is kinda hacky - we should probably only ever store
   1397 	     * and pass SHORT_REPOS (perhaps with the occassional exception
   1398 	     * for optimizations, but many, many functions end up
   1399 	     * deconstructing REPOS to gain SHORT_REPOS anyhow) - the
   1400 	     * CVSROOT portion of REPOS is redundant with
   1401 	     * current_parsed_root->directory - but since this is the way
   1402 	     * things have always been done, changing this will likely involve
   1403 	     * a major overhaul.
   1404 	     */
   1405 	    char *short_repos;
   1406 
   1407 	    short_repos = repos;
   1408 	    repos = Xasprintf ("%s/%s",
   1409 	                      current_parsed_root->directory, short_repos);
   1410 	    free (short_repos);
   1411 	}
   1412 	else
   1413 	    repos = xstrdup (primary_root_translate (repos));
   1414 
   1415 	if (
   1416 # ifdef PROXY_SUPPORT
   1417 	    !proxy_log &&
   1418 # endif /* PROXY_SUPPORT */
   1419 	    !outside_root (repos))
   1420 	    dirswitch (arg, repos);
   1421 	free (repos);
   1422     }
   1423     else if (status == -2)
   1424     {
   1425 	pending_error = ENOMEM;
   1426     }
   1427     else if (status != 0)
   1428     {
   1429 	pending_error_text = xmalloc (80 + strlen (arg));
   1430 	if (pending_error_text == NULL)
   1431 	{
   1432 	    pending_error = ENOMEM;
   1433 	}
   1434 	else if (status == -1)
   1435 	{
   1436 	    sprintf (pending_error_text,
   1437 		     "E end of file reading mode for %s", arg);
   1438 	}
   1439 	else
   1440 	{
   1441 	    sprintf (pending_error_text,
   1442 		     "E error reading mode for %s", arg);
   1443 	    pending_error = status;
   1444 	}
   1445     }
   1446 }
   1447 
   1448 
   1449 
   1450 static void
   1451 serve_static_directory (char *arg)
   1452 {
   1453     FILE *f;
   1454 
   1455     if (error_pending ()
   1456 # ifdef PROXY_SUPPORT
   1457 	|| proxy_log
   1458 # endif /* PROXY_SUPPORT */
   1459        ) return;
   1460 
   1461     f = CVS_FOPEN (CVSADM_ENTSTAT, "w+");
   1462     if (f == NULL)
   1463     {
   1464 	int save_errno = errno;
   1465 	if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
   1466 	    sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
   1467 	pending_error = save_errno;
   1468 	return;
   1469     }
   1470     if (fclose (f) == EOF)
   1471     {
   1472 	int save_errno = errno;
   1473 	if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
   1474 	    sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
   1475 	pending_error = save_errno;
   1476 	return;
   1477     }
   1478 }
   1479 
   1480 
   1481 
   1482 static void
   1483 serve_sticky (char *arg)
   1484 {
   1485     FILE *f;
   1486 
   1487     if (error_pending ()
   1488 # ifdef PROXY_SUPPORT
   1489 	|| proxy_log
   1490 # endif /* PROXY_SUPPORT */
   1491        ) return;
   1492 
   1493     f = CVS_FOPEN (CVSADM_TAG, "w+");
   1494     if (f == NULL)
   1495     {
   1496 	int save_errno = errno;
   1497 	if (alloc_pending (80 + strlen (CVSADM_TAG)))
   1498 	    sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG);
   1499 	pending_error = save_errno;
   1500 	return;
   1501     }
   1502     if (fprintf (f, "%s\n", arg) < 0)
   1503     {
   1504 	int save_errno = errno;
   1505 	if (alloc_pending (80 + strlen (CVSADM_TAG)))
   1506 	    sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
   1507 	pending_error = save_errno;
   1508 	return;
   1509     }
   1510     if (fclose (f) == EOF)
   1511     {
   1512 	int save_errno = errno;
   1513 	if (alloc_pending (80 + strlen (CVSADM_TAG)))
   1514 	    sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG);
   1515 	pending_error = save_errno;
   1516 	return;
   1517     }
   1518 }
   1519 
   1520 
   1521 
   1522 /*
   1523  * Read SIZE bytes from buf_from_net, write them to FILE.
   1524  *
   1525  * Currently this isn't really used for receiving parts of a file --
   1526  * the file is still sent over in one chunk.  But if/when we get
   1527  * spiffy in-process gzip support working, perhaps the compressed
   1528  * pieces could be sent over as they're ready, if the network is fast
   1529  * enough.  Or something.
   1530  */
   1531 static void
   1532 receive_partial_file (size_t size, int file)
   1533 {
   1534     while (size > 0)
   1535     {
   1536 	int status;
   1537 	size_t nread;
   1538 	char *data;
   1539 
   1540 	status = buf_read_data (buf_from_net, size, &data, &nread);
   1541 	if (status != 0)
   1542 	{
   1543 	    if (status == -2)
   1544 		pending_error = ENOMEM;
   1545 	    else
   1546 	    {
   1547 		pending_error_text = xmalloc (80);
   1548 		if (pending_error_text == NULL)
   1549 		    pending_error = ENOMEM;
   1550 		else if (status == -1)
   1551 		{
   1552 		    sprintf (pending_error_text,
   1553 			     "E premature end of file from client");
   1554 		    pending_error = 0;
   1555 		}
   1556 		else
   1557 		{
   1558 		    sprintf (pending_error_text,
   1559 			     "E error reading from client");
   1560 		    pending_error = status;
   1561 		}
   1562 	    }
   1563 	    return;
   1564 	}
   1565 
   1566 	size -= nread;
   1567 
   1568 	while (nread > 0)
   1569 	{
   1570 	    ssize_t nwrote;
   1571 
   1572 	    nwrote = write (file, data, nread);
   1573 	    if (nwrote < 0)
   1574 	    {
   1575 		int save_errno = errno;
   1576 		if (alloc_pending (40))
   1577 		    strcpy (pending_error_text, "E unable to write");
   1578 		pending_error = save_errno;
   1579 
   1580 		/* Read and discard the file data.  */
   1581 		while (size > 0)
   1582 		{
   1583 		    int status;
   1584 		    size_t nread;
   1585 		    char *data;
   1586 
   1587 		    status = buf_read_data (buf_from_net, size, &data, &nread);
   1588 		    if (status != 0)
   1589 			return;
   1590 		    size -= nread;
   1591 		}
   1592 
   1593 		return;
   1594 	    }
   1595 	    nread -= nwrote;
   1596 	    data += nwrote;
   1597 	}
   1598     }
   1599 }
   1600 
   1601 
   1602 
   1603 /* Receive SIZE bytes, write to filename FILE.  */
   1604 static void
   1605 receive_file (size_t size, char *file, int gzipped)
   1606 {
   1607     int fd;
   1608     char *arg = file;
   1609 
   1610     /* Write the file.  */
   1611     fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
   1612     if (fd < 0)
   1613     {
   1614 	int save_errno = errno;
   1615 	if (alloc_pending (40 + strlen (arg)))
   1616 	    sprintf (pending_error_text, "E cannot open %s", arg);
   1617 	pending_error = save_errno;
   1618 	return;
   1619     }
   1620 
   1621     if (gzipped)
   1622     {
   1623 	/* Using gunzip_and_write isn't really a high-performance
   1624 	   approach, because it keeps the whole thing in memory
   1625 	   (contiguous memory, worse yet).  But it seems easier to
   1626 	   code than the alternative (and less vulnerable to subtle
   1627 	   bugs).  Given that this feature is mainly for
   1628 	   compatibility, that is the better tradeoff.  */
   1629 
   1630 	size_t toread = size;
   1631 	char *filebuf;
   1632 	char *p;
   1633 
   1634 	filebuf = xmalloc (size);
   1635 	p = filebuf;
   1636 	/* If NULL, we still want to read the data and discard it.  */
   1637 
   1638 	while (toread > 0)
   1639 	{
   1640 	    int status;
   1641 	    size_t nread;
   1642 	    char *data;
   1643 
   1644 	    status = buf_read_data (buf_from_net, toread, &data, &nread);
   1645 	    if (status != 0)
   1646 	    {
   1647 		if (status == -2)
   1648 		    pending_error = ENOMEM;
   1649 		else
   1650 		{
   1651 		    pending_error_text = xmalloc (80);
   1652 		    if (pending_error_text == NULL)
   1653 			pending_error = ENOMEM;
   1654 		    else if (status == -1)
   1655 		    {
   1656 			sprintf (pending_error_text,
   1657 				 "E premature end of file from client");
   1658 			pending_error = 0;
   1659 		    }
   1660 		    else
   1661 		    {
   1662 			sprintf (pending_error_text,
   1663 				 "E error reading from client");
   1664 			pending_error = status;
   1665 		    }
   1666 		}
   1667 		return;
   1668 	    }
   1669 
   1670 	    toread -= nread;
   1671 
   1672 	    if (filebuf != NULL)
   1673 	    {
   1674 		memcpy (p, data, nread);
   1675 		p += nread;
   1676 	    }
   1677 	}
   1678 	if (filebuf == NULL)
   1679 	{
   1680 	    pending_error = ENOMEM;
   1681 	    goto out;
   1682 	}
   1683 
   1684 	if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
   1685 	{
   1686 	    if (alloc_pending (80))
   1687 		sprintf (pending_error_text,
   1688 			 "E aborting due to compression error");
   1689 	}
   1690 	free (filebuf);
   1691     }
   1692     else
   1693 	receive_partial_file (size, fd);
   1694 
   1695     if (pending_error_text)
   1696     {
   1697 	char *p = xrealloc (pending_error_text,
   1698 			   strlen (pending_error_text) + strlen (arg) + 30);
   1699 	if (p)
   1700 	{
   1701 	    pending_error_text = p;
   1702 	    sprintf (p + strlen (p), ", file %s", arg);
   1703 	}
   1704 	/* else original string is supposed to be unchanged */
   1705     }
   1706 
   1707  out:
   1708     if (close (fd) < 0 && !error_pending ())
   1709     {
   1710 	int save_errno = errno;
   1711 	if (alloc_pending (40 + strlen (arg)))
   1712 	    sprintf (pending_error_text, "E cannot close %s", arg);
   1713 	pending_error = save_errno;
   1714 	return;
   1715     }
   1716 }
   1717 
   1718 
   1719 
   1720 /* Kopt for the next file sent in Modified or Is-modified.  */
   1721 static char *kopt;
   1722 
   1723 /* Timestamp (Checkin-time) for next file sent in Modified or
   1724    Is-modified.  */
   1725 static int checkin_time_valid;
   1726 static time_t checkin_time;
   1727 
   1728 
   1729 
   1730 /*
   1731  * Used to keep track of Entry requests.
   1732  */
   1733 struct an_entry {
   1734     struct an_entry *next;
   1735     char *entry;
   1736 };
   1737 
   1738 static struct an_entry *entries;
   1739 
   1740 static void
   1741 serve_is_modified (char *arg)
   1742 {
   1743     struct an_entry *p;
   1744     char *name;
   1745     char *cp;
   1746     char *timefield;
   1747     /* Have we found this file in "entries" yet.  */
   1748     int found;
   1749 
   1750     if (error_pending ()
   1751 # ifdef PROXY_SUPPORT
   1752 	|| proxy_log
   1753 # endif /* PROXY_SUPPORT */
   1754        ) return;
   1755 
   1756     if (outside_dir (arg))
   1757 	return;
   1758 
   1759     /* Rewrite entries file to have `M' in timestamp field.  */
   1760     found = 0;
   1761     for (p = entries; p != NULL; p = p->next)
   1762     {
   1763 	name = p->entry + 1;
   1764 	cp = strchr (name, '/');
   1765 	if (cp != NULL
   1766 	    && strlen (arg) == cp - name
   1767 	    && strncmp (arg, name, cp - name) == 0)
   1768 	{
   1769 	    if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
   1770 	    {
   1771 		/* We didn't find the record separator or it is followed by
   1772 		 * the end of the string, so just exit.
   1773 		 */
   1774 		if (alloc_pending (80))
   1775 		    sprintf (pending_error_text,
   1776 		             "E Malformed Entry encountered.");
   1777 		return;
   1778 	    }
   1779 	    /* If the time field is not currently empty, then one of
   1780 	     * serve_modified, serve_is_modified, & serve_unchanged were
   1781 	     * already called for this file.  We would like to ignore the
   1782 	     * reinvocation silently or, better yet, exit with an error
   1783 	     * message, but we just avoid the copy-forward and overwrite the
   1784 	     * value from the last invocation instead.  See the comment below
   1785 	     * for more.
   1786 	     */
   1787 	    if (*timefield == '/')
   1788 	    {
   1789 		/* Copy forward one character.  Space was allocated for this
   1790 		 * already in serve_entry().  */
   1791 		cp = timefield + strlen (timefield);
   1792 		cp[1] = '\0';
   1793 		while (cp > timefield)
   1794 		{
   1795 		    *cp = cp[-1];
   1796 		    --cp;
   1797 		}
   1798 
   1799 		/* *timefield == '/';  */
   1800 	    }
   1801 	    /* If *TIMEFIELD wasn't '/' and wasn't '+', we assume that it was
   1802 	     * because of multiple calls to Is-modified & Unchanged by the
   1803 	     * client and just overwrite the value from the last call.
   1804 	     * Technically, we should probably either ignore calls after the
   1805 	     * first or send the client an error, since the client/server
   1806 	     * protocol specification specifies that only one call to either
   1807 	     * Is-Modified or Unchanged is allowed, but broken versions of
   1808 	     * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a) and
   1809 	     * the WinCVS & TortoiseCVS clients which depend on those broken
   1810 	     * versions of CVSNT (WinCVS 1.3 & at least one TortoiseCVS
   1811 	     * release) rely on this behavior.
   1812 	     */
   1813 	    if (*timefield != '+')
   1814 		*timefield = 'M';
   1815 
   1816 	    if (kopt != NULL)
   1817 	    {
   1818 		if (alloc_pending (strlen (name) + 80))
   1819 		    sprintf (pending_error_text,
   1820 			     "E protocol error: both Kopt and Entry for %s",
   1821 			     arg);
   1822 		free (kopt);
   1823 		kopt = NULL;
   1824 		return;
   1825 	    }
   1826 	    found = 1;
   1827 	    break;
   1828 	}
   1829     }
   1830     if (!found)
   1831     {
   1832 	/* We got Is-modified but no Entry.  Add a dummy entry.
   1833 	   The "D" timestamp is what makes it a dummy.  */
   1834 	p = xmalloc (sizeof (struct an_entry));
   1835 	if (p == NULL)
   1836 	{
   1837 	    pending_error = ENOMEM;
   1838 	    return;
   1839 	}
   1840 	p->entry = xmalloc (strlen (arg) + 80);
   1841 	if (p->entry == NULL)
   1842 	{
   1843 	    pending_error = ENOMEM;
   1844 	    free (p);
   1845 	    return;
   1846 	}
   1847 	strcpy (p->entry, "/");
   1848 	strcat (p->entry, arg);
   1849 	strcat (p->entry, "//D/");
   1850 	if (kopt != NULL)
   1851 	{
   1852 	    strcat (p->entry, kopt);
   1853 	    free (kopt);
   1854 	    kopt = NULL;
   1855 	}
   1856 	strcat (p->entry, "/");
   1857 	p->next = entries;
   1858 	entries = p;
   1859     }
   1860 }
   1861 
   1862 
   1863 
   1864 static void
   1865 serve_modified (char *arg)
   1866 {
   1867     size_t size;
   1868     int read_size;
   1869     int status;
   1870     char *size_text;
   1871     char *mode_text;
   1872 
   1873     int gzipped = 0;
   1874 
   1875     /*
   1876      * This used to return immediately if error_pending () was true.
   1877      * However, that fails, because it causes each line of the file to
   1878      * be echoed back to the client as an unrecognized command.  The
   1879      * client isn't reading from the socket, so eventually both
   1880      * processes block trying to write to the other.  Now, we try to
   1881      * read the file if we can.
   1882      */
   1883 
   1884     status = buf_read_line (buf_from_net, &mode_text, NULL);
   1885     if (status != 0)
   1886     {
   1887 	if (status == -2)
   1888 	    pending_error = ENOMEM;
   1889 	else
   1890 	{
   1891 	    pending_error_text = xmalloc (80 + strlen (arg));
   1892 	    if (pending_error_text == NULL)
   1893 		pending_error = ENOMEM;
   1894 	    else
   1895 	    {
   1896 		if (status == -1)
   1897 		    sprintf (pending_error_text,
   1898 			     "E end of file reading mode for %s", arg);
   1899 		else
   1900 		{
   1901 		    sprintf (pending_error_text,
   1902 			     "E error reading mode for %s", arg);
   1903 		    pending_error = status;
   1904 		}
   1905 	    }
   1906 	}
   1907 	return;
   1908     }
   1909 
   1910     status = buf_read_line (buf_from_net, &size_text, NULL);
   1911     if (status != 0)
   1912     {
   1913 	if (status == -2)
   1914 	    pending_error = ENOMEM;
   1915 	else
   1916 	{
   1917 	    pending_error_text = xmalloc (80 + strlen (arg));
   1918 	    if (pending_error_text == NULL)
   1919 		pending_error = ENOMEM;
   1920 	    else
   1921 	    {
   1922 		if (status == -1)
   1923 		    sprintf (pending_error_text,
   1924 			     "E end of file reading size for %s", arg);
   1925 		else
   1926 		{
   1927 		    sprintf (pending_error_text,
   1928 			     "E error reading size for %s", arg);
   1929 		    pending_error = status;
   1930 		}
   1931 	    }
   1932 	}
   1933 	free (mode_text);
   1934 	return;
   1935     }
   1936     if (size_text[0] == 'z')
   1937     {
   1938 	gzipped = 1;
   1939 	read_size = atoi (size_text + 1);
   1940     }
   1941     else
   1942 	read_size = atoi (size_text);
   1943     free (size_text);
   1944 
   1945     if (read_size < 0 && alloc_pending (80))
   1946     {
   1947 	sprintf (pending_error_text,
   1948 		 "E client sent invalid (negative) file size");
   1949 	return;
   1950     }
   1951     else
   1952 	size = read_size;
   1953 
   1954     if (error_pending ())
   1955     {
   1956 	/* Now that we know the size, read and discard the file data.  */
   1957 	while (size > 0)
   1958 	{
   1959 	    int status;
   1960 	    size_t nread;
   1961 	    char *data;
   1962 
   1963 	    status = buf_read_data (buf_from_net, size, &data, &nread);
   1964 	    if (status != 0)
   1965 		return;
   1966 	    size -= nread;
   1967 	}
   1968 	free (mode_text);
   1969 	return;
   1970     }
   1971 
   1972     if (
   1973 # ifdef PROXY_SUPPORT
   1974 	!proxy_log &&
   1975 # endif /* PROXY_SUPPORT */
   1976 	outside_dir (arg))
   1977     {
   1978 	free (mode_text);
   1979 	return;
   1980     }
   1981 
   1982     receive_file (size,
   1983 # ifdef PROXY_SUPPORT
   1984 	          proxy_log ? DEVNULL :
   1985 # endif /* PROXY_SUPPORT */
   1986 			      arg,
   1987 		  gzipped);
   1988     if (error_pending ())
   1989     {
   1990 	free (mode_text);
   1991 	return;
   1992     }
   1993 
   1994 # ifdef PROXY_SUPPORT
   1995     /* We've read all the data that needed to be read if we're still logging
   1996      * for a secondary.  Return.
   1997      */
   1998     if (proxy_log) return;
   1999 # endif /* PROXY_SUPPORT */
   2000 
   2001     if (checkin_time_valid)
   2002     {
   2003 	struct utimbuf t;
   2004 
   2005 	memset (&t, 0, sizeof (t));
   2006 	t.modtime = t.actime = checkin_time;
   2007 	if (utime (arg, &t) < 0)
   2008 	{
   2009 	    int save_errno = errno;
   2010 	    if (alloc_pending (80 + strlen (arg)))
   2011 		sprintf (pending_error_text, "E cannot utime %s", arg);
   2012 	    pending_error = save_errno;
   2013 	    free (mode_text);
   2014 	    return;
   2015 	}
   2016 	checkin_time_valid = 0;
   2017     }
   2018 
   2019     {
   2020 	int status = change_mode (arg, mode_text, 0);
   2021 	free (mode_text);
   2022 	if (status)
   2023 	{
   2024 	    if (alloc_pending (40 + strlen (arg)))
   2025 		sprintf (pending_error_text,
   2026 			 "E cannot change mode for %s", arg);
   2027 	    pending_error = status;
   2028 	    return;
   2029 	}
   2030     }
   2031 
   2032     /* Make sure that the Entries indicate the right kopt.  We probably
   2033        could do this even in the non-kopt case and, I think, save a stat()
   2034        call in time_stamp_server.  But for conservatism I'm leaving the
   2035        non-kopt case alone.  */
   2036     if (kopt != NULL)
   2037 	serve_is_modified (arg);
   2038 }
   2039 
   2040 
   2041 
   2042 static void
   2043 serve_enable_unchanged (char *arg)
   2044 {
   2045 # ifdef PROXY_SUPPORT
   2046     /* Might as well skip this since this function does nothing anyhow.  If
   2047      * it did do anything and could generate errors, then the line below would
   2048      * be necessary since this can be processed before a `Root' request.
   2049      *
   2050      *     if (reprocessing) return;
   2051      */
   2052 # endif /* PROXY_SUPPORT */
   2053 }
   2054 
   2055 
   2056 
   2057 static void
   2058 serve_unchanged (char *arg)
   2059 {
   2060     struct an_entry *p;
   2061     char *name;
   2062     char *cp;
   2063     char *timefield;
   2064 
   2065     if (error_pending ()
   2066 # ifdef PROXY_SUPPORT
   2067 	|| proxy_log
   2068 # endif /* PROXY_SUPPORT */
   2069        ) return;
   2070 
   2071     if (outside_dir (arg))
   2072 	return;
   2073 
   2074     /* Rewrite entries file to have `=' in timestamp field.  */
   2075     for (p = entries; p != NULL; p = p->next)
   2076     {
   2077 	name = p->entry + 1;
   2078 	cp = strchr (name, '/');
   2079 	if (cp != NULL
   2080 	    && strlen (arg) == cp - name
   2081 	    && strncmp (arg, name, cp - name) == 0)
   2082 	{
   2083 	    if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
   2084 	    {
   2085 		/* We didn't find the record separator or it is followed by
   2086 		 * the end of the string, so just exit.
   2087 		 */
   2088 		if (alloc_pending (80))
   2089 		    sprintf (pending_error_text,
   2090 		             "E Malformed Entry encountered.");
   2091 		return;
   2092 	    }
   2093 	    /* If the time field is not currently empty, then one of
   2094 	     * serve_modified, serve_is_modified, & serve_unchanged were
   2095 	     * already called for this file.  We would like to ignore the
   2096 	     * reinvocation silently or, better yet, exit with an error
   2097 	     * message, but we just avoid the copy-forward and overwrite the
   2098 	     * value from the last invocation instead.  See the comment below
   2099 	     * for more.
   2100 	     */
   2101 	    if (*timefield == '/')
   2102 	    {
   2103 		/* Copy forward one character.  Space was allocated for this
   2104 		 * already in serve_entry().  */
   2105 		cp = timefield + strlen (timefield);
   2106 		cp[1] = '\0';
   2107 		while (cp > timefield)
   2108 		{
   2109 		    *cp = cp[-1];
   2110 		    --cp;
   2111 		}
   2112 
   2113 		/* *timefield == '/';  */
   2114 	    }
   2115 	    if (*timefield != '+')
   2116 	    {
   2117 		/* '+' is a conflict marker and we don't want to mess with it
   2118 		 * until Version_TS catches it.
   2119 		 */
   2120 		if (timefield[1] != '/')
   2121 		{
   2122 		    /* Obliterate anything else in TIMEFIELD.  This is again to
   2123 		     * support the broken CVSNT clients mentioned below, in
   2124 		     * conjunction with strict timestamp string boundry
   2125 		     * checking in time_stamp_server() from vers_ts.c &
   2126 		     * file_has_conflict() from subr.c, since the broken
   2127 		     * clients used to send malformed timestamp fields in the
   2128 		     * Entry request that they then depended on the subsequent
   2129 		     * Unchanged request to overwrite.
   2130 		     */
   2131 		    char *d = timefield + 1;
   2132 		    if ((cp = strchr (d, '/')))
   2133 		    {
   2134 			while (*cp)
   2135 			{
   2136 			    *d++ = *cp++;
   2137 			}
   2138 			*d = '\0';
   2139 		    }
   2140 		}
   2141 		/* If *TIMEFIELD wasn't '/', we assume that it was because of
   2142 		 * multiple calls to Is-modified & Unchanged by the client and
   2143 		 * just overwrite the value from the last call.  Technically,
   2144 		 * we should probably either ignore calls after the first or
   2145 		 * send the client an error, since the client/server protocol
   2146 		 * specification specifies that only one call to either
   2147 		 * Is-Modified or Unchanged is allowed, but broken versions of
   2148 		 * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a)
   2149 		 * and the WinCVS & TortoiseCVS clients which depend on those
   2150 		 * broken versions of CVSNT (WinCVS 1.3 & at least one
   2151 		 * TortoiseCVS release) rely on this behavior.
   2152 		 */
   2153 		*timefield = '=';
   2154 	    }
   2155 	    break;
   2156 	}
   2157     }
   2158 }
   2159 
   2160 
   2161 
   2162 static void
   2163 serve_entry (char *arg)
   2164 {
   2165     struct an_entry *p;
   2166     char *cp;
   2167     int i = 0;
   2168 
   2169     if (error_pending()
   2170 # ifdef PROXY_SUPPORT
   2171 	|| proxy_log
   2172 # endif /* PROXY_SUPPORT */
   2173        ) return;
   2174 
   2175     /* Verify that the entry is well-formed.  This can avoid problems later.
   2176      * At the moment we only check that the Entry contains five slashes in
   2177      * approximately the correct locations since some of the code makes
   2178      * assumptions about this.
   2179      */
   2180     cp = arg;
   2181     if (*cp == 'D') cp++;
   2182     while (i++ < 5)
   2183     {
   2184 	if (!cp || *cp != '/')
   2185 	{
   2186 	    if (alloc_pending (80))
   2187 		sprintf (pending_error_text,
   2188 			 "E protocol error: Malformed Entry");
   2189 	    return;
   2190 	}
   2191 	cp = strchr (cp + 1, '/');
   2192     }
   2193 
   2194     p = xmalloc (sizeof (struct an_entry));
   2195     if (p == NULL)
   2196     {
   2197 	pending_error = ENOMEM;
   2198 	return;
   2199     }
   2200     /* Leave space for serve_unchanged to write '=' if it wants.  */
   2201     cp = xmalloc (strlen (arg) + 2);
   2202     if (cp == NULL)
   2203     {
   2204 	free (p);
   2205 	pending_error = ENOMEM;
   2206 	return;
   2207     }
   2208     strcpy (cp, arg);
   2209     p->next = entries;
   2210     p->entry = cp;
   2211     entries = p;
   2212 }
   2213 
   2214 
   2215 
   2216 static void
   2217 serve_kopt (char *arg)
   2218 {
   2219     if (error_pending ()
   2220 # ifdef PROXY_SUPPORT
   2221 	|| proxy_log
   2222 # endif /* PROXY_SUPPORT */
   2223        )
   2224 	return;
   2225 
   2226     if (kopt != NULL)
   2227     {
   2228 	if (alloc_pending (80 + strlen (arg)))
   2229 	    sprintf (pending_error_text,
   2230 		     "E protocol error: duplicate Kopt request: %s", arg);
   2231 	return;
   2232     }
   2233 
   2234     /* Do some sanity checks.  In particular, that it is not too long.
   2235        This lets the rest of the code not worry so much about buffer
   2236        overrun attacks.  Probably should call RCS_check_kflag here,
   2237        but that would mean changing RCS_check_kflag to handle errors
   2238        other than via exit(), fprintf(), and such.  */
   2239     if (strlen (arg) > 10)
   2240     {
   2241 	if (alloc_pending (80 + strlen (arg)))
   2242 	    sprintf (pending_error_text,
   2243 		     "E protocol error: invalid Kopt request: %s", arg);
   2244 	return;
   2245     }
   2246 
   2247     kopt = xmalloc (strlen (arg) + 1);
   2248     if (kopt == NULL)
   2249     {
   2250 	pending_error = ENOMEM;
   2251 	return;
   2252     }
   2253     strcpy (kopt, arg);
   2254 }
   2255 
   2256 
   2257 
   2258 static void
   2259 serve_checkin_time (char *arg)
   2260 {
   2261     struct timespec t;
   2262 
   2263     if (error_pending ()
   2264 # ifdef PROXY_SUPPORT
   2265 	|| proxy_log
   2266 # endif /* PROXY_SUPPORT */
   2267        )
   2268 	return;
   2269 
   2270     if (checkin_time_valid)
   2271     {
   2272 	if (alloc_pending (80 + strlen (arg)))
   2273 	    sprintf (pending_error_text,
   2274 		     "E protocol error: duplicate Checkin-time request: %s",
   2275 		     arg);
   2276 	return;
   2277     }
   2278 
   2279     if (!get_date (&t, arg, NULL))
   2280     {
   2281 	if (alloc_pending (80 + strlen (arg)))
   2282 	    sprintf (pending_error_text, "E cannot parse date %s", arg);
   2283 	return;
   2284     }
   2285 
   2286     /* Truncate any nanoseconds returned by get_date().  */
   2287     checkin_time = t.tv_sec;
   2288     checkin_time_valid = 1;
   2289 }
   2290 
   2291 
   2292 
   2293 static void
   2294 server_write_entries (void)
   2295 {
   2296     FILE *f;
   2297     struct an_entry *p;
   2298     struct an_entry *q;
   2299 
   2300     if (entries == NULL)
   2301 	return;
   2302 
   2303     f = NULL;
   2304     /* Note that we free all the entries regardless of errors.  */
   2305     if (!error_pending ())
   2306     {
   2307 	/* We open in append mode because we don't want to clobber an
   2308 	   existing Entries file.  If we are checking out a module
   2309 	   which explicitly lists more than one file in a particular
   2310 	   directory, then we will wind up calling
   2311 	   server_write_entries for each such file.  */
   2312 	f = CVS_FOPEN (CVSADM_ENT, "a");
   2313 	if (f == NULL)
   2314 	{
   2315 	    int save_errno = errno;
   2316 	    if (alloc_pending (80 + strlen (CVSADM_ENT)))
   2317 		sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
   2318 	    pending_error = save_errno;
   2319 	}
   2320     }
   2321     for (p = entries; p != NULL;)
   2322     {
   2323 	if (!error_pending ())
   2324 	{
   2325 	    if (fprintf (f, "%s\n", p->entry) < 0)
   2326 	    {
   2327 		int save_errno = errno;
   2328 		if (alloc_pending (80 + strlen(CVSADM_ENT)))
   2329 		    sprintf (pending_error_text,
   2330 			     "E cannot write to %s", CVSADM_ENT);
   2331 		pending_error = save_errno;
   2332 	    }
   2333 	}
   2334 	free (p->entry);
   2335 	q = p->next;
   2336 	free (p);
   2337 	p = q;
   2338     }
   2339     entries = NULL;
   2340     if (f != NULL && fclose (f) == EOF && !error_pending ())
   2341     {
   2342 	int save_errno = errno;
   2343 	if (alloc_pending (80 + strlen (CVSADM_ENT)))
   2344 	    sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
   2345 	pending_error = save_errno;
   2346     }
   2347 }
   2348 
   2349 
   2350 
   2351 # ifdef PROXY_SUPPORT
   2352 /*
   2353  * callback proc to run a script when admin finishes.
   2354  */
   2355 static int
   2356 prepost_proxy_proc (const char *repository, const char *filter, void *closure)
   2357 {
   2358     char *cmdline;
   2359     bool *pre = closure;
   2360 
   2361     /* %c = cvs_cmd_name
   2362      * %p = shortrepos
   2363      * %r = repository
   2364      */
   2365     TRACE (TRACE_FUNCTION, "prepost_proxy_proc (%s, %s, %s)", repository,
   2366 	   filter, *pre ? "pre" : "post");
   2367 
   2368     /*
   2369      * Cast any NULL arguments as appropriate pointers as this is an
   2370      * stdarg function and we need to be certain the caller gets what
   2371      * is expected.
   2372      */
   2373     cmdline = format_cmdline (
   2374 # ifdef SUPPORT_OLD_INFO_FMT_STRINGS
   2375 	                      0, ".",
   2376 # endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
   2377 	                      filter,
   2378 	                      "c", "s", cvs_cmd_name,
   2379 	                      "R", "s", referrer ? referrer->original : "NONE",
   2380 	                      "p", "s", ".",
   2381 	                      "r", "s", current_parsed_root->directory,
   2382 	                      "P", "s", config->PrimaryServer->original,
   2383 	                      (char *) NULL);
   2384 
   2385     if (!cmdline || !strlen (cmdline))
   2386     {
   2387 	if (cmdline) free (cmdline);
   2388 	if (*pre)
   2389 	    error (0, 0, "preadmin proc resolved to the empty string!");
   2390 	else
   2391 	    error (0, 0, "postadmin proc resolved to the empty string!");
   2392 	return 1;
   2393     }
   2394 
   2395     run_setup (cmdline);
   2396 
   2397     free (cmdline);
   2398 
   2399     /* FIXME - read the comment in verifymsg_proc() about why we use abs()
   2400      * below() and shouldn't.
   2401      */
   2402     return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
   2403 			  RUN_NORMAL | RUN_SIGIGNORE));
   2404 }
   2405 
   2406 
   2407 
   2408 /* Become a secondary write proxy to a master server.
   2409  *
   2410  * This function opens the connection to the primary, dumps the secondary log
   2411  * to the primary, then reads data from any available connection and writes it
   2412  * to its partner:
   2413  *
   2414  *   buf_from_net -> buf_to_primary
   2415  *   buf_from_primary -> buf_to_net
   2416  *
   2417  * When all "from" connections have sent EOF and all data has been sent to
   2418  * "to" connections, this function closes the "to" pipes and returns.
   2419  */
   2420 static void
   2421 become_proxy (void)
   2422 {
   2423     struct buffer *buf_to_primary;
   2424     struct buffer *buf_from_primary;
   2425 
   2426     /* Close the client log and open it for read.  */
   2427     struct buffer *buf_clientlog = log_buffer_rewind (proxy_log_out);
   2428     int status, to_primary_fd, from_primary_fd, to_net_fd, from_net_fd;
   2429 
   2430     /* Call presecondary script.  */
   2431     bool pre = true;
   2432 
   2433 	    char *data;
   2434 	    size_t thispass, got;
   2435 	    int s;
   2436 	    char *newdata;
   2437 
   2438     Parse_Info (CVSROOTADM_PREPROXY, current_parsed_root->directory,
   2439 		prepost_proxy_proc, PIOPT_ALL, &pre);
   2440 
   2441     /* Open connection to primary server.  */
   2442     open_connection_to_server (config->PrimaryServer, &buf_to_primary,
   2443                                &buf_from_primary);
   2444     setup_logfiles ("CVS_SECONDARY_LOG", &buf_to_primary, &buf_from_primary);
   2445     if ((status = set_nonblock (buf_from_primary)))
   2446 	error (1, status, "failed to set nonblocking io from primary");
   2447     if ((status = set_nonblock (buf_from_net)))
   2448 	error (1, status, "failed to set nonblocking io from client");
   2449     if ((status = set_nonblock (buf_to_primary)))
   2450 	error (1, status, "failed to set nonblocking io to primary");
   2451     if ((status = set_nonblock (buf_to_net)))
   2452 	error (1, status, "failed to set nonblocking io to client");
   2453 
   2454     to_primary_fd = buf_get_fd (buf_to_primary);
   2455     from_primary_fd = buf_get_fd (buf_from_primary);
   2456     to_net_fd = buf_get_fd (buf_to_net);
   2457     assert (to_primary_fd >= 0 && from_primary_fd >= 0 && to_net_fd >= 0);
   2458 
   2459     /* Close the client log and open it for read.  */
   2460     rewind_buf_from_net ();
   2461 
   2462     while (from_primary_fd >= 0 || to_primary_fd >= 0)
   2463     {
   2464 	fd_set readfds, writefds;
   2465 	int status, numfds = -1;
   2466 	struct timeval *timeout_ptr;
   2467 	struct timeval timeout;
   2468 	size_t toread;
   2469 
   2470 	FD_ZERO (&readfds);
   2471 	FD_ZERO (&writefds);
   2472 
   2473 	/* The fd for a multi-source buffer can change with any read.  */
   2474 	from_net_fd = buf_from_net ? buf_get_fd (buf_from_net) : -1;
   2475 
   2476 	if ((buf_from_net && !buf_empty_p (buf_from_net))
   2477 	    || (buf_from_primary && !buf_empty_p (buf_from_primary)))
   2478 	{
   2479 	    /* There is data pending so don't block if we don't find any new
   2480 	     * data on the fds.
   2481 	     */
   2482 	    timeout.tv_sec = 0;
   2483 	    timeout.tv_usec = 0;
   2484 	    timeout_ptr = &timeout;
   2485 	}
   2486 	else
   2487 	    /* block indefinately */
   2488 	    timeout_ptr = NULL;
   2489 
   2490 	/* Set writefds if data is pending.  */
   2491 	if (to_net_fd >= 0 && !buf_empty_p (buf_to_net))
   2492 	{
   2493 	    FD_SET (to_net_fd, &writefds);
   2494 	    numfds = MAX (numfds, to_net_fd);
   2495 	}
   2496 	if (to_primary_fd >= 0 && !buf_empty_p (buf_to_primary))
   2497 	{
   2498 	    FD_SET (to_primary_fd, &writefds);
   2499 	    numfds = MAX (numfds, to_primary_fd);
   2500 	}
   2501 
   2502 	/* Set readfds if descriptors are still open.  */
   2503 	if (from_net_fd >= 0)
   2504 	{
   2505 	    FD_SET (from_net_fd, &readfds);
   2506 	    numfds = MAX (numfds, from_net_fd);
   2507 	}
   2508 	if (from_primary_fd >= 0)
   2509 	{
   2510 	    FD_SET (from_primary_fd, &readfds);
   2511 	    numfds = MAX (numfds, from_primary_fd);
   2512 	}
   2513 
   2514 	/* NUMFDS needs to be the highest descriptor + 1 according to the
   2515 	 * select spec.
   2516 	 */
   2517 	numfds++;
   2518 
   2519 	do {
   2520 	    /* This used to select on exceptions too, but as far
   2521 	       as I know there was never any reason to do that and
   2522 	       SCO doesn't let you select on exceptions on pipes.  */
   2523 	    numfds = select (numfds, &readfds, &writefds,
   2524 			     NULL, timeout_ptr);
   2525 	    if (numfds < 0 && errno != EINTR)
   2526 	    {
   2527 		/* Sending an error to the client, possibly in the middle of a
   2528 		 * separate protocol message, will likely not mean much to the
   2529 		 * client, but it's better than nothing, I guess.
   2530 		 */
   2531 		buf_output0 (buf_to_net, "E select failed\n");
   2532 		print_error (errno);
   2533 		exit (EXIT_FAILURE);
   2534 	    }
   2535 	} while (numfds < 0);
   2536 
   2537 	if (numfds == 0)
   2538 	{
   2539 	    FD_ZERO (&readfds);
   2540 	    FD_ZERO (&writefds);
   2541 	}
   2542 
   2543 	if (to_net_fd >= 0 && FD_ISSET (to_net_fd, &writefds))
   2544 	{
   2545 	    /* What should we do with errors?  syslog() them?  */
   2546 	    buf_send_output (buf_to_net);
   2547 	    buf_flush (buf_to_net, false);
   2548 	}
   2549 
   2550 	status = 0;
   2551 	if (from_net_fd >= 0 && (FD_ISSET (from_net_fd, &readfds)))
   2552 	    status = buf_input_data (buf_from_net, NULL);
   2553 
   2554 	if (buf_from_net && !buf_empty_p (buf_from_net))
   2555 	{
   2556 	    if (buf_to_primary)
   2557 		buf_append_buffer (buf_to_primary, buf_from_net);
   2558 	    else
   2559 		/* (Sys?)log this?  */;
   2560 
   2561 	}
   2562 
   2563 	if (status == -1 /* EOF */)
   2564 	{
   2565 	    SIG_beginCrSect();
   2566 	    /* Need only to shut this down and set to NULL, really, in
   2567 	     * crit sec, to ensure no double-dispose and to make sure
   2568 	     * network pipes are closed as properly as possible, but I
   2569 	     * don't see much optimization potential in saving values and
   2570 	     * postponing the free.
   2571 	     */
   2572 	    buf_shutdown (buf_from_net);
   2573 	    buf_free (buf_from_net);
   2574 	    buf_from_net = NULL;
   2575 	    /* So buf_to_primary will be closed at the end of this loop.  */
   2576 	    from_net_fd = -1;
   2577 	    SIG_endCrSect();
   2578 	}
   2579 	else if (status > 0 /* ERRNO */)
   2580 	{
   2581 	    buf_output0 (buf_to_net,
   2582 			 "E buf_input_data failed reading from client\n");
   2583 	    print_error (status);
   2584 	    exit (EXIT_FAILURE);
   2585 	}
   2586 
   2587 	if (to_primary_fd >= 0 && FD_ISSET (to_primary_fd, &writefds))
   2588 	{
   2589 	    /* What should we do with errors?  syslog() them?  */
   2590 	    buf_send_output (buf_to_primary);
   2591 	    buf_flush (buf_to_primary, false);
   2592 	}
   2593 
   2594 	status = 0;
   2595 	if (from_primary_fd >= 0 && FD_ISSET (from_primary_fd, &readfds))
   2596 	    status = buf_input_data (buf_from_primary, &toread);
   2597 
   2598 	/* Avoid resending data from the server which we already sent to the
   2599 	 * client.  Otherwise clients get really confused.
   2600 	 */
   2601 	if (buf_clientlog
   2602 	    && buf_from_primary && !buf_empty_p (buf_from_primary))
   2603 	{
   2604 	    /* Dispose of data we already sent to the client.  */
   2605 	    while (buf_clientlog && toread > 0)
   2606 	    {
   2607 		s = buf_read_data (buf_clientlog, toread, &data, &got);
   2608 		if (s == -2)
   2609 		    error (1, ENOMEM, "Failed to read data.");
   2610 		if (s == -1)
   2611 		{
   2612 		    buf_shutdown (buf_clientlog);
   2613 		    buf_clientlog = NULL;
   2614 		}
   2615 		else if (s)
   2616 		    error (1, s, "Error reading writeproxy log.");
   2617 		else
   2618 		{
   2619 		    thispass = got;
   2620 		    while (thispass > 0)
   2621 		    {
   2622 			/* No need to check for errors here since we know we
   2623 			 * won't read more than buf_input read into
   2624 			 * BUF_FROM_PRIMARY (see how TOREAD is set above).
   2625 			 */
   2626 			buf_read_data (buf_from_primary, thispass, &newdata,
   2627 				       &got);
   2628 			/* Verify that we are throwing away what we think we
   2629 			 * are.
   2630 			 *
   2631 			 * It is valid to assume that the secondary and primary
   2632 			 * are closely enough in sync that this portion of the
   2633 			 * communication will be in sync beacuse if they were
   2634 			 * not, then the secondary might provide a
   2635 			 * valid-request string to the client which contained a
   2636 			 * request that the primary didn't support.  If the
   2637 			 * client later used the request, the primary server
   2638 			 * would exit anyhow.
   2639 			 *
   2640 			 * FIXME?
   2641 			 * An alternative approach might be to make sure that
   2642 			 * the secondary provides the same string as the
   2643 			 * primary regardless, for purposes like pointing a
   2644 			 * secondary at an unwitting primary, in which case it
   2645 			 * might be useful to have some way to override the
   2646 			 * valid-requests string on a secondary, but it seems
   2647 			 * much easier to simply sync the versions, at the
   2648 			 * moment.
   2649 			 */
   2650 			if (memcmp (data, newdata, got))
   2651 			    error (1, 0, "Secondary out of sync with primary!");
   2652 			data += got;
   2653 			thispass -= got;
   2654 		    }
   2655 		    toread -= got;
   2656 		}
   2657 	    }
   2658 	}
   2659 
   2660 	if (buf_from_primary && !buf_empty_p (buf_from_primary))
   2661 	{
   2662 	    if (buf_to_net)
   2663 		buf_append_buffer (buf_to_net, buf_from_primary);
   2664 	    else
   2665 		/* (Sys?)log this?  */;
   2666 
   2667 	}
   2668 
   2669 	if (status == -1 /* EOF */)
   2670 	{
   2671 	    buf_shutdown (buf_from_primary);
   2672 	    buf_from_primary = NULL;
   2673 	    from_primary_fd = -1;
   2674 	}
   2675 	else if (status > 0 /* ERRNO */)
   2676 	{
   2677 	    buf_output0 (buf_to_net,
   2678 			 "E buf_input_data failed reading from primary\n");
   2679 	    print_error (status);
   2680 	    exit (EXIT_FAILURE);
   2681 	}
   2682 
   2683 	/* If our "source pipe" is closed and all data has been sent, avoid
   2684 	 * selecting it for writability, but don't actually close the buffer in
   2685 	 * case other routines want to use it later.  The buffer will be closed
   2686 	 * in server_cleanup ().
   2687 	 */
   2688 	if (from_primary_fd < 0
   2689 	    && buf_to_net && buf_empty_p (buf_to_net))
   2690 	    to_net_fd = -1;
   2691 
   2692 	if (buf_to_primary
   2693 	    && (/* Assume that there is no further reason to keep the buffer to
   2694 	         * the primary open if we can no longer read its responses.
   2695 	         */
   2696 	        (from_primary_fd < 0 && buf_to_primary)
   2697 	        /* Also close buf_to_primary when it becomes impossible to find
   2698 	         * more data to send to it.  We don't close buf_from_primary
   2699 	         * yet since there may be data pending or the primary may react
   2700 	         * to the EOF on its input pipe.
   2701 	         */
   2702 	        || (from_net_fd < 0 && buf_empty_p (buf_to_primary))))
   2703 	{
   2704 	    buf_shutdown (buf_to_primary);
   2705 	    buf_free (buf_to_primary);
   2706 	    buf_to_primary = NULL;
   2707 
   2708 	    /* Setting the fd < 0 with from_primary_fd already < 0 will cause
   2709 	     * an escape from this while loop.
   2710 	     */
   2711 	    to_primary_fd = -1;
   2712 	}
   2713     }
   2714 
   2715     /* Call postsecondary script.  */
   2716     pre = false;
   2717     Parse_Info (CVSROOTADM_POSTPROXY, current_parsed_root->directory,
   2718 		prepost_proxy_proc, PIOPT_ALL, &pre);
   2719 }
   2720 # endif /* PROXY_SUPPORT */
   2721 
   2722 
   2723 
   2724 struct notify_note {
   2725     /* Directory in which this notification happens.  xmalloc'd*/
   2726     char *dir;
   2727 
   2728     /* xmalloc'd.  */
   2729     char *update_dir;
   2730 
   2731     /* xmalloc'd.  */
   2732     char *filename;
   2733 
   2734     /* The following three all in one xmalloc'd block, pointed to by TYPE.
   2735        Each '\0' terminated.  */
   2736     /* "E" or "U".  */
   2737     char *type;
   2738     /* time+host+dir */
   2739     char *val;
   2740     char *watches;
   2741 
   2742     struct notify_note *next;
   2743 };
   2744 
   2745 static struct notify_note *notify_list;
   2746 /* Used while building list, to point to the last node that already exists.  */
   2747 static struct notify_note *last_node;
   2748 
   2749 static void
   2750 serve_notify (char *arg)
   2751 {
   2752     struct notify_note *new = NULL;
   2753     char *data = NULL;
   2754     int status;
   2755 
   2756     if (error_pending ()) return;
   2757 
   2758     if (isProxyServer())
   2759     {
   2760 # ifdef PROXY_SUPPORT
   2761 	if (!proxy_log)
   2762 	{
   2763 # endif /* PROXY_SUPPORT */
   2764 	    if (alloc_pending (160) + strlen (program_name))
   2765 		sprintf (pending_error_text,
   2766 "E This CVS server does not support disconnected `%s edit'.  For now, remove all `%s' files in your workspace and try your command again.",
   2767 			 program_name, CVSADM_NOTIFY);
   2768 	return;
   2769 # ifdef PROXY_SUPPORT
   2770 	}
   2771 	else
   2772 	{
   2773 	    /* This is effectively a write command, so run it on the primary.  */
   2774 	    become_proxy ();
   2775 	    exit (EXIT_SUCCESS);
   2776 	}
   2777 # endif /* PROXY_SUPPORT */
   2778     }
   2779 
   2780     if (outside_dir (arg))
   2781 	return;
   2782 
   2783     if (gDirname == NULL)
   2784 	goto error;
   2785 
   2786     new = xmalloc (sizeof (struct notify_note));
   2787     if (new == NULL)
   2788     {
   2789 	pending_error = ENOMEM;
   2790 	return;
   2791     }
   2792     new->dir = xmalloc (strlen (gDirname) + 1);
   2793     new->update_dir = xmalloc (strlen (gupdate_dir) + 1);
   2794     new->filename = xmalloc (strlen (arg) + 1);
   2795     if (new->dir == NULL || new->update_dir == NULL || new->filename == NULL)
   2796     {
   2797 	pending_error = ENOMEM;
   2798 	if (new->dir != NULL)
   2799 	    free (new->dir);
   2800 	free (new);
   2801 	return;
   2802     }
   2803     strcpy (new->dir, gDirname);
   2804     strcpy (new->update_dir, gupdate_dir);
   2805     strcpy (new->filename, arg);
   2806 
   2807     status = buf_read_line (buf_from_net, &data, NULL);
   2808     if (status != 0)
   2809     {
   2810 	if (status == -2)
   2811 	    pending_error = ENOMEM;
   2812 	else
   2813 	{
   2814 	    pending_error_text = xmalloc (80 + strlen (arg));
   2815 	    if (pending_error_text == NULL)
   2816 		pending_error = ENOMEM;
   2817 	    else
   2818 	    {
   2819 		if (status == -1)
   2820 		    sprintf (pending_error_text,
   2821 			     "E end of file reading notification for %s", arg);
   2822 		else
   2823 		{
   2824 		    sprintf (pending_error_text,
   2825 			     "E error reading notification for %s", arg);
   2826 		    pending_error = status;
   2827 		}
   2828 	    }
   2829 	}
   2830 	free (new->filename);
   2831 	free (new->dir);
   2832 	free (new);
   2833     }
   2834     else
   2835     {
   2836 	char *cp;
   2837 
   2838 	if (!data[0])
   2839 	    goto error;
   2840 
   2841 	if (strchr (data, '+'))
   2842 	    goto error;
   2843 
   2844 	new->type = data;
   2845 	if (data[1] != '\t')
   2846 	    goto error;
   2847 	data[1] = '\0';
   2848 	cp = data + 2;
   2849 	new->val = cp;
   2850 	cp = strchr (cp, '\t');
   2851 	if (cp == NULL)
   2852 	    goto error;
   2853 	*cp++ = '+';
   2854 	cp = strchr (cp, '\t');
   2855 	if (cp == NULL)
   2856 	    goto error;
   2857 	*cp++ = '+';
   2858 	cp = strchr (cp, '\t');
   2859 	if (cp == NULL)
   2860 	    goto error;
   2861 	*cp++ = '\0';
   2862 	new->watches = cp;
   2863 	/* If there is another tab, ignore everything after it,
   2864 	   for future expansion.  */
   2865 	cp = strchr (cp, '\t');
   2866 	if (cp != NULL)
   2867 	    *cp = '\0';
   2868 
   2869 	new->next = NULL;
   2870 
   2871 	if (last_node == NULL)
   2872 	    notify_list = new;
   2873 	else
   2874 	    last_node->next = new;
   2875 	last_node = new;
   2876     }
   2877     return;
   2878   error:
   2879     pending_error = 0;
   2880     if (alloc_pending (80))
   2881 	strcpy (pending_error_text,
   2882 		"E Protocol error; misformed Notify request");
   2883     if (data != NULL)
   2884 	free (data);
   2885     if (new != NULL)
   2886     {
   2887 	free (new->filename);
   2888 	free (new->update_dir);
   2889 	free (new->dir);
   2890 	free (new);
   2891     }
   2892     return;
   2893 }
   2894 
   2895 
   2896 
   2897 static void
   2898 serve_hostname (char *arg)
   2899 {
   2900     free (hostname);
   2901     hostname = xstrdup (arg);
   2902     return;
   2903 }
   2904 
   2905 
   2906 
   2907 static void
   2908 serve_localdir (char *arg)
   2909 {
   2910     if (CurDir) free (CurDir);
   2911     CurDir = xstrdup (arg);
   2912 }
   2913 
   2914 
   2915 
   2916 /* Process all the Notify requests that we have stored up.  Returns 0
   2917    if successful, if not prints error message (via error()) and
   2918    returns negative value.  */
   2919 static int
   2920 server_notify (void)
   2921 {
   2922     struct notify_note *p;
   2923     char *repos;
   2924 
   2925     TRACE (TRACE_FUNCTION, "server_notify()");
   2926 
   2927     while (notify_list != NULL)
   2928     {
   2929 	if (CVS_CHDIR (notify_list->dir) < 0)
   2930 	{
   2931 	    error (0, errno, "cannot change to %s", notify_list->dir);
   2932 	    return -1;
   2933 	}
   2934 	repos = Name_Repository (NULL, NULL);
   2935 
   2936 	lock_dir_for_write (repos);
   2937 
   2938 	fileattr_startdir (repos);
   2939 
   2940 	notify_do (*notify_list->type, notify_list->filename,
   2941 		   notify_list->update_dir, getcaller(), notify_list->val,
   2942 		   notify_list->watches, repos);
   2943 
   2944 	buf_output0 (buf_to_net, "Notified ");
   2945 	{
   2946 	    char *dir = notify_list->dir + strlen (server_temp_dir) + 1;
   2947 	    if (dir[0] == '\0')
   2948 		buf_append_char (buf_to_net, '.');
   2949 	    else
   2950 		buf_output0 (buf_to_net, dir);
   2951 	    buf_append_char (buf_to_net, '/');
   2952 	    buf_append_char (buf_to_net, '\n');
   2953 	}
   2954 	buf_output0 (buf_to_net, repos);
   2955 	buf_append_char (buf_to_net, '/');
   2956 	buf_output0 (buf_to_net, notify_list->filename);
   2957 	buf_append_char (buf_to_net, '\n');
   2958 	free (repos);
   2959 
   2960 	p = notify_list->next;
   2961 	free (notify_list->filename);
   2962 	free (notify_list->dir);
   2963 	free (notify_list->type);
   2964 	free (notify_list);
   2965 	notify_list = p;
   2966 
   2967 	fileattr_write ();
   2968 	fileattr_free ();
   2969 
   2970 	Lock_Cleanup ();
   2971     }
   2972 
   2973     last_node = NULL;
   2974 
   2975     /* The code used to call fflush (stdout) here, but that is no
   2976        longer necessary.  The data is now buffered in buf_to_net,
   2977        which will be flushed by the caller, do_cvs_command.  */
   2978 
   2979     return 0;
   2980 }
   2981 
   2982 
   2983 
   2984 /* This request is processed in all passes since requests which must
   2985  * sometimes be processed before it is known whether we are running as a
   2986  * secondary or not, for instance the `expand-modules' request, sometimes use
   2987  * the `Arguments'.
   2988  */
   2989 static void
   2990 serve_argument (char *arg)
   2991 {
   2992     char *p;
   2993 
   2994     if (error_pending()) return;
   2995 
   2996     if (argument_count >= MAXARGS)
   2997     {
   2998 	if (alloc_pending (80))
   2999 	    sprintf (pending_error_text,
   3000 		     "E Protocol error: too many arguments");
   3001 	return;
   3002     }
   3003 
   3004     if (argument_vector_size <= argument_count)
   3005     {
   3006 	argument_vector_size *= 2;
   3007 	argument_vector = xnrealloc (argument_vector,
   3008 				     argument_vector_size, sizeof (char *));
   3009 	if (argument_vector == NULL)
   3010 	{
   3011 	    pending_error = ENOMEM;
   3012 	    return;
   3013 	}
   3014     }
   3015     p = xmalloc (strlen (arg) + 1);
   3016     if (p == NULL)
   3017     {
   3018 	pending_error = ENOMEM;
   3019 	return;
   3020     }
   3021     strcpy (p, arg);
   3022     argument_vector[argument_count++] = p;
   3023 }
   3024 
   3025 
   3026 
   3027 /* For secondary servers, this is handled in all passes, as is the `Argument'
   3028  * request, and for the same reasons.
   3029  */
   3030 static void
   3031 serve_argumentx (char *arg)
   3032 {
   3033     char *p;
   3034 
   3035     if (error_pending()) return;
   3036 
   3037     if (argument_count <= 1)
   3038     {
   3039 	if (alloc_pending (80))
   3040 	    sprintf (pending_error_text,
   3041 "E Protocol error: called argumentx without prior call to argument");
   3042 	return;
   3043     }
   3044 
   3045     p = argument_vector[argument_count - 1];
   3046     p = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1);
   3047     if (p == NULL)
   3048     {
   3049 	pending_error = ENOMEM;
   3050 	return;
   3051     }
   3052     strcat (p, "\n");
   3053     strcat (p, arg);
   3054     argument_vector[argument_count - 1] = p;
   3055 }
   3056 
   3057 
   3058 
   3059 static void
   3060 serve_global_option (char *arg)
   3061 {
   3062 # ifdef PROXY_SUPPORT
   3063     /* This can generate error messages and termination before `Root' requests,
   3064      * so it must be dealt with in the first pass.
   3065      */
   3066     if (reprocessing) return;
   3067 # endif /* PROXY_SUPPORT */
   3068 
   3069     if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0')
   3070     {
   3071     error_return:
   3072 	if (alloc_pending (strlen (arg) + 80))
   3073 	    sprintf (pending_error_text,
   3074 		     "E Protocol error: bad global option %s",
   3075 		     arg);
   3076 	return;
   3077     }
   3078     switch (arg[1])
   3079     {
   3080 	case 'l':
   3081 	    error(0, 0, "WARNING: global `-l' option ignored.");
   3082 	    break;
   3083 	case 'n':
   3084 	    noexec = 1;
   3085 	    logoff = 1;
   3086 	    break;
   3087 	case 'u':
   3088 	    nolock = 1;
   3089 	    break;
   3090 	case 'q':
   3091 	    quiet = 1;
   3092 	    break;
   3093 	case 'r':
   3094 	    cvswrite = 0;
   3095 	    break;
   3096 	case 'Q':
   3097 	    really_quiet = 1;
   3098 	    break;
   3099 	case 't':
   3100 	    trace++;
   3101 	    break;
   3102 	default:
   3103 	    goto error_return;
   3104     }
   3105 }
   3106 
   3107 
   3108 
   3109 /* This needs to be processed before Root requests, so we allow it to be
   3110  * be processed before knowing whether we are running as a secondary server
   3111  * to allow `noop' and `Root' requests to generate errors as before.
   3112  */
   3113 static void
   3114 serve_set (char *arg)
   3115 {
   3116 # ifdef PROXY_SUPPORT
   3117     if (reprocessing) return;
   3118 # endif /* PROXY_SUPPORT */
   3119 
   3120     /* FIXME: This sends errors immediately (I think); they should be
   3121        put into pending_error.  */
   3122     variable_set (arg);
   3123 }
   3124 
   3125 # ifdef ENCRYPTION
   3126 
   3127 #   ifdef HAVE_KERBEROS
   3128 
   3129 static void
   3130 serve_kerberos_encrypt( char *arg )
   3131 {
   3132 #     ifdef PROXY_SUPPORT
   3133     assert (!proxy_log);
   3134 #     endif /* PROXY_SUPPORT */
   3135 
   3136     /* All future communication with the client will be encrypted.  */
   3137 
   3138     buf_to_net = krb_encrypt_buffer_initialize (buf_to_net, 0, sched,
   3139 						kblock,
   3140 						buf_to_net->memory_error);
   3141     buf_from_net = krb_encrypt_buffer_initialize (buf_from_net, 1, sched,
   3142 						  kblock,
   3143 						  buf_from_net->memory_error);
   3144 }
   3145 
   3146 #   endif /* HAVE_KERBEROS */
   3147 
   3148 #   ifdef HAVE_GSSAPI
   3149 
   3150 static void
   3151 serve_gssapi_encrypt( char *arg )
   3152 {
   3153 #     ifdef PROXY_SUPPORT
   3154     assert (!proxy_log);
   3155 #     endif /* PROXY_SUPPORT */
   3156 
   3157     if (cvs_gssapi_wrapping)
   3158     {
   3159 	/* We're already using a gssapi_wrap buffer for stream
   3160 	   authentication.  Flush everything we've output so far, and
   3161 	   turn on encryption for future data.  On the input side, we
   3162 	   should only have unwrapped as far as the Gssapi-encrypt
   3163 	   command, so future unwrapping will become encrypted.  */
   3164 	buf_flush (buf_to_net, 1);
   3165 	cvs_gssapi_encrypt = 1;
   3166 	return;
   3167     }
   3168 
   3169     /* All future communication with the client will be encrypted.  */
   3170 
   3171     cvs_gssapi_encrypt = 1;
   3172 
   3173     buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
   3174 						    gcontext,
   3175 						    buf_to_net->memory_error);
   3176     buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
   3177 						      gcontext,
   3178 						      buf_from_net->memory_error);
   3179 
   3180     cvs_gssapi_wrapping = 1;
   3181 }
   3182 
   3183 #   endif /* HAVE_GSSAPI */
   3184 
   3185 # endif /* ENCRYPTION */
   3186 
   3187 # ifdef HAVE_GSSAPI
   3188 
   3189 static void
   3190 serve_gssapi_authenticate (char *arg)
   3191 {
   3192 #   ifdef PROXY_SUPPORT
   3193     assert (!proxy_log);
   3194 #   endif /* PROXY_SUPPORT */
   3195 
   3196     if (cvs_gssapi_wrapping)
   3197     {
   3198 	/* We're already using a gssapi_wrap buffer for encryption.
   3199 	   That includes authentication, so we don't have to do
   3200 	   anything further.  */
   3201 	return;
   3202     }
   3203 
   3204     buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
   3205 						    gcontext,
   3206 						    buf_to_net->memory_error);
   3207     buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
   3208 						      gcontext,
   3209 						      buf_from_net->memory_error);
   3210 
   3211     cvs_gssapi_wrapping = 1;
   3212 }
   3213 
   3214 # endif /* HAVE_GSSAPI */
   3215 
   3216 
   3217 
   3218 # ifdef SERVER_FLOWCONTROL
   3219 /* The maximum we'll queue to the remote client before blocking.  */
   3220 #   ifndef SERVER_HI_WATER
   3221 #     define SERVER_HI_WATER (2 * 1024 * 1024)
   3222 #   endif /* SERVER_HI_WATER */
   3223 /* When the buffer drops to this, we restart the child */
   3224 #   ifndef SERVER_LO_WATER
   3225 #     define SERVER_LO_WATER (1 * 1024 * 1024)
   3226 #   endif /* SERVER_LO_WATER */
   3227 # endif /* SERVER_FLOWCONTROL */
   3228 
   3229 
   3230 
   3231 static void
   3232 serve_questionable (char *arg)
   3233 {
   3234     static int initted;
   3235 
   3236 # ifdef PROXY_SUPPORT
   3237     if (proxy_log) return;
   3238 # endif /* PROXY_SUPPORT */
   3239 
   3240     if (error_pending ()) return;
   3241 
   3242     if (!initted)
   3243     {
   3244 	/* Pick up ignores from CVSROOTADM_IGNORE, $HOME/.cvsignore on server,
   3245 	   and CVSIGNORE on server.  */
   3246 	ign_setup ();
   3247 	initted = 1;
   3248     }
   3249 
   3250     if (gDirname == NULL)
   3251     {
   3252 	if (alloc_pending (80))
   3253 	    sprintf (pending_error_text,
   3254 "E Protocol error: `Directory' missing");
   3255 	return;
   3256     }
   3257 
   3258     if (outside_dir (arg))
   3259 	return;
   3260 
   3261     if (!ign_name (arg))
   3262     {
   3263 	char *update_dir;
   3264 
   3265 	buf_output (buf_to_net, "M ? ", 4);
   3266 	update_dir = gDirname + strlen (server_temp_dir) + 1;
   3267 	if (!(update_dir[0] == '.' && update_dir[1] == '\0'))
   3268 	{
   3269 	    buf_output0 (buf_to_net, update_dir);
   3270 	    buf_output (buf_to_net, "/", 1);
   3271 	}
   3272 	buf_output0 (buf_to_net, arg);
   3273 	buf_output (buf_to_net, "\n", 1);
   3274     }
   3275 }
   3276 
   3277 
   3278 
   3279 static struct buffer *protocol = NULL;
   3280 
   3281 /* This is the output which we are saving up to send to the server, in the
   3282    child process.  We will push it through, via the `protocol' buffer, when
   3283    we have a complete line.  */
   3284 static struct buffer *saved_output;
   3285 
   3286 /* Likewise, but stuff which will go to stderr.  */
   3287 static struct buffer *saved_outerr;
   3288 
   3289 
   3290 
   3291 static void
   3292 protocol_memory_error (struct buffer *buf)
   3293 {
   3294     error (1, ENOMEM, "Virtual memory exhausted");
   3295 }
   3296 
   3297 
   3298 
   3299 /* If command is valid, return 1.
   3300  * Else if command is invalid and croak_on_invalid is set, then die.
   3301  * Else just return 0 to indicate that command is invalid.
   3302  */
   3303 static bool
   3304 check_command_valid_p (char *cmd_name)
   3305 {
   3306     /* Right now, only pserver notices invalid commands -- namely,
   3307      * write attempts by a read-only user.  Therefore, if CVS_Username
   3308      * is not set, this just returns 1, because CVS_Username unset
   3309      * means pserver is not active.
   3310      */
   3311 # ifdef AUTH_SERVER_SUPPORT
   3312     if (CVS_Username == NULL)
   3313 	return true;
   3314 
   3315     if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY)
   3316     {
   3317 	/* This command has the potential to modify the repository, so
   3318 	 * we check if the user have permission to do that.
   3319 	 *
   3320 	 * (Only relevant for remote users -- local users can do
   3321 	 * whatever normal Unix file permissions allow them to do.)
   3322 	 *
   3323 	 * The decision method:
   3324 	 *
   3325 	 *    If $CVSROOT/CVSADMROOT_READERS exists and user is listed
   3326 	 *    in it, then read-only access for user.
   3327 	 *
   3328 	 *    Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
   3329 	 *    listed in it, then also read-only access for user.
   3330 	 *
   3331 	 *    Else read-write access for user.
   3332 	 */
   3333 
   3334 	 char *linebuf = NULL;
   3335 	 int num_red = 0;
   3336 	 size_t linebuf_len = 0;
   3337 	 char *fname;
   3338 	 size_t flen;
   3339 	 FILE *fp;
   3340 	 int found_it = 0;
   3341 
   3342 	 /* else */
   3343 	 flen = strlen (current_parsed_root->directory)
   3344 		+ strlen (CVSROOTADM)
   3345 		+ strlen (CVSROOTADM_READERS)
   3346 		+ 3;
   3347 
   3348 	 fname = xmalloc (flen);
   3349 	 (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
   3350 			CVSROOTADM, CVSROOTADM_READERS);
   3351 
   3352 	 fp = fopen (fname, "r");
   3353 
   3354 	 if (fp == NULL)
   3355 	 {
   3356 	     if (!existence_error (errno))
   3357 	     {
   3358 		 /* Need to deny access, so that attackers can't fool
   3359 		    us with some sort of denial of service attack.  */
   3360 		 error (0, errno, "cannot open %s", fname);
   3361 		 free (fname);
   3362 		 return false;
   3363 	     }
   3364 	 }
   3365          else  /* successfully opened readers file */
   3366          {
   3367              while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
   3368              {
   3369                  /* Hmmm, is it worth importing my own readline
   3370                     library into CVS?  It takes care of chopping
   3371                     leading and trailing whitespace, "#" comments, and
   3372                     newlines automatically when so requested.  Would
   3373                     save some code here...  -kff */
   3374 
   3375                  /* Chop newline by hand, for strcmp()'s sake. */
   3376                  if (num_red > 0 && linebuf[num_red - 1] == '\n')
   3377                      linebuf[num_red - 1] = '\0';
   3378 
   3379                  if (strcmp (linebuf, CVS_Username) == 0)
   3380                      goto handle_invalid;
   3381              }
   3382 	     if (num_red < 0 && !feof (fp))
   3383 		 error (0, errno, "cannot read %s", fname);
   3384 
   3385 	     /* If not listed specifically as a reader, then this user
   3386 		has write access by default unless writers are also
   3387 		specified in a file . */
   3388 	     if (fclose (fp) < 0)
   3389 		 error (0, errno, "cannot close %s", fname);
   3390 	 }
   3391 	 free (fname);
   3392 
   3393 	 /* Now check the writers file.  */
   3394 
   3395 	 flen = strlen (current_parsed_root->directory)
   3396 		+ strlen (CVSROOTADM)
   3397 		+ strlen (CVSROOTADM_WRITERS)
   3398 		+ 3;
   3399 
   3400 	 fname = xmalloc (flen);
   3401 	 (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory,
   3402 			CVSROOTADM, CVSROOTADM_WRITERS);
   3403 
   3404 	 fp = fopen (fname, "r");
   3405 
   3406 	 if (fp == NULL)
   3407 	 {
   3408 	     if (linebuf)
   3409 		 free (linebuf);
   3410 	     if (existence_error (errno))
   3411 	     {
   3412 		 /* Writers file does not exist, so everyone is a writer,
   3413 		    by default.  */
   3414 		 free (fname);
   3415 		 return true;
   3416 	     }
   3417 	     else
   3418 	     {
   3419 		 /* Need to deny access, so that attackers can't fool
   3420 		    us with some sort of denial of service attack.  */
   3421 		 error (0, errno, "cannot read %s", fname);
   3422 		 free (fname);
   3423 		 return false;
   3424 	     }
   3425 	 }
   3426 
   3427 	 found_it = 0;
   3428 	 while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
   3429 	 {
   3430 	     /* Chop newline by hand, for strcmp()'s sake. */
   3431 	     if (num_red > 0 && linebuf[num_red - 1] == '\n')
   3432 		 linebuf[num_red - 1] = '\0';
   3433 
   3434 	     if (strcmp (linebuf, CVS_Username) == 0)
   3435 	     {
   3436 		 found_it = 1;
   3437 		 break;
   3438 	     }
   3439 	 }
   3440 	 if (num_red < 0 && !feof (fp))
   3441 	     error (0, errno, "cannot read %s", fname);
   3442 
   3443 	 if (found_it)
   3444 	 {
   3445 	     if (fclose (fp) < 0)
   3446 		 error (0, errno, "cannot close %s", fname);
   3447 	     if (linebuf)
   3448 		 free (linebuf);
   3449 	     free (fname);
   3450              return true;
   3451          }
   3452          else   /* writers file exists, but this user not listed in it */
   3453          {
   3454          handle_invalid:
   3455              if (fclose (fp) < 0)
   3456 		 error (0, errno, "cannot close %s", fname);
   3457 	     if (linebuf)
   3458 		 free (linebuf);
   3459 	     free (fname);
   3460 	     return false;
   3461 	 }
   3462     }
   3463 # endif /* AUTH_SERVER_SUPPORT */
   3464 
   3465     /* If ever reach end of this function, command must be valid. */
   3466     return true;
   3467 }
   3468 
   3469 
   3470 
   3471 /* Execute COMMAND in a subprocess with the approriate funky things done.  */
   3472 
   3473 static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain;
   3474 # ifdef SUNOS_KLUDGE
   3475 static int max_command_fd;
   3476 # endif
   3477 
   3478 # ifdef SERVER_FLOWCONTROL
   3479 static int flowcontrol_pipe[2];
   3480 # endif /* SERVER_FLOWCONTROL */
   3481 
   3482 
   3483 
   3484 /*
   3485  * Set buffer FD to non-blocking I/O.  Returns 0 for success or errno
   3486  * code.
   3487  */
   3488 int
   3489 set_nonblock_fd (int fd)
   3490 {
   3491 # if defined (F_GETFL) && defined (O_NONBLOCK) && defined (F_SETFL)
   3492     int flags;
   3493 
   3494     flags = fcntl (fd, F_GETFL, 0);
   3495     if (flags < 0)
   3496 	return errno;
   3497     if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
   3498 	return errno;
   3499 # endif /* F_GETFL && O_NONBLOCK && F_SETFL */
   3500     return 0;
   3501 }
   3502 
   3503 
   3504 
   3505 static void
   3506 do_cvs_command (char *cmd_name, int (*command) (int, char **))
   3507 {
   3508     /*
   3509      * The following file descriptors are set to -1 if that file is not
   3510      * currently open.
   3511      */
   3512 
   3513     /* Data on these pipes is a series of '\n'-terminated lines.  */
   3514     int stdout_pipe[2];
   3515     int stderr_pipe[2];
   3516 
   3517     /*
   3518      * Data on this pipe is a series of counted (see buf_send_counted)
   3519      * packets.  Each packet must be processed atomically (i.e. not
   3520      * interleaved with data from stdout_pipe or stderr_pipe).
   3521      */
   3522     int protocol_pipe[2];
   3523 
   3524     int dev_null_fd = -1;
   3525 
   3526     int errs;
   3527 
   3528     TRACE (TRACE_FUNCTION, "do_cvs_command (%s)", cmd_name);
   3529 
   3530     /* Write proxy logging is always terminated when a command is received.
   3531      * Therefore, we wish to avoid reprocessing the command since that would
   3532      * cause endless recursion.
   3533      */
   3534     if (isProxyServer())
   3535     {
   3536 # ifdef PROXY_SUPPORT
   3537 	if (reprocessing)
   3538 	    /* This must be the second time we've reached this point.
   3539 	     * Done reprocessing.
   3540 	     */
   3541 	    reprocessing = false;
   3542 	else
   3543 	{
   3544 	    if (lookup_command_attribute (cmd_name)
   3545 		    & CVS_CMD_MODIFIES_REPOSITORY)
   3546 	    {
   3547 		become_proxy ();
   3548 		exit (EXIT_SUCCESS);
   3549 	    }
   3550 	    else if (/* serve_co may have called this already and missing logs
   3551 		      * should have generated an error in serve_root().
   3552 		      */
   3553 		     proxy_log)
   3554 	    {
   3555 		/* Set up the log for reprocessing.  */
   3556 		rewind_buf_from_net ();
   3557 		/* And return to the main loop in server(), where we will now
   3558 		 * find the logged secondary data and reread it.
   3559 		 */
   3560 		return;
   3561 	    }
   3562 	}
   3563 # else /* !PROXY_SUPPORT */
   3564 	if (lookup_command_attribute (cmd_name)
   3565 		    & CVS_CMD_MODIFIES_REPOSITORY
   3566 	    && alloc_pending (120))
   3567 	    sprintf (pending_error_text,
   3568 "E You need a CVS client that supports the `Redirect' response for write requests to this server.");
   3569 	return;
   3570 # endif /* PROXY_SUPPORT */
   3571     }
   3572 
   3573     command_pid = -1;
   3574     stdout_pipe[0] = -1;
   3575     stdout_pipe[1] = -1;
   3576     stderr_pipe[0] = -1;
   3577     stderr_pipe[1] = -1;
   3578     protocol_pipe[0] = -1;
   3579     protocol_pipe[1] = -1;
   3580 
   3581     server_write_entries ();
   3582 
   3583     if (print_pending_error ())
   3584 	goto free_args_and_return;
   3585 
   3586     /* Global `cvs_cmd_name' is probably "server" right now -- only
   3587        serve_export() sets it to anything else.  So we will use local
   3588        parameter `cmd_name' to determine if this command is valid for
   3589        this user.  */
   3590     if (!check_command_valid_p (cmd_name))
   3591     {
   3592 	buf_output0 (buf_to_net, "E ");
   3593 	buf_output0 (buf_to_net, program_name);
   3594 	buf_output0 (buf_to_net, " [server aborted]: \"");
   3595 	buf_output0 (buf_to_net, cmd_name);
   3596 	buf_output0 (buf_to_net,
   3597 "\" requires write access to the repository\n\
   3598 error  \n");
   3599 	goto free_args_and_return;
   3600     }
   3601     cvs_cmd_name = cmd_name;
   3602 
   3603     (void) server_notify ();
   3604 
   3605     /*
   3606      * We use a child process which actually does the operation.  This
   3607      * is so we can intercept its standard output.  Even if all of CVS
   3608      * were written to go to some special routine instead of writing
   3609      * to stdout or stderr, we would still need to do the same thing
   3610      * for the RCS commands.
   3611      */
   3612 
   3613     if (pipe (stdout_pipe) < 0)
   3614     {
   3615 	buf_output0 (buf_to_net, "E pipe failed\n");
   3616 	print_error (errno);
   3617 	goto error_exit;
   3618     }
   3619     if (pipe (stderr_pipe) < 0)
   3620     {
   3621 	buf_output0 (buf_to_net, "E pipe failed\n");
   3622 	print_error (errno);
   3623 	goto error_exit;
   3624     }
   3625     if (pipe (protocol_pipe) < 0)
   3626     {
   3627 	buf_output0 (buf_to_net, "E pipe failed\n");
   3628 	print_error (errno);
   3629 	goto error_exit;
   3630     }
   3631 # ifdef SERVER_FLOWCONTROL
   3632     if (pipe (flowcontrol_pipe) < 0)
   3633     {
   3634 	buf_output0 (buf_to_net, "E pipe failed\n");
   3635 	print_error (errno);
   3636 	goto error_exit;
   3637     }
   3638     set_nonblock_fd (flowcontrol_pipe[0]);
   3639     set_nonblock_fd (flowcontrol_pipe[1]);
   3640 # endif /* SERVER_FLOWCONTROL */
   3641 
   3642     dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY);
   3643     if (dev_null_fd < 0)
   3644     {
   3645 	buf_output0 (buf_to_net, "E open /dev/null failed\n");
   3646 	print_error (errno);
   3647 	goto error_exit;
   3648     }
   3649 
   3650     /* We shouldn't have any partial lines from cvs_output and
   3651        cvs_outerr, but we handle them here in case there is a bug.  */
   3652     /* FIXME: appending a newline, rather than using "MT" as we
   3653        do in the child process, is probably not really a very good
   3654        way to "handle" them.  */
   3655     if (! buf_empty_p (saved_output))
   3656     {
   3657 	buf_append_char (saved_output, '\n');
   3658 	buf_copy_lines (buf_to_net, saved_output, 'M');
   3659     }
   3660     if (! buf_empty_p (saved_outerr))
   3661     {
   3662 	buf_append_char (saved_outerr, '\n');
   3663 	buf_copy_lines (buf_to_net, saved_outerr, 'E');
   3664     }
   3665 
   3666     /* Flush out any pending data.  */
   3667     buf_flush (buf_to_net, 1);
   3668 
   3669     /* Don't use vfork; we're not going to exec().  */
   3670     command_pid = fork ();
   3671     if (command_pid < 0)
   3672     {
   3673 	buf_output0 (buf_to_net, "E fork failed\n");
   3674 	print_error (errno);
   3675 	goto error_exit;
   3676     }
   3677     if (command_pid == 0)
   3678     {
   3679 	int exitstatus;
   3680 
   3681 	/* Since we're in the child, and the parent is going to take
   3682 	   care of packaging up our error messages, we can clear this
   3683 	   flag.  */
   3684 	error_use_protocol = 0;
   3685 
   3686 	protocol = fd_buffer_initialize (protocol_pipe[1], 0, NULL, false,
   3687 					 protocol_memory_error);
   3688 
   3689 	/* At this point we should no longer be using buf_to_net and
   3690 	   buf_from_net.  Instead, everything should go through
   3691 	   protocol.  */
   3692 	if (buf_to_net != NULL)
   3693 	{
   3694 	    buf_free (buf_to_net);
   3695 	    buf_to_net = NULL;
   3696 	}
   3697 	if (buf_from_net != NULL)
   3698 	{
   3699 	    buf_free (buf_from_net);
   3700 	    buf_from_net = NULL;
   3701 	}
   3702 
   3703 	/* These were originally set up to use outbuf_memory_error.
   3704 	   Since we're now in the child, we should use the simpler
   3705 	   protocol_memory_error function.  */
   3706 	saved_output->memory_error = protocol_memory_error;
   3707 	saved_outerr->memory_error = protocol_memory_error;
   3708 
   3709 	if (dup2 (dev_null_fd, STDIN_FILENO) < 0)
   3710 	    error (1, errno, "can't set up pipes");
   3711 	if (dup2 (stdout_pipe[1], STDOUT_FILENO) < 0)
   3712 	    error (1, errno, "can't set up pipes");
   3713 	if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0)
   3714 	    error (1, errno, "can't set up pipes");
   3715 	close (dev_null_fd);
   3716 	close (stdout_pipe[0]);
   3717 	close (stdout_pipe[1]);
   3718 	close (stderr_pipe[0]);
   3719 	close (stderr_pipe[1]);
   3720 	close (protocol_pipe[0]);
   3721 	close_on_exec (protocol_pipe[1]);
   3722 # ifdef SERVER_FLOWCONTROL
   3723 	close_on_exec (flowcontrol_pipe[0]);
   3724 	close (flowcontrol_pipe[1]);
   3725 # endif /* SERVER_FLOWCONTROL */
   3726 
   3727 	/*
   3728 	 * Set this in .bashrc if you want to give yourself time to attach
   3729 	 * to the subprocess with a debugger.
   3730 	 */
   3731 	if (getenv ("CVS_SERVER_SLEEP"))
   3732 	{
   3733 	    int secs = atoi (getenv ("CVS_SERVER_SLEEP"));
   3734 	    TRACE (TRACE_DATA, "Sleeping CVS_SERVER_SLEEP (%d) seconds", secs);
   3735 	    sleep (secs);
   3736 	}
   3737 	else
   3738 	    TRACE (TRACE_DATA, "CVS_SERVER_SLEEP not set.");
   3739 
   3740 	exitstatus = (*command) (argument_count, argument_vector);
   3741 
   3742 	/* Output any partial lines.  If the client doesn't support
   3743 	   "MT", we go ahead and just tack on a newline since the
   3744 	   protocol doesn't support anything better.  */
   3745 	if (! buf_empty_p (saved_output))
   3746 	{
   3747 	    buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M ");
   3748 	    buf_append_buffer (protocol, saved_output);
   3749 	    buf_output (protocol, "\n", 1);
   3750 	    buf_send_counted (protocol);
   3751 	}
   3752 	/* For now we just discard partial lines on stderr.  I suspect
   3753 	   that CVS can't write such lines unless there is a bug.  */
   3754 
   3755 	buf_free (protocol);
   3756 
   3757 	/* Close the pipes explicitly in order to send an EOF to the parent,
   3758 	 * then wait for the parent to close the flow control pipe.  This
   3759 	 * avoids a race condition where a child which dumped more than the
   3760 	 * high water mark into the pipes could complete its job and exit,
   3761 	 * leaving the parent process to attempt to write a stop byte to the
   3762 	 * closed flow control pipe, which earned the parent a SIGPIPE, which
   3763 	 * it normally only expects on the network pipe and that causes it to
   3764 	 * exit with an error message, rather than the SIGCHILD that it knows
   3765 	 * how to handle correctly.
   3766 	 */
   3767 	/* Let exit() close STDIN - it's from /dev/null anyhow.  */
   3768 	fclose (stderr);
   3769 	fclose (stdout);
   3770 	close (protocol_pipe[1]);
   3771 # ifdef SERVER_FLOWCONTROL
   3772 	{
   3773 	    char junk;
   3774 	    ssize_t status;
   3775 	    while ((status = read (flowcontrol_pipe[0], &junk, 1)) > 0
   3776 	           || (status == -1 && errno == EAGAIN));
   3777 	}
   3778 	/* FIXME: No point in printing an error message with error(),
   3779 	 * as STDERR is already closed, but perhaps this could be syslogged?
   3780 	 */
   3781 # endif
   3782 
   3783 	exit (exitstatus);
   3784     }
   3785 
   3786     /* OK, sit around getting all the input from the child.  */
   3787     {
   3788 	struct buffer *stdoutbuf;
   3789 	struct buffer *stderrbuf;
   3790 	struct buffer *protocol_inbuf;
   3791 	/* Number of file descriptors to check in select ().  */
   3792 	int num_to_check;
   3793 	int count_needed = 1;
   3794 # ifdef SERVER_FLOWCONTROL
   3795 	int have_flowcontrolled = 0;
   3796 # endif /* SERVER_FLOWCONTROL */
   3797 
   3798 	FD_ZERO (&command_fds_to_drain.fds);
   3799 	num_to_check = stdout_pipe[0];
   3800 	FD_SET (stdout_pipe[0], &command_fds_to_drain.fds);
   3801 	num_to_check = MAX (num_to_check, stderr_pipe[0]);
   3802 	FD_SET (stderr_pipe[0], &command_fds_to_drain.fds);
   3803 	num_to_check = MAX (num_to_check, protocol_pipe[0]);
   3804 	FD_SET (protocol_pipe[0], &command_fds_to_drain.fds);
   3805 	num_to_check = MAX (num_to_check, STDOUT_FILENO);
   3806 # ifdef SUNOS_KLUDGE
   3807 	max_command_fd = num_to_check;
   3808 # endif
   3809 	/*
   3810 	 * File descriptors are numbered from 0, so num_to_check needs to
   3811 	 * be one larger than the largest descriptor.
   3812 	 */
   3813 	++num_to_check;
   3814 	if (num_to_check > FD_SETSIZE)
   3815 	{
   3816 	    buf_output0 (buf_to_net,
   3817 			 "E internal error: FD_SETSIZE not big enough.\n\
   3818 error  \n");
   3819 	    goto error_exit;
   3820 	}
   3821 
   3822 	stdoutbuf = fd_buffer_initialize (stdout_pipe[0], 0, NULL, true,
   3823 					  input_memory_error);
   3824 
   3825 	stderrbuf = fd_buffer_initialize (stderr_pipe[0], 0, NULL, true,
   3826 					  input_memory_error);
   3827 
   3828 	protocol_inbuf = fd_buffer_initialize (protocol_pipe[0], 0, NULL, true,
   3829 					       input_memory_error);
   3830 
   3831 	set_nonblock (buf_to_net);
   3832 	set_nonblock (stdoutbuf);
   3833 	set_nonblock (stderrbuf);
   3834 	set_nonblock (protocol_inbuf);
   3835 
   3836 	if (close (stdout_pipe[1]) < 0)
   3837 	{
   3838 	    buf_output0 (buf_to_net, "E close failed\n");
   3839 	    print_error (errno);
   3840 	    goto error_exit;
   3841 	}
   3842 	stdout_pipe[1] = -1;
   3843 
   3844 	if (close (stderr_pipe[1]) < 0)
   3845 	{
   3846 	    buf_output0 (buf_to_net, "E close failed\n");
   3847 	    print_error (errno);
   3848 	    goto error_exit;
   3849 	}
   3850 	stderr_pipe[1] = -1;
   3851 
   3852 	if (close (protocol_pipe[1]) < 0)
   3853 	{
   3854 	    buf_output0 (buf_to_net, "E close failed\n");
   3855 	    print_error (errno);
   3856 	    goto error_exit;
   3857 	}
   3858 	protocol_pipe[1] = -1;
   3859 
   3860 # ifdef SERVER_FLOWCONTROL
   3861 	if (close (flowcontrol_pipe[0]) < 0)
   3862 	{
   3863 	    buf_output0 (buf_to_net, "E close failed\n");
   3864 	    print_error (errno);
   3865 	    goto error_exit;
   3866 	}
   3867 	flowcontrol_pipe[0] = -1;
   3868 # endif /* SERVER_FLOWCONTROL */
   3869 
   3870 	if (close (dev_null_fd) < 0)
   3871 	{
   3872 	    buf_output0 (buf_to_net, "E close failed\n");
   3873 	    print_error (errno);
   3874 	    goto error_exit;
   3875 	}
   3876 	dev_null_fd = -1;
   3877 
   3878 	while (stdout_pipe[0] >= 0
   3879 	       || stderr_pipe[0] >= 0
   3880 	       || protocol_pipe[0] >= 0
   3881 	       || count_needed <= 0)
   3882 	{
   3883 	    fd_set readfds;
   3884 	    fd_set writefds;
   3885 	    int numfds;
   3886 	    struct timeval *timeout_ptr;
   3887 	    struct timeval timeout;
   3888 # ifdef SERVER_FLOWCONTROL
   3889 	    int bufmemsize;
   3890 
   3891 	    /*
   3892 	     * See if we are swamping the remote client and filling our VM.
   3893 	     * Tell child to hold off if we do.
   3894 	     */
   3895 	    bufmemsize = buf_count_mem (buf_to_net);
   3896 	    if (!have_flowcontrolled && (bufmemsize > SERVER_HI_WATER))
   3897 	    {
   3898 		if (write(flowcontrol_pipe[1], "S", 1) == 1)
   3899 		    have_flowcontrolled = 1;
   3900 	    }
   3901 	    else if (have_flowcontrolled && (bufmemsize < SERVER_LO_WATER))
   3902 	    {
   3903 		if (write(flowcontrol_pipe[1], "G", 1) == 1)
   3904 		    have_flowcontrolled = 0;
   3905 	    }
   3906 # endif /* SERVER_FLOWCONTROL */
   3907 
   3908 	    FD_ZERO (&readfds);
   3909 	    FD_ZERO (&writefds);
   3910 
   3911 	    if (count_needed <= 0)
   3912 	    {
   3913 		/* there is data pending which was read from the protocol pipe
   3914 		 * so don't block if we don't find any data
   3915 		 */
   3916 		timeout.tv_sec = 0;
   3917 		timeout.tv_usec = 0;
   3918 		timeout_ptr = &timeout;
   3919 	    }
   3920 	    else
   3921 	    {
   3922 		/* block indefinately */
   3923 		timeout_ptr = NULL;
   3924 	    }
   3925 
   3926 	    if (! buf_empty_p (buf_to_net))
   3927 		FD_SET (STDOUT_FILENO, &writefds);
   3928 
   3929 	    if (stdout_pipe[0] >= 0)
   3930 	    {
   3931 		FD_SET (stdout_pipe[0], &readfds);
   3932 	    }
   3933 	    if (stderr_pipe[0] >= 0)
   3934 	    {
   3935 		FD_SET (stderr_pipe[0], &readfds);
   3936 	    }
   3937 	    if (protocol_pipe[0] >= 0)
   3938 	    {
   3939 		FD_SET (protocol_pipe[0], &readfds);
   3940 	    }
   3941 
   3942 	    /* This process of selecting on the three pipes means that
   3943 	     we might not get output in the same order in which it
   3944 	     was written, thus producing the well-known
   3945 	     "out-of-order" bug.  If the child process uses
   3946 	     cvs_output and cvs_outerr, it will send everything on
   3947 	     the protocol_pipe and avoid this problem, so the
   3948 	     solution is to use cvs_output and cvs_outerr in the
   3949 	     child process.  */
   3950 	    do {
   3951 		/* This used to select on exceptions too, but as far
   3952 		   as I know there was never any reason to do that and
   3953 		   SCO doesn't let you select on exceptions on pipes.  */
   3954 		numfds = select (num_to_check, &readfds, &writefds,
   3955 				 NULL, timeout_ptr);
   3956 		if (numfds < 0
   3957 			&& errno != EINTR)
   3958 		{
   3959 		    buf_output0 (buf_to_net, "E select failed\n");
   3960 		    print_error (errno);
   3961 		    goto error_exit;
   3962 		}
   3963 	    } while (numfds < 0);
   3964 
   3965 	    if (numfds == 0)
   3966 	    {
   3967 		FD_ZERO (&readfds);
   3968 		FD_ZERO (&writefds);
   3969 	    }
   3970 
   3971 	    if (FD_ISSET (STDOUT_FILENO, &writefds))
   3972 	    {
   3973 		/* What should we do with errors?  syslog() them?  */
   3974 		buf_send_output (buf_to_net);
   3975 	    }
   3976 
   3977 	    if (protocol_pipe[0] >= 0
   3978 		&& (FD_ISSET (protocol_pipe[0], &readfds)))
   3979 	    {
   3980 		int status;
   3981 		size_t count_read;
   3982 
   3983 		status = buf_input_data (protocol_inbuf, &count_read);
   3984 
   3985 		if (status == -1)
   3986 		{
   3987 		    close (protocol_pipe[0]);
   3988 		    protocol_pipe[0] = -1;
   3989 		}
   3990 		else if (status > 0)
   3991 		{
   3992 		    buf_output0 (buf_to_net, "E buf_input_data failed\n");
   3993 		    print_error (status);
   3994 		    goto error_exit;
   3995 		}
   3996 
   3997 		/*
   3998 		 * We only call buf_copy_counted if we have read
   3999 		 * enough bytes to make it worthwhile.  This saves us
   4000 		 * from continually recounting the amount of data we
   4001 		 * have.
   4002 		 */
   4003 		count_needed -= count_read;
   4004 	    }
   4005 	    /* this is still part of the protocol pipe procedure, but it is
   4006 	     * outside the above conditional so that unprocessed data can be
   4007 	     * left in the buffer and stderr/stdout can be read when a flush
   4008 	     * signal is received and control can return here without passing
   4009 	     * through the select code and maybe blocking
   4010 	     */
   4011 	    while (count_needed <= 0)
   4012 	    {
   4013 		int special = 0;
   4014 
   4015 		count_needed = buf_copy_counted (buf_to_net,
   4016 						     protocol_inbuf,
   4017 						     &special);
   4018 
   4019 		/* What should we do with errors?  syslog() them?  */
   4020 		buf_send_output (buf_to_net);
   4021 
   4022 		/* If SPECIAL got set to <0, it means that the child
   4023 		 * wants us to flush the pipe & maybe stderr or stdout.
   4024 		 *
   4025 		 * After that we break to read stderr & stdout again before
   4026 		 * going back to the protocol pipe
   4027 		 *
   4028 		 * Upon breaking, count_needed = 0, so the next pass will only
   4029 		 * perform a non-blocking select before returning here to finish
   4030 		 * processing data we already read from the protocol buffer
   4031 		 */
   4032 		 if (special == -1)
   4033 		 {
   4034 		     cvs_flushout();
   4035 		     break;
   4036 		 }
   4037 		if (special == -2)
   4038 		{
   4039 		    /* If the client supports the 'F' command, we send it. */
   4040 		    if (supported_response ("F"))
   4041 		    {
   4042 			buf_append_char (buf_to_net, 'F');
   4043 			buf_append_char (buf_to_net, '\n');
   4044 		    }
   4045 		    cvs_flusherr ();
   4046 		    break;
   4047 		}
   4048 	    }
   4049 
   4050 	    if (stdout_pipe[0] >= 0
   4051 		&& (FD_ISSET (stdout_pipe[0], &readfds)))
   4052 	    {
   4053 		int status;
   4054 
   4055 		status = buf_input_data (stdoutbuf, NULL);
   4056 
   4057 		buf_copy_lines (buf_to_net, stdoutbuf, 'M');
   4058 
   4059 		if (status == -1)
   4060 		{
   4061 		    close (stdout_pipe[0]);
   4062 		    stdout_pipe[0] = -1;
   4063 		}
   4064 		else if (status > 0)
   4065 		{
   4066 		    buf_output0 (buf_to_net, "E buf_input_data failed\n");
   4067 		    print_error (status);
   4068 		    goto error_exit;
   4069 		}
   4070 
   4071 		/* What should we do with errors?  syslog() them?  */
   4072 		buf_send_output (buf_to_net);
   4073 	    }
   4074 
   4075 	    if (stderr_pipe[0] >= 0
   4076 		&& (FD_ISSET (stderr_pipe[0], &readfds)))
   4077 	    {
   4078 		int status;
   4079 
   4080 		status = buf_input_data (stderrbuf, NULL);
   4081 
   4082 		buf_copy_lines (buf_to_net, stderrbuf, 'E');
   4083 
   4084 		if (status == -1)
   4085 		{
   4086 		    close (stderr_pipe[0]);
   4087 		    stderr_pipe[0] = -1;
   4088 		}
   4089 		else if (status > 0)
   4090 		{
   4091 		    buf_output0 (buf_to_net, "E buf_input_data failed\n");
   4092 		    print_error (status);
   4093 		    goto error_exit;
   4094 		}
   4095 
   4096 		/* What should we do with errors?  syslog() them?  */
   4097 		buf_send_output (buf_to_net);
   4098 	    }
   4099 	}
   4100 
   4101 	/*
   4102 	 * OK, we've gotten EOF on all the pipes.  If there is
   4103 	 * anything left on stdoutbuf or stderrbuf (this could only
   4104 	 * happen if there was no trailing newline), send it over.
   4105 	 */
   4106 	if (! buf_empty_p (stdoutbuf))
   4107 	{
   4108 	    buf_append_char (stdoutbuf, '\n');
   4109 	    buf_copy_lines (buf_to_net, stdoutbuf, 'M');
   4110 	}
   4111 	if (! buf_empty_p (stderrbuf))
   4112 	{
   4113 	    buf_append_char (stderrbuf, '\n');
   4114 	    buf_copy_lines (buf_to_net, stderrbuf, 'E');
   4115 	}
   4116 	if (! buf_empty_p (protocol_inbuf))
   4117 	    buf_output0 (buf_to_net,
   4118 			 "E Protocol error: uncounted data discarded\n");
   4119 
   4120 # ifdef SERVER_FLOWCONTROL
   4121 	close (flowcontrol_pipe[1]);
   4122 	flowcontrol_pipe[1] = -1;
   4123 # endif /* SERVER_FLOWCONTROL */
   4124 
   4125 	errs = 0;
   4126 
   4127 	while (command_pid > 0)
   4128 	{
   4129 	    int status;
   4130 	    pid_t waited_pid;
   4131 	    waited_pid = waitpid (command_pid, &status, 0);
   4132 	    if (waited_pid < 0)
   4133 	    {
   4134 		/*
   4135 		 * Intentionally ignoring EINTR.  Other errors
   4136 		 * "can't happen".
   4137 		 */
   4138 		continue;
   4139 	    }
   4140 
   4141 	    if (WIFEXITED (status))
   4142 		errs += WEXITSTATUS (status);
   4143 	    else
   4144 	    {
   4145 		int sig = WTERMSIG (status);
   4146 		char buf[50];
   4147 		/*
   4148 		 * This is really evil, because signals might be numbered
   4149 		 * differently on the two systems.  We should be using
   4150 		 * signal names (either of the "Terminated" or the "SIGTERM"
   4151 		 * variety).  But cvs doesn't currently use libiberty...we
   4152 		 * could roll our own....  FIXME.
   4153 		 */
   4154 		buf_output0 (buf_to_net, "E Terminated with fatal signal ");
   4155 		sprintf (buf, "%d\n", sig);
   4156 		buf_output0 (buf_to_net, buf);
   4157 
   4158 		/* Test for a core dump.  */
   4159 		if (WCOREDUMP (status))
   4160 		{
   4161 		    buf_output0 (buf_to_net, "E Core dumped; preserving ");
   4162 		    buf_output0 (buf_to_net, orig_server_temp_dir);
   4163 		    buf_output0 (buf_to_net, " on server.\n\
   4164 E CVS locks may need cleaning up.\n");
   4165 		    dont_delete_temp = 1;
   4166 		}
   4167 		++errs;
   4168 	    }
   4169 	    if (waited_pid == command_pid)
   4170 		command_pid = -1;
   4171 	}
   4172 
   4173 	/*
   4174 	 * OK, we've waited for the child.  By now all CVS locks are free
   4175 	 * and it's OK to block on the network.
   4176 	 */
   4177 	set_block (buf_to_net);
   4178 	buf_flush (buf_to_net, 1);
   4179 	buf_shutdown (protocol_inbuf);
   4180 	buf_free (protocol_inbuf);
   4181 	protocol_inbuf = NULL;
   4182 	buf_shutdown (stderrbuf);
   4183 	buf_free (stderrbuf);
   4184 	stderrbuf = NULL;
   4185 	buf_shutdown (stdoutbuf);
   4186 	buf_free (stdoutbuf);
   4187 	stdoutbuf = NULL;
   4188     }
   4189 
   4190     if (errs)
   4191 	/* We will have printed an error message already.  */
   4192 	buf_output0 (buf_to_net, "error  \n");
   4193     else
   4194 	buf_output0 (buf_to_net, "ok\n");
   4195     goto free_args_and_return;
   4196 
   4197  error_exit:
   4198     if (command_pid > 0)
   4199 	kill (command_pid, SIGTERM);
   4200 
   4201     while (command_pid > 0)
   4202     {
   4203 	pid_t waited_pid;
   4204 	waited_pid = waitpid (command_pid, NULL, 0);
   4205 	if (waited_pid < 0 && errno == EINTR)
   4206 	    continue;
   4207 	if (waited_pid == command_pid)
   4208 	    command_pid = -1;
   4209     }
   4210 
   4211     close (dev_null_fd);
   4212     close (protocol_pipe[0]);
   4213     close (protocol_pipe[1]);
   4214     close (stderr_pipe[0]);
   4215     close (stderr_pipe[1]);
   4216     close (stdout_pipe[0]);
   4217     close (stdout_pipe[1]);
   4218 # ifdef SERVER_FLOWCONTROL
   4219     close (flowcontrol_pipe[0]);
   4220     close (flowcontrol_pipe[1]);
   4221 # endif /* SERVER_FLOWCONTROL */
   4222 
   4223  free_args_and_return:
   4224     /* Now free the arguments.  */
   4225     {
   4226 	/* argument_vector[0] is a dummy argument, we don't mess with it.  */
   4227 	char **cp;
   4228 	for (cp = argument_vector + 1;
   4229 	     cp < argument_vector + argument_count;
   4230 	     ++cp)
   4231 	    free (*cp);
   4232 
   4233 	argument_count = 1;
   4234     }
   4235 
   4236     /* Flush out any data not yet sent.  */
   4237     set_block (buf_to_net);
   4238     buf_flush (buf_to_net, 1);
   4239 
   4240     return;
   4241 }
   4242 
   4243 
   4244 
   4245 # ifdef SERVER_FLOWCONTROL
   4246 /*
   4247  * Called by the child at convenient points in the server's execution for
   4248  * the server child to block.. ie: when it has no locks active.
   4249  */
   4250 void
   4251 server_pause_check(void)
   4252 {
   4253     int paused = 0;
   4254     char buf[1];
   4255 
   4256     while (read (flowcontrol_pipe[0], buf, 1) == 1)
   4257     {
   4258 	if (*buf == 'S')	/* Stop */
   4259 	    paused = 1;
   4260 	else if (*buf == 'G')	/* Go */
   4261 	    paused = 0;
   4262 	else
   4263 	    return;		/* ??? */
   4264     }
   4265     while (paused) {
   4266 	int numfds, numtocheck;
   4267 	fd_set fds;
   4268 
   4269 	FD_ZERO (&fds);
   4270 	FD_SET (flowcontrol_pipe[0], &fds);
   4271 	numtocheck = flowcontrol_pipe[0] + 1;
   4272 
   4273 	do {
   4274 	    numfds = select (numtocheck, &fds, NULL, NULL, NULL);
   4275 	    if (numfds < 0
   4276 		&& errno != EINTR)
   4277 	    {
   4278 		buf_output0 (buf_to_net, "E select failed\n");
   4279 		print_error (errno);
   4280 		return;
   4281 	    }
   4282 	} while (numfds < 0);
   4283 
   4284 	if (FD_ISSET (flowcontrol_pipe[0], &fds))
   4285 	{
   4286 	    int got;
   4287 
   4288 	    while ((got = read (flowcontrol_pipe[0], buf, 1)) == 1)
   4289 	    {
   4290 		if (*buf == 'S')	/* Stop */
   4291 		    paused = 1;
   4292 		else if (*buf == 'G')	/* Go */
   4293 		    paused = 0;
   4294 		else
   4295 		    return;		/* ??? */
   4296 	    }
   4297 
   4298 	    /* This assumes that we are using BSD or POSIX nonblocking
   4299 	       I/O.  System V nonblocking I/O returns zero if there is
   4300 	       nothing to read.  */
   4301 	    if (got == 0)
   4302 		error (1, 0, "flow control EOF");
   4303 	    if (got < 0 && ! blocking_error (errno))
   4304 	    {
   4305 		error (1, errno, "flow control read failed");
   4306 	    }
   4307 	}
   4308     }
   4309 }
   4310 # endif /* SERVER_FLOWCONTROL */
   4311 
   4312 
   4313 
   4314 /* This variable commented in server.h.  */
   4315 char *server_dir = NULL;
   4316 
   4317 
   4318 
   4319 static void
   4320 output_dir (const char *update_dir, const char *repository)
   4321 {
   4322     /* Set up SHORT_REPOS.  */
   4323     const char *short_repos = Short_Repository (repository);
   4324 
   4325     /* Send the update_dir/repos.  */
   4326     if (server_dir != NULL)
   4327     {
   4328 	buf_output0 (protocol, server_dir);
   4329 	buf_output0 (protocol, "/");
   4330     }
   4331     if (update_dir[0] == '\0')
   4332 	buf_output0 (protocol, ".");
   4333     else
   4334 	buf_output0 (protocol, update_dir);
   4335     buf_output0 (protocol, "/\n");
   4336     if (short_repos[0] == '\0')
   4337 	buf_output0 (protocol, ".");
   4338     else
   4339 	buf_output0 (protocol, short_repos);
   4340     buf_output0 (protocol, "/");
   4341 }
   4342 
   4343 
   4344 
   4345 /*
   4346  * Entries line that we are squirreling away to send to the client when
   4347  * we are ready.
   4348  */
   4349 static char *entries_line;
   4350 
   4351 /*
   4352  * File which has been Scratch_File'd, we are squirreling away that fact
   4353  * to inform the client when we are ready.
   4354  */
   4355 static char *scratched_file;
   4356 
   4357 /*
   4358  * The scratched_file will need to be removed as well as having its entry
   4359  * removed.
   4360  */
   4361 static int kill_scratched_file;
   4362 
   4363 
   4364 
   4365 void
   4366 server_register (const char *name, const char *version, const char *timestamp,
   4367                  const char *options, const char *tag, const char *date,
   4368                  const char *conflict)
   4369 {
   4370     int len;
   4371 
   4372     if (options == NULL)
   4373 	options = "";
   4374 
   4375     TRACE (TRACE_FUNCTION, "server_register(%s, %s, %s, %s, %s, %s, %s)",
   4376 	   name, version, timestamp ? timestamp : "", options,
   4377 	   tag ? tag : "", date ? date : "",
   4378 	   conflict ? conflict : "");
   4379 
   4380     if (entries_line != NULL)
   4381     {
   4382 	/*
   4383 	 * If CVS decides to Register it more than once (which happens
   4384 	 * on "cvs update foo/foo.c" where foo and foo.c are already
   4385 	 * checked out), use the last of the entries lines Register'd.
   4386 	 */
   4387 	free (entries_line);
   4388     }
   4389 
   4390     /*
   4391      * I have reports of Scratch_Entry and Register both happening, in
   4392      * two different cases.  Using the last one which happens is almost
   4393      * surely correct; I haven't tracked down why they both happen (or
   4394      * even verified that they are for the same file).
   4395      */
   4396     if (scratched_file != NULL)
   4397     {
   4398 	free (scratched_file);
   4399 	scratched_file = NULL;
   4400     }
   4401 
   4402     len = (strlen (name) + strlen (version) + strlen (options) + 80);
   4403     if (tag)
   4404 	len += strlen (tag);
   4405     if (date)
   4406 	len += strlen (date);
   4407 
   4408     entries_line = xmalloc (len);
   4409     sprintf (entries_line, "/%s/%s/", name, version);
   4410     if (conflict != NULL)
   4411     {
   4412 	strcat (entries_line, "+=");
   4413     }
   4414     strcat (entries_line, "/");
   4415     strcat (entries_line, options);
   4416     strcat (entries_line, "/");
   4417     if (tag != NULL)
   4418     {
   4419 	strcat (entries_line, "T");
   4420 	strcat (entries_line, tag);
   4421     }
   4422     else if (date != NULL)
   4423     {
   4424 	strcat (entries_line, "D");
   4425 	strcat (entries_line, date);
   4426     }
   4427 }
   4428 
   4429 
   4430 
   4431 void
   4432 server_scratch (const char *fname)
   4433 {
   4434     /*
   4435      * I have reports of Scratch_Entry and Register both happening, in
   4436      * two different cases.  Using the last one which happens is almost
   4437      * surely correct; I haven't tracked down why they both happen (or
   4438      * even verified that they are for the same file).
   4439      *
   4440      * Don't know if this is what whoever wrote the above comment was
   4441      * talking about, but this can happen in the case where a join
   4442      * removes a file - the call to Register puts the '-vers' into the
   4443      * Entries file after the file is removed
   4444      */
   4445     if (entries_line != NULL)
   4446     {
   4447 	free (entries_line);
   4448 	entries_line = NULL;
   4449     }
   4450 
   4451     if (scratched_file != NULL)
   4452     {
   4453 	buf_output0 (protocol,
   4454 		     "E CVS server internal error: duplicate Scratch_Entry\n");
   4455 	buf_send_counted (protocol);
   4456 	return;
   4457     }
   4458     scratched_file = xstrdup (fname);
   4459     kill_scratched_file = 1;
   4460 }
   4461 
   4462 
   4463 
   4464 void
   4465 server_scratch_entry_only (void)
   4466 {
   4467     kill_scratched_file = 0;
   4468 }
   4469 
   4470 
   4471 
   4472 /* Print a new entries line, from a previous server_register.  */
   4473 static void
   4474 new_entries_line (void)
   4475 {
   4476     if (entries_line)
   4477     {
   4478 	buf_output0 (protocol, entries_line);
   4479 	buf_output (protocol, "\n", 1);
   4480     }
   4481     else
   4482 	/* Return the error message as the Entries line.  */
   4483 	buf_output0 (protocol,
   4484 		     "CVS server internal error: Register missing\n");
   4485     free (entries_line);
   4486     entries_line = NULL;
   4487 }
   4488 
   4489 
   4490 
   4491 static void
   4492 serve_ci (char *arg)
   4493 {
   4494     do_cvs_command ("commit", commit);
   4495 }
   4496 
   4497 
   4498 
   4499 static void
   4500 checked_in_response (const char *file, const char *update_dir,
   4501                      const char *repository)
   4502 {
   4503     if (supported_response ("Mode"))
   4504     {
   4505 	struct stat sb;
   4506 	char *mode_string;
   4507 
   4508 	if (stat (file, &sb) < 0)
   4509 	{
   4510 	    /* Not clear to me why the file would fail to exist, but it
   4511 	       was happening somewhere in the testsuite.  */
   4512 	    if (!existence_error (errno))
   4513 		error (0, errno, "cannot stat %s", file);
   4514 	}
   4515 	else
   4516 	{
   4517 	    buf_output0 (protocol, "Mode ");
   4518 	    mode_string = mode_to_string (sb.st_mode);
   4519 	    buf_output0 (protocol, mode_string);
   4520 	    buf_output0 (protocol, "\n");
   4521 	    free (mode_string);
   4522 	}
   4523     }
   4524 
   4525     buf_output0 (protocol, "Checked-in ");
   4526     output_dir (update_dir, repository);
   4527     buf_output0 (protocol, file);
   4528     buf_output (protocol, "\n", 1);
   4529     new_entries_line ();
   4530 }
   4531 
   4532 
   4533 
   4534 void
   4535 server_checked_in (const char *file, const char *update_dir,
   4536                    const char *repository)
   4537 {
   4538     if (noexec)
   4539 	return;
   4540     if (scratched_file != NULL && entries_line == NULL)
   4541     {
   4542 	/*
   4543 	 * This happens if we are now doing a "cvs remove" after a previous
   4544 	 * "cvs add" (without a "cvs ci" in between).
   4545 	 */
   4546 	buf_output0 (protocol, "Remove-entry ");
   4547 	output_dir (update_dir, repository);
   4548 	buf_output0 (protocol, file);
   4549 	buf_output (protocol, "\n", 1);
   4550 	free (scratched_file);
   4551 	scratched_file = NULL;
   4552     }
   4553     else
   4554     {
   4555 	checked_in_response (file, update_dir, repository);
   4556     }
   4557     buf_send_counted (protocol);
   4558 }
   4559 
   4560 
   4561 
   4562 void
   4563 server_update_entries (const char *file, const char *update_dir,
   4564                        const char *repository,
   4565                        enum server_updated_arg4 updated)
   4566 {
   4567     if (noexec)
   4568 	return;
   4569     if (updated == SERVER_UPDATED)
   4570 	checked_in_response (file, update_dir, repository);
   4571     else
   4572     {
   4573 	if (!supported_response ("New-entry"))
   4574 	    return;
   4575 	buf_output0 (protocol, "New-entry ");
   4576 	output_dir (update_dir, repository);
   4577 	buf_output0 (protocol, file);
   4578 	buf_output (protocol, "\n", 1);
   4579 	new_entries_line ();
   4580     }
   4581 
   4582     buf_send_counted (protocol);
   4583 }
   4584 
   4585 
   4586 
   4587 static void
   4588 serve_update (char *arg)
   4589 {
   4590     do_cvs_command ("update", update);
   4591 }
   4592 
   4593 
   4594 
   4595 static void
   4596 serve_diff (char *arg)
   4597 {
   4598     do_cvs_command ("diff", diff);
   4599 }
   4600 
   4601 
   4602 
   4603 static void
   4604 serve_log (char *arg)
   4605 {
   4606     do_cvs_command ("log", cvslog);
   4607 }
   4608 
   4609 
   4610 
   4611 static void
   4612 serve_rlog (char *arg)
   4613 {
   4614     do_cvs_command ("rlog", cvslog);
   4615 }
   4616 
   4617 
   4618 
   4619 static void
   4620 serve_ls (char *arg)
   4621 {
   4622   do_cvs_command ("ls", ls);
   4623 }
   4624 
   4625 
   4626 
   4627 static void
   4628 serve_rls (char *arg)
   4629 {
   4630   do_cvs_command ("rls", ls);
   4631 }
   4632 
   4633 /* cvsacl patch */
   4634 static void
   4635 serve_acl (char *arg)
   4636 {
   4637     do_cvs_command ("acl", cvsacl);
   4638 }
   4639 
   4640 /* cvsacl patch */
   4641 static void
   4642 serve_racl (char *arg)
   4643 {
   4644     cvs_cmd_name = "racl";
   4645     do_cvs_command ("racl", cvsacl);
   4646 }
   4647 
   4648 static void
   4649 serve_add (char *arg)
   4650 {
   4651     do_cvs_command ("add", add);
   4652 }
   4653 
   4654 
   4655 
   4656 static void
   4657 serve_remove (char *arg)
   4658 {
   4659     do_cvs_command ("remove", cvsremove);
   4660 }
   4661 
   4662 
   4663 
   4664 static void
   4665 serve_status (char *arg)
   4666 {
   4667     do_cvs_command ("status", cvsstatus);
   4668 }
   4669 
   4670 
   4671 
   4672 static void
   4673 serve_rdiff (char *arg)
   4674 {
   4675     do_cvs_command ("rdiff", patch);
   4676 }
   4677 
   4678 
   4679 
   4680 static void
   4681 serve_tag (char *arg)
   4682 {
   4683     do_cvs_command ("tag", cvstag);
   4684 }
   4685 
   4686 
   4687 
   4688 static void
   4689 serve_rtag (char *arg)
   4690 {
   4691     do_cvs_command ("rtag", cvstag);
   4692 }
   4693 
   4694 
   4695 
   4696 static void
   4697 serve_import (char *arg)
   4698 {
   4699     do_cvs_command ("import", import);
   4700 }
   4701 
   4702 
   4703 
   4704 static void
   4705 serve_admin (char *arg)
   4706 {
   4707     do_cvs_command ("admin", admin);
   4708 }
   4709 
   4710 
   4711 
   4712 static void
   4713 serve_history (char *arg)
   4714 {
   4715     do_cvs_command ("history", history);
   4716 }
   4717 
   4718 
   4719 
   4720 static void
   4721 serve_release (char *arg)
   4722 {
   4723     do_cvs_command ("release", release);
   4724 }
   4725 
   4726 
   4727 
   4728 static void
   4729 serve_watch_on (char *arg)
   4730 {
   4731     do_cvs_command ("watch", watch_on);
   4732 }
   4733 
   4734 
   4735 
   4736 static void
   4737 serve_watch_off (char *arg)
   4738 {
   4739     do_cvs_command ("watch", watch_off);
   4740 }
   4741 
   4742 
   4743 
   4744 static void
   4745 serve_watch_add (char *arg)
   4746 {
   4747     do_cvs_command ("watch", watch_add);
   4748 }
   4749 
   4750 
   4751 
   4752 static void
   4753 serve_watch_remove (char *arg)
   4754 {
   4755     do_cvs_command ("watch", watch_remove);
   4756 }
   4757 
   4758 
   4759 
   4760 static void
   4761 serve_watchers (char *arg)
   4762 {
   4763     do_cvs_command ("watchers", watchers);
   4764 }
   4765 
   4766 
   4767 
   4768 static void
   4769 serve_editors (char *arg)
   4770 {
   4771     do_cvs_command ("editors", editors);
   4772 }
   4773 
   4774 
   4775 
   4776 static void
   4777 serve_edit (char *arg)
   4778 {
   4779     do_cvs_command ("edit", edit);
   4780 }
   4781 
   4782 
   4783 
   4784 # ifdef PROXY_SUPPORT
   4785 /* We need to handle some of this before reprocessing since it is defined to
   4786  * send a response and print errors before a Root request is received.
   4787  */
   4788 # endif /* PROXY_SUPPORT */
   4789 static void
   4790 serve_noop (char *arg)
   4791 {
   4792     /* Errors could be encountered in the first or second passes, so always
   4793      * send them to the client.
   4794      */
   4795     bool pe = print_pending_error();
   4796 
   4797 # ifdef PROXY_SUPPORT
   4798     /* The portions below need not be handled until reprocessing anyhow since
   4799      * there should be no entries or notifications prior to that.  */
   4800     if (!proxy_log)
   4801 # endif /* PROXY_SUPPORT */
   4802     {
   4803 	server_write_entries ();
   4804 	if (!pe)
   4805 	    (void) server_notify ();
   4806     }
   4807 
   4808     if (!pe
   4809 # ifdef PROXY_SUPPORT
   4810         /* "ok" only goes across in the first pass.  */
   4811         && !reprocessing
   4812 # endif /* PROXY_SUPPORT */
   4813        )
   4814 	buf_output0 (buf_to_net, "ok\n");
   4815     buf_flush (buf_to_net, 1);
   4816 }
   4817 
   4818 
   4819 
   4820 static void
   4821 serve_version (char *arg)
   4822 {
   4823     do_cvs_command ("version", version);
   4824 }
   4825 
   4826 
   4827 
   4828 static void
   4829 serve_init (char *arg)
   4830 {
   4831     cvsroot_t *saved_parsed_root;
   4832 
   4833     if (!ISABSOLUTE (arg))
   4834     {
   4835 	if (alloc_pending (80 + strlen (arg)))
   4836 	    sprintf (pending_error_text,
   4837 		     "E init %s must be an absolute pathname", arg);
   4838     }
   4839 # ifdef AUTH_SERVER_SUPPORT
   4840     else if (Pserver_Repos != NULL)
   4841     {
   4842 	if (strcmp (Pserver_Repos, arg) != 0)
   4843 	{
   4844 	    if (alloc_pending (80 + strlen (Pserver_Repos) + strlen (arg)))
   4845 		/* The explicitness is to aid people who are writing clients.
   4846 		   I don't see how this information could help an
   4847 		   attacker.  */
   4848 		sprintf (pending_error_text, "\
   4849 E Protocol error: init says \"%s\" but pserver says \"%s\"",
   4850 			 arg, Pserver_Repos);
   4851 	}
   4852     }
   4853 # endif
   4854 
   4855     if (print_pending_error ())
   4856 	return;
   4857 
   4858     saved_parsed_root = current_parsed_root;
   4859     current_parsed_root = local_cvsroot (arg);
   4860 
   4861     do_cvs_command ("init", init);
   4862 
   4863     /* Do not free CURRENT_PARSED_ROOT since it is still in the cache.  */
   4864     current_parsed_root = saved_parsed_root;
   4865 }
   4866 
   4867 
   4868 
   4869 static void
   4870 serve_annotate (char *arg)
   4871 {
   4872     do_cvs_command ("annotate", annotate);
   4873 }
   4874 
   4875 
   4876 
   4877 static void
   4878 serve_rannotate (char *arg)
   4879 {
   4880     do_cvs_command ("rannotate", annotate);
   4881 }
   4882 
   4883 
   4884 
   4885 static void
   4886 serve_co (char *arg)
   4887 {
   4888     if (print_pending_error ())
   4889 	return;
   4890 
   4891 # ifdef PROXY_SUPPORT
   4892     /* If we are not a secondary server, the write proxy log will already have
   4893      * been processed.
   4894      */
   4895     if (isProxyServer ())
   4896     {
   4897 	if (reprocessing)
   4898 	    reprocessing = false;
   4899 	else if (/* The proxy log may be closed if the client sent a
   4900 		  * `Command-prep' request.
   4901 		  */
   4902 		 proxy_log)
   4903 	{
   4904 	    /* Set up the log for reprocessing.  */
   4905 	    rewind_buf_from_net ();
   4906 	    /* And return to the main loop in server(), where we will now find
   4907 	     * the logged secondary data and reread it.
   4908 	     */
   4909 	    return;
   4910 	}
   4911     }
   4912 # endif /* PROXY_SUPPORT */
   4913 
   4914     /* Compensate for server_export()'s setting of cvs_cmd_name.
   4915      *
   4916      * [It probably doesn't matter if do_cvs_command() gets "export"
   4917      *  or "checkout", but we ought to be accurate where possible.]
   4918      */
   4919     do_cvs_command (!strcmp (cvs_cmd_name, "export") ? "export" : "checkout",
   4920                    checkout);
   4921 }
   4922 
   4923 
   4924 
   4925 static void
   4926 serve_export (char *arg)
   4927 {
   4928     /* Tell checkout() to behave like export not checkout.  */
   4929     cvs_cmd_name = "export";
   4930     serve_co (arg);
   4931 }
   4932 
   4933 
   4934 
   4935 void
   4936 server_copy_file (const char *file, const char *update_dir,
   4937                   const char *repository, const char *newfile)
   4938 {
   4939     /* At least for now, our practice is to have the server enforce
   4940        noexec for the repository and the client enforce it for the
   4941        working directory.  This might want more thought, and/or
   4942        documentation in cvsclient.texi (other responses do it
   4943        differently).  */
   4944 
   4945     if (!supported_response ("Copy-file"))
   4946 	return;
   4947     buf_output0 (protocol, "Copy-file ");
   4948     output_dir (update_dir, repository);
   4949     buf_output0 (protocol, file);
   4950     buf_output0 (protocol, "\n");
   4951     buf_output0 (protocol, newfile);
   4952     buf_output0 (protocol, "\n");
   4953 }
   4954 
   4955 
   4956 
   4957 /* See server.h for description.  */
   4958 void
   4959 server_modtime (struct file_info *finfo, Vers_TS *vers_ts)
   4960 {
   4961     char date[MAXDATELEN];
   4962     char outdate[MAXDATELEN];
   4963 
   4964     assert (vers_ts->vn_rcs != NULL);
   4965 
   4966     if (!supported_response ("Mod-time"))
   4967 	return;
   4968 
   4969     if (RCS_getrevtime (finfo->rcs, vers_ts->vn_rcs, date, 0) == (time_t) -1)
   4970 	/* FIXME? should we be printing some kind of warning?  For one
   4971 	   thing I'm not 100% sure whether this happens in non-error
   4972 	   circumstances.  */
   4973 	return;
   4974     date_to_internet (outdate, date);
   4975     buf_output0 (protocol, "Mod-time ");
   4976     buf_output0 (protocol, outdate);
   4977     buf_output0 (protocol, "\n");
   4978 }
   4979 
   4980 
   4981 
   4982 /* See server.h for description.  */
   4983 void
   4984 server_updated (
   4985     struct file_info *finfo,
   4986     Vers_TS *vers,
   4987     enum server_updated_arg4 updated,
   4988     mode_t mode,
   4989     unsigned char *checksum,
   4990     struct buffer *filebuf)
   4991 {
   4992     if (noexec)
   4993     {
   4994 	/* Hmm, maybe if we did the same thing for entries_file, we
   4995 	   could get rid of the kludges in server_register and
   4996 	   server_scratch which refrain from warning if both
   4997 	   Scratch_Entry and Register get called.  Maybe.  */
   4998 	if (scratched_file)
   4999 	{
   5000 	    free (scratched_file);
   5001 	    scratched_file = NULL;
   5002 	}
   5003 	buf_send_counted (protocol);
   5004 	return;
   5005     }
   5006 
   5007     if (entries_line != NULL && scratched_file == NULL)
   5008     {
   5009 	FILE *f;
   5010 	struct buffer_data *list, *last;
   5011 	unsigned long size;
   5012 	char size_text[80];
   5013 
   5014 	/* The contents of the file will be in one of filebuf,
   5015 	   list/last, or here.  */
   5016 	unsigned char *file;
   5017 	size_t file_allocated;
   5018 	size_t file_used;
   5019 
   5020 	if (filebuf != NULL)
   5021 	{
   5022 	    size = buf_length (filebuf);
   5023 	    if (mode == (mode_t) -1)
   5024 		error (1, 0, "\
   5025 CVS server internal error: no mode in server_updated");
   5026 	}
   5027 	else
   5028 	{
   5029 	    struct stat sb;
   5030 
   5031 	    if (stat (finfo->file, &sb) < 0)
   5032 	    {
   5033 		if (existence_error (errno))
   5034 		{
   5035 		    /* If we have a sticky tag for a branch on which
   5036 		       the file is dead, and cvs update the directory,
   5037 		       it gets a T_CHECKOUT but no file.  So in this
   5038 		       case just forget the whole thing.  */
   5039 		    free (entries_line);
   5040 		    entries_line = NULL;
   5041 		    goto done;
   5042 		}
   5043 		error (1, errno, "reading %s", finfo->fullname);
   5044 	    }
   5045 	    size = sb.st_size;
   5046 	    if (mode == (mode_t) -1)
   5047 	    {
   5048 		/* FIXME: When we check out files the umask of the
   5049 		   server (set in .bashrc if rsh is in use) affects
   5050 		   what mode we send, and it shouldn't.  */
   5051 		mode = sb.st_mode;
   5052 	    }
   5053 	}
   5054 
   5055 	if (checksum != NULL)
   5056 	{
   5057 	    static int checksum_supported = -1;
   5058 
   5059 	    if (checksum_supported == -1)
   5060 	    {
   5061 		checksum_supported = supported_response ("Checksum");
   5062 	    }
   5063 
   5064 	    if (checksum_supported)
   5065 	    {
   5066 		int i;
   5067 		char buf[3];
   5068 
   5069 		buf_output0 (protocol, "Checksum ");
   5070 		for (i = 0; i < 16; i++)
   5071 		{
   5072 		    sprintf (buf, "%02x", (unsigned int) checksum[i]);
   5073 		    buf_output0 (protocol, buf);
   5074 		}
   5075 		buf_append_char (protocol, '\n');
   5076 	    }
   5077 	}
   5078 
   5079 	if (updated == SERVER_UPDATED)
   5080 	{
   5081 	    Node *node;
   5082 	    Entnode *entnode;
   5083 
   5084 	    if (!(supported_response ("Created")
   5085 		  && supported_response ("Update-existing")))
   5086 		buf_output0 (protocol, "Updated ");
   5087 	    else
   5088 	    {
   5089 		assert (vers != NULL);
   5090 		if (vers->ts_user == NULL)
   5091 		    buf_output0 (protocol, "Created ");
   5092 		else
   5093 		    buf_output0 (protocol, "Update-existing ");
   5094 	    }
   5095 
   5096 	    /* Now munge the entries to say that the file is unmodified,
   5097 	       in case we end up processing it again (e.g. modules3-6
   5098 	       in the testsuite).  */
   5099 	    node = findnode_fn (finfo->entries, finfo->file);
   5100 	    entnode = node->data;
   5101 	    free (entnode->timestamp);
   5102 	    entnode->timestamp = xstrdup ("=");
   5103 	}
   5104 	else if (updated == SERVER_MERGED)
   5105 	    buf_output0 (protocol, "Merged ");
   5106 	else if (updated == SERVER_PATCHED)
   5107 	    buf_output0 (protocol, "Patched ");
   5108 	else if (updated == SERVER_RCS_DIFF)
   5109 	    buf_output0 (protocol, "Rcs-diff ");
   5110 	else
   5111 	    abort ();
   5112 	output_dir (finfo->update_dir, finfo->repository);
   5113 	buf_output0 (protocol, finfo->file);
   5114 	buf_output (protocol, "\n", 1);
   5115 
   5116 	new_entries_line ();
   5117 
   5118 	{
   5119 	    char *mode_string;
   5120 
   5121 	    mode_string = mode_to_string (mode);
   5122 	    buf_output0 (protocol, mode_string);
   5123 	    buf_output0 (protocol, "\n");
   5124 	    free (mode_string);
   5125 	}
   5126 
   5127 	list = last = NULL;
   5128 
   5129 	file = NULL;
   5130 	file_allocated = 0;
   5131 	file_used = 0;
   5132 
   5133 	if (size > 0)
   5134 	{
   5135 	    /* Throughout this section we use binary mode to read the
   5136 	       file we are sending.  The client handles any line ending
   5137 	       translation if necessary.  */
   5138 
   5139 	    if (file_gzip_level
   5140 		/*
   5141 		 * For really tiny files, the gzip process startup
   5142 		 * time will outweigh the compression savings.  This
   5143 		 * might be computable somehow; using 100 here is just
   5144 		 * a first approximation.
   5145 		 */
   5146 		&& size > 100)
   5147 	    {
   5148 		/* Basing this routine on read_and_gzip is not a
   5149 		   high-performance approach.  But it seems easier
   5150 		   to code than the alternative (and less
   5151 		   vulnerable to subtle bugs).  Given that this feature
   5152 		   is mainly for compatibility, that is the better
   5153 		   tradeoff.  */
   5154 
   5155 		int fd;
   5156 
   5157 		/* Callers must avoid passing us a buffer if
   5158 		   file_gzip_level is set.  We could handle this case,
   5159 		   but it's not worth it since this case never arises
   5160 		   with a current client and server.  */
   5161 		if (filebuf != NULL)
   5162 		    error (1, 0, "\
   5163 CVS server internal error: unhandled case in server_updated");
   5164 
   5165 		fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0);
   5166 		if (fd < 0)
   5167 		    error (1, errno, "reading %s", finfo->fullname);
   5168 		if (read_and_gzip (fd, finfo->fullname, &file,
   5169 				   &file_allocated, &file_used,
   5170 				   file_gzip_level))
   5171 		    error (1, 0, "aborting due to compression error");
   5172 		size = file_used;
   5173 		if (close (fd) < 0)
   5174 		    error (1, errno, "reading %s", finfo->fullname);
   5175 		/* Prepending length with "z" is flag for using gzip here.  */
   5176 		buf_output0 (protocol, "z");
   5177 	    }
   5178 	    else if (filebuf == NULL)
   5179 	    {
   5180 		long status;
   5181 
   5182 		f = CVS_FOPEN (finfo->file, "rb");
   5183 		if (f == NULL)
   5184 		    error (1, errno, "reading %s", finfo->fullname);
   5185 		status = buf_read_file (f, size, &list, &last);
   5186 		if (status == -2)
   5187 		    (*protocol->memory_error) (protocol);
   5188 		else if (status != 0)
   5189 		    error (1, ferror (f) ? errno : 0, "reading %s",
   5190 			   finfo->fullname);
   5191 		if (fclose (f) == EOF)
   5192 		    error (1, errno, "reading %s", finfo->fullname);
   5193 	    }
   5194 	}
   5195 
   5196 	sprintf (size_text, "%lu\n", size);
   5197 	buf_output0 (protocol, size_text);
   5198 
   5199 	if (file != NULL)
   5200 	{
   5201 	    buf_output (protocol, (char *) file, file_used);
   5202 	    free (file);
   5203 	    file = NULL;
   5204 	}
   5205 	else if (filebuf == NULL)
   5206 	    buf_append_data (protocol, list, last);
   5207 	else
   5208 	    buf_append_buffer (protocol, filebuf);
   5209 	/* Note we only send a newline here if the file ended with one.  */
   5210 
   5211 	/*
   5212 	 * Avoid using up too much disk space for temporary files.
   5213 	 * A file which does not exist indicates that the file is up-to-date,
   5214 	 * which is now the case.  If this is SERVER_MERGED, the file is
   5215 	 * not up-to-date, and we indicate that by leaving the file there.
   5216 	 * I'm thinking of cases like "cvs update foo/foo.c foo".
   5217 	 */
   5218 	if ((updated == SERVER_UPDATED
   5219 	     || updated == SERVER_PATCHED
   5220 	     || updated == SERVER_RCS_DIFF)
   5221 	    && filebuf == NULL
   5222 	    /* But if we are joining, we'll need the file when we call
   5223 	       join_file.  */
   5224 	    && !joining ())
   5225 	{
   5226 	    if (CVS_UNLINK (finfo->file) < 0)
   5227 		error (0, errno, "cannot remove temp file for %s",
   5228 		       finfo->fullname);
   5229 	}
   5230     }
   5231     else if (scratched_file != NULL && entries_line == NULL)
   5232     {
   5233 	if (strcmp (scratched_file, finfo->file) != 0)
   5234 	    error (1, 0,
   5235 		   "CVS server internal error: `%s' vs. `%s' scratched",
   5236 		   scratched_file,
   5237 		   finfo->file);
   5238 	free (scratched_file);
   5239 	scratched_file = NULL;
   5240 
   5241 	if (kill_scratched_file)
   5242 	    buf_output0 (protocol, "Removed ");
   5243 	else
   5244 	    buf_output0 (protocol, "Remove-entry ");
   5245 	output_dir (finfo->update_dir, finfo->repository);
   5246 	buf_output0 (protocol, finfo->file);
   5247 	buf_output (protocol, "\n", 1);
   5248 	/* keep the vers structure up to date in case we do a join
   5249 	 * - if there isn't a file, it can't very well have a version number,
   5250 	 *   can it?
   5251 	 *
   5252 	 * we do it here on the assumption that since we just told the client
   5253 	 * to remove the file/entry, it will, and we want to remember that.
   5254 	 * If it fails, that's the client's problem, not ours
   5255 	 */
   5256 	if (vers && vers->vn_user != NULL)
   5257 	{
   5258 	    free (vers->vn_user);
   5259 	    vers->vn_user = NULL;
   5260 	}
   5261 	if (vers && vers->ts_user != NULL)
   5262 	{
   5263 	    free (vers->ts_user);
   5264 	    vers->ts_user = NULL;
   5265 	}
   5266     }
   5267     else if (scratched_file == NULL && entries_line == NULL)
   5268     {
   5269 	/*
   5270 	 * This can happen with death support if we were processing
   5271 	 * a dead file in a checkout.
   5272 	 */
   5273     }
   5274     else
   5275 	error (1, 0,
   5276 	       "CVS server internal error: Register *and* Scratch_Entry.\n");
   5277     buf_send_counted (protocol);
   5278   done:;
   5279 }
   5280 
   5281 
   5282 
   5283 /* Return whether we should send patches in RCS format.  */
   5284 int
   5285 server_use_rcs_diff (void)
   5286 {
   5287     return supported_response ("Rcs-diff");
   5288 }
   5289 
   5290 
   5291 
   5292 void
   5293 server_set_entstat (const char *update_dir, const char *repository)
   5294 {
   5295     static int set_static_supported = -1;
   5296     if (set_static_supported == -1)
   5297 	set_static_supported = supported_response ("Set-static-directory");
   5298     if (!set_static_supported) return;
   5299 
   5300     buf_output0 (protocol, "Set-static-directory ");
   5301     output_dir (update_dir, repository);
   5302     buf_output0 (protocol, "\n");
   5303     buf_send_counted (protocol);
   5304 }
   5305 
   5306 
   5307 
   5308 void
   5309 server_clear_entstat (const char *update_dir, const char *repository)
   5310 {
   5311     static int clear_static_supported = -1;
   5312     if (clear_static_supported == -1)
   5313 	clear_static_supported = supported_response ("Clear-static-directory");
   5314     if (!clear_static_supported) return;
   5315 
   5316     if (noexec)
   5317 	return;
   5318 
   5319     buf_output0 (protocol, "Clear-static-directory ");
   5320     output_dir (update_dir, repository);
   5321     buf_output0 (protocol, "\n");
   5322     buf_send_counted (protocol);
   5323 }
   5324 
   5325 
   5326 
   5327 void
   5328 server_set_sticky (const char *update_dir, const char *repository,
   5329                    const char *tag, const char *date, int nonbranch)
   5330 {
   5331     static int set_sticky_supported = -1;
   5332 
   5333     assert (update_dir != NULL);
   5334 
   5335     if (set_sticky_supported == -1)
   5336 	set_sticky_supported = supported_response ("Set-sticky");
   5337     if (!set_sticky_supported) return;
   5338 
   5339     if (noexec)
   5340 	return;
   5341 
   5342     if (tag == NULL && date == NULL)
   5343     {
   5344 	buf_output0 (protocol, "Clear-sticky ");
   5345 	output_dir (update_dir, repository);
   5346 	buf_output0 (protocol, "\n");
   5347     }
   5348     else
   5349     {
   5350 	buf_output0 (protocol, "Set-sticky ");
   5351 	output_dir (update_dir, repository);
   5352 	buf_output0 (protocol, "\n");
   5353 	if (tag != NULL)
   5354 	{
   5355 	    if (nonbranch)
   5356 		buf_output0 (protocol, "N");
   5357 	    else
   5358 		buf_output0 (protocol, "T");
   5359 	    buf_output0 (protocol, tag);
   5360 	}
   5361 	else
   5362 	{
   5363 	    buf_output0 (protocol, "D");
   5364 	    buf_output0 (protocol, date);
   5365 	}
   5366 	buf_output0 (protocol, "\n");
   5367     }
   5368     buf_send_counted (protocol);
   5369 }
   5370 
   5371 
   5372 
   5373 void
   5374 server_edit_file (struct file_info *finfo)
   5375 {
   5376     buf_output (protocol, "Edit-file ", 10);
   5377     output_dir (finfo->update_dir, finfo->repository);
   5378     buf_output0 (protocol, finfo->file);
   5379     buf_output (protocol, "\n", 1);
   5380     buf_send_counted (protocol);
   5381 }
   5382 
   5383 
   5384 
   5385 struct template_proc_data
   5386 {
   5387     const char *update_dir;
   5388     const char *repository;
   5389 };
   5390 
   5391 static int
   5392 template_proc (const char *repository, const char *template, void *closure)
   5393 {
   5394     FILE *fp;
   5395     char buf[1024];
   5396     size_t n;
   5397     struct stat sb;
   5398     struct template_proc_data *data = (struct template_proc_data *)closure;
   5399 
   5400     if (!supported_response ("Template"))
   5401 	/* Might want to warn the user that the rcsinfo feature won't work.  */
   5402 	return 0;
   5403     buf_output0 (protocol, "Template ");
   5404     output_dir (data->update_dir, data->repository);
   5405     buf_output0 (protocol, "\n");
   5406 
   5407     fp = CVS_FOPEN (template, "rb");
   5408     if (fp == NULL)
   5409     {
   5410 	error (0, errno, "Couldn't open rcsinfo template file %s", template);
   5411 	return 1;
   5412     }
   5413     if (fstat (fileno (fp), &sb) < 0)
   5414     {
   5415 	error (0, errno, "cannot stat rcsinfo template file %s", template);
   5416 	return 1;
   5417     }
   5418     sprintf (buf, "%ld\n", (long) sb.st_size);
   5419     buf_output0 (protocol, buf);
   5420     while (!feof (fp))
   5421     {
   5422 	n = fread (buf, 1, sizeof buf, fp);
   5423 	buf_output (protocol, buf, n);
   5424 	if (ferror (fp))
   5425 	{
   5426 	    error (0, errno, "cannot read rcsinfo template file %s", template);
   5427 	    (void) fclose (fp);
   5428 	    return 1;
   5429 	}
   5430     }
   5431     buf_send_counted (protocol);
   5432     if (fclose (fp) < 0)
   5433 	error (0, errno, "cannot close rcsinfo template file %s", template);
   5434     return 0;
   5435 }
   5436 
   5437 
   5438 
   5439 void
   5440 server_clear_template (const char *update_dir, const char *repository)
   5441 {
   5442     assert (update_dir != NULL);
   5443 
   5444     if (noexec)
   5445 	return;
   5446 
   5447     if (!supported_response ("Clear-template") &&
   5448 	!supported_response ("Template"))
   5449 	/* Might want to warn the user that the rcsinfo feature won't work.  */
   5450 	return;
   5451 
   5452     if (supported_response ("Clear-template"))
   5453     {
   5454 	buf_output0 (protocol, "Clear-template ");
   5455 	output_dir (update_dir, repository);
   5456 	buf_output0 (protocol, "\n");
   5457 	buf_send_counted (protocol);
   5458     }
   5459     else
   5460     {
   5461 	buf_output0 (protocol, "Template ");
   5462 	output_dir (update_dir, repository);
   5463 	buf_output0 (protocol, "\n");
   5464 	buf_output0 (protocol, "0\n");
   5465 	buf_send_counted (protocol);
   5466     }
   5467 }
   5468 
   5469 
   5470 
   5471 void
   5472 server_template (const char *update_dir, const char *repository)
   5473 {
   5474     struct template_proc_data data;
   5475     data.update_dir = update_dir;
   5476     data.repository = repository;
   5477     (void) Parse_Info (CVSROOTADM_RCSINFO, repository, template_proc,
   5478 		       PIOPT_ALL, &data);
   5479 }
   5480 
   5481 
   5482 
   5483 static void
   5484 serve_gzip_contents (char *arg)
   5485 {
   5486     int level;
   5487     bool forced = false;
   5488 
   5489 # ifdef PROXY_SUPPORT
   5490     assert (!proxy_log);
   5491 # endif /* PROXY_SUPPORT */
   5492 
   5493     level = atoi (arg);
   5494     if (level == 0)
   5495 	level = 6;
   5496 
   5497     if (config && level < config->MinCompressionLevel)
   5498     {
   5499 	level = config->MinCompressionLevel;
   5500 	forced = true;
   5501     }
   5502     if (config && level > config->MaxCompressionLevel)
   5503     {
   5504 	level = config->MaxCompressionLevel;
   5505 	forced = true;
   5506     }
   5507 
   5508     if (forced && !quiet
   5509 	&& alloc_pending_warning (120 + strlen (program_name)))
   5510 	sprintf (pending_warning_text,
   5511 "E %s server: Forcing compression level %d (allowed: %zu <= z <= %zu).",
   5512 		 program_name, level, config->MinCompressionLevel,
   5513 		 config->MaxCompressionLevel);
   5514 
   5515     gzip_level = file_gzip_level = level;
   5516 }
   5517 
   5518 
   5519 
   5520 static void
   5521 serve_gzip_stream (char *arg)
   5522 {
   5523     int level;
   5524     bool forced = false;
   5525 
   5526     level = atoi (arg);
   5527 
   5528     if (config && level < config->MinCompressionLevel)
   5529     {
   5530 	level = config->MinCompressionLevel;
   5531 	forced = true;
   5532     }
   5533     if (config && level > config->MaxCompressionLevel)
   5534     {
   5535 	level = config->MaxCompressionLevel;
   5536 	forced = true;
   5537     }
   5538 
   5539     if (forced && !quiet
   5540 	&& alloc_pending_warning (120 + strlen (program_name)))
   5541 	sprintf (pending_warning_text,
   5542 "E %s server: Forcing compression level %d (allowed: %zu <= z <= %zu).",
   5543 		 program_name, level, config->MinCompressionLevel,
   5544 		 config->MaxCompressionLevel);
   5545 
   5546     gzip_level = level;
   5547 
   5548     /* All further communication with the client will be compressed.
   5549      *
   5550      * The deflate buffers need to be initialized even for compression level
   5551      * 0, or the client will no longer be able to understand us.  At
   5552      * compression level 0, the correct compression headers will be created and
   5553      * sent, but data will thereafter simply be copied to the network buffers.
   5554      */
   5555 
   5556     /* This needs to be processed in both passes so that we may continue to
   5557      * understand client requests on both the socket and from the log.
   5558      */
   5559     buf_from_net = compress_buffer_initialize (buf_from_net, 1,
   5560 					       0 /* Not used. */,
   5561 					       buf_from_net->memory_error);
   5562 
   5563     /* This needs to be skipped in subsequent passes to avoid compressing data
   5564      * to the client twice.
   5565      */
   5566 # ifdef PROXY_SUPPORT
   5567     if (reprocessing) return;
   5568 # endif /* PROXY_SUPPORT */
   5569     buf_to_net = compress_buffer_initialize (buf_to_net, 0, level,
   5570 					     buf_to_net->memory_error);
   5571 }
   5572 
   5573 
   5574 
   5575 /* Tell the client about RCS options set in CVSROOT/cvswrappers. */
   5576 static void
   5577 serve_wrapper_sendme_rcs_options (char *arg)
   5578 {
   5579     /* Actually, this is kind of sdrawkcab-ssa: the client wants
   5580      * verbatim lines from a cvswrappers file, but the server has
   5581      * already parsed the cvswrappers file into the wrap_list struct.
   5582      * Therefore, the server loops over wrap_list, unparsing each
   5583      * entry before sending it.
   5584      */
   5585     char *wrapper_line = NULL;
   5586 
   5587 # ifdef PROXY_SUPPORT
   5588     if (reprocessing) return;
   5589 # endif /* PROXY_SUPPORT */
   5590 
   5591     wrap_setup ();
   5592 
   5593     for (wrap_unparse_rcs_options (&wrapper_line, 1);
   5594 	 wrapper_line;
   5595 	 wrap_unparse_rcs_options (&wrapper_line, 0))
   5596     {
   5597 	buf_output0 (buf_to_net, "Wrapper-rcsOption ");
   5598 	buf_output0 (buf_to_net, wrapper_line);
   5599 	buf_output0 (buf_to_net, "\012");;
   5600 	free (wrapper_line);
   5601     }
   5602 
   5603     buf_output0 (buf_to_net, "ok\012");
   5604 
   5605     /* The client is waiting for us, so we better send the data now.  */
   5606     buf_flush (buf_to_net, 1);
   5607 }
   5608 
   5609 
   5610 
   5611 static void
   5612 serve_ignore (char *arg)
   5613 {
   5614     /*
   5615      * Just ignore this command.  This is used to support the
   5616      * update-patches command, which is not a real command, but a signal
   5617      * to the client that update will accept the -u argument.
   5618      */
   5619 # ifdef PROXY_SUPPORT
   5620     assert (!proxy_log);
   5621 # endif /* PROXY_SUPPORT */
   5622 }
   5623 
   5624 
   5625 
   5626 static int
   5627 expand_proc (int argc, char **argv, char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)
   5628 {
   5629     int i;
   5630     char *dir = argv[0];
   5631 
   5632     /* If mwhere has been specified, the thing we're expanding is a
   5633        module -- just return its name so the client will ask for the
   5634        right thing later.  If it is an alias or a real directory,
   5635        mwhere will not be set, so send out the appropriate
   5636        expansion. */
   5637 
   5638     if (mwhere != NULL)
   5639     {
   5640 	buf_output0 (buf_to_net, "Module-expansion ");
   5641 	if (server_dir != NULL)
   5642 	{
   5643 	    buf_output0 (buf_to_net, server_dir);
   5644 	    buf_output0 (buf_to_net, "/");
   5645 	}
   5646 	buf_output0 (buf_to_net, mwhere);
   5647 	if (mfile != NULL)
   5648 	{
   5649 	    buf_append_char (buf_to_net, '/');
   5650 	    buf_output0 (buf_to_net, mfile);
   5651 	}
   5652 	buf_append_char (buf_to_net, '\n');
   5653     }
   5654     else
   5655     {
   5656 	/* We may not need to do this anymore -- check the definition
   5657 	   of aliases before removing */
   5658 	if (argc == 1)
   5659 	{
   5660 	    buf_output0 (buf_to_net, "Module-expansion ");
   5661 	    if (server_dir != NULL)
   5662 	    {
   5663 		buf_output0 (buf_to_net, server_dir);
   5664 		buf_output0 (buf_to_net, "/");
   5665 	    }
   5666 	    buf_output0 (buf_to_net, dir);
   5667 	    buf_append_char (buf_to_net, '\n');
   5668 	}
   5669 	else
   5670 	{
   5671 	    for (i = 1; i < argc; ++i)
   5672 	    {
   5673 		buf_output0 (buf_to_net, "Module-expansion ");
   5674 		if (server_dir != NULL)
   5675 		{
   5676 		    buf_output0 (buf_to_net, server_dir);
   5677 		    buf_output0 (buf_to_net, "/");
   5678 		}
   5679 		buf_output0 (buf_to_net, dir);
   5680 		buf_append_char (buf_to_net, '/');
   5681 		buf_output0 (buf_to_net, argv[i]);
   5682 		buf_append_char (buf_to_net, '\n');
   5683 	    }
   5684 	}
   5685     }
   5686     return 0;
   5687 }
   5688 
   5689 
   5690 
   5691 static void
   5692 serve_expand_modules (char *arg)
   5693 {
   5694     int i;
   5695     int err = 0;
   5696     DBM *db;
   5697 
   5698 # ifdef PROXY_SUPPORT
   5699     /* This needs to be processed in the first pass since the client expects a
   5700      * response but we may not yet know if we are a secondary.
   5701      *
   5702      * On the second pass, we still must make sure to ignore the arguments.
   5703      */
   5704     if (!reprocessing)
   5705 # endif /* PROXY_SUPPORT */
   5706     {
   5707 	err = 0;
   5708 
   5709 	db = open_module ();
   5710 	for (i = 1; i < argument_count; i++)
   5711 	    err += do_module (db, argument_vector[i],
   5712 			      CHECKOUT, "Updating", expand_proc,
   5713 			      NULL, 0, 0, 0, 0, NULL);
   5714 	close_module (db);
   5715     }
   5716 
   5717     {
   5718 	/* argument_vector[0] is a dummy argument, we don't mess with it.  */
   5719 	char **cp;
   5720 	for (cp = argument_vector + 1;
   5721 	     cp < argument_vector + argument_count;
   5722 	     ++cp)
   5723 	    free (*cp);
   5724 
   5725 	argument_count = 1;
   5726     }
   5727 
   5728 # ifdef PROXY_SUPPORT
   5729     if (!reprocessing)
   5730 # endif /* PROXY_SUPPORT */
   5731     {
   5732 	if (err)
   5733 	    /* We will have printed an error message already.  */
   5734 	    buf_output0 (buf_to_net, "error  \n");
   5735 	else
   5736 	    buf_output0 (buf_to_net, "ok\n");
   5737 
   5738 	/* The client is waiting for the module expansions, so we must
   5739 	   send the output now.  */
   5740 	buf_flush (buf_to_net, 1);
   5741     }
   5742 }
   5743 
   5744 
   5745 
   5746 /* Decide if we should redirect the client to another server.
   5747  *
   5748  * GLOBALS
   5749  *   config->PrimaryServer	The server to redirect write requests to, if
   5750  *				any.
   5751  *
   5752  * ASSUMPTIONS
   5753  *   The `Root' request has already been processed.
   5754  *
   5755  * RETURNS
   5756  *   Nothing.
   5757  */
   5758 static void
   5759 serve_command_prep (char *arg)
   5760 {
   5761     bool redirect_supported;
   5762 # ifdef PROXY_SUPPORT
   5763     bool ditch_log;
   5764 # endif /* PROXY_SUPPORT */
   5765 
   5766     if (print_pending_error ()) return;
   5767 
   5768     redirect_supported = supported_response ("Redirect");
   5769     if (redirect_supported
   5770 	&& lookup_command_attribute (arg) & CVS_CMD_MODIFIES_REPOSITORY
   5771 	/* I call isProxyServer() last because it can probably be the slowest
   5772 	 * call due to the call to gethostbyname().
   5773 	 */
   5774 	&& isProxyServer ())
   5775     {
   5776 	/* Before sending a redirect, send a "Referrer" line to the client,
   5777 	 * if possible, to give admins more control over canonicalizing roots
   5778 	 * sent from the client.
   5779 	 */
   5780 	if (supported_response ("Referrer"))
   5781 	{
   5782 	    /* assume :ext:, since that is all we currently support for
   5783 	     * proxies and redirection.
   5784 	     */
   5785 	    char *referrer = Xasprintf (":ext:%s@%s%s", getcaller(),
   5786 					server_hostname,
   5787 					current_parsed_root->directory);
   5788 
   5789 	    buf_output0 (buf_to_net, "Referrer ");
   5790 	    buf_output0 (buf_to_net, referrer);
   5791 	    buf_output0 (buf_to_net, "\n");
   5792 
   5793 	    free (referrer);
   5794 	}
   5795 
   5796 	/* Send `Redirect' to redirect client requests to the primary.  */
   5797 	buf_output0 (buf_to_net, "Redirect ");
   5798 	buf_output0 (buf_to_net, config->PrimaryServer->original);
   5799 	buf_output0 (buf_to_net, "\n");
   5800 	buf_flush (buf_to_net, 1);
   5801 # ifdef PROXY_SUPPORT
   5802 	ditch_log = true;
   5803 # endif /* PROXY_SUPPORT */
   5804     }
   5805     else
   5806     {
   5807 	/* Send `ok' so the client can proceed.  */
   5808 	buf_output0 (buf_to_net, "ok\n");
   5809 	buf_flush (buf_to_net, 1);
   5810 # ifdef PROXY_SUPPORT
   5811 	if (lookup_command_attribute (arg) & CVS_CMD_MODIFIES_REPOSITORY
   5812             && isProxyServer ())
   5813 	    /* Don't ditch the log for write commands on a proxy server.  We
   5814 	     * we got here because the `Redirect' response was not supported.
   5815 	     */
   5816 	    ditch_log = false;
   5817 	else
   5818 	    ditch_log = true;
   5819 # endif /* PROXY_SUPPORT */
   5820     }
   5821 # ifdef PROXY_SUPPORT
   5822     if (proxy_log && ditch_log)
   5823     {
   5824 	/* If the client supported the redirect response, then they will always
   5825 	 * be redirected if they are preparing for a write request.  It is
   5826 	 * therefore safe to close the proxy logs.
   5827 	 *
   5828 	 * If the client is broken and ignores the redirect, this will be
   5829 	 * detected later, in rewind_buf_from_net().
   5830 	 *
   5831 	 * Since a `Command-prep' response is only acceptable immediately
   5832 	 * following the `Root' request according to the specification, there
   5833 	 * is no need to rewind the log and reprocess.
   5834 	 */
   5835 	log_buffer_closelog (proxy_log);
   5836 	log_buffer_closelog (proxy_log_out);
   5837 	proxy_log = NULL;
   5838     }
   5839 # endif /* PROXY_SUPPORT */
   5840 }
   5841 
   5842 
   5843 
   5844 /* Save a referrer, potentially for passing to hook scripts later.
   5845  *
   5846  * GLOBALS
   5847  *   referrer	Where we save the parsed referrer.
   5848  *
   5849  * ASSUMPTIONS
   5850  *   The `Root' request has already been processed.
   5851  *   There is no need to dispose of REFERRER if it is set.  It's memory is
   5852  *   tracked by parse_root().
   5853  *
   5854  * RETURNS
   5855  *   Nothing.
   5856  */
   5857 static void
   5858 serve_referrer (char *arg)
   5859 {
   5860     if (error_pending ()) return;
   5861 
   5862     referrer = parse_cvsroot (arg);
   5863 
   5864     if (!referrer
   5865 	&& alloc_pending (80 + strlen (arg)))
   5866 	sprintf (pending_error_text,
   5867 		 "E Protocol error: Invalid Referrer: `%s'",
   5868 		 arg);
   5869 }
   5870 
   5871 
   5872 
   5873 static void serve_valid_requests (char *arg);
   5874 
   5875 #endif /* SERVER_SUPPORT */
   5876 /*
   5877  * Comment to move position of the following #if line which works
   5878  * around an apparent bug in Microsoft Visual C++ 6.0 compiler.
   5879  */
   5880 #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
   5881 /*
   5882  * Parts of this table are shared with the client code,
   5883  * but the client doesn't need to know about the handler
   5884  * functions.
   5885  */
   5886 
   5887 struct request requests[] =
   5888 {
   5889 #ifdef SERVER_SUPPORT
   5890 #define REQ_LINE(n, f, s) {n, f, s}
   5891 #else
   5892 #define REQ_LINE(n, f, s) {n, s}
   5893 #endif
   5894 
   5895   REQ_LINE("Root", serve_root, RQ_ESSENTIAL | RQ_ROOTLESS),
   5896   REQ_LINE("Valid-responses", serve_valid_responses,
   5897 	   RQ_ESSENTIAL | RQ_ROOTLESS),
   5898   REQ_LINE("valid-requests", serve_valid_requests,
   5899 	   RQ_ESSENTIAL | RQ_ROOTLESS),
   5900   REQ_LINE("Command-prep", serve_command_prep, 0),
   5901   REQ_LINE("Referrer", serve_referrer, 0),
   5902   REQ_LINE("Repository", serve_repository, 0),
   5903   REQ_LINE("Directory", serve_directory, RQ_ESSENTIAL),
   5904   REQ_LINE("Relative-directory", serve_directory, 0),
   5905   REQ_LINE("Max-dotdot", serve_max_dotdot, 0),
   5906   REQ_LINE("Static-directory", serve_static_directory, 0),
   5907   REQ_LINE("Sticky", serve_sticky, 0),
   5908   REQ_LINE("Checkin-prog", serve_noop, 0),
   5909   REQ_LINE("Update-prog", serve_noop, 0),
   5910   REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL),
   5911   REQ_LINE("Kopt", serve_kopt, 0),
   5912   REQ_LINE("Checkin-time", serve_checkin_time, 0),
   5913   REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL),
   5914   REQ_LINE("Is-modified", serve_is_modified, 0),
   5915 
   5916   /* The client must send this request to interoperate with CVS 1.5
   5917      through 1.9 servers.  The server must support it (although it can
   5918      be and is a noop) to interoperate with CVS 1.5 to 1.9 clients.  */
   5919   REQ_LINE("UseUnchanged", serve_enable_unchanged, RQ_ENABLEME | RQ_ROOTLESS),
   5920 
   5921   REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL),
   5922   REQ_LINE("Notify", serve_notify, 0),
   5923   REQ_LINE("Hostname", serve_hostname, 0),
   5924   REQ_LINE("LocalDir", serve_localdir, 0),
   5925   REQ_LINE("Questionable", serve_questionable, 0),
   5926   REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL),
   5927   REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL),
   5928   REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS),
   5929   /* This is rootless, even though the client/server spec does not specify
   5930    * such, to allow error messages to be understood by the client when they are
   5931    * sent.
   5932    */
   5933   REQ_LINE("Gzip-stream", serve_gzip_stream, RQ_ROOTLESS),
   5934   REQ_LINE("wrapper-sendme-rcsOptions",
   5935 	   serve_wrapper_sendme_rcs_options,
   5936 	   0),
   5937   REQ_LINE("Set", serve_set, RQ_ROOTLESS),
   5938 #ifdef ENCRYPTION
   5939   /* These are rootless despite what the client/server spec says for the same
   5940    * reasons as Gzip-stream.
   5941    */
   5942 #  ifdef HAVE_KERBEROS
   5943   REQ_LINE("Kerberos-encrypt", serve_kerberos_encrypt, RQ_ROOTLESS),
   5944 #  endif
   5945 #  ifdef HAVE_GSSAPI
   5946   REQ_LINE("Gssapi-encrypt", serve_gssapi_encrypt, RQ_ROOTLESS),
   5947 #  endif
   5948 #endif
   5949 #ifdef HAVE_GSSAPI
   5950   REQ_LINE("Gssapi-authenticate", serve_gssapi_authenticate, RQ_ROOTLESS),
   5951 #endif
   5952   REQ_LINE("expand-modules", serve_expand_modules, 0),
   5953   REQ_LINE("ci", serve_ci, RQ_ESSENTIAL),
   5954   REQ_LINE("co", serve_co, RQ_ESSENTIAL),
   5955   REQ_LINE("update", serve_update, RQ_ESSENTIAL),
   5956   REQ_LINE("diff", serve_diff, 0),
   5957   REQ_LINE("log", serve_log, 0),
   5958   REQ_LINE("rlog", serve_rlog, 0),
   5959 
   5960   /* cvsacl patch */
   5961   REQ_LINE("acl", serve_acl, 0),
   5962   REQ_LINE("racl", serve_racl, 0),
   5963 
   5964   REQ_LINE("list", serve_ls, 0),
   5965   REQ_LINE("rlist", serve_rls, 0),
   5966   /* This allows us to avoid sending `-q' as a command argument to `cvs ls',
   5967    * or more accurately, allows us to send `-q' to backwards CVSNT servers.
   5968    */
   5969   REQ_LINE("global-list-quiet", serve_noop, RQ_ROOTLESS),
   5970   /* Deprecated synonym for rlist, for compatibility with CVSNT. */
   5971   REQ_LINE("ls", serve_rls, 0),
   5972   REQ_LINE("add", serve_add, 0),
   5973   REQ_LINE("remove", serve_remove, 0),
   5974   REQ_LINE("update-patches", serve_ignore, 0),
   5975   REQ_LINE("gzip-file-contents", serve_gzip_contents, RQ_ROOTLESS),
   5976   REQ_LINE("status", serve_status, 0),
   5977   REQ_LINE("rdiff", serve_rdiff, 0),
   5978   REQ_LINE("tag", serve_tag, 0),
   5979   REQ_LINE("rtag", serve_rtag, 0),
   5980   REQ_LINE("import", serve_import, 0),
   5981   REQ_LINE("admin", serve_admin, 0),
   5982   REQ_LINE("export", serve_export, 0),
   5983   REQ_LINE("history", serve_history, 0),
   5984   REQ_LINE("release", serve_release, 0),
   5985   REQ_LINE("watch-on", serve_watch_on, 0),
   5986   REQ_LINE("watch-off", serve_watch_off, 0),
   5987   REQ_LINE("watch-add", serve_watch_add, 0),
   5988   REQ_LINE("watch-remove", serve_watch_remove, 0),
   5989   REQ_LINE("watchers", serve_watchers, 0),
   5990   REQ_LINE("editors", serve_editors, 0),
   5991   REQ_LINE("edit", serve_edit, 0),
   5992   REQ_LINE("init", serve_init, RQ_ROOTLESS),
   5993   REQ_LINE("annotate", serve_annotate, 0),
   5994   REQ_LINE("rannotate", serve_rannotate, 0),
   5995   REQ_LINE("noop", serve_noop, RQ_ROOTLESS),
   5996   REQ_LINE("version", serve_version, RQ_ROOTLESS),
   5997   REQ_LINE(NULL, NULL, 0)
   5998 
   5999 #undef REQ_LINE
   6000 };
   6001 #endif /* SERVER_SUPPORT or CLIENT_SUPPORT */
   6002 
   6003 
   6004 
   6005 #ifdef SERVER_SUPPORT
   6006 /*
   6007  * This server request is not ignored by the secondary.
   6008  */
   6009 static void
   6010 serve_valid_requests (char *arg)
   6011 {
   6012     struct request *rq;
   6013 
   6014     /* Since this is processed in the first pass, don't reprocess it in the
   6015      * second.
   6016      *
   6017      * We still print errors since new errors could have been generated in the
   6018      * second pass.
   6019      */
   6020     if (print_pending_error ()
   6021 #ifdef PROXY_SUPPORT
   6022 	|| reprocessing
   6023 #endif /* PROXY_SUPPORT */
   6024        )
   6025 	return;
   6026 
   6027     buf_output0 (buf_to_net, "Valid-requests");
   6028     for (rq = requests; rq->name != NULL; rq++)
   6029     {
   6030 	if (rq->func != NULL)
   6031 	{
   6032 	    buf_append_char (buf_to_net, ' ');
   6033 	    buf_output0 (buf_to_net, rq->name);
   6034 	}
   6035     }
   6036 
   6037     if (config && config->MinCompressionLevel
   6038 	&& supported_response ("Force-gzip"))
   6039     {
   6040 	    buf_output0 (buf_to_net, "\n");
   6041 	    buf_output0 (buf_to_net, "Force-gzip");
   6042     }
   6043 
   6044     buf_output0 (buf_to_net, "\nok\n");
   6045 
   6046     /* The client is waiting for the list of valid requests, so we
   6047        must send the output now.  */
   6048     buf_flush (buf_to_net, 1);
   6049 }
   6050 
   6051 
   6052 
   6053 #ifdef SUNOS_KLUDGE
   6054 /*
   6055  * Delete temporary files.  SIG is the signal making this happen, or
   6056  * 0 if not called as a result of a signal.
   6057  */
   6058 static int command_pid_is_dead;
   6059 static void wait_sig (int sig)
   6060 {
   6061     int status;
   6062     pid_t r = wait (&status);
   6063     if (r == command_pid)
   6064 	command_pid_is_dead++;
   6065 }
   6066 #endif /* SUNOS_KLUDGE */
   6067 
   6068 
   6069 
   6070 /*
   6071  * This function cleans up after the server.  Specifically, it:
   6072  *
   6073  * <ol>
   6074  * <li>Sets BUF_TO_NET to blocking and fluxhes it.</li>
   6075  * <li>With SUNOS_KLUDGE enabled:
   6076  *   <ol>
   6077  *   <li>Terminates the command process.</li>
   6078  *   <li>Waits on the command process, draining output as necessary.</li>
   6079  *   </ol>
   6080  * </li>
   6081  * <li>Removes the temporary directory.</li>
   6082  * <li>Flush and shutdown the buffers.</li>
   6083  * <li>Set ERROR_USE_PROTOCOL and SERVER_ACTIVE to false.</li>
   6084  * </ol>
   6085  *
   6086  * NOTES
   6087  *   This function needs to be reentrant since a call to exit() can cause a
   6088  *   call to this function, which can then be interrupted by a signal, which
   6089  *   can cause a second call to this function.
   6090  *
   6091  * GLOBALS
   6092  *   buf_from_net		The input buffer which brings data from the
   6093  *   				CVS client.
   6094  *   buf_to_net			The output buffer which moves data to the CVS
   6095  *   				client.
   6096  *   error_use_protocol		Set when the server parent process is active.
   6097  *   				Cleared for the server child processes.
   6098  *   dont_delete_temp		Set when a core dump of a child process is
   6099  *   				detected so that the core and related data may
   6100  *   				be preserved.
   6101  *   noexec			Whether we are supposed to change the disk.
   6102  *   orig_server_temp_dir	The temporary directory we created within
   6103  *   				Tmpdir for our duplicate of the client
   6104  *   				workspace.
   6105  *
   6106  * INPUTS
   6107  *   None.
   6108  *
   6109  * ERRORS
   6110  *   Problems encountered during the cleanup, for instance low memory or
   6111  *   problems deleting the temp files and directories, can cause the error
   6112  *   function to be called, which might call exit.  If exit gets called in this
   6113  *   manner. this routine will not complete, but the other exit handlers
   6114  *   registered via atexit() will still run.
   6115  *
   6116  * RETURNS
   6117  *   Nothing.
   6118  */
   6119 void
   6120 server_cleanup (void)
   6121 {
   6122     TRACE (TRACE_FUNCTION, "server_cleanup()");
   6123 
   6124     assert (server_active);
   6125 
   6126     /* FIXME: Do not perform buffered I/O from an interrupt handler like
   6127      * this (via error).  However, I'm leaving the error-calling code there
   6128      * in the hope that on the rare occasion the error call is actually made
   6129      * (e.g., a fluky I/O error or permissions problem prevents the deletion
   6130      * of a just-created file) reentrancy won't be an issue.
   6131      */
   6132 
   6133     /* We don't want to be interrupted during calls which set globals to NULL,
   6134      * but we know that by the time we reach this function, interrupts have
   6135      * already been blocked.
   6136      */
   6137 
   6138     /* Since we install this function in an atexit() handler before forking,
   6139      * reuse the ERROR_USE_PROTOCOL flag, which we know is only set in the
   6140      * parent server process, to avoid cleaning up the temp space multiple
   6141      * times.  Skip the buf_to_net checks too as an optimization since we know
   6142      * they will be set to NULL in the child process anyhow.
   6143      */
   6144     if (error_use_protocol)
   6145     {
   6146 	if (buf_to_net != NULL)
   6147 	{
   6148 	    int status;
   6149 
   6150 	    /* Since we're done, go ahead and put BUF_TO_NET back into blocking
   6151 	     * mode and send any pending output.  In the usual case there won't
   6152 	     * won't be any, but there might be if an error occured.
   6153 	     */
   6154 
   6155 	    set_block (buf_to_net);
   6156 	    buf_flush (buf_to_net, 1);
   6157 
   6158 	    /* Next we shut down BUF_FROM_NET.  That will pick up the checksum
   6159 	     * generated when the client shuts down its buffer.  Then, after we
   6160 	     * have generated any final output, we shut down BUF_TO_NET.
   6161 	     */
   6162 
   6163 	    /* SIG_beginCrSect(); */
   6164 	    if (buf_from_net)
   6165 	    {
   6166 		status = buf_shutdown (buf_from_net);
   6167 		if (status != 0)
   6168 		    error (0, status, "shutting down buffer from client");
   6169 		buf_free (buf_from_net);
   6170 		buf_from_net = NULL;
   6171 	    }
   6172 	    /* SIG_endCrSect(); */
   6173 	}
   6174 
   6175 	if (!dont_delete_temp)
   6176 	{
   6177 	    int save_noexec;
   6178 
   6179 	    /* What a bogus kludge.  This disgusting code makes all kinds of
   6180 	       assumptions about SunOS, and is only for a bug in that system.
   6181 	       So only enable it on Suns.  */
   6182 #ifdef SUNOS_KLUDGE
   6183 	    if (command_pid > 0)
   6184 	    {
   6185 		/* To avoid crashes on SunOS due to bugs in SunOS tmpfs
   6186 		 * triggered by the use of rename() in RCS, wait for the
   6187 		 * subprocess to die.  Unfortunately, this means draining
   6188 		 * output while waiting for it to unblock the signal we sent
   6189 		 * it.  Yuck!
   6190 		 */
   6191 		int status;
   6192 		pid_t r;
   6193 
   6194 		signal (SIGCHLD, wait_sig);
   6195 		/* Perhaps SIGTERM would be more correct.  But the child
   6196 		   process will delay the SIGINT delivery until its own
   6197 		   children have exited.  */
   6198 		kill (command_pid, SIGINT);
   6199 		/* The caller may also have sent a signal to command_pid, so
   6200 		 * always try waiting.  First, though, check and see if it's
   6201 		 * still there....
   6202 		 */
   6203 	    do_waitpid:
   6204 		r = waitpid (command_pid, &status, WNOHANG);
   6205 		if (r == 0)
   6206 		    ;
   6207 		else if (r == command_pid)
   6208 		    command_pid_is_dead++;
   6209 		else if (r == -1)
   6210 		    switch (errno)
   6211 		    {
   6212 			case ECHILD:
   6213 			    command_pid_is_dead++;
   6214 			    break;
   6215 			case EINTR:
   6216 			    goto do_waitpid;
   6217 		    }
   6218 		else
   6219 		    /* waitpid should always return one of the above values */
   6220 		    abort ();
   6221 		while (!command_pid_is_dead)
   6222 		{
   6223 		    struct timeval timeout;
   6224 		    struct fd_set_wrapper readfds;
   6225 		    char buf[100];
   6226 		    int i;
   6227 
   6228 		    /* Use a non-zero timeout to avoid eating up CPU cycles.  */
   6229 		    timeout.tv_sec = 2;
   6230 		    timeout.tv_usec = 0;
   6231 		    readfds = command_fds_to_drain;
   6232 		    switch (select (max_command_fd + 1, &readfds.fds,
   6233 				    NULL, NULL &timeout))
   6234 		    {
   6235 			case -1:
   6236 			    if (errno != EINTR)
   6237 				abort ();
   6238 			case 0:
   6239 			    /* timeout */
   6240 			    break;
   6241 			case 1:
   6242 			    for (i = 0; i <= max_command_fd; i++)
   6243 			    {
   6244 				if (!FD_ISSET (i, &readfds.fds))
   6245 				    continue;
   6246 				/* this fd is non-blocking */
   6247 				while (read (i, buf, sizeof (buf)) >= 1)
   6248 				    ;
   6249 			    }
   6250 			    break;
   6251 			default:
   6252 			    abort ();
   6253 		    }
   6254 		}
   6255 	    }
   6256 #endif /* SUNOS_KLUDGE */
   6257 
   6258 	    /* Make sure our working directory isn't inside the tree we're
   6259 	       going to delete.  */
   6260 	    if (CVS_CHDIR (get_cvs_tmp_dir ()) == -1)
   6261 		error (0, errno, "Cannot chdir to `%s'", get_cvs_tmp_dir ());
   6262 
   6263 	    /* Temporarily clear noexec, so that we clean up our temp directory
   6264 	       regardless of it (this could more cleanly be handled by moving
   6265 	       the noexec check to all the unlink_file_dir callers from
   6266 	       unlink_file_dir itself).  */
   6267 	    save_noexec = noexec;
   6268 
   6269 	    /* SIG_beginCrSect(); */
   6270 	    noexec = 0;
   6271 	    unlink_file_dir (orig_server_temp_dir);
   6272 	    noexec = save_noexec;
   6273 	    /* SIG_endCrSect(); */
   6274 	} /* !dont_delete_temp */
   6275 
   6276 	/* SIG_beginCrSect(); */
   6277 	if (buf_to_net != NULL)
   6278 	{
   6279 	    /* Save BUF_TO_NET and set the global pointer to NULL so that any
   6280 	     * error messages generated during shutdown go to the syslog rather
   6281 	     * than getting lost.
   6282 	     */
   6283 	    struct buffer *buf_to_net_save = buf_to_net;
   6284 	    buf_to_net = NULL;
   6285 
   6286 	    (void) buf_flush (buf_to_net_save, 1);
   6287 	    (void) buf_shutdown (buf_to_net_save);
   6288 	    buf_free (buf_to_net_save);
   6289 	    error_use_protocol = 0;
   6290 	}
   6291 	/* SIG_endCrSect(); */
   6292     }
   6293 
   6294     server_active = 0;
   6295 }
   6296 
   6297 
   6298 
   6299 #ifdef PROXY_SUPPORT
   6300 size_t MaxProxyBufferSize = (size_t)(8 * 1024 * 1024); /* 8 megabytes,
   6301                                                         * by default.
   6302                                                         */
   6303 #endif /* PROXY_SUPPORT */
   6304 
   6305 static const char *const server_usage[] =
   6306 {
   6307     "Usage: %s %s [-c config-file]\n",
   6308     "\t-c config-file\tPath to an alternative CVS config file.\n",
   6309     "Normally invoked by a cvs client on a remote machine.\n",
   6310     NULL
   6311 };
   6312 
   6313 
   6314 
   6315 void
   6316 parseServerOptions (int argc, char **argv)
   6317 {
   6318     int c;
   6319 
   6320     getoptreset ();
   6321     while ((c = getopt (argc, argv, "+c:")) != -1)
   6322     {
   6323 	switch (c)
   6324 	{
   6325 #ifdef ALLOW_CONFIG_OVERRIDE
   6326 	    case 'c':
   6327 		if (gConfigPath) free (gConfigPath);
   6328 		gConfigPath = xstrdup (optarg);
   6329 		break;
   6330 #endif
   6331 	    case '?':
   6332 	    default:
   6333 		usage (server_usage);
   6334 		break;
   6335 	}
   6336     }
   6337 }
   6338 
   6339 
   6340 
   6341 int
   6342 server (int argc, char **argv)
   6343 {
   6344     char *error_prog_name;		/* Used in error messages */
   6345 
   6346     if (argc == -1)
   6347 	usage (server_usage);
   6348 
   6349     /* Options were pre-parsed in main.c.  */
   6350 
   6351     /*
   6352      * Set this in .bashrc if you want to give yourself time to attach
   6353      * to the subprocess with a debugger.
   6354      */
   6355     if (getenv ("CVS_PARENT_SERVER_SLEEP"))
   6356     {
   6357 	int secs = atoi (getenv ("CVS_PARENT_SERVER_SLEEP"));
   6358 	TRACE (TRACE_DATA, "Sleeping CVS_PARENT_SERVER_SLEEP (%d) seconds",
   6359 	       secs);
   6360 	sleep (secs);
   6361     }
   6362     else
   6363 	TRACE (TRACE_DATA, "CVS_PARENT_SERVER_SLEEP not set.");
   6364 
   6365     /* pserver_authenticate_connection () (called from main ()) can initialize
   6366      * these.
   6367      */
   6368     if (!buf_to_net)
   6369     {
   6370 	buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, NULL, false,
   6371 					   outbuf_memory_error);
   6372 	buf_from_net = fd_buffer_initialize (STDIN_FILENO, 0, NULL, true,
   6373 					     outbuf_memory_error);
   6374     }
   6375 
   6376     setup_logfiles ("CVS_SERVER_LOG", &buf_to_net, &buf_from_net);
   6377 
   6378 #ifdef PROXY_SUPPORT
   6379     /* We have to set up the recording for all servers.  Until we receive the
   6380      * `Root' request and load CVSROOT/config, we can't tell if we are a
   6381      * secondary or primary.
   6382      */
   6383     {
   6384 	/* Open the secondary log.  */
   6385 	buf_from_net = log_buffer_initialize (buf_from_net, NULL,
   6386 # ifdef PROXY_SUPPORT
   6387 					      true,
   6388 					      config
   6389 						? config->MaxProxyBufferSize
   6390 						: MaxProxyBufferSize,
   6391 # endif /* PROXY_SUPPORT */
   6392 					      true, outbuf_memory_error);
   6393 	proxy_log = buf_from_net;
   6394 
   6395 	/* And again for the out log.  */
   6396 	buf_to_net = log_buffer_initialize (buf_to_net, NULL,
   6397 # ifdef PROXY_SUPPORT
   6398 					    true,
   6399 					    config
   6400 					      ? config->MaxProxyBufferSize
   6401 					      : MaxProxyBufferSize,
   6402 # endif /* PROXY_SUPPORT */
   6403 					    false, outbuf_memory_error);
   6404 	proxy_log_out = buf_to_net;
   6405     }
   6406 #endif /* PROXY_SUPPORT */
   6407 
   6408     saved_output = buf_nonio_initialize (outbuf_memory_error);
   6409     saved_outerr = buf_nonio_initialize (outbuf_memory_error);
   6410 
   6411     /* Since we're in the server parent process, error should use the
   6412        protocol to report error messages.  */
   6413     error_use_protocol = 1;
   6414 
   6415     /* Now initialize our argument vector (for arguments from the client).  */
   6416 
   6417     /* Small for testing.  */
   6418     argument_vector_size = 1;
   6419     argument_vector = xmalloc (argument_vector_size * sizeof (char *));
   6420     argument_count = 1;
   6421     /* This gets printed if the client supports an option which the
   6422        server doesn't, causing the server to print a usage message.
   6423        FIXME: just a nit, I suppose, but the usage message the server
   6424        prints isn't literally true--it suggests "cvs server" followed
   6425        by options which are for a particular command.  Might be nice to
   6426        say something like "client apparently supports an option not supported
   6427        by this server" or something like that instead of usage message.  */
   6428     error_prog_name = xmalloc (strlen (program_name) + 8);
   6429     sprintf(error_prog_name, "%s server", program_name);
   6430     argument_vector[0] = error_prog_name;
   6431 
   6432     while (1)
   6433     {
   6434 	char *cmd, *orig_cmd;
   6435 	struct request *rq;
   6436 	int status;
   6437 
   6438 	status = buf_read_line (buf_from_net, &cmd, NULL);
   6439 	if (status == -2)
   6440 	{
   6441 	    buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\
   6442 error ENOMEM Virtual memory exhausted.\n");
   6443 	    break;
   6444 	}
   6445 	if (status != 0)
   6446 	    break;
   6447 
   6448 	orig_cmd = cmd;
   6449 	for (rq = requests; rq->name != NULL; ++rq)
   6450 	    if (strncmp (cmd, rq->name, strlen (rq->name)) == 0)
   6451 	    {
   6452 		int len = strlen (rq->name);
   6453 		if (cmd[len] == '\0')
   6454 		    cmd += len;
   6455 		else if (cmd[len] == ' ')
   6456 		    cmd += len + 1;
   6457 		else
   6458 		    /*
   6459 		     * The first len characters match, but it's a different
   6460 		     * command.  e.g. the command is "cooperate" but we matched
   6461 		     * "co".
   6462 		     */
   6463 		    continue;
   6464 
   6465 		if (!(rq->flags & RQ_ROOTLESS)
   6466 		    && current_parsed_root == NULL)
   6467 		{
   6468 		    if (alloc_pending (80))
   6469 			sprintf (pending_error_text,
   6470 				 "E Protocol error: Root request missing");
   6471 		}
   6472 		else
   6473 		{
   6474 		    if (config && config->MinCompressionLevel && !gzip_level
   6475 			&& !(rq->flags & RQ_ROOTLESS))
   6476 		    {
   6477 			/* This is a rootless request, a minimum compression
   6478 			 * level has been configured, and no compression has
   6479 			 * been requested by the client.
   6480 			 */
   6481 			if (alloc_pending (80 + strlen (program_name)))
   6482 			    sprintf (pending_error_text,
   6483 "E %s [server aborted]: Compression must be used with this server.",
   6484 				     program_name);
   6485 		    }
   6486 		    (*rq->func) (cmd);
   6487 		}
   6488 		break;
   6489 	    }
   6490 	if (rq->name == NULL)
   6491 	{
   6492 	    if (!print_pending_error ())
   6493 	    {
   6494 		buf_output0 (buf_to_net, "error  unrecognized request `");
   6495 		buf_output0 (buf_to_net, cmd);
   6496 		buf_append_char (buf_to_net, '\'');
   6497 		buf_append_char (buf_to_net, '\n');
   6498 	    }
   6499 	}
   6500 	free (orig_cmd);
   6501     }
   6502 
   6503     free (error_prog_name);
   6504 
   6505     /* We expect the client is done talking to us at this point.  If there is
   6506      * any data in the buffer or on the network pipe, then something we didn't
   6507      * prepare for is happening.
   6508      */
   6509     if (!buf_empty (buf_from_net))
   6510     {
   6511 	/* Try to send the error message to the client, but also syslog it, in
   6512 	 * case the client isn't listening anymore.
   6513 	 */
   6514 #ifdef HAVE_SYSLOG_H
   6515 	/* FIXME: Can the IP address of the connecting client be retrieved
   6516 	 * and printed here?
   6517 	 */
   6518 	syslog (LOG_DAEMON | LOG_ERR, "Dying gasps received from client.");
   6519 #endif /* HAVE_SYSLOG_H */
   6520 	error (0, 0, "Dying gasps received from client.");
   6521     }
   6522 
   6523 #ifdef HAVE_PAM
   6524     if (pamh)
   6525     {
   6526         int retval;
   6527 
   6528         retval = pam_close_session (pamh, 0);
   6529 # ifdef HAVE_SYSLOG_H
   6530         if (retval != PAM_SUCCESS)
   6531             syslog (LOG_DAEMON | LOG_ERR,
   6532                     "PAM close session error: %s",
   6533                     pam_strerror (pamh, retval));
   6534 # endif /* HAVE_SYSLOG_H */
   6535 
   6536         retval = pam_end (pamh, retval);
   6537 # ifdef HAVE_SYSLOG_H
   6538         if (retval != PAM_SUCCESS)
   6539             syslog (LOG_DAEMON | LOG_ERR,
   6540                     "PAM failed to release authenticator, error: %s",
   6541                     pam_strerror (pamh, retval));
   6542 # endif /* HAVE_SYSLOG_H */
   6543     }
   6544 #endif /* HAVE_PAM */
   6545 
   6546     /* server_cleanup() will be called on a normal exit and close the buffers
   6547      * explicitly.
   6548      */
   6549     return 0;
   6550 }
   6551 
   6552 
   6553 
   6554 #if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
   6555 static void
   6556 switch_to_user (const char *cvs_username, const char *username)
   6557 {
   6558     struct passwd *pw;
   6559     int rc;
   6560 #ifdef HAVE_PAM
   6561     int retval;
   6562     char *pam_stage = "open session";
   6563 
   6564     if (pamh)
   6565     {
   6566         retval = pam_open_session (pamh, 0);
   6567         if (retval == PAM_SUCCESS)
   6568         {
   6569             pam_stage = "get pam user";
   6570             retval = pam_get_item (pamh, PAM_USER, (const void **)&username);
   6571         }
   6572 
   6573         if (retval != PAM_SUCCESS)
   6574         {
   6575             printf("E PAM %s error: %s\n", pam_stage,
   6576                     pam_strerror (pamh, retval));
   6577             exit (EXIT_FAILURE);
   6578         }
   6579     }
   6580 #endif
   6581 
   6582     /* cvsacl patch */
   6583     if (use_cvs_acl && cvs_server_run_as)
   6584 	username = cvs_server_run_as;
   6585 
   6586     pw = getpwnam (username);
   6587     if (pw == NULL)
   6588     {
   6589 	/* check_password contains a similar check, so this usually won't be
   6590 	   reached unless the CVS user is mapped to an invalid system user.  */
   6591 
   6592 	printf ("E Fatal error, aborting.\n\
   6593 error 0 %s: no such system user\n", username);
   6594 	exit (EXIT_FAILURE);
   6595     }
   6596 
   6597     if (pw->pw_uid == 0)
   6598     {
   6599 #ifdef HAVE_SYSLOG_H
   6600 	    /* FIXME: Can the IP address of the connecting client be retrieved
   6601 	     * and printed here?
   6602 	     */
   6603 	    syslog (LOG_DAEMON | LOG_ALERT,
   6604 		    "attempt to root from account: %s", cvs_username
   6605 		   );
   6606 #endif /* HAVE_SYSLOG_H */
   6607         printf("error 0: root not allowed\n");
   6608 	exit (EXIT_FAILURE);
   6609     }
   6610 
   6611 #if HAVE_INITGROUPS
   6612     if (initgroups (pw->pw_name, pw->pw_gid) < 0
   6613 #  ifdef EPERM
   6614 	/* At least on the system I tried, initgroups() only works as root.
   6615 	   But we do still want to report ENOMEM and whatever other
   6616 	   errors initgroups() might dish up.  */
   6617 	&& errno != EPERM
   6618 #  endif
   6619 	)
   6620     {
   6621 	/* This could be a warning, but I'm not sure I see the point
   6622 	   in doing that instead of an error given that it would happen
   6623 	   on every connection.  We could log it somewhere and not tell
   6624 	   the user.  But at least for now make it an error.  */
   6625 	printf ("error 0 initgroups failed: %s\n", strerror (errno));
   6626 	exit (EXIT_FAILURE);
   6627     }
   6628 #endif /* HAVE_INITGROUPS */
   6629 
   6630 #ifdef HAVE_PAM
   6631     if (pamh)
   6632     {
   6633         retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
   6634         if (retval != PAM_SUCCESS)
   6635         {
   6636             printf("E PAM reestablish credentials error: %s\n",
   6637                     pam_strerror (pamh, retval));
   6638             exit (EXIT_FAILURE);
   6639         }
   6640     }
   6641 #endif
   6642 
   6643 #ifdef SETXID_SUPPORT
   6644     /* honor the setgid bit iff set*/
   6645     if (getgid() != getegid())
   6646     {
   6647 	if (setgid (getegid ()) < 0)
   6648 	{
   6649 	    /* See comments at setuid call below for more discussion.  */
   6650 	    printf ("error 0 setgid failed: %s\n", strerror (errno));
   6651 	    exit (EXIT_FAILURE);
   6652 	}
   6653     }
   6654     else
   6655 #endif
   6656     {
   6657 	if (setgid (pw->pw_gid) < 0)
   6658 	{
   6659 	    /* See comments at setuid call below for more discussion.  */
   6660 	    printf ("error 0 setgid failed: %s\n", strerror (errno));
   6661 #ifdef HAVE_SYSLOG_H
   6662 	    syslog (LOG_DAEMON | LOG_ERR,
   6663 		    "setgid to %d failed (%m): real %d/%d, effective %d/%d ",
   6664 		    pw->pw_gid, getuid(), getgid(), geteuid(), getegid());
   6665 #endif /* HAVE_SYSLOG_H */
   6666 	    exit (EXIT_FAILURE);
   6667 	}
   6668     }
   6669 
   6670 #ifdef SETXID_SUPPORT
   6671     /* Honor the setuid bit iff set. */
   6672     if (getuid() != geteuid())
   6673 	rc = setuid (geteuid ());
   6674     else
   6675 #endif
   6676 	rc = setuid (pw->pw_uid);
   6677     if (rc < 0)
   6678     {
   6679 	/* Note that this means that if run as a non-root user,
   6680 	   CVSROOT/passwd must contain the user we are running as
   6681 	   (e.g. "joe:FsEfVcu:cvs" if run as "cvs" user).  This seems
   6682 	   cleaner than ignoring the error like CVS 1.10 and older but
   6683 	   it does mean that some people might need to update their
   6684 	   CVSROOT/passwd file.  */
   6685 	printf ("error 0 setuid failed: %s\n", strerror (errno));
   6686 #ifdef HAVE_SYSLOG_H
   6687 	    syslog (LOG_DAEMON | LOG_ERR,
   6688 		    "setuid to %d failed (%m): real %d/%d, effective %d/%d ",
   6689 		    pw->pw_uid, getuid(), getgid(), geteuid(), getegid());
   6690 #endif /* HAVE_SYSLOG_H */
   6691 	exit (EXIT_FAILURE);
   6692     }
   6693 
   6694     /* We don't want our umask to change file modes.  The modes should
   6695        be set by the modes used in the repository, and by the umask of
   6696        the client.  */
   6697     umask (0);
   6698 
   6699 #ifdef AUTH_SERVER_SUPPORT
   6700     /* Make sure our CVS_Username has been set. */
   6701     if (CVS_Username == NULL)
   6702 	CVS_Username = xstrdup (username);
   6703 #endif
   6704 
   6705     /* Set LOGNAME, USER and CVS_USER in the environment, in case they
   6706        are already set to something else.  */
   6707     setenv ("LOGNAME", username, 1);
   6708     setenv ("USER", username, 1);
   6709 # ifdef AUTH_SERVER_SUPPORT
   6710     setenv ("CVS_USER", CVS_Username, 1);
   6711 # endif
   6712 }
   6713 #endif
   6714 
   6715 #ifdef AUTH_SERVER_SUPPORT
   6716 
   6717 extern char *crypt (const char *, const char *);
   6718 
   6719 
   6720 /*
   6722  * 0 means no entry found for this user.
   6723  * 1 means entry found and password matches (or found password is empty)
   6724  * 2 means entry found, but password does not match.
   6725  *
   6726  * If 1, host_user_ptr will be set to point at the system
   6727  * username (i.e., the "real" identity, which may or may not be the
   6728  * CVS username) of this user; caller may free this.  Global
   6729  * CVS_Username will point at an allocated copy of cvs username (i.e.,
   6730  * the username argument below).
   6731  * kff todo: FIXME: last sentence is not true, it applies to caller.
   6732  */
   6733 static int
   6734 check_repository_password (char *username, char *password, char *repository, char **host_user_ptr)
   6735 {
   6736     int retval = 0;
   6737     FILE *fp;
   6738     char *filename;
   6739     char *linebuf = NULL;
   6740     size_t linebuf_len;
   6741     int found_it = 0;
   6742     int namelen;
   6743 
   6744     /* We don't use current_parsed_root->directory because it hasn't been
   6745      * set yet -- our `repository' argument came from the authentication
   6746      * protocol, not the regular CVS protocol.
   6747      */
   6748 
   6749     filename = xmalloc (strlen (repository)
   6750 			+ 1
   6751 			+ strlen (CVSROOTADM)
   6752 			+ 1
   6753 			+ strlen (CVSROOTADM_PASSWD)
   6754 			+ 1);
   6755 
   6756     (void) sprintf (filename, "%s/%s/%s", repository,
   6757 		    CVSROOTADM, CVSROOTADM_PASSWD);
   6758 
   6759     fp = CVS_FOPEN (filename, "r");
   6760     if (fp == NULL)
   6761     {
   6762 	if (!existence_error (errno))
   6763 	    error (0, errno, "cannot open %s", filename);
   6764 	free (filename);
   6765 	return 0;
   6766     }
   6767 
   6768     /* Look for a relevant line -- one with this user's name. */
   6769     namelen = strlen (username);
   6770     while (getline (&linebuf, &linebuf_len, fp) >= 0)
   6771     {
   6772 	if ((strncmp (linebuf, username, namelen) == 0)
   6773 	    && (linebuf[namelen] == ':'))
   6774 	{
   6775 	    found_it = 1;
   6776 	    break;
   6777 	}
   6778     }
   6779     if (ferror (fp))
   6780 	error (0, errno, "cannot read %s", filename);
   6781     if (fclose (fp) < 0)
   6782 	error (0, errno, "cannot close %s", filename);
   6783 
   6784     /* If found_it, then linebuf contains the information we need. */
   6785     if (found_it)
   6786     {
   6787 	char *found_password, *host_user_tmp;
   6788 	char *non_cvsuser_portion;
   6789 
   6790 	/* We need to make sure lines such as
   6791 	 *
   6792 	 *    "username::sysuser\n"
   6793 	 *    "username:\n"
   6794 	 *    "username:  \n"
   6795 	 *
   6796 	 * all result in a found_password of NULL, but we also need to
   6797 	 * make sure that
   6798 	 *
   6799 	 *    "username:   :sysuser\n"
   6800 	 *    "username: <whatever>:sysuser\n"
   6801 	 *
   6802 	 * continues to result in an impossible password.  That way,
   6803 	 * an admin would be on safe ground by going in and tacking a
   6804 	 * space onto the front of a password to disable the account
   6805 	 * (a technique some people use to close accounts
   6806 	 * temporarily).
   6807 	 */
   6808 
   6809 	/* Make `non_cvsuser_portion' contain everything after the CVS
   6810 	   username, but null out any final newline. */
   6811 	non_cvsuser_portion = linebuf + namelen;
   6812 	strtok (non_cvsuser_portion, "\n");
   6813 
   6814 	/* If there's a colon now, we just want to inch past it. */
   6815 	if (strchr (non_cvsuser_portion, ':') == non_cvsuser_portion)
   6816 	    non_cvsuser_portion++;
   6817 
   6818 	/* Okay, after this conditional chain, found_password and
   6819 	   host_user_tmp will have useful values: */
   6820 
   6821 	if ((non_cvsuser_portion == NULL)
   6822 	    || (strlen (non_cvsuser_portion) == 0)
   6823 	    || ((strspn (non_cvsuser_portion, " \t"))
   6824 		== strlen (non_cvsuser_portion)))
   6825 	{
   6826 	    found_password = NULL;
   6827 	    host_user_tmp = NULL;
   6828 	}
   6829 	else if (strncmp (non_cvsuser_portion, ":", 1) == 0)
   6830 	{
   6831 	    found_password = NULL;
   6832 	    host_user_tmp = non_cvsuser_portion + 1;
   6833 	    if (strlen (host_user_tmp) == 0)
   6834 		host_user_tmp = NULL;
   6835 	}
   6836 	else
   6837 	{
   6838 	    found_password = strtok (non_cvsuser_portion, ":");
   6839 	    host_user_tmp = strtok (NULL, ":");
   6840 	}
   6841 
   6842 	/* Of course, maybe there was no system user portion... */
   6843 	if (host_user_tmp == NULL)
   6844 	    host_user_tmp = username;
   6845 
   6846 	/* Verify blank passwords directly, otherwise use crypt(). */
   6847 	if ((found_password == NULL)
   6848 	    || ((strcmp (found_password, crypt (password, found_password))
   6849 		 == 0)))
   6850 	{
   6851 	    /* Give host_user_ptr permanent storage. */
   6852 	    *host_user_ptr = xstrdup (host_user_tmp);
   6853 	    retval = 1;
   6854 	}
   6855 	else
   6856 	{
   6857 #ifdef LOG_AUTHPRIV
   6858 	syslog (LOG_AUTHPRIV | LOG_NOTICE,
   6859 		"password mismatch for %s in %s: %s vs. %s", username,
   6860 		repository, crypt(password, found_password), found_password);
   6861 #endif
   6862 	    *host_user_ptr = NULL;
   6863 	    retval	 = 2;
   6864 	}
   6865     }
   6866     else     /* Didn't find this user, so deny access. */
   6867     {
   6868 	*host_user_ptr = NULL;
   6869 	retval = 0;
   6870     }
   6871 
   6872     free (filename);
   6873     if (linebuf)
   6874 	free (linebuf);
   6875 
   6876     return retval;
   6877 }
   6878 
   6879 #ifdef HAVE_PAM
   6880 
   6881 static int
   6882 cvs_pam_conv (int num_msg, const struct pam_message **msg,
   6883               struct pam_response **resp, void *appdata_ptr)
   6884 {
   6885     int i;
   6886     struct pam_response *response;
   6887 
   6888     assert (msg && resp);
   6889 
   6890     response = xnmalloc (num_msg, sizeof (struct pam_response));
   6891     memset (response, 0, num_msg * sizeof (struct pam_response));
   6892 
   6893     for (i = 0; i < num_msg; i++)
   6894     {
   6895 	switch (msg[i]->msg_style)
   6896 	{
   6897 	    /* PAM wants a username */
   6898 	    case PAM_PROMPT_ECHO_ON:
   6899                 assert (pam_username != 0);
   6900 		response[i].resp = xstrdup (pam_username);
   6901 		break;
   6902 	    /* PAM wants a password */
   6903 	    case PAM_PROMPT_ECHO_OFF:
   6904                 assert (pam_password != 0);
   6905 		response[i].resp = xstrdup (pam_password);
   6906 		break;
   6907 	    case PAM_ERROR_MSG:
   6908 	    case PAM_TEXT_INFO:
   6909 		printf ("E %s\n", msg[i]->msg);
   6910 		break;
   6911 	    /* PAM wants something we don't understand - bail out */
   6912 	    default:
   6913 		goto cleanup;
   6914 	}
   6915     }
   6916 
   6917     *resp = response;
   6918     return PAM_SUCCESS;
   6919 
   6920 cleanup:
   6921     for (i = 0; i < num_msg; i++)
   6922     {
   6923 	if (response[i].resp)
   6924 	{
   6925 	    free (response[i].resp);
   6926 	    response[i].resp = 0;
   6927 	}
   6928     }
   6929     free (response);
   6930     return PAM_CONV_ERR;
   6931 }
   6932 
   6933 static int
   6934 check_pam_password (char **username, char *password)
   6935 {
   6936     int retval, err;
   6937     struct pam_conv conv = { cvs_pam_conv, 0 };
   6938     char *pam_stage = "start";
   6939 
   6940     pam_username = *username;
   6941     pam_password = password;
   6942 
   6943     retval = pam_start (PAM_SERVICE_NAME, *username, &conv, &pamh);
   6944 
   6945     /* sets a dummy tty name which pam modules can check for */
   6946     if (retval == PAM_SUCCESS)
   6947     {
   6948         pam_stage = "set dummy tty";
   6949         retval = pam_set_item (pamh, PAM_TTY, PAM_SERVICE_NAME);
   6950     }
   6951 
   6952     if (retval == PAM_SUCCESS)
   6953     {
   6954 	pam_stage = "authenticate";
   6955 	retval = pam_authenticate (pamh, 0);
   6956     }
   6957 
   6958     if (retval == PAM_SUCCESS)
   6959     {
   6960 	pam_stage = "account";
   6961 	retval = pam_acct_mgmt (pamh, 0);
   6962     }
   6963 
   6964     if (retval == PAM_SUCCESS)
   6965     {
   6966         pam_stage = "get pam user";
   6967         retval = pam_get_item (pamh, PAM_USER, (const void **)username);
   6968     }
   6969 
   6970     if (retval != PAM_SUCCESS)
   6971 	printf ("E PAM %s error: %s\n", pam_stage, pam_strerror (pamh, retval));
   6972 
   6973     /* clear the pointers to make sure we don't use these references again */
   6974     pam_username = 0;
   6975     pam_password = 0;
   6976 
   6977     return retval == PAM_SUCCESS;       /* indicate success */
   6978 }
   6979 #endif
   6980 
   6981 static int
   6982 check_system_password (char *username, char *password)
   6983 {
   6984     char *found_passwd = NULL;
   6985     struct passwd *pw;
   6986 #ifdef HAVE_GETSPNAM
   6987     {
   6988 	struct spwd *spw;
   6989 
   6990 	spw = getspnam (username);
   6991 	if (spw != NULL)
   6992 	    found_passwd = spw->sp_pwdp;
   6993     }
   6994 #endif
   6995 
   6996     if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
   6997 	found_passwd = pw->pw_passwd;
   6998 
   6999     if (found_passwd == NULL)
   7000     {
   7001 	printf ("E Fatal error, aborting.\n\
   7002 error 0 %s: no such user\n", username);
   7003 
   7004 	exit (EXIT_FAILURE);
   7005     }
   7006 
   7007     /* Allow for dain bramaged HPUX passwd aging
   7008      *  - Basically, HPUX adds a comma and some data
   7009      *    about whether the passwd has expired or not
   7010      *    on the end of the passwd field.
   7011      *  - This code replaces the ',' with '\0'.
   7012      *
   7013      * FIXME - our workaround is brain damaged too.  I'm
   7014      * guessing that HPUX WANTED other systems to think the
   7015      * password was wrong so logins would fail if the
   7016      * system didn't handle expired passwds and the passwd
   7017      * might be expired.  I think the way to go here
   7018      * is with PAM.
   7019      */
   7020     strtok (found_passwd, ",");
   7021 
   7022     if (*found_passwd)
   7023     {
   7024 	/* user exists and has a password */
   7025 	if (strcmp (found_passwd, crypt (password, found_passwd)) == 0)
   7026 	    return 1;
   7027 	else
   7028 	{
   7029 #ifdef LOG_AUTHPRIV
   7030 	    syslog (LOG_AUTHPRIV | LOG_NOTICE,
   7031 		    "password mismatch for %s: %s vs. %s", username,
   7032 		    crypt(password, found_passwd), found_passwd);
   7033 #endif
   7034 	    return 0;
   7035 	}
   7036     }
   7037 
   7038 #ifdef LOG_AUTHPRIV
   7039     syslog (LOG_AUTHPRIV | LOG_NOTICE,
   7040 	    "user %s authenticated because of blank system password",
   7041 	    username);
   7042 #endif
   7043     return 1;
   7044 }
   7045 
   7046 
   7047 
   7048 /* Return a hosting username if password matches, else NULL. */
   7049 static char *
   7050 check_password (char *username, char *password, char *repository)
   7051 {
   7052     int rc;
   7053     char *host_user = NULL;
   7054 
   7055     /* First we see if this user has a password in the CVS-specific
   7056        password file.  If so, that's enough to authenticate with.  If
   7057        not, we'll check /etc/passwd or maybe whatever is configured via PAM. */
   7058 
   7059     rc = check_repository_password (username, password, repository,
   7060 				    &host_user);
   7061 
   7062     if (rc == 2)
   7063 	return NULL;
   7064 
   7065     if (rc == 1)
   7066 	/* host_user already set by reference, so just return. */
   7067 	goto handle_return;
   7068 
   7069     assert (rc == 0);
   7070 
   7071     if (!config->system_auth)
   7072     {
   7073 	/* Note that the message _does_ distinguish between the case in
   7074 	   which we check for a system password and the case in which
   7075 	   we do not.  It is a real pain to track down why it isn't
   7076 	   letting you in if it won't say why, and I am not convinced
   7077 	   that the potential information disclosure to an attacker
   7078 	   outweighs this.  */
   7079 	printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
   7080 
   7081 	exit (EXIT_FAILURE);
   7082     }
   7083 
   7084     /* No cvs password found, so try /etc/passwd. */
   7085 #ifdef HAVE_PAM
   7086     if (check_pam_password (&username, password))
   7087 #else /* !HAVE_PAM */
   7088     if (check_system_password (username, password))
   7089 #endif /* HAVE_PAM */
   7090 	host_user = xstrdup (username);
   7091     else
   7092 	host_user = NULL;
   7093 
   7094 #ifdef LOG_AUTHPRIV
   7095     if (!host_user)
   7096 	syslog (LOG_AUTHPRIV | LOG_NOTICE,
   7097 		"login refused for %s: user has no password", username);
   7098 #endif
   7099 
   7100 handle_return:
   7101     if (host_user)
   7102     {
   7103 	/* Set CVS_Username here, in allocated space.
   7104 	   It might or might not be the same as host_user. */
   7105 	CVS_Username = xmalloc (strlen (username) + 1);
   7106 	strcpy (CVS_Username, username);
   7107     }
   7108 
   7109     return host_user;
   7110 }
   7111 
   7112 #endif /* AUTH_SERVER_SUPPORT */
   7113 
   7114 #if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)
   7115 
   7116 static void
   7117 pserver_read_line (char **tmp, size_t *tmp_len)
   7118 {
   7119     int status;
   7120 
   7121     /* Make sure the protocol starts off on the right foot... */
   7122     status = buf_read_short_line (buf_from_net, tmp, tmp_len, PATH_MAX);
   7123     if (status == -1)
   7124     {
   7125 # ifdef HAVE_SYSLOG_H
   7126 	syslog (LOG_DAEMON | LOG_NOTICE,
   7127 	        "unexpected EOF encountered during authentication");
   7128 # endif /* HAVE_SYSLOG_H */
   7129 	error (1, 0, "unexpected EOF encountered during authentication");
   7130     }
   7131     if (status == -2)
   7132 	status = ENOMEM;
   7133     if (status != 0)
   7134     {
   7135 # ifdef HAVE_SYSLOG_H
   7136 	syslog (LOG_DAEMON | LOG_NOTICE,
   7137                 "error reading from net while validating pserver");
   7138 # endif /* HAVE_SYSLOG_H */
   7139 	error (1, status, "error reading from net while validating pserver");
   7140     }
   7141 }
   7142 
   7143 /* Read username and password from client (i.e., stdin).
   7144    If correct, then switch to run as that user and send an ACK to the
   7145    client via stdout, else send NACK and die. */
   7146 void
   7147 pserver_authenticate_connection (void)
   7148 {
   7149     char *tmp;
   7150 #ifdef AUTH_SERVER_SUPPORT
   7151     char *repository = NULL;
   7152     char *username = NULL;
   7153     char *password = NULL;
   7154 
   7155     char *host_user;
   7156     char *descrambled_password;
   7157 #endif /* AUTH_SERVER_SUPPORT */
   7158     int verify_and_exit = 0;
   7159 
   7160     /* The Authentication Protocol.  Client sends:
   7161      *
   7162      *   BEGIN AUTH REQUEST\n
   7163      *   <REPOSITORY>\n
   7164      *   <USERNAME>\n
   7165      *   <PASSWORD>\n
   7166      *   END AUTH REQUEST\n
   7167      *
   7168      * Server uses above information to authenticate, then sends
   7169      *
   7170      *   I LOVE YOU\n
   7171      *
   7172      * if it grants access, else
   7173      *
   7174      *   I HATE YOU\n
   7175      *
   7176      * if it denies access (and it exits if denying).
   7177      *
   7178      * When the client is "cvs login", the user does not desire actual
   7179      * repository access, but would like to confirm the password with
   7180      * the server.  In this case, the start and stop strings are
   7181      *
   7182      *   BEGIN VERIFICATION REQUEST\n
   7183      *
   7184      *	    and
   7185      *
   7186      *   END VERIFICATION REQUEST\n
   7187      *
   7188      * On a verification request, the server's responses are the same
   7189      * (with the obvious semantics), but it exits immediately after
   7190      * sending the response in both cases.
   7191      *
   7192      * Why is the repository sent?  Well, note that the actual
   7193      * client/server protocol can't start up until authentication is
   7194      * successful.  But in order to perform authentication, the server
   7195      * needs to look up the password in the special CVS passwd file,
   7196      * before trying /etc/passwd.  So the client transmits the
   7197      * repository as part of the "authentication protocol".  The
   7198      * repository will be redundantly retransmitted later, but that's no
   7199      * big deal.
   7200      */
   7201 
   7202     /* Initialize buffers.  */
   7203     buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, NULL, false,
   7204 				       outbuf_memory_error);
   7205     buf_from_net = fd_buffer_initialize (STDIN_FILENO, 0, NULL, true,
   7206 					 outbuf_memory_error);
   7207 
   7208 #ifdef SO_KEEPALIVE
   7209     /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
   7210        if the client dies while we are waiting for input.  */
   7211     {
   7212 	int on = 1;
   7213 
   7214 	if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
   7215 			&on, sizeof on) < 0)
   7216 	{
   7217 # ifdef HAVE_SYSLOG_H
   7218 	    syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m");
   7219 # endif /* HAVE_SYSLOG_H */
   7220 	}
   7221     }
   7222 #endif
   7223 
   7224     /* Make sure the protocol starts off on the right foot... */
   7225     pserver_read_line (&tmp, NULL);
   7226 
   7227     if (strcmp (tmp, "BEGIN VERIFICATION REQUEST") == 0)
   7228 	verify_and_exit = 1;
   7229     else if (strcmp (tmp, "BEGIN AUTH REQUEST") == 0)
   7230 	;
   7231     else if (strcmp (tmp, "BEGIN GSSAPI REQUEST") == 0)
   7232     {
   7233 #ifdef HAVE_GSSAPI
   7234 	free (tmp);
   7235 	gserver_authenticate_connection ();
   7236 	return;
   7237 #else
   7238 	error (1, 0, "GSSAPI authentication not supported by this server");
   7239 #endif
   7240     }
   7241     else
   7242 	error (1, 0, "bad auth protocol start: %s", tmp);
   7243 
   7244 #ifndef AUTH_SERVER_SUPPORT
   7245 
   7246     error (1, 0, "Password authentication not supported by this server");
   7247 
   7248 #else /* AUTH_SERVER_SUPPORT */
   7249 
   7250     free (tmp);
   7251 
   7252     /* Get the three important pieces of information in order. */
   7253     /* See above comment about error handling.  */
   7254     pserver_read_line (&repository, NULL);
   7255     pserver_read_line (&username, NULL);
   7256     pserver_read_line (&password, NULL);
   7257 
   7258     /* ... and make sure the protocol ends on the right foot. */
   7259     /* See above comment about error handling.  */
   7260     pserver_read_line (&tmp, NULL);
   7261     if (strcmp (tmp,
   7262 		verify_and_exit ?
   7263 		"END VERIFICATION REQUEST" : "END AUTH REQUEST")
   7264 	!= 0)
   7265     {
   7266 	error (1, 0, "bad auth protocol end: %s", tmp);
   7267     }
   7268     free (tmp);
   7269 
   7270     if (!root_allow_ok (repository))
   7271     {
   7272 	error (1, 0, "%s: no such repository", repository);
   7273 # ifdef HAVE_SYSLOG_H
   7274 	syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository);
   7275 # endif /* HAVE_SYSLOG_H */
   7276 	goto i_hate_you;
   7277     }
   7278 
   7279     /* OK, now parse the config file, so we can use it to control how
   7280        to check passwords.  If there was an error parsing the config
   7281        file, parse_config already printed an error.  We keep going.
   7282        Why?  Because if we didn't, then there would be no way to check
   7283        in a new CVSROOT/config file to fix the broken one!  */
   7284     config = get_root_allow_config (repository, gConfigPath);
   7285 
   7286     /* cvsacl patch */
   7287     parse_aclconfig (repository);
   7288 
   7289     /* We need the real cleartext before we hash it. */
   7290     descrambled_password = descramble (password);
   7291     host_user = check_password (username, descrambled_password, repository);
   7292     if (host_user == NULL)
   7293     {
   7294 # ifdef HAVE_SYSLOG_H
   7295 	syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository);
   7296 # endif /* HAVE_SYSLOG_H */
   7297 	memset (descrambled_password, 0, strlen (descrambled_password));
   7298 	free (descrambled_password);
   7299     i_hate_you:
   7300 	buf_output0 (buf_to_net, "I HATE YOU\n");
   7301 	buf_flush (buf_to_net, true);
   7302 
   7303 	/* Don't worry about server_cleanup, server_active isn't set
   7304 	   yet.  */
   7305 	exit (EXIT_FAILURE);
   7306     }
   7307     memset (descrambled_password, 0, strlen (descrambled_password));
   7308     free (descrambled_password);
   7309 
   7310     /* Don't go any farther if we're just responding to "cvs login". */
   7311     if (verify_and_exit)
   7312     {
   7313 	buf_output0 (buf_to_net, "I LOVE YOU\n");
   7314 	buf_flush (buf_to_net, true);
   7315 	exit (EXIT_SUCCESS);
   7316     }
   7317 
   7318     /* Set Pserver_Repos so that we can check later that the same
   7319        repository is sent in later client/server protocol. */
   7320     Pserver_Repos = xmalloc (strlen (repository) + 1);
   7321     strcpy (Pserver_Repos, repository);
   7322 
   7323     /* Switch to run as this user. */
   7324     switch_to_user (username, host_user);
   7325     free (host_user);
   7326     free (repository);
   7327     free (username);
   7328     free (password);
   7329 
   7330     buf_output0 (buf_to_net, "I LOVE YOU\n");
   7331     buf_flush (buf_to_net, true);
   7332 #endif /* AUTH_SERVER_SUPPORT */
   7333 }
   7334 
   7335 #endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */
   7336 
   7337 
   7338 #ifdef HAVE_KERBEROS
   7339 void
   7340 kserver_authenticate_connection( void )
   7341 {
   7342     int status;
   7343     char instance[INST_SZ];
   7344     struct sockaddr_storage peer;
   7345     struct sockaddr_storage laddr;
   7346     int plen, llen;
   7347     KTEXT_ST ticket;
   7348     AUTH_DAT auth;
   7349     char version[KRB_SENDAUTH_VLEN];
   7350     char user[ANAME_SZ];
   7351 
   7352     strcpy (instance, "*");
   7353     plen = sizeof peer;
   7354     llen = sizeof laddr;
   7355     if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &plen) < 0
   7356 	|| getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
   7357 			&llen) < 0)
   7358     {
   7359 	printf ("E Fatal error, aborting.\n\
   7360 error %s getpeername or getsockname failed\n", strerror (errno));
   7361 
   7362 	exit (EXIT_FAILURE);
   7363     }
   7364 
   7365 #ifdef SO_KEEPALIVE
   7366     /* Set SO_KEEPALIVE on the socket, so that we don't hang forever
   7367        if the client dies while we are waiting for input.  */
   7368     {
   7369 	int on = 1;
   7370 
   7371 	if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
   7372 			   (char *) &on, sizeof on) < 0)
   7373 	{
   7374 # ifdef HAVE_SYSLOG_H
   7375 	    syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m");
   7376 # endif /* HAVE_SYSLOG_H */
   7377 	}
   7378     }
   7379 #endif
   7380 
   7381     status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd",
   7382 			   instance, &peer, &laddr, &auth, "", sched,
   7383 			   version);
   7384     if (status != KSUCCESS)
   7385     {
   7386 	printf ("E Fatal error, aborting.\n\
   7387 error 0 kerberos: %s\n", krb_get_err_text(status));
   7388 
   7389 	exit (EXIT_FAILURE);
   7390     }
   7391 
   7392     memcpy (kblock, auth.session, sizeof (C_Block));
   7393 
   7394     /* Get the local name.  */
   7395     status = krb_kntoln (&auth, user);
   7396     if (status != KSUCCESS)
   7397     {
   7398 	printf ("E Fatal error, aborting.\n"
   7399 		"error 0 kerberos: can't get local name: %s\n",
   7400 		krb_get_err_text(status));
   7401 
   7402 	exit (EXIT_FAILURE);
   7403     }
   7404 
   7405     /* Switch to run as this user. */
   7406     switch_to_user ("Kerberos 4", user);
   7407 }
   7408 #endif /* HAVE_KERBEROS */
   7409 
   7410 
   7411 
   7412 # ifdef HAVE_GSSAPI /* && SERVER_SUPPORT */
   7413 /* Authenticate a GSSAPI connection.  This is called from
   7414  * pserver_authenticate_connection, and it handles success and failure
   7415  * the same way.
   7416  *
   7417  * GLOBALS
   7418  *   server_hostname	The name of this host, as set via a call to
   7419  *			xgethostname() in main().
   7420  */
   7421 static void
   7422 gserver_authenticate_connection (void)
   7423 {
   7424     char *hn;
   7425     gss_buffer_desc tok_in, tok_out;
   7426     char buf[1024];
   7427     char *credbuf;
   7428     size_t credbuflen;
   7429     OM_uint32 stat_min, ret;
   7430     gss_name_t server_name, client_name;
   7431     gss_cred_id_t server_creds;
   7432     int nbytes;
   7433     gss_OID mechid;
   7434 
   7435     hn = canon_host (server_hostname);
   7436     if (!hn)
   7437 	error (1, 0, "can't get canonical hostname for `%s': %s",
   7438 	       server_hostname, ch_strerror ());
   7439 
   7440     sprintf (buf, "cvs@%s", hn);
   7441     free (hn);
   7442     tok_in.value = buf;
   7443     tok_in.length = strlen (buf);
   7444 
   7445     if (gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
   7446 			 &server_name) != GSS_S_COMPLETE)
   7447 	error (1, 0, "could not import GSSAPI service name %s", buf);
   7448 
   7449     /* Acquire the server credential to verify the client's
   7450        authentication.  */
   7451     if (gss_acquire_cred (&stat_min, server_name, 0, GSS_C_NULL_OID_SET,
   7452 			  GSS_C_ACCEPT, &server_creds,
   7453 			  NULL, NULL) != GSS_S_COMPLETE)
   7454 	error (1, 0, "could not acquire GSSAPI server credentials");
   7455 
   7456     gss_release_name (&stat_min, &server_name);
   7457 
   7458     /* The client will send us a two byte length followed by that many
   7459        bytes.  */
   7460     if (fread (buf, 1, 2, stdin) != 2)
   7461 	error (1, errno, "read of length failed");
   7462 
   7463     nbytes = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff);
   7464     if (nbytes <= sizeof buf)
   7465     {
   7466         credbuf = buf;
   7467         credbuflen = sizeof buf;
   7468     }
   7469     else
   7470     {
   7471         credbuflen = nbytes;
   7472         credbuf = xmalloc (credbuflen);
   7473     }
   7474 
   7475     if (fread (credbuf, 1, nbytes, stdin) != nbytes)
   7476 	error (1, errno, "read of data failed");
   7477 
   7478     gcontext = GSS_C_NO_CONTEXT;
   7479     tok_in.length = nbytes;
   7480     tok_in.value = credbuf;
   7481 
   7482     if (gss_accept_sec_context (&stat_min,
   7483 				&gcontext,	/* context_handle */
   7484 				server_creds,	/* verifier_cred_handle */
   7485 				&tok_in,	/* input_token */
   7486 				NULL,		/* channel bindings */
   7487 				&client_name,	/* src_name */
   7488 				&mechid,	/* mech_type */
   7489 				&tok_out,	/* output_token */
   7490 				&ret,
   7491 				NULL,		/* ignore time_rec */
   7492 				NULL)		/* ignore del_cred_handle */
   7493 	!= GSS_S_COMPLETE)
   7494     {
   7495 	error (1, 0, "could not verify credentials");
   7496     }
   7497 
   7498     /* FIXME: Use Kerberos v5 specific code to authenticate to a user.
   7499        We could instead use an authentication to access mapping.  */
   7500     {
   7501 	krb5_context kc;
   7502 	krb5_principal p;
   7503 	gss_buffer_desc desc;
   7504 
   7505 	krb5_init_context (&kc);
   7506 	if (gss_display_name (&stat_min, client_name, &desc,
   7507 			      &mechid) != GSS_S_COMPLETE
   7508 	    || krb5_parse_name (kc, ((gss_buffer_t) &desc)->value, &p) != 0
   7509 	    || krb5_aname_to_localname (kc, p, sizeof buf, buf) != 0
   7510 	    || krb5_kuserok (kc, p, buf) != TRUE)
   7511 	{
   7512 	    error (1, 0, "access denied");
   7513 	}
   7514 	krb5_free_principal (kc, p);
   7515 	krb5_free_context (kc);
   7516     }
   7517 
   7518     if (tok_out.length != 0)
   7519     {
   7520 	char cbuf[2];
   7521 
   7522 	cbuf[0] = (tok_out.length >> 8) & 0xff;
   7523 	cbuf[1] = tok_out.length & 0xff;
   7524 	if (fwrite (cbuf, 1, 2, stdout) != 2
   7525 	    || (fwrite (tok_out.value, 1, tok_out.length, stdout)
   7526 		!= tok_out.length))
   7527 	    error (1, errno, "fwrite failed");
   7528     }
   7529 
   7530     switch_to_user ("GSSAPI", buf);
   7531 
   7532     if (credbuf != buf)
   7533         free (credbuf);
   7534 
   7535     printf ("I LOVE YOU\n");
   7536     fflush (stdout);
   7537 }
   7538 
   7539 # endif /* HAVE_GSSAPI */
   7540 
   7541 #endif /* SERVER_SUPPORT */
   7542 
   7543 #if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
   7544 
   7545 /* This global variable is non-zero if the user requests encryption on
   7546    the command line.  */
   7547 int cvsencrypt;
   7548 
   7549 /* This global variable is non-zero if the users requests stream
   7550    authentication on the command line.  */
   7551 int cvsauthenticate;
   7552 
   7553 #ifdef ENCRYPTION
   7554 
   7555 #ifdef HAVE_KERBEROS
   7556 
   7557 /* An encryption interface using Kerberos.  This is built on top of a
   7558    packetizing buffer.  */
   7559 
   7560 /* This structure is the closure field of the Kerberos translation
   7561    routines.  */
   7562 struct krb_encrypt_data
   7563 {
   7564     /* The Kerberos key schedule.  */
   7565     Key_schedule sched;
   7566     /* The Kerberos DES block.  */
   7567     C_Block block;
   7568 };
   7569 
   7570 
   7571 
   7572 /* Decrypt Kerberos data.  */
   7573 static int
   7574 krb_encrypt_input( void *fnclosure, const char *input, char *output, int size )
   7575 {
   7576     struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure;
   7577     int tcount;
   7578 
   7579     des_cbc_encrypt ((char *) input, (char *) output,
   7580 		     size, kd->sched, &kd->block, 0);
   7581 
   7582     /* SIZE is the size of the buffer, which is set by the encryption
   7583        routine.  The packetizing buffer will arrange for the first two
   7584        bytes in the decrypted buffer to be the real (unaligned)
   7585        length.  As a safety check, make sure that the length in the
   7586        buffer corresponds to SIZE.  Note that the length in the buffer
   7587        is just the length of the data.  We must add 2 to account for
   7588        the buffer count itself.  */
   7589     tcount = ((output[0] & 0xff) << 8) + (output[1] & 0xff);
   7590     if (((tcount + 2 + 7) & ~7) != size)
   7591       error (1, 0, "Decryption failure");
   7592 
   7593     return 0;
   7594 }
   7595 
   7596 
   7597 
   7598 /* Encrypt Kerberos data.  */
   7599 static int
   7600 krb_encrypt_output( void *fnclosure, const char *input, char *output,
   7601                     int size, int *translated )
   7602 {
   7603     struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure;
   7604     int aligned;
   7605 
   7606     /* For security against a known plaintext attack, we should
   7607        initialize any padding bytes to random values.  Instead, we
   7608        just pick up whatever is on the stack, which is at least better
   7609        than using zero.  */
   7610 
   7611     /* Align SIZE to an 8 byte boundary.  Note that SIZE includes the
   7612        two byte buffer count at the start of INPUT which was added by
   7613        the packetizing buffer.  */
   7614     aligned = (size + 7) & ~7;
   7615 
   7616     /* We use des_cbc_encrypt rather than krb_mk_priv because the
   7617        latter sticks a timestamp in the block, and krb_rd_priv expects
   7618        that timestamp to be within five minutes of the current time.
   7619        Given the way the CVS server buffers up data, that can easily
   7620        fail over a long network connection.  We trust krb_recvauth to
   7621        guard against a replay attack.  */
   7622 
   7623     des_cbc_encrypt ((char *) input, (char *) output, aligned,
   7624 		     kd->sched, &kd->block, 1);
   7625 
   7626     *translated = aligned;
   7627 
   7628     return 0;
   7629 }
   7630 
   7631 
   7632 
   7633 /* Create a Kerberos encryption buffer.  We use a packetizing buffer
   7634    with Kerberos encryption translation routines.  */
   7635 struct buffer *
   7636 krb_encrypt_buffer_initialize( struct buffer *buf, int input,
   7637                                Key_schedule sched, C_Block block,
   7638                                void *memory( struct buffer * ) )
   7639 {
   7640     struct krb_encrypt_data *kd;
   7641 
   7642     kd = (struct krb_encrypt_data *) xmalloc (sizeof *kd);
   7643     memcpy (kd->sched, sched, sizeof (Key_schedule));
   7644     memcpy (kd->block, block, sizeof (C_Block));
   7645 
   7646     return packetizing_buffer_initialize (buf,
   7647 					  input ? krb_encrypt_input : NULL,
   7648 					  input ? NULL : krb_encrypt_output,
   7649 					  kd,
   7650 					  memory);
   7651 }
   7652 
   7653 #endif /* HAVE_KERBEROS */
   7654 #endif /* ENCRYPTION */
   7655 #endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */
   7656 
   7657 
   7658 
   7659 /* Output LEN bytes at STR.  If LEN is zero, then output up to (not including)
   7660    the first '\0' byte.  */
   7661 void
   7662 cvs_output (const char *str, size_t len)
   7663 {
   7664     if (len == 0)
   7665 	len = strlen (str);
   7666 #ifdef SERVER_SUPPORT
   7667     if (error_use_protocol)
   7668     {
   7669 	if (buf_to_net)
   7670 	{
   7671 	    buf_output (saved_output, str, len);
   7672 	    buf_copy_lines (buf_to_net, saved_output, 'M');
   7673 	}
   7674 # if HAVE_SYSLOG_H
   7675 	else
   7676 	    syslog (LOG_DAEMON | LOG_ERR,
   7677 		    "Attempt to write message after close of network buffer.  "
   7678 		    "Message was: %s",
   7679 		    str);
   7680 # endif /* HAVE_SYSLOG_H */
   7681     }
   7682     else if (server_active)
   7683     {
   7684 	if (protocol)
   7685 	{
   7686 	    buf_output (saved_output, str, len);
   7687 	    buf_copy_lines (protocol, saved_output, 'M');
   7688 	    buf_send_counted (protocol);
   7689 	}
   7690 # if HAVE_SYSLOG_H
   7691 	else
   7692 	    syslog (LOG_DAEMON | LOG_ERR,
   7693 		    "Attempt to write message before initialization of "
   7694 		    "protocol buffer.  Message was: %s",
   7695 		    str);
   7696 # endif /* HAVE_SYSLOG_H */
   7697     }
   7698     else
   7699 #endif
   7700     {
   7701 	size_t written;
   7702 	size_t to_write = len;
   7703 	const char *p = str;
   7704 
   7705 	/* Local users that do 'cvs status 2>&1' on a local repository
   7706 	   may see the informational messages out-of-order with the
   7707 	   status messages unless we use the fflush (stderr) here. */
   7708 	fflush (stderr);
   7709 
   7710 	while (to_write > 0)
   7711 	{
   7712 	    written = fwrite (p, 1, to_write, stdout);
   7713 	    if (written == 0)
   7714 		break;
   7715 	    p += written;
   7716 	    to_write -= written;
   7717 	}
   7718     }
   7719 }
   7720 
   7721 /* Output LEN bytes at STR in binary mode.  If LEN is zero, then
   7722    output zero bytes.  */
   7723 
   7724 void
   7725 cvs_output_binary (char *str, size_t len)
   7726 {
   7727 #ifdef SERVER_SUPPORT
   7728     if (error_use_protocol || server_active)
   7729     {
   7730 	struct buffer *buf;
   7731 	char size_text[40];
   7732 
   7733 	if (error_use_protocol)
   7734 	    buf = buf_to_net;
   7735 	else
   7736 	    buf = protocol;
   7737 
   7738 	assert (buf);
   7739 
   7740 	if (!supported_response ("Mbinary"))
   7741 	{
   7742 	    error (0, 0, "\
   7743 this client does not support writing binary files to stdout");
   7744 	    return;
   7745 	}
   7746 
   7747 	buf_output0 (buf, "Mbinary\012");
   7748 	sprintf (size_text, "%lu\012", (unsigned long) len);
   7749 	buf_output0 (buf, size_text);
   7750 
   7751 	/* Not sure what would be involved in using buf_append_data here
   7752 	   without stepping on the toes of our caller (which is responsible
   7753 	   for the memory allocation of STR).  */
   7754 	buf_output (buf, str, len);
   7755 
   7756 	if (!error_use_protocol)
   7757 	    buf_send_counted (protocol);
   7758     }
   7759     else
   7760 #endif
   7761     {
   7762 	size_t written;
   7763 	size_t to_write = len;
   7764 	const char *p = str;
   7765 #ifdef USE_SETMODE_STDOUT
   7766 	int oldmode;
   7767 #endif
   7768 
   7769 	/* Local users that do 'cvs status 2>&1' on a local repository
   7770 	   may see the informational messages out-of-order with the
   7771 	   status messages unless we use the fflush (stderr) here. */
   7772 	fflush (stderr);
   7773 
   7774 #ifdef USE_SETMODE_STDOUT
   7775 	/* It is possible that this should be the same ifdef as
   7776 	   USE_SETMODE_BINARY but at least for the moment we keep them
   7777 	   separate.  Mostly this is just laziness and/or a question
   7778 	   of what has been tested where.  Also there might be an
   7779 	   issue of setmode vs. _setmode.  */
   7780 	/* The Windows doc says to call setmode only right after startup.
   7781 	   I assume that what they are talking about can also be helped
   7782 	   by flushing the stream before changing the mode.  */
   7783 	fflush (stdout);
   7784 	oldmode = _setmode (_fileno (stdout), OPEN_BINARY);
   7785 	if (oldmode < 0)
   7786 	    error (0, errno, "failed to setmode on stdout");
   7787 #endif
   7788 
   7789 	while (to_write > 0)
   7790 	{
   7791 	    written = fwrite (p, 1, to_write, stdout);
   7792 	    if (written == 0)
   7793 		break;
   7794 	    p += written;
   7795 	    to_write -= written;
   7796 	}
   7797 #ifdef USE_SETMODE_STDOUT
   7798 	fflush (stdout);
   7799 	if (_setmode (_fileno (stdout), oldmode) != OPEN_BINARY)
   7800 	    error (0, errno, "failed to setmode on stdout");
   7801 #endif
   7802     }
   7803 }
   7804 
   7805 
   7806 
   7807 /* Like CVS_OUTPUT but output is for stderr not stdout.  */
   7808 void
   7809 cvs_outerr (const char *str, size_t len)
   7810 {
   7811     if (len == 0)
   7812 	len = strlen (str);
   7813 #ifdef SERVER_SUPPORT
   7814     if (error_use_protocol)
   7815     {
   7816 	if (buf_to_net)
   7817 	{
   7818 	    buf_output (saved_outerr, str, len);
   7819 	    buf_copy_lines (buf_to_net, saved_outerr, 'E');
   7820 	}
   7821 # if HAVE_SYSLOG_H
   7822 	else
   7823 	    syslog (LOG_DAEMON | LOG_ERR,
   7824 		    "Attempt to write error message after close of network "
   7825 		    "buffer.  Message was: `%s'",
   7826 		    str);
   7827 # endif /* HAVE_SYSLOG_H */
   7828     }
   7829     else if (server_active)
   7830     {
   7831 	if (protocol)
   7832 	{
   7833 	    buf_output (saved_outerr, str, len);
   7834 	    buf_copy_lines (protocol, saved_outerr, 'E');
   7835 	    buf_send_counted (protocol);
   7836 	}
   7837 # if HAVE_SYSLOG_H
   7838 	else
   7839 	    syslog (LOG_DAEMON | LOG_ERR,
   7840 		    "Attempt to write error message before initialization of "
   7841 		    "protocol buffer.  Message was: `%s'",
   7842 		    str);
   7843 # endif /* HAVE_SYSLOG_H */
   7844     }
   7845     else
   7846 #endif
   7847     {
   7848 	size_t written;
   7849 	size_t to_write = len;
   7850 	const char *p = str;
   7851 
   7852 	/* Make sure that output appears in order if stdout and stderr
   7853 	   point to the same place.  For the server case this is taken
   7854 	   care of by the fact that saved_outerr always holds less
   7855 	   than a line.  */
   7856 	fflush (stdout);
   7857 
   7858 	while (to_write > 0)
   7859 	{
   7860 	    written = fwrite (p, 1, to_write, stderr);
   7861 	    if (written == 0)
   7862 		break;
   7863 	    p += written;
   7864 	    to_write -= written;
   7865 	}
   7866     }
   7867 }
   7868 
   7869 
   7870 
   7871 /* Flush stderr.  stderr is normally flushed automatically, of course,
   7872    but this function is used to flush information from the server back
   7873    to the client.  */
   7874 void
   7875 cvs_flusherr (void)
   7876 {
   7877 #ifdef SERVER_SUPPORT
   7878     if (error_use_protocol)
   7879     {
   7880 	/* skip the actual stderr flush in this case since the parent process
   7881 	 * on the server should only be writing to stdout anyhow
   7882 	 */
   7883 	/* Flush what we can to the network, but don't block.  */
   7884 	buf_flush (buf_to_net, 0);
   7885     }
   7886     else if (server_active)
   7887     {
   7888 	/* make sure stderr is flushed before we send the flush count on the
   7889 	 * protocol pipe
   7890 	 */
   7891 	fflush (stderr);
   7892 	/* Send a special count to tell the parent to flush.  */
   7893 	buf_send_special_count (protocol, -2);
   7894     }
   7895     else
   7896 #endif
   7897 	fflush (stderr);
   7898 }
   7899 
   7900 
   7901 
   7902 /* Make it possible for the user to see what has been written to
   7903    stdout (it is up to the implementation to decide exactly how far it
   7904    should go to ensure this).  */
   7905 void
   7906 cvs_flushout (void)
   7907 {
   7908 #ifdef SERVER_SUPPORT
   7909     if (error_use_protocol)
   7910     {
   7911 	/* Flush what we can to the network, but don't block.  */
   7912 	buf_flush (buf_to_net, 0);
   7913     }
   7914     else if (server_active)
   7915     {
   7916 	/* Just do nothing.  This is because the code which
   7917 	   cvs_flushout replaces, setting stdout to line buffering in
   7918 	   main.c, didn't get called in the server child process.  But
   7919 	   in the future it is quite plausible that we'll want to make
   7920 	   this case work analogously to cvs_flusherr.
   7921 
   7922 	   FIXME - DRP - I tried to implement this and triggered the following
   7923 	   error: "Protocol error: uncounted data discarded".  I don't need
   7924 	   this feature right now, so I'm not going to bother with it yet.
   7925 	 */
   7926 	buf_send_special_count (protocol, -1);
   7927     }
   7928     else
   7929 #endif
   7930 	fflush (stdout);
   7931 }
   7932 
   7933 
   7934 
   7935 /* Output TEXT, tagging it according to TAG.  There are lots more
   7936    details about what TAG means in cvsclient.texi but for the simple
   7937    case (e.g. non-client/server), TAG is just "newline" to output a
   7938    newline (in which case TEXT must be NULL), and any other tag to
   7939    output normal text.
   7940 
   7941    Note that there is no way to output either \0 or \n as part of TEXT.  */
   7942 
   7943 void
   7944 cvs_output_tagged (const char *tag, const char *text)
   7945 {
   7946     if (text != NULL && strchr (text, '\n') != NULL)
   7947 	/* Uh oh.  The protocol has no way to cope with this.  For now
   7948 	   we dump core, although that really isn't such a nice
   7949 	   response given that this probably can be caused by newlines
   7950 	   in filenames and other causes other than bugs in CVS.  Note
   7951 	   that we don't want to turn this into "MT newline" because
   7952 	   this case is a newline within a tagged item, not a newline
   7953 	   as extraneous sugar for the user.  */
   7954 	assert (0);
   7955 
   7956     /* Start and end tags don't take any text, per cvsclient.texi.  */
   7957     if (tag[0] == '+' || tag[0] == '-')
   7958 	assert (text == NULL);
   7959 
   7960 #ifdef SERVER_SUPPORT
   7961     if (server_active && supported_response ("MT"))
   7962     {
   7963 	struct buffer *buf;
   7964 
   7965 	if (error_use_protocol)
   7966 	    buf = buf_to_net;
   7967 	else
   7968 	    buf = protocol;
   7969 
   7970 	buf_output0 (buf, "MT ");
   7971 	buf_output0 (buf, tag);
   7972 	if (text != NULL)
   7973 	{
   7974 	    buf_output (buf, " ", 1);
   7975 	    buf_output0 (buf, text);
   7976 	}
   7977 	buf_output (buf, "\n", 1);
   7978 
   7979 	if (!error_use_protocol)
   7980 	    buf_send_counted (protocol);
   7981     }
   7982     else
   7983 #endif /* SERVER_SUPPORT */
   7984     {
   7985 	/* No MT support or we are using a local repository. */
   7986 	if (strcmp (tag, "newline") == 0)
   7987 	    cvs_output ("\n", 1);
   7988 	else if (strcmp (tag, "date") == 0)
   7989 	{
   7990 #ifdef SERVER_SUPPORT
   7991 	    if (server_active)
   7992 		/* Output UTC when running as a server without MT support in
   7993 		 * the client since it is likely to be more meaningful than
   7994 	         * localtime.
   7995 		 */
   7996 		cvs_output (text, 0);
   7997 	    else
   7998 #endif /* SERVER_SUPPORT */
   7999 	    {
   8000 		char *date_in = xstrdup (text);
   8001 		char *date = format_date_alloc (date_in);
   8002 		cvs_output (date, 0);
   8003 		free (date);
   8004 		free (date_in);
   8005 	    }
   8006 	}
   8007 	else if (text != NULL)
   8008 	    cvs_output (text, 0);
   8009     }
   8010 }
   8011 
   8012 
   8013 
   8014 /*
   8015  * void cvs_trace(int level, const char *fmt, ...)
   8016  *
   8017  * Print tracing information to stderr on request.  Levels are implemented
   8018  * as with CVSNT.
   8019  */
   8020 void
   8021 cvs_trace (int level, const char *fmt, ...)
   8022 {
   8023     if (trace >= level)
   8024     {
   8025 	va_list va;
   8026 
   8027 	va_start (va, fmt);
   8028 #ifdef SERVER_SUPPORT
   8029 	fprintf (stderr,"%c -> ",server_active?(isProxyServer()?'P':'S'):' ');
   8030 #else /* ! SERVER_SUPPORT */
   8031 	fprintf (stderr,"  -> ");
   8032 #endif
   8033 	vfprintf (stderr, fmt, va);
   8034 	fprintf (stderr,"\n");
   8035 	va_end (va);
   8036     }
   8037 }
   8038