2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: rsh-security.c,v 1.18 2005/12/01 01:14:39 martinea Exp $
30 * rsh-security.c - security and transport over rsh or a rsh-like command.
32 * XXX still need to check for initial keyword on connect so we can skip
33 * over shell garbage and other stuff that rsh might want to spew out.
49 #define rshprintf(x) dbprintf(x)
55 * Path to the rsh binary. This should be configurable.
57 #define RSH_PATH "/usr/bin/rsh"
60 * Arguments to rsh. This should also be configurable
62 #define RSH_ARGS "-l", CLIENT_LOGIN
65 * Number of seconds rsh has to start up
67 #define CONNECT_TIMEOUT 20
70 * Magic values for rsh_conn->handle
72 #define H_TAKEN -1 /* rsh_conn->tok was already read */
73 #define H_EOF -2 /* this connection has been shut down */
76 * This is a rsh connection to a host. We should only have
77 * one connection per host.
80 int read, write; /* pipes to rsh */
81 pid_t pid; /* pid of rsh process */
82 char pkt[NETWORK_BLOCK_BYTES]; /* last pkt read */
83 unsigned long pktlen; /* len of above */
84 struct { /* buffer read() calls */
85 char buf[STREAM_BUFSIZE]; /* buffer */
86 size_t left; /* unread data */
87 ssize_t size; /* size of last read */
89 event_handle_t *ev_read; /* read (EV_READFD) handle */
90 int ev_read_refcnt; /* number of readers */
91 char hostname[MAX_HOSTNAME_LENGTH+1]; /* host we're talking to */
92 char *errmsg; /* error passed up */
93 int refcnt; /* number of handles using */
94 int handle; /* last proto handle read */
95 TAILQ_ENTRY(rsh_conn) tq; /* queue handle */
102 * This is the private handle data.
105 security_handle_t sech; /* MUST be first */
106 char *hostname; /* ptr to rc->hostname */
107 struct rsh_stream *rs; /* virtual stream we xmit over */
110 void (*recvpkt) P((void *, pkt_t *, security_status_t));
111 /* func to call when packet recvd */
112 void (*connect) P((void *, security_handle_t *, security_status_t));
113 /* func to call when connected */
115 void *arg; /* argument to pass function */
116 event_handle_t *ev_timeout; /* timeout handle for recv */
120 * This is the internal security_stream data for rsh.
123 security_stream_t secstr; /* MUST be first */
124 struct rsh_conn *rc; /* physical connection */
125 int handle; /* protocol handle */
126 event_handle_t *ev_read; /* read (EV_WAIT) event handle */
127 void (*fn) P((void *, void *, ssize_t)); /* read event fn */
128 void *arg; /* arg for previous */
132 * Interface functions
134 static int rsh_sendpkt P((void *, pkt_t *));
135 static int rsh_stream_accept P((void *));
136 static int rsh_stream_auth P((void *));
137 static int rsh_stream_id P((void *));
138 static int rsh_stream_write P((void *, const void *, size_t));
139 static void *rsh_stream_client P((void *, int));
140 static void *rsh_stream_server P((void *));
141 static void rsh_accept P((int, int,
142 void (*)(security_handle_t *, pkt_t *)));
143 static void rsh_close P((void *));
144 static void rsh_connect P((const char *,
145 char *(*)(char *, void *),
146 void (*)(void *, security_handle_t *, security_status_t), void *));
147 static void rsh_recvpkt P((void *,
148 void (*)(void *, pkt_t *, security_status_t), void *, int));
149 static void rsh_recvpkt_cancel P((void *));
150 static void rsh_stream_close P((void *));
151 static void rsh_stream_read P((void *, void (*)(void *, void *, ssize_t),
153 static void rsh_stream_read_cancel P((void *));
156 * This is our interface to the outside world.
158 const security_driver_t rsh_security_driver = {
174 rsh_stream_read_cancel,
178 * This is a queue of open connections
181 TAILQ_HEAD(, rsh_conn) tailq;
184 TAILQ_HEAD_INITIALIZER(connq.tailq), 0
186 #define connq_first() TAILQ_FIRST(&connq.tailq)
187 #define connq_next(rc) TAILQ_NEXT(rc, tq)
188 #define connq_append(rc) do { \
189 TAILQ_INSERT_TAIL(&connq.tailq, rc, tq); \
192 #define connq_remove(rc) do { \
193 assert(connq.qlength > 0); \
194 TAILQ_REMOVE(&connq.tailq, rc, tq); \
198 static int newhandle = 1;
201 * This is a function that should be called if a new security_handle_t is
202 * created. If NULL, no new handles are created.
203 * It is passed the new handle and the received pkt
205 static void (*accept_fn) P((security_handle_t *, pkt_t *));
210 static void connect_callback P((void *));
211 static void connect_timeout P((void *));
212 static int send_token P((struct rsh_conn *, int, const void *, size_t));
213 static int recv_token P((struct rsh_conn *, int));
214 static void recvpkt_callback P((void *, void *, ssize_t));
215 static void recvpkt_timeout P((void *));
216 static void stream_read_callback P((void *));
218 static int runrsh P((struct rsh_conn *));
219 static struct rsh_conn *conn_get P((const char *));
220 static void conn_put P((struct rsh_conn *));
221 static void conn_read P((struct rsh_conn *));
222 static void conn_read_cancel P((struct rsh_conn *));
223 static void conn_read_callback P((void *));
224 static int net_writev P((int, struct iovec *, int));
225 static ssize_t net_read P((struct rsh_conn *, void *, size_t, int));
226 static int net_read_fillbuf P((struct rsh_conn *, int, int));
227 static void parse_pkt P((pkt_t *, const void *, size_t));
231 * rsh version of a security handle allocator. Logically sets
232 * up a network "connection".
235 rsh_connect(hostname, conf_fn, fn, arg)
236 const char *hostname;
237 char *(*conf_fn) P((char *, void *));
238 void (*fn) P((void *, security_handle_t *, security_status_t));
241 struct rsh_handle *rh;
245 assert(hostname != NULL);
247 rshprintf(("rsh_connect: %s\n", hostname));
249 rh = alloc(sizeof(*rh));
250 security_handleinit(&rh->sech, &rsh_security_driver);
253 rh->ev_timeout = NULL;
255 if ((he = gethostbyname(hostname)) == NULL) {
256 security_seterror(&rh->sech,
257 "%s: could not resolve hostname", hostname);
258 (*fn)(arg, &rh->sech, S_ERROR);
261 rh->hostname = he->h_name; /* will be replaced */
262 rh->rs = rsh_stream_client(rh, newhandle++);
267 rh->hostname = rh->rs->rc->hostname;
269 if (rh->rs->rc->pid < 0) {
271 * We need to open a new connection.
273 * XXX need to eventually limit number of outgoing connections here.
275 if (runrsh(rh->rs->rc) < 0) {
276 security_seterror(&rh->sech,
277 "can't connect to %s: %s", hostname, rh->rs->rc->errmsg);
282 * The socket will be opened async so hosts that are down won't
283 * block everything. We need to register a write event
284 * so we will know when the socket comes alive.
286 * Overload rh->rs->ev_read to provide a write event handle.
287 * We also register a timeout.
291 rh->rs->ev_read = event_register(rh->rs->rc->write, EV_WRITEFD,
292 connect_callback, rh);
293 rh->ev_timeout = event_register(CONNECT_TIMEOUT, EV_TIME,
294 connect_timeout, rh);
299 (*fn)(arg, &rh->sech, S_ERROR);
303 * Called when a rsh connection is finished connecting and is ready
304 * to be authenticated.
307 connect_callback(cookie)
310 struct rsh_handle *rh = cookie;
312 event_release(rh->rs->ev_read);
313 rh->rs->ev_read = NULL;
314 event_release(rh->ev_timeout);
315 rh->ev_timeout = NULL;
317 (*rh->fn.connect)(rh->arg, &rh->sech, S_OK);
321 * Called if a connection times out before completion.
324 connect_timeout(cookie)
327 struct rsh_handle *rh = cookie;
329 event_release(rh->rs->ev_read);
330 rh->rs->ev_read = NULL;
331 event_release(rh->ev_timeout);
332 rh->ev_timeout = NULL;
334 (*rh->fn.connect)(rh->arg, &rh->sech, S_TIMEOUT);
338 * Setup to handle new incoming connections
341 rsh_accept(in, out, fn)
343 void (*fn) P((security_handle_t *, pkt_t *));
347 rc = conn_get("unknown");
355 * Locate an existing connection to the given host, or create a new,
356 * unconnected entry if none exists. The caller is expected to check
357 * for the lack of a connection (rc->read == -1) and set one up.
359 static struct rsh_conn *
361 const char *hostname;
365 rshprintf(("rsh: conn_get: %s\n", hostname));
367 for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
368 if (strcasecmp(hostname, rc->hostname) == 0)
374 rshprintf(("rsh: conn_get: exists, refcnt to %s is now %d\n",
375 rc->hostname, rc->refcnt));
379 rshprintf(("rsh: conn_get: creating new handle\n"));
381 * We can't be creating a new handle if we are the client
383 assert(accept_fn == NULL);
384 rc = alloc(sizeof(*rc));
385 rc->read = rc->write = -1;
387 rc->readbuf.left = 0;
388 rc->readbuf.size = 0;
390 strncpy(rc->hostname, hostname, sizeof(rc->hostname) - 1);
391 rc->hostname[sizeof(rc->hostname) - 1] = '\0';
400 * Delete a reference to a connection, and close it if it is the last
409 assert(rc->refcnt > 0);
410 if (--rc->refcnt > 0) {
411 rshprintf(("rsh: conn_put: decrementing refcnt for %s to %d\n",
412 rc->hostname, rc->refcnt));
415 rshprintf(("rsh: conn_put: closing connection to %s\n", rc->hostname));
421 waitpid(rc->pid, &status, WNOHANG);
423 if (rc->ev_read != NULL)
424 event_release(rc->ev_read);
425 if (rc->errmsg != NULL)
432 * Turn on read events for a conn. Or, increase a refcnt if we are
433 * already receiving read events.
440 if (rc->ev_read != NULL) {
441 rc->ev_read_refcnt++;
442 rshprintf(("rsh: conn_read: incremented refcnt to %d for %s\n",
443 rc->ev_read_refcnt, rc->hostname));
446 rshprintf(("rsh: conn_read registering event handler for %s\n",
448 rc->ev_read = event_register(rc->read, EV_READFD, conn_read_callback, rc);
449 rc->ev_read_refcnt = 1;
457 if (--rc->ev_read_refcnt > 0) {
458 rshprintf(("rsh: conn_read_cancel: decremented refcnt to %d for %s\n",
459 rc->ev_read_refcnt, rc->hostname));
462 rshprintf(("rsh: conn_read_cancel: releasing event handler for %s\n",
464 event_release(rc->ev_read);
469 * frees a handle allocated by the above
475 struct rsh_handle *rh = inst;
479 rshprintf(("rsh: closing handle to %s\n", rh->hostname));
481 if (rh->rs != NULL) {
482 /* This may be null if we get here on an error */
483 rsh_recvpkt_cancel(rh);
484 security_stream_close(&rh->rs->secstr);
486 /* keep us from getting here again */
487 rh->sech.driver = NULL;
492 * Forks a rsh to the host listed in rc->hostname
493 * Returns negative on error, with an errmsg in rc->errmsg.
499 int rpipe[2], wpipe[2];
502 if (pipe(rpipe) < 0 || pipe(wpipe) < 0) {
503 rc->errmsg = newvstralloc("pipe: ", strerror(errno), NULL);
506 switch (rc->pid = fork()) {
508 rc->errmsg = newvstralloc("fork: ", strerror(errno), NULL);
522 rc->write = wpipe[1];
529 amandad_path = vstralloc(libexecdir, "/", "amandad", versionsuffix(),
531 execlp(RSH_PATH, RSH_PATH, RSH_ARGS, rc->hostname, amandad_path,
533 error("error: couldn't exec %s: %s", RSH_PATH, strerror(errno));
535 /* should nerver go here, shut up compiler warning */
543 rsh_sendpkt(cookie, pkt)
547 char buf[sizeof(pkt_t)];
548 struct rsh_handle *rh = cookie;
554 rshprintf(("rsh: sendpkt: enter\n"));
556 len = strlen(pkt->body) + 2;
557 buf[0] = (char)pkt->type;
558 strcpy(&buf[1], pkt->body);
560 rshprintf(("rsh: sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
561 pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body));
563 if (rsh_stream_write(rh->rs, buf, len) < 0) {
564 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
571 * Set up to receive a packet asyncronously, and call back when
575 rsh_recvpkt(cookie, fn, arg, timeout)
577 void (*fn) P((void *, pkt_t *, security_status_t));
580 struct rsh_handle *rh = cookie;
584 rshprintf(("rsh: recvpkt registered for %s\n", rh->hostname));
587 * Reset any pending timeout on this handle
589 if (rh->ev_timeout != NULL)
590 event_release(rh->ev_timeout);
593 * Negative timeouts mean no timeout
596 rh->ev_timeout = NULL;
598 rh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, rh);
602 rsh_stream_read(rh->rs, recvpkt_callback, rh);
606 * Remove a async receive request from the queue
609 rsh_recvpkt_cancel(cookie)
612 struct rsh_handle *rh = cookie;
614 rshprintf(("rsh: cancelling recvpkt for %s\n", rh->hostname));
618 rsh_stream_read_cancel(rh->rs);
619 if (rh->ev_timeout != NULL) {
620 event_release(rh->ev_timeout);
621 rh->ev_timeout = NULL;
626 * This is called when a handle is woken up because data read off of the
630 recvpkt_callback(cookie, buf, bufsize)
635 struct rsh_handle *rh = cookie;
640 * We need to cancel the recvpkt request before calling
641 * the callback because the callback may reschedule us.
643 rsh_recvpkt_cancel(rh);
647 security_seterror(&rh->sech,
648 "EOF on read from %s", rh->hostname);
649 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
652 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
653 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
659 parse_pkt(&pkt, buf, bufsize);
660 rshprintf(("rsh: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n",
661 pkt_type2str(pkt.type), pkt.type, rh->hostname, pkt.body));
662 (*rh->fn.recvpkt)(rh->arg, &pkt, S_OK);
666 * This is called when a handle times out before receiving a packet.
669 recvpkt_timeout(cookie)
672 struct rsh_handle *rh = cookie;
676 rshprintf(("rsh: recvpkt timeout for %s\n", rh->hostname));
678 rsh_recvpkt_cancel(rh);
679 (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);
683 * Create the server end of a stream. For rsh, this means setup a stream
684 * object and allocate a new handle for it.
690 struct rsh_handle *rh = h;
691 struct rsh_stream *rs;
695 rs = alloc(sizeof(*rs));
696 security_streaminit(&rs->secstr, &rsh_security_driver);
697 rs->rc = conn_get(rh->hostname);
699 * Stream should already be setup!
701 if (rs->rc->read < 0) {
704 security_seterror(&rh->sech, "lost connection to %s", rh->hostname);
707 rh->hostname = rs->rc->hostname;
709 * so as not to conflict with the amanda server's handle numbers,
710 * we start at 5000 and work down
712 rs->handle = 5000 - newhandle++;
714 rshprintf(("rsh: stream_server: created stream %d\n", rs->handle));
719 * Accept an incoming connection on a stream_server socket
720 * Nothing needed for rsh.
731 * Return a connected stream. For rsh, this means setup a stream
732 * with the supplied handle.
735 rsh_stream_client(h, id)
739 struct rsh_handle *rh = h;
740 struct rsh_stream *rs;
745 security_seterror(&rh->sech,
746 "%d: invalid security stream id", id);
750 rs = alloc(sizeof(*rs));
751 security_streaminit(&rs->secstr, &rsh_security_driver);
754 rs->rc = conn_get(rh->hostname);
756 rshprintf(("rsh: stream_client: connected to stream %d\n", id));
762 * Close and unallocate resources for a stream.
768 struct rsh_stream *rs = s;
772 rshprintf(("rsh: stream_close: closing stream %d\n", rs->handle));
774 rsh_stream_read_cancel(rs);
780 * Authenticate a stream
781 * Nothing needed for rsh. The connection is authenticated by rshd
793 * Returns the stream id for this stream. This is just the local
800 struct rsh_stream *rs = s;
808 * Write a chunk of data to a stream. Blocks until completion.
811 rsh_stream_write(s, buf, size)
816 struct rsh_stream *rs = s;
820 rshprintf(("rsh: stream_write: writing %d bytes to %s:%d\n", size,
821 rs->rc->hostname, rs->handle));
823 if (send_token(rs->rc, rs->handle, buf, size) < 0) {
824 security_stream_seterror(&rs->secstr, rs->rc->errmsg);
831 * Submit a request to read some data. Calls back with the given
832 * function and arg when completed.
835 rsh_stream_read(s, fn, arg)
837 void (*fn) P((void *, void *, ssize_t));
839 struct rsh_stream *rs = s;
844 * Only one read request can be active per stream.
846 if (rs->ev_read == NULL) {
847 rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
848 stream_read_callback, rs);
856 * Cancel a previous stream read request. It's ok if we didn't have a read
860 rsh_stream_read_cancel(s)
863 struct rsh_stream *rs = s;
867 if (rs->ev_read != NULL) {
868 event_release(rs->ev_read);
870 conn_read_cancel(rs->rc);
875 * Callback for rsh_stream_read
878 stream_read_callback(arg)
881 struct rsh_stream *rs = arg;
884 rshprintf(("rsh: stream_read_callback: handle %d\n", rs->handle));
887 * Make sure this was for us. If it was, then blow away the handle
888 * so it doesn't get claimed twice. Otherwise, leave it alone.
890 * If the handle is EOF, pass that up to our callback.
892 if (rs->rc->handle == rs->handle) {
893 rshprintf(("rsh: stream_read_callback: it was for us\n"));
894 rs->rc->handle = H_TAKEN;
895 } else if (rs->rc->handle != H_EOF) {
896 rshprintf(("rsh: stream_read_callback: not for us\n"));
901 * Remove the event first, and then call the callback.
902 * We remove it first because we don't want to get in their
903 * way if they reschedule it.
905 rsh_stream_read_cancel(rs);
907 if (rs->rc->pktlen == 0) {
908 rshprintf(("rsh: stream_read_callback: EOF\n"));
909 (*rs->fn)(rs->arg, NULL, 0);
912 rshprintf(("rsh: stream_read_callback: read %ld bytes from %s:%d\n",
913 rs->rc->pktlen, rs->rc->hostname, rs->handle));
914 (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen);
918 * The callback for the netfd for the event handler
919 * Determines if this packet is for this security handle,
920 * and does the real callback if so.
923 conn_read_callback(cookie)
926 struct rsh_conn *rc = cookie;
927 struct rsh_handle *rh;
931 assert(cookie != NULL);
933 rshprintf(("rsh: conn_read_callback\n"));
935 /* Read the data off the wire. If we get errors, shut down. */
936 rval = recv_token(rc, 5);
937 rshprintf(("rsh: conn_read_callback: recv_token returned %d\n", rval));
941 rval = event_wakeup((event_id_t)rc);
942 rshprintf(("rsh: conn_read_callback: event_wakeup return %d\n", rval));
943 /* delete our 'accept' reference */
944 if (accept_fn != NULL)
950 /* If there are events waiting on this handle, we're done */
951 rval = event_wakeup((event_id_t)rc);
952 rshprintf(("rsh: conn_read_callback: event_wakeup return %d\n", rval));
956 /* If there is no accept fn registered, then drop the packet */
957 if (accept_fn == NULL)
960 rh = alloc(sizeof(*rh));
961 security_handleinit(&rh->sech, &rsh_security_driver);
962 rh->hostname = rc->hostname;
963 rh->rs = rsh_stream_client(rh, rc->handle);
964 rh->ev_timeout = NULL;
966 rshprintf(("rsh: new connection\n"));
967 parse_pkt(&pkt, rc->pkt, rc->pktlen);
968 rshprintf(("rsh: calling accept_fn\n"));
969 (*accept_fn)(&rh->sech, &pkt);
973 parse_pkt(pkt, buf, bufsize)
978 const unsigned char *bufp = buf;
980 rshprintf(("rsh: parse_pkt: parsing buffer of %d bytes\n", bufsize));
982 pkt->type = (pktype_t)*bufp++;
988 if (bufsize > sizeof(pkt->body) - 1)
989 bufsize = sizeof(pkt->body) - 1;
990 memcpy(pkt->body, bufp, bufsize);
991 pkt->body[sizeof(pkt->body) - 1] = '\0';
994 rshprintf(("rsh: parse_pkt: %s (%d): \"%s\"\n", pkt_type2str(pkt->type),
995 pkt->type, pkt->body));
1000 * Transmits a chunk of data over a rsh_handle, adding
1001 * the necessary headers to allow the remote end to decode it.
1004 send_token(rc, handle, buf, len)
1005 struct rsh_conn *rc;
1010 unsigned int netlength, nethandle;
1011 struct iovec iov[3];
1013 rshprintf(("rsh: send_token: writing %d bytes to %s\n", len,
1016 assert(sizeof(netlength) == 4);
1020 * 32 bit length (network byte order)
1021 * 32 bit handle (network byte order)
1024 netlength = htonl(len);
1025 iov[0].iov_base = (void *)&netlength;
1026 iov[0].iov_len = sizeof(netlength);
1028 nethandle = htonl(handle);
1029 iov[1].iov_base = (void *)&nethandle;
1030 iov[1].iov_len = sizeof(nethandle);
1032 iov[2].iov_base = (void *)buf;
1033 iov[2].iov_len = len;
1035 if (net_writev(rc->write, iov, 3) < 0) {
1036 rc->errmsg = newvstralloc(rc->errmsg, "rsh write error to ",
1037 rc->hostname, ": ", strerror(errno), NULL);
1044 recv_token(rc, timeout)
1045 struct rsh_conn *rc;
1048 unsigned int netint;
1050 assert(sizeof(netint) == 4);
1052 assert(rc->read >= 0);
1054 rshprintf(("rsh: recv_token: reading from %s\n", rc->hostname));
1056 switch (net_read(rc, &netint, sizeof(netint), timeout)) {
1058 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1067 rc->pktlen = ntohl(netint);
1068 if (rc->pktlen > sizeof(rc->pkt)) {
1069 rc->errmsg = newstralloc(rc->errmsg, "recv error: huge packet");
1073 switch (net_read(rc, &netint, sizeof(netint), timeout)) {
1075 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1084 rc->handle = ntohl(netint);
1086 switch (net_read(rc, rc->pkt, rc->pktlen, timeout)) {
1088 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1098 rshprintf(("rsh: recv_token: read %ld bytes from %s\n", rc->pktlen,
1100 return (rc->pktlen);
1104 * Writes out the entire iovec
1107 net_writev(fd, iov, iovcnt)
1111 int delta, n, total;
1113 assert(iov != NULL);
1116 while (iovcnt > 0) {
1120 total += n = writev(fd, iov, iovcnt);
1128 * Iterate through each iov. Figure out what we still need
1131 for (; n > 0; iovcnt--, iov++) {
1132 /* 'delta' is the bytes written from this iovec */
1133 delta = n < iov->iov_len ? n : iov->iov_len;
1134 /* subtract from the total num bytes written */
1137 /* subtract from this iovec */
1138 iov->iov_len -= delta;
1139 iov->iov_base = (char *)iov->iov_base + delta;
1140 /* if this iovec isn't empty, run the writev again */
1141 if (iov->iov_len > 0)
1149 * Like read(), but waits until the entire buffer has been filled.
1152 net_read(rc, vbuf, origsize, timeout)
1153 struct rsh_conn *rc;
1158 char *buf = vbuf, *off; /* ptr arith */
1160 size_t size = origsize;
1163 if (rc->readbuf.left == 0) {
1164 if (net_read_fillbuf(rc, timeout, size) < 0)
1166 if (rc->readbuf.size == 0)
1169 nread = min(rc->readbuf.left, size);
1170 off = rc->readbuf.buf + rc->readbuf.size - rc->readbuf.left;
1171 memcpy(buf, off, nread);
1175 rc->readbuf.left -= nread;
1177 return ((ssize_t)origsize);
1181 * net_read likes to do a lot of little reads. Buffer it.
1184 net_read_fillbuf(rc, timeout, size)
1185 struct rsh_conn *rc;
1191 if(size > sizeof(rc->readbuf.buf)) size = sizeof(rc->readbuf.buf);
1194 FD_SET(rc->read, &readfds);
1195 tv.tv_sec = timeout;
1197 switch (select(rc->read + 1, &readfds, NULL, NULL, &tv)) {
1204 assert(FD_ISSET(rc->read, &readfds));
1210 rc->readbuf.left = 0;
1211 rc->readbuf.size = read(rc->read, rc->readbuf.buf, size);
1212 if (rc->readbuf.size < 0)
1214 rc->readbuf.left = rc->readbuf.size;
1218 #endif /* RSH_SECURITY */