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