xref: /netbsd/usr.sbin/puffs/mount_psshfs/psbuf.c (revision 808903e4)
1*808903e4Schristos /*      $NetBSD: psbuf.c,v 1.19 2012/11/04 22:46:08 christos Exp $        */
2c3ef8ea5Spooka 
3c3ef8ea5Spooka /*
4dac06153Spooka  * Copyright (c) 2006-2009  Antti Kantee.  All Rights Reserved.
5c3ef8ea5Spooka  *
6c3ef8ea5Spooka  * Redistribution and use in source and binary forms, with or without
7c3ef8ea5Spooka  * modification, are permitted provided that the following conditions
8c3ef8ea5Spooka  * are met:
9c3ef8ea5Spooka  * 1. Redistributions of source code must retain the above copyright
10c3ef8ea5Spooka  *    notice, this list of conditions and the following disclaimer.
11c3ef8ea5Spooka  * 2. Redistributions in binary form must reproduce the above copyright
12c3ef8ea5Spooka  *    notice, this list of conditions and the following disclaimer in the
13c3ef8ea5Spooka  *    documentation and/or other materials provided with the distribution.
14c3ef8ea5Spooka  *
15c3ef8ea5Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16c3ef8ea5Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17c3ef8ea5Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18c3ef8ea5Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c3ef8ea5Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c3ef8ea5Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21c3ef8ea5Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c3ef8ea5Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c3ef8ea5Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c3ef8ea5Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c3ef8ea5Spooka  * SUCH DAMAGE.
26c3ef8ea5Spooka  */
27c3ef8ea5Spooka 
28c3ef8ea5Spooka #include <sys/cdefs.h>
29c3ef8ea5Spooka #ifndef lint
30*808903e4Schristos __RCSID("$NetBSD: psbuf.c,v 1.19 2012/11/04 22:46:08 christos Exp $");
31c3ef8ea5Spooka #endif /* !lint */
32c3ef8ea5Spooka 
33c3ef8ea5Spooka /*
34c3ef8ea5Spooka  * buffering functions for network input/output.  slightly different
35c3ef8ea5Spooka  * from the average joe buffer routines, as is usually the case ...
36c3ef8ea5Spooka  * these use efuns for now.
37c3ef8ea5Spooka  */
38c3ef8ea5Spooka 
39c3ef8ea5Spooka #include <sys/types.h>
40c3ef8ea5Spooka #include <sys/time.h>
41c3ef8ea5Spooka #include <sys/vnode.h>
42*808903e4Schristos #include <sys/socket.h>
43c3ef8ea5Spooka 
44c3ef8ea5Spooka #include <err.h>
45c3ef8ea5Spooka #include <errno.h>
46c3ef8ea5Spooka #include <stdlib.h>
47c3ef8ea5Spooka #include <util.h>
48c3ef8ea5Spooka #include <unistd.h>
49c3ef8ea5Spooka 
50c3ef8ea5Spooka #include "psshfs.h"
51c3ef8ea5Spooka #include "sftp_proto.h"
52c3ef8ea5Spooka 
530e7bdfc1Spooka #define FAILRV(x) do { int rv; if ((rv=x)) return (rv); } while (/*CONSTCOND*/0)
540e7bdfc1Spooka #define READSTATE_LENGTH(off) (off < 4)
55c3ef8ea5Spooka 
560e7bdfc1Spooka #define SFTP_LENOFF	0
570e7bdfc1Spooka #define SFTP_TYPEOFF	4
580e7bdfc1Spooka #define SFTP_REQIDOFF	5
590e7bdfc1Spooka 
600e7bdfc1Spooka #define CHECK(v) if (!(v)) abort()
610e7bdfc1Spooka 
620e7bdfc1Spooka uint8_t
psbuf_get_type(struct puffs_framebuf * pb)630e7bdfc1Spooka psbuf_get_type(struct puffs_framebuf *pb)
64c3ef8ea5Spooka {
650e7bdfc1Spooka 	uint8_t type;
660e7bdfc1Spooka 
670e7bdfc1Spooka 	puffs_framebuf_getdata_atoff(pb, SFTP_TYPEOFF, &type, 1);
680e7bdfc1Spooka 	return type;
690e7bdfc1Spooka }
700e7bdfc1Spooka 
710e7bdfc1Spooka uint32_t
psbuf_get_len(struct puffs_framebuf * pb)720e7bdfc1Spooka psbuf_get_len(struct puffs_framebuf *pb)
730e7bdfc1Spooka {
740e7bdfc1Spooka 	uint32_t len;
750e7bdfc1Spooka 
760e7bdfc1Spooka 	puffs_framebuf_getdata_atoff(pb, SFTP_LENOFF, &len, 4);
770e7bdfc1Spooka 	return be32toh(len);
780e7bdfc1Spooka }
790e7bdfc1Spooka 
800e7bdfc1Spooka uint32_t
psbuf_get_reqid(struct puffs_framebuf * pb)810e7bdfc1Spooka psbuf_get_reqid(struct puffs_framebuf *pb)
820e7bdfc1Spooka {
830e7bdfc1Spooka 	uint32_t req;
840e7bdfc1Spooka 
850e7bdfc1Spooka 	puffs_framebuf_getdata_atoff(pb, SFTP_REQIDOFF, &req, 4);
860e7bdfc1Spooka 	return be32toh(req);
870e7bdfc1Spooka }
880e7bdfc1Spooka 
890e7bdfc1Spooka #define CUROFF(pb) (puffs_framebuf_telloff(pb))
900e7bdfc1Spooka int
psbuf_read(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)910e7bdfc1Spooka psbuf_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
920e7bdfc1Spooka 	int fd, int *done)
930e7bdfc1Spooka {
940e7bdfc1Spooka 	void *win;
95c3ef8ea5Spooka 	ssize_t n;
960e7bdfc1Spooka 	size_t howmuch, winlen;
970e7bdfc1Spooka 	int lenstate;
98c3ef8ea5Spooka 
990e7bdfc1Spooka  the_next_level:
1000e7bdfc1Spooka 	if ((lenstate = READSTATE_LENGTH(CUROFF(pb))))
1010e7bdfc1Spooka 		howmuch = 4 - CUROFF(pb);
1020e7bdfc1Spooka 	else
1030e7bdfc1Spooka 		howmuch = psbuf_get_len(pb) - (CUROFF(pb) - 4);
104c3ef8ea5Spooka 
1050e7bdfc1Spooka 	if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
1060e7bdfc1Spooka 		return errno;
1070e7bdfc1Spooka 
1080e7bdfc1Spooka 	while (howmuch) {
1090e7bdfc1Spooka 		winlen = howmuch;
1100e7bdfc1Spooka 		if (puffs_framebuf_getwindow(pb, CUROFF(pb), &win, &winlen)==-1)
1110e7bdfc1Spooka 			return errno;
112f423bfeeSpooka 		n = recv(fd, win, winlen, MSG_NOSIGNAL);
113c3ef8ea5Spooka 		switch (n) {
114c3ef8ea5Spooka 		case 0:
1150e7bdfc1Spooka 			return ECONNRESET;
116c3ef8ea5Spooka 		case -1:
117c3ef8ea5Spooka 			if (errno == EAGAIN)
118c3ef8ea5Spooka 				return 0;
1190e7bdfc1Spooka 			return errno;
120c3ef8ea5Spooka 		default:
1210e7bdfc1Spooka 			howmuch -= n;
1220e7bdfc1Spooka 			puffs_framebuf_seekset(pb, CUROFF(pb) + n);
1230e7bdfc1Spooka 			break;
1240e7bdfc1Spooka 		}
125c3ef8ea5Spooka 	}
126c3ef8ea5Spooka 
1270e7bdfc1Spooka 	if (!lenstate) {
1280e7bdfc1Spooka 		/* XXX: initial exchange shorter.. but don't worry, be happy */
1290e7bdfc1Spooka 		puffs_framebuf_seekset(pb, 9);
1300e7bdfc1Spooka 		*done = 1;
131c3ef8ea5Spooka 		return 0;
1320e7bdfc1Spooka 	} else
1330e7bdfc1Spooka 		goto the_next_level;
134c3ef8ea5Spooka }
135c3ef8ea5Spooka 
136c3ef8ea5Spooka int
psbuf_write(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)1370e7bdfc1Spooka psbuf_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
1380e7bdfc1Spooka 	int fd, int *done)
139c3ef8ea5Spooka {
1400e7bdfc1Spooka 	void *win;
141c3ef8ea5Spooka 	ssize_t n;
1420e7bdfc1Spooka 	size_t winlen, howmuch;
143c3ef8ea5Spooka 
1440e7bdfc1Spooka 	/* finalize buffer.. could be elsewhere ... */
1450e7bdfc1Spooka 	if (CUROFF(pb) == 0) {
146c3ef8ea5Spooka 		uint32_t len;
147c3ef8ea5Spooka 
1480e7bdfc1Spooka 		len = htobe32(puffs_framebuf_tellsize(pb) - 4);
1490e7bdfc1Spooka 		puffs_framebuf_putdata_atoff(pb, 0, &len, 4);
150c3ef8ea5Spooka 	}
151c3ef8ea5Spooka 
1520e7bdfc1Spooka 	howmuch = puffs_framebuf_tellsize(pb) - CUROFF(pb);
1530e7bdfc1Spooka 	while (howmuch) {
1540e7bdfc1Spooka 		winlen = howmuch;
1550e7bdfc1Spooka 		if (puffs_framebuf_getwindow(pb, CUROFF(pb), &win, &winlen)==-1)
1560e7bdfc1Spooka 			return errno;
157e3468dbcSpooka 		n = send(fd, win, winlen, MSG_NOSIGNAL);
1580e7bdfc1Spooka 		switch (n) {
1590e7bdfc1Spooka 		case 0:
1600e7bdfc1Spooka 			return ECONNRESET;
1610e7bdfc1Spooka 		case -1:
162c3ef8ea5Spooka 			if (errno == EAGAIN)
163c3ef8ea5Spooka 				return 0;
1640e7bdfc1Spooka 			return errno;
1650e7bdfc1Spooka 		default:
1660e7bdfc1Spooka 			howmuch -= n;
1670e7bdfc1Spooka 			puffs_framebuf_seekset(pb, CUROFF(pb) + n);
1680e7bdfc1Spooka 			break;
1690e7bdfc1Spooka 		}
170c3ef8ea5Spooka 	}
171c3ef8ea5Spooka 
1720e7bdfc1Spooka 	*done = 1;
173c3ef8ea5Spooka 	return 0;
174c3ef8ea5Spooka }
1750e7bdfc1Spooka #undef CUROFF
176c3ef8ea5Spooka 
1770e7bdfc1Spooka int
psbuf_cmp(struct puffs_usermount * pu,struct puffs_framebuf * cmp1,struct puffs_framebuf * cmp2,int * notresp)1780e7bdfc1Spooka psbuf_cmp(struct puffs_usermount *pu,
17908386a8cSpooka 	struct puffs_framebuf *cmp1, struct puffs_framebuf *cmp2, int *notresp)
180c3ef8ea5Spooka {
181c3ef8ea5Spooka 
1827c537b89Spooka 	return psbuf_get_reqid(cmp1) != psbuf_get_reqid(cmp2);
1830e7bdfc1Spooka }
184c3ef8ea5Spooka 
1850e7bdfc1Spooka struct puffs_framebuf *
psbuf_makeout()1860e7bdfc1Spooka psbuf_makeout()
1870e7bdfc1Spooka {
1880e7bdfc1Spooka 	struct puffs_framebuf *pb;
189c3ef8ea5Spooka 
1900e7bdfc1Spooka 	pb = puffs_framebuf_make();
1910e7bdfc1Spooka 	puffs_framebuf_seekset(pb, 4);
192c3ef8ea5Spooka 	return pb;
193c3ef8ea5Spooka }
194c3ef8ea5Spooka 
195c3ef8ea5Spooka void
psbuf_recycleout(struct puffs_framebuf * pb)1960e7bdfc1Spooka psbuf_recycleout(struct puffs_framebuf *pb)
197c3ef8ea5Spooka {
198c3ef8ea5Spooka 
1990e7bdfc1Spooka 	puffs_framebuf_recycle(pb);
2000e7bdfc1Spooka 	puffs_framebuf_seekset(pb, 4);
201c3ef8ea5Spooka }
202c3ef8ea5Spooka 
203c3ef8ea5Spooka void
psbuf_put_1(struct puffs_framebuf * pb,uint8_t val)2040e7bdfc1Spooka psbuf_put_1(struct puffs_framebuf *pb, uint8_t val)
205c3ef8ea5Spooka {
2060e7bdfc1Spooka 	int rv;
207c3ef8ea5Spooka 
2080e7bdfc1Spooka 	rv = puffs_framebuf_putdata(pb, &val, 1);
2090e7bdfc1Spooka 	CHECK(rv == 0);
210c3ef8ea5Spooka }
211c3ef8ea5Spooka 
2120e7bdfc1Spooka void
psbuf_put_2(struct puffs_framebuf * pb,uint16_t val)2130e7bdfc1Spooka psbuf_put_2(struct puffs_framebuf *pb, uint16_t val)
214c3ef8ea5Spooka {
2150e7bdfc1Spooka 	int rv;
216c3ef8ea5Spooka 
2170e7bdfc1Spooka 	HTOBE16(val);
2180e7bdfc1Spooka 	rv = puffs_framebuf_putdata(pb, &val, 2);
2190e7bdfc1Spooka 	CHECK(rv == 0);
220c3ef8ea5Spooka }
221c3ef8ea5Spooka 
2220e7bdfc1Spooka void
psbuf_put_4(struct puffs_framebuf * pb,uint32_t val)2230e7bdfc1Spooka psbuf_put_4(struct puffs_framebuf *pb, uint32_t val)
224c3ef8ea5Spooka {
2250e7bdfc1Spooka 	int rv;
226c3ef8ea5Spooka 
2270e7bdfc1Spooka 	HTOBE32(val);
2280e7bdfc1Spooka 	rv = puffs_framebuf_putdata(pb, &val, 4);
2290e7bdfc1Spooka 	CHECK(rv == 0);
230c3ef8ea5Spooka }
231c3ef8ea5Spooka 
2320e7bdfc1Spooka void
psbuf_put_8(struct puffs_framebuf * pb,uint64_t val)2330e7bdfc1Spooka psbuf_put_8(struct puffs_framebuf *pb, uint64_t val)
234c3ef8ea5Spooka {
2350e7bdfc1Spooka 	int rv;
236c3ef8ea5Spooka 
2370e7bdfc1Spooka 	HTOBE64(val);
2380e7bdfc1Spooka 	rv = puffs_framebuf_putdata(pb, &val, 8);
2390e7bdfc1Spooka 	CHECK(rv == 0);
240c3ef8ea5Spooka }
241c3ef8ea5Spooka 
2420e7bdfc1Spooka void
psbuf_put_data(struct puffs_framebuf * pb,const void * data,uint32_t dlen)2430e7bdfc1Spooka psbuf_put_data(struct puffs_framebuf *pb, const void *data, uint32_t dlen)
244c3ef8ea5Spooka {
2450e7bdfc1Spooka 	int rv;
246c3ef8ea5Spooka 
247c3ef8ea5Spooka 	psbuf_put_4(pb, dlen);
2480e7bdfc1Spooka 	rv = puffs_framebuf_putdata(pb, data, dlen);
2490e7bdfc1Spooka 	CHECK(rv == 0);
250c3ef8ea5Spooka }
251c3ef8ea5Spooka 
2520e7bdfc1Spooka void
psbuf_put_str(struct puffs_framebuf * pb,const char * str)2530e7bdfc1Spooka psbuf_put_str(struct puffs_framebuf *pb, const char *str)
254c3ef8ea5Spooka {
255c3ef8ea5Spooka 
2560e7bdfc1Spooka 	psbuf_put_data(pb, str, strlen(str));
257c3ef8ea5Spooka }
258c3ef8ea5Spooka 
2590e7bdfc1Spooka void
psbuf_put_vattr(struct puffs_framebuf * pb,const struct vattr * va,const struct psshfs_ctx * pctx)260c4291c19Spooka psbuf_put_vattr(struct puffs_framebuf *pb, const struct vattr *va,
261c4291c19Spooka 	const struct psshfs_ctx *pctx)
262c3ef8ea5Spooka {
263c3ef8ea5Spooka 	uint32_t flags;
264e828ea6bSpooka 	uint32_t theuid = -1, thegid = -1;
265c3ef8ea5Spooka 	flags = 0;
266c3ef8ea5Spooka 
2675866121cSpooka 	if (va->va_size != (uint64_t)PUFFS_VNOVAL)
268c3ef8ea5Spooka 		flags |= SSH_FILEXFER_ATTR_SIZE;
2696cd252daSpooka 	if (va->va_uid != (uid_t)PUFFS_VNOVAL) {
2706cd252daSpooka 		theuid = va->va_uid;
2716cd252daSpooka 		if (pctx->domangleuid && theuid == pctx->myuid)
2726cd252daSpooka 			theuid = pctx->mangleuid;
273c3ef8ea5Spooka 		flags |= SSH_FILEXFER_ATTR_UIDGID;
2746cd252daSpooka 	}
2756cd252daSpooka 	if (va->va_gid != (gid_t)PUFFS_VNOVAL) {
2766cd252daSpooka 		thegid = va->va_gid;
2776cd252daSpooka 		if (pctx->domanglegid && thegid == pctx->mygid)
2786cd252daSpooka 			thegid = pctx->manglegid;
2796cd252daSpooka 		flags |= SSH_FILEXFER_ATTR_UIDGID;
2806cd252daSpooka 	}
2815866121cSpooka 	if (va->va_mode != (mode_t)PUFFS_VNOVAL)
282c3ef8ea5Spooka 		flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2837f864d60Spooka 
284c3ef8ea5Spooka 	if (va->va_atime.tv_sec != PUFFS_VNOVAL)
285c3ef8ea5Spooka 		flags |= SSH_FILEXFER_ATTR_ACCESSTIME;
286c3ef8ea5Spooka 
287c3ef8ea5Spooka 	psbuf_put_4(pb, flags);
288c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_SIZE)
289c3ef8ea5Spooka 		psbuf_put_8(pb, va->va_size);
290c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_UIDGID) {
291c4291c19Spooka 		psbuf_put_4(pb, theuid);
292c4291c19Spooka 		psbuf_put_4(pb, thegid);
293c3ef8ea5Spooka 	}
294c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_PERMISSIONS)
295c3ef8ea5Spooka 		psbuf_put_4(pb, va->va_mode);
2967f864d60Spooka 
2977f864d60Spooka 	/* XXX: this is totally wrong for protocol v3, see OpenSSH */
2987f864d60Spooka 	if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
299c3ef8ea5Spooka 		psbuf_put_4(pb, va->va_atime.tv_sec);
300c3ef8ea5Spooka 		psbuf_put_4(pb, va->va_mtime.tv_sec);
3017f864d60Spooka 	}
302c3ef8ea5Spooka }
303c3ef8ea5Spooka 
3040e7bdfc1Spooka #define ERETURN(rv) return ((rv) == -1 ? errno : 0)
305c3ef8ea5Spooka 
306c3ef8ea5Spooka int
psbuf_get_1(struct puffs_framebuf * pb,uint8_t * val)3070e7bdfc1Spooka psbuf_get_1(struct puffs_framebuf *pb, uint8_t *val)
308c3ef8ea5Spooka {
309c3ef8ea5Spooka 
3100e7bdfc1Spooka 	ERETURN(puffs_framebuf_getdata(pb, val, 1));
311c3ef8ea5Spooka }
312c3ef8ea5Spooka 
313c3ef8ea5Spooka int
psbuf_get_2(struct puffs_framebuf * pb,uint16_t * val)3140e7bdfc1Spooka psbuf_get_2(struct puffs_framebuf *pb, uint16_t *val)
315c3ef8ea5Spooka {
3160e7bdfc1Spooka 	int rv;
317c3ef8ea5Spooka 
3180e7bdfc1Spooka 	rv = puffs_framebuf_getdata(pb, val, 2);
3190e7bdfc1Spooka 	BE16TOH(*val);
320c3ef8ea5Spooka 
3210e7bdfc1Spooka 	ERETURN(rv);
322c3ef8ea5Spooka }
323c3ef8ea5Spooka 
324c3ef8ea5Spooka int
psbuf_get_4(struct puffs_framebuf * pb,uint32_t * val)3250e7bdfc1Spooka psbuf_get_4(struct puffs_framebuf *pb, uint32_t *val)
326c3ef8ea5Spooka {
3270e7bdfc1Spooka 	int rv;
328c3ef8ea5Spooka 
3290e7bdfc1Spooka 	rv = puffs_framebuf_getdata(pb, val, 4);
3300e7bdfc1Spooka 	BE32TOH(*val);
331c3ef8ea5Spooka 
3320e7bdfc1Spooka 	ERETURN(rv);
333c3ef8ea5Spooka }
334c3ef8ea5Spooka 
335c3ef8ea5Spooka int
psbuf_get_8(struct puffs_framebuf * pb,uint64_t * val)3360e7bdfc1Spooka psbuf_get_8(struct puffs_framebuf *pb, uint64_t *val)
337c3ef8ea5Spooka {
3380e7bdfc1Spooka 	int rv;
339c3ef8ea5Spooka 
3400e7bdfc1Spooka 	rv = puffs_framebuf_getdata(pb, val, 8);
3410e7bdfc1Spooka 	BE64TOH(*val);
342c3ef8ea5Spooka 
3430e7bdfc1Spooka 	ERETURN(rv);
344c3ef8ea5Spooka }
345c3ef8ea5Spooka 
346c3ef8ea5Spooka int
psbuf_get_str(struct puffs_framebuf * pb,char ** strp,uint32_t * strlenp)3470e7bdfc1Spooka psbuf_get_str(struct puffs_framebuf *pb, char **strp, uint32_t *strlenp)
348c3ef8ea5Spooka {
349c3ef8ea5Spooka 	char *str;
350c3ef8ea5Spooka 	uint32_t len;
351c3ef8ea5Spooka 
3520e7bdfc1Spooka 	FAILRV(psbuf_get_4(pb, &len));
353c3ef8ea5Spooka 
354d34b7523Spooka 	if (puffs_framebuf_remaining(pb) < len)
3550e7bdfc1Spooka 		return EPROTO;
356c3ef8ea5Spooka 
357c3ef8ea5Spooka 	str = emalloc(len+1);
3580e7bdfc1Spooka 	puffs_framebuf_getdata(pb, str, len);
359c3ef8ea5Spooka 	str[len] = '\0';
360c3ef8ea5Spooka 	*strp = str;
361c3ef8ea5Spooka 
362c3ef8ea5Spooka 	if (strlenp)
363c3ef8ea5Spooka 		*strlenp = len;
364c3ef8ea5Spooka 
3650e7bdfc1Spooka 	return 0;
366c3ef8ea5Spooka }
367c3ef8ea5Spooka 
368c3ef8ea5Spooka int
psbuf_get_vattr(struct puffs_framebuf * pb,struct vattr * vap)3690e7bdfc1Spooka psbuf_get_vattr(struct puffs_framebuf *pb, struct vattr *vap)
370c3ef8ea5Spooka {
371c3ef8ea5Spooka 	uint32_t flags;
372c3ef8ea5Spooka 	uint32_t val;
373c3ef8ea5Spooka 
374c3ef8ea5Spooka 	puffs_vattr_null(vap);
375c3ef8ea5Spooka 
3760e7bdfc1Spooka 	FAILRV(psbuf_get_4(pb, &flags));
377c3ef8ea5Spooka 
378c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_SIZE) {
3790e7bdfc1Spooka 		FAILRV(psbuf_get_8(pb, &vap->va_size));
380c3ef8ea5Spooka 		vap->va_bytes = vap->va_size;
381c3ef8ea5Spooka 	}
382c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_UIDGID) {
3830e7bdfc1Spooka 		FAILRV(psbuf_get_4(pb, &vap->va_uid));
3840e7bdfc1Spooka 		FAILRV(psbuf_get_4(pb, &vap->va_gid));
385c3ef8ea5Spooka 	}
386c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
3870e7bdfc1Spooka 		FAILRV(psbuf_get_4(pb, &vap->va_mode));
388c3ef8ea5Spooka 		vap->va_type = puffs_mode2vt(vap->va_mode);
389c3ef8ea5Spooka 	}
390c3ef8ea5Spooka 	if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
391c3ef8ea5Spooka 		/*
392c3ef8ea5Spooka 		 * XXX: this is utterly wrong if we want to speak
393c3ef8ea5Spooka 		 * protocol version 3, but it seems like the
394c3ef8ea5Spooka 		 * "internet standard" for doing this
395c3ef8ea5Spooka 		 */
3960e7bdfc1Spooka 		FAILRV(psbuf_get_4(pb, &val));
397c3ef8ea5Spooka 		vap->va_atime.tv_sec = val;
3980e7bdfc1Spooka 		FAILRV(psbuf_get_4(pb, &val));
399c3ef8ea5Spooka 		vap->va_mtime.tv_sec = val;
400c3ef8ea5Spooka 		/* make ctime the same as mtime */
401c3ef8ea5Spooka 		vap->va_ctime.tv_sec = val;
402c3ef8ea5Spooka 
403c3ef8ea5Spooka 		vap->va_atime.tv_nsec = 0;
404c3ef8ea5Spooka 		vap->va_ctime.tv_nsec = 0;
405c3ef8ea5Spooka 		vap->va_mtime.tv_nsec = 0;
406c3ef8ea5Spooka 	}
407c3ef8ea5Spooka 
4080e7bdfc1Spooka 	return 0;
409c3ef8ea5Spooka }
410c3ef8ea5Spooka 
411c3ef8ea5Spooka /*
412c3ef8ea5Spooka  * Buffer content helpers.  Caller frees all data.
413c3ef8ea5Spooka  */
414c3ef8ea5Spooka 
415c3ef8ea5Spooka /*
416c3ef8ea5Spooka  * error mapping.. most are not expected for a file system, but
417c3ef8ea5Spooka  * should help with diagnosing a possible error
418c3ef8ea5Spooka  */
419c3ef8ea5Spooka static int emap[] = {
420c3ef8ea5Spooka 	0,			/* OK			*/
421c3ef8ea5Spooka 	0,			/* EOF			*/
422c3ef8ea5Spooka 	ENOENT,			/* NO_SUCH_FILE		*/
423c3ef8ea5Spooka 	EPERM,			/* PERMISSION_DENIED	*/
424c3ef8ea5Spooka 	EIO,			/* FAILURE		*/
425c3ef8ea5Spooka 	EBADMSG,		/* BAD_MESSAGE		*/
426c3ef8ea5Spooka 	ENOTCONN,		/* NO_CONNECTION	*/
427c3ef8ea5Spooka 	ECONNRESET,		/* CONNECTION_LOST	*/
428c3ef8ea5Spooka 	EOPNOTSUPP,		/* OP_UNSUPPORTED	*/
429c3ef8ea5Spooka 	EINVAL,			/* INVALID_HANDLE	*/
430c3ef8ea5Spooka 	ENXIO,			/* NO_SUCH_PATH		*/
431c3ef8ea5Spooka 	EEXIST,			/* FILE_ALREADY_EXISTS	*/
432c3ef8ea5Spooka 	ENODEV			/* WRITE_PROTECT	*/
433c3ef8ea5Spooka };
4345866121cSpooka #define NERRORS ((int)(sizeof(emap) / sizeof(emap[0])))
435c3ef8ea5Spooka 
436c3ef8ea5Spooka static int
sftperr_to_errno(int error)437c3ef8ea5Spooka sftperr_to_errno(int error)
438c3ef8ea5Spooka {
439c3ef8ea5Spooka 
440c3ef8ea5Spooka 	if (!error)
441c3ef8ea5Spooka 		return 0;
442c3ef8ea5Spooka 
443c3ef8ea5Spooka 	if (error >= NERRORS || error < 0)
444c3ef8ea5Spooka 		return EPROTO;
445c3ef8ea5Spooka 
446c3ef8ea5Spooka 	return emap[error];
447c3ef8ea5Spooka }
448c3ef8ea5Spooka 
449c3ef8ea5Spooka #define INVALRESPONSE EPROTO
450c3ef8ea5Spooka 
451c3ef8ea5Spooka static int
expectcode(struct puffs_framebuf * pb,int value)4520e7bdfc1Spooka expectcode(struct puffs_framebuf *pb, int value)
453c3ef8ea5Spooka {
454c3ef8ea5Spooka 	uint32_t error;
4550e7bdfc1Spooka 	uint8_t type;
456c3ef8ea5Spooka 
4570e7bdfc1Spooka 	type = psbuf_get_type(pb);
4580e7bdfc1Spooka 	if (type == value)
459c3ef8ea5Spooka 		return 0;
460c3ef8ea5Spooka 
4610e7bdfc1Spooka 	if (type != SSH_FXP_STATUS)
462c3ef8ea5Spooka 		return INVALRESPONSE;
463c3ef8ea5Spooka 
4640e7bdfc1Spooka 	FAILRV(psbuf_get_4(pb, &error));
465c3ef8ea5Spooka 
466c3ef8ea5Spooka 	return sftperr_to_errno(error);
467c3ef8ea5Spooka }
468c3ef8ea5Spooka 
469c3ef8ea5Spooka #define CHECKCODE(pb,val)						\
470c3ef8ea5Spooka do {									\
471c3ef8ea5Spooka 	int rv;								\
472c3ef8ea5Spooka 	rv = expectcode(pb, val);					\
473c3ef8ea5Spooka 	if (rv)								\
474c3ef8ea5Spooka 		return rv;						\
475c3ef8ea5Spooka } while (/*CONSTCOND*/0)
476c3ef8ea5Spooka 
477c3ef8ea5Spooka int
psbuf_expect_status(struct puffs_framebuf * pb)4780e7bdfc1Spooka psbuf_expect_status(struct puffs_framebuf *pb)
479c3ef8ea5Spooka {
480c3ef8ea5Spooka 	uint32_t error;
481c3ef8ea5Spooka 
4820e7bdfc1Spooka 	if (psbuf_get_type(pb) != SSH_FXP_STATUS)
483c3ef8ea5Spooka 		return INVALRESPONSE;
484c3ef8ea5Spooka 
4850e7bdfc1Spooka 	FAILRV(psbuf_get_4(pb, &error));
486c3ef8ea5Spooka 
487c3ef8ea5Spooka 	return sftperr_to_errno(error);
488c3ef8ea5Spooka }
489c3ef8ea5Spooka 
490c3ef8ea5Spooka int
psbuf_expect_handle(struct puffs_framebuf * pb,char ** hand,uint32_t * handlen)4910e7bdfc1Spooka psbuf_expect_handle(struct puffs_framebuf *pb, char **hand, uint32_t *handlen)
492c3ef8ea5Spooka {
493c3ef8ea5Spooka 
494c3ef8ea5Spooka 	CHECKCODE(pb, SSH_FXP_HANDLE);
4950e7bdfc1Spooka 	FAILRV(psbuf_get_str(pb, hand, handlen));
496c3ef8ea5Spooka 
497c3ef8ea5Spooka 	return 0;
498c3ef8ea5Spooka }
499c3ef8ea5Spooka 
500c3ef8ea5Spooka /* no memory allocation, direct copy */
501c3ef8ea5Spooka int
psbuf_do_data(struct puffs_framebuf * pb,uint8_t * data,uint32_t * dlen)5020e7bdfc1Spooka psbuf_do_data(struct puffs_framebuf *pb, uint8_t *data, uint32_t *dlen)
503c3ef8ea5Spooka {
5040e7bdfc1Spooka 	void *win;
505c495e43bSpooka 	size_t bufoff, winlen;
506c495e43bSpooka 	uint32_t len, dataoff;
507c3ef8ea5Spooka 
5080e7bdfc1Spooka 	if (psbuf_get_type(pb) != SSH_FXP_DATA) {
509c3ef8ea5Spooka 		uint32_t val;
510c3ef8ea5Spooka 
5110e7bdfc1Spooka 		if (psbuf_get_type(pb) != SSH_FXP_STATUS)
512c3ef8ea5Spooka 			return INVALRESPONSE;
513c3ef8ea5Spooka 
5144a403dd9Spooka 		if (psbuf_get_4(pb, &val) != 0)
515c3ef8ea5Spooka 			return INVALRESPONSE;
516c3ef8ea5Spooka 
517c3ef8ea5Spooka 		if (val != SSH_FX_EOF)
518c3ef8ea5Spooka 			return sftperr_to_errno(val);
519c3ef8ea5Spooka 
520c3ef8ea5Spooka 		*dlen = 0;
521c3ef8ea5Spooka 		return 0;
522c3ef8ea5Spooka 	}
5234a403dd9Spooka 	if (psbuf_get_4(pb, &len) != 0)
524c3ef8ea5Spooka 		return INVALRESPONSE;
525c3ef8ea5Spooka 
526c3ef8ea5Spooka 	if (*dlen < len)
527c3ef8ea5Spooka 		return EINVAL;
528c3ef8ea5Spooka 
5290e7bdfc1Spooka 	*dlen = 0;
530c3ef8ea5Spooka 
5310e7bdfc1Spooka 	dataoff = 0;
5320e7bdfc1Spooka 	while (dataoff < len) {
5330e7bdfc1Spooka 		winlen = len-dataoff;
5340e7bdfc1Spooka 		bufoff = puffs_framebuf_telloff(pb);
5350e7bdfc1Spooka 		if (puffs_framebuf_getwindow(pb, bufoff,
5360e7bdfc1Spooka 		    &win, &winlen) == -1)
5370e7bdfc1Spooka 			return EINVAL;
5380e7bdfc1Spooka 		if (winlen == 0)
5390e7bdfc1Spooka 			break;
540c3ef8ea5Spooka 
5410e7bdfc1Spooka 		memcpy(data + dataoff, win, winlen);
5420e7bdfc1Spooka 		dataoff += winlen;
5430e7bdfc1Spooka 	}
5440e7bdfc1Spooka 
5450e7bdfc1Spooka 	*dlen = dataoff;
546c3ef8ea5Spooka 
547c3ef8ea5Spooka 	return 0;
548c3ef8ea5Spooka }
549c3ef8ea5Spooka 
550c3ef8ea5Spooka int
psbuf_expect_name(struct puffs_framebuf * pb,uint32_t * count)5510e7bdfc1Spooka psbuf_expect_name(struct puffs_framebuf *pb, uint32_t *count)
552c3ef8ea5Spooka {
553c3ef8ea5Spooka 
554c3ef8ea5Spooka 	CHECKCODE(pb, SSH_FXP_NAME);
5550e7bdfc1Spooka 	FAILRV(psbuf_get_4(pb, count));
556c3ef8ea5Spooka 
557c3ef8ea5Spooka 	return 0;
558c3ef8ea5Spooka }
559c3ef8ea5Spooka 
560c3ef8ea5Spooka int
psbuf_expect_attrs(struct puffs_framebuf * pb,struct vattr * vap)5610e7bdfc1Spooka psbuf_expect_attrs(struct puffs_framebuf *pb, struct vattr *vap)
562c3ef8ea5Spooka {
563c3ef8ea5Spooka 
564c3ef8ea5Spooka 	CHECKCODE(pb, SSH_FXP_ATTRS);
5650e7bdfc1Spooka 	FAILRV(psbuf_get_vattr(pb, vap));
566c3ef8ea5Spooka 
567c3ef8ea5Spooka 	return 0;
568c3ef8ea5Spooka }
569c3ef8ea5Spooka 
570c3ef8ea5Spooka /*
571c3ef8ea5Spooka  * More helpers: larger-scale put functions
572c3ef8ea5Spooka  */
573c3ef8ea5Spooka 
5740e7bdfc1Spooka void
psbuf_req_data(struct puffs_framebuf * pb,int type,uint32_t reqid,const void * data,uint32_t dlen)5750e7bdfc1Spooka psbuf_req_data(struct puffs_framebuf *pb, int type, uint32_t reqid,
5760e7bdfc1Spooka 	const void *data, uint32_t dlen)
577c3ef8ea5Spooka {
578c3ef8ea5Spooka 
579c3ef8ea5Spooka 	psbuf_put_1(pb, type);
580c3ef8ea5Spooka 	psbuf_put_4(pb, reqid);
581c3ef8ea5Spooka 	psbuf_put_data(pb, data, dlen);
582c3ef8ea5Spooka }
583c3ef8ea5Spooka 
5840e7bdfc1Spooka void
psbuf_req_str(struct puffs_framebuf * pb,int type,uint32_t reqid,const char * str)5850e7bdfc1Spooka psbuf_req_str(struct puffs_framebuf *pb, int type, uint32_t reqid,
5860e7bdfc1Spooka 	const char *str)
587c3ef8ea5Spooka {
588c3ef8ea5Spooka 
5890e7bdfc1Spooka 	psbuf_req_data(pb, type, reqid, str, strlen(str));
590c3ef8ea5Spooka }
591