Home | History | Annotate | Download | only in servinfo
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * This file delivers /usr/lib/servinfo which provides description for
     29  * IANA and running RPC services. Given a IANA name or RPC program name
     30  * or number, the program uses getservbyname(3SOCKET) and rpcbind(3NSL)
     31  * to obtain port and proto information for the specified service.
     32  */
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <strings.h>
     37 #include <netconfig.h>
     38 #include <netdb.h>
     39 #include <rpc/rpc.h>
     40 #include <rpc/rpcent.h>
     41 #include <sys/types.h>
     42 #include <netinet/in.h>
     43 #include <netdir.h>
     44 #include <inttypes.h>
     45 #include <limits.h>
     46 #include <libintl.h>
     47 #include <locale.h>
     48 
     49 #ifndef	TEXT_DOMAIN
     50 #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
     51 #endif /* TEXT_DOMAIN */
     52 
     53 #define	TCP	"tcp"
     54 #define	TCP6	"tcp6"
     55 #define	UDP	"udp"
     56 #define	UDP6	"udp6"
     57 
     58 #define	DEFAULT 0x1
     59 #define	PORT	0x2
     60 #define	PROTO	0x4
     61 
     62 #define	NETID_LEN	12 /* length for a netid or 2^16 port value */
     63 
     64 static void
     65 usage(char *arg0)
     66 {
     67 	(void) fprintf(stderr, gettext("Usage: %s [-R] [-Pp] [-tu[6]] "
     68 	    "-s service_name\n"), arg0);
     69 }
     70 
     71 static rpcport_t
     72 uaddr2port(char *addr)
     73 {
     74 	rpcport_t port = 0;
     75 	char *dot, *p;
     76 
     77 	if ((dot = strrchr(addr, '.')) == 0) {
     78 		return (0);
     79 	} else {
     80 		if (dot == addr)
     81 			return (0);
     82 
     83 		p = dot - 1;
     84 		while (*p != '.') {
     85 			/*
     86 			 * If the first dot hasn't been seen, it's a
     87 			 * malformed universal address.
     88 			 */
     89 			if (p == addr)
     90 				return (0);
     91 			p--;
     92 		}
     93 
     94 		port = strtol(p + 1, &dot, 10) << 8;
     95 		port = port | strtol(dot + 1, (char **)NULL, 10);
     96 	}
     97 
     98 	return (port);
     99 }
    100 
    101 static int
    102 svc_getrpcinfo(char *sname, char *sproto, int options)
    103 {
    104 	struct netconfig *nconf;
    105 	struct rpcblist *blist;
    106 	int	prognum = -1;
    107 	rpcport_t rpc_port;
    108 	struct rpcent  rentry;
    109 	struct rpcent  *rpc;
    110 	char line[LINE_MAX] = "";
    111 	int  line_len = LINE_MAX - 1;
    112 	char buf[NETID_LEN];
    113 
    114 	prognum = atoi(sname);
    115 	if (prognum > 0)
    116 		rpc = (struct rpcent *)getrpcbynumber(prognum);
    117 	else
    118 		rpc = (struct rpcent *)getrpcbyname(sname);
    119 
    120 	/*
    121 	 * If an entry doesn't exist, it could be a running program
    122 	 * without a registered RPC entry.
    123 	 */
    124 	if (rpc == NULL) {
    125 		if (prognum <= 0) {
    126 			(void) fprintf(stderr,
    127 			    gettext("Can't get rpc entry\n"));
    128 			return (1);
    129 		}
    130 
    131 		rpc = &rentry;
    132 		rpc->r_number = prognum;
    133 		rpc->r_name = sname;
    134 	}
    135 
    136 	if (setnetconfig() == NULL) {
    137 		(void) fprintf(stderr, gettext("setnetconfig failed\n"));
    138 		return (1);
    139 	}
    140 
    141 	if ((nconf = getnetconfigent(TCP)) == NULL) {
    142 		(void) fprintf(stderr, gettext("getnetconfig failed\n"));
    143 		return (1);
    144 	}
    145 
    146 	if ((blist = (struct rpcblist *)rpcb_getmaps(nconf, "localhost"))
    147 	    == NULL) {
    148 		(void) fprintf(stderr,
    149 		    gettext("Failed: rpcb_getmaps failed\n"));
    150 		return (1);
    151 	}
    152 
    153 	for (; blist != NULL; blist = blist->rpcb_next) {
    154 		if (blist->rpcb_map.r_prog != rpc->r_number)
    155 			continue;
    156 
    157 		if (sproto) {
    158 			if (strcmp(blist->rpcb_map.r_netid, sproto) != 0)
    159 				continue;
    160 		} else {
    161 			if (strcmp(blist->rpcb_map.r_netid, UDP) &&
    162 			    strcmp(blist->rpcb_map.r_netid, UDP6) &&
    163 			    strcmp(blist->rpcb_map.r_netid, TCP) &&
    164 			    strcmp(blist->rpcb_map.r_netid, TCP6))
    165 				continue;
    166 		}
    167 		rpc_port = uaddr2port(blist->rpcb_map.r_addr);
    168 
    169 		if (options & DEFAULT) {
    170 			(void) printf("Program %ld\n", blist->rpcb_map.r_prog);
    171 			(void) printf("Protocol %s\n", blist->rpcb_map.r_netid);
    172 			(void) printf("Port %ld\n", rpc_port);
    173 			(void) printf("Version %ld\n", blist->rpcb_map.r_vers);
    174 			(void) printf("Name %s\n", rpc->r_name);
    175 
    176 		} else if (options & PROTO) {
    177 			if (strstr(line, blist->rpcb_map.r_netid))
    178 				continue;
    179 
    180 			(void) snprintf(buf, sizeof (buf), "%5s ",
    181 			    blist->rpcb_map.r_netid);
    182 
    183 			if (strlen(buf) > line_len)
    184 				continue;
    185 
    186 			line_len = line_len - strlen(buf);
    187 			(void) strlcat(line, buf, sizeof (line));
    188 		} else {
    189 			(void) snprintf(buf, sizeof (buf), "%-7ld ", rpc_port);
    190 
    191 			if (strstr(line, buf) || strlen(buf) > line_len)
    192 				continue;
    193 
    194 			line_len = line_len - strlen(buf);
    195 			(void) strlcat(line, buf, sizeof (line));
    196 		}
    197 	}
    198 
    199 	/*
    200 	 * Print the concatenated output if options is PROTO or PORT.
    201 	 */
    202 	if (options & (PROTO | PORT))
    203 		(void) puts(line);
    204 
    205 	return (0);
    206 }
    207 
    208 int
    209 main(int argc, char *argv[])
    210 {
    211 	struct servent *service;
    212 	char *sname = NULL;
    213 	char *sproto = NULL;
    214 	int options = DEFAULT;
    215 	int c, isrpc = 0, v6_flag = 0;
    216 
    217 	(void) setlocale(LC_ALL, "");
    218 	(void) textdomain(TEXT_DOMAIN);
    219 
    220 	optind = 1;
    221 	opterr = 1;
    222 	while ((c = getopt(argc, argv, "s:PplRtu6?")) != -1) {
    223 		switch (c) {
    224 		case 's':
    225 			sname = optarg;
    226 			break;
    227 		case 't':
    228 			sproto = TCP;
    229 			break;
    230 		case 'u':
    231 			sproto = UDP;
    232 			break;
    233 		case '6':
    234 			v6_flag = 1;
    235 			break;
    236 		case 'P':
    237 			options = PROTO;
    238 			break;
    239 		case 'p':
    240 			options = PORT;
    241 			break;
    242 		case 'R':
    243 			isrpc = 1;
    244 			break;
    245 		default:
    246 			usage(argv[0]);
    247 			return (1);
    248 		}
    249 	}
    250 	if (sname == NULL) {
    251 		usage(argv[0]);
    252 		return (1);
    253 	}
    254 
    255 	/*
    256 	 * Specified service is an RPC service.
    257 	 */
    258 	if (isrpc) {
    259 		if (sproto && v6_flag) {
    260 			if (strcmp(sproto, TCP) == 0)
    261 				sproto = TCP6;
    262 			if (strcmp(sproto, UDP) == 0)
    263 				sproto = UDP6;
    264 		}
    265 
    266 		return (svc_getrpcinfo(sname, sproto, options));
    267 	}
    268 
    269 	if ((service = getservbyname(sname, sproto)) == NULL) {
    270 		(void) fprintf(stderr, gettext(
    271 		    "Failed to get information for %s\n"), sname);
    272 		return (1);
    273 	}
    274 
    275 	if (options & DEFAULT) {
    276 		(void) printf("Name %s\n", service->s_name);
    277 		(void) printf("Protocol %s\n", service->s_proto);
    278 		(void) printf("Port %d\n", htons(service->s_port));
    279 	} else if (options & PROTO)
    280 		(void) printf("%s\n", service->s_proto);
    281 	else
    282 		(void) printf("%d\n", htons(service->s_port));
    283 
    284 	return (0);
    285 }
    286