xref: /netbsd/usr.sbin/puffs/mount_9p/nineproto.c (revision 35339755)
1 /*	$NetBSD: nineproto.c,v 1.14 2021/09/03 21:55:01 andvar Exp $	*/
2 
3 /*
4  * Copyright (c) 2007  Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: nineproto.c,v 1.14 2021/09/03 21:55:01 andvar Exp $");
31 #endif /* !lint */
32 
33 #include <sys/types.h>
34 
35 #include <errno.h>
36 #include <grp.h>
37 #include <pwd.h>
38 #include <puffs.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 #include "ninepuffs.h"
43 #include "nineproto.h"
44 
45 int
proto_getqid(struct puffs_framebuf * pb,struct qid9p * qid)46 proto_getqid(struct puffs_framebuf *pb, struct qid9p *qid)
47 {
48 
49 	if (puffs_framebuf_remaining(pb) < 1+4+8)
50 		return ENOBUFS;
51 
52 	p9pbuf_get_1(pb, &qid->qidtype);
53 	p9pbuf_get_4(pb, &qid->qidvers);
54 	p9pbuf_get_8(pb, &qid->qidpath);
55 
56 	return 0;
57 }
58 
59 static uid_t
ustr2uid(char * uid)60 ustr2uid(char *uid)
61 {
62 	struct passwd *pw;
63 
64 	pw = getpwnam(uid);
65 	if (pw == NULL)
66 		return 0; /* XXXXX */
67 
68 	return pw->pw_uid;
69 }
70 
71 static gid_t
gstr2gid(char * gid)72 gstr2gid(char *gid)
73 {
74 	struct group *grr;
75 
76 	grr = getgrnam(gid);
77 	if (grr == NULL)
78 		return 0; /* more XXXX */
79 
80 	return grr->gr_gid;
81 }
82 
83 static const char *
uid2ustr(uid_t uid)84 uid2ustr(uid_t uid)
85 {
86 	struct passwd *pw;
87 
88 	pw = getpwuid(uid);
89 	if (pw == NULL)
90 		return "root"; /* XXXXX */
91 
92 	return pw->pw_name;
93 }
94 
95 static const char *
gid2gstr(gid_t gid)96 gid2gstr(gid_t gid)
97 {
98 	struct group *grr;
99 
100 	grr = getgrgid(gid);
101 	if (grr == NULL)
102 		return "wheel"; /* XXXXXX */
103 
104 	return grr->gr_name;
105 }
106 
107 #define GETFIELD(a,b,unitsize)						\
108 do {									\
109 	if (size < unitsize) return EPROTO;				\
110 	if ((rv = (a(pb, b)))) return rv;				\
111 	size -= unitsize;						\
112 } while (/*CONSTCOND*/0)
113 #define GETSTR(val,strsize)						\
114 do {									\
115 	if ((rv = p9pbuf_get_str(pb, val, strsize))) return rv;		\
116 	if (*strsize > size) return EPROTO;				\
117 	size -= *strsize;						\
118 } while (/*CONSTCOND*/0)
119 int
proto_getstat(struct puffs_usermount * pu,struct puffs_framebuf * pb,struct vattr * vap,char ** name,uint16_t * rs)120 proto_getstat(struct puffs_usermount *pu, struct puffs_framebuf *pb, struct vattr *vap,
121 	char **name, uint16_t *rs)
122 {
123 	struct puffs9p *p9p = puffs_getspecific(pu);
124 	char *uid, *gid;
125 	struct qid9p qid;
126 	uint64_t flen;
127 	uint32_t rdev, mode, atime, mtime;
128 	uint16_t size, v16;
129 	int rv;
130 
131 	/* check size */
132 	if ((rv = p9pbuf_get_2(pb, &size)))
133 		return rv;
134 	if (puffs_framebuf_remaining(pb) < size)
135 		return ENOBUFS;
136 
137 	if (rs)
138 		*rs = size+2; /* compensate for size field itself */
139 
140 	GETFIELD(p9pbuf_get_2, &v16, 2);
141 	GETFIELD(p9pbuf_get_4, &rdev, 4);
142 	GETFIELD(proto_getqid, &qid, 13);
143 	GETFIELD(p9pbuf_get_4, &mode, 4);
144 	GETFIELD(p9pbuf_get_4, &atime, 4);
145 	GETFIELD(p9pbuf_get_4, &mtime, 4);
146 	GETFIELD(p9pbuf_get_8, &flen, 8);
147 	GETSTR(name, &v16);
148 	GETSTR(&uid, &v16);
149 	GETSTR(&gid, &v16);
150 
151 	vap->va_rdev = rdev;
152 	vap->va_mode = mode & 0777; /* may contain other uninteresting bits */
153 	vap->va_atime.tv_sec = atime;
154 	vap->va_mtime.tv_sec = mtime;
155 	vap->va_ctime.tv_sec = mtime;
156 	vap->va_atime.tv_nsec=vap->va_mtime.tv_nsec=vap->va_ctime.tv_nsec = 0;
157 	vap->va_birthtime.tv_sec = vap->va_birthtime.tv_nsec = 0;
158 	vap->va_size = vap->va_bytes = flen;
159 	vap->va_uid = ustr2uid(uid);
160 	vap->va_gid = gstr2gid(gid);
161 	free(uid);
162 	free(gid);
163 	qid2vattr(vap, &qid);
164 
165 	/* some defaults */
166 	if (vap->va_type == VDIR)
167 		vap->va_nlink = 1906;
168 	else
169 		vap->va_nlink = 1;
170 	vap->va_blocksize = 512;
171 	vap->va_flags = vap->va_vaflags = 0;
172 	vap->va_filerev = PUFFS_VNOVAL;
173 
174 	/* muid, not used */
175 	GETSTR(NULL, &v16);
176 	if (p9p->protover == P9PROTO_VERSION_U) {
177 		uint32_t dummy;
178 		GETSTR(NULL, &v16); /* extension[s], not used */
179 		GETFIELD(p9pbuf_get_4, &dummy, 4); /* n_uid[4], not used */
180 		GETFIELD(p9pbuf_get_4, &dummy, 4); /* n_gid[4], not used */
181 		GETFIELD(p9pbuf_get_4, &dummy, 4); /* n_muid[4], not used */
182 	}
183 
184 	return 0;
185 }
186 
187 static int
proto_rerror(struct puffs_usermount * pu,struct puffs_framebuf * pb,uint32_t * _errno)188 proto_rerror(struct puffs_usermount *pu, struct puffs_framebuf *pb,
189     uint32_t *_errno)
190 {
191 	struct puffs9p *p9p = puffs_getspecific(pu);
192 	uint16_t size;
193 	int rv;
194 	char *name;
195 
196 	/* Skip size[4] Rerror tag[2] */
197 	rv = puffs_framebuf_seekset(pb,
198 	    sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint16_t));
199 	if (rv == -1)
200 		return EPROTO;
201 
202 	rv = p9pbuf_get_str(pb, &name, &size);
203 	if (rv != 0)
204 		return rv;
205 	if (p9p->protover == P9PROTO_VERSION_U) {
206 		rv = p9pbuf_get_4(pb, _errno);
207 	} else {
208 		/* TODO Convert error string to errno */
209 		rv = EPROTO;
210 	}
211 
212 	return rv;
213 }
214 
215 int
proto_handle_rerror(struct puffs_usermount * pu,struct puffs_framebuf * pb)216 proto_handle_rerror(struct puffs_usermount *pu, struct puffs_framebuf *pb)
217 {
218 	int rv;
219 	uint32_t _errno;
220 
221 	if (p9pbuf_get_type(pb) != P9PROTO_R_ERROR)
222 		return EPROTO;
223 
224 	rv = proto_rerror(pu, pb, &_errno);
225 	if (rv == 0)
226 		rv = _errno;
227 	return rv;
228 }
229 
230 int
proto_cc_dupfid(struct puffs_usermount * pu,p9pfid_t oldfid,p9pfid_t newfid)231 proto_cc_dupfid(struct puffs_usermount *pu, p9pfid_t oldfid, p9pfid_t newfid)
232 {
233 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
234 	struct puffs9p *p9p = puffs_getspecific(pu);
235 	struct puffs_framebuf *pb;
236 	p9ptag_t tag;
237 	uint16_t qids;
238 	int rv = 0;
239 
240 	pb = p9pbuf_makeout();
241 	tag = NEXTTAG(p9p);
242 	p9pbuf_put_1(pb, P9PROTO_T_WALK);
243 	p9pbuf_put_2(pb, tag);
244 	p9pbuf_put_4(pb, oldfid);
245 	p9pbuf_put_4(pb, newfid);
246 	p9pbuf_put_2(pb, 0);
247 	GETRESPONSE(pb);
248 
249 	rv = proto_expect_walk_nqids(pu, pb, &qids);
250 	if (rv == 0 && qids != 0)
251 		rv = EPROTO;
252 
253  out:
254 	puffs_framebuf_destroy(pb);
255 	return rv;
256 }
257 
258 int
proto_cc_clunkfid(struct puffs_usermount * pu,p9pfid_t fid,int waitforit)259 proto_cc_clunkfid(struct puffs_usermount *pu, p9pfid_t fid, int waitforit)
260 {
261 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
262 	struct puffs9p *p9p = puffs_getspecific(pu);
263 	struct puffs_framebuf *pb;
264 	p9ptag_t tag;
265 	int rv = 0;
266 
267 	pb = p9pbuf_makeout();
268 	tag = NEXTTAG(p9p);
269 	p9pbuf_put_1(pb, P9PROTO_T_CLUNK);
270 	p9pbuf_put_2(pb, tag);
271 	p9pbuf_put_4(pb, fid);
272 
273 	if (waitforit) {
274 		if (puffs_framev_enqueue_cc(pcc, p9p->servsock, pb, 0) == 0) {
275 			if (p9pbuf_get_type(pb) != P9PROTO_R_CLUNK)
276 				rv = proto_handle_rerror(pu, pb);
277 		} else {
278 			rv = errno;
279 		}
280 		puffs_framebuf_destroy(pb);
281 	} else {
282 		JUSTSEND(pb);
283 	}
284 
285  out:
286 	return rv;
287 }
288 
289 /*
290  * walk a new fid, then open it
291  */
292 int
proto_cc_open(struct puffs_usermount * pu,p9pfid_t fid,p9pfid_t newfid,int mode)293 proto_cc_open(struct puffs_usermount *pu, p9pfid_t fid,
294 	p9pfid_t newfid, int mode)
295 {
296 	struct puffs_cc *pcc = puffs_cc_getcc(pu);
297 	struct puffs9p *p9p = puffs_getspecific(pu);
298 	struct puffs_framebuf *pb;
299 	p9ptag_t tag;
300 	int rv;
301 
302 	rv = proto_cc_dupfid(pu, fid, newfid);
303 	if (rv)
304 		return rv;
305 
306 	pb = p9pbuf_makeout();
307 	tag = NEXTTAG(p9p);
308 	p9pbuf_put_1(pb, P9PROTO_T_OPEN);
309 	p9pbuf_put_2(pb, tag);
310 	p9pbuf_put_4(pb, newfid);
311 	p9pbuf_put_1(pb, mode);
312 	GETRESPONSE(pb);
313 	if (p9pbuf_get_type(pb) != P9PROTO_R_OPEN)
314 		rv = proto_handle_rerror(pu, pb);
315 
316  out:
317 	puffs_framebuf_destroy(pb);
318 	return rv;
319 }
320 
321 void
proto_make_stat(struct puffs_usermount * pu,struct puffs_framebuf * pb,const struct vattr * vap,const char * filename,enum vtype vt)322 proto_make_stat(struct puffs_usermount *pu, struct puffs_framebuf *pb,
323     const struct vattr *vap, const char *filename, enum vtype vt)
324 {
325 	struct puffs9p *p9p = puffs_getspecific(pu);
326 	struct vattr fakeva;
327 	uint32_t mode, atime, mtime;
328 	uint64_t flen;
329 	const char *owner, *group;
330 	int startoff, curoff;
331 
332 	if (vap == NULL) {
333 		puffs_vattr_null(&fakeva);
334 		vap = &fakeva;
335 	}
336 
337 	startoff = puffs_framebuf_telloff(pb);
338 	puffs_framebuf_seekset(pb, startoff + 2+2); /* stat[n] incl. stat[2] */
339 
340 	if (vap->va_mode != (mode_t)PUFFS_VNOVAL)
341 		mode = vap->va_mode | (vt == VDIR ? P9PROTO_CPERM_DIR : 0);
342 	else
343 		mode = P9PROTO_STAT_NOVAL4;
344 	if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
345 		atime = vap->va_atime.tv_sec;
346 	else
347 		atime = P9PROTO_STAT_NOVAL4;
348 	if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
349 		mtime = vap->va_mtime.tv_sec;
350 	else
351 		mtime = P9PROTO_STAT_NOVAL4;
352 	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
353 		flen = vap->va_size;
354 	else
355 		flen = P9PROTO_STAT_NOVAL8;
356 	if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
357 		owner = uid2ustr(vap->va_uid);
358 	else
359 		owner = "";
360 	if (vap->va_gid != (gid_t)PUFFS_VNOVAL)
361 		group = gid2gstr(vap->va_gid);
362 	else
363 		group = "";
364 
365 	p9pbuf_put_2(pb, P9PROTO_STAT_NOVAL2);	/* kernel type	*/
366 	p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4);	/* dev		*/
367 	p9pbuf_put_1(pb, P9PROTO_STAT_NOVAL1);	/* type		*/
368 	p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4);	/* version	*/
369 	p9pbuf_put_8(pb, P9PROTO_STAT_NOVAL8);	/* path		*/
370 	p9pbuf_put_4(pb, mode);
371 	p9pbuf_put_4(pb, atime);
372 	p9pbuf_put_4(pb, mtime);
373 	p9pbuf_put_8(pb, flen);
374 	p9pbuf_put_str(pb, filename ? filename : "");
375 	p9pbuf_put_str(pb, owner);
376 	p9pbuf_put_str(pb, group);
377 	p9pbuf_put_str(pb, "");			/* muid		*/
378 	if (p9p->protover == P9PROTO_VERSION_U) {
379 		p9pbuf_put_str(pb, P9PROTO_STAT_NOSTR);	/* extensions[s] */
380 		p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4);	/* n_uid[4] */
381 		p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4);	/* n_gid[4] */
382 		p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4);	/* n_muid[4] */
383 	}
384 
385 	curoff = puffs_framebuf_telloff(pb);
386 	puffs_framebuf_seekset(pb, startoff);
387 	p9pbuf_put_2(pb, curoff-(startoff+2));	/* stat[n] size	*/
388 	p9pbuf_put_2(pb, curoff-(startoff+4));	/* size[2] stat	*/
389 
390 	puffs_framebuf_seekset(pb, curoff);
391 }
392 
393 int
proto_expect_walk_nqids(struct puffs_usermount * pu,struct puffs_framebuf * pb,uint16_t * nqids)394 proto_expect_walk_nqids(struct puffs_usermount *pu, struct puffs_framebuf *pb,
395     uint16_t *nqids)
396 {
397 
398 	if (p9pbuf_get_type(pb) != P9PROTO_R_WALK)
399 		return proto_handle_rerror(pu, pb);
400 	return p9pbuf_get_2(pb, nqids);
401 }
402 
403 int
proto_expect_qid(struct puffs_usermount * pu,struct puffs_framebuf * pb,uint8_t op,struct qid9p * qid)404 proto_expect_qid(struct puffs_usermount *pu, struct puffs_framebuf *pb,
405     uint8_t op, struct qid9p *qid)
406 {
407 
408 	if (p9pbuf_get_type(pb) != op)
409 		return proto_handle_rerror(pu, pb);
410 	return proto_getqid(pb, qid);
411 }
412 
413 int
proto_expect_stat(struct puffs_usermount * pu,struct puffs_framebuf * pb,struct vattr * va)414 proto_expect_stat(struct puffs_usermount *pu, struct puffs_framebuf *pb,
415     struct vattr *va)
416 {
417 	uint16_t dummy;
418 	int rv;
419 
420 	if (p9pbuf_get_type(pb) != P9PROTO_R_STAT)
421 		return proto_handle_rerror(pu, pb);
422 	if ((rv = p9pbuf_get_2(pb, &dummy)))
423 		return rv;
424 	return proto_getstat(pu, pb, va, NULL, NULL);
425 }
426