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