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