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 <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <math.h>
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/un.h>
37 #include <termios.h>
38 #include <unistd.h>
39
40 #include "pr_socket.h"
41 #include "common.h"
42 #include "utils.h"
43 #include "conf.h"
44 #include "lib_wrapper.h"
45 #include "sys_util.h"
46 #include "security.h"
47 #include "dispatcher.h"
48
49 extern char tmp[MAXMAXLEN];
50 extern boolean_t stillRun;
51
52 typedef struct _SocketConnection_ {
53 int fileDescriptor;
54 int serverFileDescriptor;
55 char* uSocket;
56 } _SocketConnection;
57
58 //
59 // Support server mode sockets
60 //
61
socketFD(ConnectInfo * conn)62 int socketFD(ConnectInfo* conn)
63 {
64 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
65 if (!cn) {
66 return -1;
67 }
68 return (conn->state == PEER_WAIT_ACCEPT ||
69 conn->state == PEER_WAIT_LISTEN ? cn->serverFileDescriptor : cn->fileDescriptor);
70 }
71
socketOpenInternal(ConnectInfo * conn)72 static int socketOpenInternal(ConnectInfo* conn)
73 {
74 struct sockaddr_in tcp_addr;
75 struct sockaddr_un un_addr;
76 struct sockaddr* socketaddr = NULL;
77
78 int addFamily = 0;
79 int proto = 0;
80 int sz;
81
82 if (conn->connectionData && ((_SocketConnection*) conn->connectionData)->serverFileDescriptor > 0) {
83 logger(L_ERR, "[DS]: socketOpenInternal: TCP/local socket was already opened");
84 return 1;
85 }
86
87 if (conn->connectionData) {
88 free(((_SocketConnection*) conn->connectionData)->uSocket);
89 free(conn->connectionData);
90 }
91
92 conn->connectionData = (_SocketConnection*) malloc(sizeof(_SocketConnection));
93 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
94
95 cn->serverFileDescriptor = -1;
96 cn->fileDescriptor = -1;
97 cn->uSocket = NULL;
98
99 const char *path = (conn->portStr ? conn->portStr->str : NULL);
100
101 if (conn->mode == SERVER_TCP) {
102 addFamily = AF_INET;
103 proto = IPPROTO_TCP;
104 } else if (conn->mode == SERVER_UX) {
105 addFamily = AF_UNIX;
106 proto = 0;
107 } else {
108 logger(L_ERR, "socketOpenInternal: incorrect input");
109 return -1;
110 }
111
112 if ((cn->serverFileDescriptor = socket(addFamily, SOCK_STREAM|SOCK_CLOEXEC, proto)) < 0) {
113
114 logger(L_ERR, "[DS]: socketOpenInternal: opening TCP socket");
115 errnoDebug("opening TCP socket ",errno); // testing debug
116
117 printf("ERROR: socketOpenInternal: opening TCP socket\n");
118 cn->serverFileDescriptor = -1;
119 return -1;
120 }
121
122 int optval = 1;
123 setsockopt(cn->serverFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
124
125 if (conn->mode == SERVER_TCP) {
126
127 memset((void *) &tcp_addr, 0, sizeof(tcp_addr));
128 tcp_addr.sin_family = AF_INET;
129 tcp_addr.sin_addr.s_addr = INADDR_ANY;
130 tcp_addr.sin_port = htons(conn->port);
131
132 socketaddr=(struct sockaddr *)&tcp_addr;
133 sz = sizeof(tcp_addr);
134
135 } else if (conn->mode == SERVER_UX && path != NULL) {
136
137 memset(&un_addr, 0, sizeof(un_addr));
138 un_addr.sun_family = AF_UNIX;
139 strncpy(un_addr.sun_path, path, sizeof un_addr.sun_path - 1);
140 printf("ERROR: SOCKET %s\n", path);
141 socketaddr=(struct sockaddr *)&un_addr;
142 sz = sizeof(un_addr);
143
144 } else {
145 logger(L_ERR, "socketOpenInternal: incorrect input 2");
146 return -1;
147 }
148
149 if (bind(cn->serverFileDescriptor, (struct sockaddr *) socketaddr, sz) < 0) {
150 logger(L_ERR, "[DS]: socketOpenInternal: on bind()");
151 printf("ERROR: on bind socket to the address %s (%d)\n", strerror(errno), errno);
152 return -1;
153 }
154
155 if (conn->mode == SERVER_UX) {
156 cn->uSocket = strdup(path);
157 }
158 return 1;
159 }
160
socketOpen(ConnectInfo * conn)161 int socketOpen(ConnectInfo* conn)
162 {
163 if (conn->mode == SERVER_TCP) {
164 DEBUG2("[DS]: socketOpen: TCP mode. Use port %d", conn->port);
165 } else if (conn->mode == SERVER_UX) {
166 DEBUG2("[DS]: socketOpen: Local socket mode. Use file %s", conn->portStr->str);
167 } else {
168 DEBUG2("[DS]: socketOpen: improper mode. %d", conn->mode);
169 return EXIT_NOK;
170 }
171
172 if (socketOpenInternal(conn) < 0) {
173 return EXIT_NOK;
174 }
175
176 conn->state = PEER_WAIT_LISTEN;
177 return EXIT_OK;
178 }
179
socketClose(ConnectInfo * conn,int final)180 void socketClose(ConnectInfo* conn, int final)
181 {
182 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
183 if (!cn) return;
184
185 if (final) {
186 logger(L_INF, "[DS]: closeSocket");
187 }
188
189 if (cn->fileDescriptor >= 0) {
190 if (final) {
191 logger(L_INF, "[DS]: closeSocket close socket");
192 }
193 close(cn->fileDescriptor);
194 cn->fileDescriptor = -1;
195 }
196 if (cn->serverFileDescriptor >= 0) {
197 if (final) {
198 logger(L_INF, "[DS]: closeSocket close server socket");
199 }
200 close(cn->serverFileDescriptor);
201 cn->serverFileDescriptor = -1;
202 }
203
204 if (final) {
205 if (conn->mode == SERVER_UX) {
206 unlink(cn->uSocket);
207 free(cn->uSocket);
208 }
209 }
210 free(cn);
211 conn->connectionData = NULL;
212 conn->state = PEER_DISCONNECTED;
213 }
214
socketReset(ConnectInfo * conn)215 void socketReset(ConnectInfo* conn)
216 {
217 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
218 if (cn) {
219 if (cn->fileDescriptor >= 0) {
220 close(cn->fileDescriptor);
221 cn->fileDescriptor = -1;
222 }
223 conn->state = PEER_WAIT_ACCEPT;
224 } else {
225 conn->state = PEER_DISCONNECTED; // should not happens
226 }
227 }
228
229 //
230 // Setup listen
231 //
socketListen(ConnectInfo * conn)232 int socketListen(ConnectInfo* conn)
233 {
234 logger(L_INF, "[DS]: socketListen");
235
236 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
237 if (!cn) {
238 return -1;
239 }
240 int ret = listen(cn->serverFileDescriptor,0);
241 if (ret >= 0) {
242 conn->state = PEER_WAIT_ACCEPT;
243 }
244 return (ret < 0 ? -1 : 1);
245 }
246
247 //
248 // Wait for incoming connection
249 //
socketAccept(ConnectInfo * conn)250 int socketAccept(ConnectInfo* conn)
251 {
252 struct sockaddr* socketaddr = NULL;
253 struct sockaddr_in ip_addr;
254 struct sockaddr_un un_addr;
255
256 int cnt, sz;
257 int type = conn->mode;
258
259 INFO2("[DS]: socketAccept %d", conn->id);
260 cnt = 0;
261
262 if (type == SERVER_TCP) {
263 socketaddr=(struct sockaddr *)&ip_addr;
264 sz = sizeof(ip_addr);
265 } else if (type == SERVER_UX) {
266 socketaddr=(struct sockaddr *)&un_addr;
267 sz = sizeof(un_addr);
268 }
269
270 if (!socketaddr) {
271 return -1;
272 }
273
274 _SocketConnection* cn = (_SocketConnection*) conn->connectionData;
275 if (!cn) return -1;
276
277 while (stillRun) {
278
279 INFO2("[DS]: socketAccept: accept on %d", conn->id);
280
281 cn->fileDescriptor = accept(cn->serverFileDescriptor, (struct sockaddr *) socketaddr, (socklen_t *)&sz);
282
283 if (cn->fileDescriptor < 0 && errno == EAGAIN) {
284
285 if (cnt >= 60) { // Print to log every minute
286 logger(L_INF, "socketAccept: waiting for connection");
287 //printf(".");
288 cnt = 0;
289 }
290 fflush(stdout);
291
292 sleep(1);
293 cnt++;
294
295 continue;
296 }
297
298 if (cn->fileDescriptor < 0) {
299 logger(L_ERR, "[DS]: on accept");
300 printf("ERROR: on accept %d\n", errno);
301 return -1;
302 /*} else {
303 // Set non-blocking mode
304 if (-1 == (flags = fcntl(portfd, F_GETFL, 0))) {
305 flags = 0;
306 }
307 fcntl(portfd, F_SETFL, flags | O_NONBLOCK);
308 */
309 }
310
311 char buf[INET6_ADDRSTRLEN];
312 buf[0] = '\0';
313
314 if (type == SERVER_TCP) {
315
316 peerName(cn->fileDescriptor,buf,INET6_ADDRSTRLEN);
317
318 if (!isAllowed(buf)) {
319 INFO2("[DS]: socketAccept: host %s is not in the list of accepted host, close connection", buf);
320 write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
321
322 close(cn->fileDescriptor);
323 cn->fileDescriptor = -1;
324 conn->state = PEER_DISCONNECTED;
325
326 return -1;
327 }
328 }
329
330 if (getUsePassword() && !getIViewer()) {
331 logger(L_DBG,"[DS]: socketAccept: Do password verification");
332
333 int ret = EXIT_OK;
334
335 int i = 0;
336 for ( ; i<3; i++) {
337
338 ret = verifyPassword(cn->fileDescriptor);
339
340 if (ret == EXIT_OK) { // got it
341 break;
342 }
343 }
344
345 if (ret != EXIT_OK) {
346
347 if (ret == EXIT_NOK) { // if it is EXIT_STOP connection is already lost
348 write(cn->fileDescriptor,CMD_STR_DISCONNECT,strlen(CMD_STR_DISCONNECT));
349 }
350
351 close(cn->fileDescriptor);
352 cn->fileDescriptor = -1;
353 conn->state = PEER_DISCONNECTED;
354
355 return -1;
356 }
357
358 logger(L_DBG,"[DS]: socketAccept: Password verification OK");
359 }
360
361 INFO2("[DS]: socketAccept: accepted from %s", buf);
362 conn->state = PEER_CONNECTED;
363
364 // force to detect H/W and cover size. need to do that before (Connect) or syncPeer() handling
365 getClientSize(conn->id, cn->fileDescriptor);
366
367 break;
368 }
369
370 logger(L_INF, "[DS]: socketAccept exit");
371 return 1;
372 }
373
socketWrite(ConnectInfo * connInfo,const dMessage * msg)374 int socketWrite(ConnectInfo* connInfo, const dMessage* msg)
375 {
376 logger(L_DBG, "[DS]: socketWrite");
377 if (!msg) {
378 return EXIT_OK;
379 }
380 const char* command = msg->value;
381 int count = msg->size;
382
383 if (!command || count <= 0) {
384 return EXIT_OK;
385 }
386
387 if (strcmp("End();",command) == 0) { // used only for WEB/CMXML
388 return EXIT_OK;
389 }
390
391 _SocketConnection* cn = (_SocketConnection*) connInfo->connectionData;
392 if (!cn) {
393 return EXIT_NOK;
394 }
395
396 // send command
397 if (cn->fileDescriptor >= 0) {
398
399 if (msg->type == DM_SET) {
400 if (isDataOld(connInfo, msg->subtype, command, count)) {
401 INFO2("[DS]: Skip to send the same data to TCP peer");
402 return EXIT_OK;
403 }
404 }
405
406 memset(tmp, 0, MAXMAXLEN);
407 strcat(tmp, "[DS]: socketWrite ");
408
409 int logSz = (count > 256 ? 255 : count);
410
411 // it is possible to get binary data here
412 memcpy(tmp, command, logSz); // Do not dump long commands
413 tmp[logSz] = '\0';
414 logger(L_DBG, tmp);
415
416 sprintf(tmp, "[DS]: socketWrite %d bytes", count);
417 logger(L_INF, tmp);
418
419 int n = write(cn->fileDescriptor,command,count);
420 if (n < 0) {
421 logger(L_ERR, "[DS]: error writing to socket");
422 return EXIT_NOK;
423 }
424 return EXIT_OK;
425 } else {
426 logger(L_ERR, "[DS]: error writing to socket: already closed");
427 }
428 return EXIT_NOK;
429
430 }
431