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