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