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: ssh-security.c,v 1.8.2.1 2006/04/11 11:11:16 martinea Exp $
30 * ssh-security.c - security and transport over ssh or a ssh-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 ssh might want to spew out.
49 #define sshprintf(x) dbprintf(x)
55 * Path to the ssh binary. This should be configurable.
57 #define SSH_PATH "/usr/bin/ssh"
60 * Arguments to ssh. This should also be configurable
62 #define SSH_ARGS "-x", "-l", CLIENT_LOGIN
65 * Number of seconds ssh has to start up
67 #define CONNECT_TIMEOUT 20
70 * Magic values for ssh_conn->handle
72 #define H_TAKEN -1 /* ssh_conn->tok was already read */
73 #define H_EOF -2 /* this connection has been shut down */
76 * This is a ssh connection to a host. We should only have
77 * one connection per host.
80 int read, write; /* pipes to ssh */
81 pid_t pid; /* pid of ssh 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(ssh_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 ssh_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 ssh.
123 security_stream_t secstr; /* MUST be first */
124 struct ssh_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 ssh_sendpkt P((void *, pkt_t *));
135 static int ssh_stream_accept P((void *));
136 static int ssh_stream_auth P((void *));
137 static int ssh_stream_id P((void *));
138 static int ssh_stream_write P((void *, const void *, size_t));
139 static void *ssh_stream_client P((void *, int));
140 static void *ssh_stream_server P((void *));
141 static void ssh_accept P((int, int,
142 void (*)(security_handle_t *, pkt_t *)));
143 static void ssh_close P((void *));
144 static void ssh_connect P((const char *,
145 char *(*)(char *, void *),
146 void (*)(void *, security_handle_t *, security_status_t), void *));
147 static void ssh_recvpkt P((void *,
148 void (*)(void *, pkt_t *, security_status_t), void *, int));
149 static void ssh_recvpkt_cancel P((void *));
150 static void ssh_stream_close P((void *));
151 static void ssh_stream_read P((void *, void (*)(void *, void *, ssize_t),
153 static void ssh_stream_read_cancel P((void *));
156 * This is our interface to the outside world.
158 const security_driver_t ssh_security_driver = {
174 ssh_stream_read_cancel,
178 * This is a queue of open connections
181 TAILQ_HEAD(, ssh_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 ssh_conn *, int, const void *, size_t));
213 static int recv_token P((struct ssh_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 runssh P((struct ssh_conn *));
219 static struct ssh_conn *conn_get P((const char *));
220 static void conn_put P((struct ssh_conn *));
221 static void conn_read P((struct ssh_conn *));
222 static void conn_read_cancel P((struct ssh_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 ssh_conn *, void *, size_t, int));
226 static int net_read_fillbuf P((struct ssh_conn *, int, int));
227 static void parse_pkt P((pkt_t *, const void *, size_t));
231 * ssh version of a security handle allocator. Logically sets
232 * up a network "connection".
235 ssh_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 ssh_handle *rh;
245 assert(hostname != NULL);
247 sshprintf(("%s: ssh: ssh_connect: %s\n", debug_prefix_time(NULL), hostname));
249 rh = alloc(sizeof(*rh));
250 security_handleinit(&rh->sech, &ssh_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 = ssh_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 (runssh(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 ssh connection is finished connecting and is ready
304 * to be authenticated.
307 connect_callback(cookie)
310 struct ssh_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 ssh_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 ssh_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 ssh_conn *
361 const char *hostname;
365 sshprintf(("%s: ssh: conn_get: %s\n", debug_prefix_time(NULL), hostname));
367 for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
368 if (strcasecmp(hostname, rc->hostname) == 0)
374 sshprintf(("%s: ssh: conn_get: exists, refcnt to %s is now %d\n", debug_prefix_time(NULL),
375 rc->hostname, rc->refcnt));
379 sshprintf(("%s: ssh: conn_get: creating new handle\n", debug_prefix_time(NULL)));
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);
411 sshprintf(("%s: ssh: conn_put: decrementing refcnt for %s to %d\n", debug_prefix_time(NULL),
412 rc->hostname, rc->refcnt));
413 if (rc->refcnt > 0) {
416 sshprintf(("%s: ssh: conn_put: closing connection to %s\n", debug_prefix_time(NULL), rc->hostname));
422 waitpid(rc->pid, &status, WNOHANG);
424 if (rc->ev_read != NULL)
425 event_release(rc->ev_read);
426 if (rc->errmsg != NULL)
433 * Turn on read events for a conn. Or, increase a ev_read_refcnt if we are
434 * already receiving read events.
441 if (rc->ev_read != NULL) {
442 rc->ev_read_refcnt++;
443 sshprintf(("%s: ssh: conn_read: incremented ev_read_refcnt to %d for %s\n", debug_prefix_time(NULL),
444 rc->ev_read_refcnt, rc->hostname));
447 sshprintf(("%s: ssh: conn_read registering event handler for %s\n", debug_prefix_time(NULL),
449 rc->ev_read = event_register(rc->read, EV_READFD, conn_read_callback, rc);
450 rc->ev_read_refcnt = 1;
458 --rc->ev_read_refcnt;
459 sshprintf(("%s: ssh: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n", debug_prefix_time(NULL),
460 rc->ev_read_refcnt, rc->hostname));
461 if(rc->ev_read_refcnt > 0) {
464 sshprintf(("%s: ssh: conn_read_cancel: releasing event handler for %s\n", debug_prefix_time(NULL),
466 event_release(rc->ev_read);
471 * frees a handle allocated by the above
477 struct ssh_handle *rh = inst;
481 sshprintf(("%s: ssh: closing handle to %s\n", debug_prefix_time(NULL), rh->hostname));
483 if (rh->rs != NULL) {
484 /* This may be null if we get here on an error */
485 ssh_recvpkt_cancel(rh);
486 security_stream_close(&rh->rs->secstr);
488 /* keep us from getting here again */
489 rh->sech.driver = NULL;
494 * Forks a ssh to the host listed in rc->hostname
495 * Returns negative on error, with an errmsg in rc->errmsg.
501 int rpipe[2], wpipe[2];
504 if (pipe(rpipe) < 0 || pipe(wpipe) < 0) {
505 rc->errmsg = newvstralloc("pipe: ", strerror(errno), NULL);
508 switch (rc->pid = fork()) {
510 rc->errmsg = newvstralloc("fork: ", strerror(errno), NULL);
524 rc->write = wpipe[1];
531 amandad_path = vstralloc(libexecdir, "/", "amandad", versionsuffix(),
533 execlp(SSH_PATH, SSH_PATH, SSH_ARGS, rc->hostname, amandad_path,
535 error("error: couldn't exec %s: %s", SSH_PATH, strerror(errno));
537 /* should nerver go here, shut up compiler warning */
545 ssh_sendpkt(cookie, pkt)
549 char buf[sizeof(pkt_t)];
550 struct ssh_handle *rh = cookie;
556 sshprintf(("%s: ssh: sendpkt: enter\n", debug_prefix_time(NULL)));
558 len = strlen(pkt->body) + 2;
559 buf[0] = (char)pkt->type;
560 strcpy(&buf[1], pkt->body);
562 sshprintf(("%s: ssh: sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n", debug_prefix_time(NULL),
563 pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body));
565 if (ssh_stream_write(rh->rs, buf, len) < 0) {
566 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
573 * Set up to receive a packet asyncronously, and call back when
577 ssh_recvpkt(cookie, fn, arg, timeout)
579 void (*fn) P((void *, pkt_t *, security_status_t));
582 struct ssh_handle *rh = cookie;
586 sshprintf(("%s: ssh: recvpkt registered for %s\n", debug_prefix_time(NULL), rh->hostname));
589 * Reset any pending timeout on this handle
591 if (rh->ev_timeout != NULL)
592 event_release(rh->ev_timeout);
595 * Negative timeouts mean no timeout
598 rh->ev_timeout = NULL;
600 rh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, rh);
604 ssh_stream_read(rh->rs, recvpkt_callback, rh);
608 * Remove a async receive request from the queue
611 ssh_recvpkt_cancel(cookie)
614 struct ssh_handle *rh = cookie;
616 sshprintf(("%s: ssh: cancelling recvpkt for %s\n", debug_prefix_time(NULL), rh->hostname));
620 ssh_stream_read_cancel(rh->rs);
621 if (rh->ev_timeout != NULL) {
622 event_release(rh->ev_timeout);
623 rh->ev_timeout = NULL;
628 * This is called when a handle is woken up because data read off of the
632 recvpkt_callback(cookie, buf, bufsize)
637 struct ssh_handle *rh = cookie;
642 * We need to cancel the recvpkt request before calling
643 * the callback because the callback may reschedule us.
645 ssh_recvpkt_cancel(rh);
649 security_seterror(&rh->sech,
650 "EOF on read from %s", rh->hostname);
651 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
654 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
655 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
661 parse_pkt(&pkt, buf, bufsize);
662 sshprintf(("%s: ssh: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n", debug_prefix_time(NULL),
663 pkt_type2str(pkt.type), pkt.type, rh->hostname, pkt.body));
664 (*rh->fn.recvpkt)(rh->arg, &pkt, S_OK);
668 * This is called when a handle times out before receiving a packet.
671 recvpkt_timeout(cookie)
674 struct ssh_handle *rh = cookie;
678 sshprintf(("%s: ssh: recvpkt timeout for %s\n", debug_prefix_time(NULL), rh->hostname));
680 ssh_recvpkt_cancel(rh);
681 (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);
685 * Create the server end of a stream. For ssh, this means setup a stream
686 * object and allocate a new handle for it.
692 struct ssh_handle *rh = h;
693 struct ssh_stream *rs;
697 rs = alloc(sizeof(*rs));
698 security_streaminit(&rs->secstr, &ssh_security_driver);
699 rs->rc = conn_get(rh->hostname);
701 * Stream should already be setup!
703 if (rs->rc->read < 0) {
706 security_seterror(&rh->sech, "lost connection to %s", rh->hostname);
709 rh->hostname = rs->rc->hostname;
711 * so as not to conflict with the amanda server's handle numbers,
712 * we start at 5000 and work down
714 rs->handle = 5000 - newhandle++;
716 sshprintf(("%s: ssh: stream_server: created stream %d\n", debug_prefix_time(NULL), rs->handle));
721 * Accept an incoming connection on a stream_server socket
722 * Nothing needed for ssh.
733 * Return a connected stream. For ssh, this means setup a stream
734 * with the supplied handle.
737 ssh_stream_client(h, id)
741 struct ssh_handle *rh = h;
742 struct ssh_stream *rs;
747 security_seterror(&rh->sech,
748 "%d: invalid security stream id", id);
752 rs = alloc(sizeof(*rs));
753 security_streaminit(&rs->secstr, &ssh_security_driver);
756 rs->rc = conn_get(rh->hostname);
758 sshprintf(("%s: ssh: stream_client: connected to stream %d\n", debug_prefix_time(NULL), id));
764 * Close and unallocate resources for a stream.
770 struct ssh_stream *rs = s;
774 sshprintf(("%s: ssh: stream_close: closing stream %d\n", debug_prefix_time(NULL), rs->handle));
776 ssh_stream_read_cancel(rs);
782 * Authenticate a stream
783 * Nothing needed for ssh. The connection is authenticated by sshd
795 * Returns the stream id for this stream. This is just the local
802 struct ssh_stream *rs = s;
810 * Write a chunk of data to a stream. Blocks until completion.
813 ssh_stream_write(s, buf, size)
818 struct ssh_stream *rs = s;
822 sshprintf(("%s: ssh: stream_write: writing %d bytes to %s:%d\n", debug_prefix_time(NULL), size,
823 rs->rc->hostname, rs->handle));
825 if (send_token(rs->rc, rs->handle, buf, size) < 0) {
826 security_stream_seterror(&rs->secstr, rs->rc->errmsg);
833 * Submit a request to read some data. Calls back with the given
834 * function and arg when completed.
837 ssh_stream_read(s, fn, arg)
839 void (*fn) P((void *, void *, ssize_t));
841 struct ssh_stream *rs = s;
846 * Only one read request can be active per stream.
848 if (rs->ev_read == NULL) {
849 rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
850 stream_read_callback, rs);
858 * Cancel a previous stream read request. It's ok if we didn't have a read
862 ssh_stream_read_cancel(s)
865 struct ssh_stream *rs = s;
869 if (rs->ev_read != NULL) {
870 event_release(rs->ev_read);
872 conn_read_cancel(rs->rc);
877 * Callback for ssh_stream_read
880 stream_read_callback(arg)
883 struct ssh_stream *rs = arg;
886 sshprintf(("%s: ssh: stream_read_callback: handle %d\n", debug_prefix_time(NULL), rs->handle));
889 * Make sure this was for us. If it was, then blow away the handle
890 * so it doesn't get claimed twice. Otherwise, leave it alone.
892 * If the handle is EOF, pass that up to our callback.
894 if (rs->rc->handle == rs->handle) {
895 sshprintf(("%s: ssh: stream_read_callback: it was for us\n", debug_prefix_time(NULL)));
896 rs->rc->handle = H_TAKEN;
897 } else if (rs->rc->handle != H_EOF) {
898 sshprintf(("%s: ssh: stream_read_callback: not for us\n", debug_prefix_time(NULL)));
903 * Remove the event first, and then call the callback.
904 * We remove it first because we don't want to get in their
905 * way if they reschedule it.
907 ssh_stream_read_cancel(rs);
909 if (rs->rc->pktlen == 0) {
910 sshprintf(("%s: ssh: stream_read_callback: EOF\n", debug_prefix_time(NULL)));
911 (*rs->fn)(rs->arg, NULL, 0);
914 sshprintf(("%s: ssh: stream_read_callback: read %ld bytes from %s:%d\n", debug_prefix_time(NULL),
915 rs->rc->pktlen, rs->rc->hostname, rs->handle));
916 (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen);
920 * The callback for the netfd for the event handler
921 * Determines if this packet is for this security handle,
922 * and does the real callback if so.
925 conn_read_callback(cookie)
928 struct ssh_conn *rc = cookie;
929 struct ssh_handle *rh;
933 assert(cookie != NULL);
935 sshprintf(("%s: ssh: conn_read_callback\n",debug_prefix_time(NULL)));
937 /* Read the data off the wire. If we get errors, shut down. */
938 rval = recv_token(rc, 60);
939 sshprintf(("%s: ssh: conn_read_callback: recv_token returned %d\n", debug_prefix_time(NULL), rval));
943 rval = event_wakeup((event_id_t)rc);
944 sshprintf(("%s: ssh: conn_read_callback: event_wakeup return %d\n", debug_prefix_time(NULL), rval));
945 /* delete our 'accept' reference */
946 if (accept_fn != NULL)
952 /* If there are events waiting on this handle, we're done */
953 rval = event_wakeup((event_id_t)rc);
954 sshprintf(("%s: ssh: conn_read_callback: event_wakeup return %d\n", debug_prefix_time(NULL), rval));
958 /* If there is no accept fn registered, then drop the packet */
959 if (accept_fn == NULL)
962 rh = alloc(sizeof(*rh));
963 security_handleinit(&rh->sech, &ssh_security_driver);
964 rh->hostname = rc->hostname;
965 rh->rs = ssh_stream_client(rh, rc->handle);
966 rh->ev_timeout = NULL;
968 sshprintf(("%s: ssh: new connection\n", debug_prefix_time(NULL)));
969 parse_pkt(&pkt, rc->pkt, rc->pktlen);
970 sshprintf(("%s: ssh: calling accept_fn\n", debug_prefix_time(NULL)));
971 (*accept_fn)(&rh->sech, &pkt);
975 parse_pkt(pkt, buf, bufsize)
980 const unsigned char *bufp = buf;
982 sshprintf(("%s: ssh: parse_pkt: parsing buffer of %d bytes\n", debug_prefix_time(NULL), bufsize));
984 pkt->type = (pktype_t)*bufp++;
990 if (bufsize > sizeof(pkt->body) - 1)
991 bufsize = sizeof(pkt->body) - 1;
992 memcpy(pkt->body, bufp, bufsize);
993 pkt->body[sizeof(pkt->body) - 1] = '\0';
996 sshprintf(("%s: ssh: parse_pkt: %s (%d): \"%s\"\n", debug_prefix_time(NULL), pkt_type2str(pkt->type),
997 pkt->type, pkt->body));
1002 * Transmits a chunk of data over a ssh_handle, adding
1003 * the necessary headers to allow the remote end to decode it.
1006 send_token(rc, handle, buf, len)
1007 struct ssh_conn *rc;
1012 unsigned int netlength, nethandle;
1013 struct iovec iov[3];
1015 sshprintf(("%s: ssh: send_token: handle %d writing %d bytes to %s\n", debug_prefix_time(NULL), handle, len,
1018 assert(sizeof(netlength) == 4);
1022 * 32 bit length (network byte order)
1023 * 32 bit handle (network byte order)
1026 netlength = htonl(len);
1027 iov[0].iov_base = (void *)&netlength;
1028 iov[0].iov_len = sizeof(netlength);
1030 nethandle = htonl(handle);
1031 iov[1].iov_base = (void *)&nethandle;
1032 iov[1].iov_len = sizeof(nethandle);
1034 iov[2].iov_base = (void *)buf;
1035 iov[2].iov_len = len;
1037 if (net_writev(rc->write, iov, 3) < 0) {
1038 rc->errmsg = newvstralloc(rc->errmsg, "ssh write error to ",
1039 rc->hostname, ": ", strerror(errno), NULL);
1046 recv_token(rc, timeout)
1047 struct ssh_conn *rc;
1050 unsigned int netint;
1052 assert(sizeof(netint) == 4);
1054 assert(rc->read >= 0);
1056 sshprintf(("%s: ssh: recv_token: reading from %s\n", debug_prefix_time(NULL), rc->hostname));
1058 switch (net_read(rc, &netint, sizeof(netint), timeout)) {
1060 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1062 sshprintf(("%s: ssh: recv_token: A return(-1)\n", debug_prefix_time(NULL)));
1066 sshprintf(("%s: ssh: recv_token: A return(0)\n", debug_prefix_time(NULL)));
1071 rc->pktlen = ntohl(netint);
1072 if (rc->pktlen > sizeof(rc->pkt)) {
1073 rc->errmsg = newstralloc(rc->errmsg, "recv error: huge packet");
1074 sshprintf(("%s: ssh: recv_token: B return(-1)\n", debug_prefix_time(NULL)));
1078 switch (net_read(rc, &netint, sizeof(netint), timeout)) {
1080 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1082 sshprintf(("%s: ssh: recv_token: C return(-1)\n", debug_prefix_time(NULL)));
1086 sshprintf(("%s: ssh: recv_token: D return(0)\n", debug_prefix_time(NULL)));
1091 rc->handle = ntohl(netint);
1093 switch (net_read(rc, rc->pkt, rc->pktlen, timeout)) {
1095 rc->errmsg = newvstralloc(rc->errmsg, "recv error: ", strerror(errno),
1097 sshprintf(("%s: ssh: recv_token: E return(-1)\n", debug_prefix_time(NULL)));
1106 sshprintf(("%s: ssh: recv_token: read %ld bytes from %s\n", debug_prefix_time(NULL), rc->pktlen,
1108 sshprintf(("%s: ssh: recv_token: end %d\n", debug_prefix_time(NULL),rc->pktlen));
1109 return (rc->pktlen);
1113 * Writes out the entire iovec
1116 net_writev(fd, iov, iovcnt)
1120 int delta, n, total;
1122 assert(iov != NULL);
1125 while (iovcnt > 0) {
1129 total += n = writev(fd, iov, iovcnt);
1137 * Iterate through each iov. Figure out what we still need
1140 for (; n > 0; iovcnt--, iov++) {
1141 /* 'delta' is the bytes written from this iovec */
1142 delta = n < iov->iov_len ? n : iov->iov_len;
1143 /* subtract from the total num bytes written */
1146 /* subtract from this iovec */
1147 iov->iov_len -= delta;
1148 iov->iov_base = (char *)iov->iov_base + delta;
1149 /* if this iovec isn't empty, run the writev again */
1150 if (iov->iov_len > 0)
1158 * Like read(), but waits until the entire buffer has been filled.
1161 net_read(rc, vbuf, origsize, timeout)
1162 struct ssh_conn *rc;
1167 char *buf = vbuf, *off; /* ptr arith */
1169 size_t size = origsize;
1171 sshprintf(("%s: ssh: net_read: begin %d\n", debug_prefix_time(NULL), origsize));
1173 sshprintf(("%s: ssh: net_read: while %d\n", debug_prefix_time(NULL), size));
1174 if (rc->readbuf.left == 0) {
1175 if (net_read_fillbuf(rc, timeout, size) < 0) {
1176 sshprintf(("%s: ssh: net_read: end retrun(-1)\n", debug_prefix_time(NULL)));
1179 if (rc->readbuf.size == 0) {
1180 sshprintf(("%s: ssh: net_read: end retrun(0)\n", debug_prefix_time(NULL)));
1184 nread = min(rc->readbuf.left, size);
1185 off = rc->readbuf.buf + rc->readbuf.size - rc->readbuf.left;
1186 memcpy(buf, off, nread);
1190 rc->readbuf.left -= nread;
1192 sshprintf(("%s: ssh: net_read: end %d\n", debug_prefix_time(NULL), origsize));
1193 return ((ssize_t)origsize);
1197 * net_read likes to do a lot of little reads. Buffer it.
1200 net_read_fillbuf(rc, timeout, size)
1201 struct ssh_conn *rc;
1207 if(size > sizeof(rc->readbuf.buf)) size = sizeof(rc->readbuf.buf);
1209 sshprintf(("%s: ssh: net_read_fillbuf: begin\n", debug_prefix_time(NULL)));
1211 FD_SET(rc->read, &readfds);
1212 tv.tv_sec = timeout;
1214 switch (select(rc->read + 1, &readfds, NULL, NULL, &tv)) {
1219 sshprintf(("%s: ssh: net_read_fillbuf: case -1\n", debug_prefix_time(NULL)));
1222 sshprintf(("%s: ssh: net_read_fillbuf: case 1\n", debug_prefix_time(NULL)));
1223 assert(FD_ISSET(rc->read, &readfds));
1226 sshprintf(("%s: ssh: net_read_fillbuf: case default\n", debug_prefix_time(NULL)));
1230 rc->readbuf.left = 0;
1231 rc->readbuf.size = read(rc->read, rc->readbuf.buf, size);
1232 if (rc->readbuf.size < 0)
1234 rc->readbuf.left = rc->readbuf.size;
1235 sshprintf(("%s: ssh: net_read_fillbuf: end %d\n", debug_prefix_time(NULL),rc->readbuf.size));
1239 #endif /* SSH_SECURITY */