source: trunk/src/sh_portcheck.c@ 513

Last change on this file since 513 was 511, checked in by katerina, 8 years ago

New option PortCheckDevice =... (ticket #404).

  • Property svn:executable set to *
File size: 60.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>
[511]35#include <stdlib.h>
[67]36#include <sys/types.h>
37#include <sys/socket.h>
38#include <netinet/in.h>
39#include <arpa/inet.h>
[511]40#ifdef HAVE_IFADDRS_H
41#include <ifaddrs.h>
42#include <netdb.h>
43#endif
[67]44#include <errno.h>
45#include <unistd.h>
[109]46#include <fcntl.h>
[67]47
[76]48#define PORTCHK_VERSION "1.0"
49
50#if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)))
51
52
[67]53#define PORTMAP
[290]54#ifdef HAVE_RPC_RPC_H
[67]55#include <rpc/rpc.h>
56#ifdef HAVE_RPC_RPCENT_H
57#include <rpc/rpcent.h>
58#endif
59#include <rpc/pmap_clnt.h>
60#include <rpc/pmap_prot.h>
[290]61#endif
[67]62#include <netdb.h>
63
64/*
65 * struct pmaplist {
66 * struct pmap pml_map;
67 * struct pmaplist *pml_next;
68 * };
69 */
70
71/* struct pmap {
72 * long unsigned pm_prog;
73 * long unsigned pm_vers;
74 * long unsigned pm_prot;
75 * long unsigned pm_port;
76 * };
77 */
78
79/* TIME_WAIT ? 60-240 seconds */
80
[295]81#if !defined(TEST_ONLY)
82
83#define FIL__ _("sh_portcheck.c")
84#include "samhain.h"
85#include "sh_error.h"
86#include "sh_mem.h"
87#include "sh_calls.h"
88#include "sh_utils.h"
89#include "sh_modules.h"
90#define SH_NEED_GETHOSTBYXXX
91#include "sh_static.h"
92#include "sh_pthread.h"
93#include "sh_ipvx.h"
94
[67]95/* the size of an interface string
96 */
[295]97#define SH_INTERFACE_SIZE SH_IP_BUF
[67]98
99#define SH_PORT_NOT 0
100#define SH_PORT_REQ 1
101#define SH_PORT_OPT 2
[127]102#define SH_PORT_IGN 3
[149]103#define SH_PORT_BLACKLIST 4
[67]104
[468]105static char * sh_port_type2str (int type)
106{
107 if (type == 0) return _("not");
108 if (type == 1) return _("req");
109 if (type == 2) return _("opt");
110 if (type == 3) return _("ign");
111 if (type == 4) return _("blc");
112 return _("???");
113}
114
[67]115#define SH_PORT_MISS 0
116#define SH_PORT_ISOK 1
117#define SH_PORT_UNKN 2
118
119#define SH_PORT_NOREPT 0
120#define SH_PORT_REPORT 1
121
[149]122#define SH_PROTO_TCP 0
123#define SH_PROTO_UDP 1
124#define SH_PROTO_STR(a) (((a) == IPPROTO_TCP) ? _("tcp") : _("udp"))
125
[67]126struct sh_portentry {
127 int port;
128 char interface[SH_INTERFACE_SIZE];
129 char * service;
130 char * error;
131 int flag; /* required or not */
132 int status; /* missing or not */
133 struct sh_portentry * next;
134};
135
136static struct sh_portentry * portlist_tcp = NULL;
137static struct sh_portentry * portlist_udp = NULL;
138
[149]139
[67]140#define SH_PORTCHK_INTERVAL 300
141
142static int sh_portchk_check_udp = 1;
143static int sh_portchk_active = 1;
144static int sh_portchk_interval = SH_PORTCHK_INTERVAL;
145
[328]146static int sh_portchk_minport = -1;
147static int sh_portchk_maxport = -1;
148
[295]149struct sh_port {
150 int port;
151 struct sh_sockaddr * paddr;
152 struct sh_port * next;
153};
[67]154
[295]155static struct sh_port * blacklist_tcp = NULL;
156static struct sh_port * blacklist_udp = NULL;
157
[149]158SH_MUTEX_STATIC(mutex_port_check, PTHREAD_MUTEX_INITIALIZER);
159
[67]160static int sh_portchk_severity = SH_ERR_SEVERE;
[180]161
[295]162extern char * sh_port2proc_query(int proto, struct sh_sockaddr * saddr, int sport,
[206]163 unsigned long * pid, char * user, size_t userlen);
[180]164extern int sh_port2proc_prepare();
[235]165extern void sh_port2proc_finish();
[180]166
[67]167#endif
168
[127]169/* Exported interface to add ignoreable ports as 'iface:portlist'
170 */
171static int sh_portchk_add_ignore (const char * str);
172
[67]173/* Exported interface to add required ports as 'iface:portlist'
174 */
175static int sh_portchk_add_required (const char * str);
176
177/* Exported interface to add optional ports as 'iface:portlist'
178 */
179static int sh_portchk_add_optional (const char * str);
180
[149]181/* Exported interface to add blacklisted ports as 'iface:portlist'
182 */
183static int sh_portchk_add_blacklist (const char * str);
184
[67]185/* Exported interface to add an ethernet interface
186 */
187static int sh_portchk_add_interface (const char * str);
188
[511]189#if defined(HAVE_IFADDRS_H)
190/* Exported interface to add an ethernet device
191 */
192static int sh_portchk_add_device (const char * str);
193#endif
194
[149]195/* verify whether port/interface is blacklisted (do not check)
196 */
[295]197static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * haddr, int proto);
[67]198
199#ifndef TEST_ONLY
200
201static int sh_portchk_set_interval (const char * c)
202{
203 int retval = 0;
204 long val;
205
206 SL_ENTER(_("sh_portchk_set_interval"));
207 val = strtol (c, (char **)NULL, 10);
208 if (val <= 0)
209 {
[149]210 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]211 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
212 _("port check interval"), c);
[149]213 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]214 retval = -1;
215 }
[362]216 else
217 {
218 sh_portchk_interval = (time_t) val;
219 }
220 SL_RETURN(retval, _("sh_portchk_set_interval"));
[67]221}
222
[328]223static int sh_portchk_set_port_minmax (const char * c, int * setthis)
224{
225 int retval = 0;
226 long val;
[67]227
[328]228 SL_ENTER(_("sh_portchk_set_port_minmax"));
229 val = strtol (c, (char **)NULL, 10);
230 if (val < 0 || val > 65535)
231 {
232 SH_MUTEX_LOCK(mutex_thread_nolog);
233 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
234 _("port check port minmax"), c);
235 SH_MUTEX_UNLOCK(mutex_thread_nolog);
236 retval = -1;
237 }
[362]238 else
239 {
240 *setthis = (int) val;
241 }
242 SL_RETURN(retval, _("sh_portchk_set_port_minmax"));
[328]243}
244
245
246static int sh_portchk_set_minport (const char * str)
247{
248 return sh_portchk_set_port_minmax (str, &sh_portchk_minport);
249}
250
251static int sh_portchk_set_maxport (const char * str)
252{
253 return sh_portchk_set_port_minmax (str, &sh_portchk_maxport);
254}
255
[67]256static int sh_portchk_set_active (const char * str)
257{
258 return sh_util_flagval(str, &sh_portchk_active);
259}
260
261static int sh_portchk_set_udp (const char * str)
262{
263 return sh_util_flagval(str, &sh_portchk_check_udp);
264}
265
266static int sh_portchk_set_severity (const char * str)
267{
268 char tmp[32];
269 tmp[0] = '='; tmp[1] = '\0';
270 sl_strlcat (tmp, str, 32);
271 return sh_error_set_level (tmp, &sh_portchk_severity);
272}
273
274sh_rconf sh_portchk_table[] = {
275 {
276 N_("severityportcheck"),
277 sh_portchk_set_severity,
278 },
279 {
280 N_("portcheckrequired"),
281 sh_portchk_add_required,
282 },
283 {
284 N_("portcheckoptional"),
285 sh_portchk_add_optional,
286 },
287 {
[127]288 N_("portcheckignore"),
289 sh_portchk_add_ignore,
290 },
291 {
[149]292 N_("portcheckskip"),
293 sh_portchk_add_blacklist,
294 },
295 {
[67]296 N_("portcheckactive"),
297 sh_portchk_set_active,
298 },
[511]299#if defined(HAVE_IFADDRS_H)
[67]300 {
[511]301 N_("portcheckdevice"),
302 sh_portchk_add_device,
303 },
304#endif
305 {
[67]306 N_("portcheckinterface"),
307 sh_portchk_add_interface,
308 },
309 {
310 N_("portcheckinterval"),
311 sh_portchk_set_interval,
312 },
313 {
[328]314 N_("portcheckminport"),
315 sh_portchk_set_minport,
316 },
317 {
318 N_("portcheckmaxport"),
319 sh_portchk_set_maxport,
320 },
321 {
[67]322 N_("portcheckudp"),
323 sh_portchk_set_udp,
324 },
325 {
326 NULL,
327 NULL
328 }
329};
330
331#endif
332
333/* Interface to initialize port check
334 */
[170]335int sh_portchk_init (struct mod_type * arg);
[67]336
337/* Interface to reset port check
338 */
[170]339int sh_portchk_reset (void);
[67]340
341/* Interface to run port check
342 */
[170]343int sh_portchk_check (void);
[67]344
345
[149]346static char * check_services (int port, int proto);
[67]347
348#ifdef TEST_ONLY
349
[380]350static int portchk_debug = 0;
[67]351#define SH_ALLOC malloc
352#define SH_FREE free
353#define sh_util_strdup strdup
354#define sl_strlcpy strncpy
355#define _(a) a
356
357#else
358
359static int portchk_debug = 0;
360
361#endif
362
[290]363#ifdef HAVE_RPC_RPC_H
[218]364static char * sh_getrpcbynumber (int number, char * buf, size_t len)
365{
366 FILE * fp;
367
368 if (NULL != (fp = fopen(_("/etc/rpc"), "r")))
369 {
370 sh_string * s = sh_string_new(0);
371 while (0 < sh_string_read(s, fp, 1024))
372 {
373 char * p = sh_string_str(s);
374 while (*p && (*p == ' ' || *p == '\t')) ++p; /* skip whitespace */
375 if (*p == '\0' || *p == '#')
376 continue; /* skip comment */
377 else
378 {
379 size_t lengths[3];
380 unsigned int fields = 3;
381 char * q = sh_string_str(s);
382 char ** splits = split_array_ws(q, &fields, lengths);
383
384 if (fields >= 2)
385 {
386 int n = atoi(splits[1]);
387 if (n == number)
388 {
389 sl_strlcpy(buf, splits[0], len);
390 SH_FREE(splits);
391 sh_string_destroy(&s);
[252]392 sl_fclose(FIL__, __LINE__, fp);
[218]393 return buf;
394 }
395 }
396 SH_FREE(splits);
397 }
398 }
399 sh_string_destroy(&s);
[252]400 sl_fclose(FIL__, __LINE__, fp);
[218]401 }
402 return NULL;
403}
[290]404#endif
[218]405
406static char * sh_getservbyport (int port, const char * proto_in, char * buf, size_t len)
407{
408 FILE * fp;
409 char proto[8];
410
411 sl_strlcpy(proto, proto_in, sizeof(proto));
412
413 if (NULL != (fp = fopen(_("/etc/services"), "r")))
414 {
415 sh_string * s = sh_string_new(0);
416 while (0 < sh_string_read(s, fp, 1024))
417 {
418 char * p = sh_string_str(s);
419 while (*p && (*p == ' ' || *p == '\t')) ++p; /* skip whitespace */
420 if (*p == '\0' || *p == '#')
421 continue; /* skip comment */
422 else
423 {
424 size_t lengths[3];
425 unsigned int fields = 3;
426 char * q = sh_string_str(s);
427 char ** splits = split_array_ws(q, &fields, lengths);
428
429 if (fields >= 2)
430 {
431 char * end;
432 long n = strtol(splits[1], &end, 10);
433 if (n == port && end && (*end == '/' || *end == ','))
434 {
435 ++end;
436 if (0 == strcmp(end, proto))
437 {
438 sl_strlcpy(buf, splits[0], len);
439 SH_FREE(splits);
440 sh_string_destroy(&s);
[252]441 sl_fclose(FIL__, __LINE__, fp);
[218]442 return buf;
443 }
444 }
445 }
446 SH_FREE(splits);
447 }
448 }
449 sh_string_destroy(&s);
[252]450 sl_fclose(FIL__, __LINE__, fp);
[218]451 }
452 return NULL;
453}
454
[149]455static void sh_portchk_add_to_list (int proto,
[295]456 int port, struct sh_sockaddr * paddr,
[218]457 char * service,
[67]458 int flag, int status)
459{
460 struct sh_portentry * new = SH_ALLOC (sizeof(struct sh_portentry));
461
462 new->port = port;
[295]463 sh_ipvx_ntoa(new->interface, SH_INTERFACE_SIZE, paddr);
[67]464 new->status = status;
465 new->flag = flag;
466
467 new->error = NULL;
468
[380]469 if (portchk_debug)
470 fprintf(stderr, _("add to list: port %d/%s %d %d (%s) %s\n"),
471 port, SH_PROTO_STR(proto), flag, status, service ? service : _("undef"),
472 new->interface);
473
[67]474 if (service)
475 new->service = sh_util_strdup (service);
476 else
477 new->service = NULL;
[149]478 if (proto == IPPROTO_TCP)
[67]479 {
480 new->next = portlist_tcp;
481 portlist_tcp = new;
482 }
483 else
484 {
485 new->next = portlist_udp;
486 portlist_udp = new;
487 }
488 return;
489}
490
491/* Reset the list by setting all entries to UNKN.
492 * In the next cycle we will check, and set found ports to ISOK.
493 * Thereafter, we check for entries that are still UNKN.
494 */
[170]495static void sh_portchk_reset_lists (void)
[67]496{
497 struct sh_portentry * portlist;
498
499 portlist = portlist_tcp;
500 while (portlist)
501 {
502 if (portlist->status != SH_PORT_MISS)
503 portlist->status = SH_PORT_UNKN;
504 portlist = portlist->next;
505 }
506 portlist = portlist_udp;
507 while (portlist)
508 {
509 if (portlist->status != SH_PORT_MISS)
510 portlist->status = SH_PORT_UNKN;
511 portlist = portlist->next;
512 }
513 return;
514}
515
516static struct sh_portentry * sh_portchk_kill_list (struct sh_portentry * head)
517{
518 if (head)
519 {
520 if (head->next)
521 sh_portchk_kill_list (head->next);
522
523 if (head->service)
524 SH_FREE(head->service);
525 SH_FREE(head);
526 }
527 return NULL;
528}
529
[149]530static struct sh_port * sh_portchk_kill_blacklist (struct sh_port * head)
531{
532 if (head)
533 {
534 if (head->next)
535 sh_portchk_kill_blacklist (head->next);
536
[295]537 SH_FREE(head->paddr);
[149]538 SH_FREE(head);
539 }
540 return NULL;
541}
542
[170]543/* These variables are not used anywhere. They only exist
544 * to assign &pre, &ptr to them, which keeps gcc from
545 * putting it into a register, and avoids the 'clobbered
546 * by longjmp' warning. And no, 'volatile' proved insufficient.
547 */
[481]548void * sh_dummy_531_pre = NULL;
549void * sh_dummy_532_ptr = NULL;
[170]550
[67]551/* check the list of open ports for any that are marked as UNKN
552 */
[481]553static void sh_portchk_check_list (struct sh_portentry ** head,
554 int proto, int report)
[67]555{
556 struct sh_portentry * ptr = *head;
557 struct sh_portentry * pre = *head;
558 char errbuf[256];
559
[170]560 /* Take the address to keep gcc from putting them into registers.
561 * Avoids the 'clobbered by longjmp' warning.
562 */
[481]563 sh_dummy_531_pre = (void*) &pre;
564 sh_dummy_532_ptr = (void*) &ptr;
[170]565
[67]566 while (ptr)
567 {
568 if (portchk_debug && report)
569 fprintf(stderr, _("check list: port %d/%s %d %d\n"),
[149]570 ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
[67]571
572 if (ptr->status == SH_PORT_UNKN)
573 {
574 /* Don't report missing ports that are marked as optional
575 */
[127]576 if (ptr->flag != SH_PORT_OPT && ptr->flag != SH_PORT_IGN)
[67]577 {
[169]578 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[149]579 ptr->interface, ptr->port, SH_PROTO_STR(proto),
[67]580 ptr->service ? ptr->service : check_services(ptr->port, proto));
581#ifdef TEST_ONLY
582 if (report == SH_PORT_REPORT)
583 fprintf(stderr, _("%s\n"), errbuf);
584#else
585 if (report == SH_PORT_REPORT)
[149]586 {
587 SH_MUTEX_LOCK(mutex_thread_nolog);
588 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[169]589 MSG_PORT_MISS, errbuf);
[149]590 SH_MUTEX_UNLOCK(mutex_thread_nolog);
591 }
[67]592#endif
593 }
594
595 ptr->status = SH_PORT_MISS;
596
[128]597 if ((ptr->flag != SH_PORT_REQ) && (ptr->flag != SH_PORT_OPT) && (ptr->flag != SH_PORT_IGN))
[67]598 {
599 if (portchk_debug && report)
600 fprintf(stderr, _("removing: port %d/%s %d %d\n"),
[149]601 ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
[67]602
603 if (ptr == *head)
604 {
605 *head = ptr->next;
606 if (ptr->service)
607 SH_FREE(ptr->service);
608 SH_FREE(ptr);
609 ptr = *head;
610 pre = *head;
611 continue;
612 }
613 else if (ptr->next == NULL)
614 {
615 pre->next = NULL;
616 if (ptr->service)
617 SH_FREE(ptr->service);
618 SH_FREE(ptr);
619 return;
620 }
621 else
622 {
623 pre->next = ptr->next;
624 if (ptr->service)
625 SH_FREE(ptr->service);
626 SH_FREE(ptr);
627 ptr = pre->next;
628 continue;
629 }
630 }
631 }
632 pre = ptr;
633 ptr = ptr->next;
634 }
[383]635
[481]636 sh_dummy_532_ptr = NULL;
637 sh_dummy_531_pre = NULL;
[383]638
[67]639 return;
640}
641
642
[149]643static struct sh_portentry * sh_portchk_get_from_list (int proto, int port,
[295]644 struct sh_sockaddr * paddr, char * service)
[67]645{
646 struct sh_portentry * portlist;
[295]647 char str_addr[SH_IP_BUF];
[75]648
[149]649 if (proto == IPPROTO_TCP)
[67]650 portlist = portlist_tcp;
651 else
652 portlist = portlist_udp;
653
[295]654 sh_ipvx_ntoa(str_addr, sizeof(str_addr), paddr);
655
[67]656 if (service)
657 {
658 while (portlist)
659 {
660 if (portlist->service &&
661 0 == strcmp(service, portlist->service) &&
[295]662 ( 0 == strcmp(portlist->interface, str_addr) ||
663 sh_ipvx_isany(paddr) ))
[67]664 return portlist;
665 portlist = portlist->next;
666 }
667 }
668 else
669 {
670 while (portlist)
671 {
672 if (port == portlist->port &&
[295]673 (0 == strcmp(portlist->interface, str_addr) ||
674 sh_ipvx_isany(paddr) ))
[67]675 return portlist;
676 portlist = portlist->next;
677 }
678 }
679 return NULL;
680}
681
682
[380]683static void sh_portchk_cmp_to_list (int proto, int port,
684 struct sh_sockaddr * paddr, char * service)
[67]685{
686 struct sh_portentry * portent;
687 char errbuf[256];
688
689
[295]690 portent = sh_portchk_get_from_list (proto, port, paddr, service);
[67]691
692 if (service)
693 {
694 if (!portent)
695 {
[180]696 char * path;
[206]697 unsigned long qpid;
[180]698 char user[USER_MAX];
[295]699 char saddr[SH_IP_BUF];
[180]700
[295]701 sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
702
[169]703 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[295]704 saddr, port, SH_PROTO_STR(proto), service);
[380]705
706 if (portchk_debug)
707 fprintf(stderr, _("cmp_to_list: open port: %s:%d/%s (%s)\n"),
708 saddr, port, SH_PROTO_STR(proto), service);
709
710#ifndef TEST_ONLY
[295]711 path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
[149]712 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]713 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[206]714 MSG_PORT_NEW, errbuf, path, qpid, user);
[149]715 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[180]716 SH_FREE(path);
[67]717#endif
718 /*
719 * was not there, thus it is not in 'required' or 'optional' list
720 */
[295]721 sh_portchk_add_to_list (proto, port, paddr, service, SH_PORT_NOT, SH_PORT_ISOK);
[67]722 }
[127]723 else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
[67]724 {
[180]725 char * path;
[206]726 unsigned long qpid;
[180]727 char user[USER_MAX];
[295]728 char saddr[SH_IP_BUF];
[180]729
[295]730 sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
731
[169]732 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
[295]733 saddr, port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
[67]734#ifdef TEST_ONLY
735 fprintf(stderr, _("service: %s\n"), errbuf);
736#else
[295]737 path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
[149]738 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]739 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[206]740 MSG_PORT_RESTART, errbuf, path, qpid, user);
[149]741 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[180]742 SH_FREE(path);
[67]743#endif
744
745 portent->status = SH_PORT_ISOK;
746 }
747 else if (port != portent->port && (-1) != portent->port)
748 {
[180]749 char * path;
[206]750 unsigned long qpid;
[180]751 char user[USER_MAX];
[295]752 char saddr[SH_IP_BUF];
[180]753
[295]754 sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
755
[169]756 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
[295]757 saddr, port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
[67]758#ifdef TEST_ONLY
759 fprintf(stderr, _("service: %s\n"), errbuf);
760#else
[295]761 path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
[149]762 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]763 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[206]764 MSG_PORT_NEWPORT, errbuf, path, qpid, user);
[149]765 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[180]766 SH_FREE(path);
[67]767#endif
[127]768 portent->port = port;
[67]769 portent->status = SH_PORT_ISOK;
770 }
771 else
772 {
773 portent->status = SH_PORT_ISOK;
774 }
775 }
776 else
777 {
778 if (!portent)
779 {
[180]780 char * path;
[206]781 unsigned long qpid;
[180]782 char user[USER_MAX];
[295]783 char saddr[SH_IP_BUF];
[180]784
[468]785 if (portchk_debug)
786 fprintf(stderr, _("call to sh_ipvx_ntoa (port %d)\n"), port);
787
[295]788 sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
789
[169]790 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[295]791 saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
[380]792
793 if (portchk_debug)
794 fprintf(stderr, _("cmp_to_list: open port: %s:%d/%s (%s) check_services\n"),
795 saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
796
797#ifndef TEST_ONLY
[295]798 path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
[149]799 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]800 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[206]801 MSG_PORT_NEW, errbuf, path, qpid, user);
[149]802 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[180]803 SH_FREE(path);
[67]804#endif
805
806 /* was not there, thus it is not in 'required' or 'optional' list
807 */
[295]808 sh_portchk_add_to_list (proto, port, paddr, service, SH_PORT_NOT, SH_PORT_ISOK);
[67]809 }
[127]810 else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
[67]811 {
[180]812 char * path;
[206]813 unsigned long qpid;
[180]814 char user[USER_MAX];
[295]815 char saddr[SH_IP_BUF];
[180]816
[295]817 sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
818
[169]819 snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
[295]820 saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
[67]821#ifdef TEST_ONLY
822 fprintf(stderr, _("port : %s\n"), errbuf);
823#else
[295]824 path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
[149]825 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]826 sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
[206]827 MSG_PORT_RESTART, errbuf, path, qpid, user);
[149]828 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[180]829 SH_FREE(path);
[67]830#endif
831
832 portent->status = SH_PORT_ISOK;
833 }
834 else
835 {
836 portent->status = SH_PORT_ISOK;
837 }
838 }
839
840 return;
841}
842
843
844/* Returns a static buffer containing the name of the service
845 * running on port <port> (from /etc/services)
846 * Returns NULL on failure
847 */
[149]848static char * check_services (int port, int proto)
[67]849{
850 static char buf[256];
[218]851 char * service = sh_getservbyport(port, SH_PROTO_STR(proto), buf, sizeof(buf));
[67]852
[218]853 if (!service)
[67]854 {
[210]855 snprintf (buf, sizeof(buf), "%s",_("unknown"));
[67]856 }
857 return buf;
858}
859
860/* Returns a static buffer containing the name of the service
861 * running on port <port> at <address> (from portmap daemon)
862 * Returns NULL on failure
863 */
864static char * check_rpc_list (int port, struct sockaddr_in * address,
865 unsigned long prot)
866{
[439]867#if defined(HAVE_RPC_RPC_H) && defined(HAVE_PMAP_GETMAPS)
[67]868 struct pmaplist * head;
[218]869 char *r;
[67]870 static char buf[256];
871
872 head = pmap_getmaps(address);
873
874 if (head)
875 {
876 do /* while (head != NULL) */
877 {
878 if ((head->pml_map.pm_prot == prot) &&
879 (port == (int)head->pml_map.pm_port))
880 {
[218]881 r = sh_getrpcbynumber((int)head->pml_map.pm_prog,
882 buf, sizeof(buf));
883 if (r)
[67]884 {
885 return buf;
886 }
887 else
888 {
889 snprintf (buf, sizeof(buf), "RPC_%lu",
890 (unsigned long)head->pml_map.pm_prog);
891 return buf;
892 }
893 }
894 head = head->pml_next;
895 }
896 while (head != NULL);
897 }
[290]898#else
899 (void) port;
900 (void) address;
901 (void) prot;
902#endif
[67]903 return NULL;
904}
905
[295]906static int check_port_udp_internal (int fd, int port, struct sh_sockaddr * paddr)
[67]907{
908 int retval;
[295]909 char * p = NULL;
[67]910 char buf[8];
[78]911#ifndef TEST_ONLY
912 char errmsg[256];
913 int nerr;
914#endif
[132]915 char errbuf[SH_ERRBUF_SIZE];
[295]916 char ipbuf[SH_IP_BUF];
[67]917
[295]918 sh_ipvx_set_port(paddr, port);
[67]919
[78]920 do {
[295]921 retval = connect(fd, sh_ipvx_sockaddr_cast(paddr), SH_SSP_LEN(paddr));
[171]922 } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
[78]923
[67]924 if (retval == -1)
925 {
926#ifdef TEST_ONLY
927 if (portchk_debug)
928 perror(_("connect"));
929#else
[295]930 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
931
[78]932 nerr = errno;
933 sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/udp on %15s: %s"),
[295]934 port, ipbuf, sh_error_message(errno, errbuf, sizeof(errbuf)));
[149]935 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]936 sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
937 errmsg, _("connect"));
[149]938 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]939#endif
940 }
941 else
942 {
[78]943 do {
944 retval = send (fd, buf, 0, 0);
945 } while (retval < 0 && errno == EINTR);
[67]946
947 if (retval == -1 && errno == ECONNREFUSED)
948 {
[295]949 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[67]950 if (portchk_debug)
[380]951 fprintf(stderr, _("check port_udp: %5d/udp on %15s established/time_wait\n"),
[295]952 port, ipbuf);
[67]953 }
954 else
955 {
[78]956 /* Only the second send() may catch the error
957 */
958 do {
959 retval = send (fd, buf, 0, 0);
960 } while (retval < 0 && errno == EINTR);
961
[67]962 if (retval == -1 && errno == ECONNREFUSED)
963 {
[295]964 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[67]965 if (portchk_debug)
966 fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
[295]967 port, ipbuf);
[67]968 }
969 else if (retval != -1)
970 {
971 /* Try to get service name from portmap
972 */
[295]973 if (paddr->ss_family == AF_INET)
974 {
[380]975 p = check_rpc_list (port,
976 (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr),
977 IPPROTO_UDP);
[295]978 }
[380]979
[295]980 sh_portchk_cmp_to_list (IPPROTO_UDP, port, paddr, p ? p : NULL);
[67]981
982 /* If not an RPC service, try to get name from /etc/services
983 */
984 if (!p)
[149]985 p = check_services(port, IPPROTO_UDP);
[67]986
987 if (portchk_debug)
[295]988 {
989 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[380]990 fprintf(stderr, _("check port_udp: %5d/udp on %15s open %s\n"),
[295]991 port, ipbuf, p);
992 }
[67]993
994 }
[498]995 else
996 {
997 if (portchk_debug)
998 {
999 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
1000 fprintf(stderr, _("check port_udp: %5d/udp on %15s ERRNO %d\n"),
1001 port, ipbuf, errno);
1002 }
1003 }
[67]1004 }
1005 }
[252]1006 sl_close_fd (FIL__, __LINE__, fd);
[67]1007 return 0;
1008}
1009
[295]1010static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr)
[67]1011{
1012 int retval;
[109]1013 int flags;
[295]1014 char * p = NULL;
[78]1015#ifndef TEST_ONLY
1016 char errmsg[256];
1017 int nerr;
1018#endif
[132]1019 char errbuf[SH_ERRBUF_SIZE];
[295]1020 char ipbuf[SH_IP_BUF];
[67]1021
[295]1022 sh_ipvx_set_port(paddr, port);
[67]1023
[78]1024 do {
[295]1025 retval = connect(fd, sh_ipvx_sockaddr_cast(paddr), SH_SSP_LEN(paddr));
[171]1026 } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
[78]1027
[67]1028 if (retval == -1 && errno == ECONNREFUSED)
1029 {
1030 if (portchk_debug)
[295]1031 {
1032 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[468]1033 fprintf(stderr, _("check port_tcp: %5d on %15s closed\n"),
[295]1034 port, ipbuf);
1035 }
[67]1036 }
1037 else if (retval == -1)
1038 {
1039#ifdef TEST_ONLY
1040 if (portchk_debug)
1041 perror(_("connect"));
1042#else
[295]1043 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[78]1044 nerr = errno;
1045 sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/tcp on %15s: %s"),
[295]1046 port, ipbuf, sh_error_message(errno, errbuf, sizeof(errbuf)));
[149]1047 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]1048 sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
1049 errmsg, _("connect"));
[149]1050 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1051#endif
1052 }
1053 else
1054 {
1055 /* Try to get service name from portmap
1056 */
[295]1057 if (paddr->ss_family == AF_INET)
1058 {
[380]1059 p = check_rpc_list (port,
1060 (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr),
1061 IPPROTO_TCP);
[295]1062 }
[67]1063
[295]1064 sh_portchk_cmp_to_list (IPPROTO_TCP, port, paddr, p ? p : NULL);
[67]1065
1066 /* If not an RPC service, try to get name from /etc/services
1067 */
1068 if (!p)
[149]1069 p = check_services(port, IPPROTO_TCP);
[67]1070
1071 if (portchk_debug)
[295]1072 {
1073 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
[380]1074 fprintf(stderr, _("check port_tcp: %5d on %15s open %s\n"),
[295]1075 port, ipbuf, p);
1076 }
[109]1077
1078#if !defined(O_NONBLOCK)
1079#if defined(O_NDELAY)
1080#define O_NONBLOCK O_NDELAY
1081#else
1082#define O_NONBLOCK 0
1083#endif
1084#endif
1085
1086 /* prepare to close connection gracefully
1087 */
1088 if (port == 22) /* ssh */
1089 {
1090 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1091 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]1092 retval = write (fd, _("SSH-2.0-Foobar"), 14);
1093 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]1094 }
1095 else if (port == 25) /* smtp */
1096 {
1097 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1098 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]1099 retval = write (fd, _("QUIT"), 4);
1100 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]1101 }
1102 else if (port == 79) /* finger */
1103 {
1104 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1105 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]1106 retval = write (fd, "\r\n", 2);
[109]1107 }
1108 else if (port == 110) /* pop3 */
1109 {
1110 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1111 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]1112 retval = write (fd, _("QUIT"), 4);
1113 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]1114 }
1115 else if (port == 143) /* imap */
1116 {
1117 flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1118 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
[170]1119 retval = write (fd, _("A01 LOGOUT"), 10);
1120 if (retval > 0) retval = write (fd, "\r\n", 2);
[109]1121 }
[170]1122
1123 if (portchk_debug && retval < 0)
1124 fprintf(stderr, _("check port: error writing to port %5d\n"),
1125 port);
[67]1126 }
[252]1127 sl_close_fd (FIL__, __LINE__, fd);
[67]1128 return 0;
1129}
1130
1131/* typedef uint32_t in_addr_t;
1132 * struct in_addr
1133 * {
1134 * in_addr_t s_addr;
1135 * };
1136 */
1137
[511]1138#define SH_IFACE_MAX 64
1139#define SH_IFACE_ADDR 0
1140#define SH_IFACE_DEV 1
[67]1141
1142struct portchk_interfaces {
[511]1143 struct sh_sockaddr iface;
1144 int type;
[67]1145};
1146
[511]1147static struct portchk_interfaces iface_list[SH_IFACE_MAX];
1148static int iface_list_used = 0;
[67]1149static int iface_initialized = 0;
1150
1151#ifdef TEST_ONLY
1152static char * portchk_hostname = NULL;
1153#else
1154static char * portchk_hostname = sh.host.name;
1155#endif
1156
[149]1157static int sh_portchk_init_internal (void)
[67]1158{
[468]1159 volatile int i, j; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
[67]1160 char errbuf[256];
[295]1161#if defined(USE_IPVX)
1162 struct addrinfo hints;
1163 struct addrinfo *res;
1164#else
1165 struct hostent * hent;
1166#endif
1167 char ipbuf[SH_IP_BUF];
[67]1168
1169 if (portchk_debug)
1170 fprintf(stderr, _("checking ports on: %s\n"), portchk_hostname ? portchk_hostname : _("NULL"));
[78]1171
[67]1172 if (!portchk_hostname)
1173 return -1;
1174
[78]1175 if (sh_portchk_active == S_FALSE)
1176 return -1;
1177
[149]1178 SH_MUTEX_LOCK(mutex_port_check);
[67]1179 if (iface_initialized == 0)
1180 {
[511]1181 iface_list_used = 0;
[67]1182 iface_initialized = 1;
1183 }
[295]1184
1185#if !defined(USE_IPVX)
[134]1186 SH_MUTEX_LOCK(mutex_resolv);
[162]1187 hent = sh_gethostbyname(portchk_hostname);
[170]1188 i = 0;
[511]1189 while (hent && hent->h_addr_list[i] && (iface_list_used < SH_IFACE_MAX))
[67]1190 {
[295]1191 struct sockaddr_in sin;
[468]1192 struct sh_sockaddr iface_tmp;
[295]1193
1194 memcpy(&(sin.sin_addr.s_addr), hent->h_addr_list[i], sizeof(in_addr_t));
[468]1195 sh_ipvx_save(&iface_tmp, AF_INET, (struct sockaddr *)&sin);
1196
[511]1197 for (j = 0; j < iface_list_used; ++j)
[468]1198 {
[511]1199 if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface)))
[468]1200 {
1201 goto next_iface;
1202 }
1203 }
1204
[511]1205 sh_ipvx_save(&(iface_list[iface_list_used].iface),
[295]1206 AF_INET, (struct sockaddr *)&sin);
[511]1207 iface_list[iface_list_used].type = SH_IFACE_ADDR;
[380]1208
1209 if (portchk_debug)
1210 {
1211 char buf[256];
[511]1212 sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface));
[468]1213 fprintf(stderr, _("added interface[%d]: %s\n"), i, buf);
[380]1214 }
[511]1215 ++iface_list_used;
[468]1216
1217 next_iface:
[134]1218 ++i;
1219 }
1220 SH_MUTEX_UNLOCK(mutex_resolv);
[295]1221#else
1222 memset(&hints, '\0', sizeof(hints));
1223 hints.ai_family = PF_UNSPEC;
1224 hints.ai_flags = AI_ADDRCONFIG;
[134]1225
[295]1226 if (0 == getaddrinfo(portchk_hostname, NULL, &hints, &res))
1227 {
1228 struct addrinfo *p = res;
[468]1229 struct sh_sockaddr iface_tmp;
[295]1230
[511]1231 while ((p != NULL) && (iface_list_used < SH_IFACE_MAX))
[295]1232 {
[468]1233 sh_ipvx_save(&iface_tmp, p->ai_family, p->ai_addr);
1234
[511]1235 for (j = 0; j < iface_list_used; ++j)
[468]1236 {
1237 if (portchk_debug)
1238 {
1239 char buf1[256], buf2[256];
[511]1240 sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list[j].iface));
[468]1241 sh_ipvx_ntoa(buf2, sizeof(buf2), &iface_tmp);
1242 fprintf(stderr, _("check interface[%d]: %s vs %s\n"), j, buf1, buf2);
1243 }
[511]1244 if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface)))
[468]1245 {
1246 if (portchk_debug)
1247 fprintf(stderr, _("skipping interface[%d]\n"), j);
1248 goto next_iface;
1249 }
1250 }
[511]1251 sh_ipvx_save(&(iface_list[iface_list_used].iface),
[295]1252 p->ai_family, p->ai_addr);
[511]1253 iface_list[iface_list_used].type = SH_IFACE_ADDR;
[468]1254 if (portchk_debug)
1255 {
1256 char buf[256];
[511]1257 sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface));
1258 fprintf(stderr, _("added interface[%d]: %s\n"), iface_list_used, buf);
[468]1259 }
1260
[511]1261 ++iface_list_used;
[468]1262
1263 next_iface:
[295]1264 p = p->ai_next;
1265 }
1266 freeaddrinfo(res);
1267 }
1268#endif
1269
[511]1270 for (i = 0; i < iface_list_used; ++i)
[134]1271 {
[511]1272 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list[i].iface));
[468]1273 sl_snprintf(errbuf, sizeof(errbuf), _("added interface: %s"), ipbuf);
[295]1274
[149]1275 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1276 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1277 errbuf, _("sh_portchk_init"));
[149]1278 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1279 }
[149]1280 SH_MUTEX_UNLOCK(mutex_port_check);
[67]1281
1282 return 0;
1283}
1284
[149]1285int sh_portchk_init (struct mod_type * arg)
1286{
[210]1287#ifndef HAVE_PTHREAD
1288 (void) arg;
1289#endif
1290
[149]1291 if (sh_portchk_active == S_FALSE)
1292 return SH_MOD_FAILED;
1293 if (!portchk_hostname)
1294 return SH_MOD_FAILED;
1295
1296#ifdef HAVE_PTHREAD
1297 if (arg != NULL && arg->initval < 0 &&
1298 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1299 {
1300 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
1301 return SH_MOD_THREAD;
1302 else
1303 return SH_MOD_FAILED;
1304 }
[335]1305 else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
1306 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1307 {
[511]1308 (void) sh_portchk_init_internal();
[335]1309 return SH_MOD_THREAD;
1310 }
[149]1311#endif
1312 return sh_portchk_init_internal();
1313}
1314
[511]1315static void dev_list_kill();
[149]1316
[67]1317#if !defined(TEST_ONLY)
[170]1318int sh_portchk_reconf (void)
[67]1319{
[149]1320 SH_MUTEX_LOCK(mutex_port_check);
[78]1321 iface_initialized = 0;
1322 sh_portchk_active = 1;
[80]1323 sh_portchk_check_udp = 1;
[149]1324 sh_portchk_interval = SH_PORTCHK_INTERVAL;
[78]1325
[328]1326 sh_portchk_minport = -1;
1327 sh_portchk_maxport = -1;
1328
[511]1329 dev_list_kill();
1330
[67]1331 portlist_udp = sh_portchk_kill_list (portlist_udp);
1332 portlist_tcp = sh_portchk_kill_list (portlist_tcp);
[149]1333
1334 blacklist_udp = sh_portchk_kill_blacklist (blacklist_udp);
1335 blacklist_tcp = sh_portchk_kill_blacklist (blacklist_tcp);
[235]1336 sh_port2proc_finish();
1337
[149]1338 SH_MUTEX_UNLOCK(mutex_port_check);
[67]1339 return 0;
1340}
1341
[170]1342int sh_portchk_cleanup (void)
[67]1343{
1344 return sh_portchk_reconf ();
1345}
1346
1347int sh_portchk_timer (time_t tcurrent)
1348{
1349 static time_t lastcheck = 0;
1350
1351 SL_ENTER(_("sh_portchk_timer"));
1352 if ((time_t) (tcurrent - lastcheck) >= sh_portchk_interval)
1353 {
1354 lastcheck = tcurrent;
1355 SL_RETURN((-1), _("sh_portchk_timer"));
1356 }
1357 SL_RETURN(0, _("sh_portchk_timer"));
1358}
1359#endif
1360
[295]1361static int check_port_generic (int port, int domain, int type, int protocol)
[67]1362{
[170]1363 volatile int i = 0;
[67]1364 int sock = -1;
1365 int flag = 1; /* non-zero to enable an option */
[295]1366 struct sh_sockaddr paddr;
[132]1367 char errbuf[SH_ERRBUF_SIZE];
1368
[67]1369 /* Check all interfaces for this host
1370 */
[511]1371 while (i < iface_list_used)
[67]1372 {
[511]1373 memcpy(&paddr, &(iface_list[i].iface), sizeof(paddr));
[149]1374
[295]1375 if (paddr.ss_family != domain)
[149]1376 {
[295]1377 ++i;
1378 continue;
[149]1379 }
1380
[295]1381 if (0 != sh_portchk_is_blacklisted(port, &paddr, protocol))
[67]1382 {
[295]1383 ++i;
1384 continue;
1385 }
1386
1387 if ((sock = socket(paddr.ss_family, type, protocol)) < 0 )
1388 {
[170]1389 ++i;
[67]1390#ifdef TEST_ONLY
1391 if (portchk_debug)
1392 perror(_("socket"));
1393#else
[334]1394
1395#ifndef EPROTONOSUPPORT
1396#define EPROTONOSUPPORT 0
[170]1397#endif
[334]1398#ifndef EAFNOSUPPORT
1399#define EAFNOSUPPORT 0
1400#endif
1401 if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
1402 {
1403 SH_MUTEX_LOCK(mutex_thread_nolog);
1404 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1405 sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
1406 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1407 }
1408#endif
[149]1409 continue;
[67]1410 }
1411 if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1412 (void *) &flag, sizeof(flag)) < 0 )
1413 {
[170]1414 ++i;
[67]1415#ifdef TEST_ONLY
1416 if (portchk_debug)
1417 perror(_("setsockopt"));
1418#else
[149]1419 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1420 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1421 sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
[149]1422 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1423#endif
[149]1424 continue;
[67]1425 }
1426
1427
1428 if (protocol == IPPROTO_TCP)
[295]1429 check_port_tcp_internal(sock, port, &paddr);
[67]1430 else
[295]1431 check_port_udp_internal(sock, port, &paddr);
[67]1432
1433 ++i;
1434 }
1435
1436 return 0;
1437}
1438
1439
1440
[295]1441static int check_port_udp (int port, int domain)
[67]1442{
[295]1443 return check_port_generic(port, domain, SOCK_DGRAM, IPPROTO_UDP);
[67]1444}
1445
[295]1446static int check_port_tcp (int port, int domain)
[67]1447{
[295]1448 return check_port_generic(port, domain, SOCK_STREAM, IPPROTO_TCP);
[67]1449}
1450
1451
[295]1452static int sh_portchk_scan_ports_generic (int min_port, int max_port_arg,
1453 int domain, int type, int protocol)
[67]1454{
1455 /*
1456 int min_port = 1024;
1457 int max_port = 65535;
1458 */
1459
[170]1460 volatile int port; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
1461 volatile int max_port = max_port_arg;
[67]1462 int retval;
1463 int sock = -1;
[498]1464#if 0
[67]1465 int flag = 1; /* non-zero to enable an option */
[498]1466#endif
[295]1467 struct sockaddr_in addr4;
1468 struct sockaddr_in6 addr6;
1469
1470 int addrlen4 = sizeof(addr4);
1471 int addrlen6 = sizeof(addr6);
1472
1473 struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
1474
[132]1475 char errbuf[SH_ERRBUF_SIZE];
[67]1476
1477 if (min_port == -1)
1478 min_port = 0;
1479 if (max_port == -1)
1480 max_port = 65535;
1481
[468]1482 if (portchk_debug)
1483 fprintf(stderr, _("scan_ports_generic %d-%d %s %s\n"),
1484 min_port, max_port, (domain == AF_INET6) ? _("AF_INET6") : _("AF_INET"),
1485 (protocol == IPPROTO_TCP) ? _("tcp") : _("udp"));
1486
[67]1487 for (port = min_port; port <= max_port; ++port)
1488 {
[295]1489 if ((sock = socket(domain, type, protocol)) < 0 )
[67]1490 {
1491#ifdef TEST_ONLY
1492 if (portchk_debug)
1493 perror(_("socket"));
1494#else
[334]1495#ifndef EPROTONOSUPPORT
1496#define EPROTONOSUPPORT 0
[67]1497#endif
[334]1498#ifndef EAFNOSUPPORT
1499#define EAFNOSUPPORT 0
1500#endif
1501 if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
1502 {
1503 SH_MUTEX_LOCK(mutex_thread_nolog);
1504 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1505 sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
1506 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1507 }
1508#endif
[149]1509 continue;
[67]1510 }
[498]1511
1512#if 0
[67]1513 if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1514 (void *) &flag, sizeof(flag)) < 0 )
1515 {
1516#ifdef TEST_ONLY
1517 if (portchk_debug)
1518 perror(_("setsockopt"));
1519#else
[149]1520 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1521 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1522 sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
[149]1523 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1524#endif
[149]1525 continue;
[67]1526 }
[498]1527#endif
[67]1528
[295]1529 if (domain == AF_INET)
1530 {
1531 addr4.sin_family = AF_INET;
1532 addr4.sin_port = htons(port);
1533 addr4.sin_addr.s_addr = INADDR_ANY;
1534 retval = bind (sock, (struct sockaddr *) &addr4, addrlen4);
1535 }
1536 else
1537 {
1538 addr6.sin6_family = AF_INET6;
1539 addr6.sin6_port = htons(port);
1540 memcpy(&(addr6.sin6_addr.s6_addr), &anyaddr, sizeof(anyaddr));
1541 retval = bind (sock, (struct sockaddr *) &addr6, addrlen6);
1542 }
[67]1543
1544 if (retval == 0)
1545 {
1546 /* we can bind the port, thus it is unused
1547 */
[252]1548 sl_close_fd (FIL__, __LINE__, sock);
[67]1549 }
1550 else
1551 {
1552 if (errno == EINVAL || errno == EADDRINUSE)
1553 {
1554 /* try to connect to the port
1555 */
1556 if (protocol == IPPROTO_TCP)
[295]1557 check_port_tcp(port, domain);
[67]1558 else
[295]1559 check_port_udp(port, domain);
[67]1560 }
1561 else
1562 {
1563#ifdef TEST_ONLY
1564 if (portchk_debug)
1565 perror(_("bind"));
1566#else
[149]1567 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]1568 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1569 sh_error_message(errno, errbuf, sizeof(errbuf)), _("bind"));
[149]1570 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1571#endif
1572 }
[252]1573 sl_close_fd (FIL__, __LINE__, sock);
[67]1574 }
1575 }
1576 return 0;
1577}
1578
1579static int sh_portchk_scan_ports_tcp (int min_port, int max_port)
1580{
[295]1581#if defined(USE_IPVX)
1582 sh_portchk_scan_ports_generic (min_port, max_port, AF_INET6,
1583 SOCK_STREAM, IPPROTO_TCP);
1584#endif
1585 return sh_portchk_scan_ports_generic (min_port, max_port, AF_INET,
1586 SOCK_STREAM, IPPROTO_TCP);
[67]1587}
1588
1589static int sh_portchk_scan_ports_udp (int min_port, int max_port)
1590{
[295]1591#if defined(USE_IPVX)
1592 sh_portchk_scan_ports_generic (min_port, max_port, AF_INET6,
1593 SOCK_DGRAM, IPPROTO_UDP);
1594#endif
1595 return sh_portchk_scan_ports_generic (min_port, max_port, AF_INET,
1596 SOCK_DGRAM, IPPROTO_UDP);
[67]1597}
1598
1599/* Subroutine to add an interface
1600 */
[481]1601void * sh_dummy_1564_str = NULL; /* fix clobbered by.. warning */
[212]1602
[511]1603static int sh_portchk_add_interface_int (const char * str, int type)
[67]1604{
[295]1605 struct sh_sockaddr saddr;
[67]1606 char errbuf[256];
[212]1607 char buf[64];
[67]1608
[481]1609 sh_dummy_1564_str = (void*) &str;
[212]1610
[67]1611 if (iface_initialized == 0)
1612 {
[511]1613 iface_list_used = 0;
[67]1614 iface_initialized = 1;
1615 }
1616
[212]1617 do {
[67]1618
[212]1619 while (*str == ',' || *str == ' ' || *str == '\t') ++str;
[67]1620
[212]1621 if (*str)
1622 {
[295]1623 char ipbuf[SH_IP_BUF];
[212]1624 unsigned int i = 0;
[295]1625 while (*str && i < (sizeof(buf)-1) &&
1626 *str != ',' && *str != ' ' && *str != '\t')
[212]1627 {
1628 buf[i] = *str; ++str; ++i;
1629 }
1630 buf[i] = '\0';
[67]1631
[295]1632 if (0 == sh_ipvx_aton(buf, &saddr))
[212]1633 return -1;
[67]1634
[511]1635 if (iface_list_used == SH_IFACE_MAX)
[212]1636 return -1;
1637
[295]1638 sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &saddr);
1639 sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"), ipbuf);
[212]1640 SH_MUTEX_LOCK(mutex_thread_nolog);
1641 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1642 errbuf, _("sh_portchk_add_interface"));
1643 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1644
[511]1645 memcpy (&(iface_list[iface_list_used].iface), &(saddr), sizeof(saddr));
1646 iface_list[iface_list_used].type = type;
1647 ++iface_list_used;
[212]1648 }
1649 } while (*str);
1650
[481]1651 sh_dummy_1564_str = NULL;
[67]1652 return 0;
1653}
1654
[511]1655static int sh_portchk_add_interface (const char * str)
1656{
1657 return sh_portchk_add_interface_int (str, SH_IFACE_ADDR);
1658}
1659
1660#if defined(HAVE_IFADDRS_H)
1661/*
1662 * subroutines to add a device
1663 */
1664void * sh_dummy_1651_ifa = NULL; /* fix clobbered by.. warning */
1665
1666static int portchk_add_device_int (const char * buf)
1667{
1668 struct ifaddrs *ifaddr, *ifa;
1669 int family;
1670#ifndef NI_MAXHOST
1671#define NI_MAXHOST 1025
1672#endif
1673 char host[NI_MAXHOST];
1674
1675 sh_dummy_1651_ifa = (void*) &ifa;
1676
1677 if (getifaddrs(&ifaddr) == -1)
1678 {
1679 volatile int nerr = errno;
1680 char errbuf[SH_ERRBUF_SIZE];
1681 sh_error_message(errno, errbuf, sizeof(errbuf));
1682 SH_MUTEX_LOCK(mutex_thread_nolog);
1683 sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
1684 errbuf, _("getifaddrs"));
1685 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1686 return -1;
1687 }
1688
1689 for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
1690 {
1691 if (ifa->ifa_addr == NULL)
1692 continue;
1693
1694 if (strcmp(ifa->ifa_name, buf) == 0)
1695 {
1696 volatile int s = 0;
1697 family = ifa->ifa_addr->sa_family;
1698
1699 if (family == AF_INET)
1700 {
1701 s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in),
1702 host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
1703
1704 if (s == 0)
1705 {
1706 if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0)
1707 {
1708 freeifaddrs(ifaddr);
1709 return -1;
1710 }
1711 }
1712 }
1713
1714#if defined(USE_IPVX)
1715 if (family == AF_INET6)
1716 {
1717 s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in6),
1718 host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
1719
1720 if (s == 0)
1721 {
1722 if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0)
1723 {
1724 freeifaddrs(ifaddr);
1725 return -1;
1726 }
1727 }
1728 }
1729#endif
1730
1731 if (s != 0)
1732 {
1733 char errbuf[SH_ERRBUF_SIZE];
1734 sl_strlcpy(errbuf, buf, sizeof(errbuf));
1735 sl_strlcat(errbuf, ": ", sizeof(errbuf));
1736 sl_strlcat(errbuf, gai_strerror(s), sizeof(errbuf));
1737 SH_MUTEX_LOCK(mutex_thread_nolog);
1738 sh_error_handle((-1), FIL__, __LINE__, s, MSG_E_SUBGEN,
1739 errbuf, _("getnameinfo"));
1740 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1741 }
1742
1743 }
1744 }
1745
1746 freeifaddrs(ifaddr);
1747 return 0;
1748}
1749
1750struct added_dev {
1751 char dev[64];
1752 struct added_dev * next;
1753};
1754
1755static struct added_dev * dev_list = NULL;
1756
1757static void dev_list_add (char * buf)
1758{
1759 struct added_dev * new = SH_ALLOC(sizeof(struct added_dev));
1760 sl_strlcpy(new->dev, buf, 64);
1761 new->next = dev_list;
1762 dev_list = new;
1763 return;
1764}
1765
1766static void dev_list_kill ()
1767{
1768 struct added_dev * old;
1769 struct added_dev * new = dev_list;
1770 dev_list = NULL;
1771
1772 while (new)
1773 {
1774 old = new;
1775 new = new->next;
1776 SH_FREE(old);
1777 }
1778 return;
1779}
1780
1781static int sh_portchk_add_device (const char * str)
1782{
1783 char buf[64];
1784
1785 do {
1786
1787 while (*str == ',' || *str == ' ' || *str == '\t') ++str;
1788
1789 if (*str)
1790 {
1791 unsigned int i = 0;
1792 while (*str && i < (sizeof(buf)-1) &&
1793 *str != ',' && *str != ' ' && *str != '\t') {
1794 buf[i] = *str; ++str; ++i;
1795 }
1796 buf[i] = '\0';
1797
1798 if (portchk_add_device_int (buf) < 0)
1799 return -1;
1800
1801 dev_list_add(buf);
1802 }
1803 } while (*str);
1804
1805 return 0;
1806}
1807
1808static int iface_comp (const void *a, const void *b)
1809{
1810 const struct portchk_interfaces * aa = (struct portchk_interfaces *) a;
1811 const struct portchk_interfaces * bb = (struct portchk_interfaces *) b;
1812 return (aa->type - bb->type);
1813}
1814
1815static void iface_qsort()
1816{
1817 qsort(&iface_list[0], iface_list_used, sizeof(struct portchk_interfaces),
1818 iface_comp);
1819 return;
1820}
1821
1822static void recheck_devices()
1823{
1824 if (dev_list)
1825 {
1826 struct added_dev * dev = dev_list;
1827 int i, j;
1828
1829 if (portchk_debug)
1830 {
1831 for (j = 0; j < iface_list_used; ++j)
1832 {
1833 char buf[SH_IP_BUF];
1834 struct portchk_interfaces * aa = &(iface_list[j]);
1835 sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
1836 fprintf(stderr, _("presort: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
1837 }
1838 }
1839
1840 iface_qsort();
1841
1842 if (portchk_debug)
1843 {
1844 for (j = 0; j < iface_list_used; ++j)
1845 {
1846 char buf[SH_IP_BUF];
1847 struct portchk_interfaces * aa = &(iface_list[j]);
1848 sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
1849 fprintf(stderr, _("postsor: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
1850 }
1851 }
1852
1853 i = 0;
1854 for (j = 0; j < iface_list_used; ++j)
1855 if (iface_list[j].type == SH_IFACE_DEV) ++i;
1856 iface_list_used -= i;
1857
1858 if (portchk_debug)
1859 {
1860 for (j = 0; j < iface_list_used; ++j)
1861 {
1862 char buf[SH_IP_BUF];
1863 struct portchk_interfaces * aa = &(iface_list[j]);
1864 sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
1865 fprintf(stderr, _("postdel: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
1866 }
1867 }
1868
1869 while (dev)
1870 {
1871 portchk_add_device_int (dev->dev);
1872 dev = dev->next;
1873 }
1874 }
1875 return;
1876}
1877#endif
1878
[149]1879/* verify whether port/interface is blacklisted (do not check)
1880 */
[295]1881static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * saddr,
1882 int proto)
[149]1883{
1884 struct sh_port * head;
1885
1886 if (proto == IPPROTO_TCP)
1887 head = blacklist_tcp;
1888 else
1889 head = blacklist_udp;
1890
1891 while (head)
1892 {
1893 if (head->port == port)
1894 {
[295]1895 if (sh_ipvx_isany(head->paddr) ||
1896 0 == sh_ipvx_cmp(head->paddr, saddr))
[149]1897 return 1;
1898 else
1899 return 0;
1900 }
1901 head = head->next;
1902 }
1903 return 0;
1904}
1905
1906
[295]1907static int sh_portchk_blacklist(int port, struct sh_sockaddr * saddr, int proto)
[149]1908{
1909 struct sh_port * black;
1910 struct sh_port * head;
1911
1912 if (proto == IPPROTO_TCP)
1913 head = blacklist_tcp;
1914 else
1915 head = blacklist_udp;
1916
1917 black = head;
1918
1919 while (black)
1920 {
[295]1921 if (black->port == port &&
1922 0 == sh_ipvx_cmp(head->paddr, saddr))
[149]1923 return -1;
1924 black = black->next;
1925 }
[295]1926
[149]1927 black = SH_ALLOC (sizeof(struct sh_port));
[295]1928 black->paddr = SH_ALLOC (sizeof(struct sh_sockaddr));
[149]1929 black->port = port;
[295]1930 memcpy(black->paddr, saddr, sizeof(struct sh_sockaddr));
[149]1931 black->next = head;
1932
1933 if (proto == IPPROTO_TCP)
1934 blacklist_tcp = black;
1935 else
1936 blacklist_udp = black;
[468]1937
1938 if (portchk_debug)
1939 {
1940 int checkit = sh_portchk_is_blacklisted(port, saddr, proto);
1941 fprintf(stderr, _("port blacklisted: %d %s\n"), port,
1942 (checkit == 1) ? _("ok") : _("fail"));
1943 }
[149]1944 return 0;
1945}
1946
[67]1947
1948/* Subroutine to add a required or optional port/service
1949 */
[295]1950static int sh_portchk_add_required_port_generic (char * service,
1951 char * interface, int type)
[67]1952{
[473]1953 char buf[256] = { '\0' };
[149]1954 int proto;
[67]1955 char * p;
1956 char * endptr;
1957 unsigned long int port;
[295]1958 struct sh_sockaddr saddr;
[67]1959 struct sh_portentry * portent;
1960
[295]1961 if (0 == sh_ipvx_aton(interface, &saddr))
[67]1962 return -1;
1963
1964 sl_strlcpy (buf, service, sizeof(buf));
1965
1966 p = strchr(buf, '/');
1967 if (!p)
1968 return -1;
1969 if (0 == strcmp(p, _("/tcp")))
[149]1970 proto = IPPROTO_TCP;
1971 else if (0 == strcmp(p, _("/udp")))
1972 proto = IPPROTO_UDP;
[67]1973 else
1974 return -1;
1975
1976 *p = '\0';
1977 port = strtoul(buf, &endptr, 0);
1978
[468]1979 if (portchk_debug)
1980 {
1981 char buf[SH_IP_BUF];
1982 sh_ipvx_ntoa(buf, sizeof(buf), &saddr);
1983 fprintf(stderr, _("add_port_generic: %s (%s) %d %s (%s)\n"),
1984 interface, buf, (int) port, (proto == IPPROTO_TCP) ? _("tcp") : _("udp"),
1985 sh_port_type2str(type));
1986 }
1987
[149]1988 /* Blacklisted ports
1989 */
1990 if (*endptr == '\0' && port <= 65535 && type == SH_PORT_BLACKLIST)
[295]1991 return (sh_portchk_blacklist(port, &saddr, proto));
[149]1992
[67]1993 if (*endptr != '\0')
1994 {
[295]1995 portent = sh_portchk_get_from_list (proto, -1, &saddr, buf);
[67]1996 if (!portent)
[380]1997 {
1998 if (portchk_debug)
[383]1999 fprintf(stderr, _("add_required_port %d\n"), (int) port);
[380]2000 sh_portchk_add_to_list (proto, -1, &saddr, buf, type, SH_PORT_UNKN);
2001 }
[67]2002 else
2003 {
2004#ifdef TEST_ONLY
[149]2005 fprintf(stderr, "** WARNING: duplicate port definition %s/%s\n", buf, SH_PROTO_STR(proto));
[67]2006#else
[149]2007 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]2008 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2009 _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
[149]2010 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]2011#endif
2012 return -1;
2013 }
2014 }
2015 else if (port <= 65535)
2016 {
[295]2017 portent = sh_portchk_get_from_list (proto, port, &saddr, NULL);
[67]2018 if (!portent)
[380]2019 {
2020 if (portchk_debug)
2021 fprintf(stderr, _("add_required_port: open port: %d/%s\n"),
2022 (int) port, SH_PROTO_STR(proto));
2023 sh_portchk_add_to_list (proto, port, &saddr, NULL, type, SH_PORT_UNKN);
2024 }
[67]2025 else
2026 {
2027#ifdef TEST_ONLY
[149]2028 fprintf(stderr, "** WARNING: duplicate port definition %lu/%s\n", port, SH_PROTO_STR(proto));
[67]2029#else
[149]2030 SH_MUTEX_LOCK(mutex_thread_nolog);
[67]2031 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2032 _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
[149]2033 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]2034#endif
2035 return -1;
2036 }
2037 }
2038 else
2039 return -1;
2040
2041 return 0;
2042}
2043
2044/* Internal interface to add required or optional ports as 'iface:portlist'
2045 */
2046static int sh_portchk_add_required_generic (const char * str, int type)
2047{
2048 size_t ll = 0;
[149]2049 int status;
[67]2050
2051 char * interface = NULL;
2052 char * list;
2053 char * p;
[131]2054#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
2055 char * saveptr;
2056#endif
[67]2057
2058 if (!str)
2059 return -1;
2060
2061 if (strchr(str, ':'))
2062 {
[468]2063 char *last = strrchr(str, ':');
2064 if (last != NULL)
[67]2065 {
[468]2066 size_t tolast = (last - str);
2067 interface = SH_ALLOC(tolast+1);
2068 sl_strlcpy(interface, str, tolast+1);
2069 interface[tolast] = '\0';
2070
2071 ll = tolast;
2072
2073 while (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
2074 ++ll;
[67]2075 }
2076 }
2077 else
2078 {
2079 interface = SH_ALLOC(8);
2080 sl_strlcpy(interface, _("0.0.0.0"), 8);
2081 interface[7] = '\0';
2082 while (str[ll] == ' ' || str[ll] == '\t')
2083 ++ll;
2084 }
2085
2086 if (!interface)
2087 return -1;
2088
2089 if (str[ll] == '\0')
2090 {
2091 SH_FREE(interface);
2092 return -1;
2093 }
2094
2095 if (portchk_debug)
[468]2096 fprintf(stderr, "add ports for interface: %s (%s)\n", interface, sh_port_type2str(type));
[67]2097
2098 list = sh_util_strdup(&str[ll]);
[131]2099#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
2100 p = strtok_r (list, " ,\t", &saveptr);
2101#else
[67]2102 p = strtok (list, " ,\t");
[131]2103#endif
[67]2104 if (!p)
2105 {
2106 SH_FREE(interface);
2107 SH_FREE(list);
2108 return -1;
2109 }
2110 while (p)
2111 {
[149]2112 status = sh_portchk_add_required_port_generic (p, interface, type);
2113
2114 if (-1 == status)
[67]2115 {
2116 SH_FREE(interface);
2117 SH_FREE(list);
2118 return -1;
2119 }
[131]2120#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
2121 p = strtok_r (NULL, " ,\t", &saveptr);
2122#else
[67]2123 p = strtok (NULL, " ,\t");
[131]2124#endif
[67]2125 }
2126 SH_FREE(interface);
2127 SH_FREE(list);
2128 return 0;
2129}
2130
2131/* User interface to add required ports as 'iface:portlist'
2132 */
2133static int sh_portchk_add_required (const char * str)
2134{
2135 return sh_portchk_add_required_generic (str, SH_PORT_REQ);
2136}
2137
2138/* User interface to add optional ports as 'iface:portlist'
2139 */
2140static int sh_portchk_add_optional (const char * str)
2141{
2142 return sh_portchk_add_required_generic (str, SH_PORT_OPT);
2143}
2144
[127]2145/* User interface to add ignoreable ports as 'iface:portlist'
2146 */
2147static int sh_portchk_add_ignore (const char * str)
2148{
2149 return sh_portchk_add_required_generic (str, SH_PORT_IGN);
2150}
2151
[149]2152/* User interface to add ports that should not be checked as 'iface:portlist'
2153 */
2154static int sh_portchk_add_blacklist (const char * str)
2155{
2156 return sh_portchk_add_required_generic (str, SH_PORT_BLACKLIST);
2157}
2158
[67]2159/* Interface to run port check
2160 */
2161int sh_portchk_check ()
2162{
[170]2163 volatile int min_port;
[376]2164 static int noprivports = 0;
[67]2165
[149]2166 SH_MUTEX_LOCK(mutex_port_check);
[170]2167
[328]2168 min_port = (sh_portchk_minport == -1) ? 0 : sh_portchk_minport;
[170]2169
[78]2170 if (sh_portchk_active != S_FALSE)
[67]2171 {
[405]2172 SH_MUTEX_LOCK(mutex_thread_nolog);
[253]2173 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2174 _("Checking for open ports"),
2175 _("sh_portchk_check"));
[405]2176 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[253]2177
[78]2178 sh_portchk_reset_lists();
[511]2179
2180#if defined(HAVE_IFADDRS_H)
2181 recheck_devices();
2182#endif
2183
[328]2184 if ((0 != geteuid()) && (min_port < 1024))
[78]2185 {
2186 min_port = 1024;
[376]2187 if (noprivports == 0)
2188 {
[67]2189#ifdef TEST_ONLY
[376]2190 fprintf(stderr, "** WARNING not scanning ports < 1024\n");
[67]2191#else
[376]2192 SH_MUTEX_LOCK(mutex_thread_nolog);
2193 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2194 _("not scanning ports below 1024"),
2195 _("sh_portchk_check"));
2196 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]2197#endif
[376]2198 noprivports = 1;
2199 }
[78]2200 }
[180]2201
2202 sh_port2proc_prepare();
2203
[78]2204 if (sh_portchk_check_udp == 1)
[328]2205 sh_portchk_scan_ports_udp(min_port, sh_portchk_maxport);
2206 sh_portchk_scan_ports_tcp(min_port, sh_portchk_maxport);
[180]2207
2208
[149]2209 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_REPORT);
[78]2210 if (sh_portchk_check_udp == 1)
[149]2211 sh_portchk_check_list (&portlist_udp, IPPROTO_UDP, SH_PORT_REPORT);
[180]2212
[67]2213 }
[149]2214 SH_MUTEX_UNLOCK(mutex_port_check);
[67]2215 return 0;
2216}
2217#endif
2218
2219#ifdef SH_CUTEST
2220#include "CuTest.h"
2221
2222void Test_portcheck_lists (CuTest *tc)
2223{
[73]2224#if defined(SH_USE_PORTCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
[295]2225 struct sh_sockaddr haddr_local;
[67]2226 struct sh_portentry * portent;
[218]2227 char buf[256];
2228 char * p;
[67]2229
[290]2230#ifdef HAVE_RPC_RPC_H
[218]2231 p = sh_getrpcbynumber(0, buf, sizeof(buf));
2232 CuAssertTrue(tc, p == NULL);
2233
2234 p = sh_getrpcbynumber(100000, buf, sizeof(buf));
2235 CuAssertPtrNotNull(tc, p);
2236 CuAssertTrue(tc, (0 == strcmp(p, "portmapper") || 0 == strcmp(p, "rpcbind")));
2237 CuAssertTrue(tc, (0 == strcmp(buf, "portmapper") || 0 == strcmp(p, "rpcbind")));
2238
2239 p = sh_getrpcbynumber(100007, buf, sizeof(buf));
2240 CuAssertPtrNotNull(tc, p);
2241 CuAssertTrue(tc, 0 == strcmp(p, "ypbind"));
2242 CuAssertTrue(tc, 0 == strcmp(buf, "ypbind"));
[290]2243#endif
[218]2244
[300]2245 p = sh_getservbyport(0, SH_PROTO_STR(IPPROTO_UDP), buf, sizeof(buf));
[218]2246 CuAssertTrue(tc, p == NULL);
2247
[290]2248#if !defined(HOST_IS_CYGWIN)
[218]2249 p = sh_getservbyport(22, SH_PROTO_STR(IPPROTO_TCP), buf, sizeof(buf));
2250 CuAssertPtrNotNull(tc, p);
2251 CuAssertTrue(tc, 0 == strcmp(p, "ssh"));
2252 CuAssertTrue(tc, 0 == strcmp(buf, "ssh"));
[290]2253#endif
[218]2254
2255 p = sh_getservbyport(13, SH_PROTO_STR(IPPROTO_UDP), buf, sizeof(buf));
2256 CuAssertPtrNotNull(tc, p);
2257 CuAssertTrue(tc, 0 == strcmp(p, "daytime"));
2258 CuAssertTrue(tc, 0 == strcmp(buf, "daytime"));
2259
[295]2260 CuAssertTrue(tc, 0 != sh_ipvx_aton("127.0.0.1", &haddr_local));
[67]2261
[295]2262 sh_portchk_add_to_list (IPPROTO_TCP, 8000, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
[67]2263
[295]2264 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, NULL);
[67]2265 CuAssertPtrNotNull(tc, portent);
2266
2267 CuAssertTrue(tc, portent->port == 8000);
2268 CuAssertTrue(tc, 0 == strcmp("127.0.0.1", portent->interface));
2269 CuAssertTrue(tc, portent->status == SH_PORT_UNKN);
2270 CuAssertTrue(tc, portent->flag == SH_PORT_NOT);
2271
[149]2272 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]2273
2274 CuAssertTrue(tc, NULL == portlist_tcp);
2275
[295]2276 sh_portchk_add_to_list (IPPROTO_TCP, 8000, &haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
2277 sh_portchk_add_to_list (IPPROTO_TCP, 8001, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
2278 sh_portchk_add_to_list (IPPROTO_TCP, 8002, &haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
2279 sh_portchk_add_to_list (IPPROTO_TCP, 8003, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
2280 sh_portchk_add_to_list (IPPROTO_TCP, 8004, &haddr_local, NULL, SH_PORT_IGN, SH_PORT_UNKN);
2281 sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo1", SH_PORT_NOT, SH_PORT_UNKN);
2282 sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo2", SH_PORT_REQ, SH_PORT_UNKN);
2283 sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo3", SH_PORT_NOT, SH_PORT_UNKN);
2284 sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo4", SH_PORT_REQ, SH_PORT_UNKN);
2285 sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo5", SH_PORT_IGN, SH_PORT_UNKN);
[67]2286
[149]2287 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]2288
2289 CuAssertPtrNotNull(tc, portlist_tcp);
2290
[295]2291 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, NULL);
[67]2292 CuAssertPtrNotNull(tc, portent);
2293
[295]2294 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8001, &haddr_local, NULL);
[67]2295 CuAssertTrue(tc, NULL == portent);
2296
[295]2297 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8002, &haddr_local, NULL);
[67]2298 CuAssertPtrNotNull(tc, portent);
2299
[295]2300 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8003, &haddr_local, NULL);
[67]2301 CuAssertTrue(tc, NULL == portent);
2302
[295]2303 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8004, &haddr_local, NULL);
[127]2304 CuAssertPtrNotNull(tc, portent);
2305
[295]2306 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo1");
[67]2307 CuAssertTrue(tc, NULL == portent);
2308
[295]2309 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo2");
[67]2310 CuAssertPtrNotNull(tc, portent);
2311 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo2"));
2312
[295]2313 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo3");
[67]2314 CuAssertTrue(tc, NULL == portent);
2315
[295]2316 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo4");
[67]2317 CuAssertPtrNotNull(tc, portent);
2318 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo4"));
[127]2319
[295]2320 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo5");
[127]2321 CuAssertPtrNotNull(tc, portent);
2322 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo5"));
[149]2323
[295]2324 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, &haddr_local, IPPROTO_TCP));
2325 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, &haddr_local, IPPROTO_TCP));
2326 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, &haddr_local, IPPROTO_TCP));
2327 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, &haddr_local, IPPROTO_TCP));
2328 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, &haddr_local, IPPROTO_UDP));
2329 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, &haddr_local, IPPROTO_UDP));
2330 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, &haddr_local, IPPROTO_UDP));
2331 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, &haddr_local, IPPROTO_UDP));
[149]2332
[295]2333 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, &haddr_local, IPPROTO_UDP));
2334 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, &haddr_local, IPPROTO_UDP));
2335 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, &haddr_local, IPPROTO_UDP));
2336 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, &haddr_local, IPPROTO_UDP));
[149]2337
[295]2338 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, &haddr_local, IPPROTO_TCP));
2339 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, &haddr_local, IPPROTO_TCP));
2340 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, &haddr_local, IPPROTO_TCP));
2341 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, &haddr_local, IPPROTO_TCP));
[67]2342#else
2343 (void) tc; /* fix compiler warning */
2344#endif
2345 return;
2346}
2347#endif
2348
2349#ifdef TEST_ONLY
2350
2351void usage (char * pname)
2352{
2353 printf ("%s [-r|--required interface:portlist][-o|--optional interface:portlist][--no-udp][-d|--debug] hostname\n\n", pname);
2354 printf (" Check local host for open ports; Version %s\n\n", PORTCHK_VERSION);
2355 printf (" Interface: Numeric address for an interface, e.g. 127.0.0.1\n");
2356 printf (" Portlist: List of ports or services, e.g. 22/tcp,nfs/udp,nlockmgr/udp\n");
2357 printf (" required -> must be open\n");
2358 printf (" optional -> may be open or closed\n");
2359 printf (" RPC services must be specified with service **name**, others with **port number**\n\n");
2360 printf (" Example:\n");
2361 printf (" %s --required 192.168.1.2:22/tcp,nfs/udp,nlockmgr/udp\n\n", pname);
2362 return;
2363}
2364
2365int main(int argc, char *argv[])
2366{
2367 char * pname = argv[0];
2368
2369
2370 /*
2371 test_lists();
2372
2373 portlist_tcp = sh_portchk_kill_list (portlist_tcp);
2374 portlist_udp = sh_portchk_kill_list (portlist_udp);
2375 */
2376
[237]2377 /* sh_portchk_add_required ("127.0.0.1 : nlockmgr/tcp, 5308/tcp, nfs/tcp"); */
[67]2378
2379 while (argc > 1 && argv[1][0] == '-')
2380 {
2381 if (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))
2382 {
2383 usage(pname);
2384 exit (0);
2385 }
2386 else if (0 == strcmp(argv[1], "--required") || 0 == strcmp(argv[1], "-r"))
2387 {
2388 if (argc < 3)
2389 {
2390 usage(pname);
2391 exit (1);
2392 }
2393 sh_portchk_add_required (argv[2]);
2394 --argc; ++argv;
2395 }
2396 else if (0 == strcmp(argv[1], "--optional") || 0 == strcmp(argv[1], "-o"))
2397 {
2398 if (argc < 3)
2399 {
2400 usage(pname);
2401 exit (1);
2402 }
2403 sh_portchk_add_optional (argv[2]);
2404 --argc; ++argv;
2405 }
2406 else if (0 == strcmp(argv[1], "--no-udp"))
2407 {
2408 sh_portchk_check_udp = 0;
2409 }
2410 else if (0 == strcmp(argv[1], "--debug") || 0 == strcmp(argv[1], "-d"))
2411 {
2412 portchk_debug = 1;
2413 }
2414 else
2415 {
2416 usage(pname);
2417 exit (1);
2418 }
2419 --argc; ++argv;
2420 }
2421
2422 if (argc < 2)
2423 {
2424 usage(pname);
2425 exit (1);
2426 }
2427
2428 portchk_hostname = argv[1];
2429
2430 if (0 != sh_portchk_init ())
2431 {
2432 usage(pname);
2433 exit (1);
2434 }
2435
2436 sh_portchk_check();
2437
2438 return 0;
2439}
2440#endif
Note: See TracBrowser for help on using the repository browser.