Blob


1 /*
2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include "compat.h"
19 #include <sys/stat.h>
21 #include <endian.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <pwd.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <syslog.h>
29 #include <unistd.h>
31 #include "client.h"
32 #include "kamid.h"
33 #include "log.h"
34 #include "sandbox.h"
35 #include "utils.h"
37 #define DEBUG_PACKETS 0
39 STAILQ_HEAD(qidhead, qid) qids;
40 struct qid {
41 /* definition of a qid */
42 uint64_t path;
43 uint32_t vers;
44 uint8_t type;
46 int fd;
47 int refcount;
49 char fpath[PATH_MAX];
50 struct stat sb;
52 STAILQ_ENTRY(qid) entries;
53 };
55 STAILQ_HEAD(fidhead, fid) fids;
56 struct fid {
57 uint32_t fid;
58 int iomode;
59 struct qid *qid;
60 STAILQ_ENTRY(fid) entries;
61 };
63 static struct imsgev *iev_listener;
64 static struct evbuffer *evb;
65 static uint32_t peerid;
67 static int handshaked, attached;
68 uint32_t msize;
70 static ATTR_DEAD void client_shutdown(void);
71 static void client_sig_handler(int, short, void *);
72 static void client_dispatch_listener(int, short, void *);
73 static void client_privdrop(const char *, const char *);
75 static int client_send_listener(int, const void *, uint16_t);
77 static void qid_set_from_sb(struct qid *);
78 static int qid_update_stat(struct qid *);
79 static struct qid *qid_from_copy(const struct qid *);
80 static struct qid *qid_from_fd(int);
81 static struct qid *qid_from_path(const char *);
82 static struct qid *qid_incref(struct qid *);
83 static void qid_decref(struct qid *);
85 static struct fid *new_fid(struct qid *, uint32_t);
86 static struct fid *fid_by_id(uint32_t);
87 static void free_fid(struct fid *);
89 static void parse_message(const uint8_t *, size_t,
90 struct np_msg_header *, uint8_t **);
92 static void np_write16(uint16_t);
93 static void np_header(uint32_t, uint8_t, uint16_t);
94 static void np_string(uint16_t, const char *);
95 static void np_qid(struct qid *);
96 static void do_send(void);
98 static void np_version(uint16_t, uint32_t, const char *);
99 static void np_attach(uint16_t, struct qid *);
100 static void np_clunk(uint16_t);
101 static void np_flush(uint16_t);
102 static void np_walk(uint16_t, int, struct qid *);
103 static void np_error(uint16_t, const char *);
104 static void np_errno(uint16_t);
106 static int np_read8(const char *, const char *, uint8_t *,
107 const uint8_t **, size_t *);
108 static int np_read16(const char *, const char *, uint16_t *,
109 const uint8_t **, size_t *);
110 static int np_read32(const char *, const char *, uint32_t *,
111 const uint8_t **, size_t *);
113 #define READSTRERR -1
114 #define READSTRTRUNC -2
115 static int np_readstr(const char *, const char *, char *, size_t,
116 const uint8_t **, size_t *);
118 #define NPREAD8(f, dst, src, len) np_read8(__func__, f, dst, src, len)
119 #define NPREAD16(f, dst, src, len) np_read16(__func__, f, dst, src, len)
120 #define NPREAD32(f, dst, src, len) np_read32(__func__, f, dst, src, len)
122 #define NPREADSTR(f, b, bl, src, len) np_readstr(__func__, f, b, bl, src, len)
124 static void tversion(struct np_msg_header *, const uint8_t *, size_t);
125 static void tattach(struct np_msg_header *, const uint8_t *, size_t);
126 static void tclunk(struct np_msg_header *, const uint8_t *, size_t);
127 static void tflush(struct np_msg_header *, const uint8_t *, size_t);
128 static void twalk(struct np_msg_header *, const uint8_t *, size_t);
129 static void handle_message(struct imsg *, size_t);
131 ATTR_DEAD void
132 client(int debug, int verbose)
134 struct event ev_sigint, ev_sigterm;
136 log_init(debug, LOG_DAEMON);
137 log_setverbose(verbose);
139 setproctitle("client");
140 log_procinit("client");
142 log_debug("warming up");
144 event_init();
146 /* Setup signal handlers */
147 signal_set(&ev_sigint, SIGINT, client_sig_handler, NULL);
148 signal_set(&ev_sigterm, SIGTERM, client_sig_handler, NULL);
150 signal_add(&ev_sigint, NULL);
151 signal_add(&ev_sigterm, NULL);
153 signal(SIGPIPE, SIG_IGN);
154 signal(SIGHUP, SIG_IGN);
156 /* Setup pipe and event handler to the listener process */
157 if ((iev_listener = malloc(sizeof(*iev_listener))) == NULL)
158 fatal(NULL);
160 imsg_init(&iev_listener->ibuf, 3);
161 iev_listener->handler = client_dispatch_listener;
163 /* Setup event handlers. */
164 iev_listener->events = EV_READ;
165 event_set(&iev_listener->ev, iev_listener->ibuf.fd,
166 iev_listener->events, iev_listener->handler, iev_listener);
167 event_add(&iev_listener->ev, NULL);
169 event_dispatch();
170 client_shutdown();
173 static ATTR_DEAD void
174 client_shutdown(void)
176 if (evb != NULL)
177 evbuffer_free(evb);
179 msgbuf_clear(&iev_listener->ibuf.w);
180 close(iev_listener->ibuf.fd);
182 free(iev_listener);
184 log_info("client exiting");
185 exit(0);
188 static void
189 client_sig_handler(int sig, short event, void *d)
191 /*
192 * Normal signal handler rules don't apply because libevent
193 * decouples for us.
194 */
196 switch (sig) {
197 case SIGINT:
198 case SIGTERM:
199 client_shutdown();
200 default:
201 fatalx("unexpected signal %d", sig);
205 #define AUTH_NONE 0
206 #define AUTH_USER 1
207 #define AUTH_DONE 2
209 static void
210 client_dispatch_listener(int fd, short event, void *d)
212 static int auth = AUTH_NONE;
213 static char username[64] = {0};
214 static char dir[PATH_MAX] = {0};
215 struct imsg imsg;
216 struct imsgev *iev = d;
217 struct imsgbuf *ibuf;
218 ssize_t n;
219 int shut = 0;
221 ibuf = &iev->ibuf;
223 if (event & EV_READ) {
224 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
225 fatal("imsg_read error");
226 if (n == 0) /* Connection closed */
227 shut = 1;
229 if (event & EV_WRITE) {
230 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
231 fatal("msgbuf_write");
232 if (n == 0) /* Connection closed */
233 shut = 1;
236 for (;;) {
237 if ((n = imsg_get(ibuf, &imsg)) == -1)
238 fatal("%s: imsg_get error", __func__);
239 if (n == 0) /* No more messages. */
240 break;
242 switch (imsg.hdr.type) {
243 case IMSG_AUTH:
244 peerid = imsg.hdr.peerid;
245 if (auth)
246 fatalx("%s: IMSG_AUTH already done", __func__);
247 auth = AUTH_USER;
248 ((char *)imsg.data)[IMSG_DATA_SIZE(imsg)-1] = '\0';
249 strlcpy(username, imsg.data, sizeof(username));
250 break;
251 case IMSG_AUTH_DIR:
252 if (auth != AUTH_USER)
253 fatalx("%s: IMSG_AUTH_DIR not after IMSG_AUTH",
254 __func__);
255 auth = AUTH_DONE;
256 ((char *)imsg.data)[IMSG_DATA_SIZE(imsg)-1] = '\0';
257 strlcpy(dir, imsg.data, sizeof(dir));
258 client_privdrop(username, dir);
259 memset(username, 0, sizeof(username));
260 memset(dir, 0, sizeof(username));
261 break;
262 case IMSG_BUF:
263 /* echo! */
264 if (!auth)
265 fatalx("%s: can't handle messages before"
266 " doing the auth", __func__);
267 handle_message(&imsg, IMSG_DATA_SIZE(imsg));
268 break;
269 case IMSG_CONN_GONE:
270 log_debug("closing");
271 shut = 1;
272 break;
273 default:
274 log_debug("%s: unexpected imsg %d",
275 __func__, imsg.hdr.type);
276 break;
278 imsg_free(&imsg);
281 if (!shut)
282 imsg_event_add(iev);
283 else {
284 /* This pipe is dead. Remove its event handler. */
285 event_del(&iev->ev);
286 log_warnx("pipe closed, shutting down...");
287 event_loopexit(NULL);
291 static void
292 client_privdrop(const char *username, const char *dir)
294 struct passwd *pw;
296 setproctitle("client %s", username);
298 if ((pw = getpwnam(username)) == NULL)
299 fatalx("getpwnam(%s) failed", username);
301 if (chroot(dir) == -1)
302 fatal("chroot");
303 if (chdir("/") == -1)
304 fatal("chdir(\"/\")");
306 if (setgroups(1, &pw->pw_gid) ||
307 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
308 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
309 fatal("can't drop privileges");
311 sandbox_client();
312 log_debug("client ready; user=%s dir=%s", username, dir);
314 if ((evb = evbuffer_new()) == NULL)
315 fatal("evbuffer_new");
318 static int
319 client_send_listener(int type, const void *data, uint16_t len)
321 int ret;
323 if ((ret = imsg_compose(&iev_listener->ibuf, type, peerid, 0, -1,
324 data, len)) != -1)
325 imsg_event_add(iev_listener);
327 return ret;
330 /* set qid fields from the sb field */
331 static void
332 qid_set_from_sb(struct qid *qid)
334 qid->path = qid->sb.st_ino;
336 /*
337 * Theoretically (and hopefully!) this should be a 64 bit
338 * number. Unfortunately, 9P uses 32 bit timestamps.
339 */
340 qid->vers = qid->sb.st_mtim.tv_sec;
342 if (S_ISREG(qid->sb.st_mode))
343 qid->type = QTFILE;
344 else if (S_ISDIR(qid->sb.st_mode))
345 qid->type = QTDIR;
346 else if (S_ISLNK(qid->sb.st_mode))
347 qid->type = QTSYMLINK;
350 /* update qid info */
351 static int
352 qid_update_stat(struct qid *qid)
354 if (fstat(qid->fd, &qid->sb) == -1)
355 return -1;
357 qid_set_from_sb(qid);
358 return 0;
361 /* create a new qid by copying info from an existing one */
362 static struct qid *
363 qid_from_copy(const struct qid *qid)
365 struct qid *q;
367 if ((q = calloc(1, sizeof(*q))) == NULL)
368 return NULL;
369 q->fd = -1;
371 memcpy(q->fpath, qid->fpath, sizeof(q->fpath));
373 memcpy(&q->sb, &qid->sb, sizeof(q->sb));
374 memcpy(&q->path, &qid->path, sizeof(q->path));
375 memcpy(&q->vers, &qid->vers, sizeof(q->vers));
376 memcpy(&q->type, &qid->type, sizeof(q->type));
378 return q;
381 /* creates a qid given a fd */
382 static struct qid *
383 qid_from_fd(int fd)
385 struct qid *qid;
387 if ((qid = calloc(1, sizeof(*qid))) == NULL)
388 return NULL;
390 qid->fd = fd;
391 qid_update_stat(qid);
393 STAILQ_INSERT_HEAD(&qids, qid, entries);
395 return qid;
398 static struct qid *
399 qid_from_path(const char *path)
401 struct qid *qid;
403 if ((qid = calloc(1, sizeof(*qid))) == NULL)
404 return NULL;
406 qid->fd = -1;
408 if (stat(path, &qid->sb) == -1) {
409 free(qid);
410 return NULL;
413 qid_set_from_sb(qid);
415 STAILQ_INSERT_HEAD(&qids, qid, entries);
417 return qid;
420 static struct qid *
421 qid_incref(struct qid *qid)
423 qid->refcount++;
424 return qid;
427 static void
428 qid_decref(struct qid *qid)
430 if (--qid->refcount > 0)
431 return;
433 STAILQ_REMOVE(&qids, qid, qid, entries);
435 close(qid->fd);
436 free(qid);
438 if (STAILQ_EMPTY(&qids))
439 attached = 0;
442 static struct fid *
443 new_fid(struct qid *qid, uint32_t fid)
445 struct fid *f;
447 if ((f = calloc(1, sizeof(*f))) == NULL)
448 return NULL;
450 f->qid = qid_incref(qid);
451 f->fid = fid;
453 STAILQ_INSERT_HEAD(&fids, f, entries);
455 return f;
458 static struct fid *
459 fid_by_id(uint32_t fid)
461 struct fid *f;
463 STAILQ_FOREACH(f, &fids, entries) {
464 if (f->fid == fid)
465 return f;
468 return NULL;
471 static void
472 free_fid(struct fid *f)
474 qid_decref(f->qid);
476 STAILQ_REMOVE(&fids, f, fid, entries);
477 free(f);
480 static void
481 parse_message(const uint8_t *data, size_t len, struct np_msg_header *hdr,
482 uint8_t **cnt)
484 size_t olen = len;
486 if (!NPREAD32("len", &hdr->len, &data, &len) ||
487 !NPREAD8("type", &hdr->type, &data, &len) ||
488 !NPREAD16("tag", &hdr->tag, &data, &len))
489 goto err;
491 if (olen != hdr->len)
492 goto err;
494 if (hdr->type < Tversion ||
495 hdr->type >= Tmax ||
496 hdr->type == Terror ||
497 (hdr->type & 0x1) != 0) /* cannot recv a R* */
498 goto err;
500 hdr->tag = le32toh(hdr->tag);
502 *cnt = (uint8_t *)data;
503 return;
505 err:
506 /* TODO: send a proper message to terminate the connection. */
507 fatalx("got invalid message");
510 static void
511 np_write16(uint16_t x)
513 x = htole16(x);
514 evbuffer_add(evb, &x, sizeof(x));
517 static void
518 np_header(uint32_t len, uint8_t type, uint16_t tag)
520 len += HEADERSIZE;
522 len = htole32(len);
523 tag = htole16(tag);
525 evbuffer_add(evb, &len, sizeof(len));
526 evbuffer_add(evb, &type, sizeof(type));
527 evbuffer_add(evb, &tag, sizeof(tag));
530 static void
531 np_string(uint16_t len, const char *str)
533 uint16_t l = len;
535 len = htole16(len);
536 evbuffer_add(evb, &len, sizeof(len));
537 evbuffer_add(evb, str, l);
540 static void
541 np_qid(struct qid *qid)
543 uint64_t path;
544 uint32_t vers;
546 path = htole64(qid->path);
547 vers = htole32(qid->vers);
549 evbuffer_add(evb, &qid->type, sizeof(qid->type));
550 evbuffer_add(evb, &vers, sizeof(vers));
551 evbuffer_add(evb, &path, sizeof(path));
554 static void
555 do_send(void)
557 size_t len;
558 void *data;
560 len = EVBUFFER_LENGTH(evb);
561 data = EVBUFFER_DATA(evb);
563 #if DEBUG_PACKETS
564 hexdump("outgoing packet", data, len);
565 #endif
566 client_send_listener(IMSG_BUF, data, len);
567 evbuffer_drain(evb, len);
570 static void
571 np_version(uint16_t tag, uint32_t msize, const char *version)
573 uint16_t l;
575 l = strlen(version);
577 msize = htole32(msize);
579 np_header(sizeof(msize) + sizeof(l) + l, Rversion, tag);
580 evbuffer_add(evb, &msize, sizeof(msize));
581 np_string(l, version);
582 do_send();
585 static void
586 np_attach(uint16_t tag, struct qid *qid)
588 np_header(QIDSIZE, Rattach, tag);
589 np_qid(qid);
590 do_send();
593 static void
594 np_clunk(uint16_t tag)
596 np_header(0, Rclunk, tag);
597 do_send();
600 static void
601 np_flush(uint16_t tag)
603 np_header(0, Rflush, tag);
604 do_send();
607 static void
608 np_walk(uint16_t tag, int nwqid, struct qid *wqid)
610 int i;
612 /* two bytes for the counter */
613 np_header(2 + QIDSIZE * nwqid, Rwalk, tag);
614 np_write16(nwqid);
615 for (i = 0; i < nwqid; ++i)
616 np_qid(wqid + i);
618 do_send();
621 static void
622 np_error(uint16_t tag, const char *errstr)
624 uint16_t l;
626 l = strlen(errstr);
628 np_header(sizeof(l) + l, Rerror, tag);
629 np_string(l, errstr);
630 do_send();
633 static void
634 np_errno(uint16_t tag)
636 int saved_errno;
637 char buf[64];
639 saved_errno = errno;
641 strerror_r(errno, buf, sizeof(buf));
642 np_error(tag, buf);
644 errno = saved_errno;
647 static int
648 np_read8(const char *t, const char *f, uint8_t *dst, const uint8_t **src,
649 size_t *len)
651 if (*len < sizeof(*dst)) {
652 log_warnx("%s: wanted %zu bytes for the %s field but only "
653 "%zu are available.", t, sizeof(*dst), f, *len);
654 return -1;
657 memcpy(dst, *src, sizeof(*dst));
658 *src += sizeof(*dst);
659 *len -= sizeof(*dst);
661 return 1;
664 static int
665 np_read16(const char *t, const char *f, uint16_t *dst, const uint8_t **src,
666 size_t *len)
668 if (*len < sizeof(*dst)) {
669 log_warnx("%s: wanted %zu bytes for the %s field but only "
670 "%zu are available.", t, sizeof(*dst), f, *len);
671 return -1;
674 memcpy(dst, *src, sizeof(*dst));
675 *src += sizeof(*dst);
676 *len -= sizeof(*dst);
677 *dst = le16toh(*dst);
679 return 1;
682 static int
683 np_read32(const char *t, const char *f, uint32_t *dst, const uint8_t **src,
684 size_t *len)
686 if (*len < sizeof(*dst)) {
687 log_warnx("%s: wanted %zu bytes for the %s field but only "
688 "%zu are available.", t, sizeof(*dst), f, *len);
689 return -1;
692 memcpy(dst, *src, sizeof(*dst));
693 *src += sizeof(*dst);
694 *len -= sizeof(*dst);
695 *dst = le32toh(*dst);
697 return 1;
700 static int
701 np_readstr(const char *t, const char *f, char *res, size_t reslen,
702 const uint8_t **src, size_t *len)
704 uint16_t sl;
705 char buf[32];
707 strlcpy(buf, f, sizeof(buf));
708 strlcat(buf, "-len", sizeof(buf));
710 if (!np_read16(t, buf, &sl, src, len))
711 return READSTRERR;
713 if (*len < sl) {
714 log_warnx("%s: wanted %d bytes for the %s field but only "
715 "%zu are available.", t, sl, f, *len);
716 return READSTRERR;
719 if (*len > reslen-1)
720 return READSTRTRUNC;
722 memcpy(res, *src, sl);
723 res[sl] = '\0';
724 *src += sl;
725 *len -= sl;
727 return 0;
730 static void
731 tversion(struct np_msg_header *hdr, const uint8_t *data, size_t len)
733 char *dot, version[32];
735 if (handshaked)
736 goto err;
738 /* msize[4] version[s] */
739 if (!NPREAD32("msize", &msize, &data, &len))
740 goto err;
742 switch (NPREADSTR("version", version, sizeof(version), &data, &len)) {
743 case READSTRERR:
744 goto err;
745 case READSTRTRUNC:
746 log_warnx("9P version string too long, truncated");
747 goto mismatch;
750 if ((dot = strchr(version, '.')) != NULL)
751 *dot = '\0';
753 if (strcmp(version, VERSION9P) != 0 ||
754 msize == 0)
755 goto mismatch;
757 /* version matched */
758 handshaked = 1;
759 msize = MIN(msize, MSIZE9P);
760 client_send_listener(IMSG_MSIZE, &msize, sizeof(msize));
761 np_version(hdr->tag, msize, VERSION9P);
762 return;
764 mismatch:
765 log_warnx("unknown 9P version string: \"%s\", want "VERSION9P,
766 version);
767 np_version(hdr->tag, MSIZE9P, "unknown");
768 return;
770 err:
771 client_send_listener(IMSG_CLOSE, NULL, 0);
772 client_shutdown();
775 static void
776 tattach(struct np_msg_header *hdr, const uint8_t *data, size_t len)
778 struct qid *qid;
779 struct fid *f;
780 uint32_t fid, afid;
781 char aname[PATH_MAX];
783 if (attached) {
784 np_error(hdr->tag, "already attached");
785 return;
788 /* fid[4] afid[4] uname[s] aname[s] */
790 if (!NPREAD32("fid", &fid, &data, &len) ||
791 !NPREAD32("afid", &afid, &data, &len))
792 goto err;
794 /* read the uname but don't actually use it */
795 switch (NPREADSTR("uname", aname, sizeof(aname), &data, &len)) {
796 case READSTRERR:
797 goto err;
798 case READSTRTRUNC:
799 np_error(hdr->tag, "name too long");
800 return;
803 switch (NPREADSTR("aname", aname, sizeof(aname), &data, &len)) {
804 case READSTRERR:
805 goto err;
806 case READSTRTRUNC:
807 np_error(hdr->tag, "name too long");
808 return;
811 if ((qid = qid_from_path(aname)) == NULL) {
812 np_errno(hdr->tag);
813 log_debug("failed to attach %s: %s", aname, strerror(errno));
814 return;
816 log_debug("attached %s", aname);
818 if ((f = new_fid(qid, fid)) == NULL) {
819 qid_decref(qid);
820 np_error(hdr->tag, "no memory");
821 return;
824 np_attach(hdr->tag, qid);
825 attached = 1;
826 return;
828 err:
829 client_send_listener(IMSG_CLOSE, NULL, 0);
830 client_shutdown();
833 static void
834 tclunk(struct np_msg_header *hdr, const uint8_t *data, size_t len)
836 struct fid *f;
837 uint32_t fid;
839 /* fid[4] */
840 if (!NPREAD32("fid", &fid, &data, &len)) {
841 client_send_listener(IMSG_CLOSE, NULL, 0);
842 client_shutdown();
843 return;
846 if ((f = fid_by_id(fid)) == NULL) {
847 np_error(hdr->tag, "invalid fid");
848 return;
851 free_fid(f);
852 np_clunk(hdr->tag);
855 static void
856 tflush(struct np_msg_header *hdr, const uint8_t *data, size_t len)
858 uint16_t oldtag;
860 /*
861 * We're doing only synchronous I/O. Tflush is implemented
862 * only because it's illegal to reply with a Rerror.
863 */
865 /* oldtag[2] */
866 if (len != sizeof(oldtag)) {
867 log_warnx("Tclunk with the wrong size: got %zu want %zu",
868 len, sizeof(oldtag));
869 client_send_listener(IMSG_CLOSE, NULL, 0);
870 client_shutdown();
871 return;
874 np_flush(hdr->tag);
877 static void
878 twalk(struct np_msg_header *hdr, const uint8_t *data, size_t len)
880 struct qid *qid, wqid[MAXWELEM] = {0};
881 struct fid *f, *nf;
882 uint32_t fid, newfid;
883 uint16_t nwname;
884 int nwqid = 0;
885 char wnam[PATH_MAX+1], path[PATH_MAX+1];
887 if (!NPREAD32("fid", &fid, &data, &len) ||
888 !NPREAD32("newfid", &newfid, &data, &len) ||
889 !NPREAD16("nwname", &nwname, &data, &len))
890 goto err;
892 if (nwname > MAXWELEM) {
893 log_warnx("Twalk: more than %d path elements: %d",
894 MAXWELEM, nwname);
895 goto err;
898 if ((f = fid_by_id(fid)) == NULL) {
899 np_error(hdr->tag, "invalid fid");
900 return;
903 if (fid == newfid)
904 nf = f;
905 else if ((nf = fid_by_id(newfid)) != NULL) {
906 np_error(hdr->tag, "newfid already in use");
907 return;
908 } else
909 nf = NULL;
911 /* special case: fid duplication */
912 if (nwname == 0) {
913 /*
914 * TODO: should we forbid fids duplication when fid ==
915 * newfid?
916 */
918 if (nf == NULL) {
919 if ((nf = new_fid(f->qid, newfid)) == NULL)
920 fatal("new_fid duplication");
923 np_walk(hdr->tag, 1, f->qid);
924 return;
927 if (f->iomode != 0) {
928 np_error(hdr->tag, "fid already opened for I/O");
929 return;
932 if (f->qid->type != QTDIR) {
933 np_error(hdr->tag, "fid doesn't represent a directory");
934 return;
937 strlcpy(path, f->qid->fpath, sizeof(path));
939 for (nwqid = 0; nwqid < nwname; nwqid++) {
940 switch (NPREADSTR("wname", wnam, sizeof(wnam), &data, &len)) {
941 case READSTRERR:
942 goto err;
943 case READSTRTRUNC:
944 np_error(hdr->tag, "wname too long");
945 return;
948 strlcat(path, "/", sizeof(path));
949 strlcat(path, wnam, sizeof(path));
951 if (stat(path, &wqid[nwqid].sb) == -1) {
952 if (nwqid == 0)
953 np_errno(hdr->tag);
954 else
955 np_walk(hdr->tag, nwqid, wqid);
956 return;
959 qid_set_from_sb(&wqid[nwqid]);
962 if ((qid = qid_from_path(path)) == NULL)
963 fatal("qid_from_fd");
965 if (nf == NULL) {
966 if ((nf = new_fid(qid, newfid)) == NULL)
967 fatal("new_fid");
968 } else {
969 /* swap qid */
970 qid_decref(nf->qid);
971 nf->qid = qid_incref(qid);
974 np_walk(hdr->tag, nwqid, wqid);
976 return;
978 err:
979 client_send_listener(IMSG_CLOSE, NULL, 0);
980 client_shutdown();
983 static void
984 handle_message(struct imsg *imsg, size_t len)
986 struct msg {
987 uint8_t type;
988 void (*fn)(struct np_msg_header *, const uint8_t *, size_t);
989 } msgs[] = {
990 {Tversion, tversion},
991 {Tattach, tattach},
992 {Tclunk, tclunk},
993 {Tflush, tflush},
994 {Twalk, twalk},
995 };
996 struct np_msg_header hdr;
997 size_t i;
998 uint8_t *data;
1000 #if DEBUG_PACKETS
1001 hexdump("incoming packet", imsg->data, len);
1002 #endif
1004 parse_message(imsg->data, len, &hdr, &data);
1005 len -= HEADERSIZE;
1007 log_debug("got request: len=%d type=%d[%s] tag=%d",
1008 hdr.len, hdr.type, pp_msg_type(hdr.type), hdr.tag);
1010 if (!handshaked && hdr.type != Tversion) {
1011 client_send_listener(IMSG_CLOSE, NULL, 0);
1012 client_shutdown();
1013 return;
1016 for (i = 0; i < sizeof(msgs)/sizeof(msgs[0]); ++i) {
1017 if (msgs[i].type != hdr.type)
1018 continue;
1020 msgs[i].fn(&hdr, data, len);
1021 return;
1024 np_error(hdr.tag, "Not supported.");