/* * 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; } } }
int clnt_rdma_kcreate(char *proto, void *handle, struct netbuf *raddr, int family, rpcprog_t pgm, rpcvers_t vers, struct cred *cred, CLIENT **cl) { CLIENT *h; struct cku_private *p; struct rpc_msg call_msg; rdma_registry_t *rp; ASSERT(INGLOBALZONE(curproc)); if (cl == NULL) return (EINVAL); *cl = NULL; p = kmem_zalloc(sizeof (*p), KM_SLEEP); /* * Find underlying RDMATF plugin */ rw_enter(&rdma_lock, RW_READER); rp = rdma_mod_head; while (rp != NULL) { if (strcmp(rp->r_mod->rdma_api, proto)) rp = rp->r_next; else { p->cku_rd_mod = rp->r_mod; p->cku_rd_handle = handle; break; } } rw_exit(&rdma_lock); if (p->cku_rd_mod == NULL) { /* * Should not happen. * No matching RDMATF plugin. */ kmem_free(p, sizeof (struct cku_private)); return (EINVAL); } h = ptoh(p); h->cl_ops = &rdma_clnt_ops; h->cl_private = (caddr_t)p; h->cl_auth = authkern_create(); /* call message, just used to pre-serialize below */ call_msg.rm_xid = 0; call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = pgm; call_msg.rm_call.cb_vers = vers; xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, CKU_HDRSIZE, XDR_ENCODE); /* pre-serialize call message header */ if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) { XDR_DESTROY(&p->cku_outxdr); auth_destroy(h->cl_auth); kmem_free(p, sizeof (struct cku_private)); return (EINVAL); } /* * Set up the rpc information */ p->cku_cred = cred; p->cku_srcaddr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); p->cku_srcaddr.maxlen = raddr->maxlen; p->cku_srcaddr.len = 0; p->cku_addr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); p->cku_addr.maxlen = raddr->maxlen; p->cku_addr.len = raddr->len; bcopy(raddr->buf, p->cku_addr.buf, raddr->len); p->cku_addrfmly = family; *cl = h; return (0); }