source: trunk/src/sh_portcheck.c@ 206

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

Fix for ticket #133 (improve port checking and its reporting to prelude).

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