1 /*****************************************************************************
2 * file.c: File and crypt keystore
3 *****************************************************************************
4 * Copyright © 2015-2016 VLC authors, VideoLAN and VideoLabs
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program 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 Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_memory.h>
38 #include <vlc_keystore.h>
39 #include <vlc_strings.h>
43 #include "file_crypt.h"
44 #include "list_util.h"
46 static int Open(vlc_object_t
*);
47 static void Close(vlc_object_t
*);
49 static int OpenCrypt(vlc_object_t
*);
50 static void CloseCrypt(vlc_object_t
*);
54 set_shortname(N_("file keystore (plaintext)"))
55 set_description(N_("secrets are stored on a file without any encryption"))
56 set_category(CAT_ADVANCED
)
57 set_subcategory(SUBCAT_ADVANCED_MISC
)
58 set_callbacks(Open
, Close
)
59 add_savefile("keystore-file", NULL
, NULL
, NULL
, true)
61 set_capability("keystore", 0)
62 add_shortcut("file_plaintext")
65 set_shortname(N_("crypt keystore"))
66 set_description(N_("secrets are stored encrypted on a file"))
67 set_category(CAT_ADVANCED
)
68 set_subcategory(SUBCAT_ADVANCED_MISC
)
69 set_callbacks(OpenCrypt
, CloseCrypt
)
70 set_capability("keystore", 1)
71 add_shortcut("file_crypt")
75 struct vlc_keystore_sys
84 static const char *const ppsz_keys
[] = {
93 static_assert(sizeof(ppsz_keys
)/sizeof(*ppsz_keys
) == KEY_MAX
, "key mismatch");
96 str2key(const char *psz_key
)
98 for (unsigned int i
= 0; i
< KEY_MAX
; ++i
)
100 if (strcmp(ppsz_keys
[i
], psz_key
) == 0)
107 values_write(FILE *p_file
, const char *const ppsz_values
[KEY_MAX
])
109 for (unsigned int i
= 0; i
< KEY_MAX
; ++i
)
113 char *psz_b64
= vlc_b64_encode(ppsz_values
[i
]);
116 const char *psz_end_sep
= "";
117 for (unsigned int j
= i
+ 1; j
< KEY_MAX
; ++j
)
125 if (fprintf(p_file
, "%s:%s%s", ppsz_keys
[i
], psz_b64
, psz_end_sep
) < 0)
140 return ftruncate(i_fd
, 0) == 0 ? VLC_SUCCESS
: VLC_EGENERIC
;
142 return _chsize(i_fd
, 0) == 0 ? VLC_SUCCESS
: VLC_EGENERIC
;
146 /* a line is "{key1:VALUE1_B64,key2:VALUE2_B64}:PASSWORD_B64" */
148 file_save(vlc_keystore
*p_keystore
, FILE *p_file
, int i_fd
, struct ks_list
*p_list
)
150 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
151 int i_ret
= VLC_EGENERIC
;
156 vlc_unlink(p_sys
->psz_file
);
160 for (unsigned int i
= 0; i
< p_list
->i_count
; ++i
)
162 vlc_keystore_entry
*p_entry
= &p_list
->p_entries
[i
];
163 if (!p_entry
->p_secret
)
166 if (fprintf(p_file
, "{") < 0)
168 if (values_write(p_file
, (const char *const *) p_entry
->ppsz_values
))
170 char *psz_b64
= vlc_b64_encode_binary(p_entry
->p_secret
,
171 p_entry
->i_secret_len
);
174 if (fprintf(p_file
, "}:%s\n", psz_b64
) < 0)
184 if (i_ret
!= VLC_SUCCESS
)
187 vlc_unlink(p_sys
->psz_file
);
193 file_read(vlc_keystore
*p_keystore
, FILE *p_file
, int i_fd
, struct ks_list
*p_list
)
195 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
196 char *psz_line
= NULL
;
197 size_t i_line_len
= 0;
199 bool b_valid
= false;
201 while ((i_read
= getline(&psz_line
, &i_line_len
, p_file
)) != -1)
210 vlc_keystore_entry
*p_entry
= ks_list_new_entry(p_list
);
215 while (*p
!= '\0' && !b_end
)
218 char *p_key
, *p_value
;
222 i_len
= strcspn(p
, ":");
223 if (!i_len
|| p
[i_len
] == '\0')
228 i_key
= str2key(p_key
);
229 if (i_key
== -1 || i_key
>= KEY_MAX
)
234 i_len
= strcspn(p
, ",}");
235 if (!i_len
|| p
[i_len
] == '\0')
242 p_value
= vlc_b64_decode(p
); /* BASE 64 */
247 p_entry
->ppsz_values
[i_key
] = p_value
;
250 if (*p
== '\0' || *p
!= ':')
253 p_entry
->i_secret_len
= vlc_b64_decode_binary(&p_entry
->p_secret
, p
+ 1);
254 if (!p_entry
->p_secret
)
265 vlc_unlink(p_sys
->psz_file
);
270 #if (!defined(HAVE_FLOCK) && defined (HAVE_FCNTL) && defined (F_SETLKW))
272 posix_lock_fd(int fd
)
280 flags
= fcntl(fd
, F_GETFL
);
284 lock
.l_whence
= SEEK_SET
;
285 lock
.l_type
= (flags
& O_ACCMODE
) == O_RDONLY
? F_RDLCK
: F_WRLCK
;
287 return fcntl(fd
, F_SETLKW
, &lock
);
292 file_open(const char *psz_file
, const char *psz_mode
, FILE **pp_file
)
294 FILE *p_file
= vlc_fopen(psz_file
, psz_mode
);
298 int i_fd
= fileno(p_file
);
306 if (flock(i_fd
, LOCK_EX
) != 0)
311 #elif defined (HAVE_FCNTL) && defined (F_SETLKW)
312 if (posix_lock_fd(i_fd
) != 0)
323 file_close(FILE *p_file
)
329 Store(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
],
330 const uint8_t *p_secret
, size_t i_secret_len
, const char *psz_label
)
333 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
334 int i_ret
= VLC_EGENERIC
;
335 struct ks_list list
= { 0 };
337 int i_fd
= file_open(p_sys
->psz_file
, "r+", &p_file
);
341 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
344 vlc_keystore_entry
*p_entry
= ks_list_find_entry(&list
, ppsz_values
, NULL
);
347 vlc_keystore_release_entry(p_entry
);
350 p_entry
= ks_list_new_entry(&list
);
354 if (ks_values_copy((const char **)p_entry
->ppsz_values
, ppsz_values
))
358 if (p_sys
->b_crypted
)
360 struct crypt
*p_crypt
= &p_sys
->crypt
;
361 uint8_t *p_enc_secret
;
362 size_t i_enc_secret_len
=
363 p_crypt
->pf_encrypt(p_keystore
, p_crypt
->p_ctx
, p_secret
,
364 i_secret_len
, &p_enc_secret
);
365 if (i_enc_secret_len
== 0)
368 if (vlc_keystore_entry_set_secret(p_entry
, p_enc_secret
,
376 if (vlc_keystore_entry_set_secret(p_entry
, p_secret
, i_secret_len
))
381 i_ret
= file_save(p_keystore
, p_file
, i_fd
, &list
);
390 Find(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
],
391 vlc_keystore_entry
**pp_entries
)
393 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
394 struct ks_list list
= { 0 };
395 struct ks_list out_list
= { 0 };
397 int i_fd
= file_open(p_sys
->psz_file
, "r", &p_file
);
401 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
404 vlc_keystore_entry
*p_entry
;
405 unsigned i_index
= 0;
406 while ((p_entry
= ks_list_find_entry(&list
, ppsz_values
, &i_index
)))
408 vlc_keystore_entry
*p_out_entry
= ks_list_new_entry(&out_list
);
411 || ks_values_copy((const char **)p_out_entry
->ppsz_values
,
412 (const char *const*)p_entry
->ppsz_values
))
414 ks_list_free(&out_list
);
419 if (p_sys
->b_crypted
)
421 struct crypt
*p_crypt
= &p_sys
->crypt
;
422 uint8_t *p_dec_secret
;
423 size_t i_dec_secret_len
=
424 p_crypt
->pf_decrypt(p_keystore
, p_crypt
->p_ctx
, p_entry
->p_secret
,
425 p_entry
->i_secret_len
, &p_dec_secret
);
426 if (i_dec_secret_len
== 0)
428 ks_list_free(&out_list
);
432 free(p_entry
->p_secret
);
433 p_entry
->p_secret
= p_dec_secret
;
434 p_entry
->i_secret_len
= i_dec_secret_len
;
438 if (vlc_keystore_entry_set_secret(p_out_entry
, p_entry
->p_secret
,
439 p_entry
->i_secret_len
))
441 ks_list_free(&out_list
);
446 *pp_entries
= out_list
.p_entries
;
450 return out_list
.i_count
;
454 Remove(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
])
456 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
457 unsigned int i_count
= 0;
458 struct ks_list list
= { 0 };
460 int i_fd
= file_open(p_sys
->psz_file
, "r+", &p_file
);
464 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
467 vlc_keystore_entry
*p_entry
;
468 unsigned i_index
= 0;
469 while ((p_entry
= ks_list_find_entry(&list
, ppsz_values
, &i_index
)))
471 vlc_keystore_release_entry(p_entry
);
476 && file_save(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
486 Close(vlc_object_t
*p_this
)
488 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
489 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
491 free(p_sys
->psz_file
);
496 Open(vlc_object_t
*p_this
)
498 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
500 vlc_keystore_sys
*p_sys
= calloc(1, sizeof(vlc_keystore_sys
));
504 char *psz_file
= var_InheritString(p_this
, "keystore-file");
512 bool b_file_exists
= false;
513 if (vlc_stat(psz_file
, &stat
) != 0)
515 FILE *p_file
= vlc_fopen(psz_file
, "a+");
523 b_file_exists
= true;
532 p_sys
->psz_file
= psz_file
;
533 p_keystore
->p_sys
= p_sys
;
534 p_keystore
->pf_store
= Store
;
535 p_keystore
->pf_find
= Find
;
536 p_keystore
->pf_remove
= Remove
;
543 CloseCrypt(vlc_object_t
*p_this
)
545 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
546 struct crypt
*p_crypt
= &p_keystore
->p_sys
->crypt
;
548 if (p_crypt
->pf_clean
!= NULL
)
549 p_crypt
->pf_clean(p_keystore
, p_crypt
->p_ctx
);
555 OpenCrypt(vlc_object_t
*p_this
)
557 int i_ret
= Open(p_this
);
559 if (i_ret
!= VLC_SUCCESS
)
562 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
563 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
565 if (CryptInit(p_keystore
, &p_sys
->crypt
) != VLC_SUCCESS
)
570 assert(p_sys
->crypt
.pf_encrypt
!= NULL
&& p_sys
->crypt
.pf_decrypt
!= NULL
);
571 p_sys
->b_crypted
= true;
575 #endif /* CRYPTFILE */