source: trunk/src/sh_portcheck.c@ 293

Last change on this file since 293 was 290, checked in by katerina, 14 years ago

Fixes for tickets #215, #216, #217, #218, version bumped to 2.7.2

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