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