static enum xprt_stat svc_dg_decode(struct svc_req *req) { XDR *xdrs = req->rq_xdrs; SVCXPRT *xprt = req->rq_xprt; xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); rpc_msg_init(&req->rq_msg); if (!xdr_dplx_decode(xdrs, &req->rq_msg)) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: %p fd %d failed (will set dead)", __func__, xprt, xprt->xp_fd); return (XPRT_DIED); } /* in order of likelihood */ if (req->rq_msg.rm_direction == CALL) { /* an ordinary call header */ return xprt->xp_dispatch.process_cb(req); } if (req->rq_msg.rm_direction == REPLY) { /* reply header (xprt OK) */ return clnt_req_process_reply(xprt->xp_parent, req); } __warnx(TIRPC_DEBUG_FLAG_WARN, "%s: %p fd %d failed direction %" PRIu32 " (will set dead)", __func__, __func__, xprt, xprt->xp_fd, req->rq_msg.rm_direction); return (XPRT_DIED); }
struct rpc_dplx_rec * rpc_dplx_lookup_rec(int fd, uint32_t iflags, uint32_t *oflags) { struct rbtree_x_part *t; struct rpc_dplx_rec rk, *rec = NULL; struct opr_rbtree_node *nv; cond_init_rpc_dplx(); rk.fd_k = fd; t = rbtx_partition_of_scalar(&(rpc_dplx_rec_set.xt), fd); rwlock_rdlock(&t->lock); nv = opr_rbtree_lookup(&t->t, &rk.node_k); /* XXX rework lock+insert case, so that new entries are inserted * locked, and t->lock critical section is reduced */ if (! nv) { rwlock_unlock(&t->lock); rwlock_wrlock(&t->lock); nv = opr_rbtree_lookup(&t->t, &rk.node_k); if (! nv) { rec = alloc_dplx_rec(); if (! rec) { __warnx(TIRPC_DEBUG_FLAG_LOCK, "%s: failed allocating rpc_dplx_rec", __func__); goto unlock; } /* tell the caller */ *oflags = RPC_DPLX_LKP_OFLAG_ALLOC; rec->fd_k = fd; if (opr_rbtree_insert(&t->t, &rec->node_k)) { /* cant happen */ __warnx(TIRPC_DEBUG_FLAG_LOCK, "%s: collision inserting in locked rbtree partition", __func__); free_dplx_rec(rec); } } } else { rec = opr_containerof(nv, struct rpc_dplx_rec, node_k); *oflags = RPC_DPLX_LKP_FLAG_NONE; } rpc_dplx_ref(rec, (iflags & RPC_DPLX_LKP_IFLAG_LOCKREC) ? RPC_DPLX_FLAG_LOCK : RPC_DPLX_FLAG_NONE); unlock: rwlock_unlock(&t->lock); return (rec); }
/* * 3. Validate */ static bool authdes_validate(AUTH *auth, struct opaque_auth *rverf) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_verf verf; int status; uint32_t *ixdr; des_block buf; if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) return (false); /* LINTED pointer alignment */ ixdr = (uint32_t *) rverf->oa_base; buf.key.high = (uint32_t) *ixdr++; buf.key.low = (uint32_t) *ixdr++; verf.adv_int_u = (uint32_t) *ixdr++; /* * Decrypt the timestamp */ status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, (u_int) sizeof(des_block), DES_DECRYPT | DES_HW); if (DES_FAILED(status)) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "authdes_validate: DES decryption failure"); return (false); } /* * xdr the decrypted timestamp */ /* LINTED pointer alignment */ ixdr = (uint32_t *) buf.c; verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); /* * validate */ if (bcmp ((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, sizeof(struct timeval)) != 0) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "authdes_validate: verifier mismatch"); return (false); } /* * We have a nickname now, let's use it */ ad->ad_nickname = verf.adv_nickname; ad->ad_cred.adc_namekind = ADN_NICKNAME; return (true); }
static enum xprt_stat svc_dg_reply(struct svc_req *req) { SVCXPRT *xprt = req->rq_xprt; struct rpc_dplx_rec *rec = REC_XPRT(xprt); XDR *xdrs = rec->ioq.xdrs; struct svc_dg_xprt *su = DG_DR(rec); struct msghdr *msg = &su->su_msghdr; struct iovec iov; size_t slen; if (!xprt->xp_remote.nb.len) { __warnx(TIRPC_DEBUG_FLAG_WARN, "%s: %p fd %d has no remote address", __func__, xprt, xprt->xp_fd); return (XPRT_IDLE); } xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); if (!xdr_reply_encode(xdrs, &req->rq_msg)) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: %p fd %d xdr_reply_encode failed (will set dead)", __func__, xprt, xprt->xp_fd); return (XPRT_DIED); } if (req->rq_msg.rm_reply.rp_stat == MSG_ACCEPTED && req->rq_msg.rm_reply.rp_acpt.ar_stat == SUCCESS && req->rq_auth && !SVCAUTH_WRAP(req, xdrs)) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: %p fd %d SVCAUTH_WRAP failed (will set dead)", __func__, xprt, xprt->xp_fd); return (XPRT_DIED); } iov.iov_base = &su[1]; iov.iov_len = slen = XDR_GETPOS(xdrs); msg->msg_iov = &iov; msg->msg_iovlen = 1; msg->msg_name = (struct sockaddr *)&xprt->xp_remote.ss; msg->msg_namelen = xprt->xp_remote.nb.len; /* cmsg already set in svc_dg_rendezvous */ if (sendmsg(xprt->xp_fd, msg, 0) != (ssize_t) slen) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: %p fd %d sendmsg failed (will set dead)", __func__, xprt, xprt->xp_fd); return (XPRT_DIED); } return (XPRT_IDLE); }
static bool svc_rdma_reply(SVCXPRT *xprt, struct svc_req *req, struct rpc_msg *msg) { struct rpc_rdma_cbc *cbc = req->rq_context; XDR *xdrs = cbc->holdq.xdrs; xdrproc_t proc; void *where; bool has_args; __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s() xprt %p cbc %p outgoing xdr %p\n", __func__, xprt, cbc, xdrs); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { has_args = TRUE; proc = msg->acpted_rply.ar_results.proc; where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; msg->acpted_rply.ar_results.where = NULL; } else { has_args = FALSE; proc = NULL; where = NULL; } if (!xdr_rdma_svc_reply(cbc, 0)){ __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s: xdr_rdma_svc_reply failed (will set dead)", __func__); return (FALSE); } xdrs->x_op = XDR_ENCODE; if (!xdr_reply_encode(xdrs, msg)) { __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s: xdr_reply_encode failed (will set dead)", __func__); return (FALSE); } xdr_tail_update(xdrs); if (has_args && req->rq_auth && !SVCAUTH_WRAP(req->rq_auth, req, xdrs, proc, where)) { __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s: SVCAUTH_WRAP failed (will set dead)", __func__); return (FALSE); } xdr_tail_update(xdrs); return xdr_rdma_svc_flushout(cbc); }
void authgss_hash_init() { int ix, code = 0; mutex_lock(&authgss_hash_st.lock); /* once */ if (authgss_hash_st.initialized) goto unlock; code = rbtx_init(&authgss_hash_st.xt, svc_rpc_gss_cmpf, __svc_params->gss.ctx_hash_partitions, RBT_X_FLAG_ALLOC | RBT_X_FLAG_CACHE_RT); if (code) __warnx(TIRPC_DEBUG_FLAG_RPCSEC_GSS, "%s: rbtx_init failed", __func__); /* init read-through cache */ for (ix = 0; ix < __svc_params->gss.ctx_hash_partitions; ++ix) { struct rbtree_x_part *xp = &(authgss_hash_st.xt.tree[ix]); struct authgss_x_part *axp; xp->cache = mem_zalloc(authgss_hash_st.xt.cachesz * sizeof(struct opr_rbtree_node *)); if (unlikely(!xp->cache)) { __warnx(TIRPC_DEBUG_FLAG_RPCSEC_GSS, "%s: rbtx cache partition alloc failed", __func__); authgss_hash_st.xt.cachesz = 0; break; } /* partition ctx LRU */ axp = (struct authgss_x_part *) mem_alloc(sizeof(struct authgss_x_part)); TAILQ_INIT(&axp->lru_q); xp->u1 = axp; } authgss_hash_st.size = 0; authgss_hash_st.max_part = __svc_params->gss.max_gc / authgss_hash_st.xt.npart; authgss_hash_st.initialized = true; unlock: mutex_unlock(&authgss_hash_st.lock); }
/* * Create an xdr handle for xdrrec * xdr_inrec_create fills in xdrs. Sendsize and recvsize are * send and recv buffer sizes (0 => use default). * tcp_handle is an opaque handle that is passed as the first parameter to * the procedures readit and writeit. Readit and writeit are read and * write respectively. They are like the system * calls expect that they take an opaque handle rather than an fd. */ void xdr_inrec_create(XDR *xdrs, u_int recvsize, void *tcp_handle, /* like read, but pass it a tcp_handle, not sock */ int (*readit)(XDR *, void *, void *, int)) { RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); if (rstrm == NULL) { __warnx(TIRPC_DEBUG_FLAG_XDRREC, "xdr_inrec_create: out of memory"); /* * This is bad. Should rework xdr_inrec_create to * return a handle, and in this case return NULL */ return; } rstrm->recvsize = recvsize = fix_buf_size(recvsize); rstrm->in_base = mem_alloc(recvsize); if (rstrm->in_base == NULL) { __warnx(TIRPC_DEBUG_FLAG_XDRREC, "xdr_inrec_create: out of memory"); mem_free(rstrm, sizeof(RECSTREAM)); return; } /* * now the rest ... */ xdrs->x_ops = &xdr_inrec_ops; xdrs->x_lib[0] = NULL; xdrs->x_lib[1] = NULL; xdrs->x_public = NULL; xdrs->x_private = rstrm; xdrs->x_flags = XDR_FLAG_CKSUM; rstrm->xdrs = xdrs; rstrm->tcp_handle = tcp_handle; rstrm->readit = readit; rstrm->in_size = recvsize; rstrm->in_boundry = rstrm->in_base; rstrm->in_finger = (rstrm->in_boundry += recvsize); rstrm->fbtbc = 0; rstrm->last_frag = TRUE; rstrm->in_haveheader = FALSE; rstrm->offset = 0; rstrm->cksum = 0; rstrm->cklen = 256; }
static void svc_dg_destroy_it(SVCXPRT *xprt, u_int flags, const char *tag, const int line) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 0, }; if (!xprt->xp_parent) { /* only original parent is registered */ svc_rqst_xprt_unregister(xprt); } __warnx(TIRPC_DEBUG_FLAG_REFCNT, "%s() %p fd %d xp_refs %" PRIu32 " should actually destroy things @ %s:%d", __func__, xprt, xprt->xp_fd, xprt->xp_refs, tag, line); while (atomic_postset_uint16_t_bits(&(REC_XPRT(xprt)->ioq.ioq_s.qflags), IOQ_FLAG_WORKING) & IOQ_FLAG_WORKING) { nanosleep(&ts, NULL); } REC_XPRT(xprt)->ioq.ioq_wpe.fun = svc_dg_destroy_task; work_pool_submit(&svc_work_pool, &(REC_XPRT(xprt)->ioq.ioq_wpe)); } static void svc_dg_destroy(SVCXPRT *xprt, u_int flags, const char *tag, const int line) { svc_dg_destroy_it(xprt, flags, tag, line); }
/* * writes data to the tcp connection. * Any error is fatal and the connection is closed. */ static inline int svc_write_vc(XDR *xdrs, void *ctp, void *buf, int len) { SVCXPRT *xprt; struct x_vc_data *xd; struct timespec ts0, ts1; int i, cnt; xd = (struct x_vc_data *) ctp; xprt = xd->rec->hdl.xprt; if (xd->shared.nonblock) (void) clock_gettime(CLOCK_MONOTONIC_FAST, &ts0); for (cnt = len; cnt > 0; cnt -= i, buf += i) { i = write(xprt->xp_fd, buf, (size_t)cnt); if (i < 0) { if (errno != EAGAIN || !xd->shared.nonblock) { __warnx(TIRPC_DEBUG_FLAG_SVC_VC, "%s: short write !EAGAIN (will set dead)", __func__); cfconn_set_dead(xprt, xd); return (-1); } if (xd->shared.nonblock && i != cnt) { /* * For non-blocking connections, do not * take more than 2 seconds writing the * data out. * * XXX 2 is an arbitrary amount. */ (void) clock_gettime(CLOCK_MONOTONIC_FAST, &ts1); if (ts1.tv_sec - ts0.tv_sec >= 2) { __warnx(TIRPC_DEBUG_FLAG_SVC_VC, "%s: short write !EAGAIN (will set dead)", __func__); cfconn_set_dead(xprt, xd); return (-1); } } } } return (len); }
static inline int svc_read_vc(XDR *xdrs, void *ctp, void *buf, int len) { SVCXPRT *xprt; int milliseconds = 35 * 1000; /* XXX shouldn't this be configurable? */ struct pollfd pollfd; struct x_vc_data *xd; xd = (struct x_vc_data *) ctp; xprt = xd->rec->hdl.xprt; if (xd->shared.nonblock) { len = read(xprt->xp_fd, buf, (size_t)len); if (len < 0) { if (errno == EAGAIN) len = 0; else goto fatal_err; } if (len != 0) (void) clock_gettime( CLOCK_MONOTONIC_FAST, &xd->sx.last_recv); return len; } do { pollfd.fd = xprt->xp_fd; pollfd.events = POLLIN; pollfd.revents = 0; switch (poll(&pollfd, 1, milliseconds)) { case -1: if (errno == EINTR) continue; /*FALLTHROUGH*/ case 0: __warnx(TIRPC_DEBUG_FLAG_SVC_VC, "%s: poll returns 0 (will set dead)", __func__); goto fatal_err; default: break; } } while ((pollfd.revents & POLLIN) == 0); if ((len = read(xprt->xp_fd, buf, (size_t)len)) > 0) { (void) clock_gettime( CLOCK_MONOTONIC_FAST, &xd->sx.last_recv); return (len); } fatal_err: cfconn_set_dead(xprt, xd); return (-1); }
static bool svc_rdma_recv(SVCXPRT *xprt, struct svc_req *req) { struct rpc_rdma_cbc *cbc = req->rq_context; XDR *xdrs = cbc->holdq.xdrs; __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s() xprt %p cbc %p incoming xdr %p\n", __func__, xprt, cbc, xdrs); req->rq_msg = alloc_rpc_msg(); if (!xdr_rdma_svc_recv(cbc, 0)){ __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s: xdr_rdma_svc_recv failed", __func__); return (FALSE); } xdrs->x_op = XDR_DECODE; /* No need, already positioned to beginning ... XDR_SETPOS(xdrs, 0); */ if (!xdr_dplx_decode(xdrs, req->rq_msg)) { __warnx(TIRPC_DEBUG_FLAG_SVC_RDMA, "%s: xdr_dplx_decode failed", __func__); return (FALSE); } req->rq_xprt = xprt; req->rq_prog = req->rq_msg->rm_call.cb_prog; req->rq_vers = req->rq_msg->rm_call.cb_vers; req->rq_proc = req->rq_msg->rm_call.cb_proc; req->rq_xid = req->rq_msg->rm_xid; req->rq_clntcred = req->rq_msg->rq_cred_body; /* the checksum */ req->rq_cksum = 0; return (TRUE); }
int _des_crypt_call(char *buf, int len, struct desparams *dparms) { CLIENT *clnt; desresp *result_1; desargs des_crypt_1_arg; struct netconfig *nconf; void *localhandle; int stat; nconf = NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) { __warnx("getnetconfig: %s", nc_sperror()); return(DESERR_HWERROR); } clnt = clnt_tp_ncreate(NULL, CRYPT_PROG, CRYPT_VERS, nconf); if (clnt == (CLIENT *) NULL) { endnetconfig(localhandle); return(DESERR_HWERROR); } endnetconfig(localhandle); des_crypt_1_arg.desbuf.desbuf_len = len; des_crypt_1_arg.desbuf.desbuf_val = buf; des_crypt_1_arg.des_dir = dparms->des_dir; des_crypt_1_arg.des_mode = dparms->des_mode; bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8); bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8); result_1 = des_crypt_1(&des_crypt_1_arg, clnt); if (result_1 == (desresp *) NULL) { clnt_destroy(clnt); return(DESERR_HWERROR); } stat = result_1->stat; if (result_1->stat == DESERR_NONE || result_1->stat == DESERR_NOHWDEVICE) { bcopy(result_1->desbuf.desbuf_val, buf, len); bcopy(result_1->des_ivec, dparms->des_ivec, 8); } clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1); clnt_destroy(clnt); return(stat); }
/* * Create a unix style authenticator. * Returns an auth handle with the given stuff in it. */ AUTH * authunix_ncreate(char *machname, uid_t uid, gid_t gid, int len, gid_t *aup_gids) { struct audata *au = mem_alloc(sizeof(*au)); AUTH *auth = &au->au_auth; struct authunix_parms aup; struct timespec now; XDR xdrs; /* * Allocate and set up auth handle */ auth->ah_ops = authunix_ops(); auth->ah_private = NULL; auth->ah_error.re_status = RPC_SUCCESS; auth->ah_verf = au->au_shcred = _null_auth; auth->ah_refcnt = 1; au->au_shfaults = 0; /* * fill in param struct from the given params */ (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); aup.aup_time = now.tv_sec; aup.aup_machname = machname; aup.aup_uid = uid; aup.aup_gid = gid; aup.aup_len = (u_int) len; aup.aup_gids = aup_gids; /* * Serialize the parameters into origcred */ xdrmem_create(&xdrs, au->au_origcred.oa_body, MAX_AUTH_BYTES, XDR_ENCODE); if (!xdr_authunix_parms(&xdrs, &aup)) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "%s: %s", __func__, clnt_sperrno(RPC_CANTENCODEARGS)); auth->ah_error.re_status = RPC_CANTENCODEARGS; return (auth); } au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); au->au_origcred.oa_flavor = AUTH_UNIX; /* * set auth handle to reflect new cred. */ auth->ah_cred = au->au_origcred; /* auth_get not needed: ah_refcnt == 1, as desired */ marshal_new_auth(auth); /* */ return (auth); }
int32_t rpc_dplx_unref(struct rpc_dplx_rec *rec, u_int flags) { struct rbtree_x_part *t; struct opr_rbtree_node *nv; int32_t refcnt; if (! (flags & RPC_DPLX_FLAG_LOCKED)) REC_LOCK(rec); refcnt = --(rec->refcnt); __warnx(TIRPC_DEBUG_FLAG_REFCNT, "%s: postunref %p rec->refcnt %u", __func__, rec, refcnt); if (rec->refcnt == 0) { t = rbtx_partition_of_scalar(&rpc_dplx_rec_set.xt, rec->fd_k); REC_UNLOCK(rec); rwlock_wrlock(&t->lock); nv = opr_rbtree_lookup(&t->t, &rec->node_k); rec = NULL; if (nv) { rec = opr_containerof(nv, struct rpc_dplx_rec, node_k); REC_LOCK(rec); if (rec->refcnt == 0) { (void) opr_rbtree_remove(&t->t, &rec->node_k); REC_UNLOCK(rec); __warnx(TIRPC_DEBUG_FLAG_REFCNT, "%s: free rec %p rec->refcnt %u", __func__, rec, refcnt); free_dplx_rec(rec); rec = NULL; } else { refcnt = rec->refcnt; } } rwlock_unlock(&t->lock); }
/* * Create a client handle for memory based rpc. */ CLIENT * clnt_raw_ncreate(rpcprog_t prog, rpcvers_t vers) { struct clntraw_private *clp; struct rpc_msg call_msg; XDR *xdrs; CLIENT *client; mutex_lock(&clntraw_lock); clp = clntraw_private; if (clp == 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(TIRPC_DEBUG_FLAG_CLNT_RAW, "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(); mutex_unlock(&clntraw_lock); return (client); }
static int svcauth_gss_validate(struct svc_req *req, struct svc_rpc_gss_data *gd, struct rpc_msg *msg) { struct opaque_auth *oa; gss_buffer_desc rpcbuf, checksum; OM_uint32 maj_stat, min_stat, qop_state; u_char rpchdr[RPCHDR_LEN]; int32_t *buf; memset(rpchdr, 0, RPCHDR_LEN); /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */ oa = &msg->rm_call.cb_cred; if (oa->oa_length > MAX_AUTH_BYTES) return GSS_S_CALL_BAD_STRUCTURE; /* XXX since MAX_AUTH_BYTES is 400, the following code trivially * overruns (up to 431 per Coverity, but compare RPCHDR_LEN with * what is marshalled below). */ buf = (int32_t *) rpchdr; IXDR_PUT_LONG(buf, msg->rm_xid); IXDR_PUT_ENUM(buf, msg->rm_direction); IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); IXDR_PUT_ENUM(buf, oa->oa_flavor); IXDR_PUT_LONG(buf, oa->oa_length); if (oa->oa_length) { memcpy((caddr_t) buf, oa->oa_base, oa->oa_length); buf += RNDUP(oa->oa_length) / sizeof(int32_t); } rpcbuf.value = rpchdr; rpcbuf.length = (u_char *) buf - rpchdr; checksum.value = msg->rm_call.cb_verf.oa_base; checksum.length = msg->rm_call.cb_verf.oa_length; maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, &qop_state); if (maj_stat != GSS_S_COMPLETE) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "%s: %d %d", __func__, maj_stat, min_stat); return (maj_stat); } return GSS_S_COMPLETE; }
/* * svc_rdma_ncreate: waits for connection request and returns transport */ SVCXPRT * svc_rdma_ncreate(void *arg, const u_int sendsize, const u_int recvsize, const u_int flags) { struct svc_rdma_xdr *sm; struct sockaddr_storage *ss; RDMAXPRT *l_xprt = arg; RDMAXPRT *xprt = rpc_rdma_accept_wait(l_xprt, l_xprt->xa->timeout); if (!xprt) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s:%u ERROR (return)", __func__, __LINE__); return (NULL); } sm = mem_zalloc(sizeof (*sm)); sm->sm_xdrs.x_lib[1] = xprt; xprt->xprt.xp_p2 = sm; xprt->xprt.xp_flags = flags; /* fixme: put something here, but make it not work on fd operations. */ xprt->xprt.xp_fd = -1; ss = (struct sockaddr_storage *)rdma_get_local_addr(xprt->cm_id); __rpc_set_address(&xprt->xprt.xp_local, ss, 0); ss = (struct sockaddr_storage *)rdma_get_peer_addr(xprt->cm_id); __rpc_set_address(&xprt->xprt.xp_remote, ss, 0); svc_rdma_ops(&xprt->xprt); if (xdr_rdma_create(&sm->sm_xdrs, xprt, sendsize, recvsize, flags)) { goto freedata; } if (rpc_rdma_accept_finalize(xprt)) { goto freedata; } return (&xprt->xprt); freedata: mem_free(sm, sizeof (*sm)); xprt->xprt.xp_p2 = NULL; xprt_unregister(&xprt->xprt); return (NULL); }
rpc_ctx_t * alloc_rpc_call_ctx(CLIENT *clnt, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr, xdrproc_t xdr_results, void *results_ptr, struct timeval timeout) { struct x_vc_data *xd = (struct x_vc_data *) clnt->cl_p1; struct rpc_dplx_rec *rec = xd->rec; rpc_ctx_t *ctx; ctx = mem_alloc(sizeof(rpc_ctx_t)); if (! ctx) goto out; /* potects this */ mutex_init(&ctx->we.mtx, NULL); cond_init(&ctx->we.cv, 0, NULL); /* rec->calls and rbtree protected by (adaptive) mtx */ mutex_lock(&rec->mtx); /* XXX we hold the client-fd lock */ ctx->xid = ++(xd->cx.calls.xid); /* some of this looks like overkill; it's here to support future, * fully async calls */ ctx->ctx_u.clnt.clnt = clnt; ctx->ctx_u.clnt.timeout.tv_sec = 0; ctx->ctx_u.clnt.timeout.tv_nsec = 0; timespec_addms(&ctx->ctx_u.clnt.timeout, tv_to_ms(&timeout)); ctx->msg = alloc_rpc_msg(); ctx->flags = 0; /* stash it */ if (opr_rbtree_insert(&xd->cx.calls.t, &ctx->node_k)) { __warnx(TIRPC_DEBUG_FLAG_RPC_CTX, "%s: call ctx insert failed (xid %d client %p)", __func__, ctx->xid, clnt); mutex_unlock(&rec->mtx); mem_free(ctx, sizeof(rpc_ctx_t)); ctx = NULL; goto out; } mutex_unlock(&rec->mtx); out: return (ctx); }
/* * XDR counted bytes * *cpp is a pointer to the bytes, *sizep is the count. * If *cpp is NULL maxsize bytes are allocated */ bool xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize) { char *sp = *cpp; /* sp is the actual string pointer */ u_int nodesize; /* * first deal with the length since xdr bytes are counted */ if (! xdr_u_int(xdrs, sizep)) { return (FALSE); } nodesize = *sizep; if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { return (FALSE); } /* * now deal with the actual bytes */ switch (xdrs->x_op) { case XDR_DECODE: if (nodesize == 0) { return (TRUE); } if (sp == NULL) { *cpp = sp = mem_alloc(nodesize); } if (sp == NULL) { __warnx(TIRPC_DEBUG_FLAG_XDR, "xdr_bytes: out of memory"); return (FALSE); } /* FALLTHROUGH */ case XDR_ENCODE: return (xdr_opaque(xdrs, sp, nodesize)); case XDR_FREE: if (sp != NULL) { mem_free(sp, nodesize); *cpp = NULL; } return (TRUE); } /* NOTREACHED */ return (FALSE); }
/*ARGSUSED*/ static bool authdes_refresh(AUTH *auth, void *dummy) { /* LINTED pointer alignment */ struct ad_private *ad = AUTH_PRIVATE(auth); struct authdes_cred *cred = &ad->ad_cred; int ok; netobj pkey; if (ad->ad_dosync) { ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, ad->ad_timehost, &(ad->ad_uaddr), &(ad->ad_netid)); if (!ok) { /* * Hope the clocks are synced! */ ad->ad_dosync = 0; __warnx(TIRPC_DEBUG_FLAG_AUTH, "authdes_refresh: unable to synchronize clock"); } } ad->ad_xkey = auth->ah_key; pkey.n_bytes = (char *)(ad->ad_pkey); pkey.n_len = (u_int) strlen((char *)ad->ad_pkey) + 1; if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "authdes_refresh: keyserv(1m) is unable to encrypt " "session key"); return (false); } cred->adc_fullname.key = ad->ad_xkey; cred->adc_namekind = ADN_FULLNAME; cred->adc_fullname.name = ad->ad_fullname; return (true); }
/* * Marshals (pre-serializes) an auth struct. * sets private data, au_marshed and au_mpos */ static void marshal_new_auth(AUTH *auth) { XDR xdrs[1]; struct audata *au = AUTH_PRIVATE(auth); assert(auth != NULL); xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); if ((!xdr_opaque_auth_encode(xdrs, &(auth->ah_cred))) || (!xdr_opaque_auth_encode(xdrs, &(auth->ah_verf)))) __warnx(TIRPC_DEBUG_FLAG_AUTH, "auth_none.c - Fatal marshalling " "problem"); else au->au_mpos = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); }
/* * reads data from the tcp or udp connection. * any error is fatal and the connection is closed. * (And a read of zero bytes is a half closed stream => error.) * All read operations timeout after 35 seconds. A timeout is * fatal for the connection. */ static inline size_t svc_readv_vc(XDR *xdrs, void *ctp, struct iovec *iov, int iovcnt, u_int flags) { SVCXPRT *xprt; int milliseconds = 35 * 1000; /* XXX shouldn't this be configurable? */ struct pollfd pollfd; struct x_vc_data *xd; size_t nbytes = -1; xd = (struct x_vc_data *) ctp; xprt = xd->rec->hdl.xprt; do { pollfd.fd = xprt->xp_fd; pollfd.events = POLLIN; pollfd.revents = 0; switch (poll(&pollfd, 1, milliseconds)) { case -1: if (errno == EINTR) continue; /*FALLTHROUGH*/ case 0: __warnx(TIRPC_DEBUG_FLAG_SVC_VC, "%s: poll returns 0 (will set dead)", __func__); goto fatal_err; default: break; } } while ((pollfd.revents & POLLIN) == 0); if ((nbytes = readv(xprt->xp_fd, iov, iovcnt)) > 0) { (void) clock_gettime(CLOCK_MONOTONIC_FAST, &xd->sx.last_recv); goto out; } fatal_err: cfconn_set_dead(xprt, xd); out: return (nbytes); }
static void svc_rdma_destroy(SVCXPRT *xprt, u_int flags, const char *tag, const int line) { struct svc_rdma_xdr *sm = sm_data(xprt); __warnx(TIRPC_DEBUG_FLAG_REFCNT, "%s() %p xp_refs %" PRId32 " should actually destroy things @ %s:%d", __func__, xprt, xprt->xp_refs, tag, line); xdr_rdma_destroy(&(sm->sm_xdrs)); mem_free(sm, sizeof (*sm)); if (xprt->xp_ops->xp_free_user_data) { /* call free hook */ xprt->xp_ops->xp_free_user_data(xprt); } rpc_rdma_destroy(xprt); }
AUTH * authdes_nseccreate(const char *servername, const u_int win, const char *timehost, const des_block *ckey) { u_char pkey_data[1024]; netobj pkey; AUTH *dummy; if (!getpublickey(servername, (char *)pkey_data)) { __warnx(TIRPC_DEBUG_FLAG_AUTH, "authdes_nseccreate: no public key found for %s", servername); return (NULL); } pkey.n_bytes = (char *)pkey_data; pkey.n_len = (u_int) strlen((char *)pkey_data) + 1; dummy = authdes_pk_nseccreate(servername, &pkey, win, timehost, ckey, NULL); return (dummy); }
/* * writes data to the tcp connection. * Any error is fatal and the connection is closed. */ static size_t svc_writev_vc(XDR *xdrs, void *ctp, struct iovec *iov, int iovcnt, u_int flags) { SVCXPRT *xprt; struct x_vc_data *xd; size_t nbytes; xd = (struct x_vc_data *) ctp; xprt = xd->rec->hdl.xprt; nbytes = writev(xprt->xp_fd, iov, iovcnt); if (nbytes < 0) { __warnx(TIRPC_DEBUG_FLAG_SVC_VC, "%s: short writev (will set dead)", __func__); cfconn_set_dead(xprt, xd); return (-1); } return (nbytes); }
static void svc_dg_destroy_task(struct work_pool_entry *wpe) { struct rpc_dplx_rec *rec = opr_containerof(wpe, struct rpc_dplx_rec, ioq.ioq_wpe); uint16_t xp_flags; __warnx(TIRPC_DEBUG_FLAG_REFCNT, "%s() %p fd %d xp_refs %" PRIu32, __func__, rec, rec->xprt.xp_fd, rec->xprt.xp_refs); if (rec->xprt.xp_refs) { /* instead of nanosleep */ work_pool_submit(&svc_work_pool, &(rec->ioq.ioq_wpe)); return; } xp_flags = atomic_postclear_uint16_t_bits(&rec->xprt.xp_flags, SVC_XPRT_FLAG_CLOSE); if ((xp_flags & SVC_XPRT_FLAG_CLOSE) && rec->xprt.xp_fd != RPC_ANYFD) { (void)close(rec->xprt.xp_fd); rec->xprt.xp_fd = RPC_ANYFD; } if (rec->xprt.xp_ops->xp_free_user_data) rec->xprt.xp_ops->xp_free_user_data(&rec->xprt); if (rec->xprt.xp_tp) mem_free(rec->xprt.xp_tp, 0); if (rec->xprt.xp_netid) mem_free(rec->xprt.xp_netid, 0); if (rec->xprt.xp_parent) SVC_RELEASE(rec->xprt.xp_parent, SVC_RELEASE_FLAG_NONE); svc_dg_xprt_free(DG_DR(rec)); }
void rpc_ctx_next_xid(rpc_ctx_t *ctx, uint32_t flags) { struct x_vc_data *xd = (struct x_vc_data *) ctx->ctx_u.clnt.clnt->cl_p1; struct rpc_dplx_rec *rec = xd->rec; assert (flags & RPC_CTX_FLAG_LOCKED); mutex_lock(&rec->mtx); opr_rbtree_remove(&xd->cx.calls.t, &ctx->node_k); ctx->xid = ++(xd->cx.calls.xid); if (opr_rbtree_insert(&xd->cx.calls.t, &ctx->node_k)) { mutex_unlock(&rec->mtx); __warnx(TIRPC_DEBUG_FLAG_RPC_CTX, "%s: call ctx insert failed (xid %d client %p)", __func__, ctx->xid, ctx->ctx_u.clnt.clnt); goto out; } mutex_unlock(&rec->mtx); out: return; }
void rpc_dplx_init() { int code = 0; /* XXX */ mutex_lock(&rpc_dplx_rec_set.clnt_fd_lock); if (initialized) goto unlock; /* one of advantages of this RBT is convenience of external * iteration, we'll go to that shortly */ code = rbtx_init(&rpc_dplx_rec_set.xt, rpc_dplx_cmpf /* NULL (inline) */, RPC_DPLX_PARTITIONS, RBT_X_FLAG_ALLOC); if (code) __warnx(TIRPC_DEBUG_FLAG_LOCK, "rpc_dplx_init: rbtx_init failed"); initialized = TRUE; unlock: mutex_unlock(&rpc_dplx_rec_set.clnt_fd_lock); }
int __rpc_raise_fd(int fd) { int nfd; if (fd >= __rpc_minfd) return (fd); if ((nfd = fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) return (fd); if (fsync(nfd) == -1) { close(nfd); return (fd); } if (close(fd) == -1) { /* this is okay, we will log an error, then use the new fd */ __warnx("could not close() fd %d; mem & fd leak", fd); } return (nfd); }
SVCXPRT * svc_dg_ncreate(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct svc_dg_data *su = NULL; struct __rpc_sockinfo si; struct sockaddr_storage ss; socklen_t slen; uint32_t oflags; if (!__rpc_fd2sockinfo(fd, &si)) { __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, svc_dg_err1); return (NULL); } /* * Find the receive and the send size */ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); if ((sendsize == 0) || (recvsize == 0)) { __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, svc_dg_err2); return (NULL); } xprt = mem_alloc(sizeof (SVCXPRT)); if (xprt == NULL) goto freedata; memset(xprt, 0, sizeof (SVCXPRT)); /* Init SVCXPRT locks, etc */ mutex_init(&xprt->xp_lock, NULL); mutex_init(&xprt->xp_auth_lock, NULL); su = mem_alloc(sizeof (*su)); if (su == NULL) goto freedata; su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) goto freedata; xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_flags = SVC_XPRT_FLAG_NONE; xprt->xp_refcnt = 1; xprt->xp_fd = fd; xprt->xp_p2 = su; svc_dg_ops(xprt); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); slen = sizeof ss; if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) goto freedata; __rpc_set_netbuf(&xprt->xp_ltaddr, &ss, slen); switch (ss.ss_family) { case AF_INET: xprt->xp_port = ntohs(((struct sockaddr_in *) &ss)->sin_port); break; #ifdef INET6 case AF_INET6: xprt->xp_port = ntohs(((struct sockaddr_in6 *) &ss)->sin6_port); break; #endif case AF_LOCAL: /* no port */ break; default: break; } /* Enable reception of IP*_PKTINFO control msgs */ svc_dg_enable_pktinfo(fd, &si); /* Make reachable */ xprt->xp_p5 = rpc_dplx_lookup_rec(xprt->xp_fd, RPC_DPLX_FLAG_NONE, &oflags); /* ref+1 */ svc_rqst_init_xprt(xprt); /* Conditional xprt_register */ if (! (__svc_params->flags & SVC_FLAG_NOREG_XPRTS)) xprt_register(xprt); return (xprt); freedata: __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, __no_mem_str); if (xprt) { if (su) (void) mem_free(su, sizeof (*su)); svc_rqst_finalize_xprt(xprt, SVC_RQST_FLAG_NONE); (void) mem_free(xprt, sizeof (SVCXPRT)); } return (NULL); }