daemon/main.cc
changeset 0 6f7a81934006
child 2 b3afb9f1e801
equal deleted inserted replaced
-1:000000000000 0:6f7a81934006
       
     1 // Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
       
     2 //
       
     3 // This program is free software; you can redistribute it and/or modify
       
     4 // it under the terms of the GNU General Public License as published by
       
     5 // the Free Software Foundation; either version 2 of the License, or
       
     6 // (at your option) any later version.
       
     7 //
       
     8 // This program is distributed in the hope that it will be useful,
       
     9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    11 // GNU General Public License for more details.
       
    12 //
       
    13 // You should have received a copy of the GNU General Public License
       
    14 // along with this program; if not, write to the Free Software
       
    15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    16 
       
    17 #include <config.h>
       
    18 #include <pwd.h>
       
    19 #include <stdio.h>
       
    20 #include <stdlib.h>
       
    21 #include <sys/types.h>
       
    22 #include <sys/stat.h>
       
    23 #include <signal.h>
       
    24 #include <unistd.h>
       
    25 #include "cli/cli.h"
       
    26 #include "daemon.h"
       
    27 
       
    28 const char* cli_program = "vmailmgrd";
       
    29 const char* cli_help_prefix = "vmailmgr support daemon\n";
       
    30 const char* cli_help_suffix = "";
       
    31 const char* cli_args_usage = "";
       
    32 const int cli_args_min = 0;
       
    33 const int cli_args_max = 0;
       
    34 int opt_log_all = true;
       
    35 int opt_verbose = false;
       
    36 
       
    37 // This program is the local server that controls the operation of many
       
    38 // parts of this package.
       
    39 // It is currently used to handle password checking and virtual user
       
    40 // lookups, but will eventually contain the functionality to handle adding
       
    41 // and deleting users and aliases, and changing passwords.
       
    42 //
       
    43 // F<vmailmgrd> logs its activity to standard output, and as such
       
    44 // requires its output to be piped through a tool to
       
    45 // record those logs, such as F<accustamp> and F<cyclog> (from the
       
    46 // F<daemontools> package), or
       
    47 // F<splogger> (included with the F<qmail> package).
       
    48 
       
    49 cli_option cli_options[] = {
       
    50   { 'd', 0, cli_option::flag, 0, &opt_log_all,
       
    51     "Log only requests that fail", 0 },
       
    52   { 'D', 0, cli_option::flag, 1, &opt_log_all,
       
    53     "Log all requests (default)", 0 },
       
    54   { 'v', 0, cli_option::flag, 0, &opt_verbose,
       
    55     "Log non-verbosely (default)", 0 },
       
    56   { 'V', 0, cli_option::flag, 1, &opt_verbose,
       
    57     "Log verbosely", 0 },
       
    58   // Log verbose messages regarding the system's status.
       
    59   // Note that this flag implies C<-D>.
       
    60   {0}
       
    61 };
       
    62 
       
    63 // SEE ALSO
       
    64 //
       
    65 // vdeliver(1), checkvpw(8)
       
    66 
       
    67 #define TIMEOUT 1
       
    68 
       
    69 static inline void die(const char* msg)
       
    70 {
       
    71   perror(msg);
       
    72   exit(1);
       
    73 }
       
    74 
       
    75 static void finishreq()
       
    76 {
       
    77   alarm(0);
       
    78   close(0);
       
    79   close(1);
       
    80 }
       
    81 
       
    82 static void abortreq(const char* m)
       
    83 {
       
    84   logresponse(response(response::bad, m));
       
    85   finishreq();
       
    86 }
       
    87 
       
    88 static RETSIGTYPE handle_hup(int)
       
    89 {
       
    90   signal(SIGHUP, handle_hup);
       
    91   log("Stray SIGHUP caught");
       
    92 }
       
    93 
       
    94 static RETSIGTYPE handle_alrm(int)
       
    95 {
       
    96   signal(SIGALRM, handle_alrm);
       
    97   abortreq("Timed out waiting for remote");
       
    98   exit(1);
       
    99 }
       
   100 
       
   101 static RETSIGTYPE handle_pipe(int) 
       
   102 {
       
   103   signal(SIGPIPE, handle_pipe);
       
   104   abortreq("Connection to client lost");
       
   105   exit(1);
       
   106 }
       
   107 
       
   108 static RETSIGTYPE handle_intr(int)
       
   109 {
       
   110   signal(SIGINT, handle_intr);
       
   111   signal(SIGTERM, handle_intr);
       
   112   log("Stray interrupt caught");
       
   113 }
       
   114 
       
   115 bool decode_string(mystring& str, uchar*& buf, ssize_t& buflen)
       
   116 {
       
   117   ssize_t length = (buf[0] << 8) | buf[1];
       
   118   buf += 2; buflen -= 2;
       
   119   if(length > buflen)
       
   120     return false;
       
   121   str = mystring((char*)buf, length);
       
   122   buf += length; buflen -= length;
       
   123   return true;
       
   124 }
       
   125   
       
   126 #define FAIL(MSG) do { abortreq(MSG ", aborting"); return 0; } while(0);
       
   127 
       
   128 command* decode_data(uchar* ptr, ssize_t length)
       
   129 {
       
   130   uchar argcount = *ptr++;
       
   131   --length;
       
   132   mystring cmdstr;
       
   133   if(!decode_string(cmdstr, ptr, length))
       
   134     FAIL("Couldn't decode the command string");
       
   135   if(cmdstr.empty())
       
   136     FAIL("Empty command string");
       
   137   command* cmd = new command(cmdstr, argcount);
       
   138   for(unsigned i = 0; i < argcount; i++) {
       
   139     mystring str;
       
   140     if(!decode_string((*cmd)[i], ptr, length)) {
       
   141       delete cmd;
       
   142       FAIL("Error decoding a command parameter");
       
   143     }
       
   144   }
       
   145   return cmd;
       
   146 }
       
   147 
       
   148 command* read_data() 
       
   149 {
       
   150   alarm(TIMEOUT); // avoid denial-of-service by faulty clients
       
   151 
       
   152   uchar hdrbuf[3];
       
   153   switch(read(0, &hdrbuf, 3)) {
       
   154   case -1: FAIL("read system call failed or was interrupted");
       
   155   case 3: break;
       
   156   default: FAIL("Short read while reading protocol header");
       
   157   }
       
   158   if(hdrbuf[0] != 2)
       
   159     FAIL("Invalid protocol from client");
       
   160   ssize_t length = (hdrbuf[1] << 8) | hdrbuf[2];
       
   161   uchar buf[length];
       
   162   if(read(0, buf, length) != length)
       
   163     FAIL("Short read while reading message data");
       
   164   alarm(0);
       
   165   return decode_data(buf, length);
       
   166 }
       
   167 
       
   168 int cli_main(int, char**)
       
   169 {
       
   170   if(opt_verbose)
       
   171     opt_log_all = true;
       
   172 
       
   173   signal(SIGALRM, handle_alrm);
       
   174   signal(SIGPIPE, handle_pipe);
       
   175   signal(SIGINT, handle_intr);
       
   176   signal(SIGTERM, handle_intr);
       
   177   signal(SIGHUP, handle_hup);
       
   178   signal(SIGQUIT, handle_intr);
       
   179   
       
   180   if(opt_verbose)
       
   181     log("Accepted connection");
       
   182   command* cmd = read_data();
       
   183   if(cmd) {
       
   184     response resp = dispatch_cmd(*cmd, 1);
       
   185     logresponse(resp);
       
   186     alarm(TIMEOUT);
       
   187     if(!resp.write(1))
       
   188       abortreq("Error writing response");
       
   189     finishreq();
       
   190     delete cmd;
       
   191   }
       
   192 
       
   193   return 0;
       
   194 }