/*********************************************************************\ * Copyright (c) 2003 by Radim Kolar (hsn@cybermail.net) * * Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) * * * * You may copy or modify this file in any manner you wish, provided * * that this notice is always included, and that you hold the author * * harmless for any loss or damage resulting from the installation or * * use of this software. * \*********************************************************************/ #include "tweak.h" #include "server_def.h" #include "s_extern.h" #include "co_extern.h" #include "my-string.h" #include "pidfile.h" #define NULL_DEV "/dev/null" static int inetd_mode = 0; static const char *config_file = CONF_FILE ; static void display_version (void) { printf( #ifndef LAMERPACK "File Service Protocol Daemon - FSP "PACKAGE_VERSION"\n" "Copyright (c) 1991-1996 by A. J. Doherty, 2001-2004 by Radim Kolar.\n" "All of the FSP code is free software with revised BSD license.\n" "Portions copyright by BSD, Wen-King Su, Philip G. Richards, Michael Meskes.\n" #ifdef __GNUC__ "Compiled "__DATE__" by GCC "__VERSION__"\n" #endif #else "FSP server "PACKAGE_VERSION"\n" "For lamerZ by Elite!\n" #endif ); } /* flush the log message to file */ static void arg_err (void) { fputs("Usage: fspd [-f configfile] [-d directory] [-v|-V] [-i] [-F] [-p port] [-X] [-t timeout] [-T temporary directory] [-l logfile] [-P pidlogname] [-b bytes/sec]\n", stderr); } static void check_required_vars (void) { double rnd; #ifdef LAMERPACK inetd_mode = 0; daemonize = 0; dbug = 0; dir_cache_limit = 500; #endif if(!inetd_mode && udp_port==0) { #ifdef LAMERPACK udp_port = 53; #else fprintf(stderr, "Error: No port set. (Use 65535 for random port)\n"); exit(1); #endif } if(udp_port == 65535) { /* generate random port in 1024-65535 range */ rnd=(random())/(double)RAND_MAX; udp_port=rnd*(65535-1024)+1024; } if(!home_dir) { #ifdef LAMERPACK home_dir = strdup("/"); #else fprintf(stderr, "Error: No home directory set.\n"); exit(1); #endif } #if 0 if(*home_dir != '/') { fprintf(stderr,"Error: home directory [%s] does not start with a /.\n", home_dir); exit(1); } #endif #if 0 if(!pidlogname) { fprintf(stderr, "No pidlogname set in your fspd.conf.\n"); exit(1); } #endif if(!readme_file) { readme_file = strdup(".README"); } if(logging && !logname) { logging=0; } if(daemonize && dbug) daemonize = 0; if(inetd_mode && dbug) dbug = 0; if(!tmp_dir && !read_only) { #ifndef LAMERPACK if(!inetd_mode) fprintf(stderr,"Warning: no tmpdir set, switching to readonly mode.\n"); #endif read_only = 1; } } static void init_random (void) { unsigned int seed; FILE *f; f=fopen("/dev/random","rb"); if(f) { fread(&seed,sizeof(unsigned int),1,f); fclose(f); } else seed=getpid()*time(NULL); srandom(seed); } int main (int argc, char ** argv) { int opt; long inetd_timeout=0; if(strlen(argv[0])>=7) inetd_mode = !strcasecmp(&argv[0][strlen(argv[0])-7],"in.fspd"); while( (opt=getopt(argc,argv,"h?Xd:f:vVip:t:FT:l:P:b:"))!=EOF) { switch(opt) { case 'X': dbug = 1; break; case 'f': load_configuration(optarg); config_file = NULL; break; case 'd': if(home_dir) free(home_dir); home_dir = strdup(optarg); break; case 'l': if(logname) free(logname); logname = strdup(optarg); logging = L_ALL ^ L_RDONLY; break; case 'P': if(pidlogname) free(pidlogname); pidlogname = strdup(optarg); break; case 'T': if(tmp_dir) free(tmp_dir); tmp_dir = strdup(optarg); break; case 'i': inetd_mode = 1; break; case 'p': udp_port = atoi (optarg); break; case 'b': maxthcallowed = atoi (optarg); break; case 't': inetd_timeout = 1000L * atoi (optarg); break; case 'F': daemonize = 0; break; case 'v': case 'V': display_version(); exit(0); case 'h': case '?': arg_err(); exit(0); default: arg_err(); exit(1); } } load_configuration(config_file); init_random(); check_required_vars(); if(!inetd_mode) { opt=_x_udp(listen_on,&udp_port); if(opt == -1) { perror("Error: socket open"); exit(2); } if(dbug) { display_version(); fprintf(stderr,"listening on port %d\n",udp_port); } #ifdef LAMERPACK display_version(); fprintf(stderr,"rocking on port %d\n",udp_port); #endif } /* Moved setuid to here from below because log file was getting opened * by root, and fspd could no longer write to the log file after the * setuid. This should always open the file as run_uid * Modified A.E.J.Fellows 9 March 93 */ if(run_uid) if(setuid(run_uid) != 0) { fprintf(stderr,"Can not change my uid to %d.\n",run_uid); exit(3); } if(run_gid) if(setgid(run_gid) != 0) { fprintf(stderr,"Can not change my gid to %d.\n",run_uid); exit(4); } init_home_dir(); if(init_caches()) { perror("init_caches"); exit(5); } umask(system_umask); if (logging) { #ifndef LAMERPACK if (dbug) #endif fprintf(stderr,"logging to %s\n",logname); /* test to see if logfile can be written */ /* open it append mode so that it doesn't wipe the file when * you are running under inetd. */ if((logfd=open(logname, O_WRONLY | O_APPEND | O_CREAT, 0640)) < 0) { if(! inetd_mode ) fprintf(stderr, "Error opening logfile: %s, logging disabled.\n", logname); logging = 0; /* no logging */ } } if(tlogname) { if (dbug) fprintf(stderr,"logging transfers to %s\n",tlogname); /* test to see if logfile can be written */ if((tlogfd=open(tlogname, O_WRONLY | O_APPEND | O_CREAT, 0640)) < 0) { if(! inetd_mode ) fprintf(stderr, "Error opening transferfile: %s, transfer logging disabled.\n",tlogname); free(tlogname); tlogname=NULL; /* no logging */ } } /* With pidfile we have currently 2 problems: 1) creating pidfile after we have droped root rights. We can not write to root only directories like /var/run 2) If we create pidfile early before setuid() we can't write new pid to it after we setuid()+fork() */ #ifndef LAMERPACK if (pidfile(pidlogname)) { fprintf(stderr,"Error: can not write pidfile - exiting.\n"); exit(1);/* cannot write pid file - exit */ } #endif init_htab(); /* we can enable table dumping from there */ signal(SIGINT,server_interrupt); signal(SIGTERM,server_interrupt); signal(SIGUSR1,server_dump); /* set timeouts */ if(inetd_mode) { if(inetd_timeout==0) inetd_timeout=120*1000L; /* 2. minutes */ }else { if(inetd_timeout==0 || !dbug) inetd_timeout=-1L; } /* inetd init */ if(inetd_mode) { opt=dup(0); } if(daemonize || inetd_mode) { freopen(NULL_DEV,"r",stdin); freopen(NULL_DEV,"w",stdout); freopen(NULL_DEV,"w",stderr); } if(!inetd_mode) { /* Fork and die to drop daemon into background */ /* Added Alban E J Fellows 12 Jan 93 */ /* Moved by JT Traub to only do this if not running under inetd. */ if(daemonize) { #if HAVE_FORK pid_t forkpid; forkpid = fork(); if (forkpid == 0) { /* child prozess */ if (pidfile(pidlogname)) { pidfile_cleanup(pidlogname); /* try cleanup */ exit(1);/* cannot write pid file - exit */ } } else if (forkpid > 0) { /* father prozess */ _exit(0); } #endif #if HAVE_SETSID setsid(); #endif } } while(1) { server_loop(opt,inetd_timeout); if(inetd_mode||dbug||shutdowning) break; } pidfile_cleanup(pidlogname); shutdown_caches(); destroy_configuration(); exit(0); }