/* * Create a client handle for memory based rpc. */ CLIENT * clnt_raw_create(const rpcprog_t prog, const rpcvers_t vers) { struct clnt_raw_private *clp; struct rpc_msg call_msg; XDR xdrs; CLIENT *client; uint_t start; /* VARIABLES PROTECTED BY clntraw_lock: clp */ (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; if (clp != NULL) { (void) mutex_unlock(&clntraw_lock); return (&clp->client_object); } clp = calloc(1, sizeof (*clp)); if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); return (NULL); } clp->raw_netbuf = &_rawcomnetbuf; /* * pre-serialize the static part of the call msg and stash it away */ call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; xdrmem_create(&xdrs, clp->mashl_callmsg, sizeof (clp->mashl_callmsg), XDR_ENCODE); start = XDR_GETPOS(&xdrs); if (!xdr_callhdr(&xdrs, &call_msg)) { free(clp); (void) syslog(LOG_ERR, "clnt_raw_create: Fatal header serialization error"); (void) mutex_unlock(&clntraw_lock); return (NULL); } clp->mcnt = XDR_GETPOS(&xdrs) - start; XDR_DESTROY(&xdrs); /* * create client handle */ client = &clp->client_object; client->cl_ops = clnt_raw_ops(); client->cl_auth = authnone_create(); clnt_raw_private = clp; (void) mutex_unlock(&clntraw_lock); return (client); }
/* * Find the mapped port for program,version. * Calls the pmap service remotely to do the lookup. * Returns 0 if no map exists. */ u_short pmap_getport(struct sockaddr_in *address, u_long program, u_long version, u_int protocol) { struct pmap parms; u_short port = 0; int sock = -1; CLIENT *client; AUTH *auth; assert(address != NULL); address->sin_port = htons(PMAPPORT); client = clntudp_nbufcreate(address, PMAPPROG, PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); if (client != NULL) { auth = authnone_create(); /* idempotent */ parms.pm_prog = program; parms.pm_vers = version; parms.pm_prot = protocol; parms.pm_port = 0; /* not needed or used */ if (CLNT_CALL (client, auth, (rpcproc_t) PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap, &parms, (xdrproc_t) xdr_u_short, &port, tottimeout) != RPC_SUCCESS) { rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); } else if (port == 0) { rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; } CLNT_DESTROY(client); } address->sin_port = 0; return (port); }
int main(int argn, char *argc[]) { //Program parameters : argc[1] : HostName or Host IP // argc[2] : Server Program Number // other arguments depend on test case //run_mode can switch into stand alone program or program launch by shell script //1 : stand alone, debug mode, more screen information //0 : launch by shell script as test case, only one printf -> result status int run_mode = 0; int test_status = 1; //Default test result set to FAILED int progNum = atoi(argc[2]); AUTH *authNone = NULL; authNone = authnone_create(); //Call routine auth_destroy(authNone); //If we are here, macro call was successful test_status = 0; //This last printf gives the result status to the tests suite //normally should be 0: test has passed or 1: test has failed printf("%d\n", test_status); return test_status; }
bool nsm_connect() { struct utsname utsname; if (nsm_clnt != NULL) return true; if (uname(&utsname) == -1) { LogCrit(COMPONENT_NLM, "uname failed with errno %d (%s)", errno, strerror(errno)); return false; } nodename = gsh_strdup(utsname.nodename); if (nodename == NULL) { LogCrit(COMPONENT_NLM, "failed to allocate memory for nodename"); return false; } nsm_clnt = gsh_clnt_create("localhost", SM_PROG, SM_VERS, "tcp"); if (nsm_clnt == NULL) { LogCrit(COMPONENT_NLM, "failed to connect to statd"); gsh_free(nodename); nodename = NULL; } /* split auth (for authnone, idempotent) */ nsm_auth = authnone_create(); return nsm_clnt != NULL; }
struct client * clnttcp_create(struct sockaddr_in *raddr, uint32_t prognum, uint32_t versnum, int *psock, unsigned int sendsz, unsigned int recvsz) { struct client *clnt; struct auth *ath; int sock; struct sockaddr_in sin; assert((raddr != NULL) && (psock != NULL)); clnt = clnt_alloc(), ath = authnone_create(); if ((clnt == NULL) || (ath == NULL)) { LOG_ERROR("clnttcp_create", "clnt_alloc failed"); rpc_create_error.stat = RPC_SYSTEMERROR; rpc_create_error.err.extra.error = ENOMEM; goto exit_with_error; } memcpy(&sin, raddr, sizeof *raddr); if (sin.sin_port == 0) { sin.sin_port = htons(pmap_getport(raddr, prognum, versnum, IPPROTO_TCP)); if (sin.sin_port == 0) { goto exit_with_error; } } assert(*psock < 0); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if ((sock < 0) || (connect(sock, (struct sockaddr *)&sin, sizeof sin) < 0)) { LOG_ERROR("clnttcp_create", "socket or connect error"); rpc_create_error.stat = RPC_SYSTEMERROR; rpc_create_error.err.extra.error = errno; close(sock); goto exit_with_error; } /* Fill client structure */ clnt->ops = &clnttcp_ops; clnt->sock = sock; clnt->ath = ath; clnt->prognum = prognum; clnt->versnum = versnum; clnt->extra.tcp.sendsz = sendsz; clnt->extra.tcp.recvsz = recvsz; *psock = sock; return clnt; exit_with_error: auth_destroy(ath); clnt_free(clnt); return NULL; }
/* * Create a client handle for memory based rpc. */ CLIENT * clnt_raw_create(rpcprog_t prog, rpcvers_t vers) { struct clntraw_private *clp; struct rpc_msg call_msg; XDR *xdrs; CLIENT *client; mutex_lock(&clntraw_lock); if ((clp = clntraw_private) == NULL) { clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); if (clp == NULL) { mutex_unlock(&clntraw_lock); return NULL; } if (__rpc_rawcombuf == NULL) __rpc_rawcombuf = (char *)calloc(UDPMSGSIZE, sizeof (char)); clp->_raw_buf = __rpc_rawcombuf; clntraw_private = clp; } xdrs = &clp->xdr_stream; client = &clp->client_object; /* * pre-serialize the static part of the call msg and stash it away */ call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; /* XXX: prog and vers have been long historically :-( */ call_msg.rm_call.cb_prog = (u_int32_t)prog; call_msg.rm_call.cb_vers = (u_int32_t)vers; xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(xdrs, &call_msg)) warnx("clntraw_create - Fatal header serialization error."); clp->mcnt = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); /* * Set xdrmem for client/server shared buffer */ xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); /* * create client handle */ client->cl_ops = clnt_raw_ops(); client->cl_auth = authnone_create(); mutex_unlock(&clntraw_lock); return (client); }
/* * Create a client handle for memory based rpc. */ CLIENT * clntraw_create(u_long prog, u_long vers) { struct clntraw_private *clp = clntraw_private; struct rpc_msg call_msg; XDR *xdrs; CLIENT *client; if (clp == NULL) { clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); if (clp == NULL) goto fail; clntraw_private = clp; } xdrs = &clp->xdr_stream; client = &clp->client_object; /* * pre-serialize the static part of the call msg and stash it away */ call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr(xdrs, &call_msg)) goto fail; clp->mcnt = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); /* * Set xdrmem for client/server shared buffer */ xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); /* * create client handle */ client->cl_ops = &client_ops; client->cl_auth = authnone_create(); if (client->cl_auth == NULL) goto fail; return (client); fail: mem_free((caddr_t)clntraw_private, sizeof(clntraw_private)); clntraw_private = NULL; rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; return (NULL); }
CLIENT * clnt_reconnect_create( struct netconfig *nconf, /* network type */ struct sockaddr *svcaddr, /* servers address */ rpcprog_t program, /* program number */ rpcvers_t version, /* version number */ size_t sendsz, /* buffer recv size */ size_t recvsz) /* buffer send size */ { CLIENT *cl = NULL; /* client handle */ struct rc_data *rc = NULL; /* private data */ if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } cl = mem_alloc(sizeof (CLIENT)); rc = mem_alloc(sizeof (*rc)); mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF); (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len); rc->rc_nconf = nconf; rc->rc_prog = program; rc->rc_vers = version; rc->rc_sendsz = sendsz; rc->rc_recvsz = recvsz; rc->rc_timeout.tv_sec = -1; rc->rc_timeout.tv_usec = -1; rc->rc_retry.tv_sec = 3; rc->rc_retry.tv_usec = 0; rc->rc_retries = INT_MAX; rc->rc_privport = FALSE; rc->rc_waitchan = "rpcrecv"; rc->rc_intr = 0; rc->rc_connecting = FALSE; rc->rc_closed = FALSE; rc->rc_ucred = crdup(curthread->td_ucred); rc->rc_client = NULL; cl->cl_refs = 1; cl->cl_ops = &clnt_reconnect_ops; cl->cl_private = (caddr_t)(void *)rc; cl->cl_auth = authnone_create(); cl->cl_tp = NULL; cl->cl_netid = NULL; return (cl); }
void * nsm_notify_1(notify *argp, CLIENT *clnt) { static char clnt_res; AUTH *nsm_auth; nsm_auth = authnone_create(); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, nsm_auth, SM_NOTIFY, (xdrproc_t) xdr_notify, (caddr_t) argp, (xdrproc_t) xdr_void, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return NULL; } return (void *)&clnt_res; }
/* * Create a client handle for memory based rpc. */ CLIENT * clntraw_create (u_long prog, u_long vers) { struct clntraw_private_s *clp = clntraw_private; struct rpc_msg call_msg; XDR *xdrs; CLIENT *client; if (clp == 0) { clp = (struct clntraw_private_s *) calloc (1, sizeof (*clp)); if (clp == 0) return (0); clntraw_private = clp; } xdrs = &clp->xdr_stream; client = &clp->client_object; /* * pre-serialize the static part of the call msg and stash it away */ call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; xdrmem_create (xdrs, clp->mashl_callmsg.msg, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (xdrs, &call_msg)) { perror (_ ("clnt_raw.c: fatal header serialization error")); } clp->mcnt = XDR_GETPOS (xdrs); XDR_DESTROY (xdrs); /* * Set xdrmem for client/server shared buffer */ xdrmem_create (xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); /* * create client handle */ client->cl_ops = (struct clnt_ops *) &client_ops; client->cl_auth = authnone_create (); return client; }
int main(void) { //Program parameters : argc[1] : HostName or Host IP // argc[2] : Server Program Number // other arguments depend on test case int test_status = 1; //Default test result set to FAILED AUTH *authNone = NULL; authNone = authnone_create(); //If we are here, macro call was successful test_status = ((AUTH *) authNone != NULL) ? 0 : 1; //This last printf gives the result status to the tests suite //normally should be 0: test has passed or 1: test has failed printf("%d\n", test_status); return test_status; }
/* * pmapper remote-call-service interface. * This routine is used to call the pmapper remote call service * which will look up a service program in the port maps, and then * remotely call that routine with the given parameters. This allows * programs to do a lookup and call in one step. */ enum clnt_stat pmap_rmtcall(struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc, xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp, struct timeval tout, u_long *port_ptr) { int sock = -1; CLIENT *client; AUTH *auth; struct rmtcallargs a; struct rmtcallres r; enum clnt_stat stat; assert(addr != NULL); assert(port_ptr != NULL); addr->sin_port = htons(PMAPPORT); client = clntudp_ncreate(addr, PMAPPROG, PMAPVERS, timeout, &sock); if (client != NULL) { auth = authnone_create(); a.prog = prog; a.vers = vers; a.proc = proc; a.args_ptr = argsp; a.xdr_args = xdrargs; r.port_ptr = port_ptr; r.results_ptr = resp; r.xdr_results = xdrres; stat = CLNT_CALL(client, auth, (rpcproc_t) PMAPPROC_CALLIT, (xdrproc_t) xdr_rmtcall_args, &a, (xdrproc_t) xdr_rmtcallres, &r, tout); CLNT_DESTROY(client); } else { stat = RPC_FAILED; } addr->sin_port = 0; return (stat); }
/* libc_hidden_proto(clntudp_bufcreate) */ CLIENT * clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clntudp_create: out of memory\n")); else #endif (void) fputs (_("clntudp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { int dontblock = 1; *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); /* the sockets rpc controls are non-blocking */ (void) ioctl (*sockp, FIONBIO, (char *) &dontblock); #ifdef IP_RECVERR { int on = 1; setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
/* * Door IPC based client creation routine. * * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * sendsz is the maximum allowable packet size that can be sent. * 0 will cause default to be used. */ CLIENT * clnt_door_create(const rpcprog_t program, const rpcvers_t version, const uint_t sendsz) { CLIENT *cl = NULL; /* client handle */ struct cu_data *cu = NULL; /* private data */ struct rpc_msg call_msg; char rendezvous[64]; int did; struct door_info info; XDR xdrs; struct timeval now; uint_t ssz; (void) sprintf(rendezvous, RPC_DOOR_RENDEZVOUS, (int)program, (int)version); if ((did = open(rendezvous, O_RDONLY, 0)) < 0) { rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; rpc_createerr.cf_error.re_errno = errno; rpc_createerr.cf_error.re_terrno = 0; return (NULL); } if (door_info(did, &info) < 0 || (info.di_attributes & DOOR_REVOKED)) { (void) close(did); rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; rpc_createerr.cf_error.re_errno = errno; rpc_createerr.cf_error.re_terrno = 0; return (NULL); } /* * Determine send size */ if (sendsz < __rpc_min_door_buf_size) ssz = __rpc_default_door_buf_size; else ssz = RNDUP(sendsz); if ((cl = malloc(sizeof (CLIENT))) == NULL || (cu = malloc(sizeof (*cu))) == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto err; } /* * Precreate RPC header for performance reasons. */ (void) gettimeofday(&now, NULL); call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&xdrs, cu->cu_header, sizeof (cu->cu_header), XDR_ENCODE); if (!xdr_callhdr(&xdrs, &call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; rpc_createerr.cf_error.re_errno = 0; goto err; } cu->cu_xdrpos = XDR_GETPOS(&xdrs); cu->cu_sendsz = ssz; cu->cu_fd = did; cu->cu_closeit = TRUE; cl->cl_ops = clnt_door_ops(); cl->cl_private = (caddr_t)cu; cl->cl_auth = authnone_create(); cl->cl_tp = strdup(rendezvous); if (cl->cl_tp == NULL) { syslog(LOG_ERR, "clnt_door_create: strdup failed"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto err; } cl->cl_netid = strdup("door"); if (cl->cl_netid == NULL) { syslog(LOG_ERR, "clnt_door_create: strdup failed"); if (cl->cl_tp) free(cl->cl_tp); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto err; } return (cl); err: rpc_createerr.cf_error.re_terrno = 0; if (cl) { free(cl); if (cu) free(cu); } (void) close(did); return (NULL); }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmition occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT *clntudp_bufcreate(struct sockaddr_in *raddr, unsigned long program, unsigned long version, struct timeval wait, int *sockp, unsigned int sendsz, unsigned int recvsz) { CLIENT *cl; register struct cu_data *cu = NULL; struct rpc_msg call_msg; static int xid_count = 0; cl = (CLIENT *) rt_malloc (sizeof(CLIENT)); if (cl == NULL) { rt_kprintf("clntudp_create: out of memory\n"); goto fooy; } sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) rt_malloc (sizeof(*cu) + sendsz + recvsz); if (cu == NULL) { rt_kprintf("clntudp_create: out of memory\n"); goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { unsigned short port; if ((port = pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons(port); } cl->cl_ops = &udp_ops; cl->cl_private = (char*) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof(cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = ((unsigned long)rt_thread_self()) ^ ((unsigned long)rt_tick_get()) ^ (xid_count++); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); if (*sockp < 0) { int dontblock = 1; *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { rt_kprintf("create socket error\n"); goto fooy; } cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create(); return (cl); fooy: if (cu) rt_free(cu); if (cl) rt_free(cl); return ((CLIENT *) NULL); }
/* * client mooshika create */ CLIENT * clnt_msk_create(msk_trans_t *trans, /* init but NOT connect()ed descriptor */ rpcprog_t program, /* program number */ rpcvers_t version, /* version number */ u_int credits) /* credits = number of parallel messages */ { CLIENT *cl = NULL; /* client handle */ struct cx_data *cx = NULL; /* private data */ struct cm_data *cm = NULL; struct timeval now; if (!trans || trans->state != MSK_INIT) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; /* FIXME, add a warnx? */ rpc_createerr.cf_error.re_errno = 0; return (NULL); } /* * Find the receive and the send size */ // u_int sendsz = 8*1024; // u_int recvsz = 4*8*1024; u_int sendsz = 1024; u_int recvsz = 1024; if (credits == 0) credits = 10; if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) goto err1; /* * Should be multiple of 4 for XDR. */ cx = alloc_cx_data(CX_MSK_DATA, sendsz, recvsz); if (cx == NULL) goto err1; cm = CM_DATA(cx); /* Other values can also be set through clnt_control() */ cm->trans = trans; cm->cm_wait.tv_sec = 15; /* heuristically chosen */ cm->cm_wait.tv_usec = 0; (void) gettimeofday(&now, NULL); cm->call_msg.rm_xid = __RPC_GETXID(&now); cm->call_msg.rm_call.cb_prog = program; cm->call_msg.rm_call.cb_vers = version; msk_connect(trans); xdrmsk_create(&cm->cm_xdrs, trans, sendsz, recvsz, credits, NULL, NULL); msk_finalize_connect(trans); /* * By default, closeit is always FALSE. It is users responsibility * to do a close on it, else the user may use clnt_control * to let clnt_destroy do it for him/her. */ cm->cm_closeit = FALSE; cl->cl_ops = clnt_msk_ops(); cl->cl_private = (caddr_t)(void *) cx; cl->cl_auth = authnone_create(); cl->cl_tp = NULL; cl->cl_netid = NULL; return (cl); err1: __warnx("clnt_msk_create: out of memory"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; if (cl) { mem_free(cl, sizeof (CLIENT)); if (cx) free_cx_data(cx); } return (NULL); }
/* * Create a client handle for a connection. * Default options are set, which the user can change using clnt_control()'s. * The rpc/vc package does buffering similar to stdio, so the client * must pick send and receive buffer sizes, 0 => use the default. * NB: fd is copied into a private area. * NB: The rpch->cl_auth is set null authentication. Caller may wish to * set this something more useful. * * fd should be an open socket */ CLIENT * clnt_vc_create( int fd, const struct netbuf *raddr, rpcprog_t prog, rpcvers_t vers, u_int sendsz, u_int recvsz ) { CLIENT *h; struct ct_data *ct = NULL; struct rpc_msg call_msg; #ifdef _REENTRANT sigset_t mask; #endif sigset_t newmask; struct sockaddr_storage ss; socklen_t slen; struct __rpc_sockinfo si; _DIAGASSERT(raddr != NULL); h = mem_alloc(sizeof(*h)); if (h == NULL) { warnx("clnt_vc_create: out of memory"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } ct = mem_alloc(sizeof(*ct)); if (ct == NULL) { warnx("clnt_vc_create: out of memory"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } __clnt_sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); #ifdef _REENTRANT mutex_lock(&clnt_fd_lock); if (vc_fd_locks == NULL) { size_t cv_allocsz, fd_allocsz; int dtbsize = __rpc_dtbsize(); fd_allocsz = dtbsize * sizeof (int); vc_fd_locks = mem_alloc(fd_allocsz); if (vc_fd_locks == NULL) { goto blooy; } else memset(vc_fd_locks, '\0', fd_allocsz); _DIAGASSERT(vc_cv == NULL); cv_allocsz = dtbsize * sizeof (cond_t); vc_cv = mem_alloc(cv_allocsz); if (vc_cv == NULL) { mem_free(vc_fd_locks, fd_allocsz); vc_fd_locks = NULL; goto blooy; } else { int i; for (i = 0; i < dtbsize; i++) cond_init(&vc_cv[i], 0, (void *) 0); } } else _DIAGASSERT(vc_cv != NULL); #endif /* * XXX - fvdl connecting while holding a mutex? */ slen = sizeof ss; if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { if (errno != ENOTCONN) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto blooy; } if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto blooy; } } mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); if (!__rpc_fd2sockinfo(fd, &si)) goto fooy; ct->ct_closeit = FALSE; /* * Set up private data struct */ ct->ct_fd = fd; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr.buf = malloc((size_t)raddr->maxlen); if (ct->ct_addr.buf == NULL) goto fooy; memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len); ct->ct_addr.len = raddr->len; ct->ct_addr.maxlen = raddr->maxlen; /* * Initialize call message */ call_msg.rm_xid = __RPC_GETXID(); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = (u_int32_t)prog; call_msg.rm_call.cb_vers = (u_int32_t)vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)close(fd); } goto fooy; } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ h->cl_ops = clnt_vc_ops(); h->cl_private = ct; h->cl_auth = authnone_create(); sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, h->cl_private, read_vc, write_vc); return (h); blooy: mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); fooy: /* * Something goofed, free stuff and barf */ if (ct) mem_free(ct, sizeof(struct ct_data)); if (h) mem_free(h, sizeof(CLIENT)); return (NULL); }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmition occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT * clntudp_bufcreate( struct sockaddr_in *raddr, unsigned long program, unsigned long version, struct timeval waitval, register int *sockp, unsigned sendsz, unsigned recvsz) { CLIENT *cl; register struct cu_data *cu = NULL; struct timeval now; struct rpc_msg call_msg; cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); if (cl == NULL) { (void) fprintf(stderr, "clntudp_create: out of memory\n"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *)mem_alloc( (size_t)(sizeof(*cu) + sendsz + recvsz)); if (cu == NULL) { (void) fprintf(stderr, "clntudp_create: out of memory\n"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } cu->cu_inbuf = (char*)&cu->cu_dummy; /* uint32_t aligned */ cu->cu_outbuf = &cu->cu_inbuf[recvsz]; (void)gettimeofday(&now, NULL); if (raddr->sin_port == 0) { unsigned short port; if ((port = pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons(port); } cl->cl_ops = &udp_ops; cl->cl_private = (char*)cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = waitval; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); if (*sockp < 0) { int flags; struct sockaddr_in myaddr; int sock; sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } (void)memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl(INADDR_ANY); myaddr.sin_port = htons(0); if (bind(sock, (struct sockaddr*)&myaddr, sizeof(myaddr)) == -1) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; (void)close(sock); goto fooy; } else { *sockp = sock; } /* the sockets rpc controls are non-blocking */ flags = fcntl(*sockp, F_GETFL); (void)fcntl(*sockp, F_SETFL, flags | O_NONBLOCK); cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create(); return (cl); fooy: if (cu) mem_free((char*)cu, sizeof(*cu) + sendsz + recvsz); if (cl) mem_free((char*)cl, sizeof(CLIENT)); return ((CLIENT *)NULL); }
/* * our version of brpc_call(). We cache in portnumber in to->sin_port for * your convenience. to and from addresses are taken and received in network * order. */ enum clnt_stat brpc_call( rpcprog_t prog, /* rpc program number to call. */ rpcvers_t vers, /* rpc program version */ rpcproc_t proc, /* rpc procedure to call */ xdrproc_t in_xdr, /* routine to serialize arguments */ caddr_t args, /* arg vector for remote call */ xdrproc_t out_xdr, /* routine to deserialize results */ caddr_t ret, /* addr of buf to place results in */ int rexmit, /* retransmission interval (secs) */ int wait_time, /* how long (secs) to wait (resp) */ struct sockaddr_in *to, /* destination */ struct sockaddr_in *from_who, /* responder's port/address */ uint_t auth) /* type of auth wanted. */ { int s; char hostname[MAXHOSTNAMELEN]; struct sockaddr_in from; /* us. */ socklen_t from_len; XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ AUTH *xmit_auth; /* our chosen auth cookie */ gid_t fake_gids = 1; /* fake gids list for auth_unix */ caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ struct rpc_msg reply; /* our reply msg header */ int trm_len, rcv_len; struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ static uint_t xid; /* current xid */ uint_t xmit_len; /* How much of the buffer we used */ int nrefreshes = 2; /* # of times to refresh cred */ int flags = 0; /* send flags */ uint_t xdelay; int errors, preserve_errno; uint32_t timeout; socklen_t optlen; xmit_auth = NULL; trm_len = mac_get_mtu(); trm_msg = bkmem_alloc(trm_len); rcv_msg = bkmem_alloc(NFSBUF_SIZE); if (trm_msg == NULL || rcv_msg == NULL) { errno = ENOMEM; rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if (dontroute) { (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (const void *)&dontroute, sizeof (dontroute)); } if (to->sin_addr.s_addr == cached_destination.s_addr) { optlen = sizeof (timeout); (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, &optlen); } else { cached_destination.s_addr = htonl(INADDR_ANY); } /* Bind our endpoint. */ from.sin_family = AF_INET; ipv4_getipaddr(&from.sin_addr); from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); from.sin_port = get_source_port(B_TRUE); if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); /* initialize reply's rpc_msg struct, so we can decode later. */ reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ reply.acpted_rply.ar_results.where = ret; reply.acpted_rply.ar_results.proc = out_xdr; if (ntohs(to->sin_port) == 0) { /* snag the udp port we need. */ if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, &(rpc_error.re_status), to, NULL)) == 0) goto gt_error; to->sin_port = htons(to->sin_port); } /* generate xid - increment */ if (xid == 0) xid = (uint_t)(prom_gettime() / 1000) + 1; else xid++; /* set up outgoing pkt as xdr modified. */ xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); /* setup rpc header */ if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { dprintf("brpc_call: cannot setup rpc header.\n"); rpc_error.re_status = RPC_FAILED; goto gt_error; } /* setup authentication */ switch (auth) { case AUTH_NONE: xmit_auth = authnone_create(); break; case AUTH_UNIX: /* * Assumes we've configured the stack and thus know our * IP address/hostname, either by using DHCP or rarp/bootparams. */ gethostname(hostname, sizeof (hostname)); xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); break; default: dprintf("brpc_call: Unsupported authentication type: %d\n", auth); rpc_error.re_status = RPC_AUTHERROR; goto gt_error; /*NOTREACHED*/ } /* * rpc_hdr puts everything in the xmit buffer for the header * EXCEPT the proc. Put it, and our authentication info into * it now, serializing as we go. We will be at the place where * we left off. */ xmit_xdrs.x_op = XDR_ENCODE; if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { rpc_error.re_status = RPC_CANTENCODEARGS; goto gt_error; } else xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ /* * Right now the outgoing packet should be all serialized and * ready to go... Set up timers. */ xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, sizeof (xdelay)); wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); wait_time += prom_gettime(); /* * send out the request. The first item in the receive buffer will * be the xid. Check if it is correct. */ errors = 0; rpc_error.re_status = RPC_TIMEDOUT; do { if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, sizeof (struct sockaddr_in)) < 0) { /* * If errno is set to ETIMEDOUT, return * with RPC status as RPC_TIMEDOUT. Calling * funciton will take care of this error by * retrying the RPC call. */ if (errno == ETIMEDOUT) { rpc_error.re_status = RPC_TIMEDOUT; } else { rpc_error.re_status = RPC_CANTSEND; } goto gt_error; } from_len = sizeof (struct sockaddr_in); while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, MSG_DONTWAIT, (struct sockaddr *)from_who, &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { if (rcv_len < 0) { if (errno == EWOULDBLOCK || errno == ETIMEDOUT) { break; /* timeout */ } rpc_error.re_status = RPC_CANTRECV; goto gt_error; } if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { dprintf("brpc_call: xid: 0x%x != 0x%x\n", *(uint32_t *)(rcv_msg), xid); continue; } /* * Let's deserialize the data into our 'ret' buffer. */ xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { rpc_error.re_status = RPC_CANTDECODERES; goto gt_error; } _seterr_reply(&reply, &rpc_error); switch (rpc_error.re_status) { case RPC_SUCCESS: /* * XXX - validate for unix and none * always return true. */ if (AUTH_VALIDATE(xmit_auth, &reply.acpted_rply.ar_verf) == FALSE) { rpc_error.re_status = RPC_AUTHERROR; rpc_error.re_why = AUTH_INVALIDRESP; errors++; } if (reply.acpted_rply.ar_verf.oa_base != 0) { xmit_xdrs.x_op = XDR_FREE; (void) xdr_opaque_auth( &xmit_xdrs, &reply.acpted_rply.ar_verf); } break; case RPC_AUTHERROR: /* * Let's see if our credentials need * refreshing */ if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, NULL, NULL)) { nrefreshes--; } errors++; break; case RPC_PROCUNAVAIL: /* * Might be a silly portmapper implementation * erroneously responding to our rpc broadcast * indirect portmapper call. For this * particular case, we don't increment the * error counter because we want to keep * sifting for successful replies... */ if (to->sin_addr.s_addr != ntohl(INADDR_BROADCAST)) errors++; break; case RPC_PROGVERSMISMATCH: /* * Successfully talked to server, but they * don't speak our lingo. */ goto gt_error; default: /* Just keep trying till there's no data... */ errors++; break; } if (rpc_error.re_status != RPC_SUCCESS) { dprintf("brpc_call: from: %s, error: ", inet_ntoa(from_who->sin_addr)); rpc_disperr(&rpc_error); } else break; } /* * If we're having trouble reassembling datagrams, let the * application know ASAP so that it can take the appropriate * actions. */ } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && prom_gettime() < wait_time); gt_error: if (xmit_auth != NULL) AUTH_DESTROY(xmit_auth); if (trm_msg != NULL) bkmem_free(trm_msg, trm_len); if (rcv_msg != NULL) bkmem_free(rcv_msg, NFSBUF_SIZE); if (rpc_error.re_status != RPC_SUCCESS) rpc_disperr(&rpc_error); /* * socket calls reset errno. Since we want to hold onto the errno * value if it is ETIMEDOUT to communicate to our caller that this * RPC_TIMEDOUT situation is due to a stack problem (we're getting * a reply, but the stack simply can't assemble it.), we need to * preserve errno's value over the socket_close(). */ preserve_errno = (errno == ETIMEDOUT) ? errno : 0; (void) socket_close(s); errno = preserve_errno; return (rpc_error.re_status); }
CLIENT * clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct; struct rpc_msg call_msg; h = (CLIENT *) mem_alloc (sizeof (*h)); ct = (struct ct_data *) mem_alloc (sizeof (*ct)); if (h == NULL || ct == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clnttcp_create: out of memory\n")); else #endif (void) fputs (_("clnttcp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } /* * If no port number given ask the pmap for one */ if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0) { mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); } raddr->sin_port = htons (port); } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); (void) bindresvport (*sockp, (struct sockaddr_in *) 0); if ((*sockp < 0) || (connect (*sockp, (struct sockaddr *) raddr, sizeof (*raddr)) < 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; if (*sockp >= 0) (void) close (*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void) close (*sockp); } goto fooy; } ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs)); XDR_DESTROY (&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz, (caddr_t) ct, readtcp, writetcp); h->cl_ops = &tcp_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create (); return h; fooy: /* * Something goofed, free stuff and barf */ mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); }
/* * Connection less client creation returns with client handle parameters. * Default options are set, which the user can change using clnt_control(). * fd should be open and bound. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. Normally they are the same, but they can be * changed to improve the program efficiency and buffer allocation. * If they are 0, use the transport default. * * If svcaddr is NULL, returns NULL. */ CLIENT * clnt_dg_create(const int fd, struct netbuf *svcaddr, const rpcprog_t program, const rpcvers_t version, const uint_t sendsz, const uint_t recvsz) { CLIENT *cl = NULL; /* client handle */ struct cu_data *cu = NULL; /* private data */ struct t_unitdata *tr_data; struct t_info tinfo; struct timeval now; struct rpc_msg call_msg; uint_t ssz; uint_t rsz; sig_mutex_lock(&dgtbl_lock); if ((dgtbl == NULL) && ((dgtbl = rpc_fd_init()) == NULL)) { sig_mutex_unlock(&dgtbl_lock); goto err1; } sig_mutex_unlock(&dgtbl_lock); if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } if (t_getinfo(fd, &tinfo) == -1) { rpc_createerr.cf_stat = RPC_TLIERROR; rpc_createerr.cf_error.re_errno = 0; rpc_createerr.cf_error.re_terrno = t_errno; return (NULL); } /* * Setup to rcv datagram error, we ignore any errors returned from * __rpc_tli_set_options() as SO_DGRAM_ERRIND is only relevant to * udp/udp6 transports and this point in the code we only know that * we are using a connection less transport. */ if (tinfo.servtype == T_CLTS) (void) __rpc_tli_set_options(fd, SOL_SOCKET, SO_DGRAM_ERRIND, 1); /* * Find the receive and the send size */ ssz = __rpc_get_t_size((int)sendsz, tinfo.tsdu); rsz = __rpc_get_t_size((int)recvsz, tinfo.tsdu); if ((ssz == 0) || (rsz == 0)) { rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ rpc_createerr.cf_error.re_errno = 0; rpc_createerr.cf_error.re_terrno = 0; return (NULL); } if ((cl = malloc(sizeof (CLIENT))) == NULL) goto err1; /* * Should be multiple of 4 for XDR. */ ssz = ((ssz + 3) / 4) * 4; rsz = ((rsz + 3) / 4) * 4; cu = malloc(sizeof (*cu) + ssz + rsz); if (cu == NULL) goto err1; if ((cu->cu_raddr.buf = malloc(svcaddr->len)) == NULL) goto err1; (void) memcpy(cu->cu_raddr.buf, svcaddr->buf, (size_t)svcaddr->len); cu->cu_raddr.len = cu->cu_raddr.maxlen = svcaddr->len; cu->cu_outbuf_start = &cu->cu_inbuf[rsz]; /* Other values can also be set through clnt_control() */ cu->cu_wait.tv_sec = 15; /* heuristically chosen */ cu->cu_wait.tv_usec = 0; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = ssz; cu->cu_recvsz = rsz; (void) gettimeofday(&now, NULL); call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, ssz, XDR_ENCODE); if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ rpc_createerr.cf_error.re_errno = 0; rpc_createerr.cf_error.re_terrno = 0; goto err2; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); XDR_DESTROY(&(cu->cu_outxdrs)); xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf_start, ssz, XDR_ENCODE); /* LINTED pointer alignment */ tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR | T_OPT); if (tr_data == NULL) { goto err1; } tr_data->udata.maxlen = cu->cu_recvsz; tr_data->udata.buf = cu->cu_inbuf; cu->cu_tr_data = tr_data; /* * By default, closeit is always FALSE. It is users responsibility * to do a t_close on it, else the user may use clnt_control * to let clnt_destroy do it for him/her. */ cu->cu_closeit = FALSE; cu->cu_fd = fd; cl->cl_ops = clnt_dg_ops(); cl->cl_private = (caddr_t)cu; cl->cl_auth = authnone_create(); cl->cl_tp = NULL; cl->cl_netid = NULL; cu->pfdp.fd = cu->cu_fd; cu->pfdp.events = MASKVAL; return (cl); err1: (void) syslog(LOG_ERR, mem_err_clnt_dg); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; rpc_createerr.cf_error.re_terrno = 0; err2: if (cl) { free(cl); if (cu) { free(cu->cu_raddr.buf); free(cu); } } return (NULL); }
/* * Create a client handle for a tcp/ip connection. * If *sockp<0, *sockp is set to a newly created TCP socket and it is * connected to raddr. If *sockp non-negative then * raddr is ignored. The rpc/tcp package does buffering * similar to stdio, so the client must pick send and receive buffer sizes,]; * 0 => use the default. * If raddr->sin_port is 0, then a binder on the remote machine is * consulted for the right port number. * NB: *sockp is copied into a private area. * NB: It is the client's responsibility to close *sockp, unless * clnttcp_create() was called with *sockp = -1 (so it created * the socket), and CLNT_DESTROY() is used. * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this * something more useful. */ CLIENT * clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct = NULL; struct timeval now; struct rpc_msg call_msg; h = (CLIENT *)mem_alloc(sizeof(*h)); if (h == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } ct = (struct ct_data *)mem_alloc(sizeof(*ct)); if (ct == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } /* * If no port number given ask the pmap for one */ if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { mem_free((caddr_t)ct, sizeof(struct ct_data)); mem_free((caddr_t)h, sizeof(CLIENT)); return (NULL); } raddr->sin_port = htons(port); } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); (void)bindresvport(*sockp, NULL); if ((*sockp < 0) || (connect(*sockp, (struct sockaddr *)raddr, sizeof(*raddr)) < 0)) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; if (*sockp != -1) (void)close(*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ (void)gettimeofday(&now, NULL); call_msg.rm_xid = arc4random(); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)close(*sockp); } goto fooy; } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, (int(*)(caddr_t, caddr_t, int))writetcp); h->cl_ops = &tcp_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create(); if (h->cl_auth == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } return (h); fooy: /* * Something goofed, free stuff and barf */ if (ct) mem_free((caddr_t)ct, sizeof(struct ct_data)); if (h) mem_free((caddr_t)h, sizeof(CLIENT)); return (NULL); }
/* * Create a client handle for a tcp/ip connection. * If *sockp<0, *sockp is set to a newly created TCP socket and it is * connected to raddr. If *sockp non-negative then * raddr is ignored. The rpc/tcp package does buffering * similar to stdio, so the client must pick send and receive buffer sizes,]; * 0 => use the default. * If raddr->sin_port is 0, then a binder on the remote machine is * consulted for the right port number. * NB: *sockp is copied into a private area. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this * something more useful. */ CLIENT * clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct)); struct rpc_msg call_msg; int len; h = (CLIENT *) mem_alloc (sizeof (*h)); if (h == NULL || ct == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = __socket (AF_UNIX, SOCK_STREAM, 0); len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1; if (*sockp < 0 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; if (*sockp != -1) __close (*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) __close (*sockp); goto fooy; } ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs)); XDR_DESTROY (&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz, (caddr_t) ct, readunix, writeunix); h->cl_ops = (struct clnt_ops *) &unix_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create (); return h; fooy: /* * Something goofed, free stuff and barf */ mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return (CLIENT *) NULL; }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmission occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT * __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz, int flags) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", "clntudp_create", _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = (struct clnt_ops *) &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { #ifdef SOCK_NONBLOCK # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec >= 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags, IPPROTO_UDP); # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec == 0) __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1; # endif } #endif #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); # ifdef SOCK_CLOEXEC if (flags & SOCK_CLOEXEC) __fcntl (*sockp, F_SETFD, FD_CLOEXEC); # endif } #endif if (__builtin_expect (*sockp < 0, 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { /* the sockets rpc controls are non-blocking */ int dontblock = 1; (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock); } #endif #ifdef IP_RECVERR { int on = 1; __setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
CLIENT *qrpc_clnt_raw_create(u_long prog, u_long vers, const char *const srcif_name, const uint8_t * dmac_addr, uint8_t sess_id) { CLIENT *client; int rawsock_fd; struct qrpc_clnt_raw_priv *priv; struct rpc_msg call_msg; rawsock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (rawsock_fd < 0) return NULL; if (qrpc_set_prot_filter(rawsock_fd, QRPC_RAW_SOCK_PROT) < 0) { close(rawsock_fd); return NULL; } priv = calloc(1, sizeof(*priv)); if (!priv) { close(rawsock_fd); return NULL; } priv->raw_sock = rawsock_fd; priv->outbuf = calloc(1, QRPC_BUFFER_LEN); priv->inbuf = calloc(1, QRPC_BUFFER_LEN); priv->out_pktbuf = calloc(1, ETH_FRAME_LEN); priv->in_pktbuf = calloc(1, ETH_FRAME_LEN); if (!priv->outbuf || !priv->inbuf || !priv->out_pktbuf || !priv->in_pktbuf) { qrpc_clnt_raw_free_priv(priv); return NULL; } if (qrpc_clnt_raw_config_dst(rawsock_fd, srcif_name, &priv->dst_addr, dmac_addr, &priv->out_hdr.qhdr, QRPC_RAW_SOCK_PROT) < 0) { qrpc_clnt_raw_free_priv(priv); return NULL; } client = calloc(1, sizeof(*client)); if (!client) { qrpc_clnt_raw_free_priv(priv); return NULL; } client->cl_ops = (struct clnt_ops *)&qrpc_clnt_raw_ops; client->cl_private = (caddr_t) priv; client->cl_auth = authnone_create(); xdrmem_create(&priv->xdrs_in, (char *)priv->inbuf + sizeof(struct qrpc_frame_hdr), QRPC_BUFFER_LEN - sizeof(struct qrpc_frame_hdr), XDR_DECODE); xdrmem_create(&priv->xdrs_out, (char *)priv->outbuf, QRPC_BUFFER_LEN, XDR_ENCODE); call_msg.rm_xid = getpid(); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; if (!xdr_callhdr(&priv->xdrs_out, &call_msg)) { qrpc_clnt_raw_free_priv(priv); free(client); return NULL; } priv->xdrs_outpos = XDR_GETPOS(&(priv->xdrs_out)); priv->sess_id = sess_id; return client; }
/* * RPC calls to the keyserv. * * If (use_ruid == 1), use real uid. * If (use_ruid == 0), use effective uid. * Returns 0 on failure, 1 on success */ int key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt, char *rslt, int use_ruid) { CLIENT *clnt; struct timeval wait_time = {0, 0}; enum clnt_stat status; int vers; if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_GEN && __key_gendes_LOCAL) { des_block res; bool_t r; r = (*__key_gendes_LOCAL)(geteuid(), 0, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(des_block*)rslt = res; return (1); } return (0); } if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || (proc == KEY_GET_CONV)) vers = 2; /* talk to version 2 */ else vers = 1; /* talk to version 1 */ clnt = getkeyserv_handle(vers, 0); if (clnt == NULL) return (0); auth_destroy(clnt->cl_auth); if (use_ruid) clnt->cl_auth = authsys_create_ruid(); else clnt->cl_auth = authnone_create(); status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time); switch (status) { case RPC_SUCCESS: return (1); case RPC_CANTRECV: /* * keyserv was probably restarted, so we'll try once more */ if ((clnt = getkeyserv_handle(vers, 1)) == NULL) return (0); auth_destroy(clnt->cl_auth); if (use_ruid) clnt->cl_auth = authsys_create_ruid(); else clnt->cl_auth = authnone_create(); if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time) == RPC_SUCCESS) return (1); return (0); default: return (0); } }
/* * Create a client handle for a connection. * Default options are set, which the user can change using clnt_control()'s. * The rpc/vc package does buffering similar to stdio, so the client * must pick send and receive buffer sizes, 0 => use the default. * NB: fd is copied into a private area. * NB: The rpch->cl_auth is set null authentication. Caller may wish to * set this something more useful. * * fd should be an open socket * * fd - open file descriptor * raddr - servers address * prog - program number * vers - version number * sendsz - buffer send size * recvsz - buffer recv size */ CLIENT * clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog, const rpcvers_t vers, u_int sendsz, u_int recvsz) { CLIENT *cl; /* client handle */ struct ct_data *ct = NULL; /* client handle */ struct timeval now; struct rpc_msg call_msg; static u_int32_t disrupt; sigset_t mask; sigset_t newmask; struct sockaddr_storage ss; socklen_t slen; struct __rpc_sockinfo si; if (disrupt == 0) disrupt = (u_int32_t)(long)raddr; cl = (CLIENT *)mem_alloc(sizeof (*cl)); ct = (struct ct_data *)mem_alloc(sizeof (*ct)); if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { (void) syslog(LOG_ERR, clnt_vc_errstr, clnt_vc_str, __no_mem_str); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto err; } ct->ct_addr.buf = NULL; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); if (vc_fd_locks == (int *) NULL) { int cv_allocsz, fd_allocsz; int dtbsize = __rpc_dtbsize(); fd_allocsz = dtbsize * sizeof (int); vc_fd_locks = (int *) mem_alloc(fd_allocsz); if (vc_fd_locks == (int *) NULL) { mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } else memset(vc_fd_locks, '\0', fd_allocsz); assert(vc_cv == (cond_t *) NULL); cv_allocsz = dtbsize * sizeof (cond_t); vc_cv = (cond_t *) mem_alloc(cv_allocsz); if (vc_cv == (cond_t *) NULL) { mem_free(vc_fd_locks, fd_allocsz); vc_fd_locks = (int *) NULL; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } else { int i; for (i = 0; i < dtbsize; i++) cond_init(&vc_cv[i], 0, (void *) 0); } } else assert(vc_cv != (cond_t *) NULL); /* * XXX - fvdl connecting while holding a mutex? */ slen = sizeof ss; if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { if (errno != ENOTCONN) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } } mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); if (!__rpc_fd2sockinfo(fd, &si)) goto err; ct->ct_closeit = FALSE; /* * Set up private data struct */ ct->ct_fd = fd; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr.buf = malloc(raddr->maxlen); if (ct->ct_addr.buf == NULL) goto err; memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); ct->ct_addr.len = raddr->len; ct->ct_addr.maxlen = raddr->maxlen; /* * Initialize call message */ (void)gettimeofday(&now, NULL); call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = (u_int32_t)prog; call_msg.rm_call.cb_vers = (u_int32_t)vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)_close(fd); } goto err; } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ cl->cl_ops = clnt_vc_ops(); cl->cl_private = ct; cl->cl_auth = authnone_create(); sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, cl->cl_private, read_vc, write_vc); return (cl); err: if (ct) { if (ct->ct_addr.len) mem_free(ct->ct_addr.buf, ct->ct_addr.len); mem_free(ct, sizeof (struct ct_data)); } if (cl) mem_free(cl, sizeof (CLIENT)); return ((CLIENT *)NULL); }
static CLIENT *_clnt_pci_create(int sock_fd, struct sockaddr_nl *src, struct sockaddr_nl *dst, u_long prog, u_long vers) { struct timeval wait; CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; struct nlmsghdr *preqnlh, *prespnlh; struct iovec iov; struct msghdr msg; //u_int sendsz, recvsz; wait.tv_sec = 15; wait.tv_usec = 0; cl = (CLIENT *) malloc(sizeof(CLIENT)); //sendsz = ((PCIMSGSIZE + 3) / 4) * 4; //recvsz = ((PCIMSGSIZE + 3) / 4) * 4; cu = (struct cu_data *)calloc(1, sizeof(*cu)); /* Allocate memory for nlm headers */ preqnlh = (struct nlmsghdr *)calloc(1, NLMSG_SPACE(PCIMSGSIZE)); prespnlh = (struct nlmsghdr *)calloc(1, NLMSG_SPACE(PCIMSGSIZE)); if (cl == NULL || cu == NULL || preqnlh == NULL || prespnlh == NULL) { fprintf(stderr, "pci_clnt_create out of memory\n"); goto fooy; } cl->cl_ops = (struct clnt_ops *)&pci_ops; cl->cl_private = (caddr_t) cu; cu->cu_saddr = *src; cu->cu_daddr = *dst; cu->cu_slen = sizeof(cu->cu_saddr); cu->cu_dlen = sizeof(cu->cu_daddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = PCIMSGSIZE; cu->cu_recvsz = PCIMSGSIZE; // setup req/resp netlink headers cu->cu_reqnlh = preqnlh; cu->cu_respnlh = prespnlh; memset(preqnlh, 0, NLMSG_SPACE(PCIMSGSIZE)); preqnlh->nlmsg_len = NLMSG_SPACE(PCIMSGSIZE); preqnlh->nlmsg_pid = getpid(); preqnlh->nlmsg_flags = NLM_F_REQUEST; cu->cu_outbuf = NLMSG_DATA(preqnlh); memset(prespnlh, 0, NLMSG_SPACE(PCIMSGSIZE)); prespnlh->nlmsg_len = NLMSG_SPACE(PCIMSGSIZE); prespnlh->nlmsg_pid = getpid(); prespnlh->nlmsg_flags = NLM_F_REQUEST; cu->cu_inbuf = NLMSG_DATA(prespnlh); call_msg.rm_xid = getpid(); //_create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, PCIMSGSIZE, XDR_ENCODE); if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); cu->cu_sock = sock_fd; cl->cl_auth = authnone_create(); // Register the client. May not be necessary. FIXME preqnlh->nlmsg_len = 0; preqnlh->nlmsg_type = NETLINK_TYPE_CLNT_REGISTER; iov.iov_base = (void *)cu->cu_reqnlh; iov.iov_len = NLMSG_SPACE(0); memset((caddr_t) & msg, 0, sizeof(msg)); msg.msg_name = (void *)&cu->cu_daddr; msg.msg_namelen = cu->cu_dlen; msg.msg_iov = &iov; msg.msg_iovlen = 1; sendmsg(cu->cu_sock, &msg, 0); return cl; fooy: if (cu) free((caddr_t) cu); if (cl) free((caddr_t) cl); if (preqnlh) free((caddr_t) preqnlh); if (prespnlh) free((caddr_t) prespnlh); return (CLIENT *) NULL; }
/* returns an initialised client, or NULL on error */ CLIENT *create_rpc_client(struct sockaddr_in *client_sock, struct addrinfo *hints, unsigned long prognum, unsigned long version, struct timeval timeout, struct sockaddr_in src_ip) { CLIENT *client = NULL; int sock; long unsigned protocol; /* for portmapper */ char src[INET_ADDRSTRLEN]; char dst[INET_ADDRSTRLEN]; struct sockaddr_in getaddr; /* for getsockname */ socklen_t len = sizeof(getaddr); /* Even if you specify a source address the portmapper will use the default one */ /* this applies to pmap_getport or clnt*_create */ /* so use our own get_rpc_port */ /* check if we need to use the portmapper, 0 = yes */ if (client_sock->sin_port == 0) { client_sock->sin_port = htons(PMAPPORT); /* 111 */ sock = socket(AF_INET, hints->ai_socktype, 0); if (sock < 0) { perror("create_rpc_client(socket)"); return NULL; } /* set the source address if specified */ if (src_ip.sin_addr.s_addr) { /* portmapper doesn't need a reserved port */ src_ip.sin_port = 0; if (bind(sock, (struct sockaddr *) &src_ip, sizeof(src_ip)) == -1) { perror("create_rpc_client(bind)"); return NULL; } } if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) { /* TCP */ if (hints->ai_socktype == SOCK_STREAM) { protocol = PMAP_IPPROTO_TCP; client = clnttcp_create(client_sock, PMAPPROG, PMAPVERS, &sock, 0, 0); if (client == NULL) { clnt_pcreateerror("clnttcp_create"); } /* UDP */ } else { protocol = PMAP_IPPROTO_UDP; client = clntudp_create(client_sock, PMAPPROG, PMAPVERS, timeout, &sock); if (client == NULL) { clnt_pcreateerror("clntudp_create"); } } } else { perror("create_rpc_client(connect)"); return NULL; } if (verbose) { if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) { perror("create_rpc_client(getsockname)"); /* this is just verbose output so don't return an error */ } else { inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN); //inet_ntop(AF_INET, &(((struct sockaddr_in *)&client_sock)->sin_addr), dst, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN); debug("portmap request = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port)); } } /* query the portmapper */ client_sock->sin_port = get_rpc_port(client, prognum, version, protocol); /* close the portmapper connection */ client = destroy_rpc_client(client); /* by this point we should know which port we're talking to */ debug("portmapper = %s:%u\n", dst, ntohs(client_sock->sin_port)); } /* now make the client connection */ /* by now we should have a port defined unless the program isn't registered */ if (client_sock->sin_port) { /* Make sure and make new sockets for each new connection */ /* clnttcp_create will happily reuse open sockets */ sock = socket(AF_INET, hints->ai_socktype, 0); if (sock < 0) { perror("create_rpc_client(socket)"); return NULL; } /* always try and bind to a low port first */ /* could check for root here but there are other mechanisms for allowing processes to bind to low ports */ if (bindresvport(sock, &src_ip) == -1) { /* permission denied, ie we aren't root */ if (errno == EACCES) { /* try an ephemeral port */ src_ip.sin_port = htons(0); } else { perror("create_rpc_client(bindresvport)"); return NULL; } } /* now we're bound to a local socket, try and connect to the server */ if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) { /* TCP */ if (hints->ai_socktype == SOCK_STREAM) { /* TODO set recvsz and sendsz to the NFS blocksize */ client = clnttcp_create(client_sock, prognum, version, &sock, 0, 0); if (client == NULL) { clnt_pcreateerror("clnttcp_create"); } /* UDP */ } else { client = clntudp_create(client_sock, prognum, version, timeout, &sock); if (client == NULL) { clnt_pcreateerror("clntudp_create"); } } } else { perror("create_rpc_client(connect)"); return NULL; } if (verbose) { if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) { perror("create_rpc_client(getsockname)"); /* this is just verbose output so don't return an error */ } else { inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN); debug("Connected = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port)); } } } if (client) { /* TODO check return values */ /* use AUTH_NONE authentication by default */ client->cl_auth = authnone_create(); /* set the RPC timeout */ clnt_control(client, CLSET_TIMEOUT, (char *)&timeout); /* set the socket to close when the client is destroyed */ clnt_control(client, CLSET_FD_CLOSE, NULL); } return client; }
/* * Get an AUTH handle for a RPC client based on the given sec_data. * If an AUTH handle exists for the same sec_data, use that AUTH handle, * otherwise create a new one. */ int sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap) { int i; struct desauthent *da; int authflavor; cred_t *savecred; int stat; /* return (errno) status */ char gss_svc_name[MAX_GSS_NAME]; dh_k4_clntdata_t *desdata; AUTH *auth; gss_clntdata_t *gssdata; zoneid_t zoneid = getzoneid(); if ((client == NULL) || (secdata == NULL) || (ap == NULL)) return (EINVAL); *ap = (AUTH *)NULL; authflavor = secdata->rpcflavor; for (;;) { int nlen; char *netname; switch (authflavor) { case AUTH_NONE: *ap = (AUTH *) authnone_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_UNIX: *ap = (AUTH *) authkern_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_LOOPBACK: *ap = (AUTH *) authloopback_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_DES: mutex_enter(&desauthtab_lock); if (desauthtab == NULL) { desauthtab = kmem_zalloc(clnt_authdes_cachesz * sizeof (struct desauthent), KM_SLEEP); } for (da = desauthtab; da < &desauthtab[clnt_authdes_cachesz]; da++) { if (da->da_data == secdata && da->da_uid == crgetuid(cr) && da->da_zoneid == zoneid && !da->da_inuse && da->da_auth != NULL) { da->da_inuse = 1; mutex_exit(&desauthtab_lock); *ap = da->da_auth; return (0); } } mutex_exit(&desauthtab_lock); /* * A better way would be to have a cred paramater to * authdes_create. */ savecred = curthread->t_cred; curthread->t_cred = cr; /* * Note that authdes_create() expects a * NUL-terminated string for netname, but * dh_k4_clntdata_t gives us netname & netnamelen. * * We must create a string for authdes_create(); * the latter takes a copy of it, so we may * immediately free it. */ desdata = (dh_k4_clntdata_t *)secdata->data; nlen = desdata->netnamelen; /* must be NUL-terminated */ netname = kmem_zalloc(nlen + 1, KM_SLEEP); bcopy(desdata->netname, netname, nlen); stat = authdes_create(netname, authdes_win, &desdata->syncaddr, desdata->knconf, (des_block *)NULL, (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0, &auth); kmem_free(netname, nlen + 1); curthread->t_cred = savecred; *ap = auth; if (stat != 0) { /* * If AUTH_F_TRYNONE is on, try again * with AUTH_NONE. See bug 1180236. */ if (secdata->flags & AUTH_F_TRYNONE) { authflavor = AUTH_NONE; continue; } else return (stat); } i = clnt_authdes_cachesz; mutex_enter(&desauthtab_lock); do { da = &desauthtab[nextdesvictim++]; nextdesvictim %= clnt_authdes_cachesz; } while (da->da_inuse && --i > 0); if (da->da_inuse) { mutex_exit(&desauthtab_lock); /* overflow of des auths */ return (stat); } da->da_inuse = 1; mutex_exit(&desauthtab_lock); if (da->da_auth != NULL) auth_destroy(da->da_auth); da->da_auth = auth; da->da_uid = crgetuid(cr); da->da_zoneid = zoneid; da->da_data = secdata; return (stat); case RPCSEC_GSS: /* * For RPCSEC_GSS, cache is done in rpc_gss_secget(). * For every rpc_gss_secget(), it should have * a corresponding rpc_gss_secfree() call. */ gssdata = (gss_clntdata_t *)secdata->data; (void) sprintf(gss_svc_name, "%s@%s", gssdata->uname, gssdata->inst); stat = rpc_gss_secget(client, gss_svc_name, &gssdata->mechanism, gssdata->service, gssdata->qop, NULL, NULL, (caddr_t)secdata, cr, &auth); *ap = auth; /* success */ if (stat == 0) return (stat); /* * let the caller retry if connection timedout * or reset. */ if (stat == ETIMEDOUT || stat == ECONNRESET) return (stat); /* * If AUTH_F_TRYNONE is on, try again * with AUTH_NONE. See bug 1180236. */ if (secdata->flags & AUTH_F_TRYNONE) { authflavor = AUTH_NONE; continue; } RPCLOG(1, "sec_clnt_geth: rpc_gss_secget" " failed with %d", stat); return (stat); default: /* * auth create must have failed, try AUTH_NONE * (this relies on AUTH_NONE never failing) */ cmn_err(CE_NOTE, "sec_clnt_geth: unknown " "authflavor %d, trying AUTH_NONE", authflavor); authflavor = AUTH_NONE; } } }