1/* $NetBSD: sshbuf-io.c,v 1.2 2020/02/27 00:24:40 christos Exp $ */ 2/* $OpenBSD: sshbuf-io.c,v 1.2 2020/01/25 23:28:06 djm Exp $ */ 3/* 4 * Copyright (c) 2011 Damien Miller 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18#include "includes.h" 19__RCSID("$NetBSD: sshbuf-io.c,v 1.2 2020/02/27 00:24:40 christos Exp $"); 20 21#include <sys/types.h> 22#include <sys/stat.h> 23 24#include <errno.h> 25#include <fcntl.h> 26#include <unistd.h> 27#include <string.h> 28 29#include "ssherr.h" 30#include "sshbuf.h" 31#include "atomicio.h" 32 33/* Load a file from a fd into a buffer */ 34int 35sshbuf_load_fd(int fd, struct sshbuf **blobp) 36{ 37 u_char buf[4096]; 38 size_t len; 39 struct stat st; 40 int r; 41 struct sshbuf *blob; 42 43 *blobp = NULL; 44 45 if (fstat(fd, &st) == -1) 46 return SSH_ERR_SYSTEM_ERROR; 47 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 48 st.st_size > SSHBUF_SIZE_MAX) 49 return SSH_ERR_INVALID_FORMAT; 50 if ((blob = sshbuf_new()) == NULL) 51 return SSH_ERR_ALLOC_FAIL; 52 for (;;) { 53 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 54 if (errno == EPIPE) 55 break; 56 r = SSH_ERR_SYSTEM_ERROR; 57 goto out; 58 } 59 if ((r = sshbuf_put(blob, buf, len)) != 0) 60 goto out; 61 if (sshbuf_len(blob) > SSHBUF_SIZE_MAX) { 62 r = SSH_ERR_INVALID_FORMAT; 63 goto out; 64 } 65 } 66 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 67 st.st_size != (off_t)sshbuf_len(blob)) { 68 r = SSH_ERR_FILE_CHANGED; 69 goto out; 70 } 71 /* success */ 72 *blobp = blob; 73 blob = NULL; /* transferred */ 74 r = 0; 75 out: 76 explicit_bzero(buf, sizeof(buf)); 77 sshbuf_free(blob); 78 return r; 79} 80 81int 82sshbuf_load_file(const char *path, struct sshbuf **bufp) 83{ 84 int r, fd, oerrno; 85 86 *bufp = NULL; 87 if ((fd = open(path, O_RDONLY)) == -1) 88 return SSH_ERR_SYSTEM_ERROR; 89 if ((r = sshbuf_load_fd(fd, bufp)) != 0) 90 goto out; 91 /* success */ 92 r = 0; 93 out: 94 oerrno = errno; 95 close(fd); 96 if (r != 0) 97 errno = oerrno; 98 return r; 99} 100 101int 102sshbuf_write_file(const char *path, struct sshbuf *buf) 103{ 104 int fd, oerrno; 105 106 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 107 return SSH_ERR_SYSTEM_ERROR; 108 if (atomicio(vwrite, fd, sshbuf_mutable_ptr(buf), 109 sshbuf_len(buf)) != sshbuf_len(buf) || close(fd) != 0) { 110 oerrno = errno; 111 close(fd); 112 unlink(path); 113 errno = oerrno; 114 return SSH_ERR_SYSTEM_ERROR; 115 } 116 return 0; 117} 118 119