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