Lines 1917-1922
unp_init(void)
Link Here
|
1917 |
} |
1917 |
} |
1918 |
|
1918 |
|
1919 |
/* |
1919 |
/* |
|
|
1920 |
* Arguments passed to internalizer/transformer (ix = internal xform). |
1921 |
* The transformation function may fill in a new ix_mbuf. |
1922 |
*/ |
1923 |
struct internalize_transform_data { |
1924 |
socklen_t ix_odatalen; /* original data length in bytes */ |
1925 |
socklen_t ix_ndatalen; /* new data length, or 0 */ |
1926 |
void *ix_odata; /* original data */ |
1927 |
void *ix_ndata; /* new data area, or NULL */ |
1928 |
struct mbuf *ix_mbuf; /* mbuf for new data */ |
1929 |
struct thread *ix_td; /* calling thread */ |
1930 |
}; |
1931 |
|
1932 |
/* |
1933 |
* Internalizers. If you provide a nonzero size, we pre-allocate |
1934 |
* the ix_mbuf and you get a nonzero ndatasize and non-NULL ndata. |
1935 |
*/ |
1936 |
struct unp_scm_internalize_op { |
1937 |
socklen_t size; /* predefined output size, or 0 */ |
1938 |
int (*func)(struct internalize_transform_data *); |
1939 |
}; |
1940 |
|
1941 |
static int unp_internalize_creds(struct internalize_transform_data *); |
1942 |
static int unp_internalize_fds(struct internalize_transform_data *); |
1943 |
static int unp_internalize_timestamp(struct internalize_transform_data *); |
1944 |
static int unp_internalize_bintime(struct internalize_transform_data *); |
1945 |
|
1946 |
static struct unp_scm_internalize_op unp_internalize_ops[] = { |
1947 |
[SCM_CREDS] = { sizeof(struct cmsgcred), unp_internalize_creds }, |
1948 |
[SCM_RIGHTS] = { 0, unp_internalize_fds }, |
1949 |
[SCM_TIMESTAMP] = { sizeof(struct timeval), unp_internalize_timestamp }, |
1950 |
[SCM_BINTIME] = { sizeof(struct bintime), unp_internalize_bintime }, |
1951 |
}; |
1952 |
|
1953 |
/* |
1920 |
* Convert incoming control message from user-supplied format |
1954 |
* Convert incoming control message from user-supplied format |
1921 |
* to internal form. |
1955 |
* to internal form. |
1922 |
* |
1956 |
* |
Lines 1925-2084
unp_init(void)
Link Here
|
1925 |
* that have not yet been internalized. On return, *controlp |
1959 |
* that have not yet been internalized. On return, *controlp |
1926 |
* is an mbuf chain whose individual mbufs are internalized; |
1960 |
* is an mbuf chain whose individual mbufs are internalized; |
1927 |
* this chain may have a different length. |
1961 |
* this chain may have a different length. |
|
|
1962 |
* |
1963 |
* Caller will always m_freem(*controlp), even if we return error. |
1928 |
*/ |
1964 |
*/ |
1929 |
static int |
1965 |
static int |
1930 |
unp_internalize(struct mbuf **controlp, struct thread *td) |
1966 |
unp_internalize(struct mbuf **controlp, struct thread *td) |
1931 |
{ |
1967 |
{ |
1932 |
struct mbuf *control = *controlp; |
1968 |
struct unp_scm_internalize_op *op; |
1933 |
struct proc *p = td->td_proc; |
1969 |
struct internalize_transform_data ix; |
1934 |
struct filedesc *fdesc = p->p_fd; |
1970 |
struct cmsghdr *cm; |
1935 |
struct bintime *bt; |
1971 |
struct mbuf *control, *m; |
1936 |
struct cmsghdr *cm = mtod(control, struct cmsghdr *); |
1972 |
void *odata; |
1937 |
struct cmsgcred *cmcred; |
1973 |
int cmtype, error; |
1938 |
struct filedescent *fde, **fdep, *fdev; |
1974 |
socklen_t clen, size, odatalen; |
1939 |
struct file *fp; |
|
|
1940 |
struct timeval *tv; |
1941 |
int i, *fdp; |
1942 |
void *data; |
1943 |
socklen_t clen = control->m_len, datalen; |
1944 |
int error, oldfds; |
1945 |
u_int newlen; |
1946 |
|
1975 |
|
1947 |
UNP_LINK_UNLOCK_ASSERT(); |
1976 |
UNP_LINK_UNLOCK_ASSERT(); |
1948 |
|
1977 |
|
|
|
1978 |
ix.ix_td = td; /* never changes, just passed through */ |
1979 |
|
1949 |
error = 0; |
1980 |
error = 0; |
|
|
1981 |
control = *controlp; |
1950 |
*controlp = NULL; |
1982 |
*controlp = NULL; |
1951 |
while (cm != NULL) { |
1983 |
clen = control->m_len; |
1952 |
if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET |
1984 |
cm = mtod(control, struct cmsghdr *); |
1953 |
|| cm->cmsg_len > clen || cm->cmsg_len < sizeof(*cm)) { |
|
|
1954 |
error = EINVAL; |
1955 |
goto out; |
1956 |
} |
1957 |
data = CMSG_DATA(cm); |
1958 |
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; |
1959 |
|
1985 |
|
1960 |
switch (cm->cmsg_type) { |
1986 |
while (error == 0) { |
1961 |
/* |
1987 |
/* |
1962 |
* Fill in credential information. |
1988 |
* Verify current control message, and set up type |
|
|
1989 |
* and old data pointer and size values. |
1963 |
*/ |
1990 |
*/ |
1964 |
case SCM_CREDS: |
1991 |
if (clen < sizeof(*cm) || cm->cmsg_level != SOL_SOCKET || |
1965 |
*controlp = sbcreatecontrol(NULL, sizeof(*cmcred), |
1992 |
cm->cmsg_len > clen || cm->cmsg_len < sizeof(*cm)) { |
1966 |
SCM_CREDS, SOL_SOCKET); |
1993 |
error = EINVAL; |
1967 |
if (*controlp == NULL) { |
|
|
1968 |
error = ENOBUFS; |
1969 |
goto out; |
1970 |
} |
1971 |
cmcred = (struct cmsgcred *) |
1972 |
CMSG_DATA(mtod(*controlp, struct cmsghdr *)); |
1973 |
cmcred->cmcred_pid = p->p_pid; |
1974 |
cmcred->cmcred_uid = td->td_ucred->cr_ruid; |
1975 |
cmcred->cmcred_gid = td->td_ucred->cr_rgid; |
1976 |
cmcred->cmcred_euid = td->td_ucred->cr_uid; |
1977 |
cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups, |
1978 |
CMGROUP_MAX); |
1979 |
for (i = 0; i < cmcred->cmcred_ngroups; i++) |
1980 |
cmcred->cmcred_groups[i] = |
1981 |
td->td_ucred->cr_groups[i]; |
1982 |
break; |
1994 |
break; |
|
|
1995 |
} |
1983 |
|
1996 |
|
1984 |
case SCM_RIGHTS: |
1997 |
cmtype = cm->cmsg_type; |
1985 |
oldfds = datalen / sizeof (int); |
1998 |
if (cmtype < 0 || cmtype >= nitems(unp_internalize_ops)) { |
1986 |
if (oldfds == 0) |
1999 |
error = EINVAL; |
1987 |
break; |
|
|
1988 |
/* |
1989 |
* Check that all the FDs passed in refer to legal |
1990 |
* files. If not, reject the entire operation. |
1991 |
*/ |
1992 |
fdp = data; |
1993 |
FILEDESC_SLOCK(fdesc); |
1994 |
for (i = 0; i < oldfds; i++, fdp++) { |
1995 |
fp = fget_locked(fdesc, *fdp); |
1996 |
if (fp == NULL) { |
1997 |
FILEDESC_SUNLOCK(fdesc); |
1998 |
error = EBADF; |
1999 |
goto out; |
2000 |
} |
2001 |
if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { |
2002 |
FILEDESC_SUNLOCK(fdesc); |
2003 |
error = EOPNOTSUPP; |
2004 |
goto out; |
2005 |
} |
2006 |
|
2007 |
} |
2008 |
|
2009 |
/* |
2010 |
* Now replace the integer FDs with pointers to the |
2011 |
* file structure and capability rights. |
2012 |
*/ |
2013 |
newlen = oldfds * sizeof(fdep[0]); |
2014 |
*controlp = sbcreatecontrol(NULL, newlen, |
2015 |
SCM_RIGHTS, SOL_SOCKET); |
2016 |
if (*controlp == NULL) { |
2017 |
FILEDESC_SUNLOCK(fdesc); |
2018 |
error = ENOBUFS; |
2019 |
goto out; |
2020 |
} |
2021 |
fdp = data; |
2022 |
fdep = (struct filedescent **) |
2023 |
CMSG_DATA(mtod(*controlp, struct cmsghdr *)); |
2024 |
fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS, |
2025 |
M_WAITOK); |
2026 |
for (i = 0; i < oldfds; i++, fdev++, fdp++) { |
2027 |
fde = &fdesc->fd_ofiles[*fdp]; |
2028 |
fdep[i] = fdev; |
2029 |
fdep[i]->fde_file = fde->fde_file; |
2030 |
filecaps_copy(&fde->fde_caps, |
2031 |
&fdep[i]->fde_caps, true); |
2032 |
unp_internalize_fp(fdep[i]->fde_file); |
2033 |
} |
2034 |
FILEDESC_SUNLOCK(fdesc); |
2035 |
break; |
2000 |
break; |
2036 |
|
2001 |
} |
2037 |
case SCM_TIMESTAMP: |
2002 |
op = &unp_internalize_ops[cmtype]; |
2038 |
*controlp = sbcreatecontrol(NULL, sizeof(*tv), |
2003 |
if (op->func == NULL) { |
2039 |
SCM_TIMESTAMP, SOL_SOCKET); |
2004 |
error = EINVAL; |
2040 |
if (*controlp == NULL) { |
|
|
2041 |
error = ENOBUFS; |
2042 |
goto out; |
2043 |
} |
2044 |
tv = (struct timeval *) |
2045 |
CMSG_DATA(mtod(*controlp, struct cmsghdr *)); |
2046 |
microtime(tv); |
2047 |
break; |
2005 |
break; |
|
|
2006 |
} |
2048 |
|
2007 |
|
2049 |
case SCM_BINTIME: |
2008 |
odata = CMSG_DATA(cm); |
2050 |
*controlp = sbcreatecontrol(NULL, sizeof(*bt), |
2009 |
odatalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)odata; |
2051 |
SCM_BINTIME, SOL_SOCKET); |
2010 |
|
2052 |
if (*controlp == NULL) { |
2011 |
ix.ix_odata = odata; |
|
|
2012 |
ix.ix_odatalen = odatalen; |
2013 |
|
2014 |
/* |
2015 |
* If transform function gives us a fixed data |
2016 |
* size, allocate new mbuf here, else leave it |
2017 |
* to the function. |
2018 |
*/ |
2019 |
if ((size = op->size) != 0) { |
2020 |
m = sbcreatecontrol(NULL, size, cmtype, SOL_SOCKET); |
2021 |
if (m == NULL) { |
2053 |
error = ENOBUFS; |
2022 |
error = ENOBUFS; |
2054 |
goto out; |
2023 |
break; |
2055 |
} |
2024 |
} |
2056 |
bt = (struct bintime *) |
2025 |
ix.ix_mbuf = m; |
2057 |
CMSG_DATA(mtod(*controlp, struct cmsghdr *)); |
2026 |
ix.ix_ndata = CMSG_DATA(mtod(m, struct cmsghdr *)); |
2058 |
bintime(bt); |
2027 |
ix.ix_ndatalen = size; |
2059 |
break; |
2028 |
} else { |
2060 |
|
2029 |
ix.ix_mbuf = NULL; |
2061 |
default: |
2030 |
ix.ix_ndata = NULL; |
2062 |
error = EINVAL; |
2031 |
ix.ix_ndatalen = 0; |
2063 |
goto out; |
|
|
2064 |
} |
2032 |
} |
2065 |
|
2033 |
|
2066 |
controlp = &(*controlp)->m_next; |
2034 |
/* |
2067 |
if (CMSG_SPACE(datalen) < clen) { |
2035 |
* Apply transform and append new mbuf (if any) to |
2068 |
clen -= CMSG_SPACE(datalen); |
2036 |
* new control chain, even on error, so that it |
2069 |
cm = (struct cmsghdr *) |
2037 |
* will get freed. |
2070 |
((caddr_t)cm + CMSG_SPACE(datalen)); |
2038 |
*/ |
2071 |
} else { |
2039 |
error = (*op->func)(&ix); |
2072 |
clen = 0; |
2040 |
if ((m = ix.ix_mbuf) != NULL) { |
2073 |
cm = NULL; |
2041 |
*controlp = m; |
|
|
2042 |
controlp = &m->m_next; |
2074 |
} |
2043 |
} |
|
|
2044 |
|
2045 |
/* Advance to next message. */ |
2046 |
size = CMSG_SPACE(odatalen); |
2047 |
if (size >= clen) |
2048 |
break; |
2049 |
cm = (struct cmsghdr *)((caddr_t)cm + size); |
2050 |
clen -= size; |
2075 |
} |
2051 |
} |
2076 |
|
2052 |
|
2077 |
out: |
|
|
2078 |
m_freem(control); |
2053 |
m_freem(control); |
2079 |
return (error); |
2054 |
return (error); |
2080 |
} |
2055 |
} |
2081 |
|
2056 |
|
|
|
2057 |
/* |
2058 |
* Internalize file descriptors ("rights"). |
2059 |
*/ |
2060 |
static int |
2061 |
unp_internalize_fds(struct internalize_transform_data *ix) |
2062 |
{ |
2063 |
struct proc *p = ix->ix_td->td_proc; |
2064 |
struct filedesc *fdesc = p->p_fd; |
2065 |
struct filedescent *fde, **fdep, *fdev; |
2066 |
struct file *fp; |
2067 |
struct mbuf *m; |
2068 |
int i, *fdp; |
2069 |
int oldfds; |
2070 |
u_int newlen; |
2071 |
|
2072 |
KASSERT(ix->ix_ndatalen == 0, ("%s: datalen", __func__)); |
2073 |
|
2074 |
/* Round down: this is forgiving, if slightly wrong. */ |
2075 |
oldfds = ix->ix_odatalen / sizeof (int); |
2076 |
if (oldfds == 0) |
2077 |
return (0); |
2078 |
|
2079 |
/* |
2080 |
* Check that all the FDs passed in refer to legal |
2081 |
* files. If not, reject the entire operation. |
2082 |
*/ |
2083 |
fdp = ix->ix_odata; |
2084 |
FILEDESC_SLOCK(fdesc); |
2085 |
for (i = 0; i < oldfds; i++, fdp++) { |
2086 |
fp = fget_locked(fdesc, *fdp); |
2087 |
if (fp == NULL) { |
2088 |
FILEDESC_SUNLOCK(fdesc); |
2089 |
return (EBADF); |
2090 |
} |
2091 |
if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { |
2092 |
FILEDESC_SUNLOCK(fdesc); |
2093 |
return (EOPNOTSUPP); |
2094 |
} |
2095 |
|
2096 |
} |
2097 |
|
2098 |
/* |
2099 |
* Now replace the integer FDs with pointers to the |
2100 |
* file structure and capability rights. |
2101 |
*/ |
2102 |
newlen = oldfds * sizeof(fdep[0]); |
2103 |
m = sbcreatecontrol(NULL, newlen, SCM_RIGHTS, SOL_SOCKET); |
2104 |
if (m == NULL) { |
2105 |
FILEDESC_SUNLOCK(fdesc); |
2106 |
return (ENOBUFS); |
2107 |
} |
2108 |
|
2109 |
fdp = ix->ix_odata; |
2110 |
fdep = (struct filedescent **)CMSG_DATA(mtod(m, struct cmsghdr *)); |
2111 |
fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS, M_WAITOK); |
2112 |
for (i = 0; i < oldfds; i++, fdev++, fdp++) { |
2113 |
fde = &fdesc->fd_ofiles[*fdp]; |
2114 |
fdep[i] = fdev; |
2115 |
fdep[i]->fde_file = fde->fde_file; |
2116 |
filecaps_copy(&fde->fde_caps, &fdep[i]->fde_caps, true); |
2117 |
unp_internalize_fp(fdep[i]->fde_file); |
2118 |
} |
2119 |
FILEDESC_SUNLOCK(fdesc); |
2120 |
|
2121 |
ix->ix_mbuf = m; |
2122 |
return (0); |
2123 |
} |
2124 |
|
2125 |
static int |
2126 |
unp_internalize_creds(struct internalize_transform_data *ix) |
2127 |
{ |
2128 |
struct cmsgcred *cmcred; |
2129 |
int i, ngroups; |
2130 |
struct thread *td = ix->ix_td; |
2131 |
struct ucred *cr = td->td_ucred; |
2132 |
|
2133 |
KASSERT(ix->ix_ndatalen == sizeof(*cmcred), ("%s: datalen", __func__)); |
2134 |
cmcred = ix->ix_ndata; |
2135 |
cmcred->cmcred_pid = td->td_proc->p_pid; |
2136 |
cmcred->cmcred_uid = cr->cr_ruid; |
2137 |
cmcred->cmcred_gid = cr->cr_rgid; |
2138 |
cmcred->cmcred_euid = cr->cr_uid; |
2139 |
ngroups = MIN(cr->cr_ngroups, CMGROUP_MAX); |
2140 |
cmcred->cmcred_ngroups = ngroups; |
2141 |
for (i = 0; i < ngroups; i++) |
2142 |
cmcred->cmcred_groups[i] = cr->cr_groups[i]; |
2143 |
return (0); |
2144 |
} |
2145 |
|
2146 |
static int |
2147 |
unp_internalize_timestamp(struct internalize_transform_data *ix) |
2148 |
{ |
2149 |
struct timeval *tv; |
2150 |
|
2151 |
KASSERT(ix->ix_ndatalen == sizeof(*tv), ("%s: datalen", __func__)); |
2152 |
tv = ix->ix_ndata; |
2153 |
microtime(tv); |
2154 |
return (0); |
2155 |
} |
2156 |
|
2157 |
static int |
2158 |
unp_internalize_bintime(struct internalize_transform_data *ix) |
2159 |
{ |
2160 |
struct bintime *bt; |
2161 |
|
2162 |
KASSERT(ix->ix_ndatalen == sizeof(*bt), ("%s: datalen", __func__)); |
2163 |
bt = ix->ix_ndata; |
2164 |
bintime(bt); |
2165 |
return (0); |
2166 |
} |
2167 |
|
2082 |
static int |
2168 |
static int |
2083 |
unp_addsockcred(struct mbuf **pcontrol, struct thread *td) |
2169 |
unp_addsockcred(struct mbuf **pcontrol, struct thread *td) |
2084 |
{ |
2170 |
{ |
2085 |
- |
|
|