1 /*-
2  * Copyright (c) 2005 Andrey Simonenko
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/ucred.h>
31 #include <sys/un.h>
32 #include <stdarg.h>
33 #include <stdbool.h>
34 
35 #include "uc_common.h"
36 #include "t_generic.h"
37 #include "t_peercred.h"
38 
39 static int
40 check_xucred(const struct xucred *xucred, socklen_t len)
41 {
42 	int rc;
43 
44 	if (len != sizeof(*xucred)) {
45 		uc_logmsgx("option value size %zu != %zu",
46 		    (size_t)len, sizeof(*xucred));
47 		return (-1);
48 	}
49 
50 	uc_dbgmsg("xucred.cr_version %u", xucred->cr_version);
51 	uc_dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
52 	uc_dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
53 
54 	rc = 0;
55 
56 	if (xucred->cr_version != XUCRED_VERSION) {
57 		uc_logmsgx("xucred.cr_version %u != %d",
58 		    xucred->cr_version, XUCRED_VERSION);
59 		rc = -1;
60 	}
61 	if (xucred->cr_uid != uc_cfg.proc_cred.euid) {
62 		uc_logmsgx("xucred.cr_uid %lu != %lu (EUID)",
63 		    (u_long)xucred->cr_uid, (u_long)uc_cfg.proc_cred.euid);
64 		rc = -1;
65 	}
66 	if (xucred->cr_ngroups == 0) {
67 		uc_logmsgx("xucred.cr_ngroups == 0");
68 		rc = -1;
69 	}
70 	if (xucred->cr_ngroups < 0) {
71 		uc_logmsgx("xucred.cr_ngroups < 0");
72 		rc = -1;
73 	}
74 	if (xucred->cr_ngroups > XU_NGROUPS) {
75 		uc_logmsgx("xucred.cr_ngroups %hu > %u (max)",
76 		    xucred->cr_ngroups, XU_NGROUPS);
77 		rc = -1;
78 	}
79 	if (xucred->cr_groups[0] != uc_cfg.proc_cred.egid) {
80 		uc_logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
81 		    (u_long)xucred->cr_groups[0], (u_long)uc_cfg.proc_cred.egid);
82 		rc = -1;
83 	}
84 	if (uc_check_groups("xucred.cr_groups", xucred->cr_groups,
85 	    "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
86 		rc = -1;
87 	return (rc);
88 }
89 
90 static int
91 t_peercred_client(int fd)
92 {
93 	struct xucred xucred;
94 	socklen_t len;
95 
96 	if (uc_sync_recv() < 0)
97 		return (-1);
98 
99 	if (uc_socket_connect(fd) < 0)
100 		return (-1);
101 
102 	len = sizeof(xucred);
103 	if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
104 		uc_logmsg("getsockopt(LOCAL_PEERCRED)");
105 		return (-1);
106 	}
107 
108 	if (check_xucred(&xucred, len) < 0)
109 		return (-1);
110 
111 	return (0);
112 }
113 
114 static int
115 t_peercred_server(int fd1)
116 {
117 	struct xucred xucred;
118 	socklen_t len;
119 	int fd2, rv;
120 
121 	if (uc_sync_send() < 0)
122 		return (-2);
123 
124 	fd2 = uc_socket_accept(fd1);
125 	if (fd2 < 0)
126 		return (-2);
127 
128 	len = sizeof(xucred);
129 	if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
130 		uc_logmsg("getsockopt(LOCAL_PEERCRED)");
131 		rv = -2;
132 		goto done;
133 	}
134 
135 	if (check_xucred(&xucred, len) < 0) {
136 		rv = -1;
137 		goto done;
138 	}
139 
140 	rv = 0;
141 done:
142 	if (uc_socket_close(fd2) < 0)
143 		rv = -2;
144 	return (rv);
145 }
146 
147 int
148 t_peercred(void)
149 {
150 	return (t_generic(t_peercred_client, t_peercred_server));
151 }
152