source: trunk/src/sh_portcheck.c@ 381

Last change on this file since 381 was 380, checked in by katerina, 13 years ago

Fix for ticket #278 (With --disable-ipv6, port check always checks all interfaces).

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