source: trunk/src/sh_portcheck.c@ 172

Last change on this file since 172 was 171, checked in by katerina, 16 years ago

Include dnmalloc (ticket #108) and fix bugs #106 (EINPROGRESS) and #107 (compressBound).

  • Property svn:executable set to *
File size: 42.7 KB
RevLine 
[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
[149]82#define SH_PORT_BLACKLIST 4
[67]83
84#define SH_PORT_MISS 0
85#define SH_PORT_ISOK 1
86#define SH_PORT_UNKN 2
87
88#define SH_PORT_NOREPT 0
89#define SH_PORT_REPORT 1
90
[149]91#define SH_PROTO_TCP 0
92#define SH_PROTO_UDP 1
93#define SH_PROTO_STR(a) (((a) == IPPROTO_TCP) ? _("tcp") : _("udp"))
94
[67]95struct sh_portentry {
96 int port;
97 char interface[SH_INTERFACE_SIZE];
98 char * service;
99 char * error;
100 int flag; /* required or not */
101 int status; /* missing or not */
102 struct sh_portentry * next;
103};
104
105static struct sh_portentry * portlist_tcp = NULL;
106static struct sh_portentry * portlist_udp = NULL;
107
[149]108struct sh_port {
109 int port;
110 struct in_addr haddr;
111 struct sh_port * next;
112};
113
114static struct sh_port * blacklist_tcp = NULL;
115static struct sh_port * blacklist_udp = NULL;
116
[67]117#define SH_PORTCHK_INTERVAL 300
118
119static int sh_portchk_check_udp = 1;
120static int sh_portchk_active = 1;
121static int sh_portchk_interval = SH_PORTCHK_INTERVAL;
122#if !defined(TEST_ONLY)
123
124#define FIL__ _("sh_portcheck.c")
125#include "samhain.h"
126#include "sh_error.h"
127#include "sh_mem.h"
[109]128#include "sh_calls.h"
[67]129#include "sh_utils.h"
130#include "sh_modules.h"
[162]131#include "sh_static.h"
[137]132#include "sh_pthread.h"
[67]133
[149]134SH_MUTEX_STATIC(mutex_port_check, PTHREAD_MUTEX_INITIALIZER);
135
[67]136static int sh_portchk_severity = SH_ERR_SEVERE;
137#endif
138
[127]139/* Exported interface to add ignoreable ports as 'iface:portlist'
140 */
141static int sh_portchk_add_ignore (const char * str);
142
[67]143/* Exported interface to add required ports as 'iface:portlist'
144 */
145static int sh_portchk_add_required (const char * str);
146
147/* Exported interface to add optional ports as 'iface:portlist'
148 */
149static int sh_portchk_add_optional (const char * str);
150
[149]151/* Exported interface to add blacklisted ports as 'iface:portlist'
152 */
153static int sh_portchk_add_blacklist (const char * str);
154
[67]155/* Exported interface to add an ethernet interface
156 */
157static int sh_portchk_add_interface (const char * str);
158
[149]159/* verify whether port/interface is blacklisted (do not check)
160 */
161static int sh_portchk_is_blacklisted(int port, struct in_addr haddr, int proto);
[67]162
163#ifndef TEST_ONLY
164
165static int sh_portchk_set_interval (const char * c)
166{
167 int retval = 0;
168 long val;
169
170 SL_ENTER(_("sh_portchk_set_interval"));
171 val = strtol (c, (char **)NULL, 10);
172 if (val <= 0)
173 {
[149]174 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]175 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
176 _("port check interval"), c);
[149]177 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]178 retval = -1;
179 }
180
181 sh_portchk_interval = (time_t) val;
182 SL_RETURN(0, _("sh_portchk_set_interval"));
183}
184
185
186static int sh_portchk_set_active (const char * str)
187{
188 return sh_util_flagval(str, &sh_portchk_active);
189}
190
191static int sh_portchk_set_udp (const char * str)
192{
193 return sh_util_flagval(str, &sh_portchk_check_udp);
194}
195
196static int sh_portchk_set_severity (const char * str)
197{
198 char tmp[32];
199 tmp[0] = '='; tmp[1] = '\0';
200 sl_strlcat (tmp, str, 32);
201 return sh_error_set_level (tmp, &sh_portchk_severity);
202}
203
204sh_rconf sh_portchk_table[] = {
205 {
206 N_("severityportcheck"),
207 sh_portchk_set_severity,
208 },
209 {
210 N_("portcheckrequired"),
211 sh_portchk_add_required,
212 },
213 {
214 N_("portcheckoptional"),
215 sh_portchk_add_optional,
216 },
217 {
[127]218 N_("portcheckignore"),
219 sh_portchk_add_ignore,
220 },
221 {
[149]222 N_("portcheckskip"),
223 sh_portchk_add_blacklist,
224 },
225 {
[67]226 N_("portcheckactive"),
227 sh_portchk_set_active,
228 },
229 {
230 N_("portcheckinterface"),
231 sh_portchk_add_interface,
232 },
233 {
234 N_("portcheckinterval"),
235 sh_portchk_set_interval,
236 },
237 {
238 N_("portcheckudp"),
239 sh_portchk_set_udp,
240 },
241 {
242 NULL,
243 NULL
244 }
245};
246
247#endif
248
249/* Interface to initialize port check
250 */
[170]251int sh_portchk_init (struct mod_type * arg);
[67]252
253/* Interface to reset port check
254 */
[170]255int sh_portchk_reset (void);
[67]256
257/* Interface to run port check
258 */
[170]259int sh_portchk_check (void);
[67]260
261
[149]262static char * check_services (int port, int proto);
[67]263
264#ifdef TEST_ONLY
265
266static int portchk_debug = 0;
267#define SH_ALLOC malloc
268#define SH_FREE free
269#define sh_util_strdup strdup
270#define sl_strlcpy strncpy
271#define _(a) a
272
273#else
274
275static int portchk_debug = 0;
276
277#endif
278
[149]279static void sh_portchk_add_to_list (int proto,
[67]280 int port, struct in_addr haddr, char * service,
281 int flag, int status)
282{
283 struct sh_portentry * new = SH_ALLOC (sizeof(struct sh_portentry));
284
285 if (portchk_debug)
286 fprintf(stderr, _("add to list: port %d/%s %d %d (%s)\n"),
[149]287 port, SH_PROTO_STR(proto), flag, status, service ? service : _("undef"));
[67]288
289 new->port = port;
290 sl_strlcpy (new->interface, inet_ntoa(haddr), SH_INTERFACE_SIZE);
291 new->status = status;
292 new->flag = flag;
293
294 new->error = NULL;
295
296 if (service)
297 new->service = sh_util_strdup (service);
298 else
299 new->service = NULL;
[149]300 if (proto == IPPROTO_TCP)
[67]301 {
302 new->next = portlist_tcp;
303 portlist_tcp = new;
304 }
305 else
306 {
307 new->next = portlist_udp;
308 portlist_udp = new;
309 }
310 return;
311}
312
313/* Reset the list by setting all entries to UNKN.
314 * In the next cycle we will check, and set found ports to ISOK.
315 * Thereafter, we check for entries that are still UNKN.
316 */
[170]317static void sh_portchk_reset_lists (void)
[67]318{
319 struct sh_portentry * portlist;
320
321 portlist = portlist_tcp;
322 while (portlist)
323 {
324 if (portlist->status != SH_PORT_MISS)
325 portlist->status = SH_PORT_UNKN;
326 portlist = portlist->next;
327 }
328 portlist = portlist_udp;
329 while (portlist)
330 {
331 if (portlist->status != SH_PORT_MISS)
332 portlist->status = SH_PORT_UNKN;
333 portlist = portlist->next;
334 }
335 return;
336}
337
338static struct sh_portentry * sh_portchk_kill_list (struct sh_portentry * head)
339{
340 if (head)
341 {
342 if (head->next)
343 sh_portchk_kill_list (head->next);
344
345 if (head->service)
346 SH_FREE(head->service);
347 SH_FREE(head);
348 }
349 return NULL;
350}
351
[149]352static struct sh_port * sh_portchk_kill_blacklist (struct sh_port * head)
353{
354 if (head)
355 {
356 if (head->next)
357 sh_portchk_kill_blacklist (head->next);
358
359 SH_FREE(head);
360 }
361 return NULL;
362}
363
[170]364/* These variables are not used anywhere. They only exist
365 * to assign &pre, &ptr to them, which keeps gcc from
366 * putting it into a register, and avoids the 'clobbered
367 * by longjmp' warning. And no, 'volatile' proved insufficient.
368 */
369static void * sh_dummy_pre = NULL;
370static void * sh_dummy_ptr = NULL;
371
[67]372/* check the list of open ports for any that are marked as UNKN
373 */
[149]374static void sh_portchk_check_list (struct sh_portentry ** head, int proto, int report)
[67]375{
376 struct sh_portentry * ptr = *head;
377 struct sh_portentry * pre = *head;
378 char errbuf[256];
379
[170]380 /* Take the address to keep gcc from putting them into registers.
381 * Avoids the 'clobbered by longjmp' warning.
382 */
383 sh_dummy_pre = (void*) &pre;
384 sh_dummy_ptr = (void*) &ptr;
385
[67]386 while (ptr)
387 {
388 if (portchk_debug && report)
389 fprintf(stderr, _("check list: port %d/%s %d %d\n"),
[149]390 ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
[67]391
392 if (ptr->status == SH_PORT_UNKN)
393 {
394 /* Don't report missing ports that are marked as optional
395 */
[127]396 if (ptr->flag != SH_PORT_OPT && ptr->flag != SH_PORT_IGN)
[67]397 {
[169]398 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[149]399 ptr->interface, ptr->port, SH_PROTO_STR(proto),
[67]400 ptr->service ? ptr->service : check_services(ptr->port, proto));
401#ifdef TEST_ONLY
402 if (report == SH_PORT_REPORT)
403 fprintf(stderr, _("%s\n"), errbuf);
404#else
405 if (report == SH_PORT_REPORT)
[149]406 {
407 SH_MUTEX_LOCK(mutex_thread_nolog);
408 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]409 MSG_PORT_MISS, errbuf);
[149]410 SH_MUTEX_UNLOCK(mutex_thread_nolog);
411 }
[67]412#endif
413 }
414
415 ptr->status = SH_PORT_MISS;
416
[128]417 if ((ptr->flag != SH_PORT_REQ) && (ptr->flag != SH_PORT_OPT) && (ptr->flag != SH_PORT_IGN))
[67]418 {
419 if (portchk_debug && report)
420 fprintf(stderr, _("removing: port %d/%s %d %d\n"),
[149]421 ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
[67]422
423 if (ptr == *head)
424 {
425 *head = ptr->next;
426 if (ptr->service)
427 SH_FREE(ptr->service);
428 SH_FREE(ptr);
429 ptr = *head;
430 pre = *head;
431 continue;
432 }
433 else if (ptr->next == NULL)
434 {
435 pre->next = NULL;
436 if (ptr->service)
437 SH_FREE(ptr->service);
438 SH_FREE(ptr);
439 return;
440 }
441 else
442 {
443 pre->next = ptr->next;
444 if (ptr->service)
445 SH_FREE(ptr->service);
446 SH_FREE(ptr);
447 ptr = pre->next;
448 continue;
449 }
450 }
451 }
452 pre = ptr;
453 ptr = ptr->next;
454 }
455 return;
456}
457
458
[149]459static struct sh_portentry * sh_portchk_get_from_list (int proto, int port,
[67]460 struct in_addr haddr, char * service)
461{
462 struct sh_portentry * portlist;
[75]463 char iface_all[8];
464
465 sl_strlcpy (iface_all, _("0.0.0.0"), sizeof(iface_all));
[67]466
[149]467 if (proto == IPPROTO_TCP)
[67]468 portlist = portlist_tcp;
469 else
470 portlist = portlist_udp;
471
472 if (service)
473 {
474 while (portlist)
475 {
476 if (portlist->service &&
477 0 == strcmp(service, portlist->service) &&
478 (0 == strcmp(portlist->interface, inet_ntoa(haddr)) ||
479 0 == strcmp(portlist->interface, iface_all)))
480 return portlist;
481 portlist = portlist->next;
482 }
483 }
484 else
485 {
486 while (portlist)
487 {
488 if (port == portlist->port &&
489 (0 == strcmp(portlist->interface, inet_ntoa(haddr)) ||
490 0 == strcmp(portlist->interface, iface_all)))
491 return portlist;
492 portlist = portlist->next;
493 }
494 }
495 return NULL;
496}
497
498
[149]499static void sh_portchk_cmp_to_list (int proto, int port, struct in_addr haddr, char * service)
[67]500{
501 struct sh_portentry * portent;
502 char errbuf[256];
503
504
505 portent = sh_portchk_get_from_list (proto, port, haddr, service);
506
507 if (service)
508 {
509 if (!portent)
510 {
[169]511 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[149]512 inet_ntoa(haddr), port, SH_PROTO_STR(proto), service);
[67]513#ifdef TEST_ONLY
514 fprintf(stderr, _("open port: %s:%d/%s (%s)\n"),
[149]515 inet_ntoa(haddr), port, SH_PROTO_STR(proto), service);
[67]516#else
[149]517 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]518 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]519 MSG_PORT_NEW, errbuf);
[149]520 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]521#endif
522 /*
523 * was not there, thus it is not in 'required' or 'optional' list
524 */
525 sh_portchk_add_to_list (proto, port, haddr, service, SH_PORT_NOT, SH_PORT_ISOK);
526 }
[127]527 else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
[67]528 {
[169]529 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
530 inet_ntoa(haddr), port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
[67]531#ifdef TEST_ONLY
532 fprintf(stderr, _("service: %s\n"), errbuf);
533#else
[149]534 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]535 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]536 MSG_PORT_RESTART, errbuf);
[149]537 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]538#endif
539
540 portent->status = SH_PORT_ISOK;
541 }
542 else if (port != portent->port && (-1) != portent->port)
543 {
[169]544 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
545 inet_ntoa(haddr), port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
[67]546#ifdef TEST_ONLY
547 fprintf(stderr, _("service: %s\n"), errbuf);
548#else
[149]549 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]550 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]551 MSG_PORT_NEWPORT, errbuf);
[149]552 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]553#endif
[127]554 portent->port = port;
[67]555 portent->status = SH_PORT_ISOK;
556 }
557 else
558 {
559 portent->status = SH_PORT_ISOK;
560 }
561 }
562 else
563 {
564 if (!portent)
565 {
[169]566 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[149]567 inet_ntoa(haddr), port, SH_PROTO_STR(proto), check_services(port, proto));
[67]568#ifdef TEST_ONLY
569 fprintf(stderr, _("open port: %s:%d/%s (%s)\n"),
[149]570 inet_ntoa(haddr), port, SH_PROTO_STR(proto), check_services(port, proto));
[67]571#else
[149]572 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]573 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]574 MSG_PORT_NEW, errbuf);
[149]575 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]576#endif
577
578 /* was not there, thus it is not in 'required' or 'optional' list
579 */
580 sh_portchk_add_to_list (proto, port, haddr, service, SH_PORT_NOT, SH_PORT_ISOK);
581 }
[127]582 else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
[67]583 {
[169]584 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[149]585 inet_ntoa(haddr), port, SH_PROTO_STR(proto), check_services(port, proto));
[67]586#ifdef TEST_ONLY
587 fprintf(stderr, _("port : %s\n"), errbuf);
588#else
[149]589 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]590 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]591 MSG_PORT_RESTART, errbuf);
[149]592 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]593#endif
594
595 portent->status = SH_PORT_ISOK;
596 }
597 else
598 {
599 portent->status = SH_PORT_ISOK;
600 }
601 }
602
603 return;
604}
605
606
607/* Returns a static buffer containing the name of the service
608 * running on port <port> (from /etc/services)
609 * Returns NULL on failure
610 */
[149]611static char * check_services (int port, int proto)
[67]612{
613 static char buf[256];
[149]614 struct servent * service = getservbyport(htons(port), SH_PROTO_STR(proto));
[67]615
616 if (service && service->s_name && service->s_name[0] != '\0')
617 {
618 snprintf (buf, sizeof(buf), _("maybe_%s"), service->s_name);
619 }
620 else
621 {
622 snprintf (buf, sizeof(buf), _("unknown"));
623 }
624 return buf;
625}
626
627/* Returns a static buffer containing the name of the service
628 * running on port <port> at <address> (from portmap daemon)
629 * Returns NULL on failure
630 */
631static char * check_rpc_list (int port, struct sockaddr_in * address,
632 unsigned long prot)
633{
634 struct pmaplist * head;
635 struct rpcent *r;
636 static char buf[256];
637
638 head = pmap_getmaps(address);
639
640 if (head)
641 {
642 do /* while (head != NULL) */
643 {
644 if ((head->pml_map.pm_prot == prot) &&
645 (port == (int)head->pml_map.pm_port))
646 {
647 r = getrpcbynumber((int)head->pml_map.pm_prog);
648 if (r && r->r_name && r->r_name[0] != '\0')
649 {
650 snprintf (buf, sizeof(buf), "%s", r->r_name);
651 return buf;
652 }
653 else
654 {
655 snprintf (buf, sizeof(buf), "RPC_%lu",
656 (unsigned long)head->pml_map.pm_prog);
657 return buf;
658 }
659 }
660 head = head->pml_next;
661 }
662 while (head != NULL);
663 }
664
665 return NULL;
666}
667
668static int check_port_udp_internal (int fd, int port, struct in_addr haddr)
669{
670 struct sockaddr_in sinr;
671 /* struct in_addr haddr; */
672 int retval;
673 char * p;
674 char buf[8];
[78]675#ifndef TEST_ONLY
676 char errmsg[256];
677 int nerr;
678#endif
[132]679 char errbuf[SH_ERRBUF_SIZE];
[67]680
681 /* inet_aton(interface, &haddr); */
682
683 sinr.sin_family = AF_INET;
684 sinr.sin_port = htons (port);
685 sinr.sin_addr = haddr;
686
[78]687 do {
688 retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
[171]689 } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
[78]690
[67]691 if (retval == -1)
692 {
693#ifdef TEST_ONLY
694 if (portchk_debug)
695 perror(_("connect"));
696#else
[78]697 nerr = errno;
698 sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/udp on %15s: %s"),
[132]699 port, inet_ntoa(haddr), sh_error_message(errno, errbuf, sizeof(errbuf)));
[149]700 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]701 sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
702 errmsg, _("connect"));
[149]703 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]704#endif
705 }
706 else
707 {
[78]708 do {
709 retval = send (fd, buf, 0, 0);
710 } while (retval < 0 && errno == EINTR);
[67]711
712 if (retval == -1 && errno == ECONNREFUSED)
713 {
714 if (portchk_debug)
715 fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
716 port, inet_ntoa(haddr));
717 }
718 else
719 {
[78]720 /* Only the second send() may catch the error
721 */
722 do {
723 retval = send (fd, buf, 0, 0);
724 } while (retval < 0 && errno == EINTR);
725
[67]726 if (retval == -1 && errno == ECONNREFUSED)
727 {
728 if (portchk_debug)
729 fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
730 port, inet_ntoa(haddr));
731 }
732 else if (retval != -1)
733 {
734 /* Try to get service name from portmap
735 */
736 p = check_rpc_list (port, &sinr, IPPROTO_UDP);
737
[149]738 sh_portchk_cmp_to_list (IPPROTO_UDP, port, haddr, p ? p : NULL);
[67]739
740 /* If not an RPC service, try to get name from /etc/services
741 */
742 if (!p)
[149]743 p = check_services(port, IPPROTO_UDP);
[67]744
745 if (portchk_debug)
746 fprintf(stderr, _("check port: %5d/udp on %15s open %s\n"),
747 port, inet_ntoa(haddr), p);
748
749 }
750 }
751 }
752 close (fd);
753 return 0;
754}
755
756static int check_port_tcp_internal (int fd, int port, struct in_addr haddr)
757{
758 struct sockaddr_in sinr;
759 /* struct in_addr haddr; */
760 int retval;
[109]761 int flags;
[67]762 char * p;
[78]763#ifndef TEST_ONLY
764 char errmsg[256];
765 int nerr;
766#endif
[132]767 char errbuf[SH_ERRBUF_SIZE];
[67]768
769 /* inet_aton(interface, &haddr); */
770
771 sinr.sin_family = AF_INET;
772 sinr.sin_port = htons (port);
773 sinr.sin_addr = haddr;
774
[78]775 do {
776 retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
[171]777 } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
[78]778
[67]779 if (retval == -1 && errno == ECONNREFUSED)
780 {
781 if (portchk_debug)
782 fprintf(stderr, _("check port: %5d on %15s established/time_wait\n"),
783 port, inet_ntoa(haddr));
784 }
785 else if (retval == -1)
786 {
787#ifdef TEST_ONLY
788 if (portchk_debug)
789 perror(_("connect"));
790#else
[78]791 nerr = errno;
792 sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/tcp on %15s: %s"),
[132]793 port, inet_ntoa(haddr), sh_error_message(errno, errbuf, sizeof(errbuf)));
[149]794 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]795 sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
796 errmsg, _("connect"));
[149]797 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]798#endif
799 }
800 else
801 {
802 /* Try to get service name from portmap
803 */
804 p = check_rpc_list (port, &sinr, IPPROTO_TCP);
805
[149]806 sh_portchk_cmp_to_list (IPPROTO_TCP, port, haddr, p ? p : NULL);
[67]807
808 /* If not an RPC service, try to get name from /etc/services
809 */
810 if (!p)
[149]811 p = check_services(port, IPPROTO_TCP);
[67]812
813 if (portchk_debug)
814 fprintf(stderr, _("check port: %5d on %15s open %s\n"),
815 port, inet_ntoa(haddr), p);
[109]816
817#if !defined(O_NONBLOCK)
818#if defined(O_NDELAY)
819#define O_NONBLOCK O_NDELAY
820#else
821#define O_NONBLOCK 0
822#endif
823#endif
824
825 /* prepare to close connection gracefully
826 */
827 if (port == 22) /* ssh */
828 {
829 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
830 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]831 retval = write (fd, _("SSH-2.0-Foobar"), 14);
832 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]833 }
834 else if (port == 25) /* smtp */
835 {
836 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
837 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]838 retval = write (fd, _("QUIT"), 4);
839 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]840 }
841 else if (port == 79) /* finger */
842 {
843 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
844 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]845 retval = write (fd, "\r\n", 2);
[109]846 }
847 else if (port == 110) /* pop3 */
848 {
849 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
850 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]851 retval = write (fd, _("QUIT"), 4);
852 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]853 }
854 else if (port == 143) /* imap */
855 {
856 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
857 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]858 retval = write (fd, _("A01 LOGOUT"), 10);
859 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]860 }
[170]861
862 if (portchk_debug && retval < 0)
863 fprintf(stderr, _("check port: error writing to port %5d\n"),
864 port);
[67]865 }
866 close (fd);
867 return 0;
868}
869
870/* typedef uint32_t in_addr_t;
871 * struct in_addr
872 * {
873 * in_addr_t s_addr;
874 * };
875 */
876
877#define SH_IFACE_MAX 16
878
879struct portchk_interfaces {
880 struct in_addr iface[SH_IFACE_MAX];
881 int used;
882};
883
884static struct portchk_interfaces iface_list;
885static int iface_initialized = 0;
886
887#ifdef TEST_ONLY
888static char * portchk_hostname = NULL;
889#else
890static char * portchk_hostname = sh.host.name;
891#endif
892
[149]893static int sh_portchk_init_internal (void)
[67]894{
895 struct hostent * hent;
[170]896 volatile int i; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
[67]897 char errbuf[256];
898
899 if (portchk_debug)
900 fprintf(stderr, _("checking ports on: %s\n"), portchk_hostname ? portchk_hostname : _("NULL"));
[78]901
[67]902 if (!portchk_hostname)
903 return -1;
904
[78]905 if (sh_portchk_active == S_FALSE)
906 return -1;
907
[149]908 SH_MUTEX_LOCK(mutex_port_check);
[67]909 if (iface_initialized == 0)
910 {
911 iface_list.used = 0;
912 iface_initialized = 1;
913 }
914
[134]915 SH_MUTEX_LOCK(mutex_resolv);
[162]916 hent = sh_gethostbyname(portchk_hostname);
[170]917 i = 0;
[67]918 while (hent && hent->h_addr_list[i] && (iface_list.used < SH_IFACE_MAX))
919 {
920 memcpy (&(iface_list.iface[iface_list.used].s_addr), hent->h_addr_list[i], sizeof(in_addr_t));
[134]921 ++iface_list.used;
922 ++i;
923 }
924 SH_MUTEX_UNLOCK(mutex_resolv);
925
926 for (i = 0; i < iface_list.used; ++i)
927 {
[67]928 sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"),
[134]929 inet_ntoa(iface_list.iface[i]));
[149]930 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]931 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
932 errbuf, _("sh_portchk_init"));
[149]933 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]934 }
[149]935 SH_MUTEX_UNLOCK(mutex_port_check);
[67]936
937 return 0;
938}
939
[149]940int sh_portchk_init (struct mod_type * arg)
941{
942 if (sh_portchk_active == S_FALSE)
943 return SH_MOD_FAILED;
944 if (!portchk_hostname)
945 return SH_MOD_FAILED;
946
947#ifdef HAVE_PTHREAD
948 if (arg != NULL && arg->initval < 0 &&
949 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
950 {
951 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
952 return SH_MOD_THREAD;
953 else
954 return SH_MOD_FAILED;
955 }
956#endif
957 return sh_portchk_init_internal();
958}
959
960
961
[67]962#if !defined(TEST_ONLY)
[170]963int sh_portchk_reconf (void)
[67]964{
[149]965 SH_MUTEX_LOCK(mutex_port_check);
[78]966 iface_initialized = 0;
967 sh_portchk_active = 1;
[80]968 sh_portchk_check_udp = 1;
[149]969 sh_portchk_interval = SH_PORTCHK_INTERVAL;
[78]970
[67]971 portlist_udp = sh_portchk_kill_list (portlist_udp);
972 portlist_tcp = sh_portchk_kill_list (portlist_tcp);
[149]973
974 blacklist_udp = sh_portchk_kill_blacklist (blacklist_udp);
975 blacklist_tcp = sh_portchk_kill_blacklist (blacklist_tcp);
976 SH_MUTEX_UNLOCK(mutex_port_check);
[67]977 return 0;
978}
979
[170]980int sh_portchk_cleanup (void)
[67]981{
982 return sh_portchk_reconf ();
983}
984
985int sh_portchk_timer (time_t tcurrent)
986{
987 static time_t lastcheck = 0;
988
989 SL_ENTER(_("sh_portchk_timer"));
990 if ((time_t) (tcurrent - lastcheck) >= sh_portchk_interval)
991 {
992 lastcheck = tcurrent;
993 SL_RETURN((-1), _("sh_portchk_timer"));
994 }
995 SL_RETURN(0, _("sh_portchk_timer"));
996}
997#endif
998
999static int check_port_generic (int port, int type, int protocol)
1000{
[170]1001 volatile int i = 0;
[67]1002 int sock = -1;
1003 int flag = 1; /* non-zero to enable an option */
1004 struct in_addr haddr;
[132]1005 char errbuf[SH_ERRBUF_SIZE];
1006
[67]1007 /* Check all interfaces for this host
1008 */
1009 while (i < iface_list.used)
1010 {
[149]1011 haddr.s_addr = iface_list.iface[i].s_addr;
1012
1013 if (0 != sh_portchk_is_blacklisted(port, haddr, protocol))
1014 {
1015 ++i; continue;
1016 }
1017
[67]1018 if ((sock = socket(AF_INET, type, protocol)) < 0 )
1019 {
[170]1020 ++i;
[67]1021#ifdef TEST_ONLY
1022 if (portchk_debug)
1023 perror(_("socket"));
1024#else
[149]1025 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1026 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1027 sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
[149]1028 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[170]1029#endif
[149]1030 continue;
[67]1031 }
1032 if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1033 (void *) &flag, sizeof(flag)) < 0 )
1034 {
[170]1035 ++i;
[67]1036#ifdef TEST_ONLY
1037 if (portchk_debug)
1038 perror(_("setsockopt"));
1039#else
[149]1040 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1041 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1042 sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
[149]1043 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1044#endif
[149]1045 continue;
[67]1046 }
1047
1048
1049 if (protocol == IPPROTO_TCP)
1050 check_port_tcp_internal(sock, port, haddr);
1051 else
1052 check_port_udp_internal(sock, port, haddr);
1053
1054 ++i;
1055 }
1056
1057 return 0;
1058}
1059
1060
1061
1062static int check_port_udp (int port)
1063{
1064 return check_port_generic(port, SOCK_DGRAM, IPPROTO_UDP);
1065}
1066
1067static int check_port_tcp (int port)
1068{
1069 return check_port_generic(port, SOCK_STREAM, IPPROTO_TCP);
1070}
1071
1072
1073
[170]1074static int sh_portchk_scan_ports_generic (int min_port, int max_port_arg, int type, int protocol)
[67]1075{
1076 /*
1077 int min_port = 1024;
1078 int max_port = 65535;
1079 */
1080
[170]1081 volatile int port; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
1082 volatile int max_port = max_port_arg;
[67]1083 int retval;
1084 int sock = -1;
1085 int flag = 1; /* non-zero to enable an option */
1086
1087 struct sockaddr_in addr;
1088 int addrlen = sizeof(addr);
[132]1089 char errbuf[SH_ERRBUF_SIZE];
[67]1090
1091 if (min_port == -1)
1092 min_port = 0;
1093 if (max_port == -1)
1094 max_port = 65535;
1095
1096 for (port = min_port; port <= max_port; ++port)
1097 {
1098
1099 if ((sock = socket(AF_INET, type, protocol)) < 0 )
1100 {
1101#ifdef TEST_ONLY
1102 if (portchk_debug)
1103 perror(_("socket"));
1104#else
[149]1105 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1106 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1107 sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
[149]1108 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1109#endif
[149]1110 continue;
[67]1111 }
1112 if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1113 (void *) &flag, sizeof(flag)) < 0 )
1114 {
1115#ifdef TEST_ONLY
1116 if (portchk_debug)
1117 perror(_("setsockopt"));
1118#else
[149]1119 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1120 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1121 sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
[149]1122 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1123#endif
[149]1124 continue;
[67]1125 }
1126
1127 addr.sin_family = AF_INET;
1128 addr.sin_port = htons(port);
1129 addr.sin_addr.s_addr = INADDR_ANY;
1130
1131 retval = bind (sock, (struct sockaddr *) &addr, addrlen);
1132
1133 if (retval == 0)
1134 {
1135 /* we can bind the port, thus it is unused
1136 */
1137 close (sock);
1138 }
1139 else
1140 {
1141 if (errno == EINVAL || errno == EADDRINUSE)
1142 {
1143 /* try to connect to the port
1144 */
1145 if (protocol == IPPROTO_TCP)
1146 check_port_tcp(port);
1147 else
1148 check_port_udp(port);
1149 }
1150 else
1151 {
1152#ifdef TEST_ONLY
1153 if (portchk_debug)
1154 perror(_("bind"));
1155#else
[149]1156 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1157 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1158 sh_error_message(errno, errbuf, sizeof(errbuf)), _("bind"));
[149]1159 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1160#endif
1161 }
1162 close (sock);
1163 }
1164 }
1165 return 0;
1166}
1167
1168static int sh_portchk_scan_ports_tcp (int min_port, int max_port)
1169{
1170 return sh_portchk_scan_ports_generic (min_port, max_port, SOCK_STREAM, IPPROTO_TCP);
1171}
1172
1173static int sh_portchk_scan_ports_udp (int min_port, int max_port)
1174{
1175 return sh_portchk_scan_ports_generic (min_port, max_port, SOCK_DGRAM, IPPROTO_UDP);
1176}
1177
1178/* Subroutine to add an interface
1179 */
1180static int sh_portchk_add_interface (const char * str)
1181{
1182 struct in_addr haddr;
1183 char errbuf[256];
1184
1185 if (iface_initialized == 0)
1186 {
1187 iface_list.used = 0;
1188 iface_initialized = 1;
1189 }
1190
1191 if (0 == inet_aton(str, &haddr))
1192 return -1;
1193
1194 if (iface_list.used == SH_IFACE_MAX)
1195 return -1;
1196
1197 sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"), inet_ntoa(haddr));
[149]1198 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1199 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1200 errbuf, _("sh_portchk_add_interface"));
[149]1201 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1202
1203 memcpy (&(iface_list.iface[iface_list.used].s_addr), &(haddr.s_addr), sizeof(in_addr_t));
1204 ++iface_list.used;
1205
1206 return 0;
1207}
1208
[149]1209/* verify whether port/interface is blacklisted (do not check)
1210 */
1211static int sh_portchk_is_blacklisted(int port, struct in_addr haddr, int proto)
1212{
1213 struct sh_port * head;
1214
1215 if (proto == IPPROTO_TCP)
1216 head = blacklist_tcp;
1217 else
1218 head = blacklist_udp;
1219
1220 while (head)
1221 {
1222 if (head->port == port)
1223 {
1224 if ((head->haddr.s_addr == 0) || (head->haddr.s_addr == haddr.s_addr))
1225 return 1;
1226 else
1227 return 0;
1228 }
1229 head = head->next;
1230 }
1231 return 0;
1232}
1233
1234
1235static int sh_portchk_blacklist(int port, struct in_addr haddr, int proto)
1236{
1237 struct sh_port * black;
1238 struct sh_port * head;
1239
1240 if (proto == IPPROTO_TCP)
1241 head = blacklist_tcp;
1242 else
1243 head = blacklist_udp;
1244
1245 black = head;
1246
1247 while (black)
1248 {
1249 if (black->port == port && head->haddr.s_addr == haddr.s_addr)
1250 return -1;
1251 black = black->next;
1252 }
1253 black = SH_ALLOC (sizeof(struct sh_port));
1254 black->port = port;
1255 black->haddr.s_addr = haddr.s_addr;
1256 black->next = head;
1257
1258 if (proto == IPPROTO_TCP)
1259 blacklist_tcp = black;
1260 else
1261 blacklist_udp = black;
1262 return 0;
1263}
1264
[67]1265
1266/* Subroutine to add a required or optional port/service
1267 */
1268static int sh_portchk_add_required_port_generic (char * service, char * interface, int type)
1269{
1270 char buf[256];
[149]1271 int proto;
[67]1272 char * p;
1273 char * endptr;
1274 unsigned long int port;
1275 struct in_addr haddr;
1276 struct sh_portentry * portent;
1277
1278 if (0 == inet_aton(interface, &haddr))
1279 return -1;
1280
1281 sl_strlcpy (buf, service, sizeof(buf));
1282
1283 p = strchr(buf, '/');
1284 if (!p)
1285 return -1;
1286 if (0 == strcmp(p, _("/tcp")))
[149]1287 proto = IPPROTO_TCP;
1288 else if (0 == strcmp(p, _("/udp")))
1289 proto = IPPROTO_UDP;
[67]1290 else
1291 return -1;
1292
1293 *p = '\0';
1294 port = strtoul(buf, &endptr, 0);
1295
[149]1296 /* Blacklisted ports
1297 */
1298 if (*endptr == '\0' && port <= 65535 && type == SH_PORT_BLACKLIST)
1299 return (sh_portchk_blacklist(port, haddr, proto));
1300
[67]1301 if (*endptr != '\0')
1302 {
1303 portent = sh_portchk_get_from_list (proto, -1, haddr, buf);
1304 if (!portent)
1305 sh_portchk_add_to_list (proto, -1, haddr, buf, type, SH_PORT_UNKN);
1306 else
1307 {
1308#ifdef TEST_ONLY
[149]1309 fprintf(stderr, "** WARNING: duplicate port definition %s/%s\n", buf, SH_PROTO_STR(proto));
[67]1310#else
[149]1311 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1312 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1313 _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
[149]1314 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1315#endif
1316 return -1;
1317 }
1318 }
1319 else if (port <= 65535)
1320 {
1321 portent = sh_portchk_get_from_list (proto, port, haddr, NULL);
1322 if (!portent)
1323 sh_portchk_add_to_list (proto, port, haddr, NULL, type, SH_PORT_UNKN);
1324 else
1325 {
1326#ifdef TEST_ONLY
[149]1327 fprintf(stderr, "** WARNING: duplicate port definition %lu/%s\n", port, SH_PROTO_STR(proto));
[67]1328#else
[149]1329 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1330 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1331 _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
[149]1332 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1333#endif
1334 return -1;
1335 }
1336 }
1337 else
1338 return -1;
1339
1340 return 0;
1341}
1342
1343/* Internal interface to add required or optional ports as 'iface:portlist'
1344 */
1345static int sh_portchk_add_required_generic (const char * str, int type)
1346{
1347 size_t len;
1348 size_t ll = 0;
[149]1349 int status;
[67]1350
1351 char * interface = NULL;
1352 char * list;
1353 char * p;
[131]1354#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1355 char * saveptr;
1356#endif
[67]1357
1358 if (!str)
1359 return -1;
1360
1361 if (strchr(str, ':'))
1362 {
1363 len = strlen(str);
1364 for (ll = 0; ll < len; ++ll)
1365 {
1366 if (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
1367 {
1368 interface = SH_ALLOC(ll+1);
1369 sl_strlcpy(interface, str, ll+1);
1370 interface[ll] = '\0';
1371 while (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
1372 ++ll;
1373 break;
1374 }
1375 }
1376 }
1377 else
1378 {
1379 interface = SH_ALLOC(8);
1380 sl_strlcpy(interface, _("0.0.0.0"), 8);
1381 interface[7] = '\0';
1382 while (str[ll] == ' ' || str[ll] == '\t')
1383 ++ll;
1384 }
1385
1386 if (!interface)
1387 return -1;
1388
1389 if (str[ll] == '\0')
1390 {
1391 SH_FREE(interface);
1392 return -1;
1393 }
1394
1395 if (portchk_debug)
1396 fprintf(stderr, "add ports for interface: %s\n", interface);
1397
1398 list = sh_util_strdup(&str[ll]);
[131]1399#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1400 p = strtok_r (list, " ,\t", &saveptr);
1401#else
[67]1402 p = strtok (list, " ,\t");
[131]1403#endif
[67]1404 if (!p)
1405 {
1406 SH_FREE(interface);
1407 SH_FREE(list);
1408 return -1;
1409 }
1410 while (p)
1411 {
[149]1412 status = sh_portchk_add_required_port_generic (p, interface, type);
1413
1414 if (-1 == status)
[67]1415 {
1416 SH_FREE(interface);
1417 SH_FREE(list);
1418 return -1;
1419 }
[131]1420#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1421 p = strtok_r (NULL, " ,\t", &saveptr);
1422#else
[67]1423 p = strtok (NULL, " ,\t");
[131]1424#endif
[67]1425 }
1426 SH_FREE(interface);
1427 SH_FREE(list);
1428 return 0;
1429}
1430
1431/* User interface to add required ports as 'iface:portlist'
1432 */
1433static int sh_portchk_add_required (const char * str)
1434{
1435 return sh_portchk_add_required_generic (str, SH_PORT_REQ);
1436}
1437
1438/* User interface to add optional ports as 'iface:portlist'
1439 */
1440static int sh_portchk_add_optional (const char * str)
1441{
1442 return sh_portchk_add_required_generic (str, SH_PORT_OPT);
1443}
1444
[127]1445/* User interface to add ignoreable ports as 'iface:portlist'
1446 */
1447static int sh_portchk_add_ignore (const char * str)
1448{
1449 return sh_portchk_add_required_generic (str, SH_PORT_IGN);
1450}
1451
[149]1452/* User interface to add ports that should not be checked as 'iface:portlist'
1453 */
1454static int sh_portchk_add_blacklist (const char * str)
1455{
1456 return sh_portchk_add_required_generic (str, SH_PORT_BLACKLIST);
1457}
1458
[67]1459/* Interface to run port check
1460 */
1461int sh_portchk_check ()
1462{
[170]1463 volatile int min_port;
[67]1464
[149]1465 SH_MUTEX_LOCK(mutex_port_check);
[170]1466
1467 min_port = 0;
1468
[78]1469 if (sh_portchk_active != S_FALSE)
[67]1470 {
[78]1471 sh_portchk_reset_lists();
1472 if (0 != geteuid())
1473 {
1474 min_port = 1024;
[67]1475#ifdef TEST_ONLY
[78]1476 fprintf(stderr, "** WARNING not scanning ports < 1024\n");
[67]1477#else
[149]1478 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]1479 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1480 _("not scanning ports below 1024"), _("sh_portchk_check"));
[149]1481 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1482#endif
[78]1483 }
1484 if (sh_portchk_check_udp == 1)
1485 sh_portchk_scan_ports_udp(min_port, -1);
1486 sh_portchk_scan_ports_tcp(min_port, -1);
[149]1487 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_REPORT);
[78]1488 if (sh_portchk_check_udp == 1)
[149]1489 sh_portchk_check_list (&portlist_udp, IPPROTO_UDP, SH_PORT_REPORT);
[67]1490 }
[149]1491 SH_MUTEX_UNLOCK(mutex_port_check);
[67]1492 return 0;
1493}
1494#endif
1495
1496#ifdef SH_CUTEST
1497#include "CuTest.h"
1498
1499void Test_portcheck_lists (CuTest *tc)
1500{
[73]1501#if defined(SH_USE_PORTCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
[67]1502 struct in_addr haddr_local;
1503 struct sh_portentry * portent;
1504
1505 CuAssertTrue(tc, 0 != inet_aton("127.0.0.1", &haddr_local));
1506
[149]1507 sh_portchk_add_to_list (IPPROTO_TCP, 8000, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
[67]1508
[149]1509 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, NULL);
[67]1510 CuAssertPtrNotNull(tc, portent);
1511
1512 CuAssertTrue(tc, portent->port == 8000);
1513 CuAssertTrue(tc, 0 == strcmp("127.0.0.1", portent->interface));
1514 CuAssertTrue(tc, portent->status == SH_PORT_UNKN);
1515 CuAssertTrue(tc, portent->flag == SH_PORT_NOT);
1516
[149]1517 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]1518
1519 CuAssertTrue(tc, NULL == portlist_tcp);
1520
[149]1521 sh_portchk_add_to_list (IPPROTO_TCP, 8000, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
1522 sh_portchk_add_to_list (IPPROTO_TCP, 8001, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
1523 sh_portchk_add_to_list (IPPROTO_TCP, 8002, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
1524 sh_portchk_add_to_list (IPPROTO_TCP, 8003, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
1525 sh_portchk_add_to_list (IPPROTO_TCP, 8004, haddr_local, NULL, SH_PORT_IGN, SH_PORT_UNKN);
1526 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo1", SH_PORT_NOT, SH_PORT_UNKN);
1527 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo2", SH_PORT_REQ, SH_PORT_UNKN);
1528 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo3", SH_PORT_NOT, SH_PORT_UNKN);
1529 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo4", SH_PORT_REQ, SH_PORT_UNKN);
1530 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo5", SH_PORT_IGN, SH_PORT_UNKN);
[67]1531
[149]1532 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]1533
1534 CuAssertPtrNotNull(tc, portlist_tcp);
1535
[149]1536 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, NULL);
[67]1537 CuAssertPtrNotNull(tc, portent);
1538
[149]1539 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8001, haddr_local, NULL);
[67]1540 CuAssertTrue(tc, NULL == portent);
1541
[149]1542 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8002, haddr_local, NULL);
[67]1543 CuAssertPtrNotNull(tc, portent);
1544
[149]1545 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8003, haddr_local, NULL);
[67]1546 CuAssertTrue(tc, NULL == portent);
1547
[149]1548 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8004, haddr_local, NULL);
[127]1549 CuAssertPtrNotNull(tc, portent);
1550
[149]1551 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo1");
[67]1552 CuAssertTrue(tc, NULL == portent);
1553
[149]1554 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo2");
[67]1555 CuAssertPtrNotNull(tc, portent);
1556 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo2"));
1557
[149]1558 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo3");
[67]1559 CuAssertTrue(tc, NULL == portent);
1560
[149]1561 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo4");
[67]1562 CuAssertPtrNotNull(tc, portent);
1563 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo4"));
[127]1564
[149]1565 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo5");
[127]1566 CuAssertPtrNotNull(tc, portent);
1567 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo5"));
[149]1568
1569 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, haddr_local, IPPROTO_TCP));
1570 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, haddr_local, IPPROTO_TCP));
1571 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, haddr_local, IPPROTO_TCP));
1572 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, haddr_local, IPPROTO_TCP));
1573 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, haddr_local, IPPROTO_UDP));
1574 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, haddr_local, IPPROTO_UDP));
1575 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, haddr_local, IPPROTO_UDP));
1576 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, haddr_local, IPPROTO_UDP));
1577
1578 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, haddr_local, IPPROTO_UDP));
1579 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, haddr_local, IPPROTO_UDP));
1580 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, haddr_local, IPPROTO_UDP));
1581 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, haddr_local, IPPROTO_UDP));
1582
1583 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, haddr_local, IPPROTO_TCP));
1584 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, haddr_local, IPPROTO_TCP));
1585 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, haddr_local, IPPROTO_TCP));
1586 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, haddr_local, IPPROTO_TCP));
[67]1587#else
1588 (void) tc; /* fix compiler warning */
1589#endif
1590 return;
1591}
1592#endif
1593
1594#ifdef TEST_ONLY
1595
1596void usage (char * pname)
1597{
1598 printf ("%s [-r|--required interface:portlist][-o|--optional interface:portlist][--no-udp][-d|--debug] hostname\n\n", pname);
1599 printf (" Check local host for open ports; Version %s\n\n", PORTCHK_VERSION);
1600 printf (" Interface: Numeric address for an interface, e.g. 127.0.0.1\n");
1601 printf (" Portlist: List of ports or services, e.g. 22/tcp,nfs/udp,nlockmgr/udp\n");
1602 printf (" required -> must be open\n");
1603 printf (" optional -> may be open or closed\n");
1604 printf (" RPC services must be specified with service **name**, others with **port number**\n\n");
1605 printf (" Example:\n");
1606 printf (" %s --required 192.168.1.2:22/tcp,nfs/udp,nlockmgr/udp\n\n", pname);
1607 return;
1608}
1609
1610int main(int argc, char *argv[])
1611{
1612 char * pname = argv[0];
1613
1614
1615 /*
1616 test_lists();
1617
1618 portlist_tcp = sh_portchk_kill_list (portlist_tcp);
1619 portlist_udp = sh_portchk_kill_list (portlist_udp);
1620 */
1621
1622 // sh_portchk_add_required ("127.0.0.1 : nlockmgr/tcp, 5308/tcp, nfs/tcp");
1623
1624 while (argc > 1 && argv[1][0] == '-')
1625 {
1626 if (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))
1627 {
1628 usage(pname);
1629 exit (0);
1630 }
1631 else if (0 == strcmp(argv[1], "--required") || 0 == strcmp(argv[1], "-r"))
1632 {
1633 if (argc < 3)
1634 {
1635 usage(pname);
1636 exit (1);
1637 }
1638 sh_portchk_add_required (argv[2]);
1639 --argc; ++argv;
1640 }
1641 else if (0 == strcmp(argv[1], "--optional") || 0 == strcmp(argv[1], "-o"))
1642 {
1643 if (argc < 3)
1644 {
1645 usage(pname);
1646 exit (1);
1647 }
1648 sh_portchk_add_optional (argv[2]);
1649 --argc; ++argv;
1650 }
1651 else if (0 == strcmp(argv[1], "--no-udp"))
1652 {
1653 sh_portchk_check_udp = 0;
1654 }
1655 else if (0 == strcmp(argv[1], "--debug") || 0 == strcmp(argv[1], "-d"))
1656 {
1657 portchk_debug = 1;
1658 }
1659 else
1660 {
1661 usage(pname);
1662 exit (1);
1663 }
1664 --argc; ++argv;
1665 }
1666
1667 if (argc < 2)
1668 {
1669 usage(pname);
1670 exit (1);
1671 }
1672
1673 portchk_hostname = argv[1];
1674
1675 if (0 != sh_portchk_init ())
1676 {
1677 usage(pname);
1678 exit (1);
1679 }
1680
1681 sh_portchk_check();
1682
1683 return 0;
1684}
1685#endif
Note: See TracBrowser for help on using the repository browser.