| [67] | 1 | /* SAMHAIN file system integrity testing                                   */
 | 
|---|
 | 2 | /* Copyright (C) 2006 Rainer Wichmann                                      */
 | 
|---|
 | 3 | /*                                                                         */
 | 
|---|
 | 4 | /*  This program is free software; you can redistribute it                 */
 | 
|---|
 | 5 | /*  and/or modify                                                          */
 | 
|---|
 | 6 | /*  it under the terms of the GNU General Public License as                */
 | 
|---|
 | 7 | /*  published by                                                           */
 | 
|---|
 | 8 | /*  the Free Software Foundation; either version 2 of the License, or      */
 | 
|---|
 | 9 | /*  (at your option) any later version.                                    */
 | 
|---|
 | 10 | /*                                                                         */
 | 
|---|
 | 11 | /*  This program is distributed in the hope that it will be useful,        */
 | 
|---|
 | 12 | /*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
 | 
|---|
 | 13 | /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
 | 
|---|
 | 14 | /*  GNU General Public License for more details.                           */
 | 
|---|
 | 15 | /*                                                                         */
 | 
|---|
 | 16 | /*  You should have received a copy of the GNU General Public License      */
 | 
|---|
 | 17 | /*  along with this program; if not, write to the Free Software            */
 | 
|---|
 | 18 | /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
 | 
|---|
 | 19 | 
 | 
|---|
 | 20 | /***************************************************************************
 | 
|---|
 | 21 |  *
 | 
|---|
 | 22 |  * This file provides a module for samhain to check for open ports
 | 
|---|
 | 23 |  * on the local machine.
 | 
|---|
 | 24 |  *
 | 
|---|
 | 25 |  */
 | 
|---|
 | 26 | 
 | 
|---|
 | 27 | 
 | 
|---|
 | 28 | /* #define TEST_ONLY */
 | 
|---|
 | 29 | #ifndef TEST_ONLY
 | 
|---|
 | 30 | #include "config_xor.h"
 | 
|---|
 | 31 | #endif
 | 
|---|
 | 32 | 
 | 
|---|
 | 33 | #include <stdio.h>
 | 
|---|
 | 34 | #include <string.h>
 | 
|---|
 | 35 | #include <sys/types.h>
 | 
|---|
 | 36 | #include <sys/socket.h>
 | 
|---|
 | 37 | #include <netinet/in.h>
 | 
|---|
 | 38 | #include <arpa/inet.h>
 | 
|---|
 | 39 | #include <errno.h>
 | 
|---|
 | 40 | #include <unistd.h>
 | 
|---|
| [109] | 41 | #include <fcntl.h>
 | 
|---|
| [67] | 42 | 
 | 
|---|
| [76] | 43 | #define PORTCHK_VERSION "1.0"
 | 
|---|
 | 44 | 
 | 
|---|
 | 45 | #if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)))
 | 
|---|
 | 46 | 
 | 
|---|
 | 47 | 
 | 
|---|
| [67] | 48 | #define PORTMAP
 | 
|---|
 | 49 | #include <rpc/rpc.h>
 | 
|---|
 | 50 | #ifdef  HAVE_RPC_RPCENT_H
 | 
|---|
 | 51 | #include <rpc/rpcent.h>
 | 
|---|
 | 52 | #endif
 | 
|---|
 | 53 | #include <rpc/pmap_clnt.h>
 | 
|---|
 | 54 | #include <rpc/pmap_prot.h>
 | 
|---|
 | 55 | #include <netdb.h>
 | 
|---|
 | 56 | 
 | 
|---|
 | 57 | /*
 | 
|---|
 | 58 |  * struct pmaplist {
 | 
|---|
 | 59 |  *      struct pmap     pml_map;
 | 
|---|
 | 60 |  *      struct pmaplist *pml_next;
 | 
|---|
 | 61 |  * };
 | 
|---|
 | 62 |  */
 | 
|---|
 | 63 | 
 | 
|---|
 | 64 | /* struct pmap {
 | 
|---|
 | 65 |  *      long unsigned pm_prog;
 | 
|---|
 | 66 |  *      long unsigned pm_vers;
 | 
|---|
 | 67 |  *      long unsigned pm_prot;
 | 
|---|
 | 68 |  *      long unsigned pm_port;
 | 
|---|
 | 69 |  * };
 | 
|---|
 | 70 |  */
 | 
|---|
 | 71 | 
 | 
|---|
 | 72 | /* TIME_WAIT ? 60-240 seconds */
 | 
|---|
 | 73 | 
 | 
|---|
 | 74 | /* the size of an interface string 
 | 
|---|
 | 75 |  */
 | 
|---|
 | 76 | #define SH_INTERFACE_SIZE 16
 | 
|---|
 | 77 | 
 | 
|---|
 | 78 | #define SH_PORT_NOT 0
 | 
|---|
 | 79 | #define SH_PORT_REQ 1
 | 
|---|
 | 80 | #define SH_PORT_OPT 2
 | 
|---|
| [127] | 81 | #define SH_PORT_IGN 3
 | 
|---|
| [67] | 82 | 
 | 
|---|
 | 83 | #define SH_PORT_MISS 0
 | 
|---|
 | 84 | #define SH_PORT_ISOK 1
 | 
|---|
 | 85 | #define SH_PORT_UNKN 2
 | 
|---|
 | 86 | 
 | 
|---|
 | 87 | #define SH_PORT_NOREPT 0
 | 
|---|
 | 88 | #define SH_PORT_REPORT 1
 | 
|---|
 | 89 | 
 | 
|---|
 | 90 | struct sh_portentry {
 | 
|---|
 | 91 |   int  port;
 | 
|---|
 | 92 |   char interface[SH_INTERFACE_SIZE];
 | 
|---|
 | 93 |   char * service;
 | 
|---|
 | 94 |   char * error;
 | 
|---|
 | 95 |   int  flag;    /* required or not */
 | 
|---|
 | 96 |   int  status;  /* missing or not  */
 | 
|---|
 | 97 |   struct sh_portentry * next;
 | 
|---|
 | 98 | };
 | 
|---|
 | 99 | 
 | 
|---|
 | 100 | static struct sh_portentry * portlist_tcp = NULL;
 | 
|---|
 | 101 | static struct sh_portentry * portlist_udp = NULL;
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 | #define SH_PORTCHK_INTERVAL 300
 | 
|---|
 | 104 | 
 | 
|---|
 | 105 | static int sh_portchk_check_udp = 1;
 | 
|---|
 | 106 | static int sh_portchk_active    = 1;
 | 
|---|
 | 107 | static int sh_portchk_interval  = SH_PORTCHK_INTERVAL;
 | 
|---|
 | 108 | #if !defined(TEST_ONLY)
 | 
|---|
 | 109 | 
 | 
|---|
 | 110 | #define FIL__ _("sh_portcheck.c")
 | 
|---|
 | 111 | #include "samhain.h"
 | 
|---|
 | 112 | #include "sh_error.h"
 | 
|---|
 | 113 | #include "sh_mem.h"
 | 
|---|
| [109] | 114 | #include "sh_calls.h"
 | 
|---|
| [67] | 115 | #include "sh_utils.h"
 | 
|---|
 | 116 | #include "sh_modules.h"
 | 
|---|
 | 117 | 
 | 
|---|
 | 118 | static int sh_portchk_severity  = SH_ERR_SEVERE;
 | 
|---|
 | 119 | #endif
 | 
|---|
 | 120 | 
 | 
|---|
| [127] | 121 | /* Exported interface to add ignoreable ports as 'iface:portlist'
 | 
|---|
 | 122 |  */
 | 
|---|
 | 123 | static int sh_portchk_add_ignore (const char * str);
 | 
|---|
 | 124 | 
 | 
|---|
| [67] | 125 | /* Exported interface to add required ports as 'iface:portlist'
 | 
|---|
 | 126 |  */
 | 
|---|
 | 127 | static int sh_portchk_add_required (const char * str);
 | 
|---|
 | 128 | 
 | 
|---|
 | 129 | /* Exported interface to add optional ports as 'iface:portlist'
 | 
|---|
 | 130 |  */
 | 
|---|
 | 131 | static int sh_portchk_add_optional (const char * str);
 | 
|---|
 | 132 | 
 | 
|---|
 | 133 | /* Exported interface to add an ethernet interface
 | 
|---|
 | 134 |  */
 | 
|---|
 | 135 | static int sh_portchk_add_interface (const char * str);
 | 
|---|
 | 136 | 
 | 
|---|
 | 137 | 
 | 
|---|
 | 138 | #ifndef TEST_ONLY
 | 
|---|
 | 139 | 
 | 
|---|
 | 140 | static int sh_portchk_set_interval (const char * c)
 | 
|---|
 | 141 | {
 | 
|---|
 | 142 |   int retval = 0;
 | 
|---|
 | 143 |   long val;
 | 
|---|
 | 144 | 
 | 
|---|
 | 145 |   SL_ENTER(_("sh_portchk_set_interval"));
 | 
|---|
 | 146 |   val = strtol (c, (char **)NULL, 10);
 | 
|---|
 | 147 |   if (val <= 0)
 | 
|---|
 | 148 |     {
 | 
|---|
 | 149 |       sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
 | 
|---|
 | 150 |                        _("port check interval"), c);
 | 
|---|
 | 151 |       retval = -1;
 | 
|---|
 | 152 |     }
 | 
|---|
 | 153 | 
 | 
|---|
 | 154 |   val = (val <= 0 ? 60 : val);
 | 
|---|
 | 155 | 
 | 
|---|
 | 156 |   sh_portchk_interval = (time_t) val;
 | 
|---|
 | 157 |   SL_RETURN(0, _("sh_portchk_set_interval"));
 | 
|---|
 | 158 | }
 | 
|---|
 | 159 | 
 | 
|---|
 | 160 | 
 | 
|---|
 | 161 | static int sh_portchk_set_active   (const char * str)
 | 
|---|
 | 162 | {
 | 
|---|
 | 163 |   return sh_util_flagval(str, &sh_portchk_active);
 | 
|---|
 | 164 | }
 | 
|---|
 | 165 | 
 | 
|---|
 | 166 | static int sh_portchk_set_udp      (const char * str)
 | 
|---|
 | 167 | {
 | 
|---|
 | 168 |   return sh_util_flagval(str, &sh_portchk_check_udp);
 | 
|---|
 | 169 | }
 | 
|---|
 | 170 | 
 | 
|---|
 | 171 | static int sh_portchk_set_severity (const char * str)
 | 
|---|
 | 172 | {
 | 
|---|
 | 173 |   char tmp[32];
 | 
|---|
 | 174 |   tmp[0] = '='; tmp[1] = '\0';
 | 
|---|
 | 175 |   sl_strlcat (tmp, str, 32);
 | 
|---|
 | 176 |   return sh_error_set_level (tmp, &sh_portchk_severity);
 | 
|---|
 | 177 | }
 | 
|---|
 | 178 | 
 | 
|---|
 | 179 | sh_rconf sh_portchk_table[] = {
 | 
|---|
 | 180 |     {
 | 
|---|
 | 181 |         N_("severityportcheck"),
 | 
|---|
 | 182 |         sh_portchk_set_severity,
 | 
|---|
 | 183 |     },
 | 
|---|
 | 184 |     {
 | 
|---|
 | 185 |         N_("portcheckrequired"),
 | 
|---|
 | 186 |         sh_portchk_add_required,
 | 
|---|
 | 187 |     },
 | 
|---|
 | 188 |     {
 | 
|---|
 | 189 |         N_("portcheckoptional"),
 | 
|---|
 | 190 |         sh_portchk_add_optional,
 | 
|---|
 | 191 |     },
 | 
|---|
 | 192 |     {
 | 
|---|
| [127] | 193 |         N_("portcheckignore"),
 | 
|---|
 | 194 |         sh_portchk_add_ignore,
 | 
|---|
 | 195 |     },
 | 
|---|
 | 196 |     {
 | 
|---|
| [67] | 197 |         N_("portcheckactive"),
 | 
|---|
 | 198 |         sh_portchk_set_active,
 | 
|---|
 | 199 |     },
 | 
|---|
 | 200 |     {
 | 
|---|
 | 201 |         N_("portcheckinterface"),
 | 
|---|
 | 202 |         sh_portchk_add_interface,
 | 
|---|
 | 203 |     },
 | 
|---|
 | 204 |     {
 | 
|---|
 | 205 |         N_("portcheckinterval"),
 | 
|---|
 | 206 |         sh_portchk_set_interval,
 | 
|---|
 | 207 |     },
 | 
|---|
 | 208 |     {
 | 
|---|
 | 209 |         N_("portcheckudp"),
 | 
|---|
 | 210 |         sh_portchk_set_udp,
 | 
|---|
 | 211 |     },
 | 
|---|
 | 212 |     {
 | 
|---|
 | 213 |         NULL,
 | 
|---|
 | 214 |         NULL
 | 
|---|
 | 215 |     }
 | 
|---|
 | 216 | };
 | 
|---|
 | 217 | 
 | 
|---|
 | 218 | #endif
 | 
|---|
 | 219 | 
 | 
|---|
 | 220 | /* Interface to initialize port check
 | 
|---|
 | 221 |  */
 | 
|---|
 | 222 | int sh_portchk_init ();
 | 
|---|
 | 223 | 
 | 
|---|
 | 224 | /* Interface to reset port check
 | 
|---|
 | 225 |  */
 | 
|---|
 | 226 | int sh_portchk_reset ();
 | 
|---|
 | 227 | 
 | 
|---|
 | 228 | /* Interface to run port check
 | 
|---|
 | 229 |  */
 | 
|---|
 | 230 | int sh_portchk_check ();
 | 
|---|
 | 231 | 
 | 
|---|
 | 232 | 
 | 
|---|
 | 233 | static char * check_services (int port, char * proto);
 | 
|---|
 | 234 | 
 | 
|---|
 | 235 | #ifdef TEST_ONLY
 | 
|---|
 | 236 | 
 | 
|---|
 | 237 | static int portchk_debug = 0;
 | 
|---|
 | 238 | #define SH_ALLOC       malloc
 | 
|---|
 | 239 | #define SH_FREE        free
 | 
|---|
 | 240 | #define sh_util_strdup strdup
 | 
|---|
 | 241 | #define sl_strlcpy     strncpy
 | 
|---|
 | 242 | #define _(a)           a
 | 
|---|
 | 243 | 
 | 
|---|
 | 244 | #else
 | 
|---|
 | 245 | 
 | 
|---|
 | 246 | static int portchk_debug = 0;
 | 
|---|
 | 247 | 
 | 
|---|
 | 248 | #endif
 | 
|---|
 | 249 | 
 | 
|---|
 | 250 | static void sh_portchk_add_to_list (char * proto, 
 | 
|---|
 | 251 |                                     int port, struct in_addr haddr, char * service,
 | 
|---|
 | 252 |                                     int flag, int status)
 | 
|---|
 | 253 | {
 | 
|---|
 | 254 |   struct sh_portentry * new = SH_ALLOC (sizeof(struct sh_portentry));
 | 
|---|
 | 255 | 
 | 
|---|
 | 256 |   if (portchk_debug)
 | 
|---|
 | 257 |     fprintf(stderr, _("add to list: port %d/%s %d %d (%s)\n"),
 | 
|---|
 | 258 |             port, proto, flag, status, service ? service : _("undef"));
 | 
|---|
 | 259 | 
 | 
|---|
 | 260 |   new->port = port;
 | 
|---|
 | 261 |   sl_strlcpy (new->interface, inet_ntoa(haddr), SH_INTERFACE_SIZE);
 | 
|---|
 | 262 |   new->status = status;
 | 
|---|
 | 263 |   new->flag   = flag;
 | 
|---|
 | 264 | 
 | 
|---|
 | 265 |   new->error  = NULL;
 | 
|---|
 | 266 | 
 | 
|---|
 | 267 |   if (service)
 | 
|---|
 | 268 |     new->service = sh_util_strdup (service);
 | 
|---|
 | 269 |   else
 | 
|---|
 | 270 |     new->service = NULL;
 | 
|---|
 | 271 |   if (0 == strcmp(proto, "tcp"))
 | 
|---|
 | 272 |     {
 | 
|---|
 | 273 |       new->next = portlist_tcp;
 | 
|---|
 | 274 |       portlist_tcp = new;
 | 
|---|
 | 275 |     }
 | 
|---|
 | 276 |   else
 | 
|---|
 | 277 |     {
 | 
|---|
 | 278 |       new->next = portlist_udp;
 | 
|---|
 | 279 |       portlist_udp = new;
 | 
|---|
 | 280 |     }
 | 
|---|
 | 281 |   return;
 | 
|---|
 | 282 | }
 | 
|---|
 | 283 | 
 | 
|---|
 | 284 | /* Reset the list by setting all entries to UNKN.
 | 
|---|
 | 285 |  * In the next cycle we will check, and set found ports to ISOK.
 | 
|---|
 | 286 |  * Thereafter, we check for entries that are still UNKN.
 | 
|---|
 | 287 |  */
 | 
|---|
 | 288 | static void sh_portchk_reset_lists ()
 | 
|---|
 | 289 | {
 | 
|---|
 | 290 |   struct sh_portentry * portlist;
 | 
|---|
 | 291 | 
 | 
|---|
 | 292 |   portlist = portlist_tcp;
 | 
|---|
 | 293 |   while (portlist)
 | 
|---|
 | 294 |     {
 | 
|---|
 | 295 |       if (portlist->status != SH_PORT_MISS)
 | 
|---|
 | 296 |         portlist->status = SH_PORT_UNKN;
 | 
|---|
 | 297 |       portlist = portlist->next;
 | 
|---|
 | 298 |     }
 | 
|---|
 | 299 |   portlist = portlist_udp;
 | 
|---|
 | 300 |   while (portlist)
 | 
|---|
 | 301 |     {
 | 
|---|
 | 302 |       if (portlist->status != SH_PORT_MISS)
 | 
|---|
 | 303 |         portlist->status = SH_PORT_UNKN;
 | 
|---|
 | 304 |       portlist = portlist->next;
 | 
|---|
 | 305 |     }
 | 
|---|
 | 306 |   return;
 | 
|---|
 | 307 | }
 | 
|---|
 | 308 | 
 | 
|---|
 | 309 | static struct sh_portentry * sh_portchk_kill_list (struct sh_portentry * head)
 | 
|---|
 | 310 | {
 | 
|---|
 | 311 |   if (head)
 | 
|---|
 | 312 |     {
 | 
|---|
 | 313 |       if (head->next)
 | 
|---|
 | 314 |         sh_portchk_kill_list (head->next);
 | 
|---|
 | 315 | 
 | 
|---|
 | 316 |       if (head->service)
 | 
|---|
 | 317 |         SH_FREE(head->service);
 | 
|---|
 | 318 |       SH_FREE(head);
 | 
|---|
 | 319 |     }
 | 
|---|
 | 320 |   return NULL;
 | 
|---|
 | 321 | }
 | 
|---|
 | 322 |   
 | 
|---|
 | 323 | /* check the list of open ports for any that are marked as UNKN
 | 
|---|
 | 324 |  */
 | 
|---|
 | 325 | static void sh_portchk_check_list (struct sh_portentry ** head, char * proto, int report)
 | 
|---|
 | 326 | {
 | 
|---|
 | 327 |   struct sh_portentry * ptr = *head;
 | 
|---|
 | 328 |   struct sh_portentry * pre = *head;
 | 
|---|
 | 329 |   char errbuf[256];
 | 
|---|
 | 330 | 
 | 
|---|
 | 331 |   while (ptr)
 | 
|---|
 | 332 |     {
 | 
|---|
 | 333 |       if (portchk_debug && report)
 | 
|---|
 | 334 |         fprintf(stderr, _("check list: port %d/%s %d %d\n"),
 | 
|---|
 | 335 |                 ptr->port, proto, ptr->flag, ptr->status);
 | 
|---|
 | 336 | 
 | 
|---|
 | 337 |       if (ptr->status == SH_PORT_UNKN)
 | 
|---|
 | 338 |         {
 | 
|---|
 | 339 |           /* Don't report missing ports that are marked as optional
 | 
|---|
 | 340 |            */
 | 
|---|
| [127] | 341 |           if (ptr->flag != SH_PORT_OPT && ptr->flag != SH_PORT_IGN)
 | 
|---|
| [67] | 342 |             {
 | 
|---|
 | 343 |               snprintf (errbuf, sizeof(errbuf), _("POLICY [ServiceMissing] port %s:%d/%s (%s)"), 
 | 
|---|
 | 344 |                         ptr->interface, ptr->port, proto, 
 | 
|---|
 | 345 |                         ptr->service ? ptr->service : check_services(ptr->port, proto));
 | 
|---|
 | 346 | #ifdef TEST_ONLY
 | 
|---|
 | 347 |               if (report == SH_PORT_REPORT)
 | 
|---|
 | 348 |                 fprintf(stderr, _("%s\n"), errbuf);
 | 
|---|
 | 349 | #else
 | 
|---|
 | 350 |               if (report == SH_PORT_REPORT)
 | 
|---|
 | 351 |                 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 352 |                                 MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 353 | #endif
 | 
|---|
 | 354 |             }
 | 
|---|
 | 355 | 
 | 
|---|
 | 356 |           ptr->status = SH_PORT_MISS;
 | 
|---|
 | 357 | 
 | 
|---|
| [128] | 358 |           if ((ptr->flag != SH_PORT_REQ) && (ptr->flag != SH_PORT_OPT) && (ptr->flag != SH_PORT_IGN))
 | 
|---|
| [67] | 359 |             {
 | 
|---|
 | 360 |               if (portchk_debug && report)
 | 
|---|
 | 361 |                 fprintf(stderr, _("removing: port %d/%s %d %d\n"),
 | 
|---|
 | 362 |                         ptr->port, proto, ptr->flag, ptr->status);
 | 
|---|
 | 363 |               
 | 
|---|
 | 364 |               if (ptr == *head)
 | 
|---|
 | 365 |                 {
 | 
|---|
 | 366 |                   *head = ptr->next;
 | 
|---|
 | 367 |                   if (ptr->service)
 | 
|---|
 | 368 |                     SH_FREE(ptr->service);
 | 
|---|
 | 369 |                   SH_FREE(ptr);
 | 
|---|
 | 370 |                   ptr = *head;
 | 
|---|
 | 371 |                   pre = *head;
 | 
|---|
 | 372 |                   continue;
 | 
|---|
 | 373 |                 }
 | 
|---|
 | 374 |               else if (ptr->next == NULL)
 | 
|---|
 | 375 |                 {
 | 
|---|
 | 376 |                   pre->next = NULL;
 | 
|---|
 | 377 |                   if (ptr->service)
 | 
|---|
 | 378 |                     SH_FREE(ptr->service);
 | 
|---|
 | 379 |                   SH_FREE(ptr);
 | 
|---|
 | 380 |                   return;
 | 
|---|
 | 381 |                 }
 | 
|---|
 | 382 |               else
 | 
|---|
 | 383 |                 {
 | 
|---|
 | 384 |                   pre->next = ptr->next;
 | 
|---|
 | 385 |                   if (ptr->service)
 | 
|---|
 | 386 |                     SH_FREE(ptr->service);
 | 
|---|
 | 387 |                   SH_FREE(ptr);
 | 
|---|
 | 388 |                   ptr = pre->next;
 | 
|---|
 | 389 |                   continue;
 | 
|---|
 | 390 |                 }
 | 
|---|
 | 391 |             }
 | 
|---|
 | 392 |         }
 | 
|---|
 | 393 |       pre = ptr;
 | 
|---|
 | 394 |       ptr = ptr->next;
 | 
|---|
 | 395 |     }
 | 
|---|
 | 396 |   return;
 | 
|---|
 | 397 | }
 | 
|---|
 | 398 | 
 | 
|---|
 | 399 | 
 | 
|---|
 | 400 | static struct sh_portentry * sh_portchk_get_from_list (char * proto, int port, 
 | 
|---|
 | 401 |                                                        struct in_addr haddr, char * service)
 | 
|---|
 | 402 | {
 | 
|---|
 | 403 |   struct sh_portentry * portlist;
 | 
|---|
| [75] | 404 |   char iface_all[8];
 | 
|---|
 | 405 | 
 | 
|---|
 | 406 |   sl_strlcpy (iface_all, _("0.0.0.0"), sizeof(iface_all));
 | 
|---|
| [67] | 407 |   
 | 
|---|
 | 408 |   if (0 == strcmp(proto, "tcp"))
 | 
|---|
 | 409 |     portlist = portlist_tcp;
 | 
|---|
 | 410 |   else
 | 
|---|
 | 411 |     portlist = portlist_udp;
 | 
|---|
 | 412 | 
 | 
|---|
 | 413 |   if (service)
 | 
|---|
 | 414 |     {
 | 
|---|
 | 415 |       while (portlist) 
 | 
|---|
 | 416 |         {
 | 
|---|
 | 417 |           if (portlist->service && 
 | 
|---|
 | 418 |               0 == strcmp(service, portlist->service) &&
 | 
|---|
 | 419 |               (0 == strcmp(portlist->interface, inet_ntoa(haddr)) ||
 | 
|---|
 | 420 |                0 == strcmp(portlist->interface, iface_all)))
 | 
|---|
 | 421 |             return portlist;
 | 
|---|
 | 422 |           portlist = portlist->next;
 | 
|---|
 | 423 |         }
 | 
|---|
 | 424 |     }
 | 
|---|
 | 425 |   else
 | 
|---|
 | 426 |     {
 | 
|---|
 | 427 |       while (portlist) 
 | 
|---|
 | 428 |         {
 | 
|---|
 | 429 |           if (port == portlist->port &&
 | 
|---|
 | 430 |               (0 == strcmp(portlist->interface, inet_ntoa(haddr)) ||
 | 
|---|
 | 431 |                0 == strcmp(portlist->interface, iface_all)))
 | 
|---|
 | 432 |             return portlist;
 | 
|---|
 | 433 |           portlist = portlist->next;
 | 
|---|
 | 434 |         }
 | 
|---|
 | 435 |     }
 | 
|---|
 | 436 |   return NULL;
 | 
|---|
 | 437 | }
 | 
|---|
 | 438 |       
 | 
|---|
 | 439 | 
 | 
|---|
 | 440 | static void sh_portchk_cmp_to_list (char * proto, int port, struct in_addr haddr, char * service)
 | 
|---|
 | 441 | {
 | 
|---|
 | 442 |   struct sh_portentry * portent;
 | 
|---|
 | 443 |   char errbuf[256];
 | 
|---|
 | 444 | 
 | 
|---|
 | 445 |   
 | 
|---|
 | 446 |   portent = sh_portchk_get_from_list (proto, port, haddr, service);
 | 
|---|
 | 447 | 
 | 
|---|
 | 448 |   if (service)
 | 
|---|
 | 449 |     {
 | 
|---|
 | 450 |       if (!portent)
 | 
|---|
 | 451 |         {
 | 
|---|
 | 452 |           snprintf (errbuf, sizeof(errbuf), _("POLICY [ServiceNew] port %s:%d/%s (%s)"), 
 | 
|---|
 | 453 |                     inet_ntoa(haddr), port, proto, service);
 | 
|---|
 | 454 | #ifdef TEST_ONLY
 | 
|---|
 | 455 |           fprintf(stderr, _("open port: %s:%d/%s (%s)\n"), 
 | 
|---|
 | 456 |                   inet_ntoa(haddr), port, proto, service);
 | 
|---|
 | 457 | #else
 | 
|---|
 | 458 |           sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 459 |                           MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 460 | #endif
 | 
|---|
 | 461 |           /* 
 | 
|---|
 | 462 |            * was not there, thus it is not in 'required' or 'optional' list
 | 
|---|
 | 463 |            */
 | 
|---|
 | 464 |           sh_portchk_add_to_list (proto, port, haddr, service, SH_PORT_NOT, SH_PORT_ISOK);
 | 
|---|
 | 465 |         }
 | 
|---|
| [127] | 466 |       else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
 | 
|---|
| [67] | 467 |         {
 | 
|---|
 | 468 |           snprintf (errbuf, sizeof(errbuf), _("POLICY [ServiceRestarted] port %s:%d/%s to %d/%s (%s)"), 
 | 
|---|
 | 469 |                     inet_ntoa(haddr), portent->port, proto, port, proto, service);
 | 
|---|
 | 470 | #ifdef TEST_ONLY
 | 
|---|
 | 471 |           fprintf(stderr, _("service: %s\n"), errbuf);
 | 
|---|
 | 472 | #else
 | 
|---|
 | 473 |           sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 474 |                           MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 475 | #endif
 | 
|---|
 | 476 | 
 | 
|---|
 | 477 |           portent->status = SH_PORT_ISOK;
 | 
|---|
 | 478 |         }
 | 
|---|
 | 479 |       else if (port != portent->port && (-1) != portent->port)
 | 
|---|
 | 480 |         {
 | 
|---|
 | 481 |           snprintf (errbuf, sizeof(errbuf), _("POLICY [ServicePortSwitch] port %s:%d/%s to %d/%s (%s)"), 
 | 
|---|
 | 482 |                     inet_ntoa(haddr), portent->port, proto, port, proto, service);
 | 
|---|
 | 483 | #ifdef TEST_ONLY
 | 
|---|
 | 484 |           fprintf(stderr, _("service: %s\n"), errbuf);
 | 
|---|
 | 485 | #else
 | 
|---|
 | 486 |           sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 487 |                           MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 488 | #endif
 | 
|---|
| [127] | 489 |           portent->port   = port;
 | 
|---|
| [67] | 490 |           portent->status = SH_PORT_ISOK;
 | 
|---|
 | 491 |         }
 | 
|---|
 | 492 |       else
 | 
|---|
 | 493 |         {
 | 
|---|
 | 494 |           portent->status = SH_PORT_ISOK;
 | 
|---|
 | 495 |         }
 | 
|---|
 | 496 |     }
 | 
|---|
 | 497 |   else
 | 
|---|
 | 498 |     {
 | 
|---|
 | 499 |       if (!portent)
 | 
|---|
 | 500 |         {
 | 
|---|
 | 501 |           snprintf (errbuf, sizeof(errbuf), _("POLICY [ServiceNew] port %s:%d/%s (%s)"), 
 | 
|---|
 | 502 |                     inet_ntoa(haddr), port, proto, check_services(port, proto));
 | 
|---|
 | 503 | #ifdef TEST_ONLY
 | 
|---|
 | 504 |           fprintf(stderr, _("open port: %s:%d/%s (%s)\n"), 
 | 
|---|
 | 505 |                   inet_ntoa(haddr), port, proto, check_services(port, proto));
 | 
|---|
 | 506 | #else
 | 
|---|
 | 507 |           sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 508 |                           MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 509 | #endif
 | 
|---|
 | 510 | 
 | 
|---|
 | 511 |           /* was not there, thus it is not in 'required' or 'optional' list
 | 
|---|
 | 512 |            */
 | 
|---|
 | 513 |           sh_portchk_add_to_list (proto, port, haddr, service, SH_PORT_NOT, SH_PORT_ISOK);
 | 
|---|
 | 514 |         }
 | 
|---|
| [127] | 515 |       else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
 | 
|---|
| [67] | 516 |         {
 | 
|---|
 | 517 |           snprintf (errbuf, sizeof(errbuf), _("POLICY [ServiceRestarted] port %s:%d/%s (%s)"), 
 | 
|---|
 | 518 |                     inet_ntoa(haddr), port, proto, check_services(port, proto));
 | 
|---|
 | 519 | #ifdef TEST_ONLY
 | 
|---|
 | 520 |           fprintf(stderr, _("port   : %s\n"), errbuf);
 | 
|---|
 | 521 | #else
 | 
|---|
 | 522 |           sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0, 
 | 
|---|
 | 523 |                           MSG_PORT_REPORT, errbuf);
 | 
|---|
 | 524 | #endif
 | 
|---|
 | 525 | 
 | 
|---|
 | 526 |           portent->status = SH_PORT_ISOK;
 | 
|---|
 | 527 |         }
 | 
|---|
 | 528 |       else
 | 
|---|
 | 529 |         {
 | 
|---|
 | 530 |           portent->status = SH_PORT_ISOK;
 | 
|---|
 | 531 |         }
 | 
|---|
 | 532 |     }
 | 
|---|
 | 533 | 
 | 
|---|
 | 534 |   return;
 | 
|---|
 | 535 | }
 | 
|---|
 | 536 | 
 | 
|---|
 | 537 |                                
 | 
|---|
 | 538 | /* Returns a static buffer containing the name of the service
 | 
|---|
 | 539 |  * running on port <port> (from /etc/services)
 | 
|---|
 | 540 |  * Returns NULL on failure
 | 
|---|
 | 541 |  */
 | 
|---|
 | 542 | static char * check_services (int port, char * proto)
 | 
|---|
 | 543 | {
 | 
|---|
 | 544 |   static char buf[256];
 | 
|---|
 | 545 |   struct servent * service = getservbyport(htons(port), proto);
 | 
|---|
 | 546 | 
 | 
|---|
 | 547 |   if (service && service->s_name && service->s_name[0] != '\0')
 | 
|---|
 | 548 |     {
 | 
|---|
 | 549 |       snprintf (buf, sizeof(buf), _("maybe_%s"), service->s_name);
 | 
|---|
 | 550 |     }
 | 
|---|
 | 551 |   else
 | 
|---|
 | 552 |     {
 | 
|---|
 | 553 |       snprintf (buf, sizeof(buf), _("unknown"));
 | 
|---|
 | 554 |     }
 | 
|---|
 | 555 |   return buf;
 | 
|---|
 | 556 | }
 | 
|---|
 | 557 | 
 | 
|---|
 | 558 | /* Returns a static buffer containing the name of the service
 | 
|---|
 | 559 |  * running on port <port> at <address> (from portmap daemon)
 | 
|---|
 | 560 |  * Returns NULL on failure
 | 
|---|
 | 561 |  */
 | 
|---|
 | 562 | static char * check_rpc_list (int port, struct sockaddr_in * address, 
 | 
|---|
 | 563 |                               unsigned long prot)
 | 
|---|
 | 564 | {
 | 
|---|
 | 565 |   struct pmaplist * head;
 | 
|---|
 | 566 |   struct rpcent *r;
 | 
|---|
 | 567 |   static char buf[256];
 | 
|---|
 | 568 | 
 | 
|---|
 | 569 |   head = pmap_getmaps(address);
 | 
|---|
 | 570 | 
 | 
|---|
 | 571 |   if (head) 
 | 
|---|
 | 572 |     {
 | 
|---|
 | 573 |       do /* while (head != NULL) */
 | 
|---|
 | 574 |         {
 | 
|---|
 | 575 |           if ((head->pml_map.pm_prot == prot) && 
 | 
|---|
 | 576 |               (port == (int)head->pml_map.pm_port)) 
 | 
|---|
 | 577 |             {
 | 
|---|
 | 578 |               r = getrpcbynumber((int)head->pml_map.pm_prog);
 | 
|---|
 | 579 |               if (r && r->r_name && r->r_name[0] != '\0')
 | 
|---|
 | 580 |                 {
 | 
|---|
 | 581 |                   snprintf (buf, sizeof(buf), "%s", r->r_name);
 | 
|---|
 | 582 |                   return buf;
 | 
|---|
 | 583 |                 }
 | 
|---|
 | 584 |               else
 | 
|---|
 | 585 |                 {
 | 
|---|
 | 586 |                   snprintf (buf, sizeof(buf), "RPC_%lu",
 | 
|---|
 | 587 |                             (unsigned long)head->pml_map.pm_prog);
 | 
|---|
 | 588 |                   return buf;
 | 
|---|
 | 589 |                 }
 | 
|---|
 | 590 |             }
 | 
|---|
 | 591 |           head = head->pml_next;
 | 
|---|
 | 592 |         }
 | 
|---|
 | 593 |       while (head != NULL);
 | 
|---|
 | 594 |     }
 | 
|---|
 | 595 | 
 | 
|---|
 | 596 |   return NULL;
 | 
|---|
 | 597 | }
 | 
|---|
 | 598 | 
 | 
|---|
 | 599 | static int check_port_udp_internal (int fd, int port, struct in_addr haddr)
 | 
|---|
 | 600 | {
 | 
|---|
 | 601 |   struct sockaddr_in sinr;
 | 
|---|
 | 602 |   /* struct in_addr     haddr; */
 | 
|---|
 | 603 |   int                retval;
 | 
|---|
 | 604 |   char             * p;
 | 
|---|
 | 605 |   char               buf[8];
 | 
|---|
| [78] | 606 | #ifndef TEST_ONLY
 | 
|---|
 | 607 |   char               errmsg[256];
 | 
|---|
 | 608 |   int                nerr;
 | 
|---|
 | 609 | #endif
 | 
|---|
| [132] | 610 |   char errbuf[SH_ERRBUF_SIZE];
 | 
|---|
| [67] | 611 | 
 | 
|---|
 | 612 |   /* inet_aton(interface, &haddr); */
 | 
|---|
 | 613 | 
 | 
|---|
 | 614 |   sinr.sin_family = AF_INET;
 | 
|---|
 | 615 |   sinr.sin_port   = htons (port);
 | 
|---|
 | 616 |   sinr.sin_addr   = haddr;
 | 
|---|
 | 617 | 
 | 
|---|
| [78] | 618 |   do {
 | 
|---|
 | 619 |     retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
 | 
|---|
 | 620 |   } while (retval < 0 && errno == EINTR);
 | 
|---|
 | 621 | 
 | 
|---|
| [67] | 622 |   if (retval == -1)
 | 
|---|
 | 623 |     {
 | 
|---|
 | 624 | #ifdef TEST_ONLY
 | 
|---|
 | 625 |       if (portchk_debug)
 | 
|---|
 | 626 |         perror(_("connect"));
 | 
|---|
 | 627 | #else
 | 
|---|
| [78] | 628 |       nerr = errno;
 | 
|---|
 | 629 |       sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/udp on %15s: %s"),
 | 
|---|
| [132] | 630 |                   port, inet_ntoa(haddr), sh_error_message(errno, errbuf, sizeof(errbuf)));
 | 
|---|
| [78] | 631 |       sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, 
 | 
|---|
 | 632 |                       errmsg, _("connect"));
 | 
|---|
| [67] | 633 | #endif
 | 
|---|
 | 634 |     }
 | 
|---|
 | 635 |   else
 | 
|---|
 | 636 |     {
 | 
|---|
| [78] | 637 |       do {
 | 
|---|
 | 638 |         retval = send (fd, buf, 0, 0);
 | 
|---|
 | 639 |       } while (retval < 0 && errno == EINTR);
 | 
|---|
| [67] | 640 | 
 | 
|---|
 | 641 |       if (retval == -1 && errno == ECONNREFUSED)
 | 
|---|
 | 642 |         {
 | 
|---|
 | 643 |           if (portchk_debug)
 | 
|---|
 | 644 |             fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
 | 
|---|
 | 645 |                     port, inet_ntoa(haddr));
 | 
|---|
 | 646 |         }
 | 
|---|
 | 647 |       else 
 | 
|---|
 | 648 |         {
 | 
|---|
| [78] | 649 |           /* Only the second send() may catch the error 
 | 
|---|
 | 650 |            */
 | 
|---|
 | 651 |           do {
 | 
|---|
 | 652 |             retval = send (fd, buf, 0, 0);
 | 
|---|
 | 653 |           } while (retval < 0 && errno == EINTR);
 | 
|---|
 | 654 | 
 | 
|---|
| [67] | 655 |           if (retval == -1 && errno == ECONNREFUSED)
 | 
|---|
 | 656 |             {
 | 
|---|
 | 657 |               if (portchk_debug)
 | 
|---|
 | 658 |                 fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
 | 
|---|
 | 659 |                         port, inet_ntoa(haddr));
 | 
|---|
 | 660 |             }
 | 
|---|
 | 661 |           else if (retval != -1)
 | 
|---|
 | 662 |             {
 | 
|---|
 | 663 |               /* Try to get service name from portmap
 | 
|---|
 | 664 |                */
 | 
|---|
 | 665 |               p = check_rpc_list (port, &sinr, IPPROTO_UDP);
 | 
|---|
 | 666 |               
 | 
|---|
 | 667 |               sh_portchk_cmp_to_list ("udp", port, haddr, p ? p : NULL);
 | 
|---|
 | 668 |               
 | 
|---|
 | 669 |               /* If not an RPC service, try to get name from /etc/services
 | 
|---|
 | 670 |                */
 | 
|---|
 | 671 |               if (!p)
 | 
|---|
 | 672 |                 p = check_services(port, "udp");
 | 
|---|
 | 673 |               
 | 
|---|
 | 674 |               if (portchk_debug)
 | 
|---|
 | 675 |                 fprintf(stderr, _("check port: %5d/udp on %15s open %s\n"), 
 | 
|---|
 | 676 |                         port, inet_ntoa(haddr), p);
 | 
|---|
 | 677 |               
 | 
|---|
 | 678 |             }
 | 
|---|
 | 679 |         }
 | 
|---|
 | 680 |     }
 | 
|---|
 | 681 |   close (fd);
 | 
|---|
 | 682 |   return 0;
 | 
|---|
 | 683 | }
 | 
|---|
 | 684 | 
 | 
|---|
 | 685 | static int check_port_tcp_internal (int fd, int port, struct in_addr haddr)
 | 
|---|
 | 686 | {
 | 
|---|
 | 687 |   struct sockaddr_in sinr;
 | 
|---|
 | 688 |   /* struct in_addr     haddr; */
 | 
|---|
 | 689 |   int                retval;
 | 
|---|
| [109] | 690 |   int                flags;
 | 
|---|
| [67] | 691 |   char             * p;
 | 
|---|
| [78] | 692 | #ifndef TEST_ONLY
 | 
|---|
 | 693 |   char               errmsg[256];
 | 
|---|
 | 694 |   int                nerr;
 | 
|---|
 | 695 | #endif
 | 
|---|
| [132] | 696 |   char errbuf[SH_ERRBUF_SIZE];
 | 
|---|
| [67] | 697 | 
 | 
|---|
 | 698 |   /* inet_aton(interface, &haddr); */
 | 
|---|
 | 699 | 
 | 
|---|
 | 700 |   sinr.sin_family = AF_INET;
 | 
|---|
 | 701 |   sinr.sin_port   = htons (port);
 | 
|---|
 | 702 |   sinr.sin_addr   = haddr;
 | 
|---|
 | 703 | 
 | 
|---|
| [78] | 704 |   do {
 | 
|---|
 | 705 |     retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
 | 
|---|
 | 706 |   } while (retval < 0 && errno == EINTR);
 | 
|---|
 | 707 | 
 | 
|---|
| [67] | 708 |   if (retval == -1 && errno == ECONNREFUSED)
 | 
|---|
 | 709 |     {
 | 
|---|
 | 710 |       if (portchk_debug)
 | 
|---|
 | 711 |         fprintf(stderr, _("check port: %5d on %15s established/time_wait\n"),
 | 
|---|
 | 712 |                 port, inet_ntoa(haddr));
 | 
|---|
 | 713 |     }
 | 
|---|
 | 714 |   else if (retval == -1)
 | 
|---|
 | 715 |     {
 | 
|---|
 | 716 | #ifdef TEST_ONLY
 | 
|---|
 | 717 |       if (portchk_debug)
 | 
|---|
 | 718 |         perror(_("connect"));
 | 
|---|
 | 719 | #else
 | 
|---|
| [78] | 720 |       nerr = errno;
 | 
|---|
 | 721 |       sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/tcp on %15s: %s"),
 | 
|---|
| [132] | 722 |                   port, inet_ntoa(haddr), sh_error_message(errno, errbuf, sizeof(errbuf)));
 | 
|---|
| [78] | 723 |       sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, 
 | 
|---|
 | 724 |                       errmsg, _("connect"));
 | 
|---|
| [67] | 725 | #endif
 | 
|---|
 | 726 |     }
 | 
|---|
 | 727 |   else
 | 
|---|
 | 728 |     {
 | 
|---|
 | 729 |       /* Try to get service name from portmap
 | 
|---|
 | 730 |        */
 | 
|---|
 | 731 |       p = check_rpc_list (port, &sinr, IPPROTO_TCP);
 | 
|---|
 | 732 | 
 | 
|---|
 | 733 |       sh_portchk_cmp_to_list ("tcp", port, haddr, p ? p : NULL);
 | 
|---|
 | 734 | 
 | 
|---|
 | 735 |       /* If not an RPC service, try to get name from /etc/services
 | 
|---|
 | 736 |        */
 | 
|---|
 | 737 |       if (!p)
 | 
|---|
 | 738 |         p = check_services(port, "tcp");
 | 
|---|
 | 739 | 
 | 
|---|
 | 740 |       if (portchk_debug)
 | 
|---|
 | 741 |         fprintf(stderr, _("check port: %5d on %15s open %s\n"), 
 | 
|---|
 | 742 |                 port, inet_ntoa(haddr), p);
 | 
|---|
| [109] | 743 | 
 | 
|---|
 | 744 | #if !defined(O_NONBLOCK)
 | 
|---|
 | 745 | #if defined(O_NDELAY)
 | 
|---|
 | 746 | #define O_NONBLOCK  O_NDELAY
 | 
|---|
 | 747 | #else
 | 
|---|
 | 748 | #define O_NONBLOCK  0
 | 
|---|
 | 749 | #endif
 | 
|---|
 | 750 | #endif
 | 
|---|
 | 751 | 
 | 
|---|
 | 752 |       /* prepare to close connection gracefully
 | 
|---|
 | 753 |        */
 | 
|---|
 | 754 |       if      (port == 22)  /* ssh */
 | 
|---|
 | 755 |         {
 | 
|---|
 | 756 |           flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
 | 
|---|
 | 757 |           retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
 | 
|---|
 | 758 |           write (fd, _("SSH-2.0-Foobar"), 14);
 | 
|---|
 | 759 |           write (fd, "\r\n", 2);
 | 
|---|
 | 760 |         }
 | 
|---|
 | 761 |       else if (port == 25)  /* smtp */
 | 
|---|
 | 762 |         {
 | 
|---|
 | 763 |           flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
 | 
|---|
 | 764 |           retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
 | 
|---|
 | 765 |           write (fd, _("QUIT"), 4);
 | 
|---|
 | 766 |           write (fd, "\r\n", 2);
 | 
|---|
 | 767 |         }
 | 
|---|
 | 768 |       else if (port == 79)  /* finger */
 | 
|---|
 | 769 |         {
 | 
|---|
 | 770 |           flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
 | 
|---|
 | 771 |           retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
 | 
|---|
 | 772 |           write (fd, "\r\n", 2);
 | 
|---|
 | 773 |         }
 | 
|---|
 | 774 |       else if (port == 110) /* pop3 */
 | 
|---|
 | 775 |         {
 | 
|---|
 | 776 |           flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
 | 
|---|
 | 777 |           retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
 | 
|---|
 | 778 |           write (fd, _("QUIT"), 4);
 | 
|---|
 | 779 |           write (fd, "\r\n", 2);
 | 
|---|
 | 780 |         }
 | 
|---|
 | 781 |       else if (port == 143) /* imap */
 | 
|---|
 | 782 |         {
 | 
|---|
 | 783 |           flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
 | 
|---|
 | 784 |           retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
 | 
|---|
 | 785 |           write (fd, _("A01 LOGOUT"), 10);
 | 
|---|
 | 786 |           write (fd, "\r\n", 2);
 | 
|---|
 | 787 |         }
 | 
|---|
| [67] | 788 |      }
 | 
|---|
 | 789 |   close (fd);
 | 
|---|
 | 790 |   return 0;
 | 
|---|
 | 791 | }
 | 
|---|
 | 792 | 
 | 
|---|
 | 793 | /* typedef uint32_t in_addr_t;
 | 
|---|
 | 794 |  * struct in_addr
 | 
|---|
 | 795 |  * {
 | 
|---|
 | 796 |  * in_addr_t s_addr;
 | 
|---|
 | 797 |  * };
 | 
|---|
 | 798 |  */
 | 
|---|
 | 799 | 
 | 
|---|
 | 800 | #define SH_IFACE_MAX 16
 | 
|---|
 | 801 | 
 | 
|---|
 | 802 | struct portchk_interfaces {
 | 
|---|
 | 803 |   struct in_addr iface[SH_IFACE_MAX];
 | 
|---|
 | 804 |   int            used;
 | 
|---|
 | 805 | };
 | 
|---|
 | 806 | 
 | 
|---|
 | 807 | static struct portchk_interfaces iface_list;
 | 
|---|
 | 808 | static int iface_initialized = 0;
 | 
|---|
 | 809 | 
 | 
|---|
 | 810 | #ifdef TEST_ONLY
 | 
|---|
 | 811 | static char * portchk_hostname = NULL;
 | 
|---|
 | 812 | #else
 | 
|---|
 | 813 | static char * portchk_hostname = sh.host.name;
 | 
|---|
 | 814 | #endif
 | 
|---|
 | 815 | 
 | 
|---|
 | 816 | int sh_portchk_init ()
 | 
|---|
 | 817 | {
 | 
|---|
 | 818 |   struct hostent * hent;
 | 
|---|
 | 819 |   int              i = 0;
 | 
|---|
 | 820 |   char errbuf[256];
 | 
|---|
 | 821 | 
 | 
|---|
 | 822 |   if (portchk_debug)
 | 
|---|
 | 823 |     fprintf(stderr, _("checking ports on: %s\n"), portchk_hostname ? portchk_hostname : _("NULL"));
 | 
|---|
| [78] | 824 | 
 | 
|---|
| [67] | 825 |   if (!portchk_hostname)
 | 
|---|
 | 826 |     return -1;
 | 
|---|
 | 827 | 
 | 
|---|
| [78] | 828 |   if (sh_portchk_active == S_FALSE)
 | 
|---|
 | 829 |     return -1;
 | 
|---|
 | 830 | 
 | 
|---|
| [67] | 831 |   if (iface_initialized == 0)
 | 
|---|
 | 832 |     {
 | 
|---|
 | 833 |       iface_list.used   = 0;
 | 
|---|
 | 834 |       iface_initialized = 1;
 | 
|---|
 | 835 |     }
 | 
|---|
 | 836 |             
 | 
|---|
| [134] | 837 |   SH_MUTEX_LOCK(mutex_resolv);
 | 
|---|
| [67] | 838 |   hent = gethostbyname(portchk_hostname);
 | 
|---|
 | 839 | 
 | 
|---|
 | 840 |   while (hent && hent->h_addr_list[i] && (iface_list.used < SH_IFACE_MAX))
 | 
|---|
 | 841 |     {
 | 
|---|
 | 842 |       memcpy (&(iface_list.iface[iface_list.used].s_addr), hent->h_addr_list[i], sizeof(in_addr_t));
 | 
|---|
| [134] | 843 |       ++iface_list.used;
 | 
|---|
 | 844 |       ++i;
 | 
|---|
 | 845 |     }
 | 
|---|
 | 846 |   SH_MUTEX_UNLOCK(mutex_resolv);
 | 
|---|
 | 847 | 
 | 
|---|
 | 848 |   for (i = 0; i < iface_list.used; ++i)
 | 
|---|
 | 849 |     {
 | 
|---|
| [67] | 850 |       sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"), 
 | 
|---|
| [134] | 851 |                   inet_ntoa(iface_list.iface[i]));
 | 
|---|
| [67] | 852 |       sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
 | 
|---|
 | 853 |                       errbuf, _("sh_portchk_init"));
 | 
|---|
 | 854 |     }
 | 
|---|
 | 855 | 
 | 
|---|
 | 856 |   return 0;
 | 
|---|
 | 857 | }
 | 
|---|
 | 858 | 
 | 
|---|
 | 859 | #if !defined(TEST_ONLY)
 | 
|---|
 | 860 | int sh_portchk_reconf ()
 | 
|---|
 | 861 | {
 | 
|---|
| [78] | 862 |   iface_initialized    = 0;
 | 
|---|
| [67] | 863 | 
 | 
|---|
| [78] | 864 |   sh_portchk_active    = 1;
 | 
|---|
| [80] | 865 |   sh_portchk_check_udp = 1;
 | 
|---|
| [78] | 866 | 
 | 
|---|
| [67] | 867 |   portlist_udp = sh_portchk_kill_list (portlist_udp);
 | 
|---|
 | 868 |   portlist_tcp = sh_portchk_kill_list (portlist_tcp);
 | 
|---|
 | 869 |   return 0;
 | 
|---|
 | 870 | }
 | 
|---|
 | 871 | 
 | 
|---|
 | 872 | int sh_portchk_cleanup ()
 | 
|---|
 | 873 | {
 | 
|---|
 | 874 |   return sh_portchk_reconf ();
 | 
|---|
 | 875 | }
 | 
|---|
 | 876 | 
 | 
|---|
 | 877 | int sh_portchk_timer (time_t tcurrent) 
 | 
|---|
 | 878 | {
 | 
|---|
 | 879 |   static time_t lastcheck = 0;
 | 
|---|
 | 880 | 
 | 
|---|
 | 881 |   SL_ENTER(_("sh_portchk_timer"));
 | 
|---|
 | 882 |   if ((time_t) (tcurrent - lastcheck) >= sh_portchk_interval)
 | 
|---|
 | 883 |     {
 | 
|---|
 | 884 |       lastcheck  = tcurrent;
 | 
|---|
 | 885 |       SL_RETURN((-1), _("sh_portchk_timer"));
 | 
|---|
 | 886 |     }
 | 
|---|
 | 887 |   SL_RETURN(0, _("sh_portchk_timer"));
 | 
|---|
 | 888 | }
 | 
|---|
 | 889 | #endif
 | 
|---|
 | 890 | 
 | 
|---|
 | 891 | static int check_port_generic (int port, int type, int protocol)
 | 
|---|
 | 892 | {
 | 
|---|
 | 893 |   int              i    =  0;
 | 
|---|
 | 894 |   int              sock = -1;
 | 
|---|
 | 895 |   int              flag =  1; /* non-zero to enable an option */
 | 
|---|
 | 896 |   struct in_addr   haddr;
 | 
|---|
| [132] | 897 |   char errbuf[SH_ERRBUF_SIZE];
 | 
|---|
 | 898 | 
 | 
|---|
| [67] | 899 |   /* Check all interfaces for this host
 | 
|---|
 | 900 |    */
 | 
|---|
 | 901 |   while (i < iface_list.used)
 | 
|---|
 | 902 |     {
 | 
|---|
 | 903 |       if ((sock = socket(AF_INET, type, protocol)) < 0 )
 | 
|---|
 | 904 |         {
 | 
|---|
 | 905 | #ifdef TEST_ONLY
 | 
|---|
 | 906 |           if (portchk_debug)
 | 
|---|
 | 907 |             perror(_("socket"));
 | 
|---|
 | 908 | #else
 | 
|---|
 | 909 |           sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, 
 | 
|---|
| [132] | 910 |                           sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
 | 
|---|
| [67] | 911 | #endif
 | 
|---|
 | 912 |         }
 | 
|---|
 | 913 |       if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
 | 
|---|
 | 914 |                       (void *) &flag, sizeof(flag)) < 0 )
 | 
|---|
 | 915 |         {
 | 
|---|
 | 916 | #ifdef TEST_ONLY
 | 
|---|
 | 917 |           if (portchk_debug)
 | 
|---|
 | 918 |             perror(_("setsockopt"));
 | 
|---|
 | 919 | #else
 | 
|---|
 | 920 |           sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, 
 | 
|---|
| [132] | 921 |                           sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
 | 
|---|
| [67] | 922 | #endif
 | 
|---|
 | 923 |         }
 | 
|---|
 | 924 | 
 | 
|---|
 | 925 |       memcpy (&(haddr.s_addr), &(iface_list.iface[i].s_addr), sizeof(in_addr_t));
 | 
|---|
 | 926 | 
 | 
|---|
 | 927 |       if (protocol == IPPROTO_TCP)
 | 
|---|
 | 928 |         check_port_tcp_internal(sock, port, haddr);
 | 
|---|
 | 929 |       else
 | 
|---|
 | 930 |         check_port_udp_internal(sock, port, haddr);
 | 
|---|
 | 931 | 
 | 
|---|
 | 932 |       ++i;
 | 
|---|
 | 933 |     }
 | 
|---|
 | 934 | 
 | 
|---|
 | 935 |   return 0;
 | 
|---|
 | 936 | }
 | 
|---|
 | 937 | 
 | 
|---|
 | 938 | 
 | 
|---|
 | 939 | 
 | 
|---|
 | 940 | static int check_port_udp (int port)
 | 
|---|
 | 941 | {
 | 
|---|
 | 942 |   return check_port_generic(port, SOCK_DGRAM, IPPROTO_UDP);
 | 
|---|
 | 943 | }
 | 
|---|
 | 944 | 
 | 
|---|
 | 945 | static int check_port_tcp (int port)
 | 
|---|
 | 946 | {
 | 
|---|
 | 947 |   return check_port_generic(port, SOCK_STREAM, IPPROTO_TCP);
 | 
|---|
 | 948 | }
 | 
|---|
 | 949 | 
 | 
|---|
 | 950 | 
 | 
|---|
 | 951 | 
 | 
|---|
 | 952 | static int sh_portchk_scan_ports_generic (int min_port, int max_port, int type, int protocol)
 | 
|---|
 | 953 | {
 | 
|---|
 | 954 |   /*
 | 
|---|
 | 955 |   int min_port = 1024;
 | 
|---|
 | 956 |   int max_port = 65535;
 | 
|---|
 | 957 |   */
 | 
|---|
 | 958 | 
 | 
|---|
 | 959 |   int port;
 | 
|---|
 | 960 |   int retval;
 | 
|---|
 | 961 |   int sock   = -1;
 | 
|---|
 | 962 |   int flag   = 1; /* non-zero to enable an option */
 | 
|---|
 | 963 | 
 | 
|---|
 | 964 |   struct sockaddr_in addr;
 | 
|---|
 | 965 |   int addrlen      = sizeof(addr);
 | 
|---|
| [132] | 966 |   char errbuf[SH_ERRBUF_SIZE];
 | 
|---|
| [67] | 967 | 
 | 
|---|
 | 968 |   if (min_port == -1)
 | 
|---|
 | 969 |      min_port = 0;
 | 
|---|
 | 970 |   if (max_port == -1)
 | 
|---|
 | 971 |     max_port = 65535;
 | 
|---|
 | 972 | 
 | 
|---|
 | 973 |   for (port = min_port; port <= max_port; ++port) 
 | 
|---|
 | 974 |     {
 | 
|---|
 | 975 | 
 | 
|---|
 | 976 |       if ((sock = socket(AF_INET, type, protocol)) < 0 )
 | 
|---|
 | 977 |         {
 | 
|---|
 | 978 | #ifdef TEST_ONLY
 | 
|---|
 | 979 |           if (portchk_debug)
 | 
|---|
 | 980 |             perror(_("socket"));
 | 
|---|
 | 981 | #else
 | 
|---|
 | 982 |           sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, 
 | 
|---|
| [132] | 983 |                           sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
 | 
|---|
| [67] | 984 | #endif
 | 
|---|
 | 985 |         }
 | 
|---|
 | 986 |       if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
 | 
|---|
 | 987 |                       (void *) &flag, sizeof(flag)) < 0 )
 | 
|---|
 | 988 |         {
 | 
|---|
 | 989 | #ifdef TEST_ONLY
 | 
|---|
 | 990 |           if (portchk_debug)
 | 
|---|
 | 991 |             perror(_("setsockopt"));
 | 
|---|
 | 992 | #else
 | 
|---|
 | 993 |           sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, 
 | 
|---|
| [132] | 994 |                           sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
 | 
|---|
| [67] | 995 | #endif
 | 
|---|
 | 996 |         }
 | 
|---|
 | 997 | 
 | 
|---|
 | 998 |       addr.sin_family      = AF_INET;
 | 
|---|
 | 999 |       addr.sin_port        = htons(port);
 | 
|---|
 | 1000 |       addr.sin_addr.s_addr = INADDR_ANY;
 | 
|---|
 | 1001 | 
 | 
|---|
 | 1002 |       retval = bind (sock, (struct sockaddr *) &addr, addrlen);
 | 
|---|
 | 1003 | 
 | 
|---|
 | 1004 |       if (retval == 0)
 | 
|---|
 | 1005 |         {
 | 
|---|
 | 1006 |           /* we can bind the port, thus it is unused
 | 
|---|
 | 1007 |            */
 | 
|---|
 | 1008 |           close (sock);
 | 
|---|
 | 1009 |         }
 | 
|---|
 | 1010 |       else
 | 
|---|
 | 1011 |         {
 | 
|---|
 | 1012 |           if (errno == EINVAL || errno == EADDRINUSE)
 | 
|---|
 | 1013 |             {
 | 
|---|
 | 1014 |               /* try to connect to the port
 | 
|---|
 | 1015 |                */
 | 
|---|
 | 1016 |               if (protocol == IPPROTO_TCP)
 | 
|---|
 | 1017 |                 check_port_tcp(port);
 | 
|---|
 | 1018 |               else
 | 
|---|
 | 1019 |                 check_port_udp(port);
 | 
|---|
 | 1020 |             }
 | 
|---|
 | 1021 |           else
 | 
|---|
 | 1022 |             {
 | 
|---|
 | 1023 | #ifdef TEST_ONLY
 | 
|---|
 | 1024 |               if (portchk_debug)
 | 
|---|
 | 1025 |                 perror(_("bind"));
 | 
|---|
 | 1026 | #else
 | 
|---|
 | 1027 |               sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, 
 | 
|---|
| [132] | 1028 |                               sh_error_message(errno, errbuf, sizeof(errbuf)), _("bind"));
 | 
|---|
| [67] | 1029 | #endif
 | 
|---|
 | 1030 |             }
 | 
|---|
 | 1031 |           close (sock);
 | 
|---|
 | 1032 |         }
 | 
|---|
 | 1033 |     }
 | 
|---|
 | 1034 |   return 0;
 | 
|---|
 | 1035 | }
 | 
|---|
 | 1036 | 
 | 
|---|
 | 1037 | static int sh_portchk_scan_ports_tcp (int min_port, int max_port)
 | 
|---|
 | 1038 | {
 | 
|---|
 | 1039 |   return sh_portchk_scan_ports_generic (min_port, max_port, SOCK_STREAM, IPPROTO_TCP);
 | 
|---|
 | 1040 | }
 | 
|---|
 | 1041 |  
 | 
|---|
 | 1042 | static int sh_portchk_scan_ports_udp (int min_port, int max_port)
 | 
|---|
 | 1043 | {
 | 
|---|
 | 1044 |   return sh_portchk_scan_ports_generic (min_port, max_port, SOCK_DGRAM, IPPROTO_UDP);
 | 
|---|
 | 1045 | }
 | 
|---|
 | 1046 | 
 | 
|---|
 | 1047 | /* Subroutine to add an interface
 | 
|---|
 | 1048 |  */
 | 
|---|
 | 1049 | static int sh_portchk_add_interface (const char * str)
 | 
|---|
 | 1050 | {
 | 
|---|
 | 1051 |   struct in_addr   haddr;
 | 
|---|
 | 1052 |   char errbuf[256];
 | 
|---|
 | 1053 | 
 | 
|---|
 | 1054 |   if (iface_initialized == 0)
 | 
|---|
 | 1055 |     {
 | 
|---|
 | 1056 |       iface_list.used   = 0;
 | 
|---|
 | 1057 |       iface_initialized = 1;
 | 
|---|
 | 1058 |     }
 | 
|---|
 | 1059 | 
 | 
|---|
 | 1060 |   if (0 == inet_aton(str, &haddr))
 | 
|---|
 | 1061 |     return -1;
 | 
|---|
 | 1062 | 
 | 
|---|
 | 1063 |   if (iface_list.used == SH_IFACE_MAX)
 | 
|---|
 | 1064 |     return -1;
 | 
|---|
 | 1065 | 
 | 
|---|
 | 1066 |   sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"), inet_ntoa(haddr));
 | 
|---|
 | 1067 |   sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
 | 
|---|
 | 1068 |                   errbuf, _("sh_portchk_add_interface"));
 | 
|---|
 | 1069 | 
 | 
|---|
 | 1070 |   memcpy (&(iface_list.iface[iface_list.used].s_addr), &(haddr.s_addr), sizeof(in_addr_t));
 | 
|---|
 | 1071 |   ++iface_list.used;
 | 
|---|
 | 1072 | 
 | 
|---|
 | 1073 |   return 0;
 | 
|---|
 | 1074 | }
 | 
|---|
 | 1075 | 
 | 
|---|
 | 1076 |  
 | 
|---|
 | 1077 | /* Subroutine to add a required or optional port/service
 | 
|---|
 | 1078 |  */
 | 
|---|
 | 1079 | static int sh_portchk_add_required_port_generic (char * service, char * interface, int type)
 | 
|---|
 | 1080 | {
 | 
|---|
 | 1081 |   char buf[256];
 | 
|---|
 | 1082 |   char proto[4];
 | 
|---|
 | 1083 |   char * p;
 | 
|---|
 | 1084 |   char * endptr;
 | 
|---|
 | 1085 |   unsigned long int  port;
 | 
|---|
 | 1086 |   struct in_addr   haddr;
 | 
|---|
 | 1087 |   struct sh_portentry * portent;
 | 
|---|
 | 1088 | 
 | 
|---|
 | 1089 |   if (0 == inet_aton(interface, &haddr))
 | 
|---|
 | 1090 |     return -1;
 | 
|---|
 | 1091 | 
 | 
|---|
 | 1092 |   sl_strlcpy (buf, service, sizeof(buf));
 | 
|---|
 | 1093 | 
 | 
|---|
 | 1094 |   p = strchr(buf, '/');
 | 
|---|
 | 1095 |   if (!p)
 | 
|---|
 | 1096 |     return -1;
 | 
|---|
 | 1097 |   if (0 == strcmp(p, _("/tcp")))
 | 
|---|
 | 1098 |     sl_strlcpy(proto, _("tcp"), sizeof(proto));
 | 
|---|
 | 1099 |   else if  (0 == strcmp(p, _("/udp")))   
 | 
|---|
 | 1100 |     sl_strlcpy(proto, _("udp"), sizeof(proto));
 | 
|---|
 | 1101 |   else
 | 
|---|
 | 1102 |     return -1;
 | 
|---|
 | 1103 | 
 | 
|---|
 | 1104 |   *p = '\0';
 | 
|---|
 | 1105 |   port = strtoul(buf, &endptr, 0);
 | 
|---|
 | 1106 | 
 | 
|---|
 | 1107 |   if (*endptr != '\0')
 | 
|---|
 | 1108 |     {  
 | 
|---|
 | 1109 |       portent = sh_portchk_get_from_list (proto, -1, haddr, buf);
 | 
|---|
 | 1110 |       if (!portent)
 | 
|---|
 | 1111 |         sh_portchk_add_to_list (proto,   -1, haddr,  buf, type, SH_PORT_UNKN);
 | 
|---|
 | 1112 |       else
 | 
|---|
 | 1113 |         {
 | 
|---|
 | 1114 | #ifdef TEST_ONLY
 | 
|---|
 | 1115 |           fprintf(stderr, "** WARNING: duplicate port definition %s/%s\n", buf, proto);
 | 
|---|
 | 1116 | #else
 | 
|---|
 | 1117 |           sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
 | 
|---|
 | 1118 |                           _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
 | 
|---|
 | 1119 | #endif
 | 
|---|
 | 1120 |           return -1;
 | 
|---|
 | 1121 |         }
 | 
|---|
 | 1122 |     }
 | 
|---|
 | 1123 |   else if (port <= 65535)
 | 
|---|
 | 1124 |     {
 | 
|---|
 | 1125 |       portent = sh_portchk_get_from_list (proto, port, haddr, NULL);
 | 
|---|
 | 1126 |       if (!portent)
 | 
|---|
 | 1127 |         sh_portchk_add_to_list (proto, port, haddr, NULL, type, SH_PORT_UNKN);
 | 
|---|
 | 1128 |       else
 | 
|---|
 | 1129 |         {
 | 
|---|
 | 1130 | #ifdef TEST_ONLY
 | 
|---|
 | 1131 |           fprintf(stderr, "** WARNING: duplicate port definition %lu/%s\n", port, proto);
 | 
|---|
 | 1132 | #else
 | 
|---|
 | 1133 |           sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
 | 
|---|
 | 1134 |                           _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
 | 
|---|
 | 1135 | #endif
 | 
|---|
 | 1136 |           return -1;
 | 
|---|
 | 1137 |         }
 | 
|---|
 | 1138 |     }
 | 
|---|
 | 1139 |   else
 | 
|---|
 | 1140 |     return -1;
 | 
|---|
 | 1141 | 
 | 
|---|
 | 1142 |   return 0;
 | 
|---|
 | 1143 | }
 | 
|---|
 | 1144 | 
 | 
|---|
 | 1145 | /* Internal interface to add required or optional ports as 'iface:portlist'
 | 
|---|
 | 1146 |  */
 | 
|---|
 | 1147 | static int sh_portchk_add_required_generic (const char * str, int type)
 | 
|---|
 | 1148 | {
 | 
|---|
 | 1149 |   size_t len;
 | 
|---|
 | 1150 |   size_t ll = 0;
 | 
|---|
 | 1151 | 
 | 
|---|
 | 1152 |   char * interface = NULL;
 | 
|---|
 | 1153 |   char * list;
 | 
|---|
 | 1154 |   char * p;
 | 
|---|
| [131] | 1155 | #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
 | 
|---|
 | 1156 |   char * saveptr;
 | 
|---|
 | 1157 | #endif
 | 
|---|
| [67] | 1158 | 
 | 
|---|
 | 1159 |   if (!str)
 | 
|---|
 | 1160 |     return -1;
 | 
|---|
 | 1161 | 
 | 
|---|
 | 1162 |   if (strchr(str, ':'))
 | 
|---|
 | 1163 |     {
 | 
|---|
 | 1164 |       len = strlen(str);
 | 
|---|
 | 1165 |       for (ll = 0; ll < len; ++ll)
 | 
|---|
 | 1166 |         {
 | 
|---|
 | 1167 |           if (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
 | 
|---|
 | 1168 |             {
 | 
|---|
 | 1169 |               interface = SH_ALLOC(ll+1);
 | 
|---|
 | 1170 |               sl_strlcpy(interface, str, ll+1);
 | 
|---|
 | 1171 |               interface[ll] = '\0';
 | 
|---|
 | 1172 |               while (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
 | 
|---|
 | 1173 |                 ++ll;
 | 
|---|
 | 1174 |               break;
 | 
|---|
 | 1175 |             }
 | 
|---|
 | 1176 |         }
 | 
|---|
 | 1177 |     }
 | 
|---|
 | 1178 |   else
 | 
|---|
 | 1179 |     {
 | 
|---|
 | 1180 |       interface = SH_ALLOC(8);
 | 
|---|
 | 1181 |       sl_strlcpy(interface, _("0.0.0.0"), 8);
 | 
|---|
 | 1182 |       interface[7] = '\0';
 | 
|---|
 | 1183 |       while (str[ll] == ' ' || str[ll] == '\t')
 | 
|---|
 | 1184 |         ++ll;      
 | 
|---|
 | 1185 |     }
 | 
|---|
 | 1186 | 
 | 
|---|
 | 1187 |   if (!interface)
 | 
|---|
 | 1188 |     return -1;
 | 
|---|
 | 1189 | 
 | 
|---|
 | 1190 |   if (str[ll] == '\0')
 | 
|---|
 | 1191 |     {
 | 
|---|
 | 1192 |       SH_FREE(interface);
 | 
|---|
 | 1193 |       return -1;
 | 
|---|
 | 1194 |     }
 | 
|---|
 | 1195 | 
 | 
|---|
 | 1196 |   if (portchk_debug)
 | 
|---|
 | 1197 |     fprintf(stderr, "add ports for interface: %s\n", interface);
 | 
|---|
 | 1198 | 
 | 
|---|
 | 1199 |   list = sh_util_strdup(&str[ll]);
 | 
|---|
| [131] | 1200 | #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
 | 
|---|
 | 1201 |   p    = strtok_r (list, " ,\t", &saveptr);
 | 
|---|
 | 1202 | #else
 | 
|---|
| [67] | 1203 |   p    = strtok (list, " ,\t");
 | 
|---|
| [131] | 1204 | #endif
 | 
|---|
| [67] | 1205 |   if (!p)
 | 
|---|
 | 1206 |     {
 | 
|---|
 | 1207 |       SH_FREE(interface);
 | 
|---|
 | 1208 |       SH_FREE(list);
 | 
|---|
 | 1209 |       return -1;
 | 
|---|
 | 1210 |     }
 | 
|---|
 | 1211 |   while (p)
 | 
|---|
 | 1212 |     {
 | 
|---|
 | 1213 |       if (-1 == sh_portchk_add_required_port_generic (p, interface, type))
 | 
|---|
 | 1214 |         {
 | 
|---|
 | 1215 |           SH_FREE(interface);
 | 
|---|
 | 1216 |           SH_FREE(list);
 | 
|---|
 | 1217 |           return -1;
 | 
|---|
 | 1218 |         }
 | 
|---|
| [131] | 1219 | #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
 | 
|---|
 | 1220 |       p    = strtok_r (NULL, " ,\t", &saveptr);
 | 
|---|
 | 1221 | #else
 | 
|---|
| [67] | 1222 |       p    = strtok (NULL, " ,\t");
 | 
|---|
| [131] | 1223 | #endif
 | 
|---|
| [67] | 1224 |     }
 | 
|---|
 | 1225 |   SH_FREE(interface);
 | 
|---|
 | 1226 |   SH_FREE(list);
 | 
|---|
 | 1227 |   return 0;
 | 
|---|
 | 1228 | }
 | 
|---|
 | 1229 | 
 | 
|---|
 | 1230 | /* User interface to add required ports as 'iface:portlist'
 | 
|---|
 | 1231 |  */
 | 
|---|
 | 1232 | static int sh_portchk_add_required (const char * str)
 | 
|---|
 | 1233 | {
 | 
|---|
 | 1234 |   return sh_portchk_add_required_generic (str, SH_PORT_REQ); 
 | 
|---|
 | 1235 | }
 | 
|---|
 | 1236 | 
 | 
|---|
 | 1237 | /* User interface to add optional ports as 'iface:portlist'
 | 
|---|
 | 1238 |  */
 | 
|---|
 | 1239 | static int sh_portchk_add_optional (const char * str)
 | 
|---|
 | 1240 | {
 | 
|---|
 | 1241 |   return sh_portchk_add_required_generic (str, SH_PORT_OPT); 
 | 
|---|
 | 1242 | }
 | 
|---|
 | 1243 | 
 | 
|---|
| [127] | 1244 | /* User interface to add ignoreable ports as 'iface:portlist'
 | 
|---|
 | 1245 |  */
 | 
|---|
 | 1246 | static int sh_portchk_add_ignore (const char * str)
 | 
|---|
 | 1247 | {
 | 
|---|
 | 1248 |   return sh_portchk_add_required_generic (str, SH_PORT_IGN); 
 | 
|---|
 | 1249 | }
 | 
|---|
 | 1250 | 
 | 
|---|
| [67] | 1251 | /* Interface to run port check
 | 
|---|
 | 1252 |  */
 | 
|---|
 | 1253 | int sh_portchk_check ()
 | 
|---|
 | 1254 | {
 | 
|---|
 | 1255 |   int min_port = 0;
 | 
|---|
 | 1256 | 
 | 
|---|
| [78] | 1257 |   if (sh_portchk_active != S_FALSE)
 | 
|---|
| [67] | 1258 |     {
 | 
|---|
| [78] | 1259 |       sh_portchk_reset_lists();
 | 
|---|
 | 1260 |       if (0 != geteuid())
 | 
|---|
 | 1261 |         {
 | 
|---|
 | 1262 |           min_port = 1024;
 | 
|---|
| [67] | 1263 | #ifdef TEST_ONLY
 | 
|---|
| [78] | 1264 |           fprintf(stderr, "** WARNING not scanning ports < 1024\n");
 | 
|---|
| [67] | 1265 | #else
 | 
|---|
| [78] | 1266 |           sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
 | 
|---|
 | 1267 |                           _("not scanning ports below 1024"), _("sh_portchk_check"));
 | 
|---|
| [67] | 1268 | #endif
 | 
|---|
| [78] | 1269 |         }
 | 
|---|
 | 1270 |       if (sh_portchk_check_udp == 1)
 | 
|---|
 | 1271 |         sh_portchk_scan_ports_udp(min_port, -1);
 | 
|---|
 | 1272 |       sh_portchk_scan_ports_tcp(min_port, -1);
 | 
|---|
 | 1273 |       sh_portchk_check_list (&portlist_tcp, "tcp", SH_PORT_REPORT);
 | 
|---|
 | 1274 |       if (sh_portchk_check_udp == 1)
 | 
|---|
 | 1275 |         sh_portchk_check_list (&portlist_udp, "udp", SH_PORT_REPORT);
 | 
|---|
| [67] | 1276 |     }
 | 
|---|
 | 1277 |   return 0;
 | 
|---|
 | 1278 | }
 | 
|---|
 | 1279 | #endif
 | 
|---|
 | 1280 | 
 | 
|---|
 | 1281 | #ifdef SH_CUTEST
 | 
|---|
 | 1282 | #include "CuTest.h"
 | 
|---|
 | 1283 | 
 | 
|---|
 | 1284 | void Test_portcheck_lists (CuTest *tc)
 | 
|---|
 | 1285 | {
 | 
|---|
| [73] | 1286 | #if defined(SH_USE_PORTCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
 | 
|---|
| [67] | 1287 |   struct in_addr   haddr_local;
 | 
|---|
 | 1288 |   struct sh_portentry * portent;
 | 
|---|
 | 1289 | 
 | 
|---|
 | 1290 |   CuAssertTrue(tc, 0 != inet_aton("127.0.0.1", &haddr_local));
 | 
|---|
 | 1291 | 
 | 
|---|
 | 1292 |   sh_portchk_add_to_list ("tcp",  8000, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
 | 
|---|
 | 1293 | 
 | 
|---|
 | 1294 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, NULL);
 | 
|---|
 | 1295 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1296 | 
 | 
|---|
 | 1297 |   CuAssertTrue(tc, portent->port == 8000);
 | 
|---|
 | 1298 |   CuAssertTrue(tc, 0 == strcmp("127.0.0.1", portent->interface));
 | 
|---|
 | 1299 |   CuAssertTrue(tc, portent->status == SH_PORT_UNKN);
 | 
|---|
 | 1300 |   CuAssertTrue(tc, portent->flag == SH_PORT_NOT);
 | 
|---|
 | 1301 | 
 | 
|---|
 | 1302 |   sh_portchk_check_list (&portlist_tcp, "tcp", SH_PORT_NOREPT);
 | 
|---|
 | 1303 | 
 | 
|---|
 | 1304 |   CuAssertTrue(tc, NULL == portlist_tcp);
 | 
|---|
 | 1305 | 
 | 
|---|
 | 1306 |   sh_portchk_add_to_list ("tcp",  8000, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
 | 
|---|
 | 1307 |   sh_portchk_add_to_list ("tcp",  8001, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
 | 
|---|
 | 1308 |   sh_portchk_add_to_list ("tcp",  8002, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
 | 
|---|
 | 1309 |   sh_portchk_add_to_list ("tcp",  8003, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
 | 
|---|
| [127] | 1310 |   sh_portchk_add_to_list ("tcp",  8004, haddr_local, NULL, SH_PORT_IGN, SH_PORT_UNKN);
 | 
|---|
| [67] | 1311 |   sh_portchk_add_to_list ("tcp",    -1, haddr_local, "foo1", SH_PORT_NOT, SH_PORT_UNKN);
 | 
|---|
 | 1312 |   sh_portchk_add_to_list ("tcp",    -1, haddr_local, "foo2", SH_PORT_REQ, SH_PORT_UNKN);
 | 
|---|
 | 1313 |   sh_portchk_add_to_list ("tcp",    -1, haddr_local, "foo3", SH_PORT_NOT, SH_PORT_UNKN);
 | 
|---|
 | 1314 |   sh_portchk_add_to_list ("tcp",    -1, haddr_local, "foo4", SH_PORT_REQ, SH_PORT_UNKN);
 | 
|---|
| [127] | 1315 |   sh_portchk_add_to_list ("tcp",    -1, haddr_local, "foo5", SH_PORT_IGN, SH_PORT_UNKN);
 | 
|---|
| [67] | 1316 | 
 | 
|---|
 | 1317 |   sh_portchk_check_list (&portlist_tcp, "tcp", SH_PORT_NOREPT);
 | 
|---|
 | 1318 | 
 | 
|---|
 | 1319 |   CuAssertPtrNotNull(tc, portlist_tcp);
 | 
|---|
 | 1320 | 
 | 
|---|
 | 1321 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, NULL);
 | 
|---|
 | 1322 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1323 | 
 | 
|---|
 | 1324 |   portent = sh_portchk_get_from_list("tcp",  8001, haddr_local, NULL);
 | 
|---|
 | 1325 |   CuAssertTrue(tc, NULL == portent);
 | 
|---|
 | 1326 | 
 | 
|---|
 | 1327 |   portent = sh_portchk_get_from_list("tcp",  8002, haddr_local, NULL);
 | 
|---|
 | 1328 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1329 | 
 | 
|---|
 | 1330 |   portent = sh_portchk_get_from_list("tcp",  8003, haddr_local, NULL);
 | 
|---|
 | 1331 |   CuAssertTrue(tc, NULL == portent);
 | 
|---|
 | 1332 | 
 | 
|---|
| [127] | 1333 |   portent = sh_portchk_get_from_list("tcp",  8004, haddr_local, NULL);
 | 
|---|
 | 1334 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1335 | 
 | 
|---|
| [67] | 1336 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, "foo1");
 | 
|---|
 | 1337 |   CuAssertTrue(tc, NULL == portent);
 | 
|---|
 | 1338 | 
 | 
|---|
 | 1339 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, "foo2");
 | 
|---|
 | 1340 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1341 |   CuAssertTrue(tc, 0 == strcmp(portent->service, "foo2"));
 | 
|---|
 | 1342 | 
 | 
|---|
 | 1343 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, "foo3");
 | 
|---|
 | 1344 |   CuAssertTrue(tc, NULL == portent);
 | 
|---|
 | 1345 | 
 | 
|---|
 | 1346 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, "foo4");
 | 
|---|
 | 1347 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1348 |   CuAssertTrue(tc, 0 == strcmp(portent->service, "foo4"));
 | 
|---|
| [127] | 1349 | 
 | 
|---|
 | 1350 |   portent = sh_portchk_get_from_list("tcp",  8000, haddr_local, "foo5");
 | 
|---|
 | 1351 |   CuAssertPtrNotNull(tc, portent);
 | 
|---|
 | 1352 |   CuAssertTrue(tc, 0 == strcmp(portent->service, "foo5"));
 | 
|---|
| [67] | 1353 | #else
 | 
|---|
 | 1354 |   (void) tc; /* fix compiler warning */
 | 
|---|
 | 1355 | #endif
 | 
|---|
 | 1356 |   return;
 | 
|---|
 | 1357 | }
 | 
|---|
 | 1358 | #endif
 | 
|---|
 | 1359 | 
 | 
|---|
 | 1360 | #ifdef TEST_ONLY
 | 
|---|
 | 1361 | 
 | 
|---|
 | 1362 | void usage (char * pname)
 | 
|---|
 | 1363 | {
 | 
|---|
 | 1364 |   printf ("%s [-r|--required interface:portlist][-o|--optional interface:portlist][--no-udp][-d|--debug] hostname\n\n", pname);
 | 
|---|
 | 1365 |   printf ("   Check local host for open ports; Version %s\n\n", PORTCHK_VERSION);
 | 
|---|
 | 1366 |   printf ("   Interface: Numeric address for an interface, e.g. 127.0.0.1\n");
 | 
|---|
 | 1367 |   printf ("   Portlist:  List of ports or services, e.g. 22/tcp,nfs/udp,nlockmgr/udp\n");
 | 
|---|
 | 1368 |   printf ("     required -> must be open\n");
 | 
|---|
 | 1369 |   printf ("     optional ->  may be open or closed\n");
 | 
|---|
 | 1370 |   printf ("   RPC services must be specified with service **name**, others with **port number**\n\n");
 | 
|---|
 | 1371 |   printf ("   Example:\n");
 | 
|---|
 | 1372 |   printf ("      %s --required 192.168.1.2:22/tcp,nfs/udp,nlockmgr/udp\n\n", pname);
 | 
|---|
 | 1373 |   return;
 | 
|---|
 | 1374 | }
 | 
|---|
 | 1375 | 
 | 
|---|
 | 1376 | int main(int argc, char *argv[])
 | 
|---|
 | 1377 | {
 | 
|---|
 | 1378 |   char * pname = argv[0];
 | 
|---|
 | 1379 | 
 | 
|---|
 | 1380 | 
 | 
|---|
 | 1381 |   /* 
 | 
|---|
 | 1382 |   test_lists();
 | 
|---|
 | 1383 | 
 | 
|---|
 | 1384 |   portlist_tcp = sh_portchk_kill_list (portlist_tcp);
 | 
|---|
 | 1385 |   portlist_udp = sh_portchk_kill_list (portlist_udp);
 | 
|---|
 | 1386 |   */
 | 
|---|
 | 1387 | 
 | 
|---|
 | 1388 |   // sh_portchk_add_required ("127.0.0.1 : nlockmgr/tcp, 5308/tcp, nfs/tcp");
 | 
|---|
 | 1389 | 
 | 
|---|
 | 1390 |   while (argc > 1 && argv[1][0] == '-')
 | 
|---|
 | 1391 |     {
 | 
|---|
 | 1392 |       if (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))
 | 
|---|
 | 1393 |         {
 | 
|---|
 | 1394 |           usage(pname);
 | 
|---|
 | 1395 |           exit (0);
 | 
|---|
 | 1396 |         }
 | 
|---|
 | 1397 |       else if (0 == strcmp(argv[1], "--required") || 0 == strcmp(argv[1], "-r"))
 | 
|---|
 | 1398 |         {
 | 
|---|
 | 1399 |           if (argc < 3)
 | 
|---|
 | 1400 |             {
 | 
|---|
 | 1401 |               usage(pname);
 | 
|---|
 | 1402 |               exit (1);
 | 
|---|
 | 1403 |             }
 | 
|---|
 | 1404 |           sh_portchk_add_required (argv[2]);
 | 
|---|
 | 1405 |           --argc; ++argv;
 | 
|---|
 | 1406 |         }
 | 
|---|
 | 1407 |       else if (0 == strcmp(argv[1], "--optional") || 0 == strcmp(argv[1], "-o"))
 | 
|---|
 | 1408 |         {
 | 
|---|
 | 1409 |           if (argc < 3)
 | 
|---|
 | 1410 |             {
 | 
|---|
 | 1411 |               usage(pname);
 | 
|---|
 | 1412 |               exit (1);
 | 
|---|
 | 1413 |             }
 | 
|---|
 | 1414 |           sh_portchk_add_optional (argv[2]);
 | 
|---|
 | 1415 |           --argc; ++argv;
 | 
|---|
 | 1416 |         }
 | 
|---|
 | 1417 |       else if (0 == strcmp(argv[1], "--no-udp"))
 | 
|---|
 | 1418 |         {
 | 
|---|
 | 1419 |           sh_portchk_check_udp = 0;
 | 
|---|
 | 1420 |         }
 | 
|---|
 | 1421 |       else if (0 == strcmp(argv[1], "--debug") || 0 == strcmp(argv[1], "-d"))
 | 
|---|
 | 1422 |         {
 | 
|---|
 | 1423 |           portchk_debug = 1;
 | 
|---|
 | 1424 |         }
 | 
|---|
 | 1425 |       else
 | 
|---|
 | 1426 |         {
 | 
|---|
 | 1427 |           usage(pname);
 | 
|---|
 | 1428 |           exit (1);
 | 
|---|
 | 1429 |         }
 | 
|---|
 | 1430 |       --argc; ++argv;
 | 
|---|
 | 1431 |     }
 | 
|---|
 | 1432 | 
 | 
|---|
 | 1433 |   if (argc < 2)
 | 
|---|
 | 1434 |     {
 | 
|---|
 | 1435 |       usage(pname);
 | 
|---|
 | 1436 |       exit (1);
 | 
|---|
 | 1437 |     }
 | 
|---|
 | 1438 | 
 | 
|---|
 | 1439 |   portchk_hostname = argv[1];
 | 
|---|
 | 1440 |       
 | 
|---|
 | 1441 |   if (0 != sh_portchk_init ())
 | 
|---|
 | 1442 |     {
 | 
|---|
 | 1443 |       usage(pname);
 | 
|---|
 | 1444 |       exit (1);
 | 
|---|
 | 1445 |     }
 | 
|---|
 | 1446 | 
 | 
|---|
 | 1447 |   sh_portchk_check();
 | 
|---|
 | 1448 | 
 | 
|---|
 | 1449 |   return 0;
 | 
|---|
 | 1450 | }
 | 
|---|
 | 1451 | #endif
 | 
|---|