diff options
Diffstat (limited to 'usr.bin/sockstat/main.c')
| -rw-r--r-- | usr.bin/sockstat/main.c | 170 | 
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)  | 
