Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / supfilesrv.c
blob0d0a698189e8550be4c34aa644e3a111fe2f9106
1 /* $NetBSD: supfilesrv.c,v 1.42 2009/10/16 12:41:37 christos Exp $ */
3 /*
4 * Copyright (c) 1992 Carnegie Mellon University
5 * All Rights Reserved.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
29 * supfilesrv -- SUP File Server
31 * Usage: supfilesrv [-d] [-l] [-P] [-N] [-R] [-S]
32 * -d "debug" -- don't fork daemon
33 * -l "log" -- print successull connects (when compiled with libwrap)
34 * -P "debug ports" -- use debugging network ports
35 * -N "debug network" -- print debugging messages for network i/o
36 * -R "RCS mode" -- if file is an rcs file, use co to get contents
37 * -S "Operate silently" -- Only print error messages
39 **********************************************************************
40 * HISTORY
41 * 2-Aug-99 Manuel Bouyer at LIP6
42 * Added libwrap support
44 * 13-Sep-92 Mary Thompson (mrt) at Carnegie-Mellon University
45 * Changed name of sup program in xpatch from /usr/cs/bin/sup to
46 * /usr/bin/sup for exported version of sup.
48 * 7-July-93 Nate Williams at Montana State University
49 * Modified SUP to use gzip based compression when sending files
50 * across the network to save BandWidth
52 * Revision 1.20 92/09/09 22:05:00 mrt
53 * Added Brad's change to make send_file take a va_list.
54 * Added support in login to accept an non-encrypted login
55 * message if no user or password is being sent. This supports
56 * a non-crypting version of sup. Also fixed to skip leading
57 * white space from crypts in host files.
58 * [92/09/01 mrt]
60 * Revision 1.19 92/08/11 12:07:59 mrt
61 * Made maxchildren a patchable variable, which can be set by the
62 * command line switch -C or else defaults to the MAXCHILDREN
63 * defined in sup.h. Added most of Brad's STUMP changes.
64 * Increased PGMVERSION to 12 to reflect substantial changes.
65 * [92/07/28 mrt]
67 * Revision 1.18 90/12/25 15:15:39 ern
68 * Yet another rewrite of the logging code. Make up the text we will write
69 * and then get in, write it and get out.
70 * Also set error on write-to-full-disk if the logging is for recording
71 * server is busy.
72 * [90/12/25 15:15:15 ern]
74 * Revision 1.17 90/05/07 09:31:13 dlc
75 * Sigh, some more fixes to the new "crypt" file handling code. First,
76 * just because the "crypt" file is in a local file system does not mean
77 * it can be trusted. We have to check for hard links to root owned
78 * files whose contents could be interpretted as a crypt key. For
79 * checking this fact, the new routine stat_info_ok() was added. This
80 * routine also makes other sanity checks, such as owner only permission,
81 * the file is a regular file, etc. Also, even if the uid/gid of th
82 * "crypt" file is not going to be used, still use its contents in order
83 * to cause fewer surprises to people supping out of a shared file system
84 * such as AFS.
85 * [90/05/07 dlc]
87 * Revision 1.16 90/04/29 04:21:08 dlc
88 * Fixed logic bug in docrypt() which would not get the stat information
89 * from the crypt file if the crypt key had already been set from a
90 * "host" file.
91 * [90/04/29 dlc]
93 * Revision 1.15 90/04/18 19:51:27 dlc
94 * Added the new routines local_file(), link_nofollow() for use in
95 * dectecting whether a file is located in a local file system. These
96 * routines probably should have been in another module, but only
97 * supfilesrv needs to do the check and none of its other modules seemed
98 * appropriate. Note, the implementation should be changed once we have
99 * direct kernel support, for example the fstatvfs(2) system call, for
100 * detecting the type of file system a file resides. Also, I changed
101 * the routines which read the crosspatch crypt file or collection crypt
102 * file to save the uid and gid from the stat information obtained via
103 * the local_file() call (when the file is local) at the same time the
104 * crypt key is read. This change disallows non-local files for the
105 * crypt key to plug a security hole involving the usage of the uid/gid
106 * of the crypt file to define who the file server should run as. If
107 * the saved uid/gid are both valid, then the server will set its uid/gid
108 * to these values.
109 * [90/04/18 dlc]
111 * Revision 1.14 89/08/23 14:56:15 gm0w
112 * Changed msgf routines to msg routines.
113 * [89/08/23 gm0w]
115 * Revision 1.13 89/08/03 19:57:33 mja
116 * Remove setaid() call.
118 * Revision 1.12 89/08/03 19:49:24 mja
119 * Updated to use v*printf() in place of _doprnt().
120 * [89/04/19 mja]
122 * 11-Sep-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
123 * Added code to record release name in logfile.
125 * 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
126 * Added host=<hostfile> support to releases file. [V7.12]
128 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
129 * Added crosspatch support. Created docrypt() routine for crypt
130 * test message.
132 * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
133 * Removed common information logging code, the quiet switch, and
134 * moved samehost() check to after device/inode check.
136 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
137 * Added code for "release" support. [V5.11]
139 * 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
140 * Added code to record final status of client in logfile. [V5.10]
142 * 22-May-87 Chriss Stephens (chriss) at Carnegie Mellon University
143 * Mergered divergent CS and ECE versions. [V5.9a]
145 * 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
146 * Removed support for version 3 of SUP protocol. Added changes
147 * to make lint happy. Added calls to new logging routines. [V5.9]
149 * 31-Mar-87 Dan Nydick (dan) at Carnegie-Mellon University
150 * Fixed so no password check is done when crypts are used.
152 * 25-Nov-86 Rudy Nedved (ern) at Carnegie-Mellon University
153 * Set F_APPEND fcntl in logging to increase the chance
154 * that the log entry from this incarnation of the file
155 * server will not be lost by another incarnation. [V5.8]
157 * 20-Oct-86 Dan Nydick (dan) at Carnegie-Mellon University
158 * Changed not to call okmumbles when not compiled with CMUCS.
160 * 04-Aug-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
161 * Added code to increment scmdebug as more -N flags are
162 * added. [V5.7]
164 * 25-May-86 Jonathan J. Chew (jjc) at Carnegie-Mellon University
165 * Renamed local variable in main program from "sigmask" to
166 * "signalmask" to avoid name conflict with 4.3BSD identifier.
167 * Conditionally compile in calls to CMU routines, "setaid" and
168 * "logaccess". [V5.6]
170 * 21-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
171 * Changed supfilesrv to use the crypt file owner and group for
172 * access purposes, rather than the directory containing the crypt
173 * file. [V5.5]
175 * 07-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
176 * Added code to keep logfiles in repository collection directory.
177 * Added code for locking collections. [V5.4]
179 * 05-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
180 * Added code to support new FSETUPBUSY return. Now accepts all
181 * connections and tells any clients after the 8th that the
182 * fileserver is busy. New clients will retry again later. [V5.3]
184 * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
185 * Major rewrite for protocol version 4. [V4.2]
187 * 12-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
188 * Fixed close of crypt file to use file pointer as argument
189 * instead of string pointer.
191 * 24-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
192 * Allow "!hostname" lines and comments in collection "host" file.
194 * 13-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
195 * Don't use access() on symbolic links since they may not point to
196 * an existing file.
198 * 22-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
199 * Added code to restrict file server availability to when it has
200 * less than or equal to eight children.
202 * 22-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
203 * Merged 4.1 and 4.2 versions together.
205 * 04-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University
206 * Created for 4.2 BSD.
208 **********************************************************************
211 #ifdef AFS
212 #include <afs/param.h>
213 #undef MAXNAMLEN
214 #endif
215 #include <sys/param.h>
216 #include <signal.h>
217 #include <errno.h>
218 #include <setjmp.h>
219 #include <pwd.h>
220 #include <grp.h>
221 #include <fcntl.h>
222 #include <stdarg.h>
223 #include <sys/time.h>
224 #include <sys/resource.h>
225 #include <sys/wait.h>
226 #include <sys/stat.h>
227 #include <sys/file.h>
228 #include <sys/mount.h>
229 #include <sys/socket.h>
230 #ifndef HAS_POSIX_DIR
231 #include <sys/dir.h>
232 #else
233 #include <dirent.h>
234 #endif
235 #if MACH
236 #include <sys/ioctl.h>
237 #endif
238 #if CMUCS
239 #include <acc.h>
240 #include <sys/ttyloc.h>
241 #include <access.h>
242 #include <sys/viceioctl.h>
243 #else /* CMUCS */
244 #define ACCESS_CODE_OK 0
245 #define ACCESS_CODE_BADPASSWORD (-2)
246 #endif /* CMUCS */
248 #ifdef __SVR4
249 #include <sys/mkdev.h>
250 #include <sys/statvfs.h>
251 #endif
252 #ifdef LIBWRAP
253 #include <tcpd.h>
254 #endif
256 #include "supcdefs.h"
257 #include "supextern.h"
258 #define MSGFILE
259 #include "supmsg.h"
260 #include "libc.h"
261 #include "c.h"
263 extern char *crypt(const char *, const char *);
265 int maxchildren;
268 * These are used to save the stat information from the crosspatch crypt
269 * file or collection crypt file at the time it is opened for the crypt
270 * key and it is verified to be a local file.
272 int runas_uid = -1;
273 int runas_gid = -1;
275 #define PGMVERSION 13
277 /*************************
278 *** M A C R O S ***
279 *************************/
281 #define HASHBITS 8
282 #define HASHSIZE (1<<HASHBITS)
283 #define HASHMASK (HASHSIZE-1)
284 #define HASHFUNC(x,y) ((x)&HASHMASK)
286 /*******************************************
287 *** D A T A S T R U C T U R E S ***
288 *******************************************/
290 struct hashstruct { /* hash table for number lists */
291 int Hnum1; /* numeric keys */
292 int Hnum2;
293 char *Hname; /* string value */
294 TREE *Htree; /* TREE value */
295 struct hashstruct *Hnext;
297 typedef struct hashstruct HASH;
299 /*********************************************
300 *** G L O B A L V A R I A B L E S ***
301 *********************************************/
303 char program[] = "supfilesrv"; /* program name for SCM messages */
304 int progpid = -1; /* and process id */
306 jmp_buf sjbuf; /* jump location for network errors */
307 TREELIST *listTL; /* list of trees to upgrade */
309 int silent; /* -S flag */
310 #ifdef LIBWRAP
311 int sup_clog; /* -l flag */
312 #endif
313 int live; /* -d flag */
314 int dbgportsq; /* -P flag */
315 extern int scmdebug; /* -N flag */
316 extern int netfile;
317 #ifdef RCS
318 int candorcs; /* -R flag */
319 int dorcs = FALSE;
320 #endif
322 int nchildren; /* number of children that exist */
323 char *prefix; /* collection pathname prefix */
324 char *release; /* collection release name */
325 char *cryptkey; /* encryption key if non-null */
326 #ifdef CVS
327 char *cvs_root; /* RCS root */
328 #endif
329 char *rcs_branch; /* RCS branch name */
330 int lockfd; /* descriptor of lock file */
332 /* global variables for scan functions */
333 int trace = FALSE; /* directory scan trace */
334 int cancompress = FALSE; /* Can we compress files */
335 int docompress = FALSE; /* Do we compress files */
337 HASH *uidH[HASHSIZE]; /* for uid and gid lookup */
338 HASH *gidH[HASHSIZE];
339 HASH *inodeH[HASHSIZE]; /* for inode lookup for linked file check */
342 /* supfilesrv.c */
343 int main(int, char **);
344 void chldsig(int);
345 void usage(void);
346 void init(int, char **);
347 void answer(void);
348 void srvsignon(void);
349 void srvsetup(void);
350 void docrypt(void);
351 void srvlogin(void);
352 void listfiles(void);
353 int denyone(TREE *, void *);
354 void send_files(void);
355 int send_one(TREE *, void *);
356 int send_dir(TREE *, void *);
357 int send_file(TREE *, va_list);
358 void srvfinishup(time_t);
359 void Hfree(HASH **);
360 HASH *Hlookup(HASH **, int, int);
361 void Hinsert(HASH **, int, int, char *, TREE *);
362 TREE *linkcheck(TREE *, int, int);
363 char *uconvert(int);
364 char *gconvert(int);
365 char *changeuid(char *, char *, int, int);
366 void goaway(const char *, ...);
367 char *fmttime(time_t);
368 int local_file(int, struct stat *);
369 int stat_info_ok(struct stat *, struct stat *);
370 int link_nofollow(int);
371 int link_nofollow(int);
373 /*************************************
374 *** M A I N R O U T I N E ***
375 *************************************/
378 main(int argc, char **argv)
380 int x, pid;
381 sigset_t nset, oset;
382 struct sigaction chld, ign;
383 time_t tloc;
384 #ifdef LIBWRAP
385 struct request_info req;
386 #endif
388 /* initialize global variables */
389 pgmversion = PGMVERSION;/* export version number */
390 isserver = TRUE; /* export that we're not a server */
391 collname = NULL; /* no current collection yet */
392 maxchildren = MAXCHILDREN; /* defined in sup.h */
394 init(argc, argv); /* process arguments */
396 #ifdef HAS_DAEMON
397 if (!live) /* if not debugging, turn into daemon */
398 daemon(0, 0);
399 #endif
401 logopen("supfile");
402 tloc = time((time_t *) NULL);
403 loginfo("SUP File Server Version %d.%d (%s) starting at %s",
404 PROTOVERSION, PGMVERSION, scmversion, fmttime(tloc));
405 if (live) {
406 x = service();
408 if (x != SCMOK)
409 logquit(1, "Can't connect to network");
410 #ifdef LIBWRAP
411 request_init(&req, RQ_DAEMON, "supfilesrv", RQ_FILE, netfile,
412 NULL);
413 fromhost(&req);
414 if (hosts_access(&req) == 0) {
415 logdeny("refused connection from %.500s",
416 eval_client(&req));
417 servicekill();
418 exit(1);
420 if (sup_clog) {
421 logallow("connection from %.500s", eval_client(&req));
423 #endif
424 answer();
425 (void) serviceend();
426 exit(0);
428 ign.sa_handler = SIG_IGN;
429 sigemptyset(&ign.sa_mask);
430 ign.sa_flags = 0;
431 (void) sigaction(SIGHUP, &ign, NULL);
432 (void) sigaction(SIGINT, &ign, NULL);
433 (void) sigaction(SIGPIPE, &ign, NULL);
434 chld.sa_handler = chldsig;
435 sigemptyset(&chld.sa_mask);
436 chld.sa_flags = 0;
437 (void) sigaction(SIGCHLD, &chld, NULL);
438 nchildren = 0;
439 for (;;) {
440 x = service();
441 if (x != SCMOK) {
442 logerr("Error in establishing network connection");
443 (void) servicekill();
444 continue;
446 sigemptyset(&nset);
447 sigaddset(&nset, SIGCHLD);
448 sigprocmask(SIG_BLOCK, &nset, &oset);
449 if ((pid = fork()) == 0) { /* server process */
450 #ifdef LIBWRAP
451 request_init(&req, RQ_DAEMON, "supfilesrv", RQ_FILE,
452 netfile, NULL);
453 fromhost(&req);
454 if (hosts_access(&req) == 0) {
455 logdeny("refused connection from %.500s",
456 eval_client(&req));
457 servicekill();
458 exit(1);
460 if (sup_clog) {
461 logallow("connection from %.500s",
462 eval_client(&req));
464 #endif
465 (void) serviceprep();
466 answer();
467 (void) serviceend();
468 exit(0);
470 (void) servicekill(); /* parent */
471 if (pid > 0)
472 nchildren++;
473 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
477 * Child status signal handler
480 void
481 chldsig(int snum __unused)
483 int w;
485 while (wait3((int *) &w, WNOHANG, (struct rusage *) 0) > 0) {
486 if (nchildren)
487 nchildren--;
490 /*****************************************
491 *** I N I T I A L I Z A T I O N ***
492 *****************************************/
494 void
495 usage(void)
497 #ifdef LIBWRAP
498 quit(1, "Usage: supfilesrv [ -4 | -6 | -l | -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
499 #else
500 quit(1, "Usage: supfilesrv [ -4 | -6 | -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
501 #endif
504 void
505 init(int argc, char **argv)
507 int i;
508 int x;
509 char *clienthost, *clientuser;
510 char *p, *q;
511 char buf[STRINGLENGTH];
512 int maxsleep;
513 FILE *f;
514 int af = AF_INET;
516 #ifdef RCS
517 candorcs = FALSE;
518 #endif
519 live = FALSE;
520 #ifdef LIBWRAP
521 sup_clog = FALSE;
522 #endif
523 dbgportsq = FALSE;
524 scmdebug = 0;
525 clienthost = NULL;
526 clientuser = NULL;
527 maxsleep = 5;
528 if (--argc < 0)
529 usage();
530 argv++;
531 while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
532 switch (argv[0][1]) {
533 case 'S':
534 silent = TRUE;
535 break;
536 #ifdef LIBWRAP
537 case 'l':
538 sup_clog = TRUE;
539 break;
540 #endif
541 case 'd':
542 live = TRUE;
543 break;
544 case 'P':
545 dbgportsq = TRUE;
546 break;
547 case 'N':
548 scmdebug++;
549 break;
550 case 'C':
551 if (--argc < 1)
552 quit(1, "Missing arg to -C\n");
553 argv++;
554 maxchildren = atoi(argv[0]);
555 break;
556 case 'H':
557 if (--argc < 3)
558 quit(1, "Missing args to -H\n");
559 argv++;
560 clienthost = argv[0];
561 clientuser = argv[1];
562 cryptkey = argv[2];
563 argc -= 2;
564 argv += 2;
565 break;
566 #ifdef RCS
567 case 'R':
568 candorcs = TRUE;
569 break;
570 #endif
571 case '4':
572 af = AF_INET;
573 break;
574 #ifdef AF_INET6
575 case '6':
576 af = AF_INET6;
577 break;
578 #endif
579 default:
580 fprintf(stderr, "Unknown flag %s ignored\n", argv[0]);
581 break;
583 --argc;
584 argv++;
586 if (clienthost == NULL) {
587 if (argc != 0)
588 usage();
589 x = servicesetup(dbgportsq ? DEBUGFPORT : FILEPORT, af);
590 if (x != SCMOK)
591 quit(1, "Error in network setup");
592 for (i = 0; i < HASHSIZE; i++)
593 uidH[i] = gidH[i] = inodeH[i] = NULL;
594 return;
596 isserver = FALSE;
597 if (argc < 1)
598 usage();
599 f = fopen(cryptkey, "r");
600 if (f == NULL)
601 quit(1, "Unable to open cryptfile %s\n", cryptkey);
602 if ((p = fgets(buf, STRINGLENGTH, f)) != NULL) {
603 if ((q = strchr(p, '\n')) != NULL)
604 *q = '\0';
605 if (*p == '\0')
606 quit(1, "No cryptkey found in %s\n", cryptkey);
607 cryptkey = estrdup(buf);
609 (void) fclose(f);
610 x = request(dbgportsq ? DEBUGFPORT : FILEPORT, clienthost, &maxsleep);
611 if (x != SCMOK)
612 quit(1, "Unable to connect to host %s\n", clienthost);
613 x = msgsignon();
614 if (x != SCMOK)
615 quit(1, "Error sending signon request to fileserver\n");
616 x = msgsignonack();
617 if (x != SCMOK)
618 quit(1, "Error reading signon reply from fileserver\n");
619 printf("SUP Fileserver %d.%d (%s) %d on %s\n",
620 protver, pgmver, scmver, fspid, remotehost());
621 free(scmver);
622 scmver = NULL;
623 if (protver < 7)
624 quit(1, "Remote fileserver does not implement reverse sup\n");
625 xpatch = TRUE;
626 xuser = clientuser;
627 x = msgsetup();
628 if (x != SCMOK)
629 quit(1, "Error sending setup request to fileserver\n");
630 x = msgsetupack();
631 if (x != SCMOK)
632 quit(1, "Error reading setup reply from fileserver\n");
633 switch (setupack) {
634 case FSETUPOK:
635 break;
636 case FSETUPSAME:
637 quit(1, "User %s not found on remote client\n", xuser);
638 case FSETUPHOST:
639 quit(1, "This host has no permission to reverse sup\n");
640 default:
641 quit(1, "Unrecognized file server setup status %d\n", setupack);
643 if (netcrypt(cryptkey) != SCMOK)
644 quit(1, "Running non-crypting fileserver\n");
645 crypttest = CRYPTTEST;
646 x = msgcrypt();
647 if (x != SCMOK)
648 quit(1, "Error sending encryption test request\n");
649 x = msgcryptok();
650 if (x == SCMEOF)
651 quit(1, "Data encryption test failed\n");
652 if (x != SCMOK)
653 quit(1, "Error reading encryption test reply\n");
654 logcrypt = CRYPTTEST;
655 loguser = NULL;
656 logpswd = NULL;
657 if (netcrypt(PSWDCRYPT) != SCMOK) /* encrypt password data */
658 quit(1, "Running non-crypting fileserver\n");
659 x = msglogin();
660 (void) netcrypt((char *) NULL); /* turn off encryption */
661 if (x != SCMOK)
662 quit(1, "Error sending login request to file server\n");
663 x = msglogack();
664 if (x != SCMOK)
665 quit(1, "Error reading login reply from file server\n");
666 if (logack == FLOGNG)
667 quit(1, "%s\nImproper login to %s account\n", logerror, xuser);
668 xargc = argc;
669 xargv = argv;
670 x = msgxpatch();
671 if (x != SCMOK)
672 quit(1, "Error sending crosspatch request\n");
673 crosspatch();
674 exit(0);
676 /*****************************************
677 *** A N S W E R R E Q U E S T ***
678 *****************************************/
680 void
681 answer(void)
683 time_t starttime;
684 int x;
686 progpid = fspid = getpid();
687 collname = NULL;
688 basedir = NULL;
689 prefix = NULL;
690 release = NULL;
691 rcs_branch = NULL;
692 #ifdef CVS
693 cvs_root = NULL;
694 #endif
695 goawayreason = NULL;
696 donereason = NULL;
697 lockfd = -1;
698 starttime = time((time_t *) NULL);
699 if (!setjmp(sjbuf)) {
700 srvsignon();
701 srvsetup();
702 docrypt();
703 srvlogin();
704 if (xpatch) {
705 int fd;
707 x = msgxpatch();
708 if (x != SCMOK)
709 exit(0);
710 xargv[0] = "sup";
711 xargv[1] = "-X";
712 xargv[xargc] = (char *) NULL;
713 (void) dup2(netfile, 0);
714 (void) dup2(netfile, 1);
715 (void) dup2(netfile, 2);
716 fd = getdtablesize();
717 while (--fd > 2)
718 (void) close(fd);
719 execvp(xargv[0], xargv);
720 exit(0);
722 listfiles();
723 send_files();
725 srvfinishup(starttime);
726 if (collname)
727 free(collname);
728 if (basedir)
729 free(basedir);
730 if (prefix)
731 free(prefix);
732 if (release)
733 free(release);
734 if (rcs_branch)
735 free(rcs_branch);
736 #ifdef CVS
737 if (cvs_root)
738 free(cvs_root);
739 #endif
740 if (goawayreason) {
741 if (donereason == goawayreason)
742 donereason = NULL;
743 free(goawayreason);
745 if (donereason)
746 free(donereason);
747 if (lockfd >= 0)
748 (void) close(lockfd);
749 endpwent();
750 (void) endgrent();
751 #if CMUCS
752 endacent();
753 #endif /* CMUCS */
754 Hfree(uidH);
755 Hfree(gidH);
756 Hfree(inodeH);
758 /*****************************************
759 *** S I G N O N C L I E N T ***
760 *****************************************/
762 void
763 srvsignon(void)
765 int x;
767 xpatch = FALSE;
768 x = msgsignon();
769 if (x != SCMOK)
770 goaway("Error reading signon request from client");
771 x = msgsignonack();
772 if (x != SCMOK)
773 goaway("Error sending signon reply to client");
774 free(scmver);
775 scmver = NULL;
777 /*****************************************************************
778 *** E X C H A N G E S E T U P I N F O R M A T I O N ***
779 *****************************************************************/
781 void
782 srvsetup(void)
784 int x;
785 char *p, *q;
786 char buf[STRINGLENGTH];
787 FILE *f;
788 struct stat sbuf;
789 TREELIST *tl;
791 if (protver > 7) {
792 cancompress = TRUE;
794 x = msgsetup();
795 if (x != SCMOK)
796 goaway("Error reading setup request from client");
797 if (protver < 4) {
798 setupack = FSETUPOLD;
799 (void) msgsetupack();
800 if (protver >= 6)
801 longjmp(sjbuf, TRUE);
802 goaway("Sup client using obsolete version of protocol");
804 if (xpatch) {
805 struct passwd *pw;
807 if ((pw = getpwnam(xuser)) == NULL) {
808 setupack = FSETUPSAME;
809 (void) msgsetupack();
810 if (protver >= 6)
811 longjmp(sjbuf, TRUE);
812 goaway("User `%s' not found", xuser);
814 (void) free(xuser);
815 xuser = estrdup(pw->pw_dir);
817 /* check crosspatch host access file */
818 cryptkey = NULL;
819 (void) sprintf(buf, FILEXPATCH, xuser);
821 /* Turn off link following */
822 if (link_nofollow(1) != -1) {
823 int hostok = FALSE;
824 /* get stat info before open */
825 if (stat(buf, &sbuf) == -1)
826 (void) bzero(&sbuf, sizeof(sbuf));
828 if ((f = fopen(buf, "r")) != NULL) {
829 struct stat fsbuf;
831 while ((p = fgets(buf, STRINGLENGTH, f)) != NULL) {
832 q = strchr(p, '\n');
833 if (q)
834 *q = 0;
835 if (strchr("#;:", *p))
836 continue;
837 q = nxtarg(&p, " \t");
838 if (*p == '\0')
839 continue;
840 if (!matchhost(q))
841 continue;
843 cryptkey = estrdup(p);
844 hostok = TRUE;
845 if (local_file(fileno(f), &fsbuf) > 0
846 && stat_info_ok(&sbuf, &fsbuf)) {
847 runas_uid = sbuf.st_uid;
848 runas_gid = sbuf.st_gid;
850 break;
852 (void) fclose(f);
854 /* Restore link following */
855 if (link_nofollow(0) == -1)
856 goaway("Restore link following");
858 if (!hostok) {
859 setupack = FSETUPHOST;
860 (void) msgsetupack();
861 if (protver >= 6)
862 longjmp(sjbuf, TRUE);
863 goaway("Host not on access list");
866 setupack = FSETUPOK;
867 x = msgsetupack();
868 if (x != SCMOK)
869 goaway("Error sending setup reply to client");
870 return;
872 #ifdef RCS
873 if (candorcs && release != NULL &&
874 (strncmp(release, "RCS.", 4) == 0)) {
875 rcs_branch = estrdup(&release[4]);
876 free(release);
877 release = estrdup("RCS");
878 dorcs = TRUE;
880 #endif
881 if (release == NULL)
882 release = estrdup(DEFRELEASE);
883 if (basedir == NULL || *basedir == '\0') {
884 basedir = NULL;
885 (void) sprintf(buf, FILEDIRS, DEFDIR);
886 f = fopen(buf, "r");
887 if (f) {
888 while ((p = fgets(buf, STRINGLENGTH, f)) != NULL) {
889 q = strchr(p, '\n');
890 if (q)
891 *q = 0;
892 if (strchr("#;:", *p))
893 continue;
894 q = nxtarg(&p, " \t=");
895 if (strcmp(q, collname) == 0) {
896 basedir = skipover(p, " \t=");
897 basedir = estrdup(basedir);
898 break;
901 (void) fclose(f);
903 if (basedir == NULL) {
904 (void) sprintf(buf, FILEBASEDEFAULT, collname);
905 basedir = estrdup(buf);
908 if (chdir(basedir) < 0)
909 goaway("Can't chdir to base directory %s", basedir);
910 (void) sprintf(buf, FILEPREFIX, collname);
911 f = fopen(buf, "r");
912 if (f) {
913 while ((p = fgets(buf, STRINGLENGTH, f)) != NULL) {
914 q = strchr(p, '\n');
915 if (q)
916 *q = 0;
917 if (strchr("#;:", *p))
918 continue;
919 prefix = estrdup(p);
920 if (chdir(prefix) < 0)
921 goaway("Can't chdir to %s from base directory %s",
922 prefix, basedir);
923 break;
925 (void) fclose(f);
927 x = stat(".", &sbuf);
928 if (prefix)
929 (void) chdir(basedir);
930 if (x < 0)
931 goaway("Can't stat base/prefix directory");
932 if (nchildren >= maxchildren) {
933 setupack = FSETUPBUSY;
934 (void) msgsetupack();
935 if (protver >= 6)
936 longjmp(sjbuf, TRUE);
937 goaway("Sup client told to try again later");
939 if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
940 setupack = FSETUPSAME;
941 (void) msgsetupack();
942 if (protver >= 6)
943 longjmp(sjbuf, TRUE);
944 goaway("Attempt to upgrade to same directory on same host");
946 /* obtain release information */
947 if (!getrelease(release)) {
948 setupack = FSETUPRELEASE;
949 (void) msgsetupack();
950 if (protver >= 6)
951 longjmp(sjbuf, TRUE);
952 goaway("Invalid release information");
954 /* check host access file */
955 cryptkey = NULL;
956 for (tl = listTL; tl != NULL; tl = tl->TLnext) {
957 char *h;
958 if ((h = tl->TLhost) == NULL)
959 h = FILEHOSTDEF;
960 (void) sprintf(buf, FILEHOST, collname, h);
961 f = fopen(buf, "r");
962 if (f) {
963 int hostok = FALSE;
964 while ((p = fgets(buf, STRINGLENGTH, f)) != NULL) {
965 int not;
966 q = strchr(p, '\n');
967 if (q)
968 *q = 0;
969 if (strchr("#;:", *p))
970 continue;
971 q = nxtarg(&p, " \t");
972 if ((not = (*q == '!')) && *++q == '\0')
973 q = nxtarg(&p, " \t");
974 hostok = (not == (matchhost(q) == 0));
975 if (hostok) {
976 while ((*p == ' ') || (*p == '\t'))
977 p++;
978 if (*p)
979 cryptkey = estrdup(p);
980 break;
983 (void) fclose(f);
984 if (!hostok) {
985 setupack = FSETUPHOST;
986 (void) msgsetupack();
987 if (protver >= 6)
988 longjmp(sjbuf, TRUE);
989 goaway("Host not on access list for %s",
990 collname);
994 /* try to lock collection */
995 (void) sprintf(buf, FILELOCK, collname);
996 #ifdef LOCK_SH
997 x = open(buf, O_RDONLY, 0);
998 if (x >= 0) {
999 if (flock(x, (LOCK_SH | LOCK_NB)) < 0) {
1000 (void) close(x);
1001 if (errno != EWOULDBLOCK)
1002 goaway("Can't lock collection %s", collname);
1003 setupack = FSETUPBUSY;
1004 (void) msgsetupack();
1005 if (protver >= 6)
1006 longjmp(sjbuf, TRUE);
1007 goaway("Sup client told to wait for lock");
1009 lockfd = x;
1011 #endif
1012 setupack = FSETUPOK;
1013 x = msgsetupack();
1014 if (x != SCMOK)
1015 goaway("Error sending setup reply to client");
1018 void
1019 /** Test data encryption **/
1020 docrypt(void)
1022 int x;
1023 char *p, *q;
1024 char buf[STRINGLENGTH];
1025 FILE *f;
1026 struct stat sbuf;
1028 if (!xpatch) {
1029 (void) sprintf(buf, FILECRYPT, collname);
1031 /* Turn off link following */
1032 if (link_nofollow(1) != -1) {
1033 /* get stat info before open */
1034 if (stat(buf, &sbuf) == -1)
1035 (void) bzero(&sbuf, sizeof(sbuf));
1037 if ((f = fopen(buf, "r")) != NULL) {
1038 struct stat fsbuf;
1040 if (cryptkey == NULL &&
1041 (p = fgets(buf, STRINGLENGTH, f))) {
1042 if ((q = strchr(p, '\n')) != NULL)
1043 *q = '\0';
1044 if (*p)
1045 cryptkey = estrdup(buf);
1047 if (local_file(fileno(f), &fsbuf) > 0
1048 && stat_info_ok(&sbuf, &fsbuf)) {
1049 runas_uid = sbuf.st_uid;
1050 runas_gid = sbuf.st_gid;
1052 (void) fclose(f);
1054 /* Restore link following */
1055 if (link_nofollow(0) == -1)
1056 goaway("Restore link following");
1059 if (netcrypt(cryptkey) != SCMOK)
1060 goaway("Runing non-crypting supfilesrv");
1061 x = msgcrypt();
1062 if (x != SCMOK)
1063 goaway("Error reading encryption test request from client");
1064 (void) netcrypt((char *) NULL);
1065 if (strcmp(crypttest, CRYPTTEST) != 0)
1066 goaway("Client not encrypting data properly");
1067 free(crypttest);
1068 crypttest = NULL;
1069 x = msgcryptok();
1070 if (x != SCMOK)
1071 goaway("Error sending encryption test reply to client");
1073 /***************************************************************
1074 *** C O N N E C T T O P R O P E R A C C O U N T ***
1075 ***************************************************************/
1077 void
1078 srvlogin(void)
1080 int x, fileuid = -1, filegid = -1;
1082 (void) netcrypt(PSWDCRYPT); /* encrypt acct name and password */
1083 x = msglogin();
1084 (void) netcrypt((char *) NULL); /* turn off encryption */
1085 if (x != SCMOK)
1086 goaway("Error reading login request from client");
1087 if (logcrypt) {
1088 if (strcmp(logcrypt, CRYPTTEST) != 0) {
1089 logack = FLOGNG;
1090 logerror = "Improper login encryption";
1091 (void) msglogack();
1092 goaway("Client not encrypting login information properly");
1094 free(logcrypt);
1095 logcrypt = NULL;
1097 if (loguser == NULL) {
1098 if (cryptkey) {
1099 if (runas_uid >= 0 && runas_gid >= 0) {
1100 fileuid = runas_uid;
1101 filegid = runas_gid;
1102 loguser = NULL;
1103 } else
1104 loguser = estrdup(DEFUSER);
1105 } else
1106 loguser = estrdup(DEFUSER);
1108 if ((logerror = changeuid(loguser, logpswd, fileuid, filegid)) != NULL) {
1109 logack = FLOGNG;
1110 (void) msglogack();
1111 if (protver >= 6)
1112 longjmp(sjbuf, TRUE);
1113 goaway("Client denied login access");
1115 if (loguser)
1116 free(loguser);
1117 if (logpswd)
1118 free(logpswd);
1119 logack = FLOGOK;
1120 x = msglogack();
1121 if (x != SCMOK)
1122 goaway("Error sending login reply to client");
1123 if (!xpatch) /* restore desired encryption */
1124 if (netcrypt(cryptkey) != SCMOK)
1125 goaway("Running non-crypting supfilesrv");
1126 free(cryptkey);
1127 cryptkey = NULL;
1129 /*****************************************
1130 *** M A K E N A M E L I S T ***
1131 *****************************************/
1133 void
1134 listfiles(void)
1136 int x;
1138 refuseT = NULL;
1139 x = msgrefuse();
1140 if (x != SCMOK)
1141 goaway("Error reading refuse list from client");
1142 getscanlists();
1143 Tfree(&refuseT);
1144 x = msglist();
1145 if (x != SCMOK)
1146 goaway("Error sending file list to client");
1147 Tfree(&listT);
1148 listT = NULL;
1149 needT = NULL;
1150 x = msgneed();
1151 if (x != SCMOK)
1152 goaway("Error reading needed files list from client");
1153 denyT = NULL;
1154 (void) Tprocess(needT, denyone, NULL);
1155 Tfree(&needT);
1156 x = msgdeny();
1157 if (x != SCMOK)
1158 goaway("Error sending denied files list to client");
1159 Tfree(&denyT);
1164 denyone(TREE * t, void *v __unused)
1166 TREELIST *tl;
1167 char *name = t->Tname;
1168 int update = (t->Tflags & FUPDATE) != 0;
1169 struct stat sbuf;
1170 TREE *tlink;
1171 char slinkname[STRINGLENGTH];
1172 int x;
1174 for (tl = listTL; tl != NULL; tl = tl->TLnext)
1175 if ((t = Tsearch(tl->TLtree, name)) != NULL)
1176 break;
1177 if (t == NULL) {
1178 (void) Tinsert(&denyT, name, FALSE);
1179 return (SCMOK);
1181 cdprefix(tl->TLprefix);
1182 if (S_ISLNK(t->Tmode))
1183 x = lstat(name, &sbuf);
1184 else
1185 x = stat(name, &sbuf);
1186 if (x < 0 || (sbuf.st_mode & S_IFMT) != (t->Tmode & S_IFMT)) {
1187 (void) Tinsert(&denyT, name, FALSE);
1188 return (SCMOK);
1190 switch (t->Tmode & S_IFMT) {
1191 case S_IFLNK:
1192 if ((x = readlink(name, slinkname, STRINGLENGTH - 1)) <= 0) {
1193 (void) Tinsert(&denyT, name, FALSE);
1194 return (SCMOK);
1196 slinkname[x] = '\0';
1197 (void) Tinsert(&t->Tlink, slinkname, FALSE);
1198 break;
1199 case S_IFREG:
1200 if (sbuf.st_nlink > 1 &&
1201 (tlink = linkcheck(t, (int) sbuf.st_dev, (int) sbuf.st_ino))) {
1202 (void) Tinsert(&tlink->Tlink, name, FALSE);
1203 return (SCMOK);
1205 if (update)
1206 t->Tflags |= FUPDATE;
1207 case S_IFDIR:
1208 t->Tuid = sbuf.st_uid;
1209 t->Tgid = sbuf.st_gid;
1210 break;
1211 default:
1212 (void) Tinsert(&denyT, name, FALSE);
1213 return (SCMOK);
1215 t->Tflags |= FNEEDED;
1216 return (SCMOK);
1218 /*********************************
1219 *** S E N D F I L E S ***
1220 *********************************/
1222 void
1223 send_files(void)
1225 TREELIST *tl;
1226 int x;
1228 /* Does the protocol support compression */
1229 if (cancompress) {
1230 /* Check for compression on sending files */
1231 x = msgcompress();
1232 if (x != SCMOK)
1233 goaway("Error sending compression check to server");
1235 /* send all files */
1236 for (tl = listTL; tl != NULL; tl = tl->TLnext) {
1237 cdprefix(tl->TLprefix);
1238 #ifdef CVS
1239 if (candorcs) {
1240 cvs_root = getcwd(NULL, 256);
1241 if (access("CVSROOT", F_OK) < 0)
1242 dorcs = FALSE;
1243 else {
1244 loginfo("is a CVSROOT \"%s\"\n", cvs_root);
1245 dorcs = TRUE;
1248 #endif
1249 (void) Tprocess(tl->TLtree, send_one, NULL);
1251 /* send directories in reverse order */
1252 for (tl = listTL; tl != NULL; tl = tl->TLnext) {
1253 cdprefix(tl->TLprefix);
1254 (void) Trprocess(tl->TLtree, send_dir, NULL);
1256 x = msgsend();
1257 if (x != SCMOK)
1258 goaway("Error reading receive file request from client");
1259 upgradeT = NULL;
1260 x = msgrecv(send_file, 0);
1261 if (x != SCMOK)
1262 goaway("Error sending file to client");
1266 send_one(TREE * t, void *v __unused)
1268 int x, fd;
1269 char temp_file[STRINGLENGTH];
1270 char *av[50]; /* More than enough */
1272 if ((t->Tflags & FNEEDED) == 0) /* only send needed files */
1273 return (SCMOK);
1274 if (S_ISDIR(t->Tmode)) /* send no directories this pass */
1275 return (SCMOK);
1276 x = msgsend();
1277 if (x != SCMOK)
1278 goaway("Error reading receive file request from client");
1279 upgradeT = t; /* upgrade file pointer */
1280 fd = -1; /* no open file */
1281 if (S_ISREG(t->Tmode)) {
1282 if (!listonly && (t->Tflags & FUPDATE) == 0) {
1283 #ifdef RCS
1284 if (dorcs) {
1285 char rcs_release[STRINGLENGTH];
1287 tmpnam(rcs_file);
1288 fd = open(rcs_file, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1289 if (fd < 0)
1290 goaway("We died trying to create temp file");
1291 close(fd);
1292 fd = -1;
1293 if (strcmp(&t->Tname[strlen(t->Tname) - 2], ",v") == 0) {
1294 t->Tname[strlen(t->Tname) - 2] = '\0';
1295 ac = 0;
1296 #ifdef CVS
1297 av[ac++] = "cvs";
1298 av[ac++] = "-d";
1299 av[ac++] = cvs_root;
1300 av[ac++] = "-r";
1301 av[ac++] = "-l";
1302 av[ac++] = "-Q";
1303 av[ac++] = "co";
1304 av[ac++] = "-p";
1305 if (rcs_branch != NULL) {
1306 av[ac++] = "-r";
1307 av[ac++] = rcs_branch;
1309 #else
1310 av[ac++] = "co";
1311 av[ac++] = "-q";
1312 av[ac++] = "-p";
1313 if (rcs_branch != NULL) {
1314 sprintf(rcs_release, "-r%s",
1315 rcs_branch);
1316 av[ac++] = rcs_release;
1318 #endif
1319 av[ac++] = t->Tname;
1320 av[ac++] = NULL;
1321 status = runio(av, NULL, rcs_file,
1322 "/dev/null");
1323 /* loginfo("using rcs mode \n"); */
1324 if (status < 0 || WEXITSTATUS(status)) {
1325 /* Just in case */
1326 unlink(rcs_file);
1327 if (status < 0) {
1328 goaway("We died trying to run cvs or rcs on %s", rcs_file);
1329 t->Tmode = 0;
1330 } else {
1331 #if 0
1332 logerr("rcs command failed = %d\n",
1333 WEXITSTATUS(status));
1334 #endif
1335 t->Tflags |= FUPDATE;
1337 } else if (docompress) {
1338 tmpnam(temp_file);
1339 av[0] = "gzip";
1340 av[1] = "-cf";
1341 av[2] = NULL;
1342 if (runio(av, rcs_file, temp_file, NULL) != 0) {
1343 /* Just in case */
1344 unlink(temp_file);
1345 unlink(rcs_file);
1346 goaway("We died trying to gzip %s", rcs_file);
1347 t->Tmode = 0;
1349 fd = open(temp_file, O_RDONLY, 0);
1350 } else
1351 fd = open(rcs_file, O_RDONLY, 0);
1354 #endif
1355 if (fd == -1) {
1356 if (docompress) {
1357 snprintf(temp_file, sizeof(temp_file),
1358 "%s/supfilesrv.XXXXXX", P_tmpdir);
1359 fd = mkstemp(temp_file);
1360 if (fd < 0)
1361 goaway("We died trying to create temp file");
1362 close(fd);
1363 fd = -1;
1364 av[0] = "gzip";
1365 av[1] = "-cf";
1366 av[2] = NULL;
1367 if (runio(av, t->Tname, temp_file, NULL) != 0) {
1368 /* Just in case */
1369 unlink(temp_file);
1370 goaway("We died trying to gzip %s", t->Tname);
1371 t->Tmode = 0;
1373 fd = open(temp_file, O_RDONLY, 0);
1374 } else
1375 fd = open(t->Tname, O_RDONLY, 0);
1377 if (fd < 0 && (t->Tflags & FUPDATE) == 0)
1378 t->Tmode = 0;
1380 if (t->Tmode) {
1381 t->Tuser = estrdup(uconvert(t->Tuid));
1382 t->Tgroup = estrdup(gconvert(t->Tgid));
1385 x = msgrecv(send_file, fd);
1386 if (docompress)
1387 unlink(temp_file);
1388 #ifdef RCS
1389 if (dorcs)
1390 unlink(rcs_file);
1391 #endif
1392 if (x != SCMOK)
1393 goaway("Error sending file %s to client", t->Tname);
1394 return (SCMOK);
1398 send_dir(TREE * t, void *v __unused)
1400 int x;
1402 if ((t->Tflags & FNEEDED) == 0) /* only send needed files */
1403 return (SCMOK);
1404 if (!S_ISDIR(t->Tmode)) /* send only directories this pass */
1405 return (SCMOK);
1406 x = msgsend();
1407 if (x != SCMOK)
1408 goaway("Error reading receive file request from client");
1409 upgradeT = t; /* upgrade file pointer */
1410 t->Tuser = estrdup(uconvert(t->Tuid));
1411 t->Tgroup = estrdup(gconvert(t->Tgid));
1412 x = msgrecv(send_file, 0);
1413 if (x != SCMOK)
1414 goaway("Error sending file %s to client", t->Tname);
1415 return (SCMOK);
1419 send_file(TREE * t, va_list ap)
1421 int x, fd;
1423 fd = va_arg(ap, int);
1424 if (!S_ISREG(t->Tmode) || listonly || (t->Tflags & FUPDATE))
1425 return (SCMOK);
1426 x = writefile(fd);
1427 if (x != SCMOK)
1428 goaway("Error sending file %s to client", t->Tname);
1429 (void) close(fd);
1430 return (SCMOK);
1432 /*****************************************
1433 *** E N D C O N N E C T I O N ***
1434 *****************************************/
1436 void
1437 srvfinishup(time_t starttime)
1439 int x = SCMOK;
1440 char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
1441 int logfd;
1442 time_t finishtime;
1443 char *releasename;
1445 (void) netcrypt((char *) NULL);
1446 if (protver < 6) {
1447 if (goawayreason != NULL)
1448 free(goawayreason);
1449 goawayreason = (char *) NULL;
1450 x = msggoaway();
1451 doneack = FDONESUCCESS;
1452 donereason = estrdup("Unknown");
1453 } else if (goawayreason == (char *) NULL)
1454 x = msgdone();
1455 else {
1456 doneack = FDONEGOAWAY;
1457 donereason = goawayreason;
1459 if (x == SCMEOF || x == SCMERR) {
1460 doneack = FDONEUSRERROR;
1461 donereason = estrdup("Premature EOF on network");
1462 } else if (x != SCMOK) {
1463 doneack = FDONESRVERROR;
1464 donereason = estrdup("Unknown SCM code");
1466 if (doneack == FDONEDONTLOG)
1467 return;
1468 if (donereason == NULL)
1469 donereason = estrdup("No reason");
1470 if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
1471 logerr("%s", donereason);
1472 else if (doneack == FDONEGOAWAY)
1473 logerr("GOAWAY: %s", donereason);
1474 else if (doneack != FDONESUCCESS)
1475 logerr("Reason %d: %s", doneack, donereason);
1476 goawayreason = donereason;
1477 cdprefix((char *) NULL);
1478 if (collname == NULL) {
1479 logerr("NULL collection in svrfinishup");
1480 return;
1482 (void) sprintf(lognam, FILELOGFILE, collname);
1483 if ((logfd = open(lognam, O_APPEND | O_WRONLY, 0644)) < 0)
1484 return; /* can not open file up...error */
1485 finishtime = time((time_t *) NULL);
1486 p = tmpbuf;
1487 (void) sprintf(p, "%s ", fmttime(lasttime));
1488 p += strlen(p);
1489 (void) sprintf(p, "%s ", fmttime(starttime));
1490 p += strlen(p);
1491 (void) sprintf(p, "%s ", fmttime(finishtime));
1492 p += strlen(p);
1493 if ((releasename = release) == NULL)
1494 releasename = "UNKNOWN";
1495 (void) sprintf(p, "%s %s %d %s\n", remotehost(), releasename,
1496 FDONESUCCESS - doneack, donereason);
1497 p += strlen(p);
1498 #if MACH
1499 /* if we are busy dont get stuck updating the disk if full */
1500 if (setupack == FSETUPBUSY) {
1501 long l = FIOCNOSPC_ERROR;
1502 ioctl(logfd, FIOCNOSPC, &l);
1504 #endif /* MACH */
1505 (void) write(logfd, tmpbuf, (p - tmpbuf));
1506 (void) close(logfd);
1508 /***************************************************
1509 *** H A S H T A B L E R O U T I N E S ***
1510 ***************************************************/
1512 void
1513 Hfree(HASH ** table)
1515 HASH *h;
1516 int i;
1517 for (i = 0; i < HASHSIZE; i++)
1518 while ((h = table[i]) != NULL) {
1519 table[i] = h->Hnext;
1520 if (h->Hname)
1521 free(h->Hname);
1522 free(h);
1526 HASH *
1527 Hlookup(HASH ** table, int num1, int num2)
1529 HASH *h;
1530 int hno;
1531 hno = HASHFUNC(num1, num2);
1532 for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
1533 return (h);
1536 void
1537 Hinsert(HASH ** table, int num1, int num2, char *name, TREE * tree)
1539 HASH *h;
1540 int hno;
1541 hno = HASHFUNC(num1, num2);
1542 h = (HASH *) malloc(sizeof(HASH));
1543 if (h == NULL)
1544 goaway("Cannot allocate memory");
1545 h->Hnum1 = num1;
1546 h->Hnum2 = num2;
1547 h->Hname = name;
1548 h->Htree = tree;
1549 h->Hnext = table[hno];
1550 table[hno] = h;
1552 /*********************************************
1553 *** U T I L I T Y R O U T I N E S ***
1554 *********************************************/
1556 TREE *
1557 linkcheck(TREE * t, int d, int i)
1558 /* inode # and device # */
1560 HASH *h;
1561 h = Hlookup(inodeH, i, d);
1562 if (h)
1563 return (h->Htree);
1564 Hinsert(inodeH, i, d, (char *) NULL, t);
1565 return ((TREE *) NULL);
1568 char *
1569 uconvert(int uid)
1571 struct passwd *pw;
1572 char *p;
1573 HASH *u;
1574 u = Hlookup(uidH, uid, 0);
1575 if (u)
1576 return (u->Hname);
1577 pw = getpwuid(uid);
1578 if (pw == NULL)
1579 return ("");
1580 p = estrdup(pw->pw_name);
1581 Hinsert(uidH, uid, 0, p, (TREE *) NULL);
1582 return (p);
1585 char *
1586 gconvert(int gid)
1588 struct group *gr;
1589 char *p;
1590 HASH *g;
1591 g = Hlookup(gidH, gid, 0);
1592 if (g)
1593 return (g->Hname);
1594 gr = getgrgid(gid);
1595 if (gr == NULL)
1596 return ("");
1597 p = estrdup(gr->gr_name);
1598 Hinsert(gidH, gid, 0, p, (TREE *) NULL);
1599 return (p);
1602 char *
1603 changeuid(char *namep, char *passwordp, int fileuid, int filegid)
1605 char *group, *account, *pswdp;
1606 struct passwd *pwd;
1607 struct group *grp;
1608 #if CMUCS
1609 struct account *acc;
1610 struct ttyloc tlc;
1611 #endif /* CMUCS */
1612 int status = ACCESS_CODE_OK;
1613 char nbuf[STRINGLENGTH];
1614 static char errbuf[STRINGLENGTH];
1615 #if CMUCS
1616 int *grps;
1617 #endif /* CMUCS */
1618 char *p = NULL;
1620 if (namep == NULL) {
1621 pwd = getpwuid(fileuid);
1622 if (pwd == NULL) {
1623 (void) sprintf(errbuf, "Reason: Unknown user id %d",
1624 fileuid);
1625 return (errbuf);
1627 grp = getgrgid(filegid);
1628 if (grp)
1629 group = strcpy(nbuf, grp->gr_name);
1630 else
1631 group = NULL;
1632 account = NULL;
1633 pswdp = NULL;
1634 } else {
1635 (void) strcpy(nbuf, namep);
1636 account = group = strchr(nbuf, ',');
1637 if (group != NULL) {
1638 *group++ = '\0';
1639 account = strchr(group, ',');
1640 if (account != NULL) {
1641 *account++ = '\0';
1642 if (*account == '\0')
1643 account = NULL;
1645 if (*group == '\0')
1646 group = NULL;
1648 pwd = getpwnam(nbuf);
1649 if (pwd == NULL) {
1650 (void) sprintf(errbuf, "Reason: Unknown user %s",
1651 nbuf);
1652 return (errbuf);
1654 if (strcmp(nbuf, DEFUSER) == 0)
1655 pswdp = NULL;
1656 else
1657 pswdp = passwordp ? passwordp : "";
1658 #ifdef AFS
1659 if (strcmp(nbuf, DEFUSER) != 0) {
1660 char *reason;
1661 setpag(); /* set a pag */
1662 if (ka_UserAuthenticate(pwd->pw_name, "", 0,
1663 pswdp, 1, &reason)) {
1664 (void) sprintf(errbuf, "AFS authentication failed, %s",
1665 reason);
1666 logerr("Attempt by %s; %s",
1667 nbuf, errbuf);
1668 return (errbuf);
1671 #endif
1673 if (getuid() != 0) {
1674 if (getuid() == pwd->pw_uid)
1675 return (NULL);
1676 if (strcmp(pwd->pw_name, DEFUSER) == 0)
1677 return (NULL);
1678 logerr("Fileserver not superuser");
1679 return ("Reason: fileserver is not running privileged");
1681 #if CMUCS
1682 tlc.tlc_hostid = TLC_UNKHOST;
1683 tlc.tlc_ttyid = TLC_UNKTTY;
1684 if (okaccess(pwd->pw_name, ACCESS_TYPE_SU, 0, -1, tlc) != 1)
1685 status = ACCESS_CODE_DENIED;
1686 else {
1687 grp = NULL;
1688 acc = NULL;
1689 status = oklogin(pwd->pw_name, group, &account, pswdp, &pwd, &grp, &acc, &grps);
1690 if (status == ACCESS_CODE_OK) {
1691 if ((p = okpassword(pswdp, pwd->pw_name, pwd->pw_gecos)) != NULL)
1692 status = ACCESS_CODE_INSECUREPWD;
1695 #else /* CMUCS */
1696 status = ACCESS_CODE_OK;
1697 if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
1698 if (pswdp == NULL || strcmp(pwd->pw_passwd, crypt(pswdp, pwd->pw_passwd)))
1699 status = ACCESS_CODE_BADPASSWORD;
1700 #endif /* CMUCS */
1701 switch (status) {
1702 case ACCESS_CODE_OK:
1703 break;
1704 case ACCESS_CODE_BADPASSWORD:
1705 p = "Reason: Invalid password";
1706 break;
1707 #if CMUCS
1708 case ACCESS_CODE_INSECUREPWD:
1709 (void) sprintf(errbuf, "Reason: %s", p);
1710 p = errbuf;
1711 break;
1712 case ACCESS_CODE_DENIED:
1713 p = "Reason: Access denied";
1714 break;
1715 case ACCESS_CODE_NOUSER:
1716 p = errbuf;
1717 break;
1718 case ACCESS_CODE_ACCEXPIRED:
1719 p = "Reason: Account expired";
1720 break;
1721 case ACCESS_CODE_GRPEXPIRED:
1722 p = "Reason: Group expired";
1723 break;
1724 case ACCESS_CODE_ACCNOTVALID:
1725 p = "Reason: Invalid account";
1726 break;
1727 case ACCESS_CODE_MANYDEFACC:
1728 p = "Reason: User has more than one default account";
1729 break;
1730 case ACCESS_CODE_NOACCFORGRP:
1731 p = "Reason: No account for group";
1732 break;
1733 case ACCESS_CODE_NOGRPFORACC:
1734 p = "Reason: No group for account";
1735 break;
1736 case ACCESS_CODE_NOGRPDEFACC:
1737 p = "Reason: No group for default account";
1738 break;
1739 case ACCESS_CODE_NOTGRPMEMB:
1740 p = "Reason: Not member of group";
1741 break;
1742 case ACCESS_CODE_NOTDEFMEMB:
1743 p = "Reason: Not member of default group";
1744 break;
1745 case ACCESS_CODE_OOPS:
1746 p = "Reason: Internal error";
1747 break;
1748 #endif /* CMUCS */
1749 default:
1750 (void) sprintf(p = errbuf, "Reason: Status %d", status);
1751 break;
1753 if (status != ACCESS_CODE_OK) {
1754 logerr("Login failure for %s", pwd->pw_name);
1755 logerr("%s", p);
1756 #if CMUCS
1757 logaccess(pwd->pw_name, ACCESS_TYPE_SUP, status, 0, -1, tlc);
1758 #endif /* CMUCS */
1759 return (p);
1761 #if CMUCS
1762 if (setgroups(grps[0], &grps[1]) < 0)
1763 logerr("setgroups: %%m");
1764 if (setgid((gid_t) grp->gr_gid) < 0)
1765 logerr("setgid: %%m");
1766 if (setuid((uid_t) pwd->pw_uid) < 0)
1767 logerr("setuid: %%m");
1768 #else /* CMUCS */
1769 if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
1770 return ("Error setting group list");
1771 if (setgid(pwd->pw_gid) < 0)
1772 logerr("setgid: %%m");
1773 if (setuid(pwd->pw_uid) < 0)
1774 logerr("setuid: %%m");
1775 #endif /* CMUCS */
1776 return (NULL);
1779 void
1780 goaway(const char *fmt, ...)
1782 char buf[STRINGLENGTH];
1783 va_list ap;
1785 va_start(ap, fmt);
1786 (void) netcrypt((char *) NULL);
1788 vsnprintf(buf, sizeof(buf), fmt, ap);
1789 va_end(ap);
1790 goawayreason = estrdup(buf);
1791 (void) msggoaway();
1792 logerr("%s", buf);
1793 longjmp(sjbuf, TRUE);
1796 char *
1797 fmttime(time_t time)
1799 static char buf[STRINGLENGTH];
1800 unsigned int len;
1802 (void) strcpy(buf, ctime(&time));
1803 len = strlen(buf + 4) - 6;
1804 (void) strncpy(buf, buf + 4, len);
1805 buf[len] = '\0';
1806 return (buf);
1809 * Determine whether the file referenced by the file descriptor 'handle' can
1810 * be trusted, namely is it a file resident in the local file system.
1812 * The main method of operation is to perform operations on the file
1813 * descriptor so that an attempt to spoof the checks should fail, for
1814 * example renamimg the file from underneath us and/or changing where the
1815 * file lives from underneath us.
1817 * returns: -1 for error, indicating that we can not tell
1818 * 0 for file is definately not local, or it is an RFS link
1819 * 1 for file is local and can be trusted
1821 * Side effect: copies the stat information into the supplied buffer,
1822 * regardless of the type of file system the file resides.
1824 * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
1825 * UFS, where the latter is considered a trusted file. We assume that the
1826 * caller has disabled link following and will detect an attempt to access
1827 * a file through an RFS link, except in the case the last component is
1828 * an RFS link. With link following disabled, the last component itself is
1829 * interpreted as a regular file if it is really an RFS link, so we
1830 * disallow the RFS link identified by group "symlink" and mode "IEXEC by
1831 * owner only". An AFS file is
1832 * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
1833 * ioctls which operate on a file descriptor. Note, this AFS ioctl is
1834 * implemented in the cache manager, so the decision does not involve a
1835 * query with the AFS file server. An NFS file is detected by looking at
1836 * the major device number and seeing if it matches the known values for
1837 * MACH NSF/Sun OS 3.x or Sun OS 4.x.
1839 * Having the fstatvfs() system call would make this routine easier and
1840 * more reliable.
1842 * Note, in order to make the checks simpler, the file referenced by the
1843 * file descriptor can not be a BSD style symlink. Even with symlink
1844 * following of the last path component disabled, the attempt to open a
1845 * file which is a symlink will succeed, so we check for the BSD symlink
1846 * file type here. Also, the link following on/off and RFS file types
1847 * are only relevant in a MACH environment.
1849 #ifdef AFS
1850 #include <sys/viceioctl.h>
1851 #endif
1853 #define SYMLINK_GRP 64
1856 local_file(int handle, struct stat * sinfo)
1858 struct stat sb;
1859 #ifdef VIOCIGETCELL
1861 * dummies for the AFS ioctl
1863 struct ViceIoctl vdata;
1864 char cellname[512];
1865 #endif /* VIOCIGETCELL */
1867 if (fstat(handle, &sb) < 0)
1868 return (-1);
1869 if (sinfo != NULL)
1870 *sinfo = sb;
1872 #if CMUCS
1874 * If the following test succeeds, then the file referenced by
1875 * 'handle' is actually an RFS link, so we will not trust it.
1876 * See <sys/inode.h>.
1878 if (sb.st_gid == SYMLINK_GRP
1879 && (sb.st_mode & (S_IFMT | S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
1880 == (S_IFREG | S_IEXEC))
1881 return (0);
1882 #endif /* CMUCS */
1885 * Do not trust BSD style symlinks either.
1887 if (S_ISLNK(sb.st_mode))
1888 return (0);
1890 #ifdef VIOCIGETCELL
1892 * This is the VIOCIGETCELL ioctl, which takes an fd, not
1893 * a path name. If it succeeds, then the file is in AFS.
1895 * On failure, ENOTTY indicates that the file was not in
1896 * AFS; all other errors are pessimistically assumed to be
1897 * a temporary AFS error.
1899 vdata.in_size = 0;
1900 vdata.out_size = sizeof(cellname);
1901 vdata.out = cellname;
1902 if (ioctl(handle, VIOCIGETCELL, (char *) &vdata) != -1)
1903 return (0);
1904 if (errno != ENOTTY)
1905 return (-1);
1906 #endif /* VIOCIGETCELL */
1909 * Verify the file is not in NFS.
1911 * Our current implementation and Sun OS 3.x use major device
1912 * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
1913 * determined this empirically -- DLC). Without a fstatvfs()
1914 * system call, this will have to do for now.
1916 #if defined(__SVR4) || __NetBSD_Version__ > 299000900
1918 struct statvfs sf;
1920 if (fstatvfs(handle, &sf) == -1)
1921 return (-1);
1922 #ifdef __SVR4
1923 return strncmp(sf.f_basetype, "nfs", 3) != 0;
1924 #else
1925 return strncmp(sf.f_fstypename, "nfs", 3) != 0;
1926 #endif
1928 #elif defined(__NetBSD__)
1930 struct statfs sf;
1931 if (fstatfs(handle, &sf) == -1)
1932 return (-1);
1933 return strncmp(sf.f_fstypename, "nfs", 3) != 0;
1935 #else
1936 if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
1937 return (0);
1938 else
1939 return (1);
1940 #endif
1944 * Companion routine for ensuring that a local file can be trusted. Compare
1945 * various pieces of the stat information to make sure that the file can be
1946 * trusted. Returns true for stat information which meets the criteria
1947 * for being trustworthy. The main paranoia is to prevent a hard link to
1948 * a root owned file. Since the link could be removed after the file is
1949 * opened, a simply fstat() can not be relied upon. The two stat buffers
1950 * for comparison should come from a stat() on the file name and a following
1951 * fstat() on the open file. Some of the following checks are also an
1952 * additional level of paranoia. Also, this test will fail (correctly) if
1953 * either or both of the stat structures have all fields zeroed; typically
1954 * due to a stat() failure.
1959 stat_info_ok(struct stat * sb1, struct stat * sb2)
1961 return (sb1->st_ino == sb2->st_ino && /* Still the same file */
1962 sb1->st_dev == sb2->st_dev && /* On the same device */
1963 sb1->st_mode == sb2->st_mode && /* Perms (and type) same */
1964 S_ISREG(sb1->st_mode) && /* Only allow reg files */
1965 (sb1->st_mode & 077) == 0 && /* Owner only perms */
1966 sb1->st_nlink == sb2->st_nlink && /* # hard links same... */
1967 sb1->st_nlink == 1 && /* and only 1 */
1968 sb1->st_uid == sb2->st_uid && /* owner and ... */
1969 sb1->st_gid == sb2->st_gid && /* group unchanged */
1970 sb1->st_mtime == sb2->st_mtime && /* Unmodified between stats */
1971 sb1->st_ctime == sb2->st_ctime); /* Inode unchanged. Hopefully
1972 * a catch-all paranoid test */
1974 #if MACH
1976 * Twiddle symbolic/RFS link following on/off. This is a no-op in a non
1977 * CMUCS/MACH environment. Also, the setmodes/getmodes interface is used
1978 * mainly because it is simpler than using table(2) directly.
1980 #include <sys/table.h>
1983 link_nofollow(int on)
1985 static int modes = -1;
1987 if (modes == -1 && (modes = getmodes()) == -1)
1988 return (-1);
1989 if (on)
1990 return (setmodes(modes | UMODE_NOFOLLOW));
1991 return (setmodes(modes));
1993 #else /* MACH */
1994 /*ARGSUSED*/
1996 link_nofollow(int on __unused)
1998 return (0);
2000 #endif /* MACH */