source: trunk/src/sh_portcheck.c@ 126

Last change on this file since 126 was 109, checked in by rainer, 17 years ago

More graceful connection teardown in portcheck.

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