1*ed75d7a8Schristos /* $NetBSD: sshbuf-io.c,v 1.2 2020/02/27 00:24:40 christos Exp $ */
218504831Schristos /* $OpenBSD: sshbuf-io.c,v 1.2 2020/01/25 23:28:06 djm Exp $ */
318504831Schristos /*
418504831Schristos * Copyright (c) 2011 Damien Miller
518504831Schristos *
618504831Schristos * Permission to use, copy, modify, and distribute this software for any
718504831Schristos * purpose with or without fee is hereby granted, provided that the above
818504831Schristos * copyright notice and this permission notice appear in all copies.
918504831Schristos *
1018504831Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1118504831Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1218504831Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1318504831Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1418504831Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1518504831Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1618504831Schristos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1718504831Schristos */
18*ed75d7a8Schristos #include "includes.h"
19*ed75d7a8Schristos __RCSID("$NetBSD: sshbuf-io.c,v 1.2 2020/02/27 00:24:40 christos Exp $");
2018504831Schristos
2118504831Schristos #include <sys/types.h>
2218504831Schristos #include <sys/stat.h>
2318504831Schristos
2418504831Schristos #include <errno.h>
2518504831Schristos #include <fcntl.h>
2618504831Schristos #include <unistd.h>
2718504831Schristos #include <string.h>
2818504831Schristos
2918504831Schristos #include "ssherr.h"
3018504831Schristos #include "sshbuf.h"
3118504831Schristos #include "atomicio.h"
3218504831Schristos
3318504831Schristos /* Load a file from a fd into a buffer */
3418504831Schristos int
sshbuf_load_fd(int fd,struct sshbuf ** blobp)3518504831Schristos sshbuf_load_fd(int fd, struct sshbuf **blobp)
3618504831Schristos {
3718504831Schristos u_char buf[4096];
3818504831Schristos size_t len;
3918504831Schristos struct stat st;
4018504831Schristos int r;
4118504831Schristos struct sshbuf *blob;
4218504831Schristos
4318504831Schristos *blobp = NULL;
4418504831Schristos
4518504831Schristos if (fstat(fd, &st) == -1)
4618504831Schristos return SSH_ERR_SYSTEM_ERROR;
4718504831Schristos if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
4818504831Schristos st.st_size > SSHBUF_SIZE_MAX)
4918504831Schristos return SSH_ERR_INVALID_FORMAT;
5018504831Schristos if ((blob = sshbuf_new()) == NULL)
5118504831Schristos return SSH_ERR_ALLOC_FAIL;
5218504831Schristos for (;;) {
5318504831Schristos if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
5418504831Schristos if (errno == EPIPE)
5518504831Schristos break;
5618504831Schristos r = SSH_ERR_SYSTEM_ERROR;
5718504831Schristos goto out;
5818504831Schristos }
5918504831Schristos if ((r = sshbuf_put(blob, buf, len)) != 0)
6018504831Schristos goto out;
6118504831Schristos if (sshbuf_len(blob) > SSHBUF_SIZE_MAX) {
6218504831Schristos r = SSH_ERR_INVALID_FORMAT;
6318504831Schristos goto out;
6418504831Schristos }
6518504831Schristos }
6618504831Schristos if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
6718504831Schristos st.st_size != (off_t)sshbuf_len(blob)) {
6818504831Schristos r = SSH_ERR_FILE_CHANGED;
6918504831Schristos goto out;
7018504831Schristos }
7118504831Schristos /* success */
7218504831Schristos *blobp = blob;
7318504831Schristos blob = NULL; /* transferred */
7418504831Schristos r = 0;
7518504831Schristos out:
7618504831Schristos explicit_bzero(buf, sizeof(buf));
7718504831Schristos sshbuf_free(blob);
7818504831Schristos return r;
7918504831Schristos }
8018504831Schristos
8118504831Schristos int
sshbuf_load_file(const char * path,struct sshbuf ** bufp)8218504831Schristos sshbuf_load_file(const char *path, struct sshbuf **bufp)
8318504831Schristos {
8418504831Schristos int r, fd, oerrno;
8518504831Schristos
8618504831Schristos *bufp = NULL;
8718504831Schristos if ((fd = open(path, O_RDONLY)) == -1)
8818504831Schristos return SSH_ERR_SYSTEM_ERROR;
8918504831Schristos if ((r = sshbuf_load_fd(fd, bufp)) != 0)
9018504831Schristos goto out;
9118504831Schristos /* success */
9218504831Schristos r = 0;
9318504831Schristos out:
9418504831Schristos oerrno = errno;
9518504831Schristos close(fd);
9618504831Schristos if (r != 0)
9718504831Schristos errno = oerrno;
9818504831Schristos return r;
9918504831Schristos }
10018504831Schristos
10118504831Schristos int
sshbuf_write_file(const char * path,struct sshbuf * buf)10218504831Schristos sshbuf_write_file(const char *path, struct sshbuf *buf)
10318504831Schristos {
10418504831Schristos int fd, oerrno;
10518504831Schristos
10618504831Schristos if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
10718504831Schristos return SSH_ERR_SYSTEM_ERROR;
10818504831Schristos if (atomicio(vwrite, fd, sshbuf_mutable_ptr(buf),
10918504831Schristos sshbuf_len(buf)) != sshbuf_len(buf) || close(fd) != 0) {
11018504831Schristos oerrno = errno;
11118504831Schristos close(fd);
11218504831Schristos unlink(path);
11318504831Schristos errno = oerrno;
11418504831Schristos return SSH_ERR_SYSTEM_ERROR;
11518504831Schristos }
11618504831Schristos return 0;
11718504831Schristos }
11818504831Schristos
119