source: trunk/src/sh_portcheck.c@ 252

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

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

  • Property svn:executable set to *
File size: 47.3 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 {
[78]1620 sh_portchk_reset_lists();
1621 if (0 != geteuid())
1622 {
1623 min_port = 1024;
[67]1624#ifdef TEST_ONLY
[78]1625 fprintf(stderr, "** WARNING not scanning ports < 1024\n");
[67]1626#else
[149]1627 SH_MUTEX_LOCK(mutex_thread_nolog);
[78]1628 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1629 _("not scanning ports below 1024"), _("sh_portchk_check"));
[149]1630 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[67]1631#endif
[78]1632 }
[180]1633
1634 sh_port2proc_prepare();
1635
[78]1636 if (sh_portchk_check_udp == 1)
1637 sh_portchk_scan_ports_udp(min_port, -1);
1638 sh_portchk_scan_ports_tcp(min_port, -1);
[180]1639
1640
[149]1641 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_REPORT);
[78]1642 if (sh_portchk_check_udp == 1)
[149]1643 sh_portchk_check_list (&portlist_udp, IPPROTO_UDP, SH_PORT_REPORT);
[180]1644
[67]1645 }
[149]1646 SH_MUTEX_UNLOCK(mutex_port_check);
[67]1647 return 0;
1648}
1649#endif
1650
1651#ifdef SH_CUTEST
1652#include "CuTest.h"
1653
1654void Test_portcheck_lists (CuTest *tc)
1655{
[73]1656#if defined(SH_USE_PORTCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
[67]1657 struct in_addr haddr_local;
1658 struct sh_portentry * portent;
[218]1659 char buf[256];
1660 char * p;
[67]1661
[218]1662 p = sh_getrpcbynumber(0, buf, sizeof(buf));
1663 CuAssertTrue(tc, p == NULL);
1664
1665 p = sh_getrpcbynumber(100000, buf, sizeof(buf));
1666 CuAssertPtrNotNull(tc, p);
1667 CuAssertTrue(tc, (0 == strcmp(p, "portmapper") || 0 == strcmp(p, "rpcbind")));
1668 CuAssertTrue(tc, (0 == strcmp(buf, "portmapper") || 0 == strcmp(p, "rpcbind")));
1669
1670 p = sh_getrpcbynumber(100007, buf, sizeof(buf));
1671 CuAssertPtrNotNull(tc, p);
1672 CuAssertTrue(tc, 0 == strcmp(p, "ypbind"));
1673 CuAssertTrue(tc, 0 == strcmp(buf, "ypbind"));
1674
1675 p = sh_getservbyport(0, SH_PROTO_STR(IPPROTO_TCP), buf, sizeof(buf));
1676 CuAssertTrue(tc, p == NULL);
1677
1678 p = sh_getservbyport(22, SH_PROTO_STR(IPPROTO_TCP), buf, sizeof(buf));
1679 CuAssertPtrNotNull(tc, p);
1680 CuAssertTrue(tc, 0 == strcmp(p, "ssh"));
1681 CuAssertTrue(tc, 0 == strcmp(buf, "ssh"));
1682
1683 p = sh_getservbyport(13, SH_PROTO_STR(IPPROTO_UDP), buf, sizeof(buf));
1684 CuAssertPtrNotNull(tc, p);
1685 CuAssertTrue(tc, 0 == strcmp(p, "daytime"));
1686 CuAssertTrue(tc, 0 == strcmp(buf, "daytime"));
1687
[67]1688 CuAssertTrue(tc, 0 != inet_aton("127.0.0.1", &haddr_local));
1689
[149]1690 sh_portchk_add_to_list (IPPROTO_TCP, 8000, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
[67]1691
[149]1692 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, NULL);
[67]1693 CuAssertPtrNotNull(tc, portent);
1694
1695 CuAssertTrue(tc, portent->port == 8000);
1696 CuAssertTrue(tc, 0 == strcmp("127.0.0.1", portent->interface));
1697 CuAssertTrue(tc, portent->status == SH_PORT_UNKN);
1698 CuAssertTrue(tc, portent->flag == SH_PORT_NOT);
1699
[149]1700 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]1701
1702 CuAssertTrue(tc, NULL == portlist_tcp);
1703
[149]1704 sh_portchk_add_to_list (IPPROTO_TCP, 8000, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
1705 sh_portchk_add_to_list (IPPROTO_TCP, 8001, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
1706 sh_portchk_add_to_list (IPPROTO_TCP, 8002, haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
1707 sh_portchk_add_to_list (IPPROTO_TCP, 8003, haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
1708 sh_portchk_add_to_list (IPPROTO_TCP, 8004, haddr_local, NULL, SH_PORT_IGN, SH_PORT_UNKN);
1709 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo1", SH_PORT_NOT, SH_PORT_UNKN);
1710 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo2", SH_PORT_REQ, SH_PORT_UNKN);
1711 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo3", SH_PORT_NOT, SH_PORT_UNKN);
1712 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo4", SH_PORT_REQ, SH_PORT_UNKN);
1713 sh_portchk_add_to_list (IPPROTO_TCP, -1, haddr_local, "foo5", SH_PORT_IGN, SH_PORT_UNKN);
[67]1714
[149]1715 sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
[67]1716
1717 CuAssertPtrNotNull(tc, portlist_tcp);
1718
[149]1719 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, NULL);
[67]1720 CuAssertPtrNotNull(tc, portent);
1721
[149]1722 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8001, haddr_local, NULL);
[67]1723 CuAssertTrue(tc, NULL == portent);
1724
[149]1725 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8002, haddr_local, NULL);
[67]1726 CuAssertPtrNotNull(tc, portent);
1727
[149]1728 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8003, haddr_local, NULL);
[67]1729 CuAssertTrue(tc, NULL == portent);
1730
[149]1731 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8004, haddr_local, NULL);
[127]1732 CuAssertPtrNotNull(tc, portent);
1733
[149]1734 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo1");
[67]1735 CuAssertTrue(tc, NULL == portent);
1736
[149]1737 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo2");
[67]1738 CuAssertPtrNotNull(tc, portent);
1739 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo2"));
1740
[149]1741 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo3");
[67]1742 CuAssertTrue(tc, NULL == portent);
1743
[149]1744 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo4");
[67]1745 CuAssertPtrNotNull(tc, portent);
1746 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo4"));
[127]1747
[149]1748 portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, haddr_local, "foo5");
[127]1749 CuAssertPtrNotNull(tc, portent);
1750 CuAssertTrue(tc, 0 == strcmp(portent->service, "foo5"));
[149]1751
1752 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, haddr_local, IPPROTO_TCP));
1753 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, haddr_local, IPPROTO_TCP));
1754 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, haddr_local, IPPROTO_TCP));
1755 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, haddr_local, IPPROTO_TCP));
1756 CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, haddr_local, IPPROTO_UDP));
1757 CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, haddr_local, IPPROTO_UDP));
1758 CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, haddr_local, IPPROTO_UDP));
1759 CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, haddr_local, IPPROTO_UDP));
1760
1761 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, haddr_local, IPPROTO_UDP));
1762 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, haddr_local, IPPROTO_UDP));
1763 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, haddr_local, IPPROTO_UDP));
1764 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, haddr_local, IPPROTO_UDP));
1765
1766 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, haddr_local, IPPROTO_TCP));
1767 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, haddr_local, IPPROTO_TCP));
1768 CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, haddr_local, IPPROTO_TCP));
1769 CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, haddr_local, IPPROTO_TCP));
[67]1770#else
1771 (void) tc; /* fix compiler warning */
1772#endif
1773 return;
1774}
1775#endif
1776
1777#ifdef TEST_ONLY
1778
1779void usage (char * pname)
1780{
1781 printf ("%s [-r|--required interface:portlist][-o|--optional interface:portlist][--no-udp][-d|--debug] hostname\n\n", pname);
1782 printf (" Check local host for open ports; Version %s\n\n", PORTCHK_VERSION);
1783 printf (" Interface: Numeric address for an interface, e.g. 127.0.0.1\n");
1784 printf (" Portlist: List of ports or services, e.g. 22/tcp,nfs/udp,nlockmgr/udp\n");
1785 printf (" required -> must be open\n");
1786 printf (" optional -> may be open or closed\n");
1787 printf (" RPC services must be specified with service **name**, others with **port number**\n\n");
1788 printf (" Example:\n");
1789 printf (" %s --required 192.168.1.2:22/tcp,nfs/udp,nlockmgr/udp\n\n", pname);
1790 return;
1791}
1792
1793int main(int argc, char *argv[])
1794{
1795 char * pname = argv[0];
1796
1797
1798 /*
1799 test_lists();
1800
1801 portlist_tcp = sh_portchk_kill_list (portlist_tcp);
1802 portlist_udp = sh_portchk_kill_list (portlist_udp);
1803 */
1804
[237]1805 /* sh_portchk_add_required ("127.0.0.1 : nlockmgr/tcp, 5308/tcp, nfs/tcp"); */
[67]1806
1807 while (argc > 1 && argv[1][0] == '-')
1808 {
1809 if (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))
1810 {
1811 usage(pname);
1812 exit (0);
1813 }
1814 else if (0 == strcmp(argv[1], "--required") || 0 == strcmp(argv[1], "-r"))
1815 {
1816 if (argc < 3)
1817 {
1818 usage(pname);
1819 exit (1);
1820 }
1821 sh_portchk_add_required (argv[2]);
1822 --argc; ++argv;
1823 }
1824 else if (0 == strcmp(argv[1], "--optional") || 0 == strcmp(argv[1], "-o"))
1825 {
1826 if (argc < 3)
1827 {
1828 usage(pname);
1829 exit (1);
1830 }
1831 sh_portchk_add_optional (argv[2]);
1832 --argc; ++argv;
1833 }
1834 else if (0 == strcmp(argv[1], "--no-udp"))
1835 {
1836 sh_portchk_check_udp = 0;
1837 }
1838 else if (0 == strcmp(argv[1], "--debug") || 0 == strcmp(argv[1], "-d"))
1839 {
1840 portchk_debug = 1;
1841 }
1842 else
1843 {
1844 usage(pname);
1845 exit (1);
1846 }
1847 --argc; ++argv;
1848 }
1849
1850 if (argc < 2)
1851 {
1852 usage(pname);
1853 exit (1);
1854 }
1855
1856 portchk_hostname = argv[1];
1857
1858 if (0 != sh_portchk_init ())
1859 {
1860 usage(pname);
1861 exit (1);
1862 }
1863
1864 sh_portchk_check();
1865
1866 return 0;
1867}
1868#endif
Note: See TracBrowser for help on using the repository browser.