Mercurial > projects > pwm
view io.c @ 33:fa93d2ff9c62
Prevent potential division by zero
Add safeguard ensuring that there is at least one possible character to
generate passwords from in order to exclude the possibility of a division by
zero error in rand_uniform.
author | Guido Berhoerster <guido+pwm@berhoerster.name> |
---|---|
date | Tue, 30 Jul 2019 20:38:08 +0200 |
parents | ec01c579024a |
children | 131c35592054 |
line wrap: on
line source
/* * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "compat.h" #ifdef HAVE_ERR_H #include <err.h> #endif /* HAVE_ERR_H */ #include <errno.h> #include <setjmp.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include "io.h" #include "util.h" #include "pwm.h" static sigjmp_buf signal_env; static void signal_handler(int signal_no) { siglongjmp(signal_env, signal_no); } void io_trim_nl(char *s) { size_t len; len = strlen(s); if ((len > 0) && (s[len - 1] == '\n')) { s[len - 1] = '\0'; } } int io_gl_complete_nothing(WordCompletion *cpl, void *data, const char *line, int word_end) { return (0); } enum io_status io_get_char(const char *prompt, int *cp) { enum io_status retval = IO_OK; GetLine *gl = NULL; gl = new_GetLine(16, 0); if (gl== NULL) { err(1, "new_GetLine"); } gl_catch_blocked(gl); /* prompt with echo off */ gl_echo_mode(gl, 0); if ((*cp = gl_query_char(gl, prompt, '\0')) == EOF) { switch (gl_return_status(gl)) { case GLR_SIGNAL: retval = IO_SIGNAL; break; case GLR_ERROR: errx(1, "gl_get_line: %s", gl_error_message(gl, NULL, 0)); default: errx(1, "unknown error in gl_get_line"); } } /* erase prompt */ if (io_printf("\r%*s\r", (int)strlen(prompt), "") == IO_SIGNAL) { retval = IO_SIGNAL; } del_GetLine(gl); return (retval); } enum io_status io_get_line(GetLine *gl, const char *prompt, int with_history, const char *start_line, int start_pos, size_t buf_size, char *buf) { enum io_status retval = IO_OK; GetLine *gl_private = NULL; GlHistoryState state; char *line; if (gl == NULL) { gl = gl_private = new_GetLine(buf_size - 1, 0); if (gl_private == NULL) { err(1, "new_GetLine"); } gl_catch_blocked(gl_private); } gl_state_of_history(gl, &state); gl_toggle_history(gl, with_history); line = gl_get_line(gl, prompt, start_line, start_pos); if (line == NULL) { switch (gl_return_status(gl)) { case GLR_BLOCKED: break; case GLR_SIGNAL: retval = IO_SIGNAL; goto out; case GLR_EOF: retval = IO_EOF; goto out; case GLR_ERROR: errx(1, "gl_get_line: %s", gl_error_message(gl, NULL, 0)); default: errx(1, "unknown error in gl_get_line"); } } if (snprintf(buf, buf_size, "%s", line) >= (int)buf_size) { retval = IO_TRUNCATED; } out: if (gl != NULL) { gl_toggle_history(gl, state.enabled); } del_GetLine(gl_private); return (retval); } enum io_status io_get_password(const char *prompt, const char *confirm_prompt, size_t buf_size, char *buf) { enum io_status retval = IO_OK; GetLine *gl = NULL; size_t len; char *password_buf = NULL; char *confirm_buf = NULL; gl = new_GetLine(buf_size - 1, 0); if (gl == NULL) { err(1, "new_GetLine"); } /* disable default filename completion */ gl_customize_completion(gl, NULL, io_gl_complete_nothing); gl_echo_mode(gl, 0); password_buf = xmalloc(buf_size); if (io_get_line(gl, prompt, 0, NULL, 0, buf_size, password_buf) == IO_SIGNAL) { retval = IO_SIGNAL; goto out; } len = strlen(password_buf); /* strip trailing newline */ if ((len > 0) && (password_buf[len - 1] == '\n')) { password_buf[--len] = '\0'; } if (len == 0) { retval = IO_PASSWORD_EMPTY; goto out; } if (confirm_prompt != NULL) { if (io_printf("\n") == IO_SIGNAL) { retval = IO_SIGNAL; goto out; } /* confirm new password */ confirm_buf = xmalloc(buf_size); if (io_get_line(gl, confirm_prompt, 0, NULL, 0, buf_size, confirm_buf) == IO_SIGNAL) { retval = IO_SIGNAL; goto out; } len = strlen(confirm_buf); /* strip trailing newline */ if ((len > 0) && (confirm_buf[len - 1] == '\n')) { confirm_buf[--len] = '\0'; } if (strcmp(password_buf, confirm_buf) != 0) { retval = IO_PASSWORD_MISMATCH; goto out; } } strcpy(buf, password_buf); out: if (io_printf("\n") == IO_SIGNAL) { retval = IO_SIGNAL; goto out; } free(password_buf); free(confirm_buf); del_GetLine(gl); return (retval); } enum io_status io_dputs(int fd, const char *s) { struct sigaction action; struct sigaction oaction; int signal_no = 0; const char *p = s; size_t remaining; ssize_t n; /* install signal handlers */ action.sa_handler = signal_handler; action.sa_flags = 0; sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGINT); sigaddset(&action.sa_mask, SIGTERM); sigaddset(&action.sa_mask, SIGHUP); sigaddset(&action.sa_mask, SIGQUIT); if ((sigaction(SIGINT, &action, &oaction) != 0) || (sigaction(SIGTERM, &action, &oaction) != 0) || (sigaction(SIGHUP, &action, &oaction) != 0) || (sigaction(SIGQUIT, &action, &oaction) != 0)) { err(1, "sigaction"); } if ((signal_no = sigsetjmp(signal_env, 1)) != 0) { /* signal received, signal mask has been restored */ goto out; } remaining = strlen(s); while (remaining > 0) { pwm_unblock_signals(); n = write(fd, p, remaining); if ((n < (int)remaining) && (errno != EINTR)) { err(1, "write"); } pwm_block_signals(); remaining -= MAX(n, 0); p += MAX(n, 0); } out: /* restore signal handlers */ if ((sigaction(SIGINT, &oaction, NULL) != 0) || (sigaction(SIGTERM, &oaction, NULL) != 0) || (sigaction(SIGHUP, &oaction, NULL) != 0) || (sigaction(SIGQUIT, &oaction, NULL) != 0)) { err(1, "sigaction"); } return ((signal_no == 0) ? IO_OK : IO_SIGNAL); } enum io_status io_vdprintf(int fd, const char *fmt, va_list args) { enum io_status retval; char *buf; xvasprintf(&buf, fmt, args); retval = io_dputs(fd, buf); free(buf); return (retval); } enum io_status io_dprintf(int fd, const char *fmt, ...) { enum io_status retval; va_list args; va_start(args, fmt); retval = io_vdprintf(fd, fmt, args); va_end(args); return (retval); } enum io_status io_printf(const char *fmt, ...) { enum io_status retval; va_list args; va_start(args, fmt); retval = io_vdprintf(STDOUT_FILENO, fmt, args); va_end(args); return (retval); }