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 "includes.h" 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <unistd.h> 26 #include <string.h> 27 28 #include "ssherr.h" 29 #include "sshbuf.h" 30 #include "atomicio.h" 31 32 /* Load a file from a fd into a buffer */ 33 int 34 sshbuf_load_fd(int fd, struct sshbuf **blobp) 35 { 36 u_char buf[4096]; 37 size_t len; 38 struct stat st; 39 int r; 40 struct sshbuf *blob; 41 42 *blobp = NULL; 43 44 if (fstat(fd, &st) == -1) 45 return SSH_ERR_SYSTEM_ERROR; 46 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 47 st.st_size > SSHBUF_SIZE_MAX) 48 return SSH_ERR_INVALID_FORMAT; 49 if ((blob = sshbuf_new()) == NULL) 50 return SSH_ERR_ALLOC_FAIL; 51 for (;;) { 52 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 53 if (errno == EPIPE) 54 break; 55 r = SSH_ERR_SYSTEM_ERROR; 56 goto out; 57 } 58 if ((r = sshbuf_put(blob, buf, len)) != 0) 59 goto out; 60 if (sshbuf_len(blob) > SSHBUF_SIZE_MAX) { 61 r = SSH_ERR_INVALID_FORMAT; 62 goto out; 63 } 64 } 65 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 66 st.st_size != (off_t)sshbuf_len(blob)) { 67 r = SSH_ERR_FILE_CHANGED; 68 goto out; 69 } 70 /* success */ 71 *blobp = blob; 72 blob = NULL; /* transferred */ 73 r = 0; 74 out: 75 explicit_bzero(buf, sizeof(buf)); 76 sshbuf_free(blob); 77 return r; 78 } 79 80 int 81 sshbuf_load_file(const char *path, struct sshbuf **bufp) 82 { 83 int r, fd, oerrno; 84 85 *bufp = NULL; 86 if ((fd = open(path, O_RDONLY)) == -1) 87 return SSH_ERR_SYSTEM_ERROR; 88 if ((r = sshbuf_load_fd(fd, bufp)) != 0) 89 goto out; 90 /* success */ 91 r = 0; 92 out: 93 oerrno = errno; 94 close(fd); 95 if (r != 0) 96 errno = oerrno; 97 return r; 98 } 99 100 int 101 sshbuf_write_file(const char *path, struct sshbuf *buf) 102 { 103 int fd, oerrno; 104 105 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 106 return SSH_ERR_SYSTEM_ERROR; 107 if (atomicio(vwrite, fd, sshbuf_mutable_ptr(buf), 108 sshbuf_len(buf)) != sshbuf_len(buf) || close(fd) != 0) { 109 oerrno = errno; 110 close(fd); 111 unlink(path); 112 errno = oerrno; 113 return SSH_ERR_SYSTEM_ERROR; 114 } 115 return 0; 116 } 117 118