source: trunk/src/sh_portcheck.c@ 285

Last change on this file since 285 was 257, checked in by katerina, 15 years ago

Fix for issues with debug code and testsuite (tickets #174, #175).

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