Bug Summary

File:src/gnu/usr.bin/cvs/src/server.c
Warning:line 819, column 5
Potential leak of memory pointed to by 'env'

Annotated Source Code

Press '?' to see keyboard shortcuts

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