xref: /openbsd-src/usr.bin/ssh/sshbuf-io.c (revision bb3c2609a8abc788209e2d9e3b3a967b1bfc9f3b)
1*bb3c2609Sdjm /*	$OpenBSD: sshbuf-io.c,v 1.2 2020/01/25 23:28:06 djm Exp $ */
262af2284Sdjm /*
362af2284Sdjm  * Copyright (c) 2011 Damien Miller
462af2284Sdjm  *
562af2284Sdjm  * Permission to use, copy, modify, and distribute this software for any
662af2284Sdjm  * purpose with or without fee is hereby granted, provided that the above
762af2284Sdjm  * copyright notice and this permission notice appear in all copies.
862af2284Sdjm  *
962af2284Sdjm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062af2284Sdjm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1162af2284Sdjm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1262af2284Sdjm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1362af2284Sdjm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1462af2284Sdjm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1562af2284Sdjm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1662af2284Sdjm  */
1762af2284Sdjm 
1862af2284Sdjm #include <sys/types.h>
1962af2284Sdjm #include <sys/stat.h>
2062af2284Sdjm 
2162af2284Sdjm #include <errno.h>
2262af2284Sdjm #include <fcntl.h>
2362af2284Sdjm #include <unistd.h>
2462af2284Sdjm #include <string.h>
2562af2284Sdjm 
2662af2284Sdjm #include "ssherr.h"
2762af2284Sdjm #include "sshbuf.h"
2862af2284Sdjm #include "atomicio.h"
2962af2284Sdjm 
3062af2284Sdjm /* Load a file from a fd into a buffer */
3162af2284Sdjm int
sshbuf_load_fd(int fd,struct sshbuf ** blobp)3262af2284Sdjm sshbuf_load_fd(int fd, struct sshbuf **blobp)
3362af2284Sdjm {
3462af2284Sdjm 	u_char buf[4096];
3562af2284Sdjm 	size_t len;
3662af2284Sdjm 	struct stat st;
3762af2284Sdjm 	int r;
3862af2284Sdjm 	struct sshbuf *blob;
3962af2284Sdjm 
4062af2284Sdjm 	*blobp = NULL;
4162af2284Sdjm 
4262af2284Sdjm 	if (fstat(fd, &st) == -1)
4362af2284Sdjm 		return SSH_ERR_SYSTEM_ERROR;
4462af2284Sdjm 	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
4562af2284Sdjm 	    st.st_size > SSHBUF_SIZE_MAX)
4662af2284Sdjm 		return SSH_ERR_INVALID_FORMAT;
4762af2284Sdjm 	if ((blob = sshbuf_new()) == NULL)
4862af2284Sdjm 		return SSH_ERR_ALLOC_FAIL;
4962af2284Sdjm 	for (;;) {
5062af2284Sdjm 		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
5162af2284Sdjm 			if (errno == EPIPE)
5262af2284Sdjm 				break;
5362af2284Sdjm 			r = SSH_ERR_SYSTEM_ERROR;
5462af2284Sdjm 			goto out;
5562af2284Sdjm 		}
5662af2284Sdjm 		if ((r = sshbuf_put(blob, buf, len)) != 0)
5762af2284Sdjm 			goto out;
5862af2284Sdjm 		if (sshbuf_len(blob) > SSHBUF_SIZE_MAX) {
5962af2284Sdjm 			r = SSH_ERR_INVALID_FORMAT;
6062af2284Sdjm 			goto out;
6162af2284Sdjm 		}
6262af2284Sdjm 	}
6362af2284Sdjm 	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
6462af2284Sdjm 	    st.st_size != (off_t)sshbuf_len(blob)) {
6562af2284Sdjm 		r = SSH_ERR_FILE_CHANGED;
6662af2284Sdjm 		goto out;
6762af2284Sdjm 	}
6862af2284Sdjm 	/* success */
6962af2284Sdjm 	*blobp = blob;
7062af2284Sdjm 	blob = NULL; /* transferred */
7162af2284Sdjm 	r = 0;
7262af2284Sdjm  out:
7362af2284Sdjm 	explicit_bzero(buf, sizeof(buf));
7462af2284Sdjm 	sshbuf_free(blob);
7562af2284Sdjm 	return r;
7662af2284Sdjm }
7762af2284Sdjm 
7862af2284Sdjm int
sshbuf_load_file(const char * path,struct sshbuf ** bufp)7962af2284Sdjm sshbuf_load_file(const char *path, struct sshbuf **bufp)
8062af2284Sdjm {
8162af2284Sdjm 	int r, fd, oerrno;
8262af2284Sdjm 
8362af2284Sdjm 	*bufp = NULL;
8462af2284Sdjm 	if ((fd = open(path, O_RDONLY)) == -1)
8562af2284Sdjm 		return SSH_ERR_SYSTEM_ERROR;
8662af2284Sdjm 	if ((r = sshbuf_load_fd(fd, bufp)) != 0)
8762af2284Sdjm 		goto out;
8862af2284Sdjm 	/* success */
8962af2284Sdjm 	r = 0;
9062af2284Sdjm  out:
9162af2284Sdjm 	oerrno = errno;
9262af2284Sdjm 	close(fd);
9362af2284Sdjm 	if (r != 0)
9462af2284Sdjm 		errno = oerrno;
9562af2284Sdjm 	return r;
9662af2284Sdjm }
9762af2284Sdjm 
9862af2284Sdjm int
sshbuf_write_file(const char * path,struct sshbuf * buf)9962af2284Sdjm sshbuf_write_file(const char *path, struct sshbuf *buf)
10062af2284Sdjm {
10162af2284Sdjm 	int fd, oerrno;
10262af2284Sdjm 
10362af2284Sdjm 	if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
10462af2284Sdjm 		return SSH_ERR_SYSTEM_ERROR;
10562af2284Sdjm 	if (atomicio(vwrite, fd, sshbuf_mutable_ptr(buf),
10662af2284Sdjm 	    sshbuf_len(buf)) != sshbuf_len(buf) || close(fd) != 0) {
10762af2284Sdjm 		oerrno = errno;
10862af2284Sdjm 		close(fd);
10962af2284Sdjm 		unlink(path);
11062af2284Sdjm 		errno = oerrno;
11162af2284Sdjm 		return SSH_ERR_SYSTEM_ERROR;
11262af2284Sdjm 	}
11362af2284Sdjm 	return 0;
11462af2284Sdjm }
11562af2284Sdjm 
116