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