| 2069 | } |
| 2070 | |
| 2071 | int |
| 2072 | kern_accessat(struct thread *td, int fd, const char *path, |
| 2073 | enum uio_seg pathseg, int flag, int amode) |
| 2074 | { |
| 2075 | struct ucred *cred, *usecred; |
| 2076 | struct vnode *vp; |
| 2077 | struct nameidata nd; |
| 2078 | int error; |
| 2079 | |
| 2080 | if ((flag & ~(AT_EACCESS | AT_RESOLVE_BENEATH)) != 0) |
| 2081 | return (EINVAL); |
| 2082 | if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) |
| 2083 | return (EINVAL); |
| 2084 | |
| 2085 | /* |
| 2086 | * Create and modify a temporary credential instead of one that |
| 2087 | * is potentially shared (if we need one). |
| 2088 | */ |
| 2089 | cred = td->td_ucred; |
| 2090 | if ((flag & AT_EACCESS) == 0 && |
| 2091 | ((cred->cr_uid != cred->cr_ruid || |
| 2092 | cred->cr_rgid != cred->cr_groups[0]))) { |
| 2093 | usecred = crdup(cred); |
| 2094 | usecred->cr_uid = cred->cr_ruid; |
| 2095 | usecred->cr_groups[0] = cred->cr_rgid; |
| 2096 | td->td_ucred = usecred; |
| 2097 | } else |
| 2098 | usecred = cred; |
| 2099 | AUDIT_ARG_VALUE(amode); |
| 2100 | NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | |
| 2101 | AUDITVNODE1 | at2cnpflags(flag, AT_RESOLVE_BENEATH), |
| 2102 | pathseg, path, fd, &cap_fstat_rights, td); |
| 2103 | if ((error = namei(&nd)) != 0) |
| 2104 | goto out; |
| 2105 | vp = nd.ni_vp; |
| 2106 | |
| 2107 | error = vn_access(vp, amode, usecred, td); |
| 2108 | NDFREE_NOTHING(&nd); |
| 2109 | vput(vp); |
| 2110 | out: |
| 2111 | if (usecred != cred) { |
| 2112 | td->td_ucred = cred; |
| 2113 | crfree(usecred); |
| 2114 | } |
| 2115 | return (error); |
| 2116 | } |
| 2117 | |
| 2118 | /* |
| 2119 | * Check access permissions using "effective" credentials. |
no test coverage detected