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