source: trunk/src/sh_portcheck.c@ 137

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

Fix compile errors.

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