086646cef5390c53a1c178be4780d659aed04cbc
[libsamsung-ipc.git] / samsung-ipc / rfs.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * libsamsung-ipc is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * libsamsung-ipc is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28
29 #include <openssl/md5.h>
30
31 #include <samsung-ipc.h>
32
33 #include <ipc.h>
34
35 char *ipc_nv_data_md5_calculate(const char *path, const char *secret,
36     size_t size, size_t chunk_size)
37 {
38     void *data = NULL;
39     char *md5_string = NULL;
40     unsigned char md5_hash[MD5_DIGEST_LENGTH] = { 0 };
41     MD5_CTX ctx;
42     int rc;
43
44     if (secret == NULL)
45         return NULL;
46
47     data = file_data_read(path, size, chunk_size, 0);
48     if (data == NULL)
49         return NULL;
50
51     MD5_Init(&ctx);
52     MD5_Update(&ctx, data, size);
53     MD5_Update(&ctx, secret, strlen(secret));
54     MD5_Final((unsigned char *) &md5_hash, &ctx);
55
56     md5_string = data2string(&md5_hash, sizeof(md5_hash));
57
58     return md5_string;
59 }
60
61 int ipc_nv_data_path_check(struct ipc_client *client)
62 {
63     struct stat st;
64     char *path;
65     size_t size;
66     int rc;
67
68     if (client == NULL)
69         return -1;
70
71     path = ipc_client_nv_data_path(client);
72     size = ipc_client_nv_data_size(client);
73     if (path == NULL || size == 0)
74         return -1;
75
76     rc = stat(path, &st);
77     if (rc < 0) {
78         ipc_client_log(client, "Checking nv_data path failed");
79         return -1;
80     }
81
82     if (st.st_size != size) {
83         ipc_client_log(client, "Checking nv_data size failed");
84         return -1;
85     }
86
87     ipc_client_log(client, "Checked nv_data path");
88
89     return 0;
90 }
91
92 int ipc_nv_data_md5_path_check(struct ipc_client *client)
93 {
94     struct stat st;
95     char *md5_path;
96     int rc;
97
98     if (client == NULL)
99         return -1;
100
101     md5_path = ipc_client_nv_data_md5_path(client);
102     if (md5_path == NULL)
103         return -1;
104
105     rc = stat(md5_path, &st);
106     if (rc < 0) {
107         ipc_client_log(client, "Checking nv_data md5 path failed");
108         return -1;
109     }
110
111     if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
112         ipc_client_log(client, "Checking nv_data md5 size failed");
113         return -1;
114     }
115
116     ipc_client_log(client, "Checked nv_data md5 path");
117
118     return 0;
119 }
120
121 int ipc_nv_data_backup_path_check(struct ipc_client *client)
122 {
123     struct stat st;
124     char *backup_path;
125     size_t size;
126     int rc;
127
128     if (client == NULL)
129         return -1;
130
131     backup_path = ipc_client_nv_data_backup_path(client);
132     size = ipc_client_nv_data_size(client);
133     if (backup_path == NULL || size == 0)
134         return -1;
135
136     rc = stat(backup_path, &st);
137     if (rc < 0) {
138         ipc_client_log(client, "Checking nv_data backup path failed");
139         return -1;
140     }
141
142     if (st.st_size != size) {
143         ipc_client_log(client, "Checking nv_data backup size failed");
144         return -1;
145     }
146
147     ipc_client_log(client, "Checked nv_data backup path");
148
149     return 0;
150 }
151
152 int ipc_nv_data_backup_md5_path_check(struct ipc_client *client)
153 {
154     struct stat st;
155     char *backup_md5_path;
156     int rc;
157
158     if (client == NULL)
159         return -1;
160
161     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
162     if (backup_md5_path == NULL)
163         return -1;
164
165     rc = stat(backup_md5_path, &st);
166     if (rc < 0) {
167         ipc_client_log(client, "Checking nv_data backup md5 path failed");
168         return -1;
169     }
170
171     if (st.st_size < 2 * sizeof(char) * MD5_DIGEST_LENGTH) {
172         ipc_client_log(client, "Checking nv_data backup md5 size failed");
173         return -1;
174     }
175
176     ipc_client_log(client, "Checked nv_data backup md5 path");
177
178     return 0;
179 }
180
181 int ipc_nv_data_check(struct ipc_client *client)
182 {
183     char *path;
184     char *md5_path;
185     char *secret;
186     size_t size;
187     size_t chunk_size;
188     char *md5_string = NULL;
189     void *buffer = NULL;
190     char *string = NULL;
191     size_t length;
192     int rc;
193
194     if (client == NULL)
195         return -1;
196
197     path = ipc_client_nv_data_path(client);
198     md5_path = ipc_client_nv_data_md5_path(client);
199     secret = ipc_client_nv_data_secret(client);
200     size = ipc_client_nv_data_size(client);
201     chunk_size = ipc_client_nv_data_chunk_size(client);
202     if (path == NULL || md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
203         return -1;
204
205     rc = ipc_nv_data_path_check(client);
206     if (rc < 0) {
207         ipc_client_log(client, "Checking nv_data path failed");
208         goto error;
209     }
210
211     rc = ipc_nv_data_md5_path_check(client);
212     if (rc < 0) {
213         ipc_client_log(client, "Checking nv_data md5 path failed");
214         goto error;
215     }
216
217     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
218     if (md5_string == NULL) {
219         ipc_client_log(client, "Calculating nv_data md5 failed");
220         goto error;
221     }
222     ipc_client_log(client, "Calculated nv_data md5: %s", md5_string);
223
224     length = strlen(md5_string);
225
226     buffer = file_data_read(md5_path, length, length, 0);
227     if (buffer == NULL) {
228         ipc_client_log(client, "Reading nv_data md5 failed");
229         goto error;
230     }
231
232     string = strndup(buffer, length);
233     ipc_client_log(client, "Read nv_data md5: %s", string);
234
235     rc = strncmp(md5_string, string, length);
236     if (rc != 0) {
237         ipc_client_log(client, "Matching nv_data md5 failed");
238         goto error;
239     }
240
241     rc = 0;
242     goto complete;
243
244 error:
245     rc = -1;
246
247 complete:
248     if (string != NULL)
249         free(string);
250
251     if (buffer != NULL)
252         free(buffer);
253
254     if (md5_string != NULL)
255         free(md5_string);
256
257     return rc;
258 }
259
260 int ipc_nv_data_backup_check(struct ipc_client *client)
261 {
262     char *backup_path;
263     char *backup_md5_path;
264     char *secret;
265     size_t size;
266     size_t chunk_size;
267     char *backup_md5_string = NULL;
268     void *buffer = NULL;
269     char *string = NULL;
270     size_t length;
271     int rc;
272
273     if (client == NULL)
274         return -1;
275
276     backup_path = ipc_client_nv_data_backup_path(client);
277     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
278     secret = ipc_client_nv_data_secret(client);
279     size = ipc_client_nv_data_size(client);
280     chunk_size = ipc_client_nv_data_chunk_size(client);
281     if (backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
282         return -1;
283
284     rc = ipc_nv_data_backup_path_check(client);
285     if (rc < 0) {
286         ipc_client_log(client, "Checking nv_data backup path failed");
287         goto error;
288     }
289
290     rc = ipc_nv_data_backup_md5_path_check(client);
291     if (rc < 0) {
292         ipc_client_log(client, "Checking nv_data backup md5 path failed");
293         goto error;
294     }
295
296     backup_md5_string = ipc_nv_data_md5_calculate(backup_path, secret, size, chunk_size);
297     if (backup_md5_string == NULL) {
298         ipc_client_log(client, "Calculating nv_data backup md5 failed");
299         goto error;
300     }
301     ipc_client_log(client, "Calculated nv_data backup md5: %s", backup_md5_string);
302
303     length = strlen(backup_md5_string);
304
305     buffer = file_data_read(backup_md5_path, length, length, 0);
306     if (buffer == NULL) {
307         ipc_client_log(client, "Reading nv_data backup md5 failed");
308         goto error;
309     }
310
311     string = strndup(buffer, length);
312     ipc_client_log(client, "Read nv_data backup md5: %s", string);
313
314     rc = strncmp(backup_md5_string, string, length);
315     if (rc != 0) {
316         ipc_client_log(client, "Matching nv_data backup md5 failed");
317         goto error;
318     }
319
320     rc = 0;
321     goto complete;
322
323 error:
324     rc = -1;
325
326 complete:
327     if (string != NULL)
328         free(string);
329
330     if (buffer != NULL)
331         free(buffer);
332
333     if (backup_md5_string != NULL)
334         free(backup_md5_string);
335
336     return rc;
337 }
338
339 int ipc_nv_data_backup(struct ipc_client *client)
340 {
341     void *data = NULL;
342     char *path;
343     char *backup_path;
344     char *backup_md5_path;
345     char *secret;
346     size_t size;
347     size_t chunk_size;
348     char *md5_string = NULL;
349     size_t length;
350     int rc;
351
352     if (client == NULL)
353         return -1;
354
355     path = ipc_client_nv_data_path(client);
356     backup_path = ipc_client_nv_data_backup_path(client);
357     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
358     secret = ipc_client_nv_data_secret(client);
359     size = ipc_client_nv_data_size(client);
360     chunk_size = ipc_client_nv_data_chunk_size(client);
361     if (path == NULL || backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
362         return -1;
363
364     rc = ipc_nv_data_path_check(client);
365     if (rc < 0) {
366         ipc_client_log(client, "Checking nv_data path failed");
367         goto error;
368     }
369
370     data = file_data_read(path, size, chunk_size, 0);
371     if (data == NULL) {
372         ipc_client_log(client, "Reading nv_data failed");
373         goto error;
374     }
375
376     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
377     if (md5_string == NULL) {
378         ipc_client_log(client, "Calculating nv_data md5 failed");
379         goto error;
380     }
381
382     length = strlen(md5_string);
383
384     rc = unlink(backup_path);
385     if (rc < 0)
386         ipc_client_log(client, "Removing nv_data backup path failed");
387
388     rc = file_data_write(backup_path, data, size, chunk_size, 0);
389     if (rc < 0) {
390         ipc_client_log(client, "Writing nv_data backup failed");
391         goto error;
392     }
393
394     rc = unlink(backup_md5_path);
395     if (rc < 0)
396         ipc_client_log(client, "Removing nv_data backup md5 path failed");
397
398     rc = file_data_write(backup_md5_path, md5_string, length, length, 0);
399     if (rc < 0) {
400         ipc_client_log(client, "Writing nv_data backup md5 failed");
401         goto error;
402     }
403
404     ipc_client_log(client, "Backed up nv_data");
405
406     rc = 0;
407     goto complete;
408
409 error:
410     rc = -1;
411
412 complete:
413     if (md5_string != NULL)
414         free(md5_string);
415
416     if (data != NULL)
417         free(data);
418
419     return rc;
420 }
421
422 int ipc_nv_data_restore(struct ipc_client *client)
423 {
424     void *data = NULL;
425     char *path;
426     char *md5_path;
427     char *backup_path;
428     char *backup_md5_path;
429     char *secret;
430     size_t size;
431     size_t chunk_size;
432     size_t length;
433     int rc;
434
435     if (client == NULL)
436         return -1;
437
438     path = ipc_client_nv_data_path(client);
439     md5_path = ipc_client_nv_data_md5_path(client);
440     backup_path = ipc_client_nv_data_backup_path(client);
441     backup_md5_path = ipc_client_nv_data_backup_md5_path(client);
442     secret = ipc_client_nv_data_secret(client);
443     size = ipc_client_nv_data_size(client);
444     chunk_size = ipc_client_nv_data_chunk_size(client);
445     if (path == NULL || md5_path == NULL || backup_path == NULL || backup_md5_path == NULL || secret == NULL || size == 0 || chunk_size == 0)
446         return -1;
447
448     rc = ipc_nv_data_backup_check(client);
449     if (rc < 0) {
450         ipc_client_log(client, "Checking nv_data backup failed");
451         goto error;
452     }
453
454     data = file_data_read(backup_path, size, chunk_size, 0);
455     if (data == NULL) {
456         ipc_client_log(client, "Reading nv_data backup failed");
457         goto error;
458     }
459
460     rc = unlink(path);
461     if (rc < 0)
462         ipc_client_log(client, "Removing nv_data path failed");
463
464     rc = file_data_write(path, data, size, chunk_size, 0);
465     if (rc < 0) {
466         ipc_client_log(client, "Writing nv_data failed");
467         goto error;
468     }
469
470     free(data);
471     data = NULL;
472
473     length = 2 * sizeof(char) * MD5_DIGEST_LENGTH;
474
475     data = file_data_read(backup_md5_path, length, length, 0);
476     if (data == NULL) {
477         ipc_client_log(client, "Reading nv_data backup md5 failed");
478         goto error;
479     }
480
481     rc = unlink(md5_path);
482     if (rc < 0)
483         ipc_client_log(client, "Removing nv_data md5 path failed");
484
485     rc = file_data_write(md5_path, data, length, length, 0);
486     if (rc < 0) {
487         ipc_client_log(client, "Writing nv_data md5 failed");
488         goto error;
489     }
490
491     ipc_client_log(client, "Restored nv_data");
492
493     rc = 0;
494     goto complete;
495
496 error:
497     rc = -1;
498
499 complete:
500     if (data != NULL)
501         free(data);
502
503     return rc;
504 }
505
506 void *ipc_nv_data_load(struct ipc_client *client)
507 {
508     void *data;
509     char *path;
510     size_t size;
511     size_t chunk_size;
512     int rc;
513
514     if (client == NULL)
515         return NULL;
516
517     path = ipc_client_nv_data_path(client);
518     size = ipc_client_nv_data_size(client);
519     chunk_size = ipc_client_nv_data_chunk_size(client);
520     if (path == NULL || size == 0 || chunk_size == 0)
521         return NULL;
522
523     rc = ipc_nv_data_check(client);
524     if (rc < 0) {
525         ipc_client_log(client, "Checking nv_data failed");
526
527         rc = ipc_nv_data_restore(client);
528         if (rc < 0) {
529             ipc_client_log(client, "Restoring nv_data failed");
530             return NULL;
531         }
532
533         rc = ipc_nv_data_check(client);
534         if (rc < 0) {
535             ipc_client_log(client, "Checking nv_data failed");
536             return NULL;
537         }
538     }
539
540     rc = ipc_nv_data_backup_path_check(client);
541     if (rc < 0) {
542         ipc_client_log(client, "Checking nv_data backup path failed");
543
544         rc = ipc_nv_data_backup(client);
545         if (rc < 0)
546             ipc_client_log(client, "Backing up nv_data failed");
547     }
548
549     data = file_data_read(path, size, chunk_size, 0);
550     if (data == NULL) {
551         ipc_client_log(client, "Reading nv_data failed");
552         return NULL;
553     }
554
555     return data;
556 }
557
558 void *ipc_nv_data_read(struct ipc_client *client, size_t size,
559     unsigned int offset)
560 {
561     void *data;
562     char *path;
563     size_t chunk_size;
564     int rc;
565
566     if (client == NULL)
567         return NULL;
568
569     path = ipc_client_nv_data_path(client);
570     chunk_size = ipc_client_nv_data_chunk_size(client);
571     if (path == NULL || chunk_size == 0)
572         return NULL;
573
574     rc = ipc_nv_data_path_check(client);
575     if (rc < 0) {
576         ipc_client_log(client, "Checking nv_data path failed");
577         return NULL;
578     }
579
580     data = file_data_read(path, size, chunk_size > size ? size : chunk_size, offset);
581     if (data == NULL) {
582         ipc_client_log(client, "Reading nv_data failed");
583         return NULL;
584     }
585
586     return data;
587 }
588
589 int ipc_nv_data_write(struct ipc_client *client, const void *data, size_t size,
590     unsigned int offset)
591 {
592     char *path;
593     char *md5_path;
594     char *secret;
595     size_t chunk_size;
596     char *md5_string = NULL;
597     size_t length;
598     int rc;
599
600     if (client == NULL)
601         return -1;
602
603     path = ipc_client_nv_data_path(client);
604     md5_path = ipc_client_nv_data_md5_path(client);
605     secret = ipc_client_nv_data_secret(client);
606     chunk_size = ipc_client_nv_data_chunk_size(client);
607     if (path == NULL || md5_path == NULL || secret == NULL || chunk_size == 0)
608         return -1;
609
610     rc = ipc_nv_data_path_check(client);
611     if (rc < 0) {
612         ipc_client_log(client, "Checking nv_data path failed");
613         goto error;
614     }
615
616     rc = file_data_write(path, data, size, chunk_size > size ? size : chunk_size, offset);
617     if (rc < 0) {
618         ipc_client_log(client, "Writing nv_data failed");
619         goto error;
620     }
621
622     size = ipc_client_nv_data_size(client);
623     if (size == 0)
624         goto error;
625
626     md5_string = ipc_nv_data_md5_calculate(path, secret, size, chunk_size);
627     if (md5_string == NULL) {
628         ipc_client_log(client, "Calculating nv_data md5 failed");
629         goto error;
630     }
631
632     length = strlen(md5_string);
633
634     rc = unlink(md5_path);
635     if (rc < 0) {
636         ipc_client_log(client, "Removing nv_data md5 path failed");
637         goto error;
638     }
639
640     rc = file_data_write(md5_path, md5_string, length, length, 0);
641     if (rc < 0) {
642         ipc_client_log(client, "Writing nv_data md5 failed");
643         goto error;
644     }
645
646     rc = 0;
647     goto complete;
648
649 error:
650     rc = -1;
651
652 complete:
653     if (md5_string != NULL)
654         free(md5_string);
655
656     return rc;
657 }
658
659 void *ipc_rfs_nv_read_item_response_setup(const void *data, size_t size,
660     unsigned int offset)
661 {
662     struct ipc_rfs_nv_read_item_response_header *header;
663     void *buffer;
664     size_t length;
665     unsigned char confirm;
666     unsigned char *p;
667
668     if (data != NULL && size > 0) {
669         length = sizeof(struct ipc_rfs_nv_read_item_response_header) + size;
670         confirm = 1;
671     } else {
672         length = sizeof(struct ipc_rfs_nv_read_item_response_header);
673         size = 0;
674         offset = 0;
675         confirm = 0;
676     }
677
678     buffer = calloc(1, length);
679
680     header = (struct ipc_rfs_nv_read_item_response_header *) buffer;
681     header->confirm = confirm;
682     header->offset = offset;
683     header->length = (unsigned int) size;
684
685     if (data != NULL && size > 0) {
686         p = (unsigned char *) buffer;
687         p += sizeof(struct ipc_rfs_nv_read_item_response_header);
688
689         memcpy(p, data, size);
690     }
691
692     return buffer;
693 }
694
695 // vim:ts=4:sw=4:expandtab