| @@ -1,619 +1,619 @@ | | | @@ -1,619 +1,619 @@ |
1 | /* $NetBSD: server.c,v 1.10 2011/07/01 03:07:21 joerg Exp $ */ | | 1 | /* $NetBSD: server.c,v 1.10.4.1 2012/03/05 19:01:49 sborrill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2006 Itronix Inc. | | 4 | * Copyright (c) 2006 Itronix Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. The name of Itronix Inc. may not be used to endorse | | 15 | * 3. The name of Itronix Inc. may not be used to endorse |
16 | * or promote products derived from this software without specific | | 16 | * or promote products derived from this software without specific |
17 | * prior written permission. | | 17 | * prior written permission. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND | | 19 | * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | 23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | /*- | | 31 | /*- |
32 | * Copyright (c) 2009 The NetBSD Foundation, Inc. | | 32 | * Copyright (c) 2009 The NetBSD Foundation, Inc. |
33 | * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> | | 33 | * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> |
34 | * All rights reserved. | | 34 | * All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * | | 44 | * |
45 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | | 45 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
55 | * SUCH DAMAGE. | | 55 | * SUCH DAMAGE. |
56 | * | | 56 | * |
57 | * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $ | | 57 | * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $ |
58 | */ | | 58 | */ |
59 | | | 59 | |
60 | #include <sys/cdefs.h> | | 60 | #include <sys/cdefs.h> |
61 | __RCSID("$NetBSD: server.c,v 1.10 2011/07/01 03:07:21 joerg Exp $"); | | 61 | __RCSID("$NetBSD: server.c,v 1.10.4.1 2012/03/05 19:01:49 sborrill Exp $"); |
62 | | | 62 | |
63 | #include <sys/select.h> | | 63 | #include <sys/select.h> |
64 | #include <sys/stat.h> | | 64 | #include <sys/stat.h> |
65 | #include <sys/ucred.h> | | 65 | #include <sys/ucred.h> |
66 | #include <sys/un.h> | | 66 | #include <sys/un.h> |
67 | | | 67 | |
68 | #include <assert.h> | | 68 | #include <assert.h> |
69 | #include <bluetooth.h> | | 69 | #include <bluetooth.h> |
70 | #include <errno.h> | | 70 | #include <errno.h> |
71 | #include <grp.h> | | 71 | #include <grp.h> |
72 | #include <pwd.h> | | 72 | #include <pwd.h> |
73 | #include <sdp.h> | | 73 | #include <sdp.h> |
74 | #include <stdio.h> | | 74 | #include <stdio.h> |
75 | #include <stdlib.h> | | 75 | #include <stdlib.h> |
76 | #include <string.h> | | 76 | #include <string.h> |
77 | #include <unistd.h> | | 77 | #include <unistd.h> |
78 | | | 78 | |
79 | #include "sdpd.h" | | 79 | #include "sdpd.h" |
80 | | | 80 | |
81 | static bool server_open_control (server_t *, char const *); | | 81 | static bool server_open_control (server_t *, char const *); |
82 | static bool server_open_l2cap (server_t *); | | 82 | static bool server_open_l2cap (server_t *); |
83 | static void server_accept_client (server_t *, int); | | 83 | static void server_accept_client (server_t *, int); |
84 | static bool server_process_request (server_t *, int); | | 84 | static bool server_process_request (server_t *, int); |
85 | static void server_close_fd (server_t *, int); | | 85 | static void server_close_fd (server_t *, int); |
86 | static bool server_auth_check (server_t *, void *); | | 86 | static bool server_auth_check (server_t *, void *); |
87 | | | 87 | |
88 | /* number of groups we allocate space for in cmsg */ | | 88 | /* number of groups we allocate space for in cmsg */ |
89 | #define MAX_GROUPS 20 | | 89 | #define MAX_GROUPS 20 |
90 | | | 90 | |
91 | /* | | 91 | /* |
92 | * Initialize server | | 92 | * Initialize server |
93 | */ | | 93 | */ |
94 | bool | | 94 | bool |
95 | server_init(server_t *srv, char const *control, char const *sgroup) | | 95 | server_init(server_t *srv, char const *control, char const *sgroup) |
96 | { | | 96 | { |
97 | | | 97 | |
98 | assert(srv != NULL); | | 98 | assert(srv != NULL); |
99 | assert(control != NULL); | | 99 | assert(control != NULL); |
100 | | | 100 | |
101 | memset(srv, 0, sizeof(*srv)); | | 101 | memset(srv, 0, sizeof(*srv)); |
102 | FD_ZERO(&srv->fdset); | | 102 | FD_ZERO(&srv->fdset); |
103 | srv->sgroup = sgroup; | | 103 | srv->sgroup = sgroup; |
104 | | | 104 | |
105 | srv->fdmax = -1; | | 105 | srv->fdmax = -1; |
106 | srv->fdidx = calloc(FD_SETSIZE, sizeof(fd_idx_t)); | | 106 | srv->fdidx = calloc(FD_SETSIZE, sizeof(fd_idx_t)); |
107 | if (srv->fdidx == NULL) { | | 107 | if (srv->fdidx == NULL) { |
108 | log_crit("Failed to allocate fd index"); | | 108 | log_crit("Failed to allocate fd index"); |
109 | goto fail; | | 109 | goto fail; |
110 | } | | 110 | } |
111 | | | 111 | |
112 | srv->ctllen = CMSG_SPACE(SOCKCREDSIZE(MAX_GROUPS)); | | 112 | srv->ctllen = CMSG_SPACE(SOCKCREDSIZE(MAX_GROUPS)); |
113 | srv->ctlbuf = malloc(srv->ctllen); | | 113 | srv->ctlbuf = malloc(srv->ctllen); |
114 | if (srv->ctlbuf == NULL) { | | 114 | if (srv->ctlbuf == NULL) { |
115 | log_crit("Malloc cmsg buffer (len=%d) failed.", srv->ctllen); | | 115 | log_crit("Malloc cmsg buffer (len=%zu) failed.", srv->ctllen); |
116 | goto fail; | | 116 | goto fail; |
117 | } | | 117 | } |
118 | | | 118 | |
119 | srv->imtu = SDP_LOCAL_MTU - sizeof(sdp_pdu_t); | | 119 | srv->imtu = SDP_LOCAL_MTU - sizeof(sdp_pdu_t); |
120 | srv->ibuf = malloc(srv->imtu); | | 120 | srv->ibuf = malloc(srv->imtu); |
121 | if (srv->ibuf == NULL) { | | 121 | if (srv->ibuf == NULL) { |
122 | log_crit("Malloc input buffer (imtu=%d) failed.", srv->imtu); | | 122 | log_crit("Malloc input buffer (imtu=%d) failed.", srv->imtu); |
123 | goto fail; | | 123 | goto fail; |
124 | } | | 124 | } |
125 | | | 125 | |
126 | srv->omtu = L2CAP_MTU_DEFAULT - sizeof(sdp_pdu_t); | | 126 | srv->omtu = L2CAP_MTU_DEFAULT - sizeof(sdp_pdu_t); |
127 | srv->obuf = malloc(srv->omtu); | | 127 | srv->obuf = malloc(srv->omtu); |
128 | if (srv->obuf == NULL) { | | 128 | if (srv->obuf == NULL) { |
129 | log_crit("Malloc output buffer (omtu=%d) failed.", srv->omtu); | | 129 | log_crit("Malloc output buffer (omtu=%d) failed.", srv->omtu); |
130 | goto fail; | | 130 | goto fail; |
131 | } | | 131 | } |
132 | | | 132 | |
133 | if (db_init(srv) | | 133 | if (db_init(srv) |
134 | && server_open_control(srv, control) | | 134 | && server_open_control(srv, control) |
135 | && server_open_l2cap(srv)) | | 135 | && server_open_l2cap(srv)) |
136 | return true; | | 136 | return true; |
137 | | | 137 | |
138 | fail: | | 138 | fail: |
139 | server_shutdown(srv); | | 139 | server_shutdown(srv); |
140 | return false; | | 140 | return false; |
141 | } | | 141 | } |
142 | | | 142 | |
143 | /* | | 143 | /* |
144 | * Open local control socket | | 144 | * Open local control socket |
145 | */ | | 145 | */ |
146 | static bool | | 146 | static bool |
147 | server_open_control(server_t *srv, char const *control) | | 147 | server_open_control(server_t *srv, char const *control) |
148 | { | | 148 | { |
149 | struct sockaddr_un un; | | 149 | struct sockaddr_un un; |
150 | int opt, fd; | | 150 | int opt, fd; |
151 | | | 151 | |
152 | if (unlink(control) == -1 && errno != ENOENT) { | | 152 | if (unlink(control) == -1 && errno != ENOENT) { |
153 | log_crit("Could not unlink(%s). %s (%d)", | | 153 | log_crit("Could not unlink(%s). %s (%d)", |
154 | control, strerror(errno), errno); | | 154 | control, strerror(errno), errno); |
155 | | | 155 | |
156 | return false; | | 156 | return false; |
157 | } | | 157 | } |
158 | | | 158 | |
159 | fd = socket(PF_LOCAL, SOCK_STREAM, 0); | | 159 | fd = socket(PF_LOCAL, SOCK_STREAM, 0); |
160 | if (fd == -1) { | | 160 | if (fd == -1) { |
161 | log_crit("Could not create control socket. %s (%d)", | | 161 | log_crit("Could not create control socket. %s (%d)", |
162 | strerror(errno), errno); | | 162 | strerror(errno), errno); |
163 | | | 163 | |
164 | return false; | | 164 | return false; |
165 | } | | 165 | } |
166 | | | 166 | |
167 | opt = 1; | | 167 | opt = 1; |
168 | if (setsockopt(fd, 0, LOCAL_CREDS, &opt, sizeof(opt)) == -1) | | 168 | if (setsockopt(fd, 0, LOCAL_CREDS, &opt, sizeof(opt)) == -1) |
169 | log_crit("Warning: No credential checks on control socket"); | | 169 | log_crit("Warning: No credential checks on control socket"); |
170 | | | 170 | |
171 | memset(&un, 0, sizeof(un)); | | 171 | memset(&un, 0, sizeof(un)); |
172 | un.sun_len = sizeof(un); | | 172 | un.sun_len = sizeof(un); |
173 | un.sun_family = AF_LOCAL; | | 173 | un.sun_family = AF_LOCAL; |
174 | strlcpy(un.sun_path, control, sizeof(un.sun_path)); | | 174 | strlcpy(un.sun_path, control, sizeof(un.sun_path)); |
175 | | | 175 | |
176 | if (bind(fd, (struct sockaddr *) &un, sizeof(un)) == -1) { | | 176 | if (bind(fd, (struct sockaddr *) &un, sizeof(un)) == -1) { |
177 | log_crit("Could not bind control socket. %s (%d)", | | 177 | log_crit("Could not bind control socket. %s (%d)", |
178 | strerror(errno), errno); | | 178 | strerror(errno), errno); |
179 | | | 179 | |
180 | close(fd); | | 180 | close(fd); |
181 | return false; | | 181 | return false; |
182 | } | | 182 | } |
183 | | | 183 | |
184 | if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { | | 184 | if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { |
185 | log_crit("Could not set permissions on control socket. %s (%d)", | | 185 | log_crit("Could not set permissions on control socket. %s (%d)", |
186 | strerror(errno), errno); | | 186 | strerror(errno), errno); |
187 | | | 187 | |
188 | close(fd); | | 188 | close(fd); |
189 | return false; | | 189 | return false; |
190 | } | | 190 | } |
191 | | | 191 | |
192 | if (listen(fd, 5) == -1) { | | 192 | if (listen(fd, 5) == -1) { |
193 | log_crit("Could not listen on control socket. %s (%d)", | | 193 | log_crit("Could not listen on control socket. %s (%d)", |
194 | strerror(errno), errno); | | 194 | strerror(errno), errno); |
195 | | | 195 | |
196 | close(fd); | | 196 | close(fd); |
197 | return false; | | 197 | return false; |
198 | } | | 198 | } |
199 | | | 199 | |
200 | /* Add control descriptor to index */ | | 200 | /* Add control descriptor to index */ |
201 | if (fd > srv->fdmax) | | 201 | if (fd > srv->fdmax) |
202 | srv->fdmax = fd; | | 202 | srv->fdmax = fd; |
203 | | | 203 | |
204 | FD_SET(fd, &srv->fdset); | | 204 | FD_SET(fd, &srv->fdset); |
205 | srv->fdidx[fd].valid = true; | | 205 | srv->fdidx[fd].valid = true; |
206 | srv->fdidx[fd].server = true; | | 206 | srv->fdidx[fd].server = true; |
207 | srv->fdidx[fd].control = true; | | 207 | srv->fdidx[fd].control = true; |
208 | srv->fdidx[fd].priv = false; | | 208 | srv->fdidx[fd].priv = false; |
209 | return true; | | 209 | return true; |
210 | } | | 210 | } |
211 | | | 211 | |
212 | /* | | 212 | /* |
213 | * Open L2CAP server socket | | 213 | * Open L2CAP server socket |
214 | */ | | 214 | */ |
215 | static bool | | 215 | static bool |
216 | server_open_l2cap(server_t *srv) | | 216 | server_open_l2cap(server_t *srv) |
217 | { | | 217 | { |
218 | struct sockaddr_bt sa; | | 218 | struct sockaddr_bt sa; |
219 | int fd; | | 219 | int fd; |
220 | | | 220 | |
221 | fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); | | 221 | fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); |
222 | if (fd == -1) { | | 222 | if (fd == -1) { |
223 | log_crit("Could not create L2CAP socket. %s (%d)", | | 223 | log_crit("Could not create L2CAP socket. %s (%d)", |
224 | strerror(errno), errno); | | 224 | strerror(errno), errno); |
225 | | | 225 | |
226 | return false; | | 226 | return false; |
227 | } | | 227 | } |
228 | | | 228 | |
229 | if (setsockopt(fd, BTPROTO_L2CAP, SO_L2CAP_IMTU, | | 229 | if (setsockopt(fd, BTPROTO_L2CAP, SO_L2CAP_IMTU, |
230 | &srv->imtu, sizeof(srv->imtu)) == -1) { | | 230 | &srv->imtu, sizeof(srv->imtu)) == -1) { |
231 | log_crit("Could not set L2CAP Incoming MTU. %s (%d)", | | 231 | log_crit("Could not set L2CAP Incoming MTU. %s (%d)", |
232 | strerror(errno), errno); | | 232 | strerror(errno), errno); |
233 | | | 233 | |
234 | close(fd); | | 234 | close(fd); |
235 | return false; | | 235 | return false; |
236 | } | | 236 | } |
237 | | | 237 | |
238 | memset(&sa, 0, sizeof(sa)); | | 238 | memset(&sa, 0, sizeof(sa)); |
239 | sa.bt_len = sizeof(sa); | | 239 | sa.bt_len = sizeof(sa); |
240 | sa.bt_family = AF_BLUETOOTH; | | 240 | sa.bt_family = AF_BLUETOOTH; |
241 | sa.bt_psm = L2CAP_PSM_SDP; | | 241 | sa.bt_psm = L2CAP_PSM_SDP; |
242 | bdaddr_copy(&sa.bt_bdaddr, BDADDR_ANY); | | 242 | bdaddr_copy(&sa.bt_bdaddr, BDADDR_ANY); |
243 | | | 243 | |
244 | if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) { | | 244 | if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) { |
245 | log_crit("Could not bind L2CAP socket. %s (%d)", | | 245 | log_crit("Could not bind L2CAP socket. %s (%d)", |
246 | strerror(errno), errno); | | 246 | strerror(errno), errno); |
247 | | | 247 | |
248 | close(fd); | | 248 | close(fd); |
249 | return false; | | 249 | return false; |
250 | } | | 250 | } |
251 | | | 251 | |
252 | if (listen(fd, 5) == -1) { | | 252 | if (listen(fd, 5) == -1) { |
253 | log_crit("Could not listen on L2CAP socket. %s (%d)", | | 253 | log_crit("Could not listen on L2CAP socket. %s (%d)", |
254 | strerror(errno), errno); | | 254 | strerror(errno), errno); |
255 | | | 255 | |
256 | close(fd); | | 256 | close(fd); |
257 | return false; | | 257 | return false; |
258 | } | | 258 | } |
259 | | | 259 | |
260 | /* Add L2CAP descriptor to index */ | | 260 | /* Add L2CAP descriptor to index */ |
261 | if (fd > srv->fdmax) | | 261 | if (fd > srv->fdmax) |
262 | srv->fdmax = fd; | | 262 | srv->fdmax = fd; |
263 | | | 263 | |
264 | FD_SET(fd, &srv->fdset); | | 264 | FD_SET(fd, &srv->fdset); |
265 | srv->fdidx[fd].valid = true; | | 265 | srv->fdidx[fd].valid = true; |
266 | srv->fdidx[fd].server = true; | | 266 | srv->fdidx[fd].server = true; |
267 | srv->fdidx[fd].control = false; | | 267 | srv->fdidx[fd].control = false; |
268 | srv->fdidx[fd].priv = false; | | 268 | srv->fdidx[fd].priv = false; |
269 | return true; | | 269 | return true; |
270 | } | | 270 | } |
271 | | | 271 | |
272 | /* | | 272 | /* |
273 | * Shutdown server | | 273 | * Shutdown server |
274 | */ | | 274 | */ |
275 | void | | 275 | void |
276 | server_shutdown(server_t *srv) | | 276 | server_shutdown(server_t *srv) |
277 | { | | 277 | { |
278 | record_t *r; | | 278 | record_t *r; |
279 | int fd; | | 279 | int fd; |
280 | | | 280 | |
281 | assert(srv != NULL); | | 281 | assert(srv != NULL); |
282 | | | 282 | |
283 | while ((r = LIST_FIRST(&srv->rlist)) != NULL) { | | 283 | while ((r = LIST_FIRST(&srv->rlist)) != NULL) { |
284 | LIST_REMOVE(r, next); | | 284 | LIST_REMOVE(r, next); |
285 | free(r); | | 285 | free(r); |
286 | } | | 286 | } |
287 | | | 287 | |
288 | for (fd = 0; fd < srv->fdmax + 1; fd ++) { | | 288 | for (fd = 0; fd < srv->fdmax + 1; fd ++) { |
289 | if (srv->fdidx[fd].valid) | | 289 | if (srv->fdidx[fd].valid) |
290 | server_close_fd(srv, fd); | | 290 | server_close_fd(srv, fd); |
291 | } | | 291 | } |
292 | | | 292 | |
293 | free(srv->fdidx); | | 293 | free(srv->fdidx); |
294 | free(srv->ctlbuf); | | 294 | free(srv->ctlbuf); |
295 | free(srv->ibuf); | | 295 | free(srv->ibuf); |
296 | free(srv->obuf); | | 296 | free(srv->obuf); |
297 | | | 297 | |
298 | memset(srv, 0, sizeof(*srv)); | | 298 | memset(srv, 0, sizeof(*srv)); |
299 | } | | 299 | } |
300 | | | 300 | |
301 | /* | | 301 | /* |
302 | * Do one server iteration | | 302 | * Do one server iteration |
303 | */ | | 303 | */ |
304 | bool | | 304 | bool |
305 | server_do(server_t *srv) | | 305 | server_do(server_t *srv) |
306 | { | | 306 | { |
307 | fd_set fdset; | | 307 | fd_set fdset; |
308 | int n, fd; | | 308 | int n, fd; |
309 | | | 309 | |
310 | assert(srv != NULL); | | 310 | assert(srv != NULL); |
311 | | | 311 | |
312 | memcpy(&fdset, &srv->fdset, sizeof(fdset)); | | 312 | memcpy(&fdset, &srv->fdset, sizeof(fdset)); |
313 | n = select(srv->fdmax + 1, &fdset, NULL, NULL, NULL); | | 313 | n = select(srv->fdmax + 1, &fdset, NULL, NULL, NULL); |
314 | if (n == -1) { | | 314 | if (n == -1) { |
315 | if (errno == EINTR) | | 315 | if (errno == EINTR) |
316 | return true; | | 316 | return true; |
317 | | | 317 | |
318 | log_err("Could not select(%d, %p). %s (%d)", | | 318 | log_err("Could not select(%d, %p). %s (%d)", |
319 | srv->fdmax + 1, &fdset, strerror(errno), errno); | | 319 | srv->fdmax + 1, &fdset, strerror(errno), errno); |
320 | | | 320 | |
321 | return false; | | 321 | return false; |
322 | } | | 322 | } |
323 | | | 323 | |
324 | for (fd = 0; fd < srv->fdmax + 1 && n > 0; fd++) { | | 324 | for (fd = 0; fd < srv->fdmax + 1 && n > 0; fd++) { |
325 | if (!FD_ISSET(fd, &fdset)) | | 325 | if (!FD_ISSET(fd, &fdset)) |
326 | continue; | | 326 | continue; |
327 | | | 327 | |
328 | assert(srv->fdidx[fd].valid); | | 328 | assert(srv->fdidx[fd].valid); |
329 | | | 329 | |
330 | if (srv->fdidx[fd].server) | | 330 | if (srv->fdidx[fd].server) |
331 | server_accept_client(srv, fd); | | 331 | server_accept_client(srv, fd); |
332 | else if (!server_process_request(srv, fd)) | | 332 | else if (!server_process_request(srv, fd)) |
333 | server_close_fd(srv, fd); | | 333 | server_close_fd(srv, fd); |
334 | | | 334 | |
335 | n--; | | 335 | n--; |
336 | } | | 336 | } |
337 | | | 337 | |
338 | return true; | | 338 | return true; |
339 | | | 339 | |
340 | } | | 340 | } |
341 | | | 341 | |
342 | /* | | 342 | /* |
343 | * Accept new client connection and register it with index | | 343 | * Accept new client connection and register it with index |
344 | */ | | 344 | */ |
345 | static void | | 345 | static void |
346 | server_accept_client(server_t *srv, int fd) | | 346 | server_accept_client(server_t *srv, int fd) |
347 | { | | 347 | { |
348 | struct sockaddr_bt sa; | | 348 | struct sockaddr_bt sa; |
349 | socklen_t len; | | 349 | socklen_t len; |
350 | int cfd; | | 350 | int cfd; |
351 | uint16_t omtu; | | 351 | uint16_t omtu; |
352 | | | 352 | |
353 | do { | | 353 | do { |
354 | cfd = accept(fd, NULL, NULL); | | 354 | cfd = accept(fd, NULL, NULL); |
355 | } while (cfd == -1 && errno == EINTR); | | 355 | } while (cfd == -1 && errno == EINTR); |
356 | | | 356 | |
357 | if (cfd == -1) { | | 357 | if (cfd == -1) { |
358 | log_err("Could not accept connection on %s socket. %s (%d)", | | 358 | log_err("Could not accept connection on %s socket. %s (%d)", |
359 | srv->fdidx[fd].control ? "control" : "L2CAP", | | 359 | srv->fdidx[fd].control ? "control" : "L2CAP", |
360 | strerror(errno), errno); | | 360 | strerror(errno), errno); |
361 | | | 361 | |
362 | return; | | 362 | return; |
363 | } | | 363 | } |
364 | | | 364 | |
365 | if (cfd >= FD_SETSIZE) { | | 365 | if (cfd >= FD_SETSIZE) { |
366 | log_crit("File descriptor too large"); | | 366 | log_crit("File descriptor too large"); |
367 | close(cfd); | | 367 | close(cfd); |
368 | return; | | 368 | return; |
369 | } | | 369 | } |
370 | | | 370 | |
371 | assert(!FD_ISSET(cfd, &srv->fdset)); | | 371 | assert(!FD_ISSET(cfd, &srv->fdset)); |
372 | assert(!srv->fdidx[cfd].valid); | | 372 | assert(!srv->fdidx[cfd].valid); |
373 | | | 373 | |
374 | memset(&sa, 0, sizeof(sa)); | | 374 | memset(&sa, 0, sizeof(sa)); |
375 | omtu = srv->omtu; | | 375 | omtu = srv->omtu; |
376 | | | 376 | |
377 | if (!srv->fdidx[fd].control) { | | 377 | if (!srv->fdidx[fd].control) { |
378 | len = sizeof(sa); | | 378 | len = sizeof(sa); |
379 | if (getsockname(cfd, (struct sockaddr *)&sa, &len) == -1) | | 379 | if (getsockname(cfd, (struct sockaddr *)&sa, &len) == -1) |
380 | log_warning("getsockname failed, using BDADDR_ANY"); | | 380 | log_warning("getsockname failed, using BDADDR_ANY"); |
381 | | | 381 | |
382 | len = sizeof(omtu); | | 382 | len = sizeof(omtu); |
383 | if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &len) == -1) | | 383 | if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &len) == -1) |
384 | log_warning("Could not get L2CAP OMTU, using %d", omtu); | | 384 | log_warning("Could not get L2CAP OMTU, using %d", omtu); |
385 | else | | 385 | else |
386 | omtu -= sizeof(sdp_pdu_t); | | 386 | omtu -= sizeof(sdp_pdu_t); |
387 | } | | 387 | } |
388 | | | 388 | |
389 | /* Add client descriptor to the index */ | | 389 | /* Add client descriptor to the index */ |
390 | if (cfd > srv->fdmax) | | 390 | if (cfd > srv->fdmax) |
391 | srv->fdmax = cfd; | | 391 | srv->fdmax = cfd; |
392 | | | 392 | |
393 | FD_SET(cfd, &srv->fdset); | | 393 | FD_SET(cfd, &srv->fdset); |
394 | srv->fdidx[cfd].valid = true; | | 394 | srv->fdidx[cfd].valid = true; |
395 | srv->fdidx[cfd].server = false; | | 395 | srv->fdidx[cfd].server = false; |
396 | srv->fdidx[cfd].control = srv->fdidx[fd].control; | | 396 | srv->fdidx[cfd].control = srv->fdidx[fd].control; |
397 | srv->fdidx[cfd].priv = false; | | 397 | srv->fdidx[cfd].priv = false; |
398 | srv->fdidx[cfd].omtu = (omtu > srv->omtu) ? srv->omtu : omtu; | | 398 | srv->fdidx[cfd].omtu = (omtu > srv->omtu) ? srv->omtu : omtu; |
399 | srv->fdidx[cfd].offset = 0; | | 399 | srv->fdidx[cfd].offset = 0; |
400 | bdaddr_copy(&srv->fdidx[cfd].bdaddr, &sa.bt_bdaddr); | | 400 | bdaddr_copy(&srv->fdidx[cfd].bdaddr, &sa.bt_bdaddr); |
401 | | | 401 | |
402 | log_debug("new %s client on fd#%d", | | 402 | log_debug("new %s client on fd#%d", |
403 | srv->fdidx[cfd].control ? "control" : "L2CAP", cfd); | | 403 | srv->fdidx[cfd].control ? "control" : "L2CAP", cfd); |
404 | } | | 404 | } |
405 | | | 405 | |
406 | /* | | 406 | /* |
407 | * Process request from the client | | 407 | * Process request from the client |
408 | */ | | 408 | */ |
409 | static bool | | 409 | static bool |
410 | server_process_request(server_t *srv, int fd) | | 410 | server_process_request(server_t *srv, int fd) |
411 | { | | 411 | { |
412 | struct msghdr msg; | | 412 | struct msghdr msg; |
413 | struct iovec iov[2]; | | 413 | struct iovec iov[2]; |
414 | struct cmsghdr *cmsg; | | 414 | struct cmsghdr *cmsg; |
415 | ssize_t len; | | 415 | ssize_t len; |
416 | uint16_t error; | | 416 | uint16_t error; |
417 | | | 417 | |
418 | assert(FD_ISSET(fd, &srv->fdset)); | | 418 | assert(FD_ISSET(fd, &srv->fdset)); |
419 | assert(srv->fdidx[fd].valid); | | 419 | assert(srv->fdidx[fd].valid); |
420 | assert(!srv->fdidx[fd].server); | | 420 | assert(!srv->fdidx[fd].server); |
421 | | | 421 | |
422 | iov[0].iov_base = &srv->pdu; | | 422 | iov[0].iov_base = &srv->pdu; |
423 | iov[0].iov_len = sizeof(srv->pdu); | | 423 | iov[0].iov_len = sizeof(srv->pdu); |
424 | iov[1].iov_base = srv->ibuf; | | 424 | iov[1].iov_base = srv->ibuf; |
425 | iov[1].iov_len = srv->imtu; | | 425 | iov[1].iov_len = srv->imtu; |
426 | | | 426 | |
427 | msg.msg_name = NULL; | | 427 | msg.msg_name = NULL; |
428 | msg.msg_namelen = 0; | | 428 | msg.msg_namelen = 0; |
429 | msg.msg_iov = iov; | | 429 | msg.msg_iov = iov; |
430 | msg.msg_iovlen = __arraycount(iov); | | 430 | msg.msg_iovlen = __arraycount(iov); |
431 | msg.msg_control = srv->ctlbuf; | | 431 | msg.msg_control = srv->ctlbuf; |
432 | msg.msg_controllen = srv->ctllen; | | 432 | msg.msg_controllen = srv->ctllen; |
433 | msg.msg_flags = 0; | | 433 | msg.msg_flags = 0; |
434 | | | 434 | |
435 | do { | | 435 | do { |
436 | len = recvmsg(fd, &msg, 0); | | 436 | len = recvmsg(fd, &msg, 0); |
437 | } while (len == -1 && errno == EINTR); | | 437 | } while (len == -1 && errno == EINTR); |
438 | | | 438 | |
439 | if (len == -1) { | | 439 | if (len == -1) { |
440 | log_err("Could not receive SDP request on %s socket. %s (%d)", | | 440 | log_err("Could not receive SDP request on %s socket. %s (%d)", |
441 | srv->fdidx[fd].control ? "control" : "L2CAP", | | 441 | srv->fdidx[fd].control ? "control" : "L2CAP", |
442 | strerror(errno), errno); | | 442 | strerror(errno), errno); |
443 | | | 443 | |
444 | return false; | | 444 | return false; |
445 | } | | 445 | } |
446 | | | 446 | |
447 | if (len == 0) { | | 447 | if (len == 0) { |
448 | log_info("Client on %s socket has disconnected", | | 448 | log_info("Client on %s socket has disconnected", |
449 | srv->fdidx[fd].control ? "control" : "L2CAP"); | | 449 | srv->fdidx[fd].control ? "control" : "L2CAP"); |
450 | | | 450 | |
451 | return false; | | 451 | return false; |
452 | } | | 452 | } |
453 | | | 453 | |
454 | if (msg.msg_flags & MSG_TRUNC) | | 454 | if (msg.msg_flags & MSG_TRUNC) |
455 | log_info("Truncated message on %s socket", | | 455 | log_info("Truncated message on %s socket", |
456 | srv->fdidx[fd].control ? "control" : "L2CAP"); | | 456 | srv->fdidx[fd].control ? "control" : "L2CAP"); |
457 | | | 457 | |
458 | if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL | | 458 | if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL |
459 | && cmsg->cmsg_level == SOL_SOCKET | | 459 | && cmsg->cmsg_level == SOL_SOCKET |
460 | && cmsg->cmsg_type == SCM_CREDS | | 460 | && cmsg->cmsg_type == SCM_CREDS |
461 | && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0))) | | 461 | && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0))) |
462 | srv->fdidx[fd].priv = server_auth_check(srv, CMSG_DATA(cmsg)); | | 462 | srv->fdidx[fd].priv = server_auth_check(srv, CMSG_DATA(cmsg)); |
463 | | | 463 | |
464 | srv->pdu.len = be16toh(srv->pdu.len); | | 464 | srv->pdu.len = be16toh(srv->pdu.len); |
465 | | | 465 | |
466 | if ((uint32_t)len < sizeof(srv->pdu) | | 466 | if ((uint32_t)len < sizeof(srv->pdu) |
467 | || (uint32_t)len != sizeof(srv->pdu) + srv->pdu.len) { | | 467 | || (uint32_t)len != sizeof(srv->pdu) + srv->pdu.len) { |
468 | error = SDP_ERROR_CODE_INVALID_PDU_SIZE; | | 468 | error = SDP_ERROR_CODE_INVALID_PDU_SIZE; |
469 | } else { | | 469 | } else { |
470 | switch (srv->pdu.pid) { | | 470 | switch (srv->pdu.pid) { |
471 | case SDP_PDU_SERVICE_SEARCH_REQUEST: | | 471 | case SDP_PDU_SERVICE_SEARCH_REQUEST: |
472 | error = service_search_request(srv, fd); | | 472 | error = service_search_request(srv, fd); |
473 | break; | | 473 | break; |
474 | | | 474 | |
475 | case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST: | | 475 | case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST: |
476 | error = service_attribute_request(srv, fd); | | 476 | error = service_attribute_request(srv, fd); |
477 | break; | | 477 | break; |
478 | | | 478 | |
479 | case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST: | | 479 | case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST: |
480 | error = service_search_attribute_request(srv, fd); | | 480 | error = service_search_attribute_request(srv, fd); |
481 | break; | | 481 | break; |
482 | | | 482 | |
483 | #ifdef SDP_COMPAT | | 483 | #ifdef SDP_COMPAT |
484 | case SDP_PDU_SERVICE_REGISTER_REQUEST: | | 484 | case SDP_PDU_SERVICE_REGISTER_REQUEST: |
485 | error = compat_register_request(srv, fd); | | 485 | error = compat_register_request(srv, fd); |
486 | break; | | 486 | break; |
487 | | | 487 | |
488 | case SDP_PDU_SERVICE_CHANGE_REQUEST: | | 488 | case SDP_PDU_SERVICE_CHANGE_REQUEST: |
489 | error = compat_change_request(srv, fd); | | 489 | error = compat_change_request(srv, fd); |
490 | break; | | 490 | break; |
491 | #endif | | 491 | #endif |
492 | | | 492 | |
493 | case SDP_PDU_RECORD_INSERT_REQUEST: | | 493 | case SDP_PDU_RECORD_INSERT_REQUEST: |
494 | error = record_insert_request(srv, fd); | | 494 | error = record_insert_request(srv, fd); |
495 | break; | | 495 | break; |
496 | | | 496 | |
497 | case SDP_PDU_RECORD_UPDATE_REQUEST: | | 497 | case SDP_PDU_RECORD_UPDATE_REQUEST: |
498 | error = record_update_request(srv, fd); | | 498 | error = record_update_request(srv, fd); |
499 | break; | | 499 | break; |
500 | | | 500 | |
501 | case SDP_PDU_RECORD_REMOVE_REQUEST: | | 501 | case SDP_PDU_RECORD_REMOVE_REQUEST: |
502 | error = record_remove_request(srv, fd); | | 502 | error = record_remove_request(srv, fd); |
503 | break; | | 503 | break; |
504 | | | 504 | |
505 | default: | | 505 | default: |
506 | error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; | | 506 | error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; |
507 | break; | | 507 | break; |
508 | } | | 508 | } |
509 | } | | 509 | } |
510 | | | 510 | |
511 | if (error != 0) { | | 511 | if (error != 0) { |
512 | srv->fdidx[fd].offset = 0; | | 512 | srv->fdidx[fd].offset = 0; |
513 | db_unselect(srv, fd); | | 513 | db_unselect(srv, fd); |
514 | srv->pdu.pid = SDP_PDU_ERROR_RESPONSE; | | 514 | srv->pdu.pid = SDP_PDU_ERROR_RESPONSE; |
515 | srv->pdu.len = sizeof(error); | | 515 | srv->pdu.len = sizeof(error); |
516 | be16enc(srv->obuf, error); | | 516 | be16enc(srv->obuf, error); |
517 | log_debug("sending ErrorResponse (error=0x%04x)", error); | | 517 | log_debug("sending ErrorResponse (error=0x%04x)", error); |
518 | } | | 518 | } |
519 | | | 519 | |
520 | iov[0].iov_base = &srv->pdu; | | 520 | iov[0].iov_base = &srv->pdu; |
521 | iov[0].iov_len = sizeof(srv->pdu); | | 521 | iov[0].iov_len = sizeof(srv->pdu); |
522 | iov[1].iov_base = srv->obuf; | | 522 | iov[1].iov_base = srv->obuf; |
523 | iov[1].iov_len = srv->pdu.len; | | 523 | iov[1].iov_len = srv->pdu.len; |
524 | | | 524 | |
525 | srv->pdu.len = htobe16(srv->pdu.len); | | 525 | srv->pdu.len = htobe16(srv->pdu.len); |
526 | | | 526 | |
527 | msg.msg_name = NULL; | | 527 | msg.msg_name = NULL; |
528 | msg.msg_namelen = 0; | | 528 | msg.msg_namelen = 0; |
529 | msg.msg_iov = iov; | | 529 | msg.msg_iov = iov; |
530 | msg.msg_iovlen = __arraycount(iov); | | 530 | msg.msg_iovlen = __arraycount(iov); |
531 | msg.msg_control = NULL; | | 531 | msg.msg_control = NULL; |
532 | msg.msg_controllen = 0; | | 532 | msg.msg_controllen = 0; |
533 | msg.msg_flags = 0; | | 533 | msg.msg_flags = 0; |
534 | | | 534 | |
535 | do { | | 535 | do { |
536 | len = sendmsg(fd, &msg, 0); | | 536 | len = sendmsg(fd, &msg, 0); |
537 | } while (len == -1 && errno == EINTR); | | 537 | } while (len == -1 && errno == EINTR); |
538 | | | 538 | |
539 | if (len == -1) { | | 539 | if (len == -1) { |
540 | log_err("Could not send SDP response on %s socket. %s (%d)", | | 540 | log_err("Could not send SDP response on %s socket. %s (%d)", |
541 | srv->fdidx[fd].control ? "control" : "L2CAP", | | 541 | srv->fdidx[fd].control ? "control" : "L2CAP", |
542 | strerror(errno), errno); | | 542 | strerror(errno), errno); |
543 | | | 543 | |
544 | return false; | | 544 | return false; |
545 | } | | 545 | } |
546 | | | 546 | |
547 | return true; | | 547 | return true; |
548 | } | | 548 | } |
549 | | | 549 | |
550 | /* | | 550 | /* |
551 | * Close descriptor and remove it from index | | 551 | * Close descriptor and remove it from index |
552 | */ | | 552 | */ |
553 | static void | | 553 | static void |
554 | server_close_fd(server_t *srv, int fd) | | 554 | server_close_fd(server_t *srv, int fd) |
555 | { | | 555 | { |
556 | | | 556 | |
557 | assert(FD_ISSET(fd, &srv->fdset)); | | 557 | assert(FD_ISSET(fd, &srv->fdset)); |
558 | assert(srv->fdidx[fd].valid); | | 558 | assert(srv->fdidx[fd].valid); |
559 | | | 559 | |
560 | db_unselect(srv, fd); /* release selected records */ | | 560 | db_unselect(srv, fd); /* release selected records */ |
561 | db_release(srv, fd); /* expire owned records */ | | 561 | db_release(srv, fd); /* expire owned records */ |
562 | | | 562 | |
563 | close(fd); | | 563 | close(fd); |
564 | FD_CLR(fd, &srv->fdset); | | 564 | FD_CLR(fd, &srv->fdset); |
565 | srv->fdidx[fd].valid = false; | | 565 | srv->fdidx[fd].valid = false; |
566 | | | 566 | |
567 | log_debug("client on fd#%d closed", fd); | | 567 | log_debug("client on fd#%d closed", fd); |
568 | | | 568 | |
569 | if (fd == srv->fdmax) { | | 569 | if (fd == srv->fdmax) { |
570 | while (fd > 0 && !srv->fdidx[fd].valid) | | 570 | while (fd > 0 && !srv->fdidx[fd].valid) |
571 | fd--; | | 571 | fd--; |
572 | | | 572 | |
573 | srv->fdmax = fd; | | 573 | srv->fdmax = fd; |
574 | } | | 574 | } |
575 | } | | 575 | } |
576 | | | 576 | |
577 | /* | | 577 | /* |
578 | * check credentials, return true when permitted to modify service records | | 578 | * check credentials, return true when permitted to modify service records |
579 | */ | | 579 | */ |
580 | static bool | | 580 | static bool |
581 | server_auth_check(server_t *srv, void *data) | | 581 | server_auth_check(server_t *srv, void *data) |
582 | { | | 582 | { |
583 | struct sockcred *cred = data; | | 583 | struct sockcred *cred = data; |
584 | struct group *grp; | | 584 | struct group *grp; |
585 | int n; | | 585 | int n; |
586 | | | 586 | |
587 | if (cred == NULL) | | 587 | if (cred == NULL) |
588 | return false; | | 588 | return false; |
589 | | | 589 | |
590 | if (cred->sc_uid == 0 || cred->sc_euid == 0) | | 590 | if (cred->sc_uid == 0 || cred->sc_euid == 0) |
591 | return true; | | 591 | return true; |
592 | | | 592 | |
593 | if (srv->sgroup == NULL) | | 593 | if (srv->sgroup == NULL) |
594 | return false; | | 594 | return false; |
595 | | | 595 | |
596 | grp = getgrnam(srv->sgroup); | | 596 | grp = getgrnam(srv->sgroup); |
597 | if (grp == NULL) { | | 597 | if (grp == NULL) { |
598 | log_err("No gid for group '%s'", srv->sgroup); | | 598 | log_err("No gid for group '%s'", srv->sgroup); |
599 | srv->sgroup = NULL; | | 599 | srv->sgroup = NULL; |
600 | return false; | | 600 | return false; |
601 | } | | 601 | } |
602 | | | 602 | |
603 | if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid) | | 603 | if (cred->sc_gid == grp->gr_gid || cred->sc_egid == grp->gr_gid) |
604 | return true; | | 604 | return true; |
605 | | | 605 | |
606 | if (cred->sc_ngroups > MAX_GROUPS) { | | 606 | if (cred->sc_ngroups > MAX_GROUPS) { |
607 | log_info("Credentials truncated, lost %d groups", | | 607 | log_info("Credentials truncated, lost %d groups", |
608 | MAX_GROUPS - cred->sc_ngroups); | | 608 | MAX_GROUPS - cred->sc_ngroups); |
609 | | | 609 | |
610 | cred->sc_ngroups = MAX_GROUPS; | | 610 | cred->sc_ngroups = MAX_GROUPS; |
611 | } | | 611 | } |
612 | | | 612 | |
613 | for (n = 0 ; n < cred->sc_ngroups ; n++) { | | 613 | for (n = 0 ; n < cred->sc_ngroups ; n++) { |
614 | if (cred->sc_groups[n] == grp->gr_gid) | | 614 | if (cred->sc_groups[n] == grp->gr_gid) |
615 | return true; | | 615 | return true; |
616 | } | | 616 | } |
617 | | | 617 | |
618 | return false; | | 618 | return false; |
619 | } | | 619 | } |