From 74fb9452a0e5baeaf0023a7ebcbb64661abfb326 Mon Sep 17 00:00:00 2001
From: Fons Rademakers <Fons.Rademakers@cern.ch>
Date: Mon, 28 Oct 2002 14:22:51 +0000
Subject: [PATCH] Applied rootd patch by Ulrik Egede and Tim Adye from BaBar.
 New features:

1) New option, -P FILE, to specify an alternate SRP password file. As an
   example

   rootd -P $HOME/.srootdpass2

   will start rootd using the files $HOME/.srootdpass2.conf and
   $HOME/.srootdpass2 for SRP authentication.

2) Modified option, -p port1-port2, will search for the first available
port in the range. You can also specify -p 0-N for search relative to the
service port specified in /etc/services (this was sort of accidental, but
not a bad feature :-). If a single port is specified as before, then no
search is made.

3) Unless started by inetd (rootd -i), it prints something like

    ROOTD_PORT=5151
    ROOTD_PID=14433

before spawning the daemon so the user knows what was used (eval `rootd`
will set these as variables in Bourne-shells).

4) rootd now shows an error message (as well as the syslog message it
always sent) if there is any problem binding the port or forking the
daemon.


git-svn-id: http://root.cern.ch/svn/root/trunk@5507 27541ba8-7e3a-0410-8455-c3a389f83636
---
 rootd/inc/rootdp.h   |  6 +--
 rootd/src/daemon.cxx | 36 +++++++++++-----
 rootd/src/net.cxx    | 62 +++++++++++++++++-----------
 rootd/src/rootd.cxx  | 98 ++++++++++++++++++++++++++++++--------------
 4 files changed, 133 insertions(+), 69 deletions(-)

diff --git a/rootd/inc/rootdp.h b/rootd/inc/rootdp.h
index 36e6ffd1a9a..4c28ad3ce40 100644
--- a/rootd/inc/rootdp.h
+++ b/rootd/inc/rootdp.h
@@ -1,4 +1,4 @@
-/* @(#)root/rootd:$Name:  $:$Id: rootdp.h,v 1.4 2001/02/22 09:43:25 rdm Exp $ */
+/* @(#)root/rootd:$Name:  $:$Id: rootdp.h,v 1.5 2001/02/26 02:49:07 rdm Exp $ */
 
 /*************************************************************************
  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
@@ -42,7 +42,7 @@ extern double  gBytesSent;
 extern double  gBytesRecv;
 
 
-void  DaemonStart(int ignsigcld);
+void  DaemonStart(int ignsigcld, int fdkeep);
 
 void  ErrorInit(const char *ident);
 void  ErrorInfo(const char *va_(fmt), ...);
@@ -53,7 +53,7 @@ int   GetErrno();
 void  ResetErrno();
 void  Perror(char *buf);
 
-void  NetInit(const char *service, int port, int tcpwindowsize);
+int   NetInit(const char *service, int port1, int port2, int tcpwindowsize);
 int   NetOpen(int inetdflag);
 void  NetClose();
 char *NetRemoteHost();
diff --git a/rootd/src/daemon.cxx b/rootd/src/daemon.cxx
index 6eca01fa7ab..b3dd4181cde 100644
--- a/rootd/src/daemon.cxx
+++ b/rootd/src/daemon.cxx
@@ -1,4 +1,4 @@
-// @(#)root/rootd:$Name:  $:$Id: daemon.cxx,v 1.3 2001/04/06 14:17:42 rdm Exp $
+// @(#)root/rootd:$Name:  $:$Id: daemon.cxx,v 1.4 2002/01/22 10:53:29 rdm Exp $
 // Author: Fons Rademakers   11/08/97
 
 /*************************************************************************
@@ -72,7 +72,7 @@ static void SigChild(int)
 #endif
 
 //______________________________________________________________________________
-void DaemonStart(int ignsigcld)
+void DaemonStart(int ignsigcld, int fdkeep)
 {
    // Detach a daemon process from login session context.
 
@@ -84,8 +84,10 @@ void DaemonStart(int ignsigcld)
 
    int fd;
 
-   if (getppid() == 1)
+   if (getppid() == 1) {
+      printf ("ROOTD_PID=%ld\n", (long) getpid());
       goto out;
+   }
 
    // Ignore the terminal stop signals (BSD).
 
@@ -104,10 +106,15 @@ void DaemonStart(int ignsigcld)
    // group leader.
 
    int childpid;
-   if ((childpid = fork()) < 0)
+   if ((childpid = fork()) < 0) {
+      fprintf(stderr,     "DaemonStart: can't fork first child\n");
       ErrorSys(kErrFatal, "DaemonStart: can't fork first child");
-   else if (childpid > 0)
+   } else if (childpid > 0) {
+#ifdef SIGTSTP
+      printf("ROOTD_PID=%d\n", childpid);
+#endif
       exit(0);    // parent
+   }
 
    // First child process...
 
@@ -117,11 +124,13 @@ void DaemonStart(int ignsigcld)
 #ifdef SIGTSTP
 
 #ifdef USE_SETSID
-   if (setsid() == -1)
+   if (setsid() == -1) {
 #else
-   if (setpgrp(0, getpid()) == -1)
+   if (setpgrp(0, getpid()) == -1) {
 #endif
+      fprintf(stderr,     "DaemonStart: can't change process group\n");
       ErrorSys(kErrFatal, "DaemonStart: can't change process group");
+   }
 
    if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
 #if !defined(__hpux) && !defined(__sun)
@@ -132,15 +141,20 @@ void DaemonStart(int ignsigcld)
 
 #else
 
-   if (setpgrp() == -1)
+   if (setpgrp() == -1) {
+      fprintf(stderr,     "DaemonStart: can't change process group\n");
       ErrorSys(kErrFatal, "DaemonStart: can't change process group");
+   }
 
    signal(SIGHUP, SIG_IGN);    // immune from pgrp leader death
 
-   if ((childpid = fork()) < 0)
+   if ((childpid = fork()) < 0) {
+      fprintf(stderr,     "DaemonStart: can't fork second child\n");
       ErrorSys(kErrFatal, "DaemonStart: can't fork second child");
-   else if (childpid > 0)
+   } else if (childpid > 0) {
+      printf("ROOTD_PID=%d\n", childpid);
       exit(0);    // first child
+   }
 
    // Second child process...
 
@@ -151,7 +165,7 @@ out:
    // Close any open file descriptors
 
    for (fd = 0; fd < NOFILE; fd++)
-      close(fd);
+      if (fd != fdkeep) close(fd);
 
    ResetErrno();   // probably got set to EBADF from a close
 
diff --git a/rootd/src/net.cxx b/rootd/src/net.cxx
index 50220421026..1a0ee8ca3f2 100644
--- a/rootd/src/net.cxx
+++ b/rootd/src/net.cxx
@@ -1,4 +1,4 @@
-// @(#)root/rootd:$Name:  $:$Id: net.cxx,v 1.14 2002/01/22 10:53:29 rdm Exp $
+// @(#)root/rootd:$Name:  $:$Id: net.cxx,v 1.15 2002/02/06 18:27:40 rdm Exp $
 // Author: Fons Rademakers   12/08/97
 
 /*************************************************************************
@@ -274,7 +274,7 @@ int NetRecv(char *msg, int len, EMessageTypes &kind)
 }
 
 //______________________________________________________________________________
-void NetInit(const char *service, int port, int tcpwindowsize)
+int NetInit(const char *service, int port1, int port2, int tcpwindowsize)
 {
    // Initialize the network connection for the server, when it has *not*
    // been invoked by inetd.
@@ -283,46 +283,56 @@ void NetInit(const char *service, int port, int tcpwindowsize)
    // We have to create a socket ourselves and bind our well-known
    // address to it.
 
-   memset(&tcp_srv_addr, 0, sizeof(tcp_srv_addr));
-   tcp_srv_addr.sin_family      = AF_INET;
-   tcp_srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-   if (service) {
-
-      if (port > 0)
-         tcp_srv_addr.sin_port = htons(port);
-      else {
+   if (port1 <= 0) {
+      if (service) {
          struct servent *sp;
-         if ((sp = getservbyname(service, "tcp")) == 0)
+         if ((sp = getservbyname(service, "tcp")) == 0) {
+            fprintf(stderr,       "NetInit: unknown service: %s/tcp\n", service);
             ErrorFatal(kErrFatal, "NetInit: unknown service: %s/tcp", service);
-         tcp_srv_addr.sin_port = sp->s_port;
-      }
-
-   } else {
-
-      if (port <= 0)
+         }
+         port1 = ntohs(sp->s_port);
+         port2 += port1;   // in this case, port2 is relative to service port
+      } else {
+         fprintf(stderr,       "NetInit: must specify either service or port\n");
          ErrorFatal(kErrFatal, "NetInit: must specify either service or port");
-      tcp_srv_addr.sin_port = htons(port);
-
+      }
    }
 
    // Create the socket and bind our local address so that any client can
    // send to us.
 
-   if ((tcp_srv_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+   if ((tcp_srv_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+      fprintf(stderr,     "NetInit: can't create socket\n");
       ErrorSys(kErrFatal, "NetInit: can't create socket");
+   }
 
    int val = 1;
    if (setsockopt(tcp_srv_sock, SOL_SOCKET, SO_REUSEADDR, (char*) &val,
-                  sizeof(val)) == -1)
+                  sizeof(val)) == -1) {
+      fprintf(stderr,     "NetInit: can't set SO_REUSEADDR socket option\n");
       ErrorSys(kErrFatal, "NetInit: can't set SO_REUSEADDR socket option");
+   }
 
    // Set several general performance network options
    NetSetOptions(tcp_srv_sock, tcpwindowsize);
 
-   if (bind(tcp_srv_sock, (struct sockaddr *) &tcp_srv_addr,
-            sizeof(tcp_srv_addr)) < 0)
-      ErrorSys(kErrFatal, "NetInit: can't bind local address");
+   memset(&tcp_srv_addr, 0, sizeof(tcp_srv_addr));
+   tcp_srv_addr.sin_family      = AF_INET;
+   tcp_srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+   int port;
+   for (port= port1; port <= port2; port++) {
+      tcp_srv_addr.sin_port = htons(port);
+      if (bind(tcp_srv_sock, (struct sockaddr *) &tcp_srv_addr,
+               sizeof(tcp_srv_addr)) == 0) break;
+   }
+
+   if (port > port2) {
+      fprintf(stderr,     "NetInit: can't bind local address to ports %d-%d\n", port1, port2);
+      ErrorSys(kErrFatal, "NetInit: can't bind local address to ports %d-%d", port1, port2);
+   }
+
+   printf("ROOTD_PORT=%d\n", port);
 
    // And set the listen parameter, telling the system that we're
    // ready to accept incoming connection requests.
@@ -332,6 +342,8 @@ void NetInit(const char *service, int port, int tcpwindowsize)
    if (gDebug > 0)
       ErrorInfo("NetInit: socket %d listening on port %d", tcp_srv_sock,
                 ntohs(tcp_srv_addr.sin_port));
+
+   return tcp_srv_sock;
 }
 
 //______________________________________________________________________________
diff --git a/rootd/src/rootd.cxx b/rootd/src/rootd.cxx
index 45cf5109b20..9f3607b049b 100644
--- a/rootd/src/rootd.cxx
+++ b/rootd/src/rootd.cxx
@@ -1,4 +1,4 @@
-// @(#)root/rootd:$Name:  $:$Id: rootd.cxx,v 1.43 2002/06/25 23:53:26 rdm Exp $
+// @(#)root/rootd:$Name:  $:$Id: rootd.cxx,v 1.44 2002/06/27 23:58:02 rdm Exp $
 // Author: Fons Rademakers   11/08/97
 
 /*************************************************************************
@@ -9,7 +9,8 @@
  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
  *************************************************************************/
 
-/* Parts of this file are copied from the MIT krb5 distribution and
+/*
+ * Parts of this file are copied from the MIT krb5 distribution and
  * are subject to the following license:
  *
  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
@@ -33,7 +34,6 @@
  * M.I.T. makes no representations about the suitability of
  * this software for any purpose.  It is provided "as is" without express
  * or implied warranty.
- *
  */
 
 //////////////////////////////////////////////////////////////////////////
@@ -63,14 +63,25 @@
 // rootd -p 5151                                                        //
 //                                                                      //
 // Notice: no & is needed. Rootd will go in background by itself.       //
+// In this case, the port number and process id will be printed, e.g.   //
+//                                                                      //
+// ROOTD_PORT=5151                                                      //
+// ROOTD_PID=14433                                                      //
 //                                                                      //
 // Rootd arguments:                                                     //
 //   -i                says we were started by inetd                    //
-//   -p port#          specifies a different port to listen on          //
+//   -p port#          specifies a different port to listen on.         //
+//                     Use port1-port2 to find first available port in  //
+//                     range. Use 0-N for range relative to service     //
+//                     port.                                            //
 //   -b tcpwindowsize  specifies the tcp window size in bytes (e.g. see //
 //                     http://www.psc.edu/networking/perf_tune.html)    //
 //                     Default is 65535. Only change default for pipes  //
 //                     with a high bandwidth*delay product.             //
+//   -P file           use this password file, instead of .srootdpass   //
+//   -S keytabfile     use this keytab file, instead of the default     //
+//                     (option only supported when compiled with        //
+//                     Kerberos5 support)                               //
 //   -d level          level of debug info written to syslog            //
 //                     0 = no debug (default)                           //
 //                     1 = minimum                                      //
@@ -289,34 +300,37 @@ extern krb5_deltat krb5_clockskew;
 
 //--- Globals ------------------------------------------------------------------
 
+const int  kMAXPATHLEN     = 1024;
 const char kRootdService[] = "rootd";
 const char kRootdTab[]     = "/usr/tmp/rootdtab";
 const char kRootdPass[]    = ".rootdpass";
 const char kSRootdPass[]   = ".srootdpass";
-const int  kMAXPATHLEN     = 1024;
 enum { kBinary, kAscii };
 
-int     gInetdFlag         = 0;
-int     gPort              = 0;
-int     gDebug             = 0;
-int     gSockFd            = -1;
-int     gAuth              = 0;
-int     gAnon              = 0;
-int     gFd                = -1;
-int     gWritable          = 0;
-int     gProtocol          = 6;       // increase when protocol changes
-int     gUploaded          = 0;
-int     gDownloaded        = 0;
-int     gFtp               = 0;
-double  gBytesRead         = 0;
-double  gBytesWritten      = 0;
-char    gUser[64]          = { 0 };
-char    gPasswd[64]        = { 0 };   // only used for anonymous access
-char    gOption[32]        = { 0 };
-char    gFile[kMAXPATHLEN] = { 0 };
+int     gInetdFlag               = 0;
+int     gPort1                   = 0;
+int     gPort2                   = 0;
+int     gDebug                   = 0;
+int     gSockFd                  = -1;
+int     gAuth                    = 0;
+int     gAnon                    = 0;
+int     gAltSRP                  = 0;
+int     gFd                      = -1;
+int     gWritable                = 0;
+int     gProtocol                = 6;       // increase when protocol changes
+int     gUploaded                = 0;
+int     gDownloaded              = 0;
+int     gFtp                     = 0;
+double  gBytesRead               = 0;
+double  gBytesWritten            = 0;
+char    gUser[64]                = { 0 };
+char    gPasswd[64]              = { 0 };   // only used for anonymous access
+char    gOption[32]              = { 0 };
+char    gFile[kMAXPATHLEN]       = { 0 };
+char    gAltSRPPass[kMAXPATHLEN] = { 0 };
 
 #ifdef R__KRB5
-krb5_keytab  gKeytab       = 0;       // to allow specifying on the command line
+krb5_keytab  gKeytab             = 0; // to allow specifying on the command line
 krb5_context gKcontext;
 #endif
 
@@ -996,8 +1010,13 @@ void RootdSRPUser(const char *user)
 
    strcpy(gUser, user);
 
-   sprintf(srootdpass, "%s/%s", pw->pw_dir, kSRootdPass);
-   sprintf(srootdconf, "%s/%s.conf", pw->pw_dir, kSRootdPass);
+   if (!gAltSRP) {
+      sprintf(srootdpass, "%s/%s", pw->pw_dir, kSRootdPass);
+      sprintf(srootdconf, "%s/%s.conf", pw->pw_dir, kSRootdPass);
+   } else {
+      sprintf(srootdpass, "%s", gAltSRPPass);
+      sprintf(srootdconf, "%s.conf", gAltSRPPass);
+   }
 
    FILE *fp1 = fopen(srootdpass, "r");
    if (!fp1) {
@@ -2166,7 +2185,17 @@ int main(int argc, char **argv)
                      fprintf(stderr, "-p requires a port number as argument\n");
                   ErrorFatal(kErrFatal, "-p requires a port number as argument");
                }
-               gPort = atoi(*++argv);
+               char *p;
+               gPort1 = strtol(*++argv, &p, 10);
+               if (*p == '-')
+                  gPort2 = strtol(++p, &p, 10);
+               else if (*p == '\0')
+                  gPort2 = gPort1;
+               if (*p != '\0' || gPort2 < gPort1 || gPort2 < 0) {
+                  if (!gInetdFlag)
+                     fprintf(stderr, "invalid port number or range: %s\n", *argv);
+                  ErrorFatal(kErrFatal, "invalid port number or range: %s", *argv);
+               }
                break;
 
             case 'd':
@@ -2187,6 +2216,16 @@ int main(int argc, char **argv)
                tcpwindowsize = atoi(*++argv);
                break;
 
+            case 'P':
+               if (--argc <= 0) {
+                  if (!gInetdFlag)
+                     fprintf(stderr, "-P requires a file name for SRP password file\n");
+                  ErrorFatal(kErrFatal, "-P requires a file name for SRP password file");
+               }
+               gAltSRP = 1;
+               sprintf(gAltSRPPass, "%s", *++argv);
+               break;
+
 #ifdef R__KRB5
             case 'S':
                if (--argc <= 0) {
@@ -2213,9 +2252,8 @@ int main(int argc, char **argv)
       // Also initialize the network connection - create the socket
       // and bind our well-know address to it.
 
-      DaemonStart(1);
-
-      NetInit(kRootdService, gPort, tcpwindowsize);
+      int fdkeep = NetInit(kRootdService, gPort1, gPort2, tcpwindowsize);
+      DaemonStart(1, fdkeep);
    }
 
    if (gDebug > 0)
-- 
GitLab