int svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp) { struct ucred *cr = NULL; int flavor; struct xucred *xcr; flavor = rqst->rq_cred.oa_flavor; if (flavorp) *flavorp = flavor; switch (flavor) { case AUTH_UNIX: xcr = (struct xucred *) rqst->rq_clntcred; cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid; crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups); cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; cr->cr_prison = &prison0; prison_hold(cr->cr_prison); *crp = cr; return (TRUE); case RPCSEC_GSS: if (!_svcauth_rpcsec_gss_getcred) return (FALSE); return (_svcauth_rpcsec_gss_getcred(rqst, crp, flavorp)); default: return (FALSE); } }
/* * Called with a modifying token held, but must still obtain p_spin to * actually replace p_ucred to handle races against syscall entry from * other threads which cache p_ucred->td_ucred. * * (the threads will only get the spin-lock, and they only need to in * the case where td_ucred != p_ucred so this is optimal). */ struct ucred * cratom_proc(struct proc *p) { struct ucred *oldcr; struct ucred *newcr; oldcr = p->p_ucred; if (oldcr->cr_ref == 1) return(oldcr); newcr = crget(); /* this might block */ oldcr = p->p_ucred; /* so re-cache oldcr (do not re-test) */ *newcr = *oldcr; if (newcr->cr_uidinfo) uihold(newcr->cr_uidinfo); if (newcr->cr_ruidinfo) uihold(newcr->cr_ruidinfo); if (jailed(newcr)) prison_hold(newcr->cr_prison); newcr->cr_ref = 1; spin_lock(&p->p_spin); p->p_ucred = newcr; spin_unlock(&p->p_spin); crfree(oldcr); return newcr; }
/* * Dup cred struct to a new held one. */ struct ucred * crdup(struct ucred *cr) { struct ucred *newcr; newcr = crget(); *newcr = *cr; if (newcr->cr_uidinfo) uihold(newcr->cr_uidinfo); if (newcr->cr_ruidinfo) uihold(newcr->cr_ruidinfo); if (jailed(newcr)) prison_hold(newcr->cr_prison); newcr->cr_ref = 1; return (newcr); }
/* * Copy cred structure to a new one and free the old one. * * MPSAFE (*cr must be stable) */ struct ucred * crcopy(struct ucred *cr) { struct ucred *newcr; if (cr->cr_ref == 1) return (cr); newcr = crget(); *newcr = *cr; if (newcr->cr_uidinfo) uihold(newcr->cr_uidinfo); if (newcr->cr_ruidinfo) uihold(newcr->cr_ruidinfo); if (jailed(newcr)) prison_hold(newcr->cr_prison); newcr->cr_ref = 1; crfree(cr); return (newcr); }
/* * Atomize a cred structure so it can be modified without polluting * other references to it. * * MPSAFE (however, *pcr must be stable) */ struct ucred * cratom(struct ucred **pcr) { struct ucred *oldcr; struct ucred *newcr; oldcr = *pcr; if (oldcr->cr_ref == 1) return (oldcr); newcr = crget(); *newcr = *oldcr; if (newcr->cr_uidinfo) uihold(newcr->cr_uidinfo); if (newcr->cr_ruidinfo) uihold(newcr->cr_ruidinfo); if (jailed(newcr)) prison_hold(newcr->cr_prison); newcr->cr_ref = 1; crfree(oldcr); *pcr = newcr; return (newcr); }
/* * Atomize a cred structure so it can be modified without polluting * other references to it. * * MPSAFE (however, *pcr must be stable) */ struct ucred * cratom(struct ucred **pcr) { struct ucred *oldcr; struct ucred *newcr; oldcr = *pcr; if (oldcr->cr_ref == 1) return (oldcr); newcr = crget(); /* this might block */ oldcr = *pcr; /* re-cache after potentially blocking */ *newcr = *oldcr; if (newcr->cr_uidinfo) uihold(newcr->cr_uidinfo); if (newcr->cr_ruidinfo) uihold(newcr->cr_ruidinfo); if (jailed(newcr)) prison_hold(newcr->cr_prison); newcr->cr_ref = 1; crfree(oldcr); *pcr = newcr; return (newcr); }
/* * Build hash lists of net addresses and hang them off the mount point. * Called by vfs_export() to set up the lists of export addresses. */ static int vfs_hang_addrlist(struct mount *mp, struct netexport *nep, struct export_args *argp) { register struct netcred *np; register struct radix_node_head *rnh; register int i; struct radix_node *rn; struct sockaddr *saddr, *smask = 0; struct domain *dom; int error; /* * XXX: This routine converts from a `struct xucred' * (argp->ex_anon) to a `struct ucred' (np->netc_anon). This * operation is questionable; for example, what should be done * with fields like cr_uidinfo and cr_prison? Currently, this * routine does not touch them (leaves them as NULL). */ if (argp->ex_anon.cr_version != XUCRED_VERSION) { vfs_mount_error(mp, "ex_anon.cr_version: %d != %d", argp->ex_anon.cr_version, XUCRED_VERSION); return (EINVAL); } if (argp->ex_addrlen == 0) { if (mp->mnt_flag & MNT_DEFEXPORTED) { vfs_mount_error(mp, "MNT_DEFEXPORTED already set for mount %p", mp); return (EPERM); } np = &nep->ne_defexported; np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); np->netc_anon->cr_uid = argp->ex_anon.cr_uid; crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, argp->ex_anon.cr_groups); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); np->netc_numsecflavors = argp->ex_numsecflavors; bcopy(argp->ex_secflavors, np->netc_secflavors, sizeof(np->netc_secflavors)); MNT_ILOCK(mp); mp->mnt_flag |= MNT_DEFEXPORTED; MNT_IUNLOCK(mp); return (0); } #if MSIZE <= 256 if (argp->ex_addrlen > MLEN) { vfs_mount_error(mp, "ex_addrlen %d is greater than %d", argp->ex_addrlen, MLEN); return (EINVAL); } #endif i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK | M_ZERO); saddr = (struct sockaddr *) (np + 1); if ((error = copyin(argp->ex_addr, saddr, argp->ex_addrlen))) goto out; if (saddr->sa_family == AF_UNSPEC || saddr->sa_family > AF_MAX) { error = EINVAL; vfs_mount_error(mp, "Invalid saddr->sa_family: %d"); goto out; } if (saddr->sa_len > argp->ex_addrlen) saddr->sa_len = argp->ex_addrlen; if (argp->ex_masklen) { smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); error = copyin(argp->ex_mask, smask, argp->ex_masklen); if (error) goto out; if (smask->sa_len > argp->ex_masklen) smask->sa_len = argp->ex_masklen; } i = saddr->sa_family; if ((rnh = nep->ne_rtable[i]) == NULL) { /* * Seems silly to initialize every AF when most are not used, * do so on demand here */ for (dom = domains; dom; dom = dom->dom_next) { KASSERT(((i == AF_INET) || (i == AF_INET6)), ("unexpected protocol in vfs_hang_addrlist")); if (dom->dom_family == i && dom->dom_rtattach) { /* * XXX MRT * The INET and INET6 domains know the * offset already. We don't need to send it * So we just use it as a flag to say that * we are or are not setting up a real routing * table. Only IP and IPV6 need have this * be 0 so all other protocols can stay the * same (ABI compatible). */ dom->dom_rtattach( (void **) &nep->ne_rtable[i], 0); break; } } if ((rnh = nep->ne_rtable[i]) == NULL) { error = ENOBUFS; vfs_mount_error(mp, "%s %s %d", "Unable to initialize radix node head ", "for address family", i); goto out; } } RADIX_NODE_HEAD_LOCK(rnh); rn = (*rnh->rnh_addaddr)(saddr, smask, rnh, np->netc_rnodes); RADIX_NODE_HEAD_UNLOCK(rnh); if (rn == NULL || np != (struct netcred *)rn) { /* already exists */ error = EPERM; vfs_mount_error(mp, "Invalid radix node head, rn: %p %p", rn, np); goto out; } np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); np->netc_anon->cr_uid = argp->ex_anon.cr_uid; crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, argp->ex_anon.cr_groups); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); np->netc_numsecflavors = argp->ex_numsecflavors; bcopy(argp->ex_secflavors, np->netc_secflavors, sizeof(np->netc_secflavors)); return (0); out: free(np, M_NETADDR); return (error); }