common.c (2729B)
- // SPDX-FileCopyrightText: 2022 Haelwenn (lanodan) Monnier <contact+skeud@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 202405L
- // for explicit_bzero
- #define _DEFAULT_SOURCE
- #include "common.h"
- #include <errno.h> // errno
- #include <stdio.h> // fclose, fopen, fprintf, perror, getline, fileno
- #include <string.h> // explicit_bzero
- #include <termios.h> // tcgetattr, tcsetattr
- #include <unistd.h> // crypt
- #undef MIN
- #define MIN(a, b) (((a) < (b)) ? (a) : (b))
- // doesn't exits to make sure cleanup is done
- int
- skeud_err(const char *errmsg, int err)
- {
- fputs(argv0, stderr);
- fputs(": error: ", stderr);
- fputs(errmsg, stderr);
- if(err != 0)
- {
- fputs(": ", stderr);
- fputs(strerror(err), stderr);
- }
- fputs("\n", stderr);
- return fflush(stderr);
- }
- // Needs to be constant-time
- bool
- hash_match(const char *a, size_t alen, const char *b, size_t blen)
- {
- size_t n = MIN(alen, blen);
- bool ret = true;
- for(size_t i = 0; i < n; i++)
- if(a[i] != b[i]) ret = false;
- if(alen != blen)
- return false;
- else
- return ret;
- }
- bool
- skeud_crypt_check(const char *hash, const char *password)
- {
- size_t hashlen = strlen0(hash);
- if(hashlen == 0) return false;
- /* flawfinder: ignore CWE-327, crypt is the only relevant function */
- char *chk_hash = crypt(password, hash);
- if(chk_hash == NULL)
- {
- skeud_err("Failed hashing password", errno);
- return false;
- }
- bool match = hash_match(hash, hashlen, chk_hash, strlen(chk_hash));
- // cleanup
- chk_hash = crypt("", hash);
- return match;
- }
- ssize_t
- skeud_getpass(char **password)
- {
- struct termios t;
- size_t len = 0;
- ssize_t got = -1;
- /* flawfinder: ignore CWE-362 */
- FILE *tty = fopen("/dev/tty", "rb+");
- if(tty == NULL)
- {
- skeud_err("Failed opening '/dev/tty'", errno);
- return got;
- }
- int tty_fd = fileno(tty);
- if(tty_fd < 0)
- {
- skeud_err("Failed getting fd from '/dev/tty' stream", errno);
- goto getpass_end;
- }
- if(tcgetattr(tty_fd, &t) < 0)
- {
- skeud_err("Failed getting terminal attributes", errno);
- goto getpass_end;
- }
- const char *prompt = "Password: ";
- write(tty_fd, prompt, strlen(prompt));
- t.c_lflag &= ~ECHO;
- if(tcsetattr(tty_fd, TCSANOW, &t) < 0)
- {
- skeud_err("Failed disabling terminal echo", errno);
- goto getpass_end;
- }
- errno = 0;
- got = getline(password, &len, tty);
- if(got < 0)
- {
- if(errno != 0) skeud_err("Failed reading line", errno);
- goto getpass_clean;
- }
- fputs("\n", tty);
- (*password)[got] = 0;
- (*password)[got - 1] = 0;
- got--;
- getpass_clean:
- t.c_lflag ^= ECHO;
- if(tcsetattr(tty_fd, TCSANOW, &t) < 0)
- {
- skeud_err("Failed re-enabling terminal echo", errno);
- explicit_bzero(password, got);
- got = -1;
- goto getpass_end;
- }
- getpass_end:
- fclose(tty);
- return got;
- }