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