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