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 <arpa/inet.h>
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.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 <net/if.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <time.h>
38 #include <unistd.h>
39 
40 #include "common.h"
41 #include "utils.h"
42 #include "conf.h"
43 #include "dispatcher.h"
44 #include "sys_util.h"
45 
46 extern char tmp[MAXMAXLEN];
47 extern int  remoteOn;
48 
49 
50 /* Have issues with sockets if use execNoFork()
51    If some app started from anyRemote, then it keeps socket open even if anyRemote
52    is killed somehow. Have "ERROR: on binding 98->Address already in use" errors because of
53    socket CLOSE_WAIT state reported by /usr/sbin/lsof -i :<port>
54    !!! Therefore need to use fork !!!
55 
56 int execNoFork(const char *cmd)
57 {
58     DEBUG2("execNoFork >%s<", cmd);
59 
60     //printf("execute >%s< command\n",cmd);
61     #ifdef __cplusplus
62     int rc =
63     #endif
64     system(cmd);
65 
66     //printf("command executed %d\n", rc);
67 
68     //if (WIFSIGNALED(rc) && (WTERMSIG(rc) == SIGINT || WTERMSIG(rc) == SIGQUIT)) {
69     //     	printf("GOR ABORT in system?");
70     //}
71     //if(rc!=-1 && WIFEXITED(rc)) {
72     //	    rc = WEXITSTATUS(rc);
73     //}
74     //printf("exit from child %d\n", rc);
75     return 0;
76 }*/
77 
execInFork(const char * cmd)78 static int execInFork(const char *cmd)
79 {
80     if (cmd == NULL) {
81         logger(L_ERR,"[EX]: Nothing to fork!");
82         return -1;
83     }
84 
85     //DEBUG2("[EX]: execInFork >%s<", cmd);
86     int cpid = fork();
87     if (cpid < 0) {
88         logger(L_ERR,"[EX]: Can not fork!");
89         return -1;
90     }
91 
92     if (cpid) {      // father
93         int rf = 0;
94         waitpid(cpid,&rf,0);
95         if(rf!=-1 && WIFEXITED(rf)) {
96             rf = WEXITSTATUS(rf);
97         }
98         return rf;
99     }
100 
101     // else - child
102 
103     int rc = 0;
104     //logger("INF", "[EX]: Close port in child");
105 
106     closePort(0);
107 
108     rc = system(cmd);
109     if (rc != -1 && WIFEXITED(rc)) {
110         rc = WEXITSTATUS(rc);
111     }
112     exit(rc);
113 }
114 
execCmdNoPipe(int subtype,const char * descr,const char * cmd,cmdParams * params)115 int execCmdNoPipe(int subtype, const char *descr, const char *cmd, cmdParams *params)
116 {
117     //logger(L_INF, "[EX]: Command: Exec");
118 
119     if (cmd == NULL || strlen(cmd) == 0 || remoteOn != 1) {
120         logger(L_DBG, "[EX]: execCmdNoPipe null input or remote if OFF");
121         return EXIT_OK;
122     }
123     DEBUG2("[EX]: execCmdNoPipe >%s<", cmd);
124 
125     char* p = (char*) calloc(strlen(cmd) + 2,1);
126     if (p == NULL) {
127         return EXIT_NOK;
128     }
129     strcpy(p,cmd);
130 
131     // How to handle & inside file names ?
132     //if (!index(p, '&') ) {
133 
134     int idx = strlen(cmd)-1;
135     while (idx > 0 && isspace(cmd[idx])) {
136         idx--;
137     }
138 
139     if (cmd[idx] != '&') {
140         strcat(p, "&");
141     }
142 
143     //int ret = execNoFork(p);
144     int ret = execInFork(p);
145 
146     free(p);
147     return (ret == -1 ? EXIT_NOK : EXIT_OK);
148 }
149 
150 
151 #define RSIZE 512
152 
153 /*
154 #define READ  0
155 #define WRITE 1
156 
157 pid_t popen2(const char *command, int *infp, int *outfp)
158 {
159     int p_stdin[2], p_stdout[2];
160     pid_t pid;
161 
162     if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
163         return -1;
164     }
165 
166     pid = fork();
167 
168     if (pid < 0) {
169 
170         return pid;
171 
172     } else if (pid == 0) { // child
173 
174 	close(p_stdin[WRITE]);
175         dup2(p_stdin[READ], STDIN_FILENO);
176 
177         close(p_stdout[READ]);
178         dup2(p_stdout[WRITE], STDOUT_FILENO);
179 
180 	execl("/bin/sh", "sh", "-c", command, NULL);
181         ERROR2("[EX]: failed in popen2");
182         return -1;
183     }
184 
185     if (infp == NULL) {
186         close(p_stdin[WRITE]);
187     } else {
188         *infp = p_stdin[WRITE];
189     }
190 
191     if (outfp == NULL) {
192         close(p_stdout[READ]);
193     } else {
194         *outfp = p_stdout[READ];
195     }
196     DEBUG2("[EX]: popen2 >%d<", pid);
197     return pid;
198 }
199 
200 this version does not send data until script is killed manually
201 
202 char* executeCommandPipe(const char* exec, size_t* sz)
203 {
204     DEBUG2("[  ]: executeCommandPipe >%s<", exec);
205 
206     int outfp;
207     pid_t pid = popen2(exec, NULL, &outfp);
208 
209     fcntl(outfp, F_SETFL, O_NONBLOCK);
210     FILE* fp = fdopen(outfp,"r");
211     if (fp) {
212         setvbuf(fp, NULL, _IONBF, 0);
213     }
214 
215     char* data = NULL;
216 
217     void*  temp[RSIZE];
218     size_t haveRead = 0;
219 
220     int maxWait = getWaitTime();
221     time_t start = time(NULL);
222     DEBUG2("[  ]: executeCommandPipe WaitTime %d", maxWait);
223 
224     while (1) {
225 
226 	DEBUG2("[  ]: executeCommandPipe -> read");
227 	ssize_t num = read(outfp, temp, RSIZE);
228 	DEBUG2("[  ]: executeCommandPipe <- read %d", num);
229 
230 	if (num == -1 && errno == EAGAIN) {
231 	    DEBUG2("[  ]: executeCommandPipe EAGAIN");
232 	    usleep(100000);
233 	} else if (num > 0) {
234             data = realloc(data, haveRead+num+1);
235             if (!data) {
236                 DEBUG2("[  ]: executeCommandPipe error on realloc %zd", haveRead+num);
237                 return NULL;
238             }
239             memcpy(data+haveRead, temp, num);
240             haveRead += num;
241             *(data + haveRead) = '\0';
242 	} else {
243 	    DEBUG2("[  ]: executeCommandPipe EOF");
244 	    break;
245 	}
246 
247 	if (maxWait > 0) {
248 	    time_t now = time(NULL);
249 	    double elapsed = difftime(now, start);
250 	    if (elapsed > maxWait) {
251 	        WARNING2("[  ]: executeCommandPipe wait time exceeded");
252 		kill(pid, SIGKILL);
253 		break;
254             }
255 	}
256     }
257     close(outfp);
258 
259     DEBUG2("[  ]: executeCommandPipe got %zd bytes", haveRead);
260     (*sz) = haveRead;
261     return data;
262 }*/
263 
264 /*  this version  also gets blocked if command runs forever
265 
266 char* executeCommandPipe(const char* exec, size_t* sz)
267 {
268     DEBUG2("[  ]: executeCommandPipe >%s<", exec);
269 
270     int outfp;
271     pid_t pid = popen2(exec, NULL, &outfp);
272 
273     char* data = NULL;
274 
275     void*  temp[RSIZE];
276     size_t haveRead = 0;
277 
278     while (1) {
279 
280 	DEBUG2("[  ]: executeCommandPipe -> read");
281 	ssize_t num = read(outfp, temp, RSIZE);
282 	DEBUG2("[  ]: executeCommandPipe <- read %d", num);
283 
284         if (num <= 0) {  // EOF or error
285             break;
286 	} else if (num > 0) {
287             data = realloc(data, haveRead+num+1);
288             if (!data) {
289                 DEBUG2("[  ]: executeCommandPipe error on realloc %zd", haveRead+num);
290                 return NULL;
291             }
292             memcpy(data+haveRead, temp, num);
293             haveRead += num;
294             *(data + haveRead) = '\0';
295         }
296 
297         //DEBUG2("[  ]: executeCommandPipe realloc %zd", haveRead);
298 
299         if (num < RSIZE) {
300             break;
301         }
302    }
303     close(outfp);
304 
305     DEBUG2("[  ]: executeCommandPipe got %zd bytes", haveRead);
306     (*sz) = haveRead;
307     return data;
308 }
309 */
310 
311 #define	RDR	0
312 #define	WTR	1
313 
314 static char bin_shell[] = "/bin/sh" ;
315 static char shell[] = "sh";
316 static char shflg[] = "-c";
317 
318 //
319 // function non-reenterable
320 // (forked child will not close fd's opened by other popen_r's
321 //
popen_r(const char * cmd,pid_t * pid)322 static int popen_r(const char* cmd, pid_t* pid)
323 {
324     int     p[2];
325     register int myside, yourside;
326 
327     if (pipe(p) < 0) {
328     	return -1;
329     }
330 
331     myside   = p[RDR];
332     yourside = p[WTR];
333 
334     if( ((*pid) = fork()) == 0) {
335 
336 	// myside and yourside reverse roles in child
337 
338      	(void) close(myside);
339     	(void) close(STDOUT_FILENO);
340     	(void) fcntl(yourside, F_DUPFD, STDOUT_FILENO);
341     	(void) close(yourside);
342     	(void) execl(bin_shell, shell, shflg, cmd, (char *)0);
343     	_exit(1);
344     }
345     if ((*pid) == -1) {
346         return -1;
347     }
348     (void) close(yourside);
349 
350     return myside;
351 }
352 
pclose_r(int fd,pid_t pid)353 static int pclose_r(int fd, pid_t pid)
354 {
355     register int r;
356     int status;
357     void (*hstat)(), (*istat)(), (*qstat)();
358 
359     (void) close(fd);
360     istat = signal(SIGINT,  SIG_IGN);
361     qstat = signal(SIGQUIT, SIG_IGN);
362     hstat = signal(SIGHUP,  SIG_IGN);
363 
364     // while the child is not done and no error has occured wait in the loop
365     while ((r = wait(&status)) != pid && (r != -1 || errno == EINTR)) {
366         usleep(1000);
367     }
368     if (r == -1) {
369         status = -1;
370     }
371 
372     (void) signal(SIGINT,  istat);
373     (void) signal(SIGQUIT, qstat);
374     (void) signal(SIGHUP,  hstat);
375 
376     return status;
377 }
378 
379 // seems this version works
380 
executeCommandPipe(const char * exec,size_t * sz)381 char* executeCommandPipe(const char* exec, size_t* sz)
382 {
383     DEBUG2("[  ]: executeCommandPipe >%s<", exec);
384 
385     pid_t pid;
386     int fd = popen_r(exec, &pid);
387     if (fd < 0) {
388         logger(L_ERR, "[  ]: Error on popen()");
389         return NULL;
390     }
391 
392     fcntl(fd, F_SETFL, O_NONBLOCK);
393 
394     char* data = NULL;
395 
396     void*  temp[RSIZE];
397     size_t haveRead = 0;
398 
399     int maxWait = getWaitTime();
400     time_t start = time(NULL);
401     if (maxWait >= 0) {
402         DEBUG2("[  ]: executeCommandPipe WaitTime %d", maxWait);
403     }
404 
405     while (1) {
406 
407         size_t num = read(fd, temp, RSIZE);
408 
409         if (num == -1 && errno == EAGAIN)  {
410  	        //DEBUG2("[  ]: executeCommandPipe EAGAIN");
411 	        usleep(1000);
412         } else if (num > 0) {
413 
414 	        //DEBUG2("[  ]: executeCommandPipe read %d", num);
415             data = realloc(data, haveRead+num+1);
416             if (!data) {
417                 DEBUG2("[  ]: executeCommandPipe error on realloc %zd", haveRead+num);
418                 return NULL;
419             }
420             memcpy(data+haveRead, temp, num);
421             haveRead += num;
422             *(data + haveRead) = '\0';
423         } else {
424 	        break;
425 	    }
426 
427         //DEBUG2("[  ]: executeCommandPipe realloc %zd", haveRead);
428 
429 	    if (maxWait > 0) {
430 	        time_t now = time(NULL);
431 	        double elapsed = difftime(now, start);
432 	        if (elapsed > maxWait) {
433 	            WARNING2("[  ]: executeCommandPipe wait time exceeded");
434 		        kill(pid, SIGTERM);
435 		        break;
436             }
437 	    }
438     }
439 
440     pclose_r(fd, pid);
441 
442     DEBUG2("[  ]: executeCommandPipe got %zd bytes", haveRead);
443     (*sz) = haveRead;
444 
445     return data;
446 }
447 
448 /* this version is simple, but gets blocked if command runs forever
449 
450 char* executeCommandPipe(const char* exec, size_t* sz)
451 {
452     DEBUG2("[  ]: executeCommandPipe >%s<", exec);
453 
454     FILE *fp = popen(exec, "r");
455     if (fp == NULL) {
456         logger(L_ERR, "[EX]: Error on popen()");
457         return NULL;
458     }
459 
460     char* data = NULL;
461 
462     void*  temp[RSIZE];
463     size_t haveRead = 0;
464 
465     while (1) {
466         size_t num = fread(temp, 1, RSIZE, fp);
467 
468         if (num > 0) {
469             data = realloc(data, haveRead+num+1);
470             if (!data) {
471                 DEBUG2("[  ]: executeCommandPipe error on realloc %zd", haveRead+num);
472                 return NULL;
473             }
474             memcpy(data+haveRead, temp, num);
475             haveRead += num;
476             *(data + haveRead) = '\0';
477         }
478 
479         //DEBUG2("[  ]: executeCommandPipe realloc %zd", haveRead);
480 
481         if (num < RSIZE) {
482             break;
483         }
484     }
485 
486 
487     //int status =
488 
489     pclose(fp);
490 
491     //if (status == -1) {
492     // Error reported by pclose()
493     //...
494     //} else {
495     // Use macros described under wait() to inspect `status' in order
496     //   to determine success/failure of command executed by popen()
497     //...
498     //}
499 
500     DEBUG2("[  ]: executeCommandPipe got %zd bytes", haveRead);
501     (*sz) = haveRead;
502     return data;
503 }*/
504 
505 
peerName(int peer,char * buf,int sz)506 void peerName(int peer, char* buf, int sz)
507 {
508     struct sockaddr_storage addr;
509     socklen_t len = sizeof(addr);
510 
511     if (getpeername(peer, (struct sockaddr*)&addr, &len) == 0) {
512 
513         // deal with both IPv4 and IPv6:
514         if (addr.ss_family == AF_INET) {
515     	    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
516     	    inet_ntop(AF_INET, &s->sin_addr, buf, sz);
517         } else {	    // AF_INET6
518     	    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
519     	    inet_ntop(AF_INET6, &s->sin6_addr, buf, sz);
520         }
521     }
522 }
523 
524 static const char* dirTmp;
525 
filterFiles(const struct dirent * dp)526 static int filterFiles(const struct dirent *dp)
527 {
528     string_t *path = stringNew(dirTmp);
529     stringAppend(path,"/");
530     stringAppend(path,dp->d_name);
531 
532     struct stat buf;
533     int stat = lstat(path->str, &buf);
534     //printf("%d %s %s\n", stat,dp->d_name,strerror(errno));
535     return (stat == 0 && !S_ISDIR(buf.st_mode));
536 }
537 
filterDirs(const struct dirent * dp)538 static int filterDirs(const struct dirent *dp)
539 {
540     string_t *path = stringNew(dirTmp);
541     stringAppend(path,"/");
542     stringAppend(path,dp->d_name);
543 
544     struct stat buf;
545     int stat = lstat(path->str, &buf);
546     //printf("%d %s %s\n", stat,dp->d_name,strerror(errno));
547     return (stat == 0 && S_ISDIR(buf.st_mode));
548 }
549 
550 // mimic "ls -F --quoting-style=shell" to little extent
executeDirListCommand(int type,const char * directory)551 string_t* executeDirListCommand(int type, const char* directory)
552 {
553     DEBUG2("[EX]: executeDirListCommand get listing of %s", directory);
554     struct stat buf;
555     int stat = lstat(directory, &buf);
556 
557     if (stat < 0) {
558         DEBUG2("[EX]: executeDirListCommand can not get %s", directory);
559         return NULL;
560     }
561 
562     if (S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) {
563 
564         string_t *file = stringNew("");
565 
566         if (type == ID_SET_ILIST) {
567             stringAppend(file,"file:");
568         }
569         stringAppend(file,directory);
570 
571         return file;
572 
573     } else if (S_ISDIR(buf.st_mode)) {
574 
575         DEBUG2("[EX]: executeDirListCommand: directory");
576 
577         dirTmp = directory;  // small trick
578 
579         struct dirent **namelist = NULL;
580 
581         string_t *folders = stringNew("");
582 
583         int comma = 0;
584 
585         int n = scandir(directory, &namelist, filterDirs, alphasort);
586         if (n >= 0) {
587 
588 	        int i = 0;
589  	        for( ; i<n; i++) {
590         	    //printf("%s\n", namelist[i]->d_name);
591 
592 		        if (strcmp(namelist[i]->d_name,".") != 0) {
593 		            if (comma == 1) {
594 			            stringAppend(folders,",");
595 		            } else {
596 		                comma = 1;
597 		            }
598 
599  		            if (type == ID_SET_ILIST) {
600 			            stringAppend(folders,"folder:");
601 		            }
602 		            stringAppend(folders,namelist[i]->d_name);
603 		            stringAppend(folders,"/");
604 		        }
605         	    free(namelist[i]);
606             }
607             free(namelist);
608         }
609         //DEBUG2("[EX]: executeDirListCommand: %s", folders->str);
610 
611 	    n = scandir(directory, &namelist, filterFiles, alphasort);
612         if (n >= 0) {
613 
614 	        int i = 0;
615  	        for( ; i<n; i++) {
616         	    //printf("%s\n", namelist[i]->d_name);
617 
618 		        if (strcmp(namelist[i]->d_name,".") != 0) {
619 		            if (comma == 1) {
620 			            stringAppend(folders,",");
621 		            } else {
622 		                comma = 1;
623 		            }
624 
625  		            if (type == ID_SET_ILIST) {
626 			            stringAppend(folders,"file:");
627 		            }
628 		            stringAppend(folders,namelist[i]->d_name);
629 		        }
630                 free(namelist[i]);
631             }
632             free(namelist);
633         }
634         //DEBUG2("[EX]: executeDirListCommand: %s", folders->str);
635 	    return folders;
636 
637 	    /* gets items unsorted
638 	    DIR *dirp = opendir(directory);
639 
640 	    if (dirp) {
641 
642 	        struct dirent *dp;
643 
644                 int fComma = 0;
645                 int dComma = 0;
646 	        string_t *files   = stringNew("");
647 	        string_t *folders = stringNew("");
648 
649 	        string_t *file    = stringNew("");
650 
651 	        while ((dp=readdir(dirp))) {
652 
653 		    if (strcmp(dp->d_name,".") == 0) continue;
654 
655 		    //DEBUG2("[EX]: executeDirListCommand process %s", dp->d_name);
656 
657 		    stringTruncate(file,0);
658 		    stringAppend(file,directory);
659 		    stringAppend(file,"/");
660 		    stringAppend(file,dp->d_name);
661 
662 		    int stat = lstat(file->str, &buf);
663 		    if (stat < 0) continue;
664 
665 		    if (S_ISDIR(buf.st_mode)) {
666 
667  		        if (dComma == 1) {
668 			    stringAppend(folders,",");
669 		        } else {
670 		            dComma = 1;
671 		        }
672 
673  		        if (type == ID_SET_ILIST) {
674 			    stringAppend(folders,"folder:");
675 		        }
676 		        stringAppend(folders,dp->d_name);
677 		        stringAppend(folders,"/");
678 
679 	            } else //if (S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode))
680 		          {
681 
682 		        if (fComma == 1) {
683 			    stringAppend(files,",");
684 		        } else {
685 		            fComma = 1;
686 		        }
687 
688 		        if (type == ID_SET_ILIST) {
689 			    stringAppend(files,"file:");
690 		        }
691 		        stringAppend(files,dp->d_name);
692 
693 		    }
694                 }
695 
696 	        stringFree(file, BOOL_YES);
697                 closedir(dirp);
698 
699 	        if (folders->len > 0) {
700 	            stringAppend(folders,",");
701 	        }
702 	        stringAppend(folders,files->str);  // dirs, then files
703 	        stringFree(files,   BOOL_YES);
704 
705 	        //DEBUG2("[EX]: executeDirListCommand DONE");
706 	        return folders;
707         }*/
708     }
709     return NULL;
710 }
711 
712 //////////////////////////////////////////////////////////////////////////////////
713 //
714 // IP address detection
715 //
716 //////////////////////////////////////////////////////////////////////////////////
717 
get_iface_list(struct ifconf * ifconf)718 static int get_iface_list(struct ifconf *ifconf)
719 {
720    int sock, rval;
721 
722    sock = socket(AF_INET,SOCK_STREAM,0);
723    if(sock < 0)
724    {
725        perror("socket");
726        return (-1);
727    }
728 
729    if((rval = ioctl(sock, SIOCGIFCONF , (char*) ifconf  )) < 0 ) {
730        perror("ioctl(SIOGIFCONF)");
731    }
732 
733    close(sock);
734 
735    return rval;
736 }
737 
getLocalIP()738 string_t* getLocalIP()
739 {
740     struct ifreq ifreqs[20];
741     struct ifconf ifconf;
742 
743     memset(&ifconf,0,sizeof(ifconf));
744     ifconf.ifc_buf = (char*) (ifreqs);
745     ifconf.ifc_len = sizeof(ifreqs);
746 
747     if(get_iface_list(&ifconf) < 0) {
748         return NULL;
749     }
750     int nifaces =  ifconf.ifc_len/sizeof(struct ifreq);
751 
752     DEBUG2("[WS]: getLocalIP found %d interfaces", nifaces);
753 
754     int  i;
755     for(i = 0; i < nifaces; i++) {
756         DEBUG2("[WS]: interface #%d is %s", i, ifreqs[i].ifr_name);
757         static char* lo = "lo";
758         if (strcmp(lo,ifreqs[i].ifr_name) == 0) {
759             continue;  // skip loopback
760         }
761         static char* loopback = "127.0.0.1";
762         if (strcmp(loopback, inet_ntoa(((struct sockaddr_in *)&ifreqs[i].ifr_addr)->sin_addr)) == 0) {
763             continue;  // skip loopback
764         }
765         DEBUG2("[WS]: use local IP %s", inet_ntoa(((struct sockaddr_in *)&ifreqs[i].ifr_addr)->sin_addr));
766         return stringNew(inet_ntoa(((struct sockaddr_in *)&ifreqs[i].ifr_addr)->sin_addr));
767     }
768     return NULL;
769 }
770