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