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