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