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