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 <errno.h>
23 #include <pwd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 
29 #include "common.h"
30 #include "lib_wrapper.h"
31 #include "utils.h"
32 #include "conf.h"
33 #include "mode.h"
34 #include "var.h"
35 #include "alarm.h"
36 #include "queue.h"
37 #include "mutex.h"
38 #include "timer.h"
39 
40 extern char         tmp[MAXMAXLEN];
41 extern CONF         conf;
42 
43 // Some globals
44 
45 char logfile [MAXLEN];
46 
47 // used by Flush() command to temporary store old configuration
48 static mode       *flushModes   = NULL;
49 static SingleList *flushAlarms  = NULL;
50 static HashTable  *flushTimers  = NULL;
51 
52 #ifdef USE_ICONV
53 
54 #include <iconv.h>
55 
56 iconv_t convertorTo   = (iconv_t) -1;
57 iconv_t convertorFrom = (iconv_t) -1;
58 
59 #endif
60 
61 //////////////////////////////////////////////////////////////////////////////////
62 //
63 // Functions related to logging
64 //
65 //////////////////////////////////////////////////////////////////////////////////
66 
initFile(char * what,const char * name)67 static void initFile(char* what, const char* name)
68 {
69     // store data in first arg
70 
71     int useuser = 0;
72 
73     char *prefix = dupVarValue("TmpDir");
74     char *h = getenv("HOME");
75 
76     if (prefix) {
77         strcat(what, prefix);
78         if (h) {
79             if (strncmp(prefix, h, strlen(h)) != 0) {
80                 useuser = 1;
81             }
82         } else {
83             useuser = 1;
84         }
85     } else {
86         if (h) {
87             strcat(what, h);
88             strcat(what, "/.anyRemote");
89         } else {			// could it ever happen ?
90             strcat(what, "/tmp");
91             useuser = 1;
92         }
93     }
94     strcat(what, name);
95 
96     if (useuser == 1) {
97         char *u = getenv("USER");
98         if (prefix && u) {
99             strcat(what, ".");
100             strcat(what, u);
101         }
102     }
103 
104     free(prefix);
105     return;
106 }
107 
initLog()108 void initLog()
109 {
110     if (getLog()) {
111 
112         initFile(logfile, LOGFILE);
113 
114         printf("INFO: log file is %s\n",logfile);
115 
116         // Just  truncate file
117         FILE *fplog = fopen(logfile, "w");
118         if (fplog) {
119             fclose(fplog);
120         }
121         if(getuid()==0 && conf.uid) { // do not open file as superuser
122             #ifdef __cplusplus
123 	        int dummy =
124 	        #endif
125 	        chown(logfile,conf.uid,conf.gid);
126         }
127 
128         mutexNew(M_LOG);
129 
130 	    printTime();
131         sprintf(tmp, "anyRemote v%s", PACKAGE_VERSION);
132 	    logger(L_CFG, tmp);
133     }
134 }
135 
releaseLog()136 void releaseLog()
137 {
138     mutexRemove(M_LOG);
139 }
140 
logger2(const char * head,const char * str)141 static void logger2(const char *head, const char *str)
142 {
143     //printf("logger ENTER\n");fflush(stdout);
144     FILE *fplog;
145     time_t logtime;
146 
147     //struct timeval  tv;
148     //struct timezone tz;
149 
150     if (!getLog() ||
151         logfile[0] == '\0' ||
152         (head && strcmp(head, "DBG") == 0 && getDebug() == 0)) {
153         return;
154     }
155 
156     mutexLock(M_LOG);
157 
158     fplog = fopen(logfile, "a");
159     if (fplog!=NULL) {
160         if (head && strcmp(head, "CFG") != 0) {
161 
162 	        time(&logtime);
163             struct tm* timeinfo = localtime (&logtime );
164 
165 	        //gettimeofday(&tv, &tz);
166 
167             char stime[32];
168             stime[8] = '\0';
169 
170             sprintf(stime, "%2d:%2d:%2d", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
171             //sprintf(stime, "%2d:%2d", tv.tv_sec, tv.tv_usec/1000);
172 
173             fprintf(fplog, "[%s] - ",stime);
174         }
175         if(head != NULL && strcmp(head, "CFG") != 0) {
176             fprintf(fplog, "%s - ",head);
177         }
178         fprintf(fplog, "%s\n",str);
179 
180         fclose(fplog);
181     } else {
182         printf("Can not open log file >%s<\n", logfile);
183 	    logfile[0] = '\0';  // print this error only once
184     }
185 
186     mutexUnlock(M_LOG);
187 
188     //printf("logger EXIT\n");fflush(stdout);
189 }
190 
logger(int head,const char * str)191 void logger(int head, const char *str)
192 {
193     switch (head) {
194         case L_CFG:
195 	    logger2("CFG", str);
196 	    break;
197 	case L_INF:
198 	    logger2("INF", str);
199 	    break;
200 	case L_WARN:
201 	    logger2("WARNING", str);
202 	    break;
203         case L_ERR:
204 	    logger2("ERR", str);
205 	    break;
206 	//case L_DBG:
207 	default:
208 	    logger2("DBG", str);
209 	    break;
210     }
211 }
212 
printTime()213 void printTime()
214 {
215     time_t logtime;
216     time(&logtime);
217 
218     char *timestr = (char *) ctime(&logtime);
219     timestr[strlen(timestr)-1]=0;
220     logger(L_CFG, timestr);
221 }
222 
223 //////////////////////////////////////////////////////////////////////////////////
224 //
225 // Functions related to encoding conversion
226 //
227 //////////////////////////////////////////////////////////////////////////////////
needConvert()228 int needConvert()
229 {
230     int ret = 0;
231     #ifdef USE_ICONV
232     if (convertorTo != (iconv_t) -1) {
233          ret = 1;
234     }
235     #endif
236     return ret;
237 }
238 
239 #ifdef USE_ICONV
closeConvertor(void)240 void closeConvertor(void)
241 {
242     if (convertorTo != (iconv_t) -1) {
243         iconv_close(convertorTo);
244 	    convertorTo = (iconv_t) -1;
245     }
246     if (convertorFrom != (iconv_t) -1) {
247         iconv_close(convertorFrom);
248 	    convertorFrom = (iconv_t) -1;
249     }
250 }
251 
encodingHook()252 void encodingHook()
253 {
254     closeConvertor();
255 
256     char* to = dupVarValue("ToEncoding");
257     if (!to) return;
258 
259     char* from = dupVarValue("FromEncoding");
260     if (!from) {
261         free(to);
262         return;
263     }
264 
265     DEBUG2("encodingHook() start conversion from >%s< to >%s<", from, to);
266 
267     convertorTo = iconv_open(to, from);
268     if (convertorTo == (iconv_t) - 1) {
269         ERROR2("Can start conversion %s -> %s, not supported by iconv()", from, to);
270     }
271 
272     convertorFrom = iconv_open(from, to);
273     if (convertorFrom == (iconv_t) - 1) {
274         ERROR2("Can start conversion %s -> %s, not supported by iconv()", to, from);
275     }
276 
277     free(to);
278     free(from);
279 }
280 #endif
281 
282 
283 //////////////////////////////////////////////////////////////////////////////////
284 //
285 // Functions related to Flush() command
286 //
287 //////////////////////////////////////////////////////////////////////////////////
288 
289 extern int  flushConf;
290 
flushData()291 int flushData()
292 {
293     //logger(L_DBG,"flushData");
294 
295     flushConf = 1;
296 
297     flushModes = getModes();
298     forgetModes();
299 
300     flushAlarms = getAlarms();
301     forgetAlarms();
302 
303     flushTimers = getTimers();
304     forgetTimers();
305 
306     // Now we ready to load new cfg.
307     return EXIT_OK;
308 }
309 
flushOldConf()310 void flushOldConf()
311 {
312 
313     freeTimers(flushTimers);
314     flushTimers = NULL;
315 
316     freeModes(flushModes);
317     flushModes = NULL;
318 
319     freeAlarms(flushAlarms);
320     flushAlarms = NULL;
321 }
322 
printHelp()323 void printHelp()
324 {
325     printf("Usage: anyremote [-f conf.file] [-s peer[,peer ...]] [-log] [-a] \n");
326     printf("                 [-cfgdir directory] [-tmpdir directory]\n");
327     printf("                 [-fe port] [-u username] [-name SDP service name] [-password]\n");
328     printf("   or: anyremote -h|-v\n\n");
329     printf(" -h|--help  print this help\n");
330     printf(" -v|--version  print version of anyRemote\n");
331     printf(" -f /path/to/file  specify configuration file\n");
332     printf(" -s peer[,peer ...], where peer possible values are\n");
333     printf("    tcp:<port>          (Server mode - TCP/IP connection)\n");
334     printf("    bluetooth:<channel 1-32> (Server mode - bluetooth connection)\n");
335     printf("    web:<port>          (Server mode - Web interface)\n");
336     printf("    cmxml:<port>        (Server mode - XML interface for Cisco IP phones)\n");
337     printf("    local:/dev/ircommX  (Server mode - IR connection)\n");
338     printf("    rfcomm:XX:XX:XX:XX:XX:XX:CC (AT mode - bluetooth connection,\n");
339     printf("        where XX:XX:XX:XX:XX:XX is bluetooth device address,\n");
340     printf("        and CC is channel number - integer from 1 to 32)\n");
341     printf("    /dev/ttyACM#        (AT mode - cable connection)\n");
342     printf("    /dev/ircomm#        (AT mode - IR connection)\n");
343     printf("    ilirc:<AF_LOCAL socket file> (use with inputlircd)\n");
344     printf("    stdin\n");
345     printf("    avahi - register SDP service using Avahi\n");
346     printf("  Default peer value is bluetooth,tcp:5197,web:5080,avahi\n");
347     printf("  It is possible to specify several peers for Server mode configuration files only\n");
348     printf("  It is possible to specify only single peer of web: or cmxml: type\n");
349     printf(" -log print verbose logging information to $HOME/.anyRemote/anyremote.log\n");
350     printf(" -cfgdir override default location of directory with configuration files\n");
351     printf(" -tmpdir override default location of directory to store temporary files\n");
352     printf(" -a	reconnect automatically in case of connection failure, used only in AT-mode\n");
353     printf(" -fe <port> work as backend for GUI frontend. Use specified port to connect to frontend.\n");
354     printf(" -name <SDP service name> if bluetooth or TCP/IP connection is used, allows one to specify SDP service name\n");
355     printf(" -password ask password on connect\n");
356     printf("           password should be stored in $HOME/.anyRemote/password file in a plain text\n");
357     printf(" -u|--user <username> if started from root, allows one to set effective user ID to specified user\n\n");
358 
359 }
360 
getUidGid(char * username,uid_t * uid,gid_t * gid)361 int getUidGid(char *username, uid_t *uid, gid_t *gid)
362 {
363     /* Set uid and gid to the preferred user (found in setuid.h). Can either be
364     * numeric or a string, found in /etc/passwd.	*/
365     struct passwd *pw;
366 
367     if ((pw = getpwnam(username))) {
368         // Name exists
369         *uid = pw->pw_uid;
370         *gid = pw->pw_gid;
371         return EXIT_OK;
372     }
373     /* something Bad happened, so send back an error */
374     return EXIT_NOK;
375 }
376 
freeMMessage(void * ptr)377 void freeMMessage(void* ptr)
378 {
379     int *mm = (int*) ptr;
380     free(mm);
381 }
382 
sendToMainThread(int * m)383 static void sendToMainThread(int *m)
384 {
385     queuePush(Q_MAIN, (void*) m);
386 }
387 
sendAbort()388 void sendAbort()
389 {
390     int* i = (int*) malloc(sizeof(int));
391     *i = M_ABORT;
392     sendToMainThread(i);
393 }
394 
sendDisconnect()395 void sendDisconnect()
396 {
397     int* i = (int*) malloc(sizeof(int));
398     *i = M_DISCONNECT;
399     sendToMainThread(i);
400 }
401 
stripCommandEnding(char * s)402 void stripCommandEnding(char *s)
403 {
404     if (s && strlen(s) >= 2) {
405         s[strlen(s)-2] = '\0';   // strip );
406     }
407 }
408 
409 //////////////////////////////////////////////////////////////////////////////////
410 
errnoDebug(const char * tag,int err)411 void errnoDebug(const char* tag, int err)
412 {
413 
414     DEBUG2("[DS]: %s error %d (%s)", tag, err, strerror(err));
415     /*switch (err) {
416     	case EPERM:
417             DEBUG2("[DS]: %s error EPERM (Operation not permitted)", tag);
418             break;
419      	case ENOENT:
420             DEBUG2("[DS]: %s error ENOENT (No such file or directory)", tag);
421             break;
422     	case EINTR:
423             DEBUG2("[DS]: %s error EINTR (Interrupted system call)", tag);
424             break;
425     	case EIO:
426             DEBUG2("[DS]: %s error EIO (I/O error"), tag);
427             break;
428    	case EBADF:
429             DEBUG2("[DS]: %s error EBADF (Bad file number)", tag);
430             break;
431     	case EAGAIN:
432             DEBUG2("[DS]: %s error EAGAIN (Try again)", tag);
433             break;
434     	case ENOMEM:
435             DEBUG2("[DS]: %s error ENOMEM (Out of memory)", tag);
436             break;
437     	case EBUSY:
438             DEBUG2("[DS]: %s error EBUSY (Device or resource busy)", tag);
439             break;
440    	case EFAULT:
441             DEBUG2("[DS]: %s error EFAULT (Bad address)", tag);
442             break;
443     	case EISDIR:
444             DEBUG2("[DS]: %s error EISDIR (Is a directory)", tag);
445             break;
446     	case EINVAL:
447             DEBUG2("[DS]: %s error EINVAL (Invalid argument)", tag);
448             break;
449     	case EFBIG:
450             DEBUG2("[DS]: %s error EFBIG (File too large)", tag);
451             break;
452     	case ENOSPC:
453             DEBUG2("[DS]: %s error ENOSPC (No space left on device)", tag);
454             break;
455     	case EPIPE:
456             DEBUG2("[DS]: %s error EPIPE (Broken pipe)", tag);
457             break;
458      	case EDESTADDRREQ:
459             DEBUG2("[DS]: %s error EDESTADDRREQ (Destination address required)", tag);
460             break;
461     	case ECONNRESET:
462             DEBUG2("[DS]: %s error ECONNRESET (Connection reset by peer)", tag);
463             break;
464     	default :
465             DEBUG2("[DS]: %s error %d", tag, err);
466             break;
467     }*/
468 }
469 //////////////////////////////////////////////////////////////////////////////////
470 //
471 // iconv() support
472 //
473 //////////////////////////////////////////////////////////////////////////////////
474 
475 #ifdef USE_ICONV
476 
convCharsetSimple(char * str,int direction)477 char * convCharsetSimple(char *str, int direction)
478 {
479     if (!str) return strdup("");
480     size_t size = strlen(str);
481 
482     return convCharset(str, size, direction);
483 }
484 
convCharset(char * str,size_t size,int direction)485 char * convCharset(char *str, size_t size, int direction)
486 {
487     DEBUG2("convCharset >%s<", str);
488     char *out;
489 
490     if (!str || size == 0 ||
491         (direction == CNV_TO   && convertorTo   == (iconv_t) - 1) ||
492 	(direction == CNV_FROM && convertorFrom == (iconv_t) - 1)) {
493 
494 	DEBUG2("convCharset skip conversion");
495         out = strdup("");
496 
497     } else {
498 
499 	char *buf, *holder;
500         size_t insize, outsize, bufsize, r;
501 
502         insize = size;
503         outsize = bufsize = insize * 4;
504 
505         buf = (char *) malloc(bufsize);
506         holder = buf;
507 
508 	    iconv_t cnv = (direction == CNV_TO ? convertorTo : convertorFrom);
509 
510         r = iconv(cnv, &str, &insize, &buf, &outsize);
511         if (r < 0 || insize != 0) {
512 	    DEBUG2("convCharset error on conversion %d", (int) outsize);
513             free(holder);
514             return strdup("");
515         }
516 
517 
518         size = bufsize - outsize;
519 
520         buf -= size;
521         out = (char *) malloc(size + 1);
522         memcpy(out, buf, size);
523 	    out[size] = '\0';
524 
525         free(holder);
526     }
527 
528     return out;
529 }
530 
531 #endif
532 
533 //////////////////////////////////////////////////////////////////////////////////
534