Merge branch 'mirbsd'
[alioth/cvs.git] / src / server.c
1 /* This program is free software; you can redistribute it and/or modify
2    it under the terms of the GNU General Public License as published by
3    the Free Software Foundation; either version 2, or (at your option)
4    any later version.
5
6    This program is distributed in the hope that it will be useful,
7    but WITHOUT ANY WARRANTY; without even the implied warranty of
8    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9    GNU General Public License for more details.  */
10
11 #include "cvs.h"
12
13 /* CVS */
14 #include "edit.h"
15 #include "fileattr.h"
16 #include "watch.h"
17
18 /* GNULIB */
19 #include "buffer.h"
20 #include "getline.h"
21 #include "getnline.h"
22
23 int server_active = 0;
24
25 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
26
27 # include "log-buffer.h"
28 # include "ms-buffer.h"
29 #endif  /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */
30
31 #if defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT)
32 # include "canon-host.h"
33 # include "gssapi-client.h"
34
35 /* This stuff isn't included solely with SERVER_SUPPORT since some of these
36  * functions (encryption & the like) get compiled with or without server
37  * support.
38  *
39  * FIXME - They should be in a different file.
40  */
41 /* We use Kerberos 5 routines to map the GSSAPI credential to a user
42    name.  */
43 # include <krb5.h>
44
45 static void gserver_authenticate_connection (void);
46
47 /* Whether we are already wrapping GSSAPI communication.  */
48 static int cvs_gssapi_wrapping;
49
50 #endif  /* defined (HAVE_GSSAPI) && defined (SERVER_SUPPORT) */
51
52 #ifdef SERVER_SUPPORT
53
54 extern char *server_hostname;
55
56 # if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
57 #   include <sys/socket.h>
58 # endif
59
60 # ifdef HAVE_SYSLOG_H
61 #   include <syslog.h>
62 #   ifndef LOG_DAEMON   /* for ancient syslogs */
63 #     define LOG_DAEMON 0
64 #   endif
65 # endif /* HAVE_SYSLOG_H */
66
67 # ifdef HAVE_KERBEROS
68 #   include <netinet/in.h>
69 #   include <krb.h>
70 #   ifndef HAVE_KRB_GET_ERR_TEXT
71 #     define krb_get_err_text(status) krb_err_txt[status]
72 #   endif
73
74 /* Information we need if we are going to use Kerberos encryption.  */
75 static C_Block kblock;
76 static Key_schedule sched;
77
78 # endif /* HAVE_KERBEROS */
79
80 /* for select */
81 # include "xselect.h"
82
83 /* for TCP_NODELAY */
84 # include <netinet/tcp.h>
85
86 # ifndef S_ISSOCK
87 #   define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
88 # endif
89
90 # ifndef O_NONBLOCK
91 #   define O_NONBLOCK O_NDELAY
92 # endif
93
94 /* For initgroups().  */
95 # if HAVE_INITGROUPS
96 #   include <grp.h>
97 # endif /* HAVE_INITGROUPS */
98
99 # ifdef AUTH_SERVER_SUPPORT
100
101 #   ifdef HAVE_GETSPNAM
102 #     include <shadow.h>
103 #   endif
104
105 /* The cvs username sent by the client, which might or might not be
106    the same as the system username the server eventually switches to
107    run as.  CVS_Username gets set iff password authentication is
108    successful. */
109 char *CVS_Username = NULL;
110
111 /* Used to check that same repos is transmitted in pserver auth and in
112    later CVS protocol.  Exported because root.c also uses. */
113 static char *Pserver_Repos = NULL;
114
115 # endif /* AUTH_SERVER_SUPPORT */
116
117 # ifdef HAVE_PAM
118 #   if defined(HAVE_SECURITY_PAM_APPL_H)
119 #     include <security/pam_appl.h>
120 #   elif defined(HAVE_PAM_PAM_APPL_H)
121 #     include <pam/pam_appl.h>
122 #   endif
123
124 static pam_handle_t *pamh = NULL;
125
126 static char *pam_username;
127 static char *pam_password;
128 # endif /* HAVE_PAM */
129
130
131
132 /* While processing requests, this buffer accumulates data to be sent to
133    the client, and then once we are in do_cvs_command, we use it
134    for all the data to be sent.  */
135 static struct buffer *buf_to_net;
136
137 /* This buffer is used to read input from the client.  */
138 static struct buffer *buf_from_net;
139
140
141
142 # ifdef PROXY_SUPPORT
143 /* These are the secondary log buffers so that we can disable them after
144  * creation, when it is determined that they are unneeded, regardless of what
145  * other filters have been prepended to the buffer chain.
146  */
147 static struct buffer *proxy_log;
148 static struct buffer *proxy_log_out;
149
150 /* Set while we are reprocessing a log so that we can avoid sending responses
151  * to some requests twice.
152  */
153 static bool reprocessing;
154 # endif /* PROXY_SUPPORT */
155
156
157
158 /* Arguments storage for `Argument' & `Argumentx' requests.  */
159 static int argument_count;
160 static char **argument_vector;
161 static int argument_vector_size;
162
163 /*
164  * This is where we stash stuff we are going to use.  Format string
165  * which expects a single directory within it, starting with a slash.
166  */
167 static char *server_temp_dir;
168
169 /* This is the original value of server_temp_dir, before any possible
170    changes inserted by serve_max_dotdot.  */
171 static char *orig_server_temp_dir;
172
173 /* Nonzero if we should keep the temp directory around after we exit.  */
174 static int dont_delete_temp;
175
176 static void server_write_entries (void);
177
178 cvsroot_t *referrer;
179
180
181
182 /* Populate all of the directories between BASE_DIR and its relative
183    subdirectory DIR with CVSADM directories.  Return 0 for success or
184    errno value.  */
185 static int
186 create_adm_p (char *base_dir, char *dir)
187 {
188     char *dir_where_cvsadm_lives, *dir_to_register, *p, *tmp;
189     int retval, done;
190     FILE *f;
191
192     if (strcmp (dir, ".") == 0)
193         return 0;                       /* nothing to do */
194
195     /* Allocate some space for our directory-munging string. */
196     p = xmalloc (strlen (dir) + 1);
197     if (p == NULL)
198         return ENOMEM;
199
200     dir_where_cvsadm_lives = xmalloc (strlen (base_dir) + strlen (dir) + 100);
201     if (dir_where_cvsadm_lives == NULL)
202     {
203         free (p);
204         return ENOMEM;
205     }
206
207     /* Allocate some space for the temporary string in which we will
208        construct filenames. */
209     tmp = xmalloc (strlen (base_dir) + strlen (dir) + 100);
210     if (tmp == NULL)
211     {
212         free (p);
213         free (dir_where_cvsadm_lives);
214         return ENOMEM;
215     }
216
217
218     /* We make several passes through this loop.  On the first pass,
219        we simply create the CVSADM directory in the deepest directory.
220        For each subsequent pass, we try to remove the last path
221        element from DIR, create the CVSADM directory in the remaining
222        pathname, and register the subdirectory in the newly created
223        CVSADM directory. */
224
225     retval = done = 0;
226
227     strcpy (p, dir);
228     strcpy (dir_where_cvsadm_lives, base_dir);
229     strcat (dir_where_cvsadm_lives, "/");
230     strcat (dir_where_cvsadm_lives, p);
231     dir_to_register = NULL;
232
233     while (1)
234     {
235         /* Create CVSADM. */
236         (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM);
237         if ((CVS_MKDIR (tmp, 0777) < 0) && (errno != EEXIST))
238         {
239             retval = errno;
240             goto finish;
241         }
242
243         /* Create CVSADM_REP. */
244         (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_REP);
245         if (! isfile (tmp))
246         {
247             /* Use Emptydir as the placeholder until the client sends
248                us the real value.  This code is similar to checkout.c
249                (emptydir_name), but the code below returns errors
250                differently.  */
251
252             char *empty;
253             empty = xmalloc (strlen (current_parsed_root->directory)
254                             + sizeof (CVSROOTADM)
255                             + sizeof (CVSNULLREPOS)
256                             + 3);
257             if (! empty)
258             {
259                 retval = ENOMEM;
260                 goto finish;
261             }
262
263             /* Create the directory name. */
264             (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory,
265                             CVSROOTADM, CVSNULLREPOS);
266
267             /* Create the directory if it doesn't exist. */
268             if (! isfile (empty))
269             {
270                 mode_t omask;
271                 omask = umask (cvsumask);
272                 if (CVS_MKDIR (empty, 0777) < 0)
273                 {
274                     retval = errno;
275                     free (empty);
276                     goto finish;
277                 }
278                 (void) umask (omask);
279             }
280
281             f = CVS_FOPEN (tmp, "w");
282             if (f == NULL)
283             {
284                 retval = errno;
285                 free (empty);
286                 goto finish;
287             }
288             /* Write the directory name to CVSADM_REP. */
289             if (fprintf (f, "%s\n", empty) < 0)
290             {
291                 retval = errno;
292                 fclose (f);
293                 free (empty);
294                 goto finish;
295             }
296             if (fclose (f) == EOF)
297             {
298                 retval = errno;
299                 free (empty);
300                 goto finish;
301             }
302
303             /* Clean up after ourselves. */
304             free (empty);
305         }
306
307         /* Create CVSADM_ENT.  We open in append mode because we
308            don't want to clobber an existing Entries file.  */
309         (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_ENT);
310         f = CVS_FOPEN (tmp, "a");
311         if (f == NULL)
312         {
313             retval = errno;
314             goto finish;
315         }
316         if (fclose (f) == EOF)
317         {
318             retval = errno;
319             goto finish;
320         }
321
322         if (dir_to_register != NULL)
323         {
324             /* FIXME: Yes, this results in duplicate entries in the
325                Entries.Log file, but it doesn't currently matter.  We
326                might need to change this later on to make sure that we
327                only write one entry.  */
328
329             Subdir_Register (NULL, dir_where_cvsadm_lives, dir_to_register);
330         }
331
332         if (done)
333             break;
334
335         dir_to_register = strrchr (p, '/');
336         if (dir_to_register == NULL)
337         {
338             dir_to_register = p;
339             strcpy (dir_where_cvsadm_lives, base_dir);
340             done = 1;
341         }
342         else
343         {
344             *dir_to_register = '\0';
345             dir_to_register++;
346             strcpy (dir_where_cvsadm_lives, base_dir);
347             strcat (dir_where_cvsadm_lives, "/");
348             strcat (dir_where_cvsadm_lives, p);
349         }
350     }
351
352   finish:
353     free (tmp);
354     free (dir_where_cvsadm_lives);
355     free (p);
356     return retval;
357 }
358
359
360
361 /*
362  * Make directory DIR, including all intermediate directories if necessary.
363  * Returns 0 for success or errno code.
364  */
365 static int
366 mkdir_p (char *dir)
367 {
368     char *p;
369     char *q = xmalloc (strlen (dir) + 1);
370     int retval;
371
372     if (q == NULL)
373         return ENOMEM;
374
375     retval = 0;
376
377     /*
378      * Skip over leading slash if present.  We won't bother to try to
379      * make '/'.
380      */
381     p = dir + 1;
382     while (1)
383     {
384         while (*p != '/' && *p != '\0')
385             ++p;
386         if (*p == '/')
387         {
388             strncpy (q, dir, p - dir);
389             q[p - dir] = '\0';
390             if (q[p - dir - 1] != '/'  &&  CVS_MKDIR (q, 0777) < 0)
391             {
392                 int saved_errno = errno;
393
394                 if (saved_errno != EEXIST
395                     && ((saved_errno != EACCES && saved_errno != EROFS)
396                         || !isdir (q)))
397                 {
398                     retval = saved_errno;
399                     goto done;
400                 }
401             }
402             ++p;
403         }
404         else
405         {
406             if (CVS_MKDIR (dir, 0777) < 0)
407                 retval = errno;
408             goto done;
409         }
410     }
411   done:
412     free (q);
413     return retval;
414 }
415
416
417
418 /*
419  * Print the error response for error code STATUS.  The caller is
420  * reponsible for making sure we get back to the command loop without
421  * any further output occuring.
422  * Must be called only in contexts where it is OK to send output.
423  */
424 static void
425 print_error (int status)
426 {
427     char *msg;
428     char tmpstr[80];
429
430     buf_output0 (buf_to_net, "error  ");
431     msg = strerror (status);
432     if (msg == NULL)
433     {
434        sprintf (tmpstr, "unknown error %d", status);
435        msg = tmpstr;
436     }
437     buf_output0 (buf_to_net, msg);
438     buf_append_char (buf_to_net, '\n');
439
440     buf_flush (buf_to_net, 0);
441 }
442
443
444
445 static int pending_error;
446 /*
447  * Malloc'd text for pending error.  Each line must start with "E ".  The
448  * last line should not end with a newline.
449  */
450 static char *pending_error_text;
451 static char *pending_warning_text;
452
453 /* If an error is pending, print it and return 1.  If not, return 0.
454    Also prints pending warnings, but this does not affect the return value.
455    Must be called only in contexts where it is OK to send output.  */
456 static int
457 print_pending_error (void)
458 {
459     /* Check this case first since it usually means we are out of memory and
460      * the buffer output routines might try and allocate memory.
461      */
462     if (!pending_error_text && pending_error)
463     {
464         print_error (pending_error);
465         pending_error = 0;
466         return 1;
467     }
468
469     if (pending_warning_text)
470     {
471         buf_output0 (buf_to_net, pending_warning_text);
472         buf_append_char (buf_to_net, '\n');
473         buf_flush (buf_to_net, 0);
474
475         free (pending_warning_text);
476         pending_warning_text = NULL;
477     }
478
479     if (pending_error_text)
480     {
481         buf_output0 (buf_to_net, pending_error_text);
482         buf_append_char (buf_to_net, '\n');
483         if (pending_error)
484             print_error (pending_error);
485         else
486             buf_output0 (buf_to_net, "error  \n");
487
488         buf_flush (buf_to_net, 0);
489
490         pending_error = 0;
491         free (pending_error_text);
492         pending_error_text = NULL;
493         return 1;
494     }
495
496     return 0;
497 }
498
499
500
501 /* Is an error pending?  */
502 # define error_pending() (pending_error || pending_error_text)
503 # define warning_pending() (pending_warning_text)
504
505 /* Allocate SIZE bytes for pending_error_text and return nonzero
506    if we could do it.  */
507 static inline int
508 alloc_pending_internal (char **dest, size_t size)
509 {
510     *dest = malloc (size);
511     if (!*dest)
512     {
513         pending_error = ENOMEM;
514         return 0;
515     }
516     return 1;
517 }
518
519
520
521 /* Allocate SIZE bytes for pending_error_text and return nonzero
522    if we could do it.  */
523 static int
524 alloc_pending (size_t size)
525 {
526     if (error_pending ())
527         /* Probably alloc_pending callers will have already checked for
528            this case.  But we might as well handle it if they don't, I
529            guess.  */
530         return 0;
531     return alloc_pending_internal (&pending_error_text, size);
532 }
533
534
535
536 /* Allocate SIZE bytes for pending_error_text and return nonzero
537    if we could do it.  */
538 static int
539 alloc_pending_warning (size_t size)
540 {
541     if (warning_pending ())
542         /* Warnings can be lost here.  */
543         return 0;
544     return alloc_pending_internal (&pending_warning_text, size);
545 }
546
547
548
549 static int
550 supported_response (char *name)
551 {
552     struct response *rs;
553
554     for (rs = responses; rs->name != NULL; ++rs)
555         if (strcmp (rs->name, name) == 0)
556             return rs->status == rs_supported;
557     error (1, 0, "internal error: testing support for unknown response?");
558     /* NOTREACHED */
559     return 0;
560 }
561
562
563
564 /*
565  * Return true if we need to relay write requests to a primary server
566  * and false otherwise.
567  *
568  * NOTES
569  *
570  *   - primarily handles :ext: method as this seems most likely to be used in
571  *     practice.
572  *
573  *   - :fork: method is handled for testing.
574  *
575  *   - Could handle pserver too, but would have to store the password
576  *     the client sent us.
577  *
578  *
579  * GLOBALS
580  *   config->PrimaryServer
581  *                        The parsed setting from CVSROOT/config, if any, or
582  *                        NULL, otherwise.
583  *   current_parsed_root  The current repository.
584  *
585  * RETURNS
586  *   true                 If this server is configured as a secondary server.
587  *   false                Otherwise.
588  */
589 static inline bool
590 isProxyServer (void)
591 {
592     assert (current_parsed_root);
593
594     /***
595      *** The following is done as a series of if/return combinations an an
596      *** optimization.
597      ***/
598
599     /* If there is no primary server defined in CVSROOT/config, then we can't
600      * be a secondary.
601      */
602     if (!config || !config->PrimaryServer) return false;
603
604     /* The directory must not match for all methods.  */
605     if (!isSamePath (config->PrimaryServer->directory,
606                      current_parsed_root->directory))
607         return true;
608
609     /* Only the directory is important for fork.  */
610     if (config->PrimaryServer->method == fork_method)
611         return false;
612
613     /* Must be :ext: method, then.  This is enforced when CVSROOT/config is
614      * parsed.
615      */
616     assert (config->PrimaryServer->isremote);
617
618     if (isThisHost (config->PrimaryServer->hostname))
619         return false;
620
621     return true;
622 }
623
624
625
626 static void
627 serve_valid_responses (char *arg)
628 {
629     char *p = arg;
630     char *q;
631     struct response *rs;
632
633 # ifdef PROXY_SUPPORT
634     /* Process this in the first pass since the data it gathers can be used
635      * prior to a `Root' request.
636      */
637     if (reprocessing) return;
638 # endif /* PROXY_SUPPORT */
639
640     do
641     {
642         q = strchr (p, ' ');
643         if (q != NULL)
644             *q++ = '\0';
645         for (rs = responses; rs->name != NULL; ++rs)
646         {
647             if (strcmp (rs->name, p) == 0)
648                 break;
649         }
650         if (rs->name == NULL)
651             /*
652              * It is a response we have never heard of (and thus never
653              * will want to use).  So don't worry about it.
654              */
655             ;
656         else
657             rs->status = rs_supported;
658         p = q;
659     } while (q != NULL);
660     for (rs = responses; rs->name != NULL; ++rs)
661     {
662         if (rs->status == rs_essential)
663         {
664             buf_output0 (buf_to_net, "E response `");
665             buf_output0 (buf_to_net, rs->name);
666             buf_output0 (buf_to_net, "' not supported by client\nerror  \n");
667
668             /* FIXME: This call to buf_flush could conceivably
669                cause deadlock, as noted in server_cleanup.  */
670             buf_flush (buf_to_net, 1);
671
672             exit (EXIT_FAILURE);
673         }
674         else if (rs->status == rs_optional)
675             rs->status = rs_not_supported;
676     }
677 }
678
679
680
681 /*
682  * Process IDs of the subprocess, or negative if that subprocess
683  * does not exist.
684  */
685 static pid_t command_pid;
686
687 static void
688 outbuf_memory_error (struct buffer *buf)
689 {
690     static const char msg[] = "E Fatal server error\n\
691 error ENOMEM Virtual memory exhausted.\n";
692     if (command_pid > 0)
693         kill (command_pid, SIGTERM);
694
695     /*
696      * We have arranged things so that printing this now either will
697      * be valid, or the "E fatal error" line will get glommed onto the
698      * end of an existing "E" or "M" response.
699      */
700
701     /* If this gives an error, not much we could do.  syslog() it?  */
702     write (STDOUT_FILENO, msg, sizeof (msg) - 1);
703 # ifdef HAVE_SYSLOG_H
704     syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted");
705 # endif /* HAVE_SYSLOG_H */
706     exit (EXIT_FAILURE);
707 }
708
709
710
711 static void
712 input_memory_error (struct buffer *buf)
713 {
714     outbuf_memory_error (buf);
715 }
716
717
718
719 # ifdef PROXY_SUPPORT
720 /* This function rewinds the net connection using the write proxy log file.
721  *
722  * GLOBALS
723  *   proxy_log  The buffer object containing the write proxy log.
724  *
725  * RETURNS
726  *   Nothing.
727  */
728 static void
729 rewind_buf_from_net (void)
730 {
731     struct buffer *log;
732
733     assert (proxy_log);
734
735     /* Free the arguments since we processed some of them in the first pass.
736      */
737     {
738         /* argument_vector[0] is a dummy argument, we don't mess with
739          * it.
740          */
741         char **cp;
742         for (cp = argument_vector + 1;
743              cp < argument_vector + argument_count;
744              ++cp)
745             free (*cp);
746
747         argument_count = 1;
748     }
749
750     log = log_buffer_rewind (proxy_log);
751     proxy_log = NULL;
752     /* Dispose of any read but unused data in the net buffer since it will
753      * already be in the log.
754      */
755     buf_free_data (buf_from_net);
756     buf_from_net = ms_buffer_initialize (outbuf_memory_error, log,
757                                          buf_from_net);
758     reprocessing = true;
759 }
760 # endif /* PROXY_SUPPORT */
761
762
763
764 char *gConfigPath;
765
766
767
768 /*
769  * This request cannot be ignored by a potential secondary since it is used to
770  * determine if we _are_ a secondary.
771  */
772 static void
773 serve_root (char *arg)
774 {
775     char *path;
776
777     TRACE (TRACE_FUNCTION, "serve_root (%s)", arg ? arg : "(null)");
778
779     /* Don't process this twice or when errors are pending.  */
780     if (error_pending()
781 # ifdef PROXY_SUPPORT
782         || reprocessing
783 # endif /* PROXY_SUPPORT */
784        ) return;
785
786     if (!ISABSOLUTE (arg))
787     {
788         if (alloc_pending (80 + strlen (arg)))
789             sprintf (pending_error_text,
790                      "E Root %s must be an absolute pathname", arg);
791         return;
792     }
793
794     /* Sending "Root" twice is invalid.
795
796        The other way to handle a duplicate Root requests would be as a
797        request to clear out all state and start over as if it was a
798        new connection.  Doing this would cause interoperability
799        headaches, so it should be a different request, if there is
800        any reason why such a feature is needed.  */
801     if (current_parsed_root != NULL)
802     {
803         if (alloc_pending (80 + strlen (arg)))
804             sprintf (pending_error_text,
805                      "E Protocol error: Duplicate Root request, for %s", arg);
806         return;
807     }
808
809     /* Set original_parsed_root here, not because it can be changed in the
810      * client Redirect sense, but so we don't have to switch in code that
811      * runs in both modes to decide which to print.
812      */
813     original_parsed_root = current_parsed_root = local_cvsroot (arg);
814
815 # ifdef AUTH_SERVER_SUPPORT
816     if (Pserver_Repos != NULL)
817     {
818         if (strcmp (Pserver_Repos, current_parsed_root->directory) != 0)
819         {
820             if (alloc_pending (80 + strlen (Pserver_Repos)
821                                + strlen (current_parsed_root->directory)))
822                 /* The explicitness is to aid people who are writing clients.
823                    I don't see how this information could help an
824                    attacker.  */
825                 sprintf (pending_error_text, "\
826 E Protocol error: Root says \"%s\" but pserver says \"%s\"",
827                          current_parsed_root->directory, Pserver_Repos);
828             return;
829         }
830     }
831 # endif
832
833     if (root_allow_used() && !root_allow_ok(arg))
834     {
835         if (alloc_pending (80 + strlen (arg)))
836             sprintf (pending_error_text,
837                      "E Bad root %s", arg);
838         return;
839     }
840
841     /* For pserver, this will already have happened, and the call will do
842        nothing.  But for rsh, we need to do it now.  */
843     config = get_root_allow_config (current_parsed_root->directory,
844                                     gConfigPath);
845
846 # ifdef PROXY_SUPPORT
847     /* At this point we have enough information to determine if we are a
848      * secondary server or not.
849      */
850     if (proxy_log && !isProxyServer ())
851     {
852         /* Else we are not a secondary server.  There is no point in
853          * reprocessing since we handle all the requests we can receive
854          * before `Root' as we receive them.  But close the logs.
855          */
856         log_buffer_closelog (proxy_log);
857         log_buffer_closelog (proxy_log_out);
858         proxy_log = NULL;
859         /*
860          * Don't need this.  We assume it when proxy_log == NULL.
861          *
862          *   proxy_log_out = NULL;
863          */
864     }
865 # endif /* PROXY_SUPPORT */
866
867     /* Now set the TMPDIR environment variable.  If it was set in the config
868      * file, we now know it.
869      */
870     push_env_temp_dir ();
871
872     /* OK, now figure out where we stash our temporary files.  */
873     {
874         char *p;
875
876         /* The code which wants to chdir into server_temp_dir is not set
877          * up to deal with it being a relative path.  So give an error
878          * for that case.
879          */
880         if (!ISABSOLUTE (get_cvs_tmp_dir ()))
881         {
882             if (alloc_pending (80 + strlen (get_cvs_tmp_dir ())))
883                 sprintf (pending_error_text,
884                          "E Value of %s for TMPDIR is not absolute",
885                          get_cvs_tmp_dir ());
886
887             /* FIXME: we would like this error to be persistent, that
888              * is, not cleared by print_pending_error.  The current client
889              * will exit as soon as it gets an error, but the protocol spec
890              * does not require a client to do so.
891              */
892         }
893         else
894         {
895             int status;
896             int i = 0;
897
898             server_temp_dir = xmalloc (strlen (get_cvs_tmp_dir ()) + 80);
899             if (!server_temp_dir)
900             {
901                 /* Strictly speaking, we're not supposed to output anything
902                  * now.  But we're about to exit(), give it a try.
903                  */
904                 printf ("E Fatal server error, aborting.\n\
905 error ENOMEM Virtual memory exhausted.\n");
906
907                 exit (EXIT_FAILURE);
908             }
909             strcpy (server_temp_dir, get_cvs_tmp_dir ());
910
911             /* Remove a trailing slash from TMPDIR if present.  */
912             p = server_temp_dir + strlen (server_temp_dir) - 1;
913             if (*p == '/')
914                 *p = '\0';
915
916             /* I wanted to use cvs-serv/PID, but then you have to worry about
917              * the permissions on the cvs-serv directory being right.  So
918              * use cvs-servPID.
919              */
920             strcat (server_temp_dir, "/cvs-serv");
921
922             p = server_temp_dir + strlen (server_temp_dir);
923             sprintf (p, "%ld", (long) getpid ());
924
925             orig_server_temp_dir = server_temp_dir;
926
927             /* Create the temporary directory, and set the mode to
928              * 700, to discourage random people from tampering with
929              * it.
930              */
931             while ((status = mkdir_p (server_temp_dir)) == EEXIST)
932             {
933                 static const char suffix[] = "abcdefghijklmnopqrstuvwxyz";
934
935                 if (i >= sizeof suffix - 1) break;
936                 if (i == 0) p = server_temp_dir + strlen (server_temp_dir);
937                 p[0] = suffix[i++];
938                 p[1] = '\0';
939             }
940             if (status)
941             {
942                 if (alloc_pending (80 + strlen (server_temp_dir)))
943                     sprintf (pending_error_text,
944                             "E can't create temporary directory %s",
945                             server_temp_dir);
946                 pending_error = status;
947             }
948 #ifndef CHMOD_BROKEN
949             else if (chmod (server_temp_dir, S_IRWXU) < 0)
950             {
951                 int save_errno = errno;
952                 if (alloc_pending (80 + strlen (server_temp_dir)))
953                     sprintf (pending_error_text,
954 "E cannot change permissions on temporary directory %s",
955                              server_temp_dir);
956                 pending_error = save_errno;
957             }
958 #endif
959             else if (CVS_CHDIR (server_temp_dir) < 0)
960             {
961                 int save_errno = errno;
962                 if (alloc_pending (80 + strlen (server_temp_dir)))
963                     sprintf (pending_error_text,
964 "E cannot change to temporary directory %s",
965                              server_temp_dir);
966                 pending_error = save_errno;
967             }
968         }
969     }
970
971     /* Now that we have a config, verify our compression level.  Since 
972      * most clients do not send Gzip-stream requests until after the root
973      * request, wait until the first request following Root to verify that
974      * compression is being used when level 0 is not allowed.
975      */
976     if (gzip_level)
977     {
978         bool forced = false;
979
980         if (gzip_level < config->MinCompressionLevel)
981         {
982             gzip_level = config->MinCompressionLevel;
983             forced = true;
984         }
985
986         if (gzip_level > config->MaxCompressionLevel)
987         {
988             gzip_level = config->MaxCompressionLevel;
989             forced = true;
990         }
991
992         if (forced && !quiet
993             && alloc_pending_warning (120 + strlen (program_name)))
994             sprintf (pending_warning_text,
995 "E %s server: Forcing compression level %d (allowed: %d <= z <= %d).",
996                      program_name, gzip_level, config->MinCompressionLevel,
997                      config->MaxCompressionLevel);
998     }
999
1000     path = xmalloc (strlen (current_parsed_root->directory)
1001                    + sizeof (CVSROOTADM)
1002                    + 2);
1003     if (path == NULL)
1004     {
1005         pending_error = ENOMEM;
1006         return;
1007     }
1008     (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM);
1009     if (!isaccessible (path, R_OK | X_OK))
1010     {
1011         int save_errno = errno;
1012         if (alloc_pending (80 + strlen (path)))
1013             sprintf (pending_error_text, "E Cannot access %s", path);
1014         pending_error = save_errno;
1015     }
1016     free (path);
1017
1018     setenv (CVSROOT_ENV, current_parsed_root->directory, 1);
1019 }
1020
1021
1022
1023 static int max_dotdot_limit = 0;
1024
1025 /* Is this pathname OK to recurse into when we are running as the server?
1026    If not, call error() with a fatal error.  */
1027 void
1028 server_pathname_check (char *path)
1029 {
1030     TRACE (TRACE_FUNCTION, "server_pathname_check (%s)",
1031            path ? path : "(null)");
1032
1033     /* An absolute pathname is almost surely a path on the *client* machine,
1034        and is unlikely to do us any good here.  It also is probably capable
1035        of being a security hole in the anonymous readonly case.  */
1036     if (ISABSOLUTE (path))
1037         /* Giving an error is actually kind of a cop-out, in the sense
1038            that it would be nice for "cvs co -d /foo/bar/baz" to work.
1039            A quick fix in the server would be requiring Max-dotdot of
1040            at least one if pathnames are absolute, and then putting
1041            /abs/foo/bar/baz in the temp dir beside the /d/d/d stuff.
1042            A cleaner fix in the server might be to decouple the
1043            pathnames we pass back to the client from pathnames in our
1044            temp directory (this would also probably remove the need
1045            for Max-dotdot).  A fix in the client would have the client
1046            turn it into "cd /foo/bar; cvs co -d baz" (more or less).
1047            This probably has some problems with pathnames which appear
1048            in messages.  */
1049         error ( 1, 0,
1050                 "absolute pathnames invalid for server (specified `%s')",
1051                 path );
1052     if (pathname_levels (path) > max_dotdot_limit)
1053     {
1054         /* Similar to the ISABSOLUTE case in security implications.  */
1055         error (0, 0, "protocol error: `%s' contains more leading ..", path);
1056         error (1, 0, "than the %d which Max-dotdot specified",
1057                max_dotdot_limit);
1058     }
1059 }
1060
1061
1062
1063 /* Is file or directory REPOS an absolute pathname within the
1064    current_parsed_root->directory?  If yes, return 0.  If no, set pending_error
1065    and return 1.  */
1066 static int
1067 outside_root (char *repos)
1068 {
1069     size_t repos_len = strlen (repos);
1070     size_t root_len = strlen (current_parsed_root->directory);
1071
1072     /* ISABSOLUTE (repos) should always be true, but
1073        this is a good security precaution regardless. -DRP
1074      */
1075     if (!ISABSOLUTE (repos))
1076     {
1077         if (alloc_pending (repos_len + 80))
1078             sprintf (pending_error_text, "\
1079 E protocol error: %s is not absolute", repos);
1080         return 1;
1081     }
1082
1083     if (repos_len < root_len
1084         || strncmp (current_parsed_root->directory, repos, root_len) != 0)
1085     {
1086     not_within:
1087         if (alloc_pending (strlen (current_parsed_root->directory)
1088                            + strlen (repos)
1089                            + 80))
1090             sprintf (pending_error_text, "\
1091 E protocol error: directory '%s' not within root '%s'",
1092                      repos, current_parsed_root->directory);
1093         return 1;
1094     }
1095     if (repos_len > root_len)
1096     {
1097         if (repos[root_len] != '/')
1098             goto not_within;
1099         if (pathname_levels (repos + root_len + 1) > 0)
1100             goto not_within;
1101     }
1102     return 0;
1103 }
1104
1105
1106
1107 /* Is file or directory FILE outside the current directory (that is, does
1108    it contain '/')?  If no, return 0.  If yes, set pending_error
1109    and return 1.  */
1110 static int
1111 outside_dir (char *file)
1112 {
1113     if (strchr (file, '/') != NULL)
1114     {
1115         if (alloc_pending (strlen (file)
1116                            + 80))
1117             sprintf (pending_error_text, "\
1118 E protocol error: directory '%s' not within current directory",
1119                      file);
1120         return 1;
1121     }
1122     return 0;
1123 }
1124
1125
1126
1127 /*
1128  * Add as many directories to the temp directory as the client tells us it
1129  * will use "..", so we never try to access something outside the temp
1130  * directory via "..".
1131  */
1132 static void
1133 serve_max_dotdot (char *arg)
1134 {
1135     int lim = atoi (arg);
1136     int i;
1137     char *p;
1138
1139 #ifdef PROXY_SUPPORT
1140     if (proxy_log) return;
1141 #endif /* PROXY_SUPPORT */
1142
1143     if (lim < 0 || lim > 10000)
1144         return;
1145     p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10);
1146     if (p == NULL)
1147     {
1148         pending_error = ENOMEM;
1149         return;
1150     }
1151     strcpy (p, server_temp_dir);
1152     for (i = 0; i < lim; ++i)
1153         strcat (p, "/d");
1154     if (server_temp_dir != orig_server_temp_dir)
1155         free (server_temp_dir);
1156     server_temp_dir = p;
1157     max_dotdot_limit = lim;
1158 }
1159
1160
1161
1162 static char *gDirname;
1163 static char *gupdate_dir;
1164
1165 static void
1166 dirswitch (char *dir, char *repos)
1167 {
1168     int status;
1169     FILE *f;
1170     size_t dir_len;
1171
1172     TRACE (TRACE_FUNCTION, "dirswitch (%s, %s)", dir ? dir : "(null)",
1173            repos ? repos : "(null)");
1174
1175     server_write_entries ();
1176
1177     if (error_pending()) return;
1178
1179     /* Check for bad directory name.
1180
1181        FIXME: could/should unify these checks with server_pathname_check
1182        except they need to report errors differently.  */
1183     if (ISABSOLUTE (dir))
1184     {
1185         if (alloc_pending (80 + strlen (dir)))
1186             sprintf ( pending_error_text,
1187                       "E absolute pathnames invalid for server (specified `%s')",
1188                       dir);
1189         return;
1190     }
1191     if (pathname_levels (dir) > max_dotdot_limit)
1192     {
1193         if (alloc_pending (80 + strlen (dir)))
1194             sprintf (pending_error_text,
1195                      "E protocol error: `%s' has too many ..", dir);
1196         return;
1197     }
1198
1199     dir_len = strlen (dir);
1200
1201     /* Check for a trailing '/'.  This is not ISSLASH because \ in the
1202        protocol is an ordinary character, not a directory separator (of
1203        course, it is perhaps unwise to use it in directory names, but that
1204        is another issue).  */
1205     if (dir_len > 0
1206         && dir[dir_len - 1] == '/')
1207     {
1208         if (alloc_pending (80 + dir_len))
1209             sprintf (pending_error_text,
1210                      "E protocol error: invalid directory syntax in %s", dir);
1211         return;
1212     }
1213
1214     if (gDirname != NULL)
1215         free (gDirname);
1216     if (gupdate_dir != NULL)
1217         free (gupdate_dir);
1218
1219     if (!strcmp (dir, "."))
1220         gupdate_dir = xstrdup ("");
1221     else
1222         gupdate_dir = xstrdup (dir);
1223
1224     gDirname = xmalloc (strlen (server_temp_dir) + dir_len + 40);
1225     if (gDirname == NULL)
1226     {
1227         pending_error = ENOMEM;
1228         return;
1229     }
1230
1231     strcpy (gDirname, server_temp_dir);
1232     strcat (gDirname, "/");
1233     strcat (gDirname, dir);
1234
1235     status = mkdir_p (gDirname);
1236     if (status != 0
1237         && status != EEXIST)
1238     {
1239         if (alloc_pending (80 + strlen (gDirname)))
1240             sprintf (pending_error_text, "E cannot mkdir %s", gDirname);
1241         pending_error = status;
1242         return;
1243     }
1244
1245     /* We need to create adm directories in all path elements because
1246        we want the server to descend them, even if the client hasn't
1247        sent the appropriate "Argument xxx" command to match the
1248        already-sent "Directory xxx" command.  See recurse.c
1249        (start_recursion) for a big discussion of this.  */
1250
1251     status = create_adm_p (server_temp_dir, dir);
1252     if (status != 0)
1253     {
1254         if (alloc_pending (80 + strlen (gDirname)))
1255             sprintf (pending_error_text, "E cannot create_adm_p %s", gDirname);
1256         pending_error = status;
1257         return;
1258     }
1259
1260     if ( CVS_CHDIR (gDirname) < 0)
1261     {
1262         int save_errno = errno;
1263         if (alloc_pending (80 + strlen (gDirname)))
1264             sprintf (pending_error_text, "E cannot change to %s", gDirname);
1265         pending_error = save_errno;
1266         return;
1267     }
1268     /*
1269      * This is pretty much like calling Create_Admin, but Create_Admin doesn't
1270      * report errors in the right way for us.
1271      */
1272     if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST))
1273     {
1274         int save_errno = errno;
1275         if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM)))
1276             sprintf (pending_error_text,
1277                      "E cannot mkdir %s/%s", gDirname, CVSADM);
1278         pending_error = save_errno;
1279         return;
1280     }
1281
1282     /* The following will overwrite the contents of CVSADM_REP.  This
1283        is the correct behavior -- mkdir_p may have written a
1284        placeholder value to this file and we need to insert the
1285        correct value. */
1286
1287     f = CVS_FOPEN (CVSADM_REP, "w");
1288     if (f == NULL)
1289     {
1290         int save_errno = errno;
1291         if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
1292             sprintf (pending_error_text,
1293                      "E cannot open %s/%s", gDirname, CVSADM_REP);
1294         pending_error = save_errno;
1295         return;
1296     }
1297     if (fprintf (f, "%s", repos) < 0)
1298     {
1299         int save_errno = errno;
1300         if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
1301             sprintf (pending_error_text,
1302                      "E error writing %s/%s", gDirname, CVSADM_REP);
1303         pending_error = save_errno;
1304         fclose (f);
1305         return;
1306     }
1307     /* Non-remote CVS handles a module representing the entire tree
1308        (e.g., an entry like ``world -a .'') by putting /. at the end
1309        of the Repository file, so we do the same.  */
1310     if (strcmp (dir, ".") == 0
1311         && current_parsed_root != NULL
1312         && current_parsed_root->directory != NULL
1313         && strcmp (current_parsed_root->directory, repos) == 0)
1314     {
1315         if (fprintf (f, "/.") < 0)
1316         {
1317             int save_errno = errno;
1318             if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
1319                 sprintf (pending_error_text,
1320                          "E error writing %s/%s", gDirname, CVSADM_REP);
1321             pending_error = save_errno;
1322             fclose (f);
1323             return;
1324         }
1325     }
1326     if (fprintf (f, "\n") < 0)
1327     {
1328         int save_errno = errno;
1329         if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
1330             sprintf (pending_error_text,
1331                      "E error writing %s/%s", gDirname, CVSADM_REP);
1332         pending_error = save_errno;
1333         fclose (f);
1334         return;
1335     }
1336     if (fclose (f) == EOF)
1337     {
1338         int save_errno = errno;
1339         if (alloc_pending (80 + strlen (gDirname) + strlen (CVSADM_REP)))
1340             sprintf (pending_error_text,
1341                      "E error closing %s/%s", gDirname, CVSADM_REP);
1342         pending_error = save_errno;
1343         return;
1344     }
1345     /* We open in append mode because we don't want to clobber an
1346        existing Entries file.  */
1347     f = CVS_FOPEN (CVSADM_ENT, "a");
1348     if (f == NULL)
1349     {
1350         int save_errno = errno;
1351         if (alloc_pending (80 + strlen (CVSADM_ENT)))
1352             sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
1353         pending_error = save_errno;
1354         return;
1355     }
1356     if (fclose (f) == EOF)
1357     {
1358         int save_errno = errno;
1359         if (alloc_pending (80 + strlen (CVSADM_ENT)))
1360             sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
1361         pending_error = save_errno;
1362         return;
1363     }
1364 }
1365
1366
1367
1368 static void
1369 serve_repository (char *arg)
1370 {
1371 # ifdef PROXY_SUPPORT
1372     assert (!proxy_log);
1373 # endif /* PROXY_SUPPORT */
1374
1375     if (alloc_pending (80))
1376         strcpy (pending_error_text,
1377                 "E Repository request is obsolete; aborted");
1378     return;
1379 }
1380
1381
1382
1383 static void
1384 serve_directory (char *arg)
1385 {
1386     int status;
1387     char *repos;
1388
1389     TRACE (TRACE_FUNCTION, "serve_directory (%s)", arg ? arg : "(null)");
1390
1391
1392     /* The data needs to be read into the secondary log regardless, but
1393      * processing of anything other than errors is skipped until later.
1394      */
1395     status = buf_read_line (buf_from_net, &repos, NULL);
1396     if (status == 0)
1397     {
1398         if (!ISABSOLUTE (repos))
1399         {
1400             /* Make absolute.
1401              *
1402              * FIXME: This is kinda hacky - we should probably only ever store
1403              * and pass SHORT_REPOS (perhaps with the occassional exception
1404              * for optimizations, but many, many functions end up
1405              * deconstructing REPOS to gain SHORT_REPOS anyhow) - the
1406              * CVSROOT portion of REPOS is redundant with
1407              * current_parsed_root->directory - but since this is the way
1408              * things have always been done, changing this will likely involve
1409              * a major overhaul.
1410              */
1411             char *short_repos;
1412
1413             short_repos = repos;
1414             repos = Xasprintf ("%s/%s",
1415                               current_parsed_root->directory, short_repos);
1416             free (short_repos);
1417         }
1418         else
1419             repos = xstrdup (primary_root_translate (repos));
1420
1421         if (
1422 # ifdef PROXY_SUPPORT
1423             !proxy_log &&
1424 # endif /* PROXY_SUPPORT */
1425             !outside_root (repos))
1426             dirswitch (arg, repos);
1427         free (repos);
1428     }
1429     else if (status == -2)
1430     {
1431         pending_error = ENOMEM;
1432     }
1433     else if (status != 0)
1434     {
1435         pending_error_text = xmalloc (80 + strlen (arg));
1436         if (pending_error_text == NULL)
1437         {
1438             pending_error = ENOMEM;
1439         }
1440         else if (status == -1)
1441         {
1442             sprintf (pending_error_text,
1443                      "E end of file reading mode for %s", arg);
1444         }
1445         else
1446         {
1447             sprintf (pending_error_text,
1448                      "E error reading mode for %s", arg);
1449             pending_error = status;
1450         }
1451     }
1452 }
1453
1454
1455
1456 static void
1457 serve_static_directory (char *arg)
1458 {
1459     FILE *f;
1460
1461     if (error_pending ()
1462 # ifdef PROXY_SUPPORT
1463         || proxy_log
1464 # endif /* PROXY_SUPPORT */
1465        ) return;
1466
1467     f = CVS_FOPEN (CVSADM_ENTSTAT, "w+");
1468     if (f == NULL)
1469     {
1470         int save_errno = errno;
1471         if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
1472             sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT);
1473         pending_error = save_errno;
1474         return;
1475     }
1476     if (fclose (f) == EOF)
1477     {
1478         int save_errno = errno;
1479         if (alloc_pending (80 + strlen (CVSADM_ENTSTAT)))
1480             sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT);
1481         pending_error = save_errno;
1482         return;
1483     }
1484 }
1485
1486
1487
1488 static void
1489 serve_sticky (char *arg)
1490 {
1491     FILE *f;
1492
1493     if (error_pending ()
1494 # ifdef PROXY_SUPPORT
1495         || proxy_log
1496 # endif /* PROXY_SUPPORT */
1497        ) return;
1498
1499     f = CVS_FOPEN (CVSADM_TAG, "w+");
1500     if (f == NULL)
1501     {
1502         int save_errno = errno;
1503         if (alloc_pending (80 + strlen (CVSADM_TAG)))
1504             sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG);
1505         pending_error = save_errno;
1506         return;
1507     }
1508     if (fprintf (f, "%s\n", arg) < 0)
1509     {
1510         int save_errno = errno;
1511         if (alloc_pending (80 + strlen (CVSADM_TAG)))
1512             sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG);
1513         pending_error = save_errno;
1514         return;
1515     }
1516     if (fclose (f) == EOF)
1517     {
1518         int save_errno = errno;
1519         if (alloc_pending (80 + strlen (CVSADM_TAG)))
1520             sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG);
1521         pending_error = save_errno;
1522         return;
1523     }
1524 }
1525
1526
1527
1528 /*
1529  * Read SIZE bytes from buf_from_net, write them to FILE.
1530  *
1531  * Currently this isn't really used for receiving parts of a file --
1532  * the file is still sent over in one chunk.  But if/when we get
1533  * spiffy in-process gzip support working, perhaps the compressed
1534  * pieces could be sent over as they're ready, if the network is fast
1535  * enough.  Or something.
1536  */
1537 static void
1538 receive_partial_file (size_t size, int file)
1539 {
1540     while (size > 0)
1541     {
1542         int status;
1543         size_t nread;
1544         char *data;
1545
1546         status = buf_read_data (buf_from_net, size, &data, &nread);
1547         if (status != 0)
1548         {
1549             if (status == -2)
1550                 pending_error = ENOMEM;
1551             else
1552             {
1553                 pending_error_text = xmalloc (80);
1554                 if (pending_error_text == NULL)
1555                     pending_error = ENOMEM;
1556                 else if (status == -1)
1557                 {
1558                     sprintf (pending_error_text,
1559                              "E premature end of file from client");
1560                     pending_error = 0;
1561                 }
1562                 else
1563                 {
1564                     sprintf (pending_error_text,
1565                              "E error reading from client");
1566                     pending_error = status;
1567                 }
1568             }
1569             return;
1570         }
1571
1572         size -= nread;
1573
1574         while (nread > 0)
1575         {
1576             ssize_t nwrote;
1577
1578             nwrote = write (file, data, nread);
1579             if (nwrote < 0)
1580             {
1581                 int save_errno = errno;
1582                 if (alloc_pending (40))
1583                     strcpy (pending_error_text, "E unable to write");
1584                 pending_error = save_errno;
1585
1586                 /* Read and discard the file data.  */
1587                 while (size > 0)
1588                 {
1589                     int status;
1590                     size_t nread;
1591                     char *data;
1592
1593                     status = buf_read_data (buf_from_net, size, &data, &nread);
1594                     if (status != 0)
1595                         return;
1596                     size -= nread;
1597                 }
1598
1599                 return;
1600             }
1601             nread -= nwrote;
1602             data += nwrote;
1603         }
1604     }
1605 }
1606
1607
1608
1609 /* Receive SIZE bytes, write to filename FILE.  */
1610 static void
1611 receive_file (size_t size, char *file, int gzipped)
1612 {
1613     int fd;
1614     char *arg = file;
1615
1616     /* Write the file.  */
1617     fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1618     if (fd < 0)
1619     {
1620         int save_errno = errno;
1621         if (alloc_pending (40 + strlen (arg)))
1622             sprintf (pending_error_text, "E cannot open %s", arg);
1623         pending_error = save_errno;
1624         return;
1625     }
1626
1627     if (gzipped)
1628     {
1629         /* Using gunzip_and_write isn't really a high-performance
1630            approach, because it keeps the whole thing in memory
1631            (contiguous memory, worse yet).  But it seems easier to
1632            code than the alternative (and less vulnerable to subtle
1633            bugs).  Given that this feature is mainly for
1634            compatibility, that is the better tradeoff.  */
1635
1636         size_t toread = size;
1637         char *filebuf;
1638         char *p;
1639
1640         filebuf = xmalloc (size);
1641         p = filebuf;
1642         /* If NULL, we still want to read the data and discard it.  */
1643
1644         while (toread > 0)
1645         {
1646             int status;
1647             size_t nread;
1648             char *data;
1649
1650             status = buf_read_data (buf_from_net, toread, &data, &nread);
1651             if (status != 0)
1652             {
1653                 if (status == -2)
1654                     pending_error = ENOMEM;
1655                 else
1656                 {
1657                     pending_error_text = xmalloc (80);
1658                     if (pending_error_text == NULL)
1659                         pending_error = ENOMEM;
1660                     else if (status == -1)
1661                     {
1662                         sprintf (pending_error_text,
1663                                  "E premature end of file from client");
1664                         pending_error = 0;
1665                     }
1666                     else
1667                     {
1668                         sprintf (pending_error_text,
1669                                  "E error reading from client");
1670                         pending_error = status;
1671                     }
1672                 }
1673                 return;
1674             }
1675
1676             toread -= nread;
1677
1678             if (filebuf != NULL)
1679             {
1680                 memcpy (p, data, nread);
1681                 p += nread;
1682             }
1683         }
1684         if (filebuf == NULL)
1685         {
1686             pending_error = ENOMEM;
1687             goto out;
1688         }
1689
1690         if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size))
1691         {
1692             if (alloc_pending (80))
1693                 sprintf (pending_error_text,
1694                          "E aborting due to compression error");
1695         }
1696         free (filebuf);
1697     }
1698     else
1699         receive_partial_file (size, fd);
1700
1701     if (pending_error_text)
1702     {
1703         char *p = xrealloc (pending_error_text,
1704                            strlen (pending_error_text) + strlen (arg) + 30);
1705         if (p)
1706         {
1707             pending_error_text = p;
1708             sprintf (p + strlen (p), ", file %s", arg);
1709         }
1710         /* else original string is supposed to be unchanged */
1711     }
1712
1713  out:
1714     if (close (fd) < 0 && !error_pending ())
1715     {
1716         int save_errno = errno;
1717         if (alloc_pending (40 + strlen (arg)))
1718             sprintf (pending_error_text, "E cannot close %s", arg);
1719         pending_error = save_errno;
1720         return;
1721     }
1722 }
1723
1724
1725
1726 /* Kopt for the next file sent in Modified or Is-modified.  */
1727 static char *kopt;
1728
1729 /* Timestamp (Checkin-time) for next file sent in Modified or
1730    Is-modified.  */
1731 static int checkin_time_valid;
1732 static time_t checkin_time;
1733
1734
1735
1736 /*
1737  * Used to keep track of Entry requests.
1738  */
1739 struct an_entry {
1740     struct an_entry *next;
1741     char *entry;
1742 };
1743
1744 static struct an_entry *entries;
1745
1746 static void
1747 serve_is_modified (char *arg)
1748 {
1749     struct an_entry *p;
1750     char *name;
1751     char *cp;
1752     char *timefield;
1753     /* Have we found this file in "entries" yet.  */
1754     int found;
1755
1756     if (error_pending ()
1757 # ifdef PROXY_SUPPORT
1758         || proxy_log
1759 # endif /* PROXY_SUPPORT */
1760        ) return;
1761
1762     if (outside_dir (arg))
1763         return;
1764
1765     /* Rewrite entries file to have `M' in timestamp field.  */
1766     found = 0;
1767     for (p = entries; p != NULL; p = p->next)
1768     {
1769         name = p->entry + 1;
1770         cp = strchr (name, '/');
1771         if (cp != NULL
1772             && strlen (arg) == cp - name
1773             && strncmp (arg, name, cp - name) == 0)
1774         {
1775             if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
1776             {
1777                 /* We didn't find the record separator or it is followed by
1778                  * the end of the string, so just exit.
1779                  */
1780                 if (alloc_pending (80))
1781                     sprintf (pending_error_text,
1782                              "E Malformed Entry encountered.");
1783                 return;
1784             }
1785             /* If the time field is not currently empty, then one of
1786              * serve_modified, serve_is_modified, & serve_unchanged were
1787              * already called for this file.  We would like to ignore the
1788              * reinvocation silently or, better yet, exit with an error
1789              * message, but we just avoid the copy-forward and overwrite the
1790              * value from the last invocation instead.  See the comment below
1791              * for more.
1792              */
1793             if (*timefield == '/')
1794             {
1795                 /* Copy forward one character.  Space was allocated for this
1796                  * already in serve_entry().  */
1797                 cp = timefield + strlen (timefield);
1798                 cp[1] = '\0';
1799                 while (cp > timefield)
1800                 {
1801                     *cp = cp[-1];
1802                     --cp;
1803                 }
1804
1805                 /* *timefield == '/';  */
1806             }
1807             /* If *TIMEFIELD wasn't '/' and wasn't '+', we assume that it was
1808              * because of multiple calls to Is-modified & Unchanged by the
1809              * client and just overwrite the value from the last call.
1810              * Technically, we should probably either ignore calls after the
1811              * first or send the client an error, since the client/server
1812              * protocol specification specifies that only one call to either
1813              * Is-Modified or Unchanged is allowed, but broken versions of
1814              * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a) and
1815              * the WinCVS & TortoiseCVS clients which depend on those broken
1816              * versions of CVSNT (WinCVS 1.3 & at least one TortoiseCVS
1817              * release) rely on this behavior.
1818              */
1819             if (*timefield != '+')
1820                 *timefield = 'M';
1821
1822             if (kopt != NULL)
1823             {
1824                 if (alloc_pending (strlen (name) + 80))
1825                     sprintf (pending_error_text,
1826                              "E protocol error: both Kopt and Entry for %s",
1827                              arg);
1828                 free (kopt);
1829                 kopt = NULL;
1830                 return;
1831             }
1832             found = 1;
1833             break;
1834         }
1835     }
1836     if (!found)
1837     {
1838         /* We got Is-modified but no Entry.  Add a dummy entry.
1839            The "D" timestamp is what makes it a dummy.  */
1840         p = xmalloc (sizeof (struct an_entry));
1841         if (p == NULL)
1842         {
1843             pending_error = ENOMEM;
1844             return;
1845         }
1846         p->entry = xmalloc (strlen (arg) + 80);
1847         if (p->entry == NULL)
1848         {
1849             pending_error = ENOMEM;
1850             free (p);
1851             return;
1852         }
1853         strcpy (p->entry, "/");
1854         strcat (p->entry, arg);
1855         strcat (p->entry, "//D/");
1856         if (kopt != NULL)
1857         {
1858             strcat (p->entry, kopt);
1859             free (kopt);
1860             kopt = NULL;
1861         }
1862         strcat (p->entry, "/");
1863         p->next = entries;
1864         entries = p;
1865     }
1866 }
1867
1868
1869
1870 static void
1871 serve_modified (char *arg)
1872 {
1873     size_t size;
1874     int read_size;
1875     int status;
1876     char *size_text;
1877     char *mode_text;
1878
1879     int gzipped = 0;
1880
1881     /*
1882      * This used to return immediately if error_pending () was true.
1883      * However, that fails, because it causes each line of the file to
1884      * be echoed back to the client as an unrecognized command.  The
1885      * client isn't reading from the socket, so eventually both
1886      * processes block trying to write to the other.  Now, we try to
1887      * read the file if we can.
1888      */
1889
1890     status = buf_read_line (buf_from_net, &mode_text, NULL);
1891     if (status != 0)
1892     {
1893         if (status == -2)
1894             pending_error = ENOMEM;
1895         else
1896         {
1897             pending_error_text = xmalloc (80 + strlen (arg));
1898             if (pending_error_text == NULL)
1899                 pending_error = ENOMEM;
1900             else
1901             {
1902                 if (status == -1)
1903                     sprintf (pending_error_text,
1904                              "E end of file reading mode for %s", arg);
1905                 else
1906                 {
1907                     sprintf (pending_error_text,
1908                              "E error reading mode for %s", arg);
1909                     pending_error = status;
1910                 }
1911             }
1912         }
1913         return;
1914     }
1915
1916     status = buf_read_line (buf_from_net, &size_text, NULL);
1917     if (status != 0)
1918     {
1919         if (status == -2)
1920             pending_error = ENOMEM;
1921         else
1922         {
1923             pending_error_text = xmalloc (80 + strlen (arg));
1924             if (pending_error_text == NULL)
1925                 pending_error = ENOMEM;
1926             else
1927             {
1928                 if (status == -1)
1929                     sprintf (pending_error_text,
1930                              "E end of file reading size for %s", arg);
1931                 else
1932                 {
1933                     sprintf (pending_error_text,
1934                              "E error reading size for %s", arg);
1935                     pending_error = status;
1936                 }
1937             }
1938         }
1939         free (mode_text);
1940         return;
1941     }
1942     if (size_text[0] == 'z')
1943     {
1944         gzipped = 1;
1945         read_size = atoi (size_text + 1);
1946     }
1947     else
1948         read_size = atoi (size_text);
1949     free (size_text);
1950
1951     if (read_size < 0 && alloc_pending (80))
1952     {
1953         sprintf (pending_error_text,
1954                  "E client sent invalid (negative) file size");
1955         return;
1956     }
1957     else
1958         size = read_size;
1959
1960     if (error_pending ())
1961     {
1962         /* Now that we know the size, read and discard the file data.  */
1963         while (size > 0)
1964         {
1965             int status;
1966             size_t nread;
1967             char *data;
1968
1969             status = buf_read_data (buf_from_net, size, &data, &nread);
1970             if (status != 0)
1971                 return;
1972             size -= nread;
1973         }
1974         free (mode_text);
1975         return;
1976     }
1977
1978     if (
1979 # ifdef PROXY_SUPPORT
1980         !proxy_log &&
1981 # endif /* PROXY_SUPPORT */
1982         outside_dir (arg))
1983     {
1984         free (mode_text);
1985         return;
1986     }
1987
1988     receive_file (size,
1989 # ifdef PROXY_SUPPORT
1990                   proxy_log ? DEVNULL :
1991 # endif /* PROXY_SUPPORT */
1992                               arg,
1993                   gzipped);
1994     if (error_pending ())
1995     {
1996         free (mode_text);
1997         return;
1998     }
1999
2000 # ifdef PROXY_SUPPORT
2001     /* We've read all the data that needed to be read if we're still logging
2002      * for a secondary.  Return.
2003      */
2004     if (proxy_log) return;
2005 # endif /* PROXY_SUPPORT */
2006
2007     if (checkin_time_valid)
2008     {
2009         struct utimbuf t;
2010
2011         memset (&t, 0, sizeof (t));
2012         t.modtime = t.actime = checkin_time;
2013         if (utime (arg, &t) < 0)
2014         {
2015             int save_errno = errno;
2016             if (alloc_pending (80 + strlen (arg)))
2017                 sprintf (pending_error_text, "E cannot utime %s", arg);
2018             pending_error = save_errno;
2019             free (mode_text);
2020             return;
2021         }
2022         checkin_time_valid = 0;
2023     }
2024
2025     {
2026         int status = change_mode (arg, mode_text, 0);
2027         free (mode_text);
2028         if (status)
2029         {
2030             if (alloc_pending (40 + strlen (arg)))
2031                 sprintf (pending_error_text,
2032                          "E cannot change mode for %s", arg);
2033             pending_error = status;
2034             return;
2035         }
2036     }
2037
2038     /* Make sure that the Entries indicate the right kopt.  We probably
2039        could do this even in the non-kopt case and, I think, save a stat()
2040        call in time_stamp_server.  But for conservatism I'm leaving the
2041        non-kopt case alone.  */
2042     if (kopt != NULL)
2043         serve_is_modified (arg);
2044 }
2045
2046
2047
2048 static void
2049 serve_enable_unchanged (char *arg)
2050 {
2051 # ifdef PROXY_SUPPORT
2052     /* Might as well skip this since this function does nothing anyhow.  If
2053      * it did do anything and could generate errors, then the line below would
2054      * be necessary since this can be processed before a `Root' request.
2055      *
2056      *     if (reprocessing) return;
2057      */
2058 # endif /* PROXY_SUPPORT */
2059 }
2060
2061
2062
2063 static void
2064 serve_unchanged (char *arg)
2065 {
2066     struct an_entry *p;
2067     char *name;
2068     char *cp;
2069     char *timefield;
2070
2071     if (error_pending ()
2072 # ifdef PROXY_SUPPORT
2073         || proxy_log
2074 # endif /* PROXY_SUPPORT */
2075        ) return;
2076
2077     if (outside_dir (arg))
2078         return;
2079
2080     /* Rewrite entries file to have `=' in timestamp field.  */
2081     for (p = entries; p != NULL; p = p->next)
2082     {
2083         name = p->entry + 1;
2084         cp = strchr (name, '/');
2085         if (cp != NULL
2086             && strlen (arg) == cp - name
2087             && strncmp (arg, name, cp - name) == 0)
2088         {
2089             if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0')
2090             {
2091                 /* We didn't find the record separator or it is followed by
2092                  * the end of the string, so just exit.
2093                  */
2094                 if (alloc_pending (80))
2095                     sprintf (pending_error_text,
2096                              "E Malformed Entry encountered.");
2097                 return;
2098             }
2099             /* If the time field is not currently empty, then one of
2100              * serve_modified, serve_is_modified, & serve_unchanged were
2101              * already called for this file.  We would like to ignore the
2102              * reinvocation silently or, better yet, exit with an error
2103              * message, but we just avoid the copy-forward and overwrite the
2104              * value from the last invocation instead.  See the comment below
2105              * for more.
2106              */
2107             if (*timefield == '/')
2108             {
2109                 /* Copy forward one character.  Space was allocated for this
2110                  * already in serve_entry().  */
2111                 cp = timefield + strlen (timefield);
2112                 cp[1] = '\0';
2113                 while (cp > timefield)
2114                 {
2115                     *cp = cp[-1];
2116                     --cp;
2117                 }
2118
2119                 /* *timefield == '/';  */
2120             }
2121             if (*timefield != '+')
2122             {
2123                 /* '+' is a conflict marker and we don't want to mess with it
2124                  * until Version_TS catches it.
2125                  */
2126                 if (timefield[1] != '/')
2127                 {
2128                     /* Obliterate anything else in TIMEFIELD.  This is again to
2129                      * support the broken CVSNT clients mentioned below, in
2130                      * conjunction with strict timestamp string boundry
2131                      * checking in time_stamp_server() from vers_ts.c &
2132                      * file_has_conflict() from subr.c, since the broken
2133                      * clients used to send malformed timestamp fields in the
2134                      * Entry request that they then depended on the subsequent
2135                      * Unchanged request to overwrite.
2136                      */
2137                     char *d = timefield + 1;
2138                     if ((cp = strchr (d, '/')))
2139                     {
2140                         while (*cp)
2141                         {
2142                             *d++ = *cp++;
2143                         }
2144                         *d = '\0';
2145                     }
2146                 }
2147                 /* If *TIMEFIELD wasn't '/', we assume that it was because of
2148                  * multiple calls to Is-modified & Unchanged by the client and
2149                  * just overwrite the value from the last call.  Technically,
2150                  * we should probably either ignore calls after the first or
2151                  * send the client an error, since the client/server protocol
2152                  * specification specifies that only one call to either
2153                  * Is-Modified or Unchanged is allowed, but broken versions of
2154                  * CVSNT (at least 2.0.34 - 2.0.41, reported fixed in 2.0.41a)
2155                  * and the WinCVS & TortoiseCVS clients which depend on those
2156                  * broken versions of CVSNT (WinCVS 1.3 & at least one
2157                  * TortoiseCVS release) rely on this behavior.
2158                  */
2159                 *timefield = '=';
2160             }
2161             break;
2162         }
2163     }
2164 }
2165
2166
2167
2168 static void
2169 serve_entry (char *arg)
2170 {
2171     struct an_entry *p;
2172     char *cp;
2173     int i = 0;
2174
2175     if (error_pending()
2176 # ifdef PROXY_SUPPORT
2177         || proxy_log
2178 # endif /* PROXY_SUPPORT */
2179        ) return;
2180
2181     /* Verify that the entry is well-formed.  This can avoid problems later.
2182      * At the moment we only check that the Entry contains five slashes in
2183      * approximately the correct locations since some of the code makes
2184      * assumptions about this.
2185      */
2186     cp = arg;
2187     if (*cp == 'D') cp++;
2188     while (i++ < 5)
2189     {
2190         if (!cp || *cp != '/')
2191         {
2192             if (alloc_pending (80))
2193                 sprintf (pending_error_text,
2194                          "E protocol error: Malformed Entry");
2195             return;
2196         }
2197         cp = strchr (cp + 1, '/');
2198     }
2199
2200     p = xmalloc (sizeof (struct an_entry));
2201     if (p == NULL)
2202     {
2203         pending_error = ENOMEM;
2204         return;
2205     }
2206     /* Leave space for serve_unchanged to write '=' if it wants.  */
2207     cp = xmalloc (strlen (arg) + 2);
2208     if (cp == NULL)
2209     {
2210         free (p);
2211         pending_error = ENOMEM;
2212         return;
2213     }
2214     strcpy (cp, arg);
2215     p->next = entries;
2216     p->entry = cp;
2217     entries = p;
2218 }
2219
2220
2221
2222 static void
2223 serve_kopt (char *arg)
2224 {
2225     if (error_pending ()
2226 # ifdef PROXY_SUPPORT
2227         || proxy_log
2228 # endif /* PROXY_SUPPORT */
2229        )
2230         return;
2231
2232     if (kopt != NULL)
2233     {
2234         if (alloc_pending (80 + strlen (arg)))
2235             sprintf (pending_error_text,
2236                      "E protocol error: duplicate Kopt request: %s", arg);
2237         return;
2238     }
2239
2240     /* Do some sanity checks.  In particular, that it is not too long.
2241        This lets the rest of the code not worry so much about buffer
2242        overrun attacks.  Probably should call RCS_check_kflag here,
2243        but that would mean changing RCS_check_kflag to handle errors
2244        other than via exit(), fprintf(), and such.  */
2245     if (strlen (arg) > 10)
2246     {
2247         if (alloc_pending (80 + strlen (arg)))
2248             sprintf (pending_error_text,
2249                      "E protocol error: invalid Kopt request: %s", arg);
2250         return;
2251     }
2252
2253     kopt = xmalloc (strlen (arg) + 1);
2254     if (kopt == NULL)
2255     {
2256         pending_error = ENOMEM;
2257         return;
2258     }
2259     strcpy (kopt, arg);
2260 }
2261
2262
2263
2264 static void
2265 serve_checkin_time (char *arg)
2266 {
2267     struct timespec t;
2268
2269     if (error_pending ()
2270 # ifdef PROXY_SUPPORT
2271         || proxy_log
2272 # endif /* PROXY_SUPPORT */
2273        )
2274         return;
2275
2276     if (checkin_time_valid)
2277     {
2278         if (alloc_pending (80 + strlen (arg)))
2279             sprintf (pending_error_text,
2280                      "E protocol error: duplicate Checkin-time request: %s",
2281                      arg);
2282         return;
2283     }
2284
2285     if (!get_date (&t, arg, NULL))
2286     {
2287         if (alloc_pending (80 + strlen (arg)))
2288             sprintf (pending_error_text, "E cannot parse date %s", arg);
2289         return;
2290     }
2291
2292     /* Truncate any nanoseconds returned by get_date().  */
2293     checkin_time = t.tv_sec;
2294     checkin_time_valid = 1;
2295 }
2296
2297
2298
2299 static void
2300 server_write_entries (void)
2301 {
2302     FILE *f;
2303     struct an_entry *p;
2304     struct an_entry *q;
2305
2306     if (entries == NULL)
2307         return;
2308
2309     f = NULL;
2310     /* Note that we free all the entries regardless of errors.  */
2311     if (!error_pending ())
2312     {
2313         /* We open in append mode because we don't want to clobber an
2314            existing Entries file.  If we are checking out a module
2315            which explicitly lists more than one file in a particular
2316            directory, then we will wind up calling
2317            server_write_entries for each such file.  */
2318         f = CVS_FOPEN (CVSADM_ENT, "a");
2319         if (f == NULL)
2320         {
2321             int save_errno = errno;
2322             if (alloc_pending (80 + strlen (CVSADM_ENT)))
2323                 sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT);
2324             pending_error = save_errno;
2325         }
2326     }
2327     for (p = entries; p != NULL;)
2328     {
2329         if (!error_pending ())
2330         {
2331             if (fprintf (f, "%s\n", p->entry) < 0)
2332             {
2333                 int save_errno = errno;
2334                 if (alloc_pending (80 + strlen(CVSADM_ENT)))
2335                     sprintf (pending_error_text,
2336                              "E cannot write to %s", CVSADM_ENT);
2337                 pending_error = save_errno;
2338             }
2339         }
2340         free (p->entry);
2341         q = p->next;
2342         free (p);
2343         p = q;
2344     }
2345     entries = NULL;
2346     if (f != NULL && fclose (f) == EOF && !error_pending ())
2347     {
2348         int save_errno = errno;
2349         if (alloc_pending (80 + strlen (CVSADM_ENT)))
2350             sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT);
2351         pending_error = save_errno;
2352     }
2353 }
2354
2355
2356
2357 # ifdef PROXY_SUPPORT
2358 /*
2359  * callback proc to run a script when admin finishes.
2360  */
2361 static int
2362 prepost_proxy_proc (const char *repository, const char *filter, void *closure)
2363 {
2364     char *cmdline;
2365     bool *pre = closure;
2366
2367     /* %c = cvs_cmd_name
2368      * %I = commit ID
2369      * %p = shortrepos
2370      * %r = repository
2371      */
2372     TRACE (TRACE_FUNCTION, "prepost_proxy_proc (%s, %s, %s)", repository,
2373            filter, *pre ? "pre" : "post");
2374
2375     /*
2376      * Cast any NULL arguments as appropriate pointers as this is an
2377      * stdarg function and we need to be certain the caller gets what
2378      * is expected.
2379      */
2380     cmdline = format_cmdline (
2381 # ifdef SUPPORT_OLD_INFO_FMT_STRINGS
2382                               0, ".",
2383 # endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
2384                               filter,
2385                               "c", "s", cvs_cmd_name,
2386                               "I", "s", global_session_id,
2387                               "R", "s", referrer ? referrer->original : "NONE",
2388                               "p", "s", ".",
2389                               "r", "s", current_parsed_root->directory,
2390                               "P", "s", config->PrimaryServer->original,
2391                               (char *) NULL);
2392
2393     if (!cmdline || !strlen (cmdline))
2394     {
2395         if (cmdline) free (cmdline);
2396         if (*pre)
2397             error (0, 0, "preadmin proc resolved to the empty string!");
2398         else
2399             error (0, 0, "postadmin proc resolved to the empty string!");
2400         return 1;
2401     }
2402
2403     run_setup (cmdline);
2404
2405     free (cmdline);
2406
2407     /* FIXME - read the comment in verifymsg_proc() about why we use abs()
2408      * below() and shouldn't.
2409      */
2410     return abs (run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
2411                           RUN_NORMAL | RUN_SIGIGNORE));
2412 }
2413
2414
2415
2416 /* Become a secondary write proxy to a master server.
2417  *
2418  * This function opens the connection to the primary, dumps the secondary log
2419  * to the primary, then reads data from any available connection and writes it
2420  * to its partner:
2421  *
2422  *   buf_from_net -> buf_to_primary
2423  *   buf_from_primary -> buf_to_net
2424  *
2425  * When all "from" connections have sent EOF and all data has been sent to
2426  * "to" connections, this function closes the "to" pipes and returns.
2427  */
2428 static void
2429 become_proxy (void)
2430 {
2431     struct buffer *buf_to_primary;
2432     struct buffer *buf_from_primary;
2433
2434     /* Close the client log and open it for read.  */
2435     struct buffer *buf_clientlog = log_buffer_rewind (proxy_log_out);
2436     int status, to_primary_fd, from_primary_fd, to_net_fd, from_net_fd;
2437
2438     /* Call presecondary script.  */
2439     bool pre = true;
2440
2441             char *data;
2442             size_t thispass, got;
2443             int s;
2444             char *newdata;
2445
2446     Parse_Info (CVSROOTADM_PREPROXY, current_parsed_root->directory,
2447                 prepost_proxy_proc, PIOPT_ALL, &pre);
2448
2449     /* Open connection to primary server.  */
2450     open_connection_to_server (config->PrimaryServer, &buf_to_primary,
2451                                &buf_from_primary);
2452     setup_logfiles ("CVS_SECONDARY_LOG", &buf_to_primary, &buf_from_primary);
2453     if ((status = set_nonblock (buf_from_primary)))
2454         error (1, status, "failed to set nonblocking io from primary");
2455     if ((status = set_nonblock (buf_from_net)))
2456         error (1, status, "failed to set nonblocking io from client");
2457     if ((status = set_nonblock (buf_to_primary)))
2458         error (1, status, "failed to set nonblocking io to primary");
2459     if ((status = set_nonblock (buf_to_net)))
2460         error (1, status, "failed to set nonblocking io to client");
2461
2462     to_primary_fd = buf_get_fd (buf_to_primary);
2463     from_primary_fd = buf_get_fd (buf_from_primary);
2464     to_net_fd = buf_get_fd (buf_to_net);
2465     assert (to_primary_fd >= 0 && from_primary_fd >= 0 && to_net_fd >= 0);
2466
2467     /* Close the client log and open it for read.  */
2468     rewind_buf_from_net ();
2469
2470     while (from_primary_fd >= 0 || to_primary_fd >= 0)
2471     {
2472         fd_set readfds, writefds;
2473         int status, numfds = -1;
2474         struct timeval *timeout_ptr;
2475         struct timeval timeout;
2476         size_t toread;
2477
2478         FD_ZERO (&readfds);
2479         FD_ZERO (&writefds);
2480
2481         /* The fd for a multi-source buffer can change with any read.  */
2482         from_net_fd = buf_from_net ? buf_get_fd (buf_from_net) : -1;
2483
2484         if ((buf_from_net && !buf_empty_p (buf_from_net))
2485             || (buf_from_primary && !buf_empty_p (buf_from_primary)))
2486         {
2487             /* There is data pending so don't block if we don't find any new
2488              * data on the fds.
2489              */
2490             timeout.tv_sec = 0;
2491             timeout.tv_usec = 0;
2492             timeout_ptr = &timeout;
2493         }
2494         else
2495             /* block indefinately */
2496             timeout_ptr = NULL;
2497
2498         /* Set writefds if data is pending.  */
2499         if (to_net_fd >= 0 && !buf_empty_p (buf_to_net))
2500         {
2501             FD_SET (to_net_fd, &writefds);
2502             numfds = MAX (numfds, to_net_fd);
2503         }
2504         if (to_primary_fd >= 0 && !buf_empty_p (buf_to_primary))
2505         {
2506             FD_SET (to_primary_fd, &writefds);
2507             numfds = MAX (numfds, to_primary_fd);
2508         }
2509
2510         /* Set readfds if descriptors are still open.  */
2511         if (from_net_fd >= 0)
2512         {
2513             FD_SET (from_net_fd, &readfds);
2514             numfds = MAX (numfds, from_net_fd);
2515         }
2516         if (from_primary_fd >= 0)
2517         {
2518             FD_SET (from_primary_fd, &readfds);
2519             numfds = MAX (numfds, from_primary_fd);
2520         }
2521
2522         /* NUMFDS needs to be the highest descriptor + 1 according to the
2523          * select spec.
2524          */
2525         numfds++;
2526
2527         do {
2528             /* This used to select on exceptions too, but as far
2529                as I know there was never any reason to do that and
2530                SCO doesn't let you select on exceptions on pipes.  */
2531             numfds = select (numfds, &readfds, &writefds,
2532                              NULL, timeout_ptr);
2533             if (numfds < 0 && errno != EINTR)
2534             {
2535                 /* Sending an error to the client, possibly in the middle of a
2536                  * separate protocol message, will likely not mean much to the
2537                  * client, but it's better than nothing, I guess.
2538                  */
2539                 buf_output0 (buf_to_net, "E select failed\n");
2540                 print_error (errno);
2541                 exit (EXIT_FAILURE);
2542             }
2543         } while (numfds < 0);
2544
2545         if (numfds == 0)
2546         {
2547             FD_ZERO (&readfds);
2548             FD_ZERO (&writefds);
2549         }
2550
2551         if (to_net_fd >= 0 && FD_ISSET (to_net_fd, &writefds))
2552         {
2553             /* What should we do with errors?  syslog() them?  */
2554             buf_send_output (buf_to_net);
2555             buf_flush (buf_to_net, false);
2556         }
2557
2558         status = 0;
2559         if (from_net_fd >= 0 && (FD_ISSET (from_net_fd, &readfds)))
2560             status = buf_input_data (buf_from_net, NULL);
2561
2562         if (buf_from_net && !buf_empty_p (buf_from_net))
2563         {
2564             if (buf_to_primary)
2565                 buf_append_buffer (buf_to_primary, buf_from_net);
2566             else
2567                 /* (Sys?)log this?  */;
2568                 
2569         }
2570
2571         if (status == -1 /* EOF */)
2572         {
2573             SIG_beginCrSect();
2574             /* Need only to shut this down and set to NULL, really, in
2575              * crit sec, to ensure no double-dispose and to make sure
2576              * network pipes are closed as properly as possible, but I
2577              * don't see much optimization potential in saving values and
2578              * postponing the free.
2579              */
2580             buf_shutdown (buf_from_net);
2581             buf_free (buf_from_net);
2582             buf_from_net = NULL;
2583             /* So buf_to_primary will be closed at the end of this loop.  */
2584             from_net_fd = -1;
2585             SIG_endCrSect();
2586         }
2587         else if (status > 0 /* ERRNO */)
2588         {
2589             buf_output0 (buf_to_net,
2590                          "E buf_input_data failed reading from client\n");
2591             print_error (status);
2592             exit (EXIT_FAILURE);
2593         }
2594
2595         if (to_primary_fd >= 0 && FD_ISSET (to_primary_fd, &writefds))
2596         {
2597             /* What should we do with errors?  syslog() them?  */
2598             buf_send_output (buf_to_primary);
2599             buf_flush (buf_to_primary, false);
2600         }
2601
2602         status = 0;
2603         if (from_primary_fd >= 0 && FD_ISSET (from_primary_fd, &readfds))
2604             status = buf_input_data (buf_from_primary, &toread);
2605
2606         /* Avoid resending data from the server which we already sent to the
2607          * client.  Otherwise clients get really confused.
2608          */
2609         if (buf_clientlog
2610             && buf_from_primary && !buf_empty_p (buf_from_primary))
2611         {
2612             /* Dispose of data we already sent to the client.  */
2613             while (buf_clientlog && toread > 0)
2614             {
2615                 s = buf_read_data (buf_clientlog, toread, &data, &got);
2616                 if (s == -2)
2617                     error (1, ENOMEM, "Failed to read data.");
2618                 if (s == -1)
2619                 {
2620                     buf_shutdown (buf_clientlog);
2621                     buf_clientlog = NULL;
2622                 }
2623                 else if (s)
2624                     error (1, s, "Error reading writeproxy log.");
2625                 else
2626                 {
2627                     thispass = got;
2628                     while (thispass > 0)
2629                     {
2630                         /* No need to check for errors here since we know we
2631                          * won't read more than buf_input read into
2632                          * BUF_FROM_PRIMARY (see how TOREAD is set above).
2633                          */
2634                         buf_read_data (buf_from_primary, thispass, &newdata,
2635                                        &got);
2636                         /* Verify that we are throwing away what we think we
2637                          * are.
2638                          *
2639                          * It is valid to assume that the secondary and primary
2640                          * are closely enough in sync that this portion of the
2641                          * communication will be in sync beacuse if they were
2642                          * not, then the secondary might provide a
2643                          * valid-request string to the client which contained a
2644                          * request that the primary didn't support.  If the
2645                          * client later used the request, the primary server
2646                          * would exit anyhow.
2647                          *
2648                          * FIXME?
2649                          * An alternative approach might be to make sure that
2650                          * the secondary provides the same string as the
2651                          * primary regardless, for purposes like pointing a
2652                          * secondary at an unwitting primary, in which case it
2653                          * might be useful to have some way to override the
2654                          * valid-requests string on a secondary, but it seems
2655                          * much easier to simply sync the versions, at the
2656                          * moment.
2657                          */
2658                         if (memcmp (data, newdata, got))
2659                             error (1, 0, "Secondary out of sync with primary!");
2660                         data += got;
2661                         thispass -= got;
2662                     }
2663                     toread -= got;
2664                 }
2665             }
2666         }
2667
2668         if (buf_from_primary && !buf_empty_p (buf_from_primary))
2669         {
2670             if (buf_to_net)
2671                 buf_append_buffer (buf_to_net, buf_from_primary);
2672             else
2673                 /* (Sys?)log this?  */;
2674                 
2675         }
2676
2677         if (status == -1 /* EOF */)
2678         {
2679             buf_shutdown (buf_from_primary);
2680             buf_from_primary = NULL;
2681             from_primary_fd = -1;
2682         }
2683         else if (status > 0 /* ERRNO */)
2684         {
2685             buf_output0 (buf_to_net,
2686                          "E buf_input_data failed reading from primary\n");
2687             print_error (status);
2688             exit (EXIT_FAILURE);
2689         }
2690
2691         /* If our "source pipe" is closed and all data has been sent, avoid
2692          * selecting it for writability, but don't actually close the buffer in
2693          * case other routines want to use it later.  The buffer will be closed
2694          * in server_cleanup ().
2695          */
2696         if (from_primary_fd < 0
2697             && buf_to_net && buf_empty_p (buf_to_net))
2698             to_net_fd = -1;
2699
2700         if (buf_to_primary
2701             && (/* Assume that there is no further reason to keep the buffer to
2702                  * the primary open if we can no longer read its responses.
2703                  */
2704                 (from_primary_fd < 0 && buf_to_primary)
2705                 /* Also close buf_to_primary when it becomes impossible to find
2706                  * more data to send to it.  We don't close buf_from_primary
2707                  * yet since there may be data pending or the primary may react
2708                  * to the EOF on its input pipe.
2709                  */
2710                 || (from_net_fd < 0 && buf_empty_p (buf_to_primary))))
2711         {
2712             buf_shutdown (buf_to_primary);
2713             buf_free (buf_to_primary);
2714             buf_to_primary = NULL;
2715
2716             /* Setting the fd < 0 with from_primary_fd already < 0 will cause
2717              * an escape from this while loop.
2718              */
2719             to_primary_fd = -1;
2720         }
2721     }
2722
2723     /* Call postsecondary script.  */
2724     pre = false;
2725     Parse_Info (CVSROOTADM_POSTPROXY, current_parsed_root->directory,
2726                 prepost_proxy_proc, PIOPT_ALL, &pre);
2727 }
2728 # endif /* PROXY_SUPPORT */
2729
2730
2731
2732 struct notify_note {
2733     /* Directory in which this notification happens.  xmalloc'd*/
2734     char *dir;
2735
2736     /* xmalloc'd.  */
2737     char *update_dir;
2738
2739     /* xmalloc'd.  */
2740     char *filename;
2741
2742     /* The following three all in one xmalloc'd block, pointed to by TYPE.
2743        Each '\0' terminated.  */
2744     /* "E" or "U".  */
2745     char *type;
2746     /* time+host+dir */
2747     char *val;
2748     char *watches;
2749
2750     struct notify_note *next;
2751 };
2752
2753 static struct notify_note *notify_list;
2754 /* Used while building list, to point to the last node that already exists.  */
2755 static struct notify_note *last_node;
2756
2757 static void
2758 serve_notify (char *arg)
2759 {
2760     struct notify_note *new = NULL;
2761     char *data = NULL;
2762     int status;
2763
2764     if (error_pending ()) return;
2765
2766     if (isProxyServer())
2767     {
2768 # ifdef PROXY_SUPPORT
2769         if (!proxy_log)
2770         {
2771 # endif /* PROXY_SUPPORT */
2772             if (alloc_pending (160) + strlen (program_name))
2773                 sprintf (pending_error_text, 
2774 "E This CVS server does not support disconnected `%s edit'.  For now, remove all `%s' files in your workspace and try your command again.",
2775                          program_name, CVSADM_NOTIFY);
2776         return;
2777 # ifdef PROXY_SUPPORT
2778         }
2779         else
2780         {
2781             /* This is effectively a write command, so run it on the primary.  */
2782             become_proxy ();
2783             exit (EXIT_SUCCESS);
2784         }
2785 # endif /* PROXY_SUPPORT */
2786     }
2787
2788     if (outside_dir (arg))
2789         return;
2790
2791     if (gDirname == NULL)
2792         goto error;
2793
2794     new = xmalloc (sizeof (struct notify_note));
2795     if (new == NULL)
2796     {
2797         pending_error = ENOMEM;
2798         return;
2799     }
2800     new->dir = xmalloc (strlen (gDirname) + 1);
2801     new->update_dir = xmalloc (strlen (gupdate_dir) + 1);
2802     new->filename = xmalloc (strlen (arg) + 1);
2803     if (new->dir == NULL || new->update_dir == NULL || new->filename == NULL)
2804     {
2805         pending_error = ENOMEM;
2806         if (new->dir != NULL)
2807             free (new->dir);
2808         free (new);
2809         return;
2810     }
2811     strcpy (new->dir, gDirname);
2812     strcpy (new->update_dir, gupdate_dir);
2813     strcpy (new->filename, arg);
2814
2815     status = buf_read_line (buf_from_net, &data, NULL);
2816     if (status != 0)
2817     {
2818         if (status == -2)
2819             pending_error = ENOMEM;
2820         else
2821         {
2822             pending_error_text = xmalloc (80 + strlen (arg));
2823             if (pending_error_text == NULL)
2824                 pending_error = ENOMEM;
2825             else
2826             {
2827                 if (status == -1)
2828                     sprintf (pending_error_text,
2829                              "E end of file reading notification for %s", arg);
2830                 else
2831                 {
2832                     sprintf (pending_error_text,
2833                              "E error reading notification for %s", arg);
2834                     pending_error = status;
2835                 }
2836             }
2837         }
2838         free (new->filename);
2839         free (new->dir);
2840         free (new);
2841     }
2842     else
2843     {
2844         char *cp;
2845
2846         if (!data[0])
2847             goto error;
2848
2849         if (strchr (data, '+'))
2850             goto error;
2851
2852         new->type = data;
2853         if (data[1] != '\t')
2854             goto error;
2855         data[1] = '\0';
2856         cp = data + 2;
2857         new->val = cp;
2858         cp = strchr (cp, '\t');
2859         if (cp == NULL)
2860             goto error;
2861         *cp++ = '+';
2862         cp = strchr (cp, '\t');
2863         if (cp == NULL)
2864             goto error;
2865         *cp++ = '+';
2866         cp = strchr (cp, '\t');
2867         if (cp == NULL)
2868             goto error;
2869         *cp++ = '\0';
2870         new->watches = cp;
2871         /* If there is another tab, ignore everything after it,
2872            for future expansion.  */
2873         cp = strchr (cp, '\t');
2874         if (cp != NULL)
2875             *cp = '\0';
2876
2877         new->next = NULL;
2878
2879         if (last_node == NULL)
2880             notify_list = new;
2881         else
2882             last_node->next = new;
2883         last_node = new;
2884     }
2885     return;
2886   error:
2887     pending_error = 0;
2888     if (alloc_pending (80))
2889         strcpy (pending_error_text,
2890                 "E Protocol error; malformed Notify request");
2891     if (data != NULL)
2892         free (data);
2893     if (new != NULL)
2894     {
2895         free (new->filename);
2896         free (new->update_dir);
2897         free (new->dir);
2898         free (new);
2899     }
2900     return;
2901 }
2902
2903
2904
2905 static void
2906 serve_hostname (char *arg)
2907 {
2908     free (hostname);
2909     hostname = xstrdup (arg);
2910     return;
2911 }
2912
2913
2914
2915 static void
2916 serve_localdir (char *arg)
2917 {
2918     if (CurDir) free (CurDir);
2919     CurDir = xstrdup (arg);
2920 }
2921
2922
2923
2924 /* Process all the Notify requests that we have stored up.  Returns 0
2925    if successful, if not prints error message (via error()) and
2926    returns negative value.  */
2927 static int
2928 server_notify (void)
2929 {
2930     struct notify_note *p;
2931     char *repos;
2932
2933     TRACE (TRACE_FUNCTION, "server_notify()");
2934
2935     while (notify_list != NULL)
2936     {
2937         if (CVS_CHDIR (notify_list->dir) < 0)
2938         {
2939             error (0, errno, "cannot change to %s", notify_list->dir);
2940             return -1;
2941         }
2942         repos = Name_Repository (NULL, NULL);
2943
2944         lock_dir_for_write (repos);
2945
2946         fileattr_startdir (repos);
2947
2948         notify_do (*notify_list->type, notify_list->filename,
2949                    notify_list->update_dir, getcaller(), notify_list->val,
2950                    notify_list->watches, repos);
2951
2952         buf_output0 (buf_to_net, "Notified ");
2953         {
2954             char *dir = notify_list->dir + strlen (server_temp_dir) + 1;
2955             if (dir[0] == '\0')
2956                 buf_append_char (buf_to_net, '.');
2957             else
2958                 buf_output0 (buf_to_net, dir);
2959             buf_append_char (buf_to_net, '/');
2960             buf_append_char (buf_to_net, '\n');
2961         }
2962         buf_output0 (buf_to_net, repos);
2963         buf_append_char (buf_to_net, '/');
2964         buf_output0 (buf_to_net, notify_list->filename);
2965         buf_append_char (buf_to_net, '\n');
2966         free (repos);
2967
2968         p = notify_list->next;
2969         free (notify_list->filename);
2970         free (notify_list->dir);
2971         free (notify_list->type);
2972         free (notify_list);
2973         notify_list = p;
2974
2975         fileattr_write ();
2976         fileattr_free ();
2977
2978         Lock_Cleanup ();
2979     }
2980
2981     last_node = NULL;
2982
2983     /* The code used to call fflush (stdout) here, but that is no
2984        longer necessary.  The data is now buffered in buf_to_net,
2985        which will be flushed by the caller, do_cvs_command.  */
2986
2987     return 0;
2988 }
2989
2990
2991
2992 /* This request is processed in all passes since requests which must
2993  * sometimes be processed before it is known whether we are running as a
2994  * secondary or not, for instance the `expand-modules' request, sometimes use
2995  * the `Arguments'.
2996  */
2997 static void
2998 serve_argument (char *arg)
2999 {
3000     char *p;
3001
3002     if (error_pending()) return;
3003
3004     if (argument_count >= 10000)
3005     {
3006         if (alloc_pending (80))
3007             sprintf (pending_error_text, 
3008                      "E Protocol error: too many arguments");
3009         return;
3010     }
3011
3012     if (argument_vector_size <= argument_count)
3013     {
3014         argument_vector_size *= 2;
3015         argument_vector = xnrealloc (argument_vector,
3016                                      argument_vector_size, sizeof (char *));
3017         if (argument_vector == NULL)
3018         {
3019             pending_error = ENOMEM;
3020             return;
3021         }
3022     }
3023     p = xmalloc (strlen (arg) + 1);
3024     if (p == NULL)
3025     {
3026         pending_error = ENOMEM;
3027         return;
3028     }
3029     strcpy (p, arg);
3030     argument_vector[argument_count++] = p;
3031 }
3032
3033
3034
3035 /* For secondary servers, this is handled in all passes, as is the `Argument'
3036  * request, and for the same reasons.
3037  */
3038 static void
3039 serve_argumentx (char *arg)
3040 {
3041     char *p;
3042
3043     if (error_pending()) return;
3044     
3045     if (argument_count <= 1) 
3046     {
3047         if (alloc_pending (80))
3048             sprintf (pending_error_text,
3049 "E Protocol error: called argumentx without prior call to argument");
3050         return;
3051     }
3052
3053     p = argument_vector[argument_count - 1];
3054     p = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1);
3055     if (p == NULL)
3056     {
3057         pending_error = ENOMEM;
3058         return;
3059     }
3060     strcat (p, "\n");
3061     strcat (p, arg);
3062     argument_vector[argument_count - 1] = p;
3063 }
3064
3065
3066
3067 static void
3068 serve_global_option (char *arg)
3069 {
3070 # ifdef PROXY_SUPPORT
3071     /* This can generate error messages and termination before `Root' requests,
3072      * so it must be dealt with in the first pass.
3073      */ 
3074     if (reprocessing) return;
3075 # endif /* PROXY_SUPPORT */
3076
3077     if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0')
3078     {
3079     error_return:
3080         if (alloc_pending (strlen (arg) + 80))
3081             sprintf (pending_error_text,
3082                      "E Protocol error: bad global option %s",
3083                      arg);
3084         return;
3085     }
3086     switch (arg[1])
3087     {
3088         case 'l':
3089             error(0, 0, "WARNING: global `-l' option ignored.");
3090             break;
3091         case 'n':
3092             noexec = 1;
3093             logoff = 1;
3094             break;
3095         case 'q':
3096             quiet = 1;
3097             break;
3098         case 'r':
3099             cvswrite = 0;
3100             break;
3101         case 'Q':
3102             really_quiet = 1;
3103             break;
3104         case 't':
3105             trace++;
3106             break;
3107         default:
3108             goto error_return;
3109     }
3110 }
3111
3112
3113
3114 /* This needs to be processed before Root requests, so we allow it to be
3115  * be processed before knowing whether we are running as a secondary server
3116  * to allow `noop' and `Root' requests to generate errors as before.
3117  */
3118 static void
3119 serve_set (char *arg)
3120 {
3121 # ifdef PROXY_SUPPORT
3122     if (reprocessing) return;
3123 # endif /* PROXY_SUPPORT */
3124
3125     /* FIXME: This sends errors immediately (I think); they should be
3126        put into pending_error.  */
3127     variable_set (arg);
3128 }
3129
3130 # ifdef ENCRYPTION
3131
3132 #   ifdef HAVE_KERBEROS
3133
3134 static void
3135 serve_kerberos_encrypt( char *arg )
3136 {
3137 #     ifdef PROXY_SUPPORT
3138     assert (!proxy_log);
3139 #     endif /* PROXY_SUPPORT */
3140
3141     /* All future communication with the client will be encrypted.  */
3142
3143     buf_to_net = krb_encrypt_buffer_initialize (buf_to_net, 0, sched,
3144                                                 kblock,
3145                                                 buf_to_net->memory_error);
3146     buf_from_net = krb_encrypt_buffer_initialize (buf_from_net, 1, sched,
3147                                                   kblock,
3148                                                   buf_from_net->memory_error);
3149 }
3150
3151 #   endif /* HAVE_KERBEROS */
3152
3153 #   ifdef HAVE_GSSAPI
3154
3155 static void
3156 serve_gssapi_encrypt( char *arg )
3157 {
3158 #     ifdef PROXY_SUPPORT
3159     assert (!proxy_log);
3160 #     endif /* PROXY_SUPPORT */
3161
3162     if (cvs_gssapi_wrapping)
3163     {
3164         /* We're already using a gssapi_wrap buffer for stream
3165            authentication.  Flush everything we've output so far, and
3166            turn on encryption for future data.  On the input side, we
3167            should only have unwrapped as far as the Gssapi-encrypt
3168            command, so future unwrapping will become encrypted.  */
3169         buf_flush (buf_to_net, 1);
3170         cvs_gssapi_encrypt = 1;
3171         return;
3172     }
3173
3174     /* All future communication with the client will be encrypted.  */
3175
3176     cvs_gssapi_encrypt = 1;
3177
3178     buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
3179                                                     gcontext,
3180                                                     buf_to_net->memory_error);
3181     buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
3182                                                       gcontext,
3183                                                       buf_from_net->memory_error);
3184
3185     cvs_gssapi_wrapping = 1;
3186 }
3187
3188 #   endif /* HAVE_GSSAPI */
3189
3190 # endif /* ENCRYPTION */
3191
3192 # ifdef HAVE_GSSAPI
3193
3194 static void
3195 serve_gssapi_authenticate (char *arg)
3196 {
3197 #   ifdef PROXY_SUPPORT
3198     assert (!proxy_log);
3199 #   endif /* PROXY_SUPPORT */
3200
3201     if (cvs_gssapi_wrapping)
3202     {
3203         /* We're already using a gssapi_wrap buffer for encryption.
3204            That includes authentication, so we don't have to do
3205            anything further.  */
3206         return;
3207     }
3208
3209     buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0,
3210                                                     gcontext,
3211                                                     buf_to_net->memory_error);
3212     buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1,
3213                                                       gcontext,
3214                                                       buf_from_net->memory_error);
3215
3216     cvs_gssapi_wrapping = 1;
3217 }
3218
3219 # endif /* HAVE_GSSAPI */
3220
3221
3222
3223 # ifdef SERVER_FLOWCONTROL
3224 /* The maximum we'll queue to the remote client before blocking.  */
3225 #   ifndef SERVER_HI_WATER
3226 #     define SERVER_HI_WATER (2 * 1024 * 1024)
3227 #   endif /* SERVER_HI_WATER */
3228 /* When the buffer drops to this, we restart the child */
3229 #   ifndef SERVER_LO_WATER
3230 #     define SERVER_LO_WATER (1 * 1024 * 1024)
3231 #   endif /* SERVER_LO_WATER */
3232 # endif /* SERVER_FLOWCONTROL */
3233
3234
3235
3236 static void
3237 serve_questionable (char *arg)
3238 {
3239     static int initted;
3240
3241 # ifdef PROXY_SUPPORT
3242     if (proxy_log) return;
3243 # endif /* PROXY_SUPPORT */
3244
3245     if (error_pending ()) return;
3246
3247     if (!initted)
3248     {
3249         /* Pick up ignores from CVSROOTADM_IGNORE, $HOME/.cvsignore on server,
3250            and CVSIGNORE on server.  */
3251         ign_setup ();
3252         initted = 1;
3253     }
3254
3255     if (gDirname == NULL)
3256     {
3257         if (alloc_pending (80))
3258             sprintf (pending_error_text,
3259 "E Protocol error: `Directory' missing");
3260         return;
3261     }
3262
3263     if (outside_dir (arg))
3264         return;
3265
3266     if (!ign_name (arg))
3267     {
3268         char *update_dir;
3269
3270         buf_output (buf_to_net, "M ? ", 4);
3271         update_dir = gDirname + strlen (server_temp_dir) + 1;
3272         if (!(update_dir[0] == '.' && update_dir[1] == '\0'))
3273         {
3274             buf_output0 (buf_to_net, update_dir);
3275             buf_output (buf_to_net, "/", 1);
3276         }
3277         buf_output0 (buf_to_net, arg);
3278         buf_output (buf_to_net, "\n", 1);
3279     }
3280 }
3281
3282
3283
3284 static struct buffer *protocol = NULL;
3285
3286 /* This is the output which we are saving up to send to the server, in the
3287    child process.  We will push it through, via the `protocol' buffer, when
3288    we have a complete line.  */
3289 static struct buffer *saved_output;
3290
3291 /* Likewise, but stuff which will go to stderr.  */
3292 static struct buffer *saved_outerr;
3293
3294
3295
3296 static void
3297 protocol_memory_error (struct buffer *buf)
3298 {
3299     error (1, ENOMEM, "Virtual memory exhausted");
3300 }
3301
3302
3303
3304 /* If command is valid, return 1.
3305  * Else if command is invalid and croak_on_invalid is set, then die.
3306  * Else just return 0 to indicate that command is invalid.
3307  */
3308 static bool
3309 check_command_valid_p (char *cmd_name)
3310 {
3311     /* Right now, only pserver notices invalid commands -- namely,
3312      * write attempts by a read-only user.  Therefore, if CVS_Username
3313      * is not set, this just returns 1, because CVS_Username unset
3314      * means pserver is not active.
3315      */
3316 # ifdef AUTH_SERVER_SUPPORT
3317     if (CVS_Username == NULL)
3318         return true;
3319
3320     if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY)
3321     {
3322         /* This command has the potential to modify the repository, so
3323          * we check if the user have permission to do that.
3324          *
3325          * (Only relevant for remote users -- local users can do
3326          * whatever normal Unix file permissions allow them to do.)
3327          *
3328          * The decision method:
3329          *
3330          *    If $CVSROOT/CVSADMROOT_READERS exists and user is listed
3331          *    in it, then read-only access for user.
3332          *
3333          *    Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT
3334          *    listed in it, then also read-only access for user.
3335          *
3336          *    Else read-write access for user.
3337          */
3338
3339          char *linebuf = NULL;
3340          int num_red = 0;
3341          size_t linebuf_len = 0;
3342          char *fname;
3343          size_t flen;