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