Added interface for tcpd wrapper for access control.
[yaz-moved-to-github.git] / server / statserv.c
index e9d7912..6bfee93 100644 (file)
@@ -1,13 +1,43 @@
 /*
- * Copyright (c) 1995-1998, Index Data
+ * Copyright (c) 1995-1999, Index Data
  * See the file LICENSE for details.
  * Sebastian Hammer, Adam Dickmeiss
  *
  * NT server based on threads by
- *   Chas Woodfield, Fretwell Downing Datasystem.
+ *   Chas Woodfield, Fretwell Downing Datasystems.
  *
  * $Log: statserv.c,v $
- * Revision 1.46  1998-01-30 15:24:57  adam
+ * Revision 1.54  1999-04-16 14:45:55  adam
+ * Added interface for tcpd wrapper for access control.
+ *
+ * Revision 1.53  1999/02/02 13:57:39  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.52  1998/08/21 14:13:34  adam
+ * Added GNU Configure script to build Makefiles.
+ *
+ * Revision 1.51  1998/07/07 15:51:03  adam
+ * Changed server so that it stops if bind fails - "address already in
+ * use" typically causes this.
+ *
+ * Revision 1.50  1998/06/22 11:32:39  adam
+ * Added 'conditional cs_listen' feature.
+ *
+ * Revision 1.49  1998/02/27 14:04:55  adam
+ * Fixed bug in statserv_remove.
+ *
+ * Revision 1.48  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.47  1998/02/10 10:28:57  adam
+ * Added app_name, service_dependencies, service_display_name and
+ * options_func. options_func allows us to specify a different function
+ * to interogate the command line arguments. The other members allow us
+ * to pass the full service details accross to the service manager (CW).
+ *
+ *
+ * Revision 1.46  1998/01/30 15:24:57  adam
  * Fixed bug in inetd code. The server listened on tcp:@:9999 even
  * though it was started in inetd mode.
  *
  *
  */
 
-#include <yconfig.h>
 #include <stdio.h>
 #include <string.h>
-#ifdef WINDOWS
+#ifdef WIN32
 #include <process.h>
 #include <winsock.h>
 #include <direct.h>
 #include <signal.h>
 #include <errno.h>
 
-#include <options.h>
 #include <comstack.h>
 #include <tcpip.h>
+#include <options.h>
 #ifdef USE_XTIMOSI
 #include <xmosi.h>
 #endif
@@ -193,7 +222,8 @@ static char *me = "statserver";
 /*
  * default behavior.
  */
-static statserv_options_block control_block = {
+int check_options(int argc, char **argv);
+statserv_options_block control_block = {
     1,                          /* dynamic mode */
     LOG_DEFAULT_LEVEL,          /* log level */
     "",                         /* no PDUs */
@@ -205,7 +235,17 @@ static statserv_options_block control_block = {
     "default-config",           /* configuration name to pass to backend */
     "",                         /* set user id */
     NULL,                       /* pre init handler */
-    "Z39.50 Server"             /* NT Service Name */
+    check_options,              /* Default routine, for checking the run-time arguments */
+    check_ip_tcpd,
+    "",
+    0                           /* default value for inet deamon */
+
+#ifdef WIN32
+    ,"Z39.50 Server",           /* NT Service Name */
+    "Server",                   /* NT application Name */
+    "",                         /* NT Service Dependencies */
+    "Z39.50 Server"             /* NT Service Display Name */
+#endif /* WIN32 */
 };
 
 /*
@@ -214,7 +254,7 @@ static statserv_options_block control_block = {
  * doing all of the listening and accepting in the parent - it's
  * safer that way.
  */
-#ifdef WINDOWS
+#ifdef WIN32
 
 typedef struct _ThreadList ThreadList;
 
@@ -232,13 +272,13 @@ static BOOL bInitialized = FALSE;
 static void ThreadList_Initialize()
 {
     /* Initialize the critical Sections */
-     InitializeCriticalSection(&Thread_CritSect);
+    InitializeCriticalSection(&Thread_CritSect);
 
      /* Set the first thraed */
-     pFirstThread = NULL;
+    pFirstThread = NULL;
 
-     /* we have been initialized */
-     bInitialized = TRUE;
+    /* we have been initialized */
+    bInitialized = TRUE;
 }
 
 static void statserv_add(HANDLE hThread, IOCHAN pIOChannel)
@@ -292,6 +332,7 @@ void statserv_remove(IOCHAN pIOChannel)
             {
                 /* We need to look at another thread */
                 pNextThread = pCurrentThread->pNext;
+                pPrevThread = pCurrentThread;
             }
         }
 
@@ -382,7 +423,7 @@ static void listener(IOCHAN h, int event)
     {
         if ((res = cs_listen(line, 0, 0)) < 0)
         {
-           logf(LOG_FATAL, "cs_listen failed.");
+           logf(LOG_FATAL, "cs_listen failed");
            return;
         }
         else if (res == 1)
@@ -406,7 +447,8 @@ static void listener(IOCHAN h, int event)
        }
        logf(LOG_DEBUG, "Accept ok");
 
-       if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, EVENT_INPUT)))
+       if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
+                                      EVENT_INPUT)))
        {
            logf(LOG_FATAL, "Failed to create iochan");
             iochan_destroy(h);
@@ -423,22 +465,22 @@ static void listener(IOCHAN h, int event)
        logf(LOG_DEBUG, "Setting timeout %d", control_block.idle_timeout);
        iochan_setdata(new_chan, newas);
        iochan_settimeout(new_chan, control_block.idle_timeout * 60);
-#ifndef WINDOWS
+#ifndef WIN32
        logf(LOG_DEBUG, "Determining client address");
        a = cs_addrstr(new_line);
        logf(LOG_LOG, "Accepted connection from %s", a ? a : "[Unknown]");
 #endif
-    /* Now what we need todo is create a new thread with this iochan as
-       the parameter */
-    /* if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)event_loop_thread,
-                       new_chan, 0, &ThreadId) == NULL) */
-    /* Somehow, somewhere we need to store this thread id, otherwise we won't be
-       able to close cleanly */
+       /* Now what we need todo is create a new thread with this iochan as
+          the parameter */
+       /* if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)event_loop_thread,
+          new_chan, 0, &ThreadId) == NULL) */
+       /* Somehow, somewhere we need to store this thread id, otherwise we
+          won't be able to close cleanly */
         NewHandle = (HANDLE)_beginthreadex(NULL, 0, event_loop_thread,
-                                           new_chan, 0, &ThreadId);
+                                          new_chan, 0, &ThreadId);
         if (NewHandle == (HANDLE)-1)
        {
-
+           
            logf(LOG_FATAL|LOG_ERRNO, "Failed to create new thread.");
             iochan_destroy(h);
             return;
@@ -457,7 +499,7 @@ static void listener(IOCHAN h, int event)
     }
 }
 
-#else /* WINDOWS */
+#else /* WIN32 */
 
 /* To save having an #ifdef in event_loop we need to define this empty function */
 void statserv_remove(IOCHAN pIOChannel)
@@ -508,7 +550,7 @@ static void listener(IOCHAN h, int event)
                {
                    if (pp != h)
                    {
-                       COMSTACK l = iochan_getdata(pp);
+                       COMSTACK l = (COMSTACK)iochan_getdata(pp);
                        cs_close(l);
                        iochan_destroy(pp);
                    }
@@ -538,9 +580,10 @@ static void listener(IOCHAN h, int event)
                return;
            }
        }
-       if ((res = cs_listen(line, 0, 0)) < 0)
+       if ((res = cs_listen_check(line, 0, 0, control_block.check_ip,
+                                  control_block.daemon_name)) < 0)
        {
-           logf(LOG_FATAL, "cs_listen failed.");
+           logf(LOG_WARN, "cs_listen failed");
            return;
        }
        else if (res == 1)
@@ -569,7 +612,7 @@ static void listener(IOCHAN h, int event)
            /* close our half of the listener socket */
            for (pp = pListener; pp; pp = iochan_getnext(pp))
            {
-               COMSTACK l = iochan_getdata(pp);
+               COMSTACK l = (COMSTACK)iochan_getdata(pp);
                cs_close(l);
                iochan_destroy(pp);
            }
@@ -579,7 +622,7 @@ static void listener(IOCHAN h, int event)
        }
        else
            iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
-
+       
        if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
            EVENT_INPUT)))
        {
@@ -608,7 +651,7 @@ static void listener(IOCHAN h, int event)
     }
 }
 
-#endif /* WINDOWS */
+#endif /* WIN32 */
 
 static void inetd_connection(int what)
 {
@@ -684,6 +727,7 @@ static void add_listener(char *where, int what)
     if (!(l = cs_create(type, 0, what)))
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to create listener");
+       return;
     }
     ap = cs_straddr (l, addr);
     if (!ap)
@@ -695,11 +739,15 @@ static void add_listener(char *where, int what)
     if (cs_bind(l, ap, CS_SERVER) < 0)
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to bind to %s", where);
+       cs_close (l);
+       return;
     }
     if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT |
         EVENT_EXCEPT)))
     {
        logf(LOG_FATAL|LOG_ERRNO, "Failed to create IOCHAN-type");
+       cs_close (l);
+       return;
     }
     iochan_setdata(lst, l);
 
@@ -708,7 +756,7 @@ static void add_listener(char *where, int what)
     pListener = lst;
 }
 
-#ifndef WINDOWS
+#ifndef WIN32
 /* For windows we don't need to catch the signals */
 static void catchchld(int num)
 {
@@ -716,7 +764,7 @@ static void catchchld(int num)
        ;
     signal(SIGCHLD, catchchld);
 }
-#endif /* WINDOWS */
+#endif /* WIN32 */
 
 statserv_options_block *statserv_getcontrol(void)
 {
@@ -733,17 +781,15 @@ void statserv_setcontrol(statserv_options_block *block)
 
 int statserv_start(int argc, char **argv)
 {
-    int ret, listeners = 0, inetd = 0, r;
-    char *arg;
-    int protocol = control_block.default_proto;
+    int ret;
 
     nmem_init ();
-#ifdef WINDOWS
+#ifdef WIN32
     /* We need to initialize the thread list */
     ThreadList_Initialize();
-#endif /* WINDOWS */
+#endif /* WIN32 */
 
-#ifdef WINDOWS
+#ifdef WIN32
     if ((me = strrchr (argv[0], '\\')))
        me++;
     else
@@ -751,70 +797,12 @@ int statserv_start(int argc, char **argv)
 #else
     me = argv[0];
 #endif
-    while ((ret = options("a:iszSl:v:u:c:w:t:k:", argv, argc, &arg)) != -2)
-    {
-       switch (ret)
-       {
-           case 0:
-                   add_listener(arg, protocol);
-                   listeners++;
-               break;
-           case 'z': protocol = PROTO_Z3950; break;
-           case 's': protocol = PROTO_SR; break;
-           case 'S': control_block.dynamic = 0; break;
-           case 'l':
-               strcpy(control_block.logfile, arg ? arg : "");
-               log_init(control_block.loglevel, me, control_block.logfile);
-               break;
-           case 'v':
-               control_block.loglevel = log_mask_str(arg);
-               log_init(control_block.loglevel, me, control_block.logfile);
-               break;
-           case 'a':
-               strcpy(control_block.apdufile, arg ? arg : ""); break;
-           case 'u':
-               strcpy(control_block.setuid, arg ? arg : ""); break;
-            case 'c':
-                strcpy(control_block.configname, arg ? arg : ""); break;
-           case 't':
-               if (!arg || !(r = atoi(arg)))
-               {
-                   fprintf(stderr, "%s: Specify positive timeout for -t.\n",
-                       me);
-                   return(1);
-               }
-               control_block.idle_timeout = r;
-               break;
-           case  'k':
-               if (!arg || !(r = atoi(arg)))
-               {
-                   fprintf(stderr, "%s: Specify positive timeout for -t.\n",
-                       me);
-                   return(1);
-               }
-               control_block.maxrecordsize = r * 1024;
-               break;
-           case 'i':
-               inetd = 1; break;
-           case 'w':
-               if (chdir(arg))
-               {
-                   perror(arg);
+    if (control_block.options_func(argc, argv))
+        return(1);
 
-                   return(1);
-               }
-               break;
-           default:
-               fprintf(stderr, "Usage: %s [ -i -a <pdufile> -v <loglevel>"
-                        " -l <logfile> -u <user> -c <config> -t <minutes>"
-                       " -k <kilobytes>"
-                        " -zsS <listener-addr> -w <directory> ... ]\n", me);
-               return(1);
-            }
-    }
-#ifndef WINDOWS
-    if (inetd)
-       inetd_connection(protocol);
+#ifndef WIN32
+    if (control_block.inetd)
+       inetd_connection(control_block.default_proto);
     else
     {
        if (control_block.pre_init)
@@ -837,22 +825,102 @@ int statserv_start(int argc, char **argv)
            exit(1);
        }
     }
-#endif /* WINDOWS */
+#endif /* WIN32 */
 
     if ((pListener == NULL) && *control_block.default_listen)
-       add_listener(control_block.default_listen, protocol);
-
-    logf(LOG_LOG, "Entering event loop.");
+       add_listener(control_block.default_listen,
+                    control_block.default_proto);
        
     if (pListener == NULL)
        ret = 1;
     else
+    {
+       logf(LOG_LOG, "Entering event loop.");
         ret = event_loop(&pListener);
+    }
     nmem_exit ();
     return ret;
 }
 
-#ifdef WINDOWS
+int check_options(int argc, char **argv)
+{
+    int ret = 0, r;
+    char *arg;
+
+    while ((ret = options("a:iszSl:v:u:c:w:t:k:d:", argv, argc, &arg)) != -2)
+    {
+       switch (ret)
+       {
+       case 0:
+           add_listener(arg, control_block.default_proto);
+           break;
+       case 'z':
+           control_block.default_proto = PROTO_Z3950;
+           break;
+       case 's':
+           control_block.default_proto = PROTO_SR;
+           break;
+       case 'S':
+           control_block.dynamic = 0;
+           break;
+       case 'l':
+           strcpy(control_block.logfile, arg ? arg : "");
+           log_init(control_block.loglevel, me, control_block.logfile);
+           break;
+       case 'v':
+           control_block.loglevel = log_mask_str(arg);
+           log_init(control_block.loglevel, me, control_block.logfile);
+           break;
+       case 'a':
+           strcpy(control_block.apdufile, arg ? arg : "");
+           break;
+       case 'u':
+           strcpy(control_block.setuid, arg ? arg : "");
+           break;
+       case 'c':
+           strcpy(control_block.configname, arg ? arg : "");
+           break;
+       case 'd':
+           strcpy(control_block.daemon_name, arg ? arg : "");
+           break;
+       case 't':
+           if (!arg || !(r = atoi(arg)))
+           {
+               fprintf(stderr, "%s: Specify positive timeout for -t.\n", me);
+               return(1);
+           }
+           control_block.idle_timeout = r;
+           break;
+       case  'k':
+           if (!arg || !(r = atoi(arg)))
+           {
+               fprintf(stderr, "%s: Specify positive size for -k.\n", me);
+               return(1);
+           }
+           control_block.maxrecordsize = r * 1024;
+           break;
+       case 'i':
+           control_block.inetd = 1;
+           break;
+       case 'w':
+           if (chdir(arg))
+           {
+               perror(arg);            
+               return(1);
+           }
+           break;
+       default:
+           fprintf(stderr, "Usage: %s [ -i -a <pdufile> -v <loglevel>"
+                   " -l <logfile> -u <user> -c <config> -t <minutes>"
+                   " -k <kilobytes> -d <daemon>"
+                        " -zsS <listener-addr> -w <directory> ... ]\n", me);
+           return(1);
+        }
+    }
+    return 0;
+}
+
+#ifdef WIN32
 typedef struct _Args
 {
     char **argv;
@@ -870,16 +938,16 @@ static Args ArgDetails;
 int statserv_main(int argc, char **argv)
 {
     statserv_options_block *cb = statserv_getcontrol();
-
-        /* Lets setup the Arg structure */
+    
+    /* Lets setup the Arg structure */
     ArgDetails.argc = argc;
     ArgDetails.argv = argv;
-
+    
     /* Now setup the service with the service controller */
     SetupService(argc, argv, &ArgDetails, SZAPPNAME,
-        cb->service_name, /* internal service name */
-        cb->service_name, /* displayed name of the service */
-        SZDEPENDENCIES);
+                cb->service_name, /* internal service name */
+                cb->service_name, /* displayed name of the service */
+                SZDEPENDENCIES);
     return 0;
 }
 
@@ -892,7 +960,7 @@ int StartAppService(void *pHandle, int argc, char **argv)
 void RunAppService(void *pHandle)
 {
     Args *pArgs = (Args *)pHandle;
-
+    
     /* Starts the app running */
     statserv_start(pArgs->argc, pArgs->argv);
 }