1 /* $OpenBSD: sshbuf-io.c,v 1.4 2026/07/05 00:16:21 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 (S_ISREG(st.st_mode) && st.st_size > SSHBUF_SIZE_MAX) 47 return SSH_ERR_INVALID_FORMAT; 48 if ((blob = sshbuf_new()) == NULL) 49 return SSH_ERR_ALLOC_FAIL; 50 for (;;) { 51 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 52 if (errno == EPIPE) 53 break; 54 r = SSH_ERR_SYSTEM_ERROR; 55 goto out; 56 } 57 if ((r = sshbuf_put(blob, buf, len)) != 0) 58 goto out; 59 if (sshbuf_len(blob) > SSHBUF_SIZE_MAX) { 60 r = SSH_ERR_INVALID_FORMAT; 61 goto out; 62 } 63 } 64 if (S_ISREG(st.st_mode) != 0 && 65 st.st_size != (off_t)sshbuf_len(blob)) { 66 r = SSH_ERR_FILE_CHANGED; 67 goto out; 68 } 69 /* success */ 70 *blobp = blob; 71 blob = NULL; /* transferred */ 72 r = 0; 73 out: 74 explicit_bzero(buf, sizeof(buf)); 75 sshbuf_free(blob); 76 return r; 77 } 78 79 int 80 sshbuf_load_file(const char *path, struct sshbuf **bufp) 81 { 82 int r, fd, oerrno; 83 84 *bufp = NULL; 85 if ((fd = open(path, O_RDONLY)) == -1) 86 return SSH_ERR_SYSTEM_ERROR; 87 if ((r = sshbuf_load_fd(fd, bufp)) != 0) 88 goto out; 89 /* success */ 90 r = 0; 91 out: 92 oerrno = errno; 93 close(fd); 94 if (r != 0) 95 errno = oerrno; 96 return r; 97 } 98 99 int 100 sshbuf_write_file(const char *path, struct sshbuf *buf) 101 { 102 int fd, oerrno; 103 104 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 105 return SSH_ERR_SYSTEM_ERROR; 106 if (atomicio(vwrite, fd, sshbuf_mutable_ptr(buf), 107 sshbuf_len(buf)) != sshbuf_len(buf) || close(fd) != 0) { 108 oerrno = errno; 109 close(fd); 110 unlink(path); 111 errno = oerrno; 112 return SSH_ERR_SYSTEM_ERROR; 113 } 114 return 0; 115 } 116 117