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_keystore.h>
38 #include <vlc_strings.h>
42 #include "file_crypt.h"
43 #include "list_util.h"
45 static int Open(vlc_object_t
*);
46 static void Close(vlc_object_t
*);
48 static int OpenCrypt(vlc_object_t
*);
49 static void CloseCrypt(vlc_object_t
*);
53 set_shortname(N_("File keystore (plaintext)"))
54 set_description(N_("Secrets are stored on a file without any encryption"))
55 set_category(CAT_ADVANCED
)
56 set_subcategory(SUBCAT_ADVANCED_MISC
)
57 set_callbacks(Open
, Close
)
58 add_savefile("keystore-file", NULL
, NULL
, NULL
)
60 set_capability("keystore", 0)
61 add_shortcut("file_plaintext")
64 set_shortname(N_("Crypt keystore"))
65 set_description(N_("Secrets are stored encrypted on a file"))
66 set_category(CAT_ADVANCED
)
67 set_subcategory(SUBCAT_ADVANCED_MISC
)
68 set_callbacks(OpenCrypt
, CloseCrypt
)
69 set_capability("keystore", 1)
70 add_shortcut("file_crypt")
74 struct vlc_keystore_sys
83 static const char *const ppsz_keys
[] = {
92 static_assert(sizeof(ppsz_keys
)/sizeof(*ppsz_keys
) == KEY_MAX
, "key mismatch");
95 str2key(const char *psz_key
)
97 for (unsigned int i
= 0; i
< KEY_MAX
; ++i
)
99 if (strcmp(ppsz_keys
[i
], psz_key
) == 0)
106 values_write(FILE *p_file
, const char *const ppsz_values
[KEY_MAX
])
108 for (unsigned int i
= 0; i
< KEY_MAX
; ++i
)
112 char *psz_b64
= vlc_b64_encode(ppsz_values
[i
]);
115 const char *psz_end_sep
= "";
116 for (unsigned int j
= i
+ 1; j
< KEY_MAX
; ++j
)
124 if (fprintf(p_file
, "%s:%s%s", ppsz_keys
[i
], psz_b64
, psz_end_sep
) < 0)
139 return ftruncate(i_fd
, 0) == 0 ? VLC_SUCCESS
: VLC_EGENERIC
;
141 return _chsize(i_fd
, 0) == 0 ? VLC_SUCCESS
: VLC_EGENERIC
;
145 /* a line is "{key1:VALUE1_B64,key2:VALUE2_B64}:PASSWORD_B64" */
147 file_save(vlc_keystore
*p_keystore
, FILE *p_file
, int i_fd
, struct ks_list
*p_list
)
149 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
150 int i_ret
= VLC_EGENERIC
;
155 vlc_unlink(p_sys
->psz_file
);
159 for (unsigned int i
= 0; i
< p_list
->i_count
; ++i
)
161 vlc_keystore_entry
*p_entry
= &p_list
->p_entries
[i
];
162 if (!p_entry
->p_secret
)
165 if (fprintf(p_file
, "{") < 0)
167 if (values_write(p_file
, (const char *const *) p_entry
->ppsz_values
))
169 char *psz_b64
= vlc_b64_encode_binary(p_entry
->p_secret
,
170 p_entry
->i_secret_len
);
173 if (fprintf(p_file
, "}:%s\n", psz_b64
) < 0)
183 if (i_ret
!= VLC_SUCCESS
)
186 vlc_unlink(p_sys
->psz_file
);
192 file_read(vlc_keystore
*p_keystore
, FILE *p_file
, int i_fd
, struct ks_list
*p_list
)
194 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
195 char *psz_line
= NULL
;
196 size_t i_line_len
= 0;
198 bool b_valid
= false;
200 while ((i_read
= getline(&psz_line
, &i_line_len
, p_file
)) != -1)
209 vlc_keystore_entry
*p_entry
= ks_list_new_entry(p_list
);
214 while (*p
!= '\0' && !b_end
)
217 char *p_key
, *p_value
;
221 i_len
= strcspn(p
, ":");
222 if (!i_len
|| p
[i_len
] == '\0')
227 i_key
= str2key(p_key
);
228 if (i_key
== -1 || i_key
>= KEY_MAX
)
233 i_len
= strcspn(p
, ",}");
234 if (!i_len
|| p
[i_len
] == '\0')
241 p_value
= vlc_b64_decode(p
); /* BASE 64 */
246 p_entry
->ppsz_values
[i_key
] = p_value
;
249 if (*p
== '\0' || *p
!= ':')
252 p_entry
->i_secret_len
= vlc_b64_decode_binary(&p_entry
->p_secret
, p
+ 1);
253 if (!p_entry
->p_secret
)
264 vlc_unlink(p_sys
->psz_file
);
269 #if (!defined(HAVE_FLOCK) && defined (HAVE_FCNTL) && defined (F_SETLKW))
271 posix_lock_fd(int fd
)
279 flags
= fcntl(fd
, F_GETFL
);
283 lock
.l_whence
= SEEK_SET
;
284 lock
.l_type
= (flags
& O_ACCMODE
) == O_RDONLY
? F_RDLCK
: F_WRLCK
;
286 return fcntl(fd
, F_SETLKW
, &lock
);
291 file_open(const char *psz_file
, const char *psz_mode
, FILE **pp_file
)
293 FILE *p_file
= vlc_fopen(psz_file
, psz_mode
);
297 int i_fd
= fileno(p_file
);
305 if (flock(i_fd
, LOCK_EX
) != 0)
310 #elif defined (HAVE_FCNTL) && defined (F_SETLKW)
311 if (posix_lock_fd(i_fd
) != 0)
322 file_close(FILE *p_file
)
328 Store(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
],
329 const uint8_t *p_secret
, size_t i_secret_len
, const char *psz_label
)
332 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
333 int i_ret
= VLC_EGENERIC
;
334 struct ks_list list
= { 0 };
336 int i_fd
= file_open(p_sys
->psz_file
, "r+", &p_file
);
340 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
343 vlc_keystore_entry
*p_entry
= ks_list_find_entry(&list
, ppsz_values
, NULL
);
346 vlc_keystore_release_entry(p_entry
);
349 p_entry
= ks_list_new_entry(&list
);
353 if (ks_values_copy((const char **)p_entry
->ppsz_values
, ppsz_values
))
357 if (p_sys
->b_crypted
)
359 struct crypt
*p_crypt
= &p_sys
->crypt
;
360 uint8_t *p_enc_secret
;
361 size_t i_enc_secret_len
=
362 p_crypt
->pf_encrypt(p_keystore
, p_crypt
->p_ctx
, p_secret
,
363 i_secret_len
, &p_enc_secret
);
364 if (i_enc_secret_len
== 0)
367 if (vlc_keystore_entry_set_secret(p_entry
, p_enc_secret
,
375 if (vlc_keystore_entry_set_secret(p_entry
, p_secret
, i_secret_len
))
380 i_ret
= file_save(p_keystore
, p_file
, i_fd
, &list
);
389 Find(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
],
390 vlc_keystore_entry
**pp_entries
)
392 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
393 struct ks_list list
= { 0 };
394 struct ks_list out_list
= { 0 };
396 int i_fd
= file_open(p_sys
->psz_file
, "r", &p_file
);
400 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
403 vlc_keystore_entry
*p_entry
;
404 unsigned i_index
= 0;
405 while ((p_entry
= ks_list_find_entry(&list
, ppsz_values
, &i_index
)))
407 vlc_keystore_entry
*p_out_entry
= ks_list_new_entry(&out_list
);
410 || ks_values_copy((const char **)p_out_entry
->ppsz_values
,
411 (const char *const*)p_entry
->ppsz_values
))
413 ks_list_free(&out_list
);
418 if (p_sys
->b_crypted
)
420 struct crypt
*p_crypt
= &p_sys
->crypt
;
421 uint8_t *p_dec_secret
;
422 size_t i_dec_secret_len
=
423 p_crypt
->pf_decrypt(p_keystore
, p_crypt
->p_ctx
, p_entry
->p_secret
,
424 p_entry
->i_secret_len
, &p_dec_secret
);
425 if (i_dec_secret_len
== 0)
427 ks_list_free(&out_list
);
431 free(p_entry
->p_secret
);
432 p_entry
->p_secret
= p_dec_secret
;
433 p_entry
->i_secret_len
= i_dec_secret_len
;
437 if (vlc_keystore_entry_set_secret(p_out_entry
, p_entry
->p_secret
,
438 p_entry
->i_secret_len
))
440 ks_list_free(&out_list
);
445 *pp_entries
= out_list
.p_entries
;
449 return out_list
.i_count
;
453 Remove(vlc_keystore
*p_keystore
, const char *const ppsz_values
[KEY_MAX
])
455 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
456 unsigned int i_count
= 0;
457 struct ks_list list
= { 0 };
459 int i_fd
= file_open(p_sys
->psz_file
, "r+", &p_file
);
463 if (file_read(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
466 vlc_keystore_entry
*p_entry
;
467 unsigned i_index
= 0;
468 while ((p_entry
= ks_list_find_entry(&list
, ppsz_values
, &i_index
)))
470 vlc_keystore_release_entry(p_entry
);
475 && file_save(p_keystore
, p_file
, i_fd
, &list
) != VLC_SUCCESS
)
485 Close(vlc_object_t
*p_this
)
487 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
488 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
490 free(p_sys
->psz_file
);
495 Open(vlc_object_t
*p_this
)
497 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
499 vlc_keystore_sys
*p_sys
= calloc(1, sizeof(vlc_keystore_sys
));
503 char *psz_file
= var_InheritString(p_this
, "keystore-file");
511 bool b_file_exists
= false;
512 if (vlc_stat(psz_file
, &stat
) != 0)
514 FILE *p_file
= vlc_fopen(psz_file
, "a+");
522 b_file_exists
= true;
531 p_sys
->psz_file
= psz_file
;
532 p_keystore
->p_sys
= p_sys
;
533 p_keystore
->pf_store
= Store
;
534 p_keystore
->pf_find
= Find
;
535 p_keystore
->pf_remove
= Remove
;
542 CloseCrypt(vlc_object_t
*p_this
)
544 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
545 struct crypt
*p_crypt
= &p_keystore
->p_sys
->crypt
;
547 if (p_crypt
->pf_clean
!= NULL
)
548 p_crypt
->pf_clean(p_keystore
, p_crypt
->p_ctx
);
554 OpenCrypt(vlc_object_t
*p_this
)
556 int i_ret
= Open(p_this
);
558 if (i_ret
!= VLC_SUCCESS
)
561 vlc_keystore
*p_keystore
= (vlc_keystore
*)p_this
;
562 vlc_keystore_sys
*p_sys
= p_keystore
->p_sys
;
564 if (CryptInit(p_keystore
, &p_sys
->crypt
) != VLC_SUCCESS
)
569 assert(p_sys
->crypt
.pf_encrypt
!= NULL
&& p_sys
->crypt
.pf_decrypt
!= NULL
);
570 p_sys
->b_crypted
= true;
574 #endif /* CRYPTFILE */