1 //
2 // anyRemote
3 // a wi-fi or bluetooth remote for your PC.
4 //
5 // Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 //
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <errno.h>
26 
27 
28 #ifdef USE_L2CAP
29 
30 #ifdef USE_BLUEZ
31 #include <bluetooth/bluetooth.h>
32 #include <bluetooth/l2cap.h>
33 #include <bluetooth/sdp.h>
34 #include <bluetooth/sdp_lib.h>
35 #endif
36 
37 #ifdef USE_BT_FBSD
38 #include <bluetooth.h>
39 #include <sdp.h>
40 #include <err.h>
41 #endif
42 
43 #include "common.h"
44 #include "utils.h"
45 #include "peer.h"
46 
47 extern char tmp[MAXMAXLEN];
48 extern boolean_t stillRun;
49 
50 typedef struct _L2CapConnection_ {
51     int           fileDescriptor;
52     int           serverFileDescriptor;
53     #ifdef USE_BLUEZ
54     sdp_session_t *session;
55     sdp_record_t  *record;
56     #endif
57     #ifdef USE_BT_FBSD
58     void      *session = NULL;
59     uint32_t      record;
60     #endif
61 } _L2CapConnection;
62 
63 //
64 // Support SDP
65 //
66 
67 #ifdef USE_BLUEZ
68 
sdpRegisterL2cap(ConnectInfo * connInfo)69 void sdpRegisterL2cap(ConnectInfo* connInfo)
70 {
71     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
72     if (!cn) return;
73 
74     uint8_t svc_uuid_int[]   = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd };
75     const char *service_name = "anyRemote/l2cap";
76     const char *svc_dsc      = "Bluetooth remote control";
77     const char *service_prov = "anyRemote";
78     uint8_t l2cap_port       = connInfo->port;
79 
80     uuid_t root_uuid, l2cap_uuid, svc_uuid, svc_class_uuid;
81     sdp_list_t *l2cap_list = 0,
82                 *root_list = 0,
83                  *proto_list = 0,
84                   *access_proto_list = 0,
85                    *svc_class_list = 0,
86                     *profile_list = 0;
87     sdp_data_t *channel = 0;
88     sdp_profile_desc_t profile;
89     cn->record = sdp_record_alloc();
90 
91     // set the general service ID
92     sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
93     sdp_set_service_id( cn->record, svc_uuid );
94 
95     // set the service class
96     sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
97     svc_class_list = sdp_list_append(0, &svc_class_uuid);
98     sdp_set_service_classes(cn->record, svc_class_list);
99 
100     // set the Bluetooth profile information
101     sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
102     profile.version = 0x0100;
103     profile_list = sdp_list_append(0, &profile);
104     sdp_set_profile_descs(cn->record, profile_list);
105 
106     // make the service record publicly browsable
107     sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
108     root_list = sdp_list_append(0, &root_uuid);
109     sdp_set_browse_groups(cn->record, root_list );
110 
111     // set l2cap information
112     sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
113     l2cap_list = sdp_list_append( 0, &l2cap_uuid );
114     channel = sdp_data_alloc(SDP_UINT8, &l2cap_port);
115     sdp_list_append(l2cap_list, channel );
116     proto_list = sdp_list_append( 0, l2cap_list );
117 
118     access_proto_list = sdp_list_append( 0, proto_list );
119     sdp_set_access_protos(cn->record, access_proto_list );
120 
121     // set the name, provider, and description
122     sdp_set_info_attr(cn->record, service_name, service_prov, svc_dsc);
123 
124     // connect to the local SDP server, register the service record,
125     // and disconnect
126     cn->session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
127     if ( (!(cn->session && cn->record)) || sdp_record_register(cn->session, cn->record, 0) == -1) {
128         logger(L_ERR, "can not register SDP service");
129     }
130 
131     // cleanup
132     sdp_data_free( channel );
133     sdp_list_free( l2cap_list, 0 );
134     sdp_list_free( proto_list, 0 );
135     sdp_list_free( root_list, 0 );
136     sdp_list_free( access_proto_list, 0 );
137     sdp_list_free( svc_class_list, 0 );
138     sdp_list_free( profile_list, 0 );
139 }
140 #endif
141 
142 #ifdef USE_BT_FBSD
143 
sdpRegisterL2cap(ConnectInfo * connInfo)144 void sdpRegisterL2cap(ConnectInfo* connInfo)
145 {
146     errx(1, "Not yet supported");
147 }
148 #endif
149 
sdpDeregisterL2cap(_L2CapConnection * cn)150 void sdpDeregisterL2cap(_L2CapConnection* cn)
151 {
152     #ifdef USE_BLUEZ
153     if (cn->session != NULL) {
154         sdp_record_unregister(cn->session, cn->record);
155         cn->session = NULL;
156     }
157     #endif
158     #ifdef USE_BT_FBSD
159     if (cn->session != NULL) {
160         sdp_unregister_service(cn->session, cn->record);
161         sdp_close(cn->session);
162         cn->session = NULL;
163     }
164     #endif
165 }
166 
167 //
168 // Support L2CAP sockets
169 //
170 
openL2capPort(ConnectInfo * connInfo)171 int openL2capPort(ConnectInfo* connInfo)
172 {
173     #ifdef USE_BLUEZ
174     struct sockaddr_l2 l2_addr;
175     #endif
176     #ifdef USE_BT_FBSD
177 
178     #endif
179 
180     struct sockaddr*   socketaddr = NULL;
181 
182     int sz;
183 
184     if (connInfo->connectionData && ((_L2CapConnection*) connInfo->connectionData)->serverFileDescriptor > 0) {
185         logger(L_ERR, "L2CAP socket was already opened");
186         return 1;
187     }
188 
189     if (connInfo->connectionData) {
190         free(connInfo->connectionData);
191     }
192 
193     connInfo->connectionData = (_L2CapConnection*) malloc(sizeof(_L2CapConnection));
194     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
195 
196     cn->serverFileDescriptor = -1;
197     cn->fileDescriptor       = -1;
198     cn->session              = NULL;
199     cn->record               = NULL;
200 
201     if ((cn->serverFileDescriptor = socket(PF_BLUETOOTH, SOCK_SEQPACKET|SOCK_CLOEXEC, BTPROTO_L2CAP)) < 0) {
202         logger(L_ERR, "opening BT/L2CAP socket");
203         printf("ERROR: opening BT/L2CAP socket\n");
204         return -1;
205     }
206 
207     #ifdef USE_BLUEZ
208     memset((void *) &l2_addr, 0, sizeof(l2_addr));
209     sz = sizeof(l2_addr);
210 
211     // bind socket to the specified port of the first available local bluetooth adapter
212     l2_addr.l2_family = AF_BLUETOOTH;
213     l2_addr.l2_bdaddr = *BDADDR_ANY;
214     l2_addr.l2_psm = htobs(0x1001); //port);
215 
216     sdpRegisterL2cap(connInfo);
217     sprintf(tmp, "registered L2CAP on port %i", connInfo->port);
218     logger(L_INF, tmp);
219     socketaddr=(struct sockaddr *)&l2_addr;
220     #endif
221 
222     #ifdef USE_BT_FBSD
223 
224     #endif
225 
226     if (bind(cn->serverFileDescriptor, (struct sockaddr *) socketaddr, sz) < 0) {
227         logger(L_ERR, "on binding");
228         printf("ERROR: on binding %d->%s\n", errno, strerror(errno));
229         return -1;
230     }
231 
232     return 1;
233 }
234 
l2capOpen(ConnectInfo * connInfo)235 int l2capOpen(ConnectInfo* connInfo)
236 {
237     DEBUG2("[DS]: L2CAP Server mode. Use port %d", connInfo->port);
238     if (openL2capPort(connInfo) < 0) {
239         return EXIT_NOK;
240     }
241     return EXIT_OK;
242 }
243 
l2capFD(ConnectInfo * connInfo)244 int l2capFD(ConnectInfo* connInfo)
245 {
246     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
247     return (cn ? cn->fileDescriptor : -1);
248 }
249 
l2capClose(ConnectInfo * connInfo,int final)250 void l2capClose(ConnectInfo* connInfo, int final)
251 {
252     logger(L_INF, "l2capClose");
253 
254     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
255     if (!cn) return;
256 
257     if (cn->fileDescriptor >= 0) {
258         close(cn->fileDescriptor);
259         cn->fileDescriptor = -1;
260     }
261     if (cn->serverFileDescriptor > 0) {
262         close(cn->serverFileDescriptor);
263         cn->serverFileDescriptor = -1;
264     }
265 
266     if (final) {
267         sdpDeregisterL2cap(cn);
268     }
269 
270     free(cn);
271     connInfo->connectionData = NULL;
272     connInfo->state = PEER_DISCONNECTED;
273 }
274 
l2capReset(ConnectInfo * conn)275 void l2capReset(ConnectInfo* conn)
276 {
277     logger(L_INF, "l2capReset");
278 
279     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
280     if (cn) {
281         if (cn->fileDescriptor >= 0) {
282             close(cn->fileDescriptor);
283             cn->fileDescriptor = -1;
284         }
285         connInfo->state = PEER_WAIT_ACCEPT;
286     } else {
287         conn->state = PEER_DISCONNECTED;  // should not happens
288     }
289 }
290 
l2capSetup(ConnectInfo * connInfo)291 int l2capSetup(ConnectInfo* connInfo)
292 {
293     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
294     if (!cn) {
295         return -1;
296     }
297     int ret = listen(cn->serverFileDescriptor,0);
298     if (ret >= 0) {
299         conn->state = PEER_WAIT_ACCEPT;
300     }
301     return (ret < 0 ? -1 : 1);
302 }
303 
l2capAccept(ConnectInfo * connInfo)304 int l2capAccept(ConnectInfo* connInfo)
305 {
306     logger(L_INF, "[DS]: Server mode/L2CAP: Waiting connection");
307     int cnt;
308     char buf[1024] = { 0 };
309 
310     #ifdef USE_BLUEZ
311     struct sockaddr_l2 l2rem_addr;
312     socklen_t opt = sizeof(l2rem_addr);
313     #endif
314 
315     #ifdef USE_BT_FBSD
316 
317     #endif
318     cnt = 0;
319 
320     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
321     if (!cn) return -1;
322 
323     while (stillRun) {
324 
325         cn->fileDescriptor = accept(cn->serverFileDescriptor, (struct sockaddr *)&l2rem_addr, &opt);
326 
327         if (cn->fileDescriptor == -1 && errno == EAGAIN) {
328 
329             if (cnt >= 60) {    // Print to log every minute
330                 logger(L_INF, "l2capAccept: waiting for connection");
331                 cnt = 0;
332             }
333             fflush(stdout);
334 
335             sleep(1);
336             cnt++;
337 
338             continue;
339         }
340 
341         if (cn->fileDescriptor < 0) {
342             logger(L_ERR, "on accept");
343             printf("ERROR: on accept %d\n", errno);
344             return -1;
345         }
346 
347         ba2str(&l2rem_addr.l2_bdaddr, buf);
348 
349         if (!isAllowed(buf)) {
350             INFO2("l2capAccept: host %s is not in the list of accepted host, close connection", buf);
351             write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
352 
353             close(cn->fileDescriptor);
354             cn->fileDescriptor = -1;
355             connInfo->state = PEER_DISCONNECTED;
356 
357             return -1;
358         }
359 
360         if (getUsePassword()) {
361             logger(L_DBG,"[DS]: l2capAccept: Do password verification");
362 
363             int ret = EXIT_OK;
364 
365             int i=0;
366             for ( ; i<3; i++) {
367                 ret = verifyPassword(cn->fileDescriptor);
368 
369                 if (ret == EXIT_OK) {    // got it
370                    break;
371                 }
372             }
373 
374             if (ret != EXIT_OK) {
375 
376                 if (ret == EXIT_NOK) {
377                     write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
378                 }
379 
380                 close(cn->fileDescriptor);
381                 cn->fileDescriptor = -1;
382                 connInfo->state = PEER_DISCONNECTED;
383 
384                 return -1;
385             }
386             logger(L_DBG,"[DS]: l2capAccept: Password verification OK");
387         }
388 
389         sprintf(tmp, "l2capAccept: accepted from %s", buf);
390         logger(L_INF, tmp);
391 
392         connInfo->state = PEER_CONNECTED;
393 
394         // force to detect cover size. need to do that before (Connect) or syncPeer() handling
395         getCoverSize(connInfo->id, cn->fileDescriptor);
396 
397         break;
398     }
399     return 1;
400 }
401 
l2capWrite(ConnectInfo * connInfo,dMessage * msg)402 int l2capWrite(ConnectInfo* connInfo, dMessage* msg)
403 {
404     _L2CapConnection* cn = (_L2CapConnection*) connInfo->connectionData;
405     if (!cn) {
406         logger(L_DBG,"[DS]: l2capWrite() no connection data");
407         return EXIT_NOK;
408     }
409     const char* command = msg->value;
410     int count = msg->size;
411 
412     logger(L_DBG, "l2capWrite");
413 
414     if (!command || count <= 0) {
415         return EXIT_OK;
416     }
417 
418     if (strcmp("End();",command) == 0) {  // used only for WEB/CMXML
419         return EXIT_OK;
420     }
421 
422     // send command
423     memset(tmp, 0, MAXMAXLEN);
424     strcat(tmp, "l2capWrite ");
425 
426     int logSz = (count > 256 ? 255 : count);
427 
428     // it is possible to get binary data here
429     memcpy(tmp, command, logSz); // Do not dump long commands
430     tmp[logSz] = '\0';
431     logger(L_DBG, tmp);
432 
433     sprintf(tmp, "l2capWrite %d bytes", count);
434     logger(L_INF, tmp);
435 
436     int n = write(cn->fileDescriptor,command,count);
437     if (n < 0) {
438         logger(L_ERR, "error writing to L2CAP socket");
439         return EXIT_NOK;
440     }
441 
442     return EXIT_OK;
443 }
444 
445 #endif
446