55785ce38f832cf92d0f53d17da70a3ca24fba34
[sdk/target/sdbd.git] / src / file_sync_service.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <utime.h>
25 #include <regex.h>
26 #include <errno.h>
27 #include <sys/socket.h>
28 #include <sys/select.h>
29 #include "sysdeps.h"
30 #include <sys/smack.h>
31 #include <tzplatform_config.h>
32
33 #define TRACE_TAG  TRACE_SYNC
34 #include "sdb.h"
35 #include "file_sync_service.h"
36 #include "sdktools.h"
37
38 #define SYNC_TIMEOUT 15
39
40 #define APP_INSTALL_PATH_PREFIX1                tzplatform_getenv(TZ_SYS_RW_APP)
41 #define APP_INSTALL_PATH_PREFIX2                tzplatform_getenv(TZ_USER_APP)
42
43 struct sync_permit_rule
44 {
45     const char *name;
46     const char *regx;
47     int mode; // 0:push, 1: pull, 2: push&push
48 };
49
50 struct sync_permit_rule sdk_sync_permit_rule[] = {
51 //    /* 0 */ {"rds", "^((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/info/\\.sdk_delta\\.info$", 1},
52     /* 1 */ {"unitest", "^((/tmp)|(/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,50}\\.xml$", 1},
53     /* 2 */ {"codecoverage", "^((/tmp)|(/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/+(.)*\\.gcda$", 1},
54     /* 3 */ {"da", "^(/tmp/da/)*+[a-zA-Z0-9_\\-\\.]{1,50}\\.png$", 1},
55     /* end */ {NULL, NULL, 0}
56 };
57
58 /* The typical default value for the umask is S_IWGRP | S_IWOTH (octal 022).
59  * Before use the DIR_PERMISSION, the process umask value should be set 0 using umask().
60  */
61 #define DIR_PERMISSION 0777
62
63 void init_sdk_sync_permit_rule_regx(void)
64 {
65     asprintf(&sdk_sync_permit_rule[0].regx, "^((/tmp)|(%s)|(%s))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,50}\\.xml$", APP_INSTALL_PATH_PREFIX1, APP_INSTALL_PATH_PREFIX2);
66     asprintf(&sdk_sync_permit_rule[1].regx, "^((/tmp)|(%s)|(%s))/[a-zA-Z0-9]{10}/data/+(.)*\\.gcda$", APP_INSTALL_PATH_PREFIX1, APP_INSTALL_PATH_PREFIX2);
67     asprintf(&sdk_sync_permit_rule[2].regx, "da", "^(/tmp/da/)*+[a-zA-Z0-9_\\-\\.]{1,50}\\.png$");
68
69 }
70
71 static void set_syncfile_smack_label(char *src) {
72     char *label_transmuted = NULL;
73     char *label = NULL;
74     char *src_chr = strrchr(src, '/');
75     int pos = src_chr - src + 1;
76     char dirname[512];
77
78     if (getuid() != 0) {
79         D("need root permission to set smack label: %d\n", getuid());
80         return;
81     }
82
83     snprintf(dirname, pos, "%s", src);
84
85     //D("src:[%s], dirname:[%s]\n", src, dirname);
86     int rc = smack_getlabel(dirname, &label_transmuted, SMACK_LABEL_TRANSMUTE);
87
88     if (rc == 0 && label_transmuted != NULL) {
89         if (!strcmp("TRUE", label_transmuted)) {
90             rc = smack_getlabel(dirname, &label, SMACK_LABEL_ACCESS);
91             if (rc == 0 && label != NULL) {
92                 if (smack_setlabel(src, label, SMACK_LABEL_ACCESS) == -1) {
93                     D("unable to set sync file smack label %s due to %s\n", label, strerror(errno));
94                 }
95                 free(label);
96             }
97         } else{
98             D("fail to set label, is it transmuted?:%s\n", label_transmuted);
99         }
100         free(label_transmuted);
101     } else {
102         if (smack_setlabel(src, SMACK_SYNC_FILE_LABEL, SMACK_LABEL_ACCESS) == -1) {
103             D("unable to set sync file smack label %s due to %s\n", SMACK_SYNC_FILE_LABEL, strerror(errno));
104         }
105     }
106 }
107
108 static int sync_send_label_notify(int s, const char *path, int success)
109 {
110     char buffer[512] = {0,};
111     snprintf(buffer, sizeof(buffer), "%d:%s", success, path);
112
113     int len = sdb_write(s, buffer, sizeof(buffer));
114
115     return len;
116 }
117
118 static void sync_read_label_notify(int s)
119 {
120     char buffer[512] = {0,};
121
122     while (1) {
123         int len = sdb_read(s, buffer, sizeof(buffer));
124         if (len < 0) {
125             D("sync notify read error:%s\n", strerror(errno));
126             exit(-1);
127         }
128
129         if (buffer[0] == '0') {
130             D("sync notify child process exit\n");
131             exit(-1);
132         }
133         char *path = buffer;
134         path++;
135         path++;
136         set_syncfile_smack_label(path);
137     }
138 }
139
140 static int mkdirs(int noti_fd, char *name)
141 {
142     int ret;
143     char *x = name + 1;
144
145     if(name[0] != '/') {
146         return -1;
147     }
148
149     for(;;) {
150         x = sdb_dirstart(x);
151         if(x == 0) {
152             return 0;
153         }
154         *x = 0;
155
156         ret = sdb_mkdir(name, DIR_PERMISSION);
157         if (ret == 0) {
158             sync_send_label_notify(noti_fd, name, 1);
159         }
160         if((ret < 0) && (errno != EEXIST)) {
161             D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
162             *x = '/';
163             return ret;
164         }
165         *x++ = '/';
166     }
167     return 0;
168 }
169
170 static int do_stat(int s, const char *path)
171 {
172     syncmsg msg;
173     struct stat st;
174
175     msg.stat.id = ID_STAT;
176
177     /* follow link */
178     if(stat(path, &st)) {
179         msg.stat.mode = 0;
180         msg.stat.size = 0;
181         msg.stat.time = 0;
182         D("failed to stat %s due to: %s\n", path, strerror(errno));
183     } else {
184         msg.stat.mode = htoll(st.st_mode);
185         msg.stat.size = htoll(st.st_size);
186         msg.stat.time = htoll(st.st_mtime);
187     }
188
189     return writex(s, &msg.stat, sizeof(msg.stat));
190 }
191
192 static int do_list(int s, const char *path)
193 {
194     DIR *d;
195     struct dirent *de;
196     struct stat st;
197     syncmsg msg;
198     int len;
199
200     char tmp[1024 + 256 + 1];
201     char *fname;
202
203     len = strlen(path);
204     memcpy(tmp, path, len);
205     tmp[len] = '/';
206     fname = tmp + len + 1;
207
208     msg.dent.id = ID_DENT;
209
210     d = opendir(path);
211     if(d == NULL) {
212         D("failed to open dir due to: %s\n", strerror(errno));
213         goto done;
214     }
215
216     while((de = readdir(d))) {
217         int len = strlen(de->d_name);
218
219             /* not supposed to be possible, but
220                if it does happen, let's not buffer overrun */
221         if(len > 256) {
222             continue;
223         }
224
225         strcpy(fname, de->d_name);
226         if(lstat(tmp, &st) == 0) {
227             msg.dent.mode = htoll(st.st_mode);
228             msg.dent.size = htoll(st.st_size);
229             msg.dent.time = htoll(st.st_mtime);
230             msg.dent.namelen = htoll(len);
231
232             if(writex(s, &msg.dent, sizeof(msg.dent)) ||
233                writex(s, de->d_name, len)) {
234                 closedir(d);
235                 return -1;
236             }
237         }
238     }
239
240     closedir(d);
241
242 done:
243     msg.dent.id = ID_DONE;
244     msg.dent.mode = 0;
245     msg.dent.size = 0;
246     msg.dent.time = 0;
247     msg.dent.namelen = 0;
248     return writex(s, &msg.dent, sizeof(msg.dent));
249 }
250
251 static int fail_message(int s, const char *reason)
252 {
253     syncmsg msg;
254     int len = strlen(reason);
255
256     D("sync: failure: %s\n", reason);
257
258     msg.data.id = ID_FAIL;
259     msg.data.size = htoll(len);
260     if(writex(s, &msg.data, sizeof(msg.data)) ||
261        writex(s, reason, len)) {
262         return -1;
263     } else {
264         return 0;
265     }
266 }
267
268 static int fail_errno(int s)
269 {
270     return fail_message(s, strerror(errno));
271 }
272
273 static int handle_send_file(int s, int noti_fd, char *path, mode_t mode, char *buffer)
274 {
275     syncmsg msg;
276     unsigned int timestamp = 0;
277     int fd;
278
279     fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
280     if(fd < 0 && errno == ENOENT) {
281         mkdirs(noti_fd, path);
282         fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
283     }
284     if(fd < 0 && errno == EEXIST) {
285         fd = sdb_open_mode(path, O_WRONLY, mode);
286     }
287     if(fd < 0) {
288         if(fail_errno(s))
289             return -1;
290         fd = -1;
291     }
292     for(;;) {
293         unsigned int len;
294
295         if(readx(s, &msg.data, sizeof(msg.data))) {
296             goto fail;
297         }
298         if(msg.data.id != ID_DATA) {
299             if(msg.data.id == ID_DONE) {
300                 timestamp = ltohl(msg.data.size);
301                 break;
302             }
303             fail_message(s, "invalid data message");
304             goto fail;
305         }
306         len = ltohl(msg.data.size);
307         if(len > SYNC_DATA_MAX) {
308             fail_message(s, "oversize data message");
309             goto fail;
310         }
311         if(readx(s, buffer, len)) {
312             D("read failed due to unknown reason\n");
313             goto fail;
314         }
315
316         if(fd < 0) {
317             continue;
318         }
319         if(writex(fd, buffer, len)) {
320             int saved_errno = errno;
321             sdb_close(fd);
322             sdb_unlink(path);
323             fd = -1;
324             errno = saved_errno;
325             if(fail_errno(s)) return -1;
326         }
327     }
328
329     if(fd >= 0) {
330         struct utimbuf u;
331         sdb_close(fd);
332         u.actime = timestamp;
333         u.modtime = timestamp;
334         utime(path, &u);
335
336         msg.status.id = ID_OKAY;
337         msg.status.msglen = 0;
338         if(writex(s, &msg.status, sizeof(msg.status)))
339             return -1;
340         // flush file system buffers due to N_SE-22305
341         sync();
342     } else {
343         D("sync error: %d!!!\n", fd);
344         return -1;
345     }
346     sync_send_label_notify(noti_fd, path, 1);
347     return 0;
348
349 fail:
350     if(fd >= 0)
351         sdb_close(fd);
352     sdb_unlink(path);
353     return -1;
354 }
355
356 #ifdef HAVE_SYMLINKS
357 static int handle_send_link(int s, int noti_fd, char *path, char *buffer)
358 {
359     syncmsg msg;
360     unsigned int len;
361     int ret;
362
363     if(readx(s, &msg.data, sizeof(msg.data)))
364         return -1;
365
366     if(msg.data.id != ID_DATA) {
367         fail_message(s, "invalid data message: expected ID_DATA");
368         return -1;
369     }
370
371     len = ltohl(msg.data.size);
372     if(len > SYNC_DATA_MAX) {
373         fail_message(s, "oversize data message");
374         return -1;
375     }
376     if(readx(s, buffer, len))
377         return -1;
378
379     ret = symlink(buffer, path);
380     if(ret && errno == ENOENT) {
381         mkdirs(noti_fd, path);
382         ret = symlink(buffer, path);
383     }
384     if(ret) {
385         fail_errno(s);
386         return -1;
387     }
388
389     if(readx(s, &msg.data, sizeof(msg.data)))
390         return -1;
391
392     if(msg.data.id == ID_DONE) {
393         msg.status.id = ID_OKAY;
394         msg.status.msglen = 0;
395         if(writex(s, &msg.status, sizeof(msg.status)))
396             return -1;
397     } else {
398         fail_message(s, "invalid data message: expected ID_DONE");
399         return -1;
400     }
401
402     return 0;
403 }
404 #endif /* HAVE_SYMLINKS */
405
406 static int do_send(int s, int noti_fd, char *path, char *buffer)
407 {
408     char *tmp;
409     mode_t mode;
410     int is_link, ret;
411
412     tmp = strrchr(path,',');
413     if(tmp) {
414         *tmp = 0;
415         errno = 0;
416         mode = strtoul(tmp + 1, NULL, 0);
417 #ifndef HAVE_SYMLINKS
418         is_link = 0;
419 #else
420         is_link = S_ISLNK(mode);
421 #endif
422         // extracts file permission from stat.mode. (ex 100644 & 0777 = 644);
423         mode &= 0777; // combination of (S_IRWXU | S_IRWXG | S_IRWXO)
424         mode |= S_IWOTH; // SDK requirement from N_SE-43337
425     }
426     if(!tmp || errno) {
427         mode = 0644; // set default permission value in most of unix system.
428         is_link = 0;
429     }
430
431     // sdb does not allow to check that file exists or not. After deleting old file and creating new file again unconditionally.
432     sdb_unlink(path);
433
434
435 #ifdef HAVE_SYMLINKS
436     if(is_link)
437         ret = handle_send_link(s, noti_fd, path, buffer);
438     else {
439 #else
440     {
441 #endif
442         /* copy user permission bits to "group" and "other" permissions.
443          * ex) 0644 file will be created copied 0666 file.
444          * the following 2 lines should be commented if sdb process has been set to umask 0.
445          */
446
447         //mode |= ((mode >> 3) & 0070);
448         //mode |= ((mode >> 3) & 0007);
449         ret = handle_send_file(s, noti_fd, path, mode, buffer);
450     }
451
452     return ret;
453 }
454
455 static int do_recv(int s, const char *path, char *buffer)
456 {
457     syncmsg msg;
458     int fd, r;
459
460     fd = sdb_open(path, O_RDONLY);
461     if(fd < 0) {
462         if(fail_errno(s)) return -1;
463         return 0;
464     }
465
466     msg.data.id = ID_DATA;
467     for(;;) {
468         r = sdb_read(fd, buffer, SYNC_DATA_MAX);
469         if(r <= 0) {
470             if(r == 0) break;
471             if(errno == EINTR) continue;
472             r = fail_errno(s);
473             sdb_close(fd);
474             return r;
475         }
476         msg.data.size = htoll(r);
477         if(writex(s, &msg.data, sizeof(msg.data)) ||
478            writex(s, buffer, r)) {
479             sdb_close(fd);
480             return -1;
481         }
482     }
483
484     sdb_close(fd);
485
486     msg.data.id = ID_DONE;
487     msg.data.size = 0;
488     if(writex(s, &msg.data, sizeof(msg.data))) {
489         return -1;
490     }
491     return 0;
492 }
493
494 static int verify_sync_rule(const char* path) {
495     regex_t regex;
496     int ret;
497     char buf[PATH_MAX];
498     int i=0;
499
500     init_sdk_sync_permit_rule_regx();
501     for (i=0; sdk_sync_permit_rule[i].regx != NULL; i++) {
502         ret = regcomp(&regex, sdk_sync_permit_rule[i].regx, REG_EXTENDED);
503         if(ret){
504             return 0;
505         }
506         // execute regular expression
507         ret = regexec(&regex, path, 0, NULL, 0);
508         if(!ret){
509             regfree(&regex);
510             D("found matched rule(%s) from %s path\n", sdk_sync_permit_rule[i].name, path);
511             return 1;
512         } else if( ret == REG_NOMATCH ){
513             // do nothin
514         } else{
515             regerror(ret, &regex, buf, sizeof(buf));
516             D("regex match failed(%s): %s\n",sdk_sync_permit_rule[i].name, buf);
517         }
518     }
519     regfree(&regex);
520     for (i = 0; i <= 3; i++){
521        free(sdk_sync_permit_rule[i].regx);
522     }
523     return 0;
524 }
525
526 void file_sync_service(int fd, void *cookie)
527 {
528     syncmsg msg;
529     char name[1025];
530     unsigned namelen;
531     fd_set set;
532     struct timeval timeout;
533     int rv;
534     int s[2];
535
536     if(sdb_socketpair(s)) {
537         D("cannot create service socket pair\n");
538         exit(-1);
539     }
540     char *buffer = malloc(SYNC_DATA_MAX);
541     if(buffer == 0) {
542         goto fail;
543     }
544
545     FD_ZERO(&set); /* clear the set */
546     FD_SET(fd, &set); /* add our file descriptor to the set */
547
548     timeout.tv_sec = SYNC_TIMEOUT;
549     timeout.tv_usec = 0;
550
551     pid_t pid = fork();
552
553     if (pid == 0) {
554         sdb_close(s[0]); //close the parent fd
555         sync_read_label_notify(s[1]);
556     } else if (pid > 0) {
557         sdb_close(s[1]);
558         for(;;) {
559             D("sync: waiting for command for %d sec\n", SYNC_TIMEOUT);
560
561             rv = select(fd + 1, &set, NULL, NULL, &timeout);
562             if (rv == -1) {
563                 D("sync file descriptor select failed\n");
564             } else if (rv == 0) {
565                 D("sync file descriptor timeout: (took %d sec over)\n", SYNC_TIMEOUT);
566                 fail_message(fd, "sync timeout");
567                 goto fail;
568             }
569
570             if(readx(fd, &msg.req, sizeof(msg.req))) {
571                 fail_message(fd, "command read failure");
572                 break;
573             }
574             namelen = ltohl(msg.req.namelen);
575             if(namelen > 1024) {
576                 fail_message(fd, "invalid namelen");
577                 break;
578             }
579             if(readx(fd, name, namelen)) {
580                 fail_message(fd, "filename read failure");
581                 break;
582             }
583             name[namelen] = 0;
584
585             msg.req.namelen = 0;
586             D("sync: '%s' '%s'\n", (char*) &msg.req, name);
587
588             if (should_drop_privileges() && !verify_sync_rule(name)) {
589                 set_developer_privileges();
590             }
591
592             switch(msg.req.id) {
593             case ID_STAT:
594                 if(do_stat(fd, name)) goto fail;
595                 break;
596             case ID_LIST:
597                 if(do_list(fd, name)) goto fail;
598                 break;
599             case ID_SEND:
600                 if(do_send(fd, s[0], name, buffer)) goto fail;
601                 break;
602             case ID_RECV:
603                 if(do_recv(fd, name, buffer)) goto fail;
604                 break;
605             case ID_QUIT:
606                 goto fail;
607             default:
608                 fail_message(fd, "unknown command");
609                 goto fail;
610             }
611         }
612     }
613
614
615 fail:
616     if(buffer != 0) {
617         free(buffer);
618     }
619     D("sync: done\n");
620     sync_send_label_notify(s[0], name, 0);
621     sdb_close(s[0]);
622     sdb_close(s[1]);
623     sdb_close(fd);
624 }