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