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