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