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