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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 /* 29 * Portions of this source code were derived from Berkeley 30 * 4.3 BSD under license from the Regents of the University of 31 * California. 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 /* 37 * svc_simple.c 38 * Simplified front end to rpc. 39 */ 40 41 /* 42 * This interface creates a virtual listener for all the services 43 * started thru rpc_reg(). It listens on the same endpoint for 44 * all the services and then executes the corresponding service 45 * for the given prognum and procnum. 46 */ 47 48 #include "mt.h" 49 #include "rpc_mt.h" 50 #include <errno.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <rpc/rpc.h> 55 #include <sys/types.h> 56 #include <syslog.h> 57 #include <rpc/nettype.h> 58 59 extern int use_portmapper; 60 61 static struct proglst { 62 char *(*p_progname)(); 63 rpcprog_t p_prognum; 64 rpcvers_t p_versnum; 65 rpcproc_t p_procnum; 66 SVCXPRT *p_transp; 67 char *p_netid; 68 char *p_xdrbuf; 69 int p_recvsz; 70 xdrproc_t p_inproc, p_outproc; 71 struct proglst *p_nxt; 72 } *proglst; 73 74 static void universal(); 75 76 static const char rpc_reg_err[] = "%s: %s"; 77 static const char rpc_reg_msg[] = "rpc_reg: "; 78 static const char __reg_err1[] = "can't find appropriate transport"; 79 static const char __reg_err3[] = "unsupported transport size"; 80 static const char __no_mem_str[] = "out of memory"; 81 /* 82 * For simplified, easy to use kind of rpc interfaces. 83 * nettype indicates the type of transport on which the service will be 84 * listening. Used for conservation of the system resource. Only one 85 * handle is created for all the services (actually one of each netid) 86 * and same xdrbuf is used for same netid. The size of the arguments 87 * is also limited by the recvsize for that transport, even if it is 88 * a COTS transport. This may be wrong, but for cases like these, they 89 * should not use the simplified interfaces like this. 90 */ 91 92 int 93 rpc_reg(const rpcprog_t prognum, const rpcvers_t versnum, 94 const rpcproc_t procnum, char *(*progname)(), const xdrproc_t inproc, 95 const xdrproc_t outproc, const char *nettype) 96 { 97 struct netconfig *nconf; 98 int done = FALSE; 99 void *handle; 100 extern mutex_t proglst_lock; 101 102 if (procnum == NULLPROC) { 103 (void) syslog(LOG_ERR, (const char *) "%s: %s %d", 104 rpc_reg_msg, 105 (const char *) "can't reassign procedure number %d", 106 NULLPROC); 107 return (-1); 108 } 109 110 if (nettype == NULL) 111 nettype = "netpath"; /* The default behavior */ 112 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 113 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err1); 114 return (-1); 115 } 116 /* VARIABLES PROTECTED BY proglst_lock: proglst */ 117 (void) mutex_lock(&proglst_lock); 118 while (nconf = __rpc_getconf(handle)) { 119 struct proglst *pl; 120 SVCXPRT *svcxprt; 121 int madenow; 122 uint_t recvsz; 123 char *xdrbuf; 124 char *netid; 125 126 madenow = FALSE; 127 svcxprt = NULL; 128 for (pl = proglst; pl; pl = pl->p_nxt) 129 if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { 130 svcxprt = pl->p_transp; 131 xdrbuf = pl->p_xdrbuf; 132 recvsz = pl->p_recvsz; 133 netid = pl->p_netid; 134 break; 135 } 136 137 if (svcxprt == NULL) { 138 struct t_info tinfo; 139 140 svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 141 if (svcxprt == NULL) 142 continue; 143 if (t_getinfo(svcxprt->xp_fd, &tinfo) == -1) { 144 char errorstr[100]; 145 146 __tli_sys_strerror(errorstr, sizeof (errorstr), 147 t_errno, errno); 148 (void) syslog(LOG_ERR, "%s : %s : %s", 149 rpc_reg_msg, "t_getinfo failed", 150 errorstr); 151 SVC_DESTROY(svcxprt); 152 continue; 153 } 154 if ((recvsz = __rpc_get_t_size(0, tinfo.tsdu)) == 0) { 155 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 156 __reg_err3); 157 SVC_DESTROY(svcxprt); 158 continue; 159 } 160 if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || 161 ((netid = strdup(nconf->nc_netid)) == NULL)) { 162 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 163 __no_mem_str); 164 SVC_DESTROY(svcxprt); 165 break; 166 } 167 madenow = TRUE; 168 } 169 /* 170 * Check if this (program, version, netid) had already been 171 * registered. The check may save a few RPC calls to rpcbind 172 */ 173 for (pl = proglst; pl; pl = pl->p_nxt) 174 if ((pl->p_prognum == prognum) && 175 (pl->p_versnum == versnum) && 176 (strcmp(pl->p_netid, netid) == 0)) 177 break; 178 if (pl == NULL) { /* Not yet */ 179 /* 180 * Note that if we're using a portmapper 181 * instead of rpcbind then we can't do an 182 * unregister operation here. 183 * 184 * The reason is that the portmapper unset 185 * operation removes all the entries for a 186 * given program/version regardelss of 187 * transport protocol. 188 * 189 * The caller of this routine needs to ensure 190 * that __pmap_unset() has been called for all 191 * program/version service pairs they plan 192 * to support before they start registering 193 * each program/version/protocol triplet. 194 */ 195 if (!use_portmapper) 196 (void) rpcb_unset(prognum, versnum, nconf); 197 } else { 198 /* so that svc_reg does not call rpcb_set() */ 199 nconf = NULL; 200 } 201 202 if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { 203 (void) syslog(LOG_ERR, 204 "%s couldn't register prog %d vers %d for %s", 205 rpc_reg_msg, prognum, versnum, netid); 206 if (madenow) { 207 SVC_DESTROY(svcxprt); 208 free(xdrbuf); 209 free(netid); 210 } 211 continue; 212 } 213 214 pl = malloc(sizeof (struct proglst)); 215 if (pl == NULL) { 216 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 217 __no_mem_str); 218 if (madenow) { 219 SVC_DESTROY(svcxprt); 220 free(xdrbuf); 221 free(netid); 222 } 223 break; 224 } 225 pl->p_progname = progname; 226 pl->p_prognum = prognum; 227 pl->p_versnum = versnum; 228 pl->p_procnum = procnum; 229 pl->p_inproc = inproc; 230 pl->p_outproc = outproc; 231 pl->p_transp = svcxprt; 232 pl->p_xdrbuf = xdrbuf; 233 pl->p_recvsz = recvsz; 234 pl->p_netid = netid; 235 pl->p_nxt = proglst; 236 proglst = pl; 237 done = TRUE; 238 } 239 __rpc_endconf(handle); 240 (void) mutex_unlock(&proglst_lock); 241 242 if (done == FALSE) { 243 (void) syslog(LOG_ERR, 244 (const char *) "%s cant find suitable transport for %s", 245 rpc_reg_msg, nettype); 246 return (-1); 247 } 248 return (0); 249 } 250 251 /* 252 * The universal handler for the services registered using registerrpc. 253 * It handles both the connectionless and the connection oriented cases. 254 */ 255 256 static void 257 universal(struct svc_req *rqstp, SVCXPRT *transp) 258 { 259 rpcprog_t prog; 260 rpcvers_t vers; 261 rpcproc_t proc; 262 char *outdata; 263 char *xdrbuf; 264 struct proglst *pl; 265 extern mutex_t proglst_lock; 266 267 /* 268 * enforce "procnum 0 is echo" convention 269 */ 270 if (rqstp->rq_proc == NULLPROC) { 271 if (svc_sendreply(transp, (xdrproc_t)xdr_void, NULL) == FALSE) { 272 (void) syslog(LOG_ERR, 273 (const char *) "svc_sendreply failed"); 274 } 275 return; 276 } 277 prog = rqstp->rq_prog; 278 vers = rqstp->rq_vers; 279 proc = rqstp->rq_proc; 280 (void) mutex_lock(&proglst_lock); 281 for (pl = proglst; pl; pl = pl->p_nxt) { 282 if (pl->p_prognum == prog && pl->p_procnum == proc && 283 pl->p_versnum == vers && 284 (strcmp(pl->p_netid, transp->xp_netid) == 0)) { 285 /* decode arguments into a CLEAN buffer */ 286 xdrbuf = pl->p_xdrbuf; 287 /* Zero the arguments: reqd ! */ 288 (void) memset(xdrbuf, 0, pl->p_recvsz); 289 /* 290 * Assuming that sizeof (xdrbuf) would be enough 291 * for the arguments; if not then the program 292 * may bomb. BEWARE! 293 */ 294 if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { 295 svcerr_decode(transp); 296 (void) mutex_unlock(&proglst_lock); 297 return; 298 } 299 outdata = (*(pl->p_progname))(xdrbuf); 300 if (outdata == NULL && 301 pl->p_outproc != (xdrproc_t)xdr_void) { 302 /* there was an error */ 303 (void) mutex_unlock(&proglst_lock); 304 return; 305 } 306 if (!svc_sendreply(transp, pl->p_outproc, outdata)) { 307 (void) syslog(LOG_ERR, (const char *) 308 "rpc: rpc_reg trouble replying to prog %d vers %d", 309 prog, vers); 310 (void) mutex_unlock(&proglst_lock); 311 return; 312 } 313 /* free the decoded arguments */ 314 (void) svc_freeargs(transp, pl->p_inproc, xdrbuf); 315 (void) mutex_unlock(&proglst_lock); 316 return; 317 } 318 } 319 (void) mutex_unlock(&proglst_lock); 320 /* This should never happen */ 321 (void) syslog(LOG_ERR, (const char *) 322 "rpc: rpc_reg: never registered prog %d vers %d", 323 prog, vers); 324 } 325