1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2023 Brett Sheffield <bacs@librecast.net> */
#include "globals.h"
#include "log.h"
#include "sec.h"
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int sec_drop_privs(void)
{
gid_t newgid = getgid();
setgroups(1, &newgid);
return setuid(getuid());
}
int sec_derive_symm_key(char *password)
{
if (!password) return (errno = EINVAL), -1;
size_t len = strlen(password) - 1;
unsigned char salt[crypto_pwhash_SALTBYTES];
password[len] = '\0'; /* chop newline */
if (!len) return (errno = ECANCELED), -1;
/* hash password to use as salt */
crypto_generichash(salt, sizeof salt, (unsigned char *)password, len, NULL, 0);
sodium_mlock(secretkey, sizeof secretkey);
if (crypto_pwhash(secretkey, sizeof secretkey, password, len, salt,
crypto_pwhash_OPSLIMIT_INTERACTIVE,
crypto_pwhash_MEMLIMIT_INTERACTIVE,
crypto_pwhash_ALG_DEFAULT) != 0)
return (errno = ENOMEM), -1;
return 0;
}
char *sec_getpassword(void)
{
static struct termios old, new;
password = malloc(PASSWORD_MAX);
if (!password) return NULL;
/* disable terminal echo */
tcgetattr(STDIN_FILENO, &old);
new = old;
new.c_lflag &= ~(ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new);
/* prompt for password */
printf("Enter password (will be used to derive a symmetric key): ");
sodium_mlock(password, PASSWORD_MAX);
if (!fgets(password, PASSWORD_MAX, stdin))
return (errno = ECANCELED), NULL;
/* restore terminal settings */
tcsetattr(STDIN_FILENO, TCSANOW, &old);
putchar('\n');
return password;
}
int sec_read_symm_keyfile(const char *pathname)
{
ssize_t rc;
int fd;
fd = open(pathname, O_RDONLY);
if (fd == -1) {
ERROR("Unable to open keyfile '%s'\n", pathname);
return -1;
}
sodium_mlock(secretkey, sizeof secretkey);
rc = read(fd, secretkey, sizeof secretkey);
if (rc == -1) perror("Error reading keyfile");
close(fd);
if (rc != -1 && rc != sizeof secretkey) {
ERROR("Invalid keyfile (too short). Key must contain %zu bytes\n", sizeof secretkey);
return (errno = EKEYREJECTED), -1;
}
return 0;
}
int sec_get_symm_key(void)
{
if (keyfile) return sec_read_symm_keyfile(keyfile);
password = getenv("LCSYNC_PASSWORD");
if (!password) password = sec_getpassword();
return sec_derive_symm_key(password);
}
|