aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/sockstat/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/sockstat/main.c')
-rw-r--r--usr.bin/sockstat/main.c170
1 files changed, 130 insertions, 40 deletions
diff --git a/usr.bin/sockstat/main.c b/usr.bin/sockstat/main.c
index 07663e54534d..1f174d827e1a 100644
--- a/usr.bin/sockstat/main.c
+++ b/usr.bin/sockstat/main.c
@@ -88,6 +88,7 @@ static bool opt_A; /* Show kernel address of pcb */
static bool opt_b; /* Show BBLog state */
static bool opt_C; /* Show congestion control */
static bool opt_c; /* Show connected sockets */
+static bool opt_F; /* Show sockets for selected user only */
static bool opt_f; /* Show FIB numbers */
static bool opt_I; /* Show spliced socket addresses */
static bool opt_i; /* Show inp_gencnt */
@@ -115,6 +116,12 @@ static size_t default_numprotos = nitems(default_protos);
static int *protos; /* protocols to use */
static size_t numprotos; /* allocated size of protos[] */
+/*
+ * Show sockets for user username or UID specified
+ */
+static char *filter_user_optarg = NULL; /* saved optarg for username/UID resolving */
+static uid_t filter_user_uid; /* UID to show sockets for */
+
struct addr {
union {
struct sockaddr_storage address;
@@ -217,6 +224,18 @@ _enforce_ksize(size_t received_size, size_t expected_size, const char *struct_na
}
#define enforce_ksize(_sz, _struct) (_enforce_ksize(_sz, sizeof(_struct), #_struct))
+static inline bool
+filtered_uid(uid_t i_uid)
+{
+ return ((i_uid) == filter_user_uid);
+}
+
+static inline bool
+need_nosocks(void)
+{
+ return !(opt_F || (opt_j >= 0));
+}
+
static int
get_proto_type(const char *proto)
{
@@ -758,7 +777,8 @@ gather_inet(int proto)
if (sock->socket != 0)
RB_INSERT(socks_t, &socks, sock);
else
- SLIST_INSERT_HEAD(&nosocks, sock, socket_list);
+ if (need_nosocks())
+ SLIST_INSERT_HEAD(&nosocks, sock, socket_list);
}
out:
free(buf);
@@ -862,6 +882,8 @@ getfiles(void)
struct xfile *xfiles;
size_t len, olen;
+ int filenum = 0;
+
olen = len = sizeof(*xfiles);
if ((xfiles = malloc(len)) == NULL)
xo_err(1, "malloc()");
@@ -880,14 +902,23 @@ getfiles(void)
if ((files = malloc(nfiles * sizeof(struct file))) == NULL)
xo_err(1, "malloc()");
+ /* Fill files structure, optionally for specified user */
for (int i = 0; i < nfiles; i++) {
- files[i].xf_data = xfiles[i].xf_data;
- files[i].xf_pid = xfiles[i].xf_pid;
- files[i].xf_uid = xfiles[i].xf_uid;
- files[i].xf_fd = xfiles[i].xf_fd;
- RB_INSERT(files_t, &ftree, &files[i]);
+ if (opt_F && !filtered_uid(xfiles[i].xf_uid))
+ continue;
+ files[filenum].xf_data = xfiles[i].xf_data;
+ files[filenum].xf_pid = xfiles[i].xf_pid;
+ files[filenum].xf_uid = xfiles[i].xf_uid;
+ files[filenum].xf_fd = xfiles[i].xf_fd;
+ RB_INSERT(files_t, &ftree, &files[filenum]);
+ filenum++;
}
+ /* Adjust global nfiles to match the number of files we
+ * actually filled into files[] array
+ */
+ nfiles = filenum;
+
free(xfiles);
}
@@ -1584,6 +1615,24 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
static void
display(void)
{
+ static const char *__HDR_USER="USER",
+ *__HDR_COMMAND="COMMAND",
+ *__HDR_PID="PID",
+ *__HDR_FD="FD",
+ *__HDR_PROTO="PROTO",
+ *__HDR_LOCAL_ADDRESS="LOCAL ADDRESS",
+ *__HDR_FOREIGN_ADDRESS="FOREIGN ADDRESS",
+ *__HDR_PCB_KVA="PCB KVA",
+ *__HDR_FIB="FIB",
+ *__HDR_SPLICE_ADDRESS="SPLICE ADDRESS",
+ *__HDR_ID="ID",
+ *__HDR_ENCAPS="ENCAPS",
+ *__HDR_PATH_STATE="PATH STATE",
+ *__HDR_CONN_STATE="CONN STATE",
+ *__HDR_BBLOG_STATE="BBLOG STATE",
+ *__HDR_STACK="STACK",
+ *__HDR_CC="CC";
+
struct passwd *pwd;
struct file *xf;
struct sock *s;
@@ -1598,23 +1647,23 @@ display(void)
if (!is_xo_style_encoding) {
cw = (struct col_widths) {
- .user = strlen("USER"),
+ .user = strlen(__HDR_USER),
.command = 10,
- .pid = strlen("PID"),
- .fd = strlen("FD"),
- .proto = strlen("PROTO"),
- .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
- .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
+ .pid = strlen(__HDR_PID),
+ .fd = strlen(__HDR_FD),
+ .proto = strlen(__HDR_PROTO),
+ .local_addr = opt_w ? strlen(__HDR_LOCAL_ADDRESS) : 21,
+ .foreign_addr = opt_w ? strlen(__HDR_FOREIGN_ADDRESS) : 21,
.pcb_kva = 18,
- .fib = strlen("FIB"),
- .splice_address = strlen("SPLICE ADDRESS"),
- .inp_gencnt = strlen("ID"),
- .encaps = strlen("ENCAPS"),
- .path_state = strlen("PATH STATE"),
- .conn_state = strlen("CONN STATE"),
- .bblog_state = strlen("BBLOG STATE"),
- .stack = strlen("STACK"),
- .cc = strlen("CC"),
+ .fib = strlen(__HDR_FIB),
+ .splice_address = strlen(__HDR_SPLICE_ADDRESS),
+ .inp_gencnt = strlen(__HDR_ID),
+ .encaps = strlen(__HDR_ENCAPS),
+ .path_state = strlen(__HDR_PATH_STATE),
+ .conn_state = strlen(__HDR_CONN_STATE),
+ .bblog_state = strlen(__HDR_BBLOG_STATE),
+ .stack = strlen(__HDR_STACK),
+ .cc = strlen(__HDR_CC),
};
calculate_column_widths(&cw);
} else
@@ -1625,34 +1674,34 @@ display(void)
xo_open_list("socket");
if (!opt_q) {
xo_emit("{T:/%-*s} {T:/%-*s} {T:/%*s} {T:/%*s} {T:/%-*s} "
- "{T:/%-*s} {T:/%-*s}", cw.user, "USER", cw.command,
- "COMMAND", cw.pid, "PID", cw.fd, "FD", cw.proto,
- "PROTO", cw.local_addr, "LOCAL ADDRESS",
- cw.foreign_addr, "FOREIGN ADDRESS");
+ "{T:/%-*s} {T:/%-*s}", cw.user, __HDR_USER, cw.command,
+ __HDR_COMMAND, cw.pid, __HDR_PID, cw.fd, __HDR_FD, cw.proto,
+ __HDR_PROTO, cw.local_addr, __HDR_LOCAL_ADDRESS,
+ cw.foreign_addr, __HDR_FOREIGN_ADDRESS);
if (opt_A)
- xo_emit(" {T:/%-*s}", cw.pcb_kva, "PCB KVA");
+ xo_emit(" {T:/%-*s}", cw.pcb_kva, __HDR_PCB_KVA);
if (opt_f)
/* RT_MAXFIBS is 65535. */
- xo_emit(" {T:/%*s}", cw.fib, "FIB");
+ xo_emit(" {T:/%*s}", cw.fib, __HDR_FIB);
if (opt_I)
xo_emit(" {T:/%-*s}", cw.splice_address,
- "SPLICE ADDRESS");
+ __HDR_SPLICE_ADDRESS);
if (opt_i)
- xo_emit(" {T:/%*s}", cw.inp_gencnt, "ID");
+ xo_emit(" {T:/%*s}", cw.inp_gencnt, __HDR_ID);
if (opt_U)
- xo_emit(" {T:/%*s}", cw.encaps, "ENCAPS");
+ xo_emit(" {T:/%*s}", cw.encaps, __HDR_ENCAPS);
if (opt_s) {
if (show_path_state)
xo_emit(" {T:/%-*s}", cw.path_state,
- "PATH STATE");
- xo_emit(" {T:/%-*s}", cw.conn_state, "CONN STATE");
+ __HDR_PATH_STATE);
+ xo_emit(" {T:/%-*s}", cw.conn_state, __HDR_CONN_STATE);
}
if (opt_b)
- xo_emit(" {T:/%-*s}", cw.bblog_state, "BBLOG STATE");
+ xo_emit(" {T:/%-*s}", cw.bblog_state, __HDR_BBLOG_STATE);
if (opt_S)
- xo_emit(" {T:/%-*s}", cw.stack, "STACK");
+ xo_emit(" {T:/%-*s}", cw.stack, __HDR_STACK);
if (opt_C)
- xo_emit(" {T:/%-*s}", cw.cc, "CC");
+ xo_emit(" {T:/%-*s}", cw.cc, __HDR_CC);
xo_emit("\n");
}
cap_setpassent(cappwd, 1);
@@ -1684,7 +1733,7 @@ display(void)
xo_close_instance("socket");
}
}
- if (opt_j >= 0)
+ if (!need_nosocks())
goto out;
SLIST_FOREACH(s, &nosocks, socket_list) {
if (!check_ports(s))
@@ -1775,11 +1824,44 @@ jail_getvnet(int jid)
return (vnet);
}
+/*
+ * Parse username and/or UID
+ */
+static bool
+parse_filter_user(void)
+{
+ struct passwd *pwd;
+ char *ep;
+ uid_t uid;
+ bool rv = false;
+
+ uid = (uid_t)strtol(filter_user_optarg, &ep, 10);
+
+ /* Open and/or rewind capsicumized password file */
+ cap_setpassent(cappwd, 1);
+
+ if (*ep == '\0') {
+ /* We have an UID specified, check if it's valid */
+ if ((pwd = cap_getpwuid(cappwd, uid)) == NULL)
+ goto out;
+ filter_user_uid = uid;
+ } else {
+ /* Check if we have a valid username */
+ if ((pwd = cap_getpwnam(cappwd, filter_user_optarg)) == NULL)
+ goto out;
+ filter_user_uid = pwd->pw_uid;
+ }
+
+ rv = true;
+out:
+ return (rv);
+}
+
static void
usage(void)
{
xo_error(
-"usage: sockstat [--libxo ...] [-46AbCcfIiLlnqSsUuvw] [-j jid] [-p ports]\n"
+"usage: sockstat [--libxo ...] [-46AbCcfIiLlnqSsUuvw] [-F uid/username] [-j jid] [-p ports]\n"
" [-P protocols]\n");
exit(1);
}
@@ -1789,8 +1871,8 @@ main(int argc, char *argv[])
{
cap_channel_t *capcas;
cap_net_limit_t *limit;
- const char *pwdcmds[] = { "setpassent", "getpwuid" };
- const char *pwdfields[] = { "pw_name" };
+ const char *pwdcmds[] = { "setpassent", "getpwuid", "getpwnam" };
+ const char *pwdfields[] = { "pw_name", "pw_uid" };
int protos_defined = -1;
int o, i, err;
@@ -1803,7 +1885,7 @@ main(int argc, char *argv[])
is_xo_style_encoding = true;
}
opt_j = -1;
- while ((o = getopt(argc, argv, "46AbCcfIij:Llnp:P:qSsUuvw")) != -1)
+ while ((o = getopt(argc, argv, "46AbCcF:fIij:Llnp:P:qSsUuvw")) != -1)
switch (o) {
case '4':
opt_4 = true;
@@ -1823,6 +1905,11 @@ main(int argc, char *argv[])
case 'c':
opt_c = true;
break;
+ case 'F':
+ /* Save optarg for later use when we enter capabilities mode */
+ filter_user_optarg = optarg;
+ opt_F = true;
+ break;
case 'f':
opt_f = true;
break;
@@ -1934,6 +2021,9 @@ main(int argc, char *argv[])
if (cap_pwd_limit_fields(cappwd, pwdfields, nitems(pwdfields)) < 0)
xo_err(1, "Unable to apply pwd commands limits");
+ if (opt_F && !parse_filter_user())
+ xo_errx(1, "Invalid username or UID specified");
+
if ((!opt_4 && !opt_6) && protos_defined != -1)
opt_4 = opt_6 = true;
if (!opt_4 && !opt_6 && !opt_u)