source: trunk/src/sh_port2proc.c@ 277

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

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

File size: 25.7 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2008 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#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <unistd.h>
27
28#ifdef HAVE_DIRENT_H
29#include <dirent.h>
30#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
31#else
32#define dirent direct
33#define NAMLEN(dirent) (dirent)->d_namlen
34#ifdef HAVE_SYS_NDIR_H
35#include <sys/ndir.h>
36#endif
37#ifdef HAVE_SYS_DIR_H
38#include <sys/dir.h>
39#endif
40#ifdef HAVE_NDIR_H
41#include <ndir.h>
42#endif
43#endif
44#define NEED_ADD_DIRENT
45
46#if defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
47
48/* #define DEBUG_P2P 1 */
49
50/****************************************************************************
51 *
52 * >>> COMMON CODE <<<
53 *
54 ****************************************************************************/
55#if defined(__linux__) || defined(__FreeBSD__)
56
57#include "samhain.h"
58#include "sh_error_min.h"
59#include "sh_utils.h"
60#include "sh_pthread.h"
61
62#define FIL__ _("sh_port2proc.c")
63
64struct sock_store {
65 unsigned long sock;
66 size_t pid;
67 char * path;
68 char * user;
69 struct sock_store * next;
70};
71
72/* /proc:
73 * linux: /proc/pid/exe
74 * freebsd: /proc/pid/file
75 * solaris10: /proc/pid/path/a.out
76 */
77static void get_user_and_path (struct sock_store * add)
78{
79 extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
80
81 char path[128];
82 char * buf;
83 struct stat sbuf;
84 int len;
85 char * tmp;
86
87 sl_snprintf (path, sizeof(path), "/proc/%ld/exe", (unsigned long) add->pid);
88
89 if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
90 {
91 goto linkread;
92 }
93
94 sl_snprintf (path, sizeof(path), "/proc/%ld/file", (unsigned long) add->pid);
95
96 if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
97 {
98 goto linkread;
99 }
100
101 sl_snprintf (path, sizeof(path), "/proc/%ld/path/a.out", (unsigned long) add->pid);
102
103 if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
104 {
105 goto linkread;
106 }
107
108 return;
109
110 linkread:
111
112 buf = SH_ALLOC(PATH_MAX);
113 len = readlink(path, buf, PATH_MAX); /* flawfinder: ignore */
114 len = (len >= PATH_MAX) ? (PATH_MAX-1) : len;
115
116 if (len > 0)
117 {
118 buf[len] = '\0';
119 add->path = buf;
120 }
121 else
122 {
123 SH_FREE(buf);
124 }
125
126 add->user = SH_ALLOC(USER_MAX);
127 tmp = sh_unix_getUIDname (SH_ERR_ALL, sbuf.st_uid, add->user, USER_MAX);
128
129 if (!tmp)
130 sl_snprintf (add->user, USER_MAX, "%ld", (unsigned long) sbuf.st_uid);
131
132 return;
133}
134
135#endif
136
137/****************************************************************************
138 *
139 * >>> LINUX CODE <<<
140 *
141 ****************************************************************************/
142
143#if defined(__linux__)
144
145static size_t sh_minpid = 0x0001;
146static size_t sh_maxpid = 0x8000;
147
148#ifndef HAVE_LSTAT
149#define lstat(x,y) stat(x,y)
150#endif /* HAVE_LSTAT */
151
152#if defined(S_IFLNK) && !defined(S_ISLNK)
153# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
154#else
155# if !defined(S_ISLNK)
156# define S_ISLNK(mode) (0)
157# endif
158#endif
159
160#if defined(__linux__)
161#define PROC_PID_MAX _("/proc/sys/kernel/pid_max")
162
163static int proc_max_pid (size_t * procpid)
164{
165 char * ret;
166 unsigned long pid;
167 FILE * fd;
168 char str[128];
169 char * ptr;
170
171 SL_ENTER(_("proc_max_pid"));
172
173 if (0 == access(PROC_PID_MAX, R_OK)) /* flawfinder: ignore */
174 {
175 if (NULL != (fd = fopen(PROC_PID_MAX, "r")))
176 {
177 str[0] = '\0';
178 ret = fgets(str, 128, fd);
179 if (ret && *str != '\0')
180 {
181 pid = strtoul(str, &ptr, 0);
182 if (*ptr == '\0' || *ptr == '\n')
183 {
184 sl_fclose(FIL__, __LINE__, fd);
185 *procpid = (size_t) pid;
186 SL_RETURN(0, _("proc_max_pid"));
187 }
188 }
189 sl_fclose(FIL__, __LINE__, fd);
190 }
191 }
192 SL_RETURN((-1), _("proc_max_pid"));
193}
194#else
195static int proc_max_pid(size_t * procpid)
196{
197 *procpid = sh_maxpid;
198 return 0;
199}
200#endif
201
202static struct sock_store * socklist = NULL;
203
204static void del_sock_all()
205{
206 struct sock_store * del = socklist;
207
208 while (del)
209 {
210 socklist = del->next;
211 if (del->path)
212 SH_FREE(del->path);
213 if (del->user)
214 SH_FREE(del->user);
215 SH_FREE(del);
216 del = socklist;
217 }
218 socklist = NULL;
219 return;
220}
221
222static void add_sock(unsigned long sock, size_t pid)
223{
224 struct sock_store * add = SH_ALLOC(sizeof(struct sock_store));
225
226 add->sock = sock;
227 add->pid = pid;
228 add->path = NULL;
229 add->user = NULL;
230 SH_MUTEX_LOCK(mutex_thread_nolog);
231 get_user_and_path(add);
232 SH_MUTEX_UNLOCK(mutex_thread_nolog);
233 add->next = socklist;
234 socklist = add;
235 return;
236}
237
238static void check_and_add_sock(char * fbuf, size_t pid)
239{
240 if (0 == strncmp(_("socket:["), fbuf, 8))
241 {
242 char * end;
243 unsigned long sock;
244 size_t len = strlen(fbuf);
245 if (fbuf[len-1] == ']')
246 fbuf[len-1] = '\0';
247 sock = strtoul(&fbuf[8], &end, 0);
248 if (*end == '\0' && fbuf[8] != '\0')
249 {
250 add_sock(sock, pid);
251 }
252 }
253}
254
255static void fetch_socks(size_t pid)
256{
257 char path[128];
258 DIR * dir;
259 sl_snprintf(path, sizeof(path), _("/proc/%lu/fd"), (unsigned long) pid);
260
261 dir = opendir(path);
262 if (dir)
263 {
264 struct dirent *entry;
265 while (NULL != (entry = readdir(dir)))
266 {
267 char fpath[384];
268 char fbuf[64];
269 int ret;
270 /* /proc/PID/fd/N-> socket:[15713] */
271 sl_snprintf(fpath, sizeof(fpath), _("%s/%s"), path, entry->d_name);
272 ret = readlink(fpath, fbuf, sizeof(fbuf)-1); /* flawfinder: ignore */
273 if (ret > 0)
274 {
275 fbuf[ret] = '\0';
276 check_and_add_sock(fbuf, pid);
277 }
278 }
279 closedir(dir);
280 }
281}
282
283int sh_port2proc_prepare()
284{
285 size_t i;
286
287 if (0 != proc_max_pid(&sh_maxpid))
288 {
289 SH_MUTEX_LOCK(mutex_thread_nolog);
290 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
291 _("Failed to detect max_pid"),
292 _("sh_port2proc"));
293 SH_MUTEX_UNLOCK(mutex_thread_nolog);
294 SL_RETURN ((-1), _("sh_port2proc"));
295 }
296
297 /* Delete old socket list and re-create it
298 */
299 del_sock_all();
300
301 for (i = sh_minpid; i < sh_maxpid; ++i)
302 {
303 fetch_socks(i);
304 }
305
306 return 0;
307}
308
309void sh_port2proc_finish()
310{
311 /* Delete old socket list
312 */
313 del_sock_all();
314 return;
315}
316
317
318#include <sys/socket.h>
319#include <netinet/in.h>
320#include <arpa/inet.h>
321
322/* returns the command and fills the 'user' array
323 */
324static char * port2proc_query(char * file, int proto, struct in_addr * saddr, int sport,
325 unsigned long * pid, char * user, size_t userlen)
326{
327 FILE * fd;
328
329 fd = fopen(file, "r");
330
331 *pid = 0;
332
333#ifdef DEBUG_P2P
334 {
335 char errmsg[256];
336 sl_snprintf(errmsg, sizeof(errmsg),
337 "query, file=%s, proto=%d, port=%d, iface=%s\n",
338 file, proto, sport, inet_ntoa(*saddr));
339 fprintf(stderr, "%s", errmsg);
340 }
341#endif
342
343 if (fd)
344 {
345 unsigned int n, iface, port, inode, istatus;
346 char line[512];
347
348 while (NULL != fgets(line, sizeof(line), fd))
349 {
350
351#ifdef DEBUG_P2P
352 {
353 fprintf(stderr, "%s", line);
354 }
355#endif
356
357 if (5 == sscanf(line,
358 "%u: %X:%X %*X:%*X %X %*X:%*X %*X:%*X %*X %*d %*d %u %*s",
359 &n, &iface, &port, &istatus, &inode))
360 {
361 struct in_addr haddr;
362
363 haddr.s_addr = (unsigned long)iface;
364
365#ifdef DEBUG_P2P
366 {
367 char a[32];
368 char b[32];
369
370 sl_strlcpy(a, inet_ntoa(haddr), sizeof(a));
371 sl_strlcpy(b, inet_ntoa(*saddr), sizeof(b));
372
373 fprintf(stderr, " -> inode %u, iface/port %s,%u, status %u, searching %s,%u, %u\n",
374 inode, a, port, istatus, b, sport,
375 proto == IPPROTO_TCP ? 0x0a : 0x07);
376 }
377#endif
378
379 if (proto == IPPROTO_TCP && istatus != 0x0a)
380 continue;
381 if (proto == IPPROTO_UDP && istatus == 0x01)
382 continue;
383
384#ifdef DEBUG_P2P
385 {
386 fprintf(stderr, "check iface %u..\n", iface);
387 }
388#endif
389
390 if ((proto == IPPROTO_UDP || iface == 0 || haddr.s_addr == saddr->s_addr) && port == (unsigned int)sport)
391 {
392 struct sock_store * new = socklist;
393
394#ifdef DEBUG_P2P
395 {
396 fprintf(stderr, "found it\n");
397 }
398#endif
399
400 while (new)
401 {
402#ifdef DEBUG_P2P
403 {
404 fprintf(stderr, "searching inode %u: %lu\n",
405 inode, new->sock);
406 }
407#endif
408 if (inode == new->sock)
409 {
410#ifdef DEBUG_P2P
411 {
412 fprintf(stderr, "found it: path=(%s), user=(%s)\n",
413 new->path == NULL ? "NULL" : new->path,
414 new->user == NULL ? "NULL" : new->user);
415 }
416#endif
417 sl_fclose(FIL__, __LINE__, fd);
418 *pid = (unsigned long) new->pid;
419 if (new->path)
420 {
421 if (new->user)
422 sl_strlcpy(user, new->user, userlen);
423 else
424 sl_strlcpy(user, "-", userlen);
425 return sh_util_strdup(new->path);
426 }
427 goto err_out;
428 }
429 new = new->next;
430 }
431 }
432 }
433 }
434 sl_fclose(FIL__, __LINE__, fd);
435 }
436 err_out:
437 sl_strlcpy(user, "-", userlen);
438 return sh_util_strdup("-");
439}
440
441/* returns the command and fills the 'user' array
442 */
443char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
444 unsigned long * pid, char * user, size_t userlen)
445{
446 char file[32];
447
448 if (proto == IPPROTO_TCP)
449 {
450 sl_strlcpy(file, _("/proc/net/tcp"), sizeof(file));
451 return port2proc_query(file, proto, saddr, sport, pid, user, userlen);
452 }
453 else
454 {
455 char * ret;
456 sl_strlcpy(file, _("/proc/net/udp"), sizeof(file));
457 ret = port2proc_query(file, proto, saddr, sport, pid, user, userlen);
458 if (ret[0] == '-' && ret[1] == '\0')
459 {
460 SH_FREE(ret);
461 sl_strlcpy(file, _("/proc/net/udp6"), sizeof(file));
462 ret = port2proc_query(file, proto, saddr, sport, pid, user, userlen);
463 }
464 return ret;
465 }
466}
467
468
469/****************************************************************************
470 *
471 * >>> FREEBSD CODE <<<
472 *
473 ****************************************************************************/
474
475#elif defined(__FreeBSD__)
476
477/* Uses code from sockstat.c. Error and memory handling modified.
478 * Only required functions from sockstat.c are included.
479 */
480
481/*-
482 * Copyright (c) 2002 Dag-Erling Co<EF>dan Sm<F8>rgrav
483 * All rights reserved.
484 *
485 * Redistribution and use in source and binary forms, with or without
486 * modification, are permitted provided that the following conditions
487 * are met:
488 * 1. Redistributions of source code must retain the above copyright
489 * notice, this list of conditions and the following disclaimer
490 * in this position and unchanged.
491 * 2. Redistributions in binary form must reproduce the above copyright
492 * notice, this list of conditions and the following disclaimer in the
493 * documentation and/or other materials provided with the distribution.
494 * 3. The name of the author may not be used to endorse or promote products
495 * derived from this software without specific prior written permission.
496 *
497 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
498 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
499 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
500 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
501 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
502 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
503 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
504 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
505 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
506 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
507 */
508#include <sys/cdefs.h>
509__FBSDID("$FreeBSD: src/usr.bin/sockstat/sockstat.c,v 1.13.2.1.4.1 2008/10/02 02:57:24 kensmith Exp $");
510
511#include <sys/param.h>
512#include <sys/socket.h>
513#include <sys/socketvar.h>
514#include <sys/sysctl.h>
515#include <sys/file.h>
516#include <sys/user.h>
517
518#include <sys/un.h>
519#include <sys/unpcb.h>
520
521#include <net/route.h>
522
523#include <netinet/in.h>
524#include <netinet/in_pcb.h>
525#include <netinet/tcp.h>
526#include <netinet/tcp_seq.h>
527#include <netinet/tcp_var.h>
528#include <arpa/inet.h>
529
530#include <ctype.h>
531#include <errno.h>
532#include <netdb.h>
533#include <stdio.h>
534#include <stdlib.h>
535
536#include <unistd.h>
537
538static int opt_4 = 1; /* Show IPv4 sockets */
539static int opt_6 = 0; /* Show IPv6 sockets */
540static int opt_c = 0; /* Show connected sockets */
541static int opt_l = 1; /* Show listening sockets */
542static int opt_v = 0; /* Verbose mode */
543
544struct sock {
545 void *socket;
546 void *pcb;
547 int vflag;
548 int family;
549 int proto;
550
551 struct sockaddr_storage laddr;
552 struct sockaddr_storage faddr;
553 struct sock *next;
554};
555
556#define HASHSIZE 1009
557static struct sock *sockhash[HASHSIZE];
558
559static struct xfile *xfiles;
560static int nxfiles;
561
562
563static void * xrealloc(void * buf, size_t len0, size_t len)
564{
565 if (len > 0)
566 {
567 void * xbuf = SH_ALLOC(len);
568 if (buf)
569 {
570 if (len0 <= len)
571 memcpy(xbuf, buf, len0);
572 else
573 memset(xbuf, '\0', len);
574 SH_FREE(buf);
575 }
576 return xbuf;
577 }
578 SH_FREE(buf);
579 return NULL;
580}
581
582/* Sets address and port in struct sockaddr_storage *sa
583 */
584static void
585sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
586{
587 struct sockaddr_in *sin4;
588 struct sockaddr_in6 *sin6;
589
590 bzero(sa, sizeof *sa);
591 switch (af) {
592 case AF_INET:
593 sin4 = (struct sockaddr_in *)sa;
594 sin4->sin_len = sizeof *sin4;
595 sin4->sin_family = af;
596 sin4->sin_port = port;
597 sin4->sin_addr = *(struct in_addr *)addr;
598 break;
599 case AF_INET6:
600 sin6 = (struct sockaddr_in6 *)sa;
601 sin6->sin6_len = sizeof *sin6;
602 sin6->sin6_family = af;
603 sin6->sin6_port = port;
604 sin6->sin6_addr = *(struct in6_addr *)addr;
605 break;
606 default:
607 return;
608 }
609}
610
611/* Get socket information from the kernel.
612 */
613static void
614gather_inet(int proto)
615{
616 struct xinpgen *xig, *exig;
617 struct xinpcb *xip;
618 struct xtcpcb *xtp;
619 struct inpcb *inp;
620 struct xsocket *so;
621 struct sock *sock;
622 char varname[32];
623 size_t len, bufsize, bufsize0;
624 void *buf;
625 int hash, retry, vflag;
626
627 vflag = 0;
628 if (opt_4)
629 vflag |= INP_IPV4;
630 if (opt_6)
631 vflag |= INP_IPV6;
632
633 switch (proto) {
634 case IPPROTO_TCP:
635 sl_strlcpy(varname, _("net.inet.tcp.pcblist"), sizeof(varname));
636 break;
637 case IPPROTO_UDP:
638 sl_strlcpy(varname, _("net.inet.udp.pcblist"), sizeof(varname));
639 break;
640 case IPPROTO_DIVERT:
641 sl_strlcpy(varname, _("net.inet.divert.pcblist"), sizeof(varname));
642 break;
643 default:
644 return;
645 }
646
647 buf = NULL;
648 bufsize = 8192;
649 bufsize0 = bufsize;
650 retry = 5;
651 do {
652 for (;;) {
653 buf = xrealloc(buf, bufsize0, bufsize);
654 bufsize0 = bufsize;
655 len = bufsize;
656 if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
657 break;
658 if (errno == ENOENT)
659 goto out;
660 if (errno != ENOMEM)
661 {
662 SH_MUTEX_LOCK(mutex_thread_nolog);
663 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__,
664 0, MSG_E_SUBGEN,
665 _("sysctlbyname()"),
666 _("gather_inet"));
667 SH_MUTEX_UNLOCK(mutex_thread_nolog);
668 SH_FREE(buf);
669 return;
670 }
671 bufsize *= 2;
672 }
673 xig = (struct xinpgen *)buf;
674 exig = (struct xinpgen *)(void *)
675 ((char *)buf + len - sizeof *exig);
676 if (xig->xig_len != sizeof *xig ||
677 exig->xig_len != sizeof *exig)
678 {
679 SH_MUTEX_LOCK(mutex_thread_nolog);
680 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
681 _("struct xinpgen size mismatch"),
682 _("gather_inet"));
683 SH_MUTEX_UNLOCK(mutex_thread_nolog);
684 goto out;
685 }
686
687 } while (xig->xig_gen != exig->xig_gen && retry--);
688
689 if (xig->xig_gen != exig->xig_gen && opt_v)
690 {
691 SH_MUTEX_LOCK(mutex_thread_nolog);
692 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
693 _("data may be inconsistent"),
694 _("gather_inet"));
695 SH_MUTEX_UNLOCK(mutex_thread_nolog);
696 }
697
698 for (;;) {
699 xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
700 if (xig >= exig)
701 break;
702 switch (proto) {
703 case IPPROTO_TCP:
704 xtp = (struct xtcpcb *)xig;
705 if (xtp->xt_len != sizeof *xtp) {
706 SH_MUTEX_LOCK(mutex_thread_nolog);
707 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
708 _("struct xtcpcb size mismatch"),
709 _("gather_inet"));
710 SH_MUTEX_UNLOCK(mutex_thread_nolog);
711 goto out;
712 }
713 inp = &xtp->xt_inp;
714 so = &xtp->xt_socket;
715 break;
716 case IPPROTO_UDP:
717 case IPPROTO_DIVERT:
718 xip = (struct xinpcb *)xig;
719 if (xip->xi_len != sizeof *xip) {
720 SH_MUTEX_LOCK(mutex_thread_nolog);
721 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
722 _("struct xinpcb size mismatch"),
723 _("gather_inet"));
724 SH_MUTEX_UNLOCK(mutex_thread_nolog);
725 goto out;
726 }
727 inp = &xip->xi_inp;
728 so = &xip->xi_socket;
729 break;
730 default:
731 return;
732 }
733 if ((inp->inp_vflag & vflag) == 0)
734 continue;
735 if (inp->inp_vflag & INP_IPV4) {
736 if ((inp->inp_fport == 0 && !opt_l) ||
737 (inp->inp_fport != 0 && !opt_c))
738 continue;
739 } else if (inp->inp_vflag & INP_IPV6) {
740 if ((inp->in6p_fport == 0 && !opt_l) ||
741 (inp->in6p_fport != 0 && !opt_c))
742 continue;
743 } else {
744 if (opt_v) {
745 char errmsg[64];
746 sl_snprintf(errmsg, sizeof(errmsg),
747 _("invalid vflag 0x%x"), inp->inp_vflag);
748 SH_MUTEX_LOCK(mutex_thread_nolog);
749 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
750 errmsg,
751 _("gather_inet"));
752 SH_MUTEX_UNLOCK(mutex_thread_nolog);
753 continue;
754 }
755 }
756
757 sock = SH_ALLOC(sizeof *sock);
758 memset(sock, '\0', sizeof (*sock));
759
760 sock->socket = so->xso_so;
761 sock->proto = proto;
762 if (inp->inp_vflag & INP_IPV4) {
763 sock->family = AF_INET;
764 sockaddr(&sock->laddr, sock->family,
765 &inp->inp_laddr, inp->inp_lport);
766 sockaddr(&sock->faddr, sock->family,
767 &inp->inp_faddr, inp->inp_fport);
768 } else if (inp->inp_vflag & INP_IPV6) {
769 sock->family = AF_INET6;
770 sockaddr(&sock->laddr, sock->family,
771 &inp->in6p_laddr, inp->in6p_lport);
772 sockaddr(&sock->faddr, sock->family,
773 &inp->in6p_faddr, inp->in6p_fport);
774 }
775 sock->vflag = inp->inp_vflag;
776
777 hash = (int)((uintptr_t)sock->socket % HASHSIZE);
778 sock->next = sockhash[hash];
779 sockhash[hash] = sock;
780 }
781out:
782 if (buf)
783 SH_FREE(buf);
784}
785
786static void
787getfiles(void)
788{
789 size_t len;
790 size_t len0;
791
792 xfiles = SH_ALLOC(len = sizeof *xfiles);
793 len0 = len;
794
795 while (sysctlbyname(_("kern.file"), xfiles, &len, 0, 0) == -1) {
796 if (errno != ENOMEM)
797 {
798 volatile int status = errno;
799 SH_MUTEX_LOCK(mutex_thread_nolog);
800 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
801 _("sysctlbyname()"),
802 _("getfiles"));
803 SH_MUTEX_UNLOCK(mutex_thread_nolog);
804 }
805 len *= 2;
806 xfiles = xrealloc(xfiles, len0, len);
807 len0 = len;
808 }
809 if (len > 0 && xfiles->xf_size != sizeof *xfiles)
810 if (errno != ENOMEM)
811 {
812 volatile int status = errno;
813 SH_MUTEX_LOCK(mutex_thread_nolog);
814 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
815 _("struct xfile size mismatch"),
816 _("getfiles"));
817 SH_MUTEX_UNLOCK(mutex_thread_nolog);
818 }
819 nxfiles = len / sizeof *xfiles;
820}
821
822static const char *
823getprocname(pid_t pid)
824{
825 static struct kinfo_proc proc;
826 size_t len;
827 int mib[4];
828
829 mib[0] = CTL_KERN;
830 mib[1] = KERN_PROC;
831 mib[2] = KERN_PROC_PID;
832 mib[3] = (int)pid;
833 len = sizeof proc;
834 if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
835 /* Do not warn if the process exits before we get its name. */
836 if (errno != ESRCH)
837 {
838 volatile int status = errno;
839 SH_MUTEX_LOCK(mutex_thread_nolog);
840 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN,
841 _("sysctl()"),
842 _("getfiles"));
843 SH_MUTEX_UNLOCK(mutex_thread_nolog);
844 }
845 return ("-");
846 }
847 return (proc.ki_ocomm);
848}
849
850char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
851 unsigned long * pid, char * user, size_t userlen)
852{
853 int n, hash;
854 struct xfile *xf;
855 struct in_addr * haddr;
856 struct sock * s;
857
858 *pid = 0;
859
860 for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
861
862 if (xf->xf_data == NULL)
863 continue;
864
865 /* Find the socket in sockhash[] that corresponds to it
866 */
867 hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
868 for (s = sockhash[hash]; s != NULL; s = s->next)
869 if ((void *)s->socket == xf->xf_data)
870 break;
871
872 if (!s)
873 continue;
874
875 /* fprintf(stderr, "FIXME: %d %d, %d %d, %d %d, %d, %d\n", s->proto, proto,
876 s->family, AF_INET,
877 sport, ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port),
878 (int) xf->xf_uid, (int)xf->xf_pid);
879 */
880
881 if (s->proto != proto)
882 continue;
883
884 if (s->family != AF_INET /* && s->family != AF_INET6 */)
885 continue;
886
887 if (sport != ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port))
888 continue;
889
890 haddr = &((struct sockaddr_in *)(&s->laddr))->sin_addr;
891
892 /* fprintf(stderr, "FIXME: %s\n", inet_ntoa(*haddr)); */
893 /* fprintf(stderr, "FIXME: %s\n", inet_ntoa(*saddr)); */
894
895 if (haddr->s_addr == saddr->s_addr || inet_lnaof(*saddr) == INADDR_ANY || inet_lnaof(*haddr) == INADDR_ANY)
896 {
897 struct sock_store try;
898
899 *pid = xf->xf_pid;
900
901 try.pid = xf->xf_pid;
902 try.path = NULL;
903 try.user = NULL;
904 get_user_and_path (&try); /* Try to get info from /proc */
905
906 if (try.path == NULL)
907 {
908 extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
909 char * tmp = sh_unix_getUIDname (SH_ERR_ALL, xf->xf_uid, user, userlen);
910 if (!tmp)
911 sl_snprintf (user, userlen, "%ld", (unsigned long) xf->xf_uid);
912 return sh_util_strdup(getprocname(xf->xf_pid));
913 }
914 else
915 {
916 sl_strlcpy(user, try.user, userlen);
917 SH_FREE(try.user);
918 return try.path;
919 }
920 }
921 }
922 sl_strlcpy(user, "-", userlen);
923 return sh_util_strdup("-");
924}
925
926static void sockdel(struct sock * sock)
927{
928 if (sock)
929 {
930 if (sock->next)
931 sockdel(sock->next);
932 SH_FREE(sock);
933 }
934 return;
935}
936
937int sh_port2proc_prepare()
938{
939 int i;
940
941 if (xfiles)
942 {
943 SH_FREE(xfiles);
944 xfiles = NULL;
945 }
946
947 for (i = 0; i < HASHSIZE; ++i)
948 {
949 sockdel(sockhash[i]);
950 sockhash[i] = NULL;
951 }
952
953 /* Inet connections
954 */
955 gather_inet(IPPROTO_TCP);
956 gather_inet(IPPROTO_UDP);
957 gather_inet(IPPROTO_DIVERT);
958
959 getfiles();
960
961 return 0;
962}
963
964void sh_port2proc_finish()
965{
966 return;
967}
968
969#else /* !defined(__linux__) && !defined(__FreeBSD__) */
970
971char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
972 unsigned long * pid, char * user, size_t userlen)
973{
974 (void) proto;
975 (void) saddr;
976 (void) sport;
977
978 *pid = 0;
979
980 sl_strlcpy(user, "-", userlen);
981 return sh_util_strdup("-");
982}
983
984int sh_port2proc_prepare()
985{
986 return 0;
987}
988
989void sh_port2proc_finish()
990{
991 return;
992}
993#endif
994
995#endif /* defined(SH_USE_PORTCHECK) */
Note: See TracBrowser for help on using the repository browser.