File: sec.c

package info (click to toggle)
lcsync 0.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,152 kB
  • sloc: ansic: 9,376; sh: 3,117; makefile: 246
file content (86 lines) | stat: -rw-r--r-- 2,367 bytes parent folder | download
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);
}