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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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