a55bafbbe22ed8c326b3faa8ccf50d864774e3ea
[debian/amanda] / common-src / security-util.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1999 University of Maryland
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26
27 /*
28  * $Id: security-util.c,v 1.25.2.10 2007/01/24 00:35:14 martinea Exp $
29  *
30  * sec-security.c - security and transport over sec or a sec-like command.
31  *
32  * XXX still need to check for initial keyword on connect so we can skip
33  * over shell garbage and other stuff that sec might want to spew out.
34  */
35
36 #include "amanda.h"
37 #include "util.h"
38 #include "event.h"
39 #include "packet.h"
40 #include "queue.h"
41 #include "security.h"
42 #include "security-util.h"
43 #include "stream.h"
44 #include "version.h"
45
46 /* #define      SEC_DEBUG */
47 #define SHOW_SECURITY_DETAIL
48
49 #ifdef SEC_DEBUG
50 #  define       secprintf(x)    dbprintf(x)
51 #else
52 #  ifdef __lint
53 #    define     secprintf(x)    (void)(x)
54 #  else
55 #    define     secprintf(x)
56 #  endif
57 #endif
58
59 /*
60  * Magic values for sec_conn->handle
61  */
62 #define H_TAKEN -1              /* sec_conn->tok was already read */
63 #define H_EOF   -2              /* this connection has been shut down */
64
65 /*
66  * This is a queue of open connections
67  */
68 struct connq_s connq = {
69     TAILQ_HEAD_INITIALIZER(connq.tailq), 0
70 };
71 static int newhandle = 1;
72 static int newevent = 1;
73
74 /*
75  * Local functions
76  */
77 static void recvpkt_callback(void *, void *, ssize_t);
78 static void stream_read_callback(void *);
79 static void stream_read_sync_callback(void *);
80
81 static void sec_tcp_conn_read_cancel(struct tcp_conn *);
82 static void sec_tcp_conn_read_callback(void *);
83
84
85 /*
86  * Authenticate a stream
87  * Nothing needed for sec.  The connection is authenticated by secd
88  * on startup.
89  */
90 int
91 sec_stream_auth(
92     void *      s)
93 {
94     (void)s;    /* Quiet unused parameter warning */
95     return (0);
96 }
97
98 /*
99  * Returns the stream id for this stream.  This is just the local
100  * port.
101  */
102 int
103 sec_stream_id(
104     void *      s)
105 {
106     struct sec_stream *rs = s;
107
108     assert(rs != NULL);
109
110     return (rs->handle);
111 }
112
113 /*
114  * Setup to handle new incoming connections
115  */
116 void
117 sec_accept(
118     const security_driver_t *driver,
119     int         in,
120     int         out,
121     void        (*fn)(security_handle_t *, pkt_t *))
122 {
123     struct tcp_conn *rc;
124
125     rc = sec_tcp_conn_get("unknown",0);
126     rc->read = in;
127     rc->write = out;
128     rc->accept_fn = fn;
129     rc->driver = driver;
130     sec_tcp_conn_read(rc);
131 }
132
133 /*
134  * frees a handle allocated by the above
135  */
136 void
137 sec_close(
138     void *      inst)
139 {
140     struct sec_handle *rh = inst;
141
142     assert(rh != NULL);
143
144     secprintf(("%s: sec: closing handle to %s\n", debug_prefix_time(NULL),
145                rh->hostname));
146
147     if (rh->rs != NULL) {
148         /* This may be null if we get here on an error */
149         stream_recvpkt_cancel(rh);
150         security_stream_close(&rh->rs->secstr);
151     }
152     /* keep us from getting here again */
153     rh->sech.driver = NULL;
154     amfree(rh->hostname);
155     amfree(rh);
156 }
157
158 /*
159  * Called when a sec connection is finished connecting and is ready
160  * to be authenticated.
161  */
162 void
163 sec_connect_callback(
164     void *      cookie)
165 {
166     struct sec_handle *rh = cookie;
167
168     event_release(rh->rs->ev_read);
169     rh->rs->ev_read = NULL;
170     event_release(rh->ev_timeout);
171     rh->ev_timeout = NULL;
172
173     (*rh->fn.connect)(rh->arg, &rh->sech, S_OK);
174 }
175
176 /*
177  * Called if a connection times out before completion.
178  */
179 void
180 sec_connect_timeout(
181     void *      cookie)
182 {
183     struct sec_handle *rh = cookie;
184
185     event_release(rh->rs->ev_read);
186     rh->rs->ev_read = NULL;
187     event_release(rh->ev_timeout);
188     rh->ev_timeout = NULL;
189
190     (*rh->fn.connect)(rh->arg, &rh->sech, S_TIMEOUT);
191 }
192
193 void
194 sec_close_connection_none(
195     void *h,
196     char *hostname)
197 {
198     h = h;
199     hostname = hostname;
200
201     return;
202 }
203
204
205
206 /*
207  * Transmit a packet.
208  */
209 ssize_t
210 stream_sendpkt(
211     void *      cookie,
212     pkt_t *     pkt)
213 {
214     char *buf;
215     struct sec_handle *rh = cookie;
216     size_t len;
217     char *s;
218
219     assert(rh != NULL);
220     assert(pkt != NULL);
221
222     secprintf(("%s: sec: stream_sendpkt: enter\n", debug_prefix_time(NULL)));
223
224     if (rh->rc->prefix_packet)
225         s = rh->rc->prefix_packet(rh, pkt);
226     else
227         s = "";
228     len = strlen(pkt->body) + strlen(s) + 2;
229     buf = alloc(len);
230     buf[0] = (char)pkt->type;
231     strncpy(&buf[1], s, len - 1);
232     strncpy(&buf[1 + strlen(s)], pkt->body, (len - strlen(s) - 1));
233     if (strlen(s) > 0)
234         amfree(s);
235
236     secprintf((
237             "%s: sec: stream_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
238             debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
239             strlen(pkt->body), pkt->body));
240
241     if (security_stream_write(&rh->rs->secstr, buf, len) < 0) {
242         security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
243         return (-1);
244     }
245     amfree(buf);
246     return (0);
247 }
248
249 /*
250  * Set up to receive a packet asyncronously, and call back when
251  * it has been read.
252  */
253 void
254 stream_recvpkt(
255     void *      cookie,
256     void        (*fn)(void *, pkt_t *, security_status_t),
257     void *      arg,
258     int         timeout)
259 {
260     struct sec_handle *rh = cookie;
261
262     assert(rh != NULL);
263
264     secprintf(("%s: sec: recvpkt registered for %s\n",
265                debug_prefix_time(NULL), rh->hostname));
266
267     /*
268      * Reset any pending timeout on this handle
269      */
270     if (rh->ev_timeout != NULL)
271         event_release(rh->ev_timeout);
272
273     /*
274      * Negative timeouts mean no timeout
275      */
276     if (timeout < 0) {
277         rh->ev_timeout = NULL;
278     } else {
279         rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
280                 stream_recvpkt_timeout, rh);
281     }
282     rh->fn.recvpkt = fn;
283     rh->arg = arg;
284     security_stream_read(&rh->rs->secstr, recvpkt_callback, rh);
285 }
286
287 /*
288  * This is called when a handle times out before receiving a packet.
289  */
290 void
291 stream_recvpkt_timeout(
292     void *      cookie)
293 {
294     struct sec_handle *rh = cookie;
295
296     assert(rh != NULL);
297
298     secprintf(("%s: sec: recvpkt timeout for %s\n",
299                debug_prefix_time(NULL), rh->hostname));
300
301     stream_recvpkt_cancel(rh);
302     (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);
303 }
304
305 /*
306  * Remove a async receive request from the queue
307  */
308 void
309 stream_recvpkt_cancel(
310     void *      cookie)
311 {
312     struct sec_handle *rh = cookie;
313
314     secprintf(("%s: sec: cancelling recvpkt for %s\n",
315                debug_prefix_time(NULL), rh->hostname));
316
317     assert(rh != NULL);
318
319     security_stream_read_cancel(&rh->rs->secstr);
320     if (rh->ev_timeout != NULL) {
321         event_release(rh->ev_timeout);
322         rh->ev_timeout = NULL;
323     }
324 }
325
326 /*
327  * Write a chunk of data to a stream.  Blocks until completion.
328  */
329 int
330 tcpm_stream_write(
331     void *      s,
332     const void *buf,
333     size_t      size)
334 {
335     struct sec_stream *rs = s;
336
337     assert(rs != NULL);
338     assert(rs->rc != NULL);
339
340     secprintf(("%s: sec: stream_write: writing %d bytes to %s:%d %d\n",
341                debug_prefix_time(NULL), size, rs->rc->hostname, rs->handle,
342                rs->rc->write));
343
344     if (tcpm_send_token(rs->rc->write, rs->handle, &rs->rc->errmsg,
345                              buf, size)) {
346         security_stream_seterror(&rs->secstr, rs->rc->errmsg);
347         return (-1);
348     }
349     return (0);
350 }
351
352 /*
353  * Submit a request to read some data.  Calls back with the given
354  * function and arg when completed.
355  */
356 void
357 tcpm_stream_read(
358     void *      s,
359     void        (*fn)(void *, void *, ssize_t),
360     void *      arg)
361 {
362     struct sec_stream *rs = s;
363
364     assert(rs != NULL);
365
366     /*
367      * Only one read request can be active per stream.
368      */
369     if (rs->ev_read == NULL) {
370         rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
371             stream_read_callback, rs);
372         sec_tcp_conn_read(rs->rc);
373     }
374     rs->fn = fn;
375     rs->arg = arg;
376 }
377
378 /*
379  * Write a chunk of data to a stream.  Blocks until completion.
380  */
381 ssize_t
382 tcpm_stream_read_sync(
383     void *      s,
384     void **     buf)
385 {
386     struct sec_stream *rs = s;
387
388     assert(rs != NULL);
389
390     /*
391      * Only one read request can be active per stream.
392      */
393     if (rs->ev_read != NULL) {
394         return -1;
395     }
396     rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
397         stream_read_sync_callback, rs);
398     sec_tcp_conn_read(rs->rc);
399     event_wait(rs->ev_read);
400     *buf = rs->rc->pkt;
401     return (rs->rc->pktlen);
402 }
403
404 /*
405  * Cancel a previous stream read request.  It's ok if we didn't have a read
406  * scheduled.
407  */
408 void
409 tcpm_stream_read_cancel(
410     void *      s)
411 {
412     struct sec_stream *rs = s;
413
414     assert(rs != NULL);
415
416     if (rs->ev_read != NULL) {
417         event_release(rs->ev_read);
418         rs->ev_read = NULL;
419         sec_tcp_conn_read_cancel(rs->rc);
420     }
421 }
422
423 /*
424  * Transmits a chunk of data over a rsh_handle, adding
425  * the necessary headers to allow the remote end to decode it.
426  */
427 ssize_t
428 tcpm_send_token(
429     int         fd,
430     int         handle,
431     char **     errmsg,
432     const void *buf,
433     size_t      len)
434 {
435     uint32_t            nethandle;
436     uint32_t            netlength;
437     struct iovec        iov[3];
438     int                 nb_iov = 3;
439
440     assert(SIZEOF(netlength) == 4);
441
442     /*
443      * Format is:
444      *   32 bit length (network byte order)
445      *   32 bit handle (network byte order)
446      *   data
447      */
448     netlength = htonl(len);
449     iov[0].iov_base = (void *)&netlength;
450     iov[0].iov_len = SIZEOF(netlength);
451
452     nethandle = htonl((uint32_t)handle);
453     iov[1].iov_base = (void *)&nethandle;
454     iov[1].iov_len = SIZEOF(nethandle);
455
456     if(len == 0) {
457         nb_iov = 2;
458     }
459     else {
460         iov[2].iov_base = (void *)buf;
461         iov[2].iov_len = len;
462         nb_iov = 3;
463     }
464
465     if (net_writev(fd, iov, nb_iov) < 0) {
466         if (errmsg)
467             *errmsg = newvstralloc(*errmsg, "write error to ",
468                                    ": ", strerror(errno), NULL);
469         return (-1);
470     }
471     return (0);
472 }
473
474 /*
475  *  return -1 on error
476  *  return  0 on EOF:   *handle = H_EOF  && *size = 0    if socket closed
477  *  return  0 on EOF:   *handle = handle && *size = 0    if stream closed
478  *  return size     :   *handle = handle && *size = size for data read
479  */
480
481 ssize_t
482 tcpm_recv_token(
483     int         fd,
484     int *       handle,
485     char **     errmsg,
486     char **     buf,
487     ssize_t *   size,
488     int         timeout)
489 {
490     unsigned int netint[2];
491
492     assert(SIZEOF(netint) == 8);
493
494     switch (net_read(fd, &netint, SIZEOF(netint), timeout)) {
495     case -1:
496         if (errmsg)
497             *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
498                                    NULL);
499         secprintf(("%s: tcpm_recv_token: A return(-1)\n",
500                    debug_prefix_time(NULL)));
501         return (-1);
502     case 0:
503         *size = 0;
504         *handle = H_EOF;
505         *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
506         secprintf(("%s: tcpm_recv_token: A return(0)\n",
507                    debug_prefix_time(NULL)));
508         return (0);
509     default:
510         break;
511     }
512
513     *size = (ssize_t)ntohl(netint[0]);
514     *handle = (int)ntohl(netint[1]);
515     /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
516     if (*size > 128*NETWORK_BLOCK_BYTES || *size < 0) {
517         if (isprint((*size        ) & 0xFF) &&
518             isprint((*size   >> 8 ) & 0xFF) &&
519             isprint((*size   >> 16) & 0xFF) &&
520             isprint((*size   >> 24) & 0xFF) &&
521             isprint((*handle      ) & 0xFF) &&
522             isprint((*handle >> 8 ) & 0xFF) &&
523             isprint((*handle >> 16) & 0xFF) &&
524             isprint((*handle >> 24) & 0xFF)) {
525             char s[101];
526             int i;
527             s[0] = (*size   >> 24) & 0xFF;
528             s[1] = (*size   >> 16) & 0xFF;
529             s[2] = (*size   >>  8) & 0xFF;
530             s[3] = (*size        ) & 0xFF;
531             s[4] = (*handle >> 24) & 0xFF;
532             s[5] = (*handle >> 16) & 0xFF;
533             s[6] = (*handle >> 8 ) & 0xFF;
534             s[7] = (*handle      ) & 0xFF;
535             i = 8; s[i] = ' ';
536             while(i<100 && isprint(s[i]) && s[i] != '\n') {
537                 switch(net_read(fd, &s[i], 1, 0)) {
538                 case -1: s[i] = '\0'; break;
539                 case  0: s[i] = '\0'; break;
540                 default: dbprintf(("read: %c\n", s[i])); i++; s[i]=' ';break;
541                 }
542             }
543             s[i] = '\0';
544             *errmsg = newvstralloc(*errmsg, "tcpm_recv_token: invalid size: ",
545                                    s, NULL);
546             dbprintf(("%s: tcpm_recv_token: invalid size: %s\n",
547                       debug_prefix_time(NULL), s));
548         } else {
549             *errmsg = newvstralloc(*errmsg, "tcpm_recv_token: invalid size",
550                                    NULL);
551             dbprintf(("%s: tcpm_recv_token: invalid size %zd\n",
552                       debug_prefix_time(NULL), *size));
553         }
554         *size = -1;
555         return -1;
556     }
557     amfree(*buf);
558     *buf = alloc((size_t)*size);
559
560     if(*size == 0) {
561         secprintf(("%s: tcpm_recv_token: read EOF from %d\n",
562                    debug_prefix_time(NULL), *handle));
563         *errmsg = newvstralloc(*errmsg, "EOF",
564                                    NULL);
565         return 0;
566     }
567     switch (net_read(fd, *buf, (size_t)*size, timeout)) {
568     case -1:
569         if (errmsg)
570             *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
571                                    NULL);
572         secprintf(("%s: tcpm_recv_token: B return(-1)\n",
573                    debug_prefix_time(NULL)));
574         return (-1);
575     case 0:
576         *size = 0;
577         *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
578         secprintf(("%s: tcpm_recv_token: B return(0)\n",
579                    debug_prefix_time(NULL)));
580         return (0);
581     default:
582         break;
583     }
584
585     secprintf(("%s: tcpm_recv_token: read %zd bytes from %d\n",
586                debug_prefix_time(NULL), *size, *handle));
587     return((*size));
588 }
589
590 void
591 tcpm_close_connection(
592     void *h,
593     char *hostname)
594 {
595     struct sec_handle *rh = h;
596
597     hostname = hostname;
598
599     if(rh->rc->toclose == 0) {
600         rh->rc->toclose = 1;
601         sec_tcp_conn_put(rh->rc);
602     }
603 }
604
605
606
607 /*
608  * Accept an incoming connection on a stream_server socket
609  * Nothing needed for tcpma.
610  */
611 int
612 tcpma_stream_accept(
613     void *      s)
614 {
615     (void)s;    /* Quiet unused parameter warning */
616
617     return (0);
618 }
619
620 /*
621  * Return a connected stream.  For sec, this means setup a stream
622  * with the supplied handle.
623  */
624 void *
625 tcpma_stream_client(
626     void *      h,
627     int         id)
628 {
629     struct sec_handle *rh = h;
630     struct sec_stream *rs;
631
632     assert(rh != NULL);
633
634     if (id <= 0) {
635         security_seterror(&rh->sech,
636             "%d: invalid security stream id", id);
637         return (NULL);
638     }
639
640     rs = alloc(SIZEOF(*rs));
641     security_streaminit(&rs->secstr, rh->sech.driver);
642     rs->handle = id;
643     rs->ev_read = NULL;
644     rs->closed_by_me = 0;
645     rs->closed_by_network = 0;
646     if (rh->rc) {
647         rs->rc = rh->rc;
648         rh->rc->refcnt++;
649     }
650     else {
651         rs->rc = sec_tcp_conn_get(rh->hostname, 0);
652         rs->rc->driver = rh->sech.driver;
653         rh->rc = rs->rc;
654     }
655
656     secprintf(("%s: sec: stream_client: connected to stream %d\n",
657                debug_prefix_time(NULL), id));
658
659     return (rs);
660 }
661
662 /*
663  * Create the server end of a stream.  For sec, this means setup a stream
664  * object and allocate a new handle for it.
665  */
666 void *
667 tcpma_stream_server(
668     void *      h)
669 {
670     struct sec_handle *rh = h;
671     struct sec_stream *rs;
672
673     assert(rh != NULL);
674
675     rs = alloc(SIZEOF(*rs));
676     security_streaminit(&rs->secstr, rh->sech.driver);
677     rs->closed_by_me = 0;
678     rs->closed_by_network = 0;
679     if (rh->rc) {
680         rs->rc = rh->rc;
681         rs->rc->refcnt++;
682     }
683     else {
684         rs->rc = sec_tcp_conn_get(rh->hostname, 0);
685         rs->rc->driver = rh->sech.driver;
686         rh->rc = rs->rc;
687     }
688     /*
689      * Stream should already be setup!
690      */
691     if (rs->rc->read < 0) {
692         sec_tcp_conn_put(rs->rc);
693         amfree(rs);
694         security_seterror(&rh->sech, "lost connection to %s", rh->hostname);
695         return (NULL);
696     }
697     assert(strcmp(rh->hostname, rs->rc->hostname) == 0);
698     /*
699      * so as not to conflict with the amanda server's handle numbers,
700      * we start at 500000 and work down
701      */
702     rs->handle = 500000 - newhandle++;
703     rs->ev_read = NULL;
704     secprintf(("%s: sec: stream_server: created stream %d\n",
705                debug_prefix_time(NULL), rs->handle));
706     return (rs);
707 }
708
709 /*
710  * Close and unallocate resources for a stream.
711  */
712 void
713 tcpma_stream_close(
714     void *      s)
715 {
716     struct sec_stream *rs = s;
717     char buf = 0;
718
719     assert(rs != NULL);
720
721     secprintf(("%s: sec: tcpma_stream_close: closing stream %d\n",
722                debug_prefix_time(NULL), rs->handle));
723
724     if(rs->closed_by_network == 0 && rs->rc->write != -1)
725         tcpm_stream_write(rs, &buf, 0);
726     security_stream_read_cancel(&rs->secstr);
727     if(rs->closed_by_network == 0)
728         sec_tcp_conn_put(rs->rc);
729     amfree(rs);
730 }
731
732 /*
733  * Create the server end of a stream.  For bsdudp, this means setup a tcp
734  * socket for receiving a connection.
735  */
736 void *
737 tcp1_stream_server(
738     void *      h)
739 {
740     struct sec_stream *rs = NULL;
741     struct sec_handle *rh = h;
742
743     assert(rh != NULL);
744
745     rs = alloc(SIZEOF(*rs));
746     security_streaminit(&rs->secstr, rh->sech.driver);
747     rs->closed_by_me = 0;
748     rs->closed_by_network = 0;
749     if (rh->rc) {
750         rs->rc = rh->rc;
751         rs->handle = 500000 - newhandle++;
752         rs->rc->refcnt++;
753         rs->socket = 0;         /* the socket is already opened */
754     }
755     else {
756         rh->rc = sec_tcp_conn_get(rh->hostname, 1);
757         rh->rc->driver = rh->sech.driver;
758         rs->rc = rh->rc;
759         rs->socket = stream_server(&rs->port, STREAM_BUFSIZE, 
760                 STREAM_BUFSIZE, 0);
761         if (rs->socket < 0) {
762             security_seterror(&rh->sech,
763                             "can't create server stream: %s", strerror(errno));
764             amfree(rs);
765             return (NULL);
766         }
767         rh->rc->read = rs->socket;
768         rh->rc->write = rs->socket;
769         rs->handle = (int)rs->port;
770     }
771     rs->fd = -1;
772     rs->ev_read = NULL;
773     return (rs);
774 }
775
776 /*
777  * Accepts a new connection on unconnected streams.  Assumes it is ok to
778  * block on accept()
779  */
780 int
781 tcp1_stream_accept(
782     void *      s)
783 {
784     struct sec_stream *bs = s;
785
786     assert(bs != NULL);
787     assert(bs->socket != -1);
788     assert(bs->fd < 0);
789
790     if (bs->socket > 0) {
791         bs->fd = stream_accept(bs->socket, 30, STREAM_BUFSIZE, STREAM_BUFSIZE);
792         if (bs->fd < 0) {
793             security_stream_seterror(&bs->secstr,
794                                      "can't accept new stream connection: %s",
795                                      strerror(errno));
796             return (-1);
797         }
798         bs->rc->read = bs->fd;
799         bs->rc->write = bs->fd;
800     }
801     return (0);
802 }
803
804 /*
805  * Return a connected stream
806  */
807 void *
808 tcp1_stream_client(
809     void *      h,
810     int         id)
811 {
812     struct sec_stream *rs = NULL;
813     struct sec_handle *rh = h;
814
815     assert(rh != NULL);
816
817     rs = alloc(SIZEOF(*rs));
818     security_streaminit(&rs->secstr, rh->sech.driver);
819     rs->handle = id;
820     rs->ev_read = NULL;
821     rs->closed_by_me = 0;
822     rs->closed_by_network = 0;
823     if (rh->rc) {
824         rs->rc = rh->rc;
825         rh->rc->refcnt++;
826     }
827     else {
828         rh->rc = sec_tcp_conn_get(rh->hostname, 1);
829         rs->rc = rh->rc;
830         rh->rc->read = stream_client(rh->hostname, (in_port_t)id,
831                         STREAM_BUFSIZE, STREAM_BUFSIZE, &rs->port, 0);
832         if (rh->rc->read < 0) {
833             security_seterror(&rh->sech,
834                               "can't connect stream to %s port %d: %s",
835                                rh->hostname, id, strerror(errno));
836             amfree(rs);
837             return (NULL);
838         }
839         rh->rc->write = rh->rc->read;
840     }
841     rs->socket = -1;    /* we're a client */
842     rh->rs = rs;
843     return (rs);
844 }
845
846 int
847 tcp_stream_write(
848     void *      s,
849     const void *buf,
850     size_t      size)
851 {
852     struct sec_stream *rs = s;
853
854     assert(rs != NULL);
855
856     if (fullwrite(rs->fd, buf, size) < 0) {
857         security_stream_seterror(&rs->secstr,
858             "write error on stream %d: %s", rs->port, strerror(errno));
859         return (-1);
860     }
861     return (0);
862 }
863
864 char *
865 bsd_prefix_packet(
866     void *      h,
867     pkt_t *     pkt)
868 {
869     struct sec_handle *rh = h;
870     struct passwd *pwd;
871     char *buf;
872
873     if (pkt->type != P_REQ)
874         return "";
875
876     if ((pwd = getpwuid(getuid())) == NULL) {
877         security_seterror(&rh->sech,
878                           "can't get login name for my uid %ld",
879                           (long)getuid());
880         return(NULL);
881     }
882     buf = alloc(16+strlen(pwd->pw_name));
883     strncpy(buf, "SECURITY USER ", (16 + strlen(pwd->pw_name)));
884     strncpy(&buf[14], pwd->pw_name, (16 + strlen(pwd->pw_name) - 14));
885     buf[14 + strlen(pwd->pw_name)] = '\n';
886     buf[15 + strlen(pwd->pw_name)] = '\0';
887
888     return (buf);
889 }
890
891
892 /*
893  * Check the security of a received packet.  Returns negative on security
894  * violation, or returns 0 if ok.  Removes the security info from the pkt_t.
895  */
896 int
897 bsd_recv_security_ok(
898     struct sec_handle * rh,
899     pkt_t *             pkt)
900 {
901     char *tok, *security, *body, *result;
902     char *service = NULL, *serviceX, *serviceY;
903     char *security_line;
904     size_t len;
905
906     /*
907      * Now, find the SECURITY line in the body, and parse it out
908      * into an argv.
909      */
910     if (strncmp(pkt->body, "SECURITY ", SIZEOF("SECURITY ") - 1) == 0) {
911         security = pkt->body;
912         len = 0;
913         while(*security != '\n' && len < pkt->size) {
914             security++;
915             len++;
916         }
917         if(*security == '\n') {
918             body = security+1;
919             *security = '\0';
920             security_line = stralloc(pkt->body);
921             security = pkt->body + strlen("SECURITY ");
922         } else {
923             body = pkt->body;
924             security_line = NULL;
925             security = NULL;
926         }
927     } else {
928         body = pkt->body;
929         security_line = NULL;
930         security = NULL;
931     }
932
933     /*
934      * Now, find the SERVICE line in the body, and parse it out
935      * into an argv.
936      */
937     if (strncmp(body, "SERVICE", SIZEOF("SERVICE") - 1) == 0) {
938         serviceX = stralloc(body + strlen("SERVICE "));
939         serviceY = strtok(serviceX, "\n");
940         if (serviceY)
941             service  = stralloc(serviceY);
942         amfree(serviceX);
943     }
944
945     /*
946      * We need to do different things depending on which type of packet
947      * this is.
948      */
949     switch (pkt->type) {
950     case P_REQ:
951         /*
952          * Request packets must come from a reserved port
953          */
954         if (ntohs(rh->peer.sin_port) >= IPPORT_RESERVED) {
955             security_seterror(&rh->sech,
956                 "host %s: port %d not secure", rh->hostname,
957                 ntohs(rh->peer.sin_port));
958             amfree(service);
959             amfree(security_line);
960             return (-1);
961         }
962
963         if (!service) {
964             security_seterror(&rh->sech,
965                               "packet as no SERVICE line");
966             amfree(security_line);
967             return (-1);
968         }
969
970         /*
971          * Request packets contain a remote username.  We need to check
972          * that we allow it in.
973          *
974          * They will look like:
975          *      SECURITY USER [username]
976          */
977
978         /* there must be some security info */
979         if (security == NULL) {
980             security_seterror(&rh->sech,
981                 "no bsd SECURITY for P_REQ");
982             amfree(service);
983             return (-1);
984         }
985
986         /* second word must be USER */
987         if ((tok = strtok(security, " ")) == NULL) {
988             security_seterror(&rh->sech,
989                 "SECURITY line: %s", security_line);
990             amfree(service);
991             amfree(security_line);
992             return (-1);        /* default errmsg */
993         }
994         if (strcmp(tok, "USER") != 0) {
995             security_seterror(&rh->sech,
996                 "REQ SECURITY line parse error, expecting USER, got %s", tok);
997             amfree(service);
998             amfree(security_line);
999             return (-1);
1000         }
1001
1002         /* the third word is the username */
1003         if ((tok = strtok(NULL, "")) == NULL) {
1004             security_seterror(&rh->sech,
1005                 "SECURITY line: %s", security_line);
1006             amfree(security_line);
1007             return (-1);        /* default errmsg */
1008         }
1009         if ((result = check_user(rh, tok, service)) != NULL) {
1010             security_seterror(&rh->sech, "%s", result);
1011             amfree(service);
1012             amfree(result);
1013             amfree(security_line);
1014             return (-1);
1015         }
1016
1017         /* we're good to go */
1018         break;
1019     default:
1020         break;
1021     }
1022     amfree(service);
1023     amfree(security_line);
1024
1025     /*
1026      * If there is security info at the front of the packet, we need to
1027      * shift the rest of the data up and nuke it.
1028      */
1029     if (body != pkt->body)
1030         memmove(pkt->body, body, strlen(body) + 1);
1031     return (0);
1032 }
1033
1034 /*
1035  * Transmit a packet.  Add security information first.
1036  */
1037 ssize_t
1038 udpbsd_sendpkt(
1039     void *      cookie,
1040     pkt_t *     pkt)
1041 {
1042     struct sec_handle *rh = cookie;
1043     struct passwd *pwd;
1044
1045     assert(rh != NULL);
1046     assert(pkt != NULL);
1047
1048     secprintf(("%s: udpbsd_sendpkt: enter\n", get_pname()));
1049     /*
1050      * Initialize this datagram, and add the header
1051      */
1052     dgram_zero(&rh->udp->dgram);
1053     dgram_cat(&rh->udp->dgram, pkthdr2str(rh, pkt));
1054
1055     /*
1056      * Add the security info.  This depends on which kind of packet we're
1057      * sending.
1058      */
1059     switch (pkt->type) {
1060     case P_REQ:
1061         /*
1062          * Requests get sent with our username in the body
1063          */
1064         if ((pwd = getpwuid(geteuid())) == NULL) {
1065             security_seterror(&rh->sech,
1066                 "can't get login name for my uid %ld", (long)getuid());
1067             return (-1);
1068         }
1069         dgram_cat(&rh->udp->dgram, "SECURITY USER %s\n", pwd->pw_name);
1070         break;
1071
1072     default:
1073         break;
1074     }
1075
1076     /*
1077      * Add the body, and send it
1078      */
1079     dgram_cat(&rh->udp->dgram, pkt->body);
1080
1081     secprintf((
1082             "%s: sec: udpbsd_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
1083             debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
1084             strlen(pkt->body), pkt->body));
1085
1086     if (dgram_send_addr(rh->peer, &rh->udp->dgram) != 0) {
1087         security_seterror(&rh->sech,
1088             "send %s to %s failed: %s", pkt_type2str(pkt->type),
1089             rh->hostname, strerror(errno));
1090         return (-1);
1091     }
1092     return (0);
1093 }
1094
1095 void
1096 udp_close(
1097     void *      cookie)
1098 {
1099     struct sec_handle *rh = cookie;
1100
1101     if (rh->proto_handle == NULL) {
1102         return;
1103     }
1104
1105     secprintf(("%s: udp: close handle '%s'\n",
1106                debug_prefix_time(NULL), rh->proto_handle));
1107
1108     udp_recvpkt_cancel(rh);
1109     if (rh->next) {
1110         rh->next->prev = rh->prev;
1111     }
1112     else {
1113         rh->udp->bh_last = rh->prev;
1114     }
1115     if (rh->prev) {
1116         rh->prev->next = rh->next;
1117     }
1118     else {
1119         rh->udp->bh_first = rh->next;
1120     }
1121
1122     amfree(rh->proto_handle);
1123     amfree(rh->hostname);
1124     amfree(rh);
1125 }
1126
1127 /*
1128  * Set up to receive a packet asynchronously, and call back when it has
1129  * been read.
1130  */
1131 void
1132 udp_recvpkt(
1133     void *      cookie,
1134     void        (*fn)(void *, pkt_t *, security_status_t),
1135     void *      arg,
1136     int         timeout)
1137 {
1138     struct sec_handle *rh = cookie;
1139
1140     secprintf(("%s: udp_recvpkt(cookie=%p, fn=%p, arg=%p, timeout=%u)\n",
1141         debug_prefix(NULL), cookie, fn, arg, timeout));
1142     assert(rh != NULL);
1143     assert(fn != NULL);
1144
1145
1146     /*
1147      * Subsequent recvpkt calls override previous ones
1148      */
1149     if (rh->ev_read == NULL) {
1150         udp_addref(rh->udp, &udp_netfd_read_callback);
1151         rh->ev_read = event_register(rh->event_id, EV_WAIT,
1152             udp_recvpkt_callback, rh);
1153     }
1154     if (rh->ev_timeout != NULL)
1155         event_release(rh->ev_timeout);
1156     if (timeout < 0)
1157         rh->ev_timeout = NULL;
1158     else
1159         rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
1160                                         udp_recvpkt_timeout, rh);
1161     rh->fn.recvpkt = fn;
1162     rh->arg = arg;
1163 }
1164
1165 /*
1166  * Remove a async receive request on this handle from the queue.
1167  * If it is the last one to be removed, then remove the event
1168  * handler for our network fd
1169  */
1170 void
1171 udp_recvpkt_cancel(
1172     void *      cookie)
1173 {
1174     struct sec_handle *rh = cookie;
1175
1176     assert(rh != NULL);
1177
1178     if (rh->ev_read != NULL) {
1179         udp_delref(rh->udp);
1180         event_release(rh->ev_read);
1181         rh->ev_read = NULL;
1182     }
1183
1184     if (rh->ev_timeout != NULL) {
1185         event_release(rh->ev_timeout);
1186         rh->ev_timeout = NULL;
1187     }
1188 }
1189
1190 /*
1191  * This is called when a handle is woken up because data read off of the
1192  * net is for it.
1193  */
1194 void
1195 udp_recvpkt_callback(
1196     void *      cookie)
1197 {
1198     struct sec_handle *rh = cookie;
1199     void (*fn)(void *, pkt_t *, security_status_t);
1200     void *arg;
1201
1202     secprintf(("%s: udp: receive handle '%s' netfd '%s'\n",
1203                debug_prefix_time(NULL), rh->proto_handle, rh->udp->handle));
1204     assert(rh != NULL);
1205
1206     if (strcmp(rh->proto_handle, rh->udp->handle) != 0) assert(1);
1207     /* if it didn't come from the same host/port, forget it */
1208     if (memcmp(&rh->peer.sin_addr, &rh->udp->peer.sin_addr,
1209         SIZEOF(rh->udp->peer.sin_addr)) != 0 ||
1210         rh->peer.sin_port != rh->udp->peer.sin_port) {
1211         amfree(rh->udp->handle);
1212         return;
1213     }
1214
1215     /*
1216      * We need to cancel the recvpkt request before calling the callback
1217      * because the callback may reschedule us.
1218      */
1219     fn = rh->fn.recvpkt;
1220     arg = rh->arg;
1221     udp_recvpkt_cancel(rh);
1222
1223     /*
1224      * Check the security of the packet.  If it is bad, then pass NULL
1225      * to the packet handling function instead of a packet.
1226      */
1227     if (rh->udp->recv_security_ok &&
1228         rh->udp->recv_security_ok(rh, &rh->udp->pkt) < 0)
1229         (*fn)(arg, NULL, S_ERROR);
1230     else
1231         (*fn)(arg, &rh->udp->pkt, S_OK);
1232 }
1233
1234 /*
1235  * This is called when a handle times out before receiving a packet.
1236  */
1237 void
1238 udp_recvpkt_timeout(
1239     void *      cookie)
1240 {
1241     struct sec_handle *rh = cookie;
1242     void (*fn)(void *, pkt_t *, security_status_t);
1243     void *arg;
1244
1245     assert(rh != NULL);
1246
1247     assert(rh->ev_timeout != NULL);
1248     fn = rh->fn.recvpkt;
1249     arg = rh->arg;
1250     udp_recvpkt_cancel(rh);
1251     (*fn)(arg, NULL, S_TIMEOUT);
1252 }
1253
1254 /*
1255  * Given a hostname and a port, setup a udp_handle
1256  */
1257 int
1258 udp_inithandle(
1259     udp_handle_t *      udp,
1260     struct sec_handle * rh,
1261     struct hostent *    he,
1262     in_port_t           port,
1263     char *              handle,
1264     int                 sequence)
1265 {
1266     int i;
1267
1268     /*
1269      * Save the hostname and port info
1270      */
1271     secprintf(("%s: udp_inithandle port %u handle %s sequence %d\n",
1272                debug_prefix_time(NULL), (unsigned int)ntohs(port),
1273                handle, sequence));
1274     assert(he != NULL);
1275
1276     rh->hostname = stralloc(he->h_name);
1277     memcpy(&rh->peer.sin_addr, he->h_addr, SIZEOF(rh->peer.sin_addr));
1278     rh->peer.sin_port = port;
1279     rh->peer.sin_family = (sa_family_t)AF_INET;
1280
1281     /*
1282      * Do a forward lookup of the hostname.  This is unnecessary if we
1283      * are initiating the connection, but is very serious if we are
1284      * receiving.  We want to make sure the hostname
1285      * resolves back to the remote ip for security reasons.
1286      */
1287     if ((he = gethostbyname(rh->hostname)) == NULL) {
1288     secprintf(("%s: udp: bb\n", debug_prefix_time(NULL)));
1289         security_seterror(&rh->sech,
1290             "%s: could not resolve hostname", rh->hostname);
1291         return (-1);
1292     }
1293
1294     /*
1295      * Make sure the hostname matches.  This should always work.
1296      */
1297     if (strncasecmp(rh->hostname, he->h_name, strlen(rh->hostname)) != 0) {
1298     secprintf(("%s: udp: cc\n", debug_prefix_time(NULL)));
1299         security_seterror(&rh->sech,
1300                           "%s: did not resolve to itself, it resolv to %s",
1301                           rh->hostname, he->h_name);
1302         return (-1);
1303     }
1304
1305     /*
1306      * Now look for a matching ip address.
1307      */
1308     for (i = 0; he->h_addr_list[i] != NULL; i++) {
1309         if (memcmp(&rh->peer.sin_addr, he->h_addr_list[i],
1310             SIZEOF(struct in_addr)) == 0) {
1311             break;
1312         }
1313     }
1314
1315     /*
1316      * If we didn't find it, try the aliases.  This is a workaround for
1317      * Solaris if DNS goes over NIS.
1318      */
1319     if (he->h_addr_list[i] == NULL) {
1320         const char *ipstr = inet_ntoa(rh->peer.sin_addr);
1321         for (i = 0; he->h_aliases[i] != NULL; i++) {
1322             if (strcmp(he->h_aliases[i], ipstr) == 0)
1323                 break;
1324         }
1325         /*
1326          * No aliases either.  Failure.  Someone is fooling with us or
1327          * DNS is messed up.
1328          */
1329         if (he->h_aliases[i] == NULL) {
1330             security_seterror(&rh->sech,
1331                 "DNS check failed: no matching ip address for %s",
1332                 rh->hostname);
1333             return (-1);
1334         }
1335     }
1336
1337     rh->prev = udp->bh_last;
1338     if (udp->bh_last) {
1339         rh->prev->next = rh;
1340     }
1341     if (!udp->bh_first) {
1342         udp->bh_first = rh;
1343     }
1344     rh->next = NULL;
1345     udp->bh_last = rh;
1346
1347     rh->sequence = sequence;
1348     rh->event_id = (event_id_t)newevent++;
1349     amfree(rh->proto_handle);
1350     rh->proto_handle = stralloc(handle);
1351     rh->fn.connect = NULL;
1352     rh->arg = NULL;
1353     rh->ev_read = NULL;
1354     rh->ev_timeout = NULL;
1355
1356     secprintf(("%s: udp: adding handle '%s'\n",
1357                debug_prefix_time(NULL), rh->proto_handle));
1358
1359     return(0);
1360 }
1361
1362
1363 /*
1364  * Callback for received packets.  This is the function bsd_recvpkt
1365  * registers with the event handler.  It is called when the event handler
1366  * realizes that data is waiting to be read on the network socket.
1367  */
1368 void
1369 udp_netfd_read_callback(
1370     void *      cookie)
1371 {
1372     struct udp_handle *udp = cookie;
1373     struct sec_handle *rh;
1374     struct hostent *he;
1375     int a;
1376
1377     secprintf(("%s: udp_netfd_read_callback(cookie=%p)\n",
1378                 debug_prefix(NULL), cookie));
1379     assert(udp != NULL);
1380     
1381 #ifndef TEST                                                    /* { */
1382     /*
1383      * Receive the packet.
1384      */
1385     dgram_zero(&udp->dgram);
1386     if (dgram_recv(&udp->dgram, 0, &udp->peer) < 0)
1387         return;
1388 #endif /* !TEST */                                              /* } */
1389
1390     /*
1391      * Parse the packet.
1392      */
1393     if (str2pkthdr(udp) < 0)
1394         return;
1395
1396     /*
1397      * If there are events waiting on this handle, we're done
1398      */
1399     rh = udp->bh_first;
1400     while(rh != NULL && (strcmp(rh->proto_handle, udp->handle) != 0 ||
1401                          rh->sequence != udp->sequence ||
1402                          rh->peer.sin_addr.s_addr != udp->peer.sin_addr.s_addr ||
1403                          rh->peer.sin_port != udp->peer.sin_port)) {
1404         rh = rh->next;
1405     }
1406     if (rh && event_wakeup(rh->event_id) > 0)
1407         return;
1408
1409     /*
1410      * If we didn't find a handle, then check for a new incoming packet.
1411      * If no accept handler was setup, then just return.
1412      */
1413     if (udp->accept_fn == NULL)
1414         return;
1415
1416     he = gethostbyaddr((void *)&udp->peer.sin_addr,
1417         (socklen_t)sizeof(udp->peer.sin_addr), AF_INET);
1418     if (he == NULL)
1419         return;
1420     rh = alloc(SIZEOF(*rh));
1421     rh->proto_handle=NULL;
1422     rh->udp = udp;
1423     rh->rc = NULL;
1424     security_handleinit(&rh->sech, udp->driver);
1425     a = udp_inithandle(udp, rh,
1426                    he,
1427                    udp->peer.sin_port,
1428                    udp->handle,
1429                    udp->sequence);
1430     if (a < 0) {
1431         secprintf(("%s: bsd: closeX handle '%s'\n",
1432                   debug_prefix_time(NULL), rh->proto_handle));
1433
1434         amfree(rh);
1435         return;
1436     }
1437     /*
1438      * Check the security of the packet.  If it is bad, then pass NULL
1439      * to the accept function instead of a packet.
1440      */
1441     if (rh->udp->recv_security_ok(rh, &udp->pkt) < 0)
1442         (*udp->accept_fn)(&rh->sech, NULL);
1443     else
1444         (*udp->accept_fn)(&rh->sech, &udp->pkt);
1445 }
1446
1447 /*
1448  * Locate an existing connection to the given host, or create a new,
1449  * unconnected entry if none exists.  The caller is expected to check
1450  * for the lack of a connection (rc->read == -1) and set one up.
1451  */
1452 struct tcp_conn *
1453 sec_tcp_conn_get(
1454     const char *hostname,
1455     int         want_new)
1456 {
1457     struct tcp_conn *rc;
1458
1459     secprintf(("%s: sec_tcp_conn_get: %s\n", debug_prefix_time(NULL), hostname));
1460
1461     if (want_new == 0) {
1462     for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
1463         if (strcasecmp(hostname, rc->hostname) == 0)
1464             break;
1465     }
1466
1467     if (rc != NULL) {
1468         rc->refcnt++;
1469         secprintf(("%s: sec_tcp_conn_get: exists, refcnt to %s is now %d\n",
1470                    debug_prefix_time(NULL),
1471                    rc->hostname, rc->refcnt));
1472         return (rc);
1473     }
1474     }
1475
1476     secprintf(("%s: sec_tcp_conn_get: creating new handle\n",
1477                debug_prefix_time(NULL)));
1478     /*
1479      * We can't be creating a new handle if we are the client
1480      */
1481     rc = alloc(SIZEOF(*rc));
1482     rc->read = rc->write = -1;
1483     rc->driver = NULL;
1484     rc->pid = -1;
1485     rc->ev_read = NULL;
1486     rc->toclose = 0;
1487     rc->donotclose = 0;
1488     strncpy(rc->hostname, hostname, SIZEOF(rc->hostname) - 1);
1489     rc->hostname[SIZEOF(rc->hostname) - 1] = '\0';
1490     rc->errmsg = NULL;
1491     rc->refcnt = 1;
1492     rc->handle = -1;
1493     rc->pkt = NULL;
1494     rc->accept_fn = NULL;
1495     rc->recv_security_ok = NULL;
1496     rc->prefix_packet = NULL;
1497     connq_append(rc);
1498     return (rc);
1499 }
1500
1501 /*
1502  * Delete a reference to a connection, and close it if it is the last
1503  * reference.
1504  */
1505 void
1506 sec_tcp_conn_put(
1507     struct tcp_conn *   rc)
1508 {
1509     amwait_t status;
1510
1511     assert(rc->refcnt > 0);
1512     --rc->refcnt;
1513     secprintf(("%s: sec_tcp_conn_put: decrementing refcnt for %s to %d\n",
1514                debug_prefix_time(NULL),
1515         rc->hostname, rc->refcnt));
1516     if (rc->refcnt > 0) {
1517         return;
1518     }
1519     secprintf(("%s: sec_tcp_conn_put: closing connection to %s\n",
1520                debug_prefix_time(NULL), rc->hostname));
1521     if (rc->read != -1)
1522         aclose(rc->read);
1523     if (rc->write != -1)
1524         aclose(rc->write);
1525     if (rc->pid != -1) {
1526         waitpid(rc->pid, &status, WNOHANG);
1527     }
1528     if (rc->ev_read != NULL)
1529         event_release(rc->ev_read);
1530     if (rc->errmsg != NULL)
1531         amfree(rc->errmsg);
1532     connq_remove(rc);
1533     amfree(rc->pkt);
1534     if(!rc->donotclose)
1535         amfree(rc); /* someone might still use it           */
1536                     /* eg. in sec_tcp_conn_read_callback if */
1537                     /*     event_wakeup call us.            */
1538 }
1539
1540 /*
1541  * Turn on read events for a conn.  Or, increase a ev_read_refcnt if we are
1542  * already receiving read events.
1543  */
1544 void
1545 sec_tcp_conn_read(
1546     struct tcp_conn *   rc)
1547 {
1548     assert (rc != NULL);
1549
1550     if (rc->ev_read != NULL) {
1551         rc->ev_read_refcnt++;
1552         secprintf((
1553                "%s: sec: conn_read: incremented ev_read_refcnt to %d for %s\n",
1554                debug_prefix_time(NULL), rc->ev_read_refcnt, rc->hostname));
1555         return;
1556     }
1557     secprintf(("%s: sec: conn_read registering event handler for %s\n",
1558                debug_prefix_time(NULL), rc->hostname));
1559     rc->ev_read = event_register((event_id_t)rc->read, EV_READFD,
1560                 sec_tcp_conn_read_callback, rc);
1561     rc->ev_read_refcnt = 1;
1562 }
1563
1564 static void
1565 sec_tcp_conn_read_cancel(
1566     struct tcp_conn *   rc)
1567 {
1568
1569     --rc->ev_read_refcnt;
1570     secprintf((
1571         "%s: sec: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n",
1572         debug_prefix_time(NULL),
1573         rc->ev_read_refcnt, rc->hostname));
1574     if (rc->ev_read_refcnt > 0) {
1575         return;
1576     }
1577     secprintf(("%s: sec: conn_read_cancel: releasing event handler for %s\n",
1578                debug_prefix_time(NULL), rc->hostname));
1579     event_release(rc->ev_read);
1580     rc->ev_read = NULL;
1581 }
1582
1583 /*
1584  * This is called when a handle is woken up because data read off of the
1585  * net is for it.
1586  */
1587 static void
1588 recvpkt_callback(
1589     void *      cookie,
1590     void *      buf,
1591     ssize_t     bufsize)
1592 {
1593     pkt_t pkt;
1594     struct sec_handle *rh = cookie;
1595
1596     assert(rh != NULL);
1597
1598     secprintf(("%s: sec: recvpkt_callback: %d\n",
1599                debug_prefix_time(NULL), bufsize));
1600     /*
1601      * We need to cancel the recvpkt request before calling
1602      * the callback because the callback may reschedule us.
1603      */
1604     stream_recvpkt_cancel(rh);
1605
1606     switch (bufsize) {
1607     case 0:
1608         security_seterror(&rh->sech,
1609             "EOF on read from %s", rh->hostname);
1610         (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1611         return;
1612     case -1:
1613         security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
1614         (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1615         return;
1616     default:
1617         break;
1618     }
1619
1620     parse_pkt(&pkt, buf, (size_t)bufsize);
1621     secprintf((
1622            "%s: sec: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n",
1623            debug_prefix_time(NULL), pkt_type2str(pkt.type), pkt.type,
1624            rh->hostname, pkt.body));
1625     if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
1626         (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1627     else
1628         (*rh->fn.recvpkt)(rh->arg, &pkt, S_OK);
1629     amfree(pkt.body);
1630 }
1631
1632 /*
1633  * Callback for tcpm_stream_read_sync
1634  */
1635 static void
1636 stream_read_sync_callback(
1637     void *      s)
1638 {
1639     struct sec_stream *rs = s;
1640     assert(rs != NULL);
1641
1642     secprintf(("%s: sec: stream_read_callback_sync: handle %d\n",
1643                debug_prefix_time(NULL), rs->handle));
1644
1645     /*
1646      * Make sure this was for us.  If it was, then blow away the handle
1647      * so it doesn't get claimed twice.  Otherwise, leave it alone.
1648      *
1649      * If the handle is EOF, pass that up to our callback.
1650      */
1651     if (rs->rc->handle == rs->handle) {
1652         secprintf(("%s: sec: stream_read_callback_sync: it was for us\n",
1653                    debug_prefix_time(NULL)));
1654         rs->rc->handle = H_TAKEN;
1655     } else if (rs->rc->handle != H_EOF) {
1656         secprintf(("%s: sec: stream_read_callback_sync: not for us\n",
1657                    debug_prefix_time(NULL)));
1658         return;
1659     }
1660
1661     /*
1662      * Remove the event first, and then call the callback.
1663      * We remove it first because we don't want to get in their
1664      * way if they reschedule it.
1665      */
1666     tcpm_stream_read_cancel(rs);
1667
1668     if (rs->rc->pktlen <= 0) {
1669         secprintf(("%s: sec: stream_read_sync_callback: %s\n",
1670                    debug_prefix_time(NULL), rs->rc->errmsg));
1671         security_stream_seterror(&rs->secstr, rs->rc->errmsg);
1672         if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
1673             sec_tcp_conn_put(rs->rc);
1674         rs->closed_by_network = 1;
1675         return;
1676     }
1677     secprintf((
1678              "%s: sec: stream_read_callback_sync: read %zd bytes from %s:%d\n",
1679              debug_prefix_time(NULL),
1680         rs->rc->pktlen, rs->rc->hostname, rs->handle));
1681 }
1682
1683 /*
1684  * Callback for tcpm_stream_read
1685  */
1686 static void
1687 stream_read_callback(
1688     void *      arg)
1689 {
1690     struct sec_stream *rs = arg;
1691     assert(rs != NULL);
1692
1693     secprintf(("%s: sec: stream_read_callback: handle %d\n",
1694                debug_prefix_time(NULL), rs->handle));
1695
1696     /*
1697      * Make sure this was for us.  If it was, then blow away the handle
1698      * so it doesn't get claimed twice.  Otherwise, leave it alone.
1699      *
1700      * If the handle is EOF, pass that up to our callback.
1701      */
1702     if (rs->rc->handle == rs->handle) {
1703         secprintf(("%s: sec: stream_read_callback: it was for us\n",
1704                    debug_prefix_time(NULL)));
1705         rs->rc->handle = H_TAKEN;
1706     } else if (rs->rc->handle != H_EOF) {
1707         secprintf(("%s: sec: stream_read_callback: not for us\n",
1708                    debug_prefix_time(NULL)));
1709         return;
1710     }
1711
1712     /*
1713      * Remove the event first, and then call the callback.
1714      * We remove it first because we don't want to get in their
1715      * way if they reschedule it.
1716      */
1717     tcpm_stream_read_cancel(rs);
1718
1719     if (rs->rc->pktlen <= 0) {
1720         secprintf(("%s: sec: stream_read_callback: %s\n",
1721                    debug_prefix_time(NULL), rs->rc->errmsg));
1722         security_stream_seterror(&rs->secstr, rs->rc->errmsg);
1723         if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
1724             sec_tcp_conn_put(rs->rc);
1725         rs->closed_by_network = 1;
1726         (*rs->fn)(rs->arg, NULL, rs->rc->pktlen);
1727         return;
1728     }
1729     secprintf(("%s: sec: stream_read_callback: read %zd bytes from %s:%d\n",
1730                debug_prefix_time(NULL),
1731         rs->rc->pktlen, rs->rc->hostname, rs->handle));
1732     (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen);
1733     secprintf(("%s: sec: after callback stream_read_callback\n",
1734                debug_prefix_time(NULL)));
1735 }
1736
1737 /*
1738  * The callback for the netfd for the event handler
1739  * Determines if this packet is for this security handle,
1740  * and does the real callback if so.
1741  */
1742 static void
1743 sec_tcp_conn_read_callback(
1744     void *      cookie)
1745 {
1746     struct tcp_conn *   rc = cookie;
1747     struct sec_handle * rh;
1748     pkt_t               pkt;
1749     ssize_t             rval;
1750     int                 revent;
1751
1752     assert(cookie != NULL);
1753
1754     secprintf(("%s: sec: conn_read_callback\n", debug_prefix_time(NULL)));
1755
1756     /* Read the data off the wire.  If we get errors, shut down. */
1757     rval = tcpm_recv_token(rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
1758                                 &rc->pktlen, 60);
1759     secprintf(("%s: sec: conn_read_callback: tcpm_recv_token returned %d\n",
1760                debug_prefix_time(NULL), rval));
1761     if (rval < 0 || rc->handle == H_EOF) {
1762         rc->pktlen = rval;
1763         rc->handle = H_EOF;
1764         revent = event_wakeup((event_id_t)rc);
1765         secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
1766                    debug_prefix_time(NULL), revent));
1767         /* delete our 'accept' reference */
1768         if (rc->accept_fn != NULL) {
1769             if(rc->refcnt != 1) {
1770                 dbprintf(("STRANGE, rc->refcnt should be 1, it is %d\n",
1771                           rc->refcnt));
1772                 rc->refcnt=1;
1773             }
1774             rc->accept_fn = NULL;
1775             sec_tcp_conn_put(rc);
1776         }
1777         return;
1778     }
1779
1780     if(rval == 0) {
1781         rc->pktlen = 0;
1782         revent = event_wakeup((event_id_t)rc);
1783         secprintf(("%s: 0 sec: conn_read_callback: event_wakeup return %d\n",
1784                    debug_prefix_time(NULL), revent));
1785         return;
1786     }
1787
1788     /* If there are events waiting on this handle, we're done */
1789     rc->donotclose = 1;
1790     revent = event_wakeup((event_id_t)rc);
1791     secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
1792                debug_prefix_time(NULL), rval));
1793     rc->donotclose = 0;
1794     if (rc->handle == H_TAKEN || rc->pktlen == 0) {
1795         if(rc->refcnt == 0) amfree(rc);
1796         return;
1797     }
1798
1799     assert(rc->refcnt > 0);
1800
1801     /* If there is no accept fn registered, then drop the packet */
1802     if (rc->accept_fn == NULL)
1803         return;
1804
1805     rh = alloc(SIZEOF(*rh));
1806     security_handleinit(&rh->sech, rc->driver);
1807     rh->hostname = stralloc(rc->hostname);
1808     rh->ev_timeout = NULL;
1809     rh->rc = rc;
1810     rh->peer = rc->peer;
1811     rh->rs = tcpma_stream_client(rh, rc->handle);
1812
1813     secprintf(("%s: sec: new connection\n", debug_prefix_time(NULL)));
1814     pkt.body = NULL;
1815     parse_pkt(&pkt, rc->pkt, (size_t)rc->pktlen);
1816     secprintf(("%s: sec: calling accept_fn\n", debug_prefix_time(NULL)));
1817     if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
1818         (*rc->accept_fn)(&rh->sech, NULL);
1819     else
1820         (*rc->accept_fn)(&rh->sech, &pkt);
1821     amfree(pkt.body);
1822 }
1823
1824 void
1825 parse_pkt(
1826     pkt_t *     pkt,
1827     const void *buf,
1828     size_t      bufsize)
1829 {
1830     const unsigned char *bufp = buf;
1831
1832     secprintf(("%s: sec: parse_pkt: parsing buffer of %d bytes\n",
1833                debug_prefix_time(NULL), bufsize));
1834
1835     pkt->type = (pktype_t)*bufp++;
1836     bufsize--;
1837
1838     pkt->packet_size = bufsize+1;
1839     pkt->body = alloc(pkt->packet_size);
1840     if (bufsize == 0) {
1841         pkt->body[0] = '\0';
1842     } else {
1843         memcpy(pkt->body, bufp, bufsize);
1844         pkt->body[pkt->packet_size - 1] = '\0';
1845     }
1846     pkt->size = strlen(pkt->body);
1847
1848     secprintf(("%s: sec: parse_pkt: %s (%d): \"%s\"\n",
1849                debug_prefix_time(NULL), pkt_type2str(pkt->type),
1850                pkt->type, pkt->body));
1851 }
1852
1853 /*
1854  * Convert a packet header into a string
1855  */
1856 const char *
1857 pkthdr2str(
1858     const struct sec_handle *   rh,
1859     const pkt_t *               pkt)
1860 {
1861     static char retbuf[256];
1862
1863     assert(rh != NULL);
1864     assert(pkt != NULL);
1865
1866     snprintf(retbuf, SIZEOF(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
1867         VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
1868         rh->proto_handle, rh->sequence);
1869
1870     secprintf(("%s: bsd: pkthdr2str handle '%s'\n",
1871                debug_prefix_time(NULL), rh->proto_handle));
1872
1873     /* check for truncation.  If only we had asprintf()... */
1874     assert(retbuf[strlen(retbuf) - 1] == '\n');
1875
1876     return (retbuf);
1877 }
1878
1879 /*
1880  * Parses out the header line in 'str' into the pkt and handle
1881  * Returns negative on parse error.
1882  */
1883 int
1884 str2pkthdr(
1885     udp_handle_t *      udp)
1886 {
1887     char *str;
1888     const char *tok;
1889     pkt_t *pkt;
1890
1891     pkt = &udp->pkt;
1892
1893     assert(udp->dgram.cur != NULL);
1894     str = stralloc(udp->dgram.cur);
1895
1896     /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */
1897
1898     /* Read in "Amanda" */
1899     if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0)
1900         goto parse_error;
1901
1902     /* nothing is done with the major/minor numbers currently */
1903     if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL)
1904         goto parse_error;
1905
1906     /* Read in the packet type */
1907     if ((tok = strtok(NULL, " ")) == NULL)
1908         goto parse_error;
1909     amfree(pkt->body);
1910     pkt_init_empty(pkt, pkt_str2type(tok));
1911     if (pkt->type == (pktype_t)-1)    
1912         goto parse_error;
1913
1914     /* Read in "HANDLE" */
1915     if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0)
1916         goto parse_error;
1917
1918     /* parse the handle */
1919     if ((tok = strtok(NULL, " ")) == NULL)
1920         goto parse_error;
1921     amfree(udp->handle);
1922     udp->handle = stralloc(tok);
1923
1924     /* Read in "SEQ" */
1925     if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)   
1926         goto parse_error;
1927
1928     /* parse the sequence number */   
1929     if ((tok = strtok(NULL, "\n")) == NULL)
1930         goto parse_error;
1931     udp->sequence = atoi(tok);
1932
1933     /* Save the body, if any */       
1934     if ((tok = strtok(NULL, "")) != NULL)
1935         pkt_cat(pkt, "%s", tok);
1936
1937     amfree(str);
1938     return (0);
1939
1940 parse_error:
1941 #if 0 /* XXX we have no way of passing this back up */
1942     security_seterror(&rh->sech,
1943         "parse error in packet header : '%s'", origstr);
1944 #endif
1945     amfree(str);
1946     return (-1);
1947 }
1948
1949 char *
1950 check_user(
1951     struct sec_handle * rh,
1952     const char *        remoteuser,
1953     const char *        service)
1954 {
1955     struct passwd *pwd;
1956     char *r;
1957     char *result = NULL;
1958     char *localuser = NULL;
1959
1960     /* lookup our local user name */
1961     if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
1962         return vstralloc("getpwnam(", CLIENT_LOGIN, ") fails", NULL);
1963     }
1964
1965     /*
1966      * Make a copy of the user name in case getpw* is called by
1967      * any of the lower level routines.
1968      */
1969     localuser = stralloc(pwd->pw_name);
1970
1971 #ifndef USE_AMANDAHOSTS
1972     r = check_user_ruserok(rh->hostname, pwd, remoteuser);
1973 #else
1974     r = check_user_amandahosts(rh->hostname, rh->peer.sin_addr, pwd, remoteuser, service);
1975 #endif
1976     if (r != NULL) {
1977         result = vstralloc("user ", remoteuser, " from ", rh->hostname,
1978                            " is not allowed to execute the service ",
1979                            service, ": ", r, NULL);
1980         amfree(r);
1981     }
1982     amfree(localuser);
1983     return result;
1984 }
1985
1986 /*
1987  * See if a remote user is allowed in.  This version uses ruserok()
1988  * and friends.
1989  *
1990  * Returns 0 on success, or negative on error.
1991  */
1992 char *
1993 check_user_ruserok(
1994     const char *        host,
1995     struct passwd *     pwd,
1996     const char *        remoteuser)
1997 {
1998     int saved_stderr;
1999     int fd[2];
2000     FILE *fError;
2001     amwait_t exitcode;
2002     pid_t ruserok_pid;
2003     pid_t pid;
2004     char *es;
2005     char *result;
2006     int ok;
2007     char number[NUM_STR_SIZE];
2008     uid_t myuid = getuid();
2009
2010     /*
2011      * note that some versions of ruserok (eg SunOS 3.2) look in
2012      * "./.rhosts" rather than "~CLIENT_LOGIN/.rhosts", so we have to
2013      * chdir ourselves.  Sigh.
2014      *
2015      * And, believe it or not, some ruserok()'s try an initgroup just
2016      * for the hell of it.  Since we probably aren't root at this point
2017      * it'll fail, and initgroup "helpfully" will blatt "Setgroups: Not owner"
2018      * into our stderr output even though the initgroup failure is not a
2019      * problem and is expected.  Thanks a lot.  Not.
2020      */
2021     if (pipe(fd) != 0) {
2022         return stralloc2("pipe() fails: ", strerror(errno));
2023     }
2024     if ((ruserok_pid = fork()) < 0) {
2025         return stralloc2("fork() fails: ", strerror(errno));
2026     } else if (ruserok_pid == 0) {
2027         int ec;
2028
2029         close(fd[0]);
2030         fError = fdopen(fd[1], "w");
2031         if (!fError) {
2032             error("Can't fdopen: %s", strerror(errno));
2033             /*NOTREACHED*/
2034         }
2035         /* pamper braindead ruserok's */
2036         if (chdir(pwd->pw_dir) != 0) {
2037             fprintf(fError, "chdir(%s) failed: %s",
2038                     pwd->pw_dir, strerror(errno));
2039             fclose(fError);
2040             exit(1);
2041         }
2042
2043 #if defined(SHOW_SECURITY_DETAIL)                               /* { */
2044         {
2045         char *dir = stralloc(pwd->pw_dir);
2046
2047         secprintf(("%s: bsd: calling ruserok(%s, %d, %s, %s)\n",
2048                    debug_prefix_time(NULL),
2049                    host, ((myuid == 0) ? 1 : 0), remoteuser, pwd->pw_name));
2050         if (myuid == 0) {
2051             secprintf(("%s: bsd: because you are running as root, ",
2052                        debug_prefix(NULL)));
2053             secprintf(("/etc/hosts.equiv will not be used\n"));
2054         } else {
2055             show_stat_info("/etc/hosts.equiv", NULL);
2056         }
2057         show_stat_info(dir, "/.rhosts");
2058         amfree(dir);
2059         }
2060 #endif                                                          /* } */
2061
2062         saved_stderr = dup(2);
2063         close(2);
2064         if (open("/dev/null", O_RDWR) == -1) {
2065             secprintf(("%s: Could not open /dev/null: %s\n",
2066                       debug_prefix(NULL), strerror(errno)));
2067             ec = 1;
2068         } else {
2069             ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN);
2070             if (ok < 0) {
2071                 ec = 1;
2072             } else {
2073                 ec = 0;
2074             }
2075         }
2076         (void)dup2(saved_stderr,2);
2077         close(saved_stderr);
2078         exit(ec);
2079     }
2080     close(fd[1]);
2081     fError = fdopen(fd[0], "r");
2082     if (!fError) {
2083         error("Can't fdopen: %s", strerror(errno));
2084         /*NOTREACHED*/
2085     }
2086
2087     result = NULL;
2088     while ((es = agets(fError)) != NULL) {
2089         if (*es == 0) {
2090             amfree(es);
2091             continue;
2092         }
2093         if (result == NULL) {
2094             result = stralloc("");
2095         } else {
2096             strappend(result, ": ");
2097         }
2098         strappend(result, es);
2099         amfree(es);
2100     }
2101     close(fd[0]);
2102
2103     pid = wait(&exitcode);
2104     while (pid != ruserok_pid) {
2105         if ((pid == (pid_t) -1) && (errno != EINTR)) {
2106             amfree(result);
2107             return stralloc2("ruserok wait failed: %s", strerror(errno));
2108         }
2109         pid = wait(&exitcode);
2110     }
2111     if (WIFSIGNALED(exitcode)) {
2112         amfree(result);
2113         snprintf(number, SIZEOF(number), "%d", WTERMSIG(exitcode));
2114         return stralloc2("ruserok child got signal ", number);
2115     }
2116     if (WEXITSTATUS(exitcode) == 0) {
2117         amfree(result);
2118     } else if (result == NULL) {
2119         result = stralloc("ruserok failed");
2120     }
2121
2122     return result;
2123 }
2124
2125 /*
2126  * Check to see if a user is allowed in.  This version uses .amandahosts
2127  * Returns -1 on failure, or 0 on success.
2128  */
2129 char *
2130 check_user_amandahosts(
2131     const char *        host,
2132     struct in_addr      addr,
2133     struct passwd *     pwd,
2134     const char *        remoteuser,
2135     const char *        service)
2136 {
2137     char *line = NULL;
2138     char *filehost;
2139     const char *fileuser;
2140     char *ptmp = NULL;
2141     char *result = NULL;
2142     FILE *fp = NULL;
2143     int found;
2144     struct stat sbuf;
2145     char n1[NUM_STR_SIZE];
2146     char n2[NUM_STR_SIZE];
2147     int hostmatch;
2148     int usermatch;
2149     char *aservice = NULL;
2150
2151     secprintf(("check_user_amandahosts(host=%s, pwd=%p, "
2152                 "remoteuser=%s, service=%s)\n",
2153                 host, pwd, remoteuser, service));
2154
2155     ptmp = stralloc2(pwd->pw_dir, "/.amandahosts");
2156 #if defined(SHOW_SECURITY_DETAIL)                               /* { */
2157     show_stat_info(ptmp, "");;
2158 #endif                                                          /* } */
2159     if ((fp = fopen(ptmp, "r")) == NULL) {
2160         result = vstralloc("cannot open ", ptmp, ": ", strerror(errno), NULL);
2161         amfree(ptmp);
2162         return result;
2163     }
2164
2165     /*
2166      * Make sure the file is owned by the Amanda user and does not
2167      * have any group/other access allowed.
2168      */
2169     if (fstat(fileno(fp), &sbuf) != 0) {
2170         result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
2171         goto common_exit;
2172     }
2173     if (sbuf.st_uid != pwd->pw_uid) {
2174         snprintf(n1, SIZEOF(n1), "%ld", (long)sbuf.st_uid);
2175         snprintf(n2, SIZEOF(n2), "%ld", (long)pwd->pw_uid);
2176         result = vstralloc(ptmp, ": ",
2177                            "owned by id ", n1,
2178                            ", should be ", n2,
2179                            NULL);
2180         goto common_exit;
2181     }
2182     if ((sbuf.st_mode & 077) != 0) {
2183         result = stralloc2(ptmp,
2184           ": incorrect permissions; file must be accessible only by its owner");
2185         goto common_exit;
2186     }
2187
2188     /*
2189      * Now, scan the file for the host/user/service.
2190      */
2191     found = 0;
2192     while ((line = agets(fp)) != NULL) {
2193         if (*line == 0) {
2194             amfree(line);
2195             continue;
2196         }
2197
2198 #if defined(SHOW_SECURITY_DETAIL)                               /* { */
2199         secprintf(("%s: bsd: processing line: <%s>\n", debug_prefix(NULL), line));
2200 #endif                                                          /* } */
2201         /* get the host out of the file */
2202         if ((filehost = strtok(line, " \t")) == NULL) {
2203             amfree(line);
2204             continue;
2205         }
2206
2207         /* get the username.  If no user specified, then use the local user */
2208         if ((fileuser = strtok(NULL, " \t")) == NULL) {
2209             fileuser = pwd->pw_name;
2210         }
2211
2212         hostmatch = (strcasecmp(filehost, host) == 0);
2213         /*  ok if addr=127.0.0.1 and
2214         *  either localhost or localhost.domain is in .amandahost */
2215        if ( !hostmatch ) {
2216          if (strcmp(inet_ntoa(addr), "127.0.0.1")== 0  &&
2217              (strcasecmp(filehost, "localhost")== 0 ||
2218               strcasecmp(filehost, "localhost.localdomain")== 0))
2219            {
2220              hostmatch = 1;
2221            }
2222        }
2223         usermatch = (strcasecmp(fileuser, remoteuser) == 0);
2224 #if defined(SHOW_SECURITY_DETAIL)                               /* { */
2225         secprintf(("%s: bsd: comparing \"%s\" with\n", debug_prefix(NULL), filehost));
2226         secprintf(("%s: bsd:           \"%s\" (%s)\n", host,
2227                   debug_prefix(NULL), hostmatch ? "match" : "no match"));
2228         secprintf(("%s: bsd:       and \"%s\" with\n", fileuser, debug_prefix(NULL)));
2229         secprintf(("%s: bsd:           \"%s\" (%s)\n", remoteuser,
2230                   debug_prefix(NULL), usermatch ? "match" : "no match"));
2231 #endif                                                          /* } */
2232         /* compare */
2233         if (!hostmatch || !usermatch) {
2234             amfree(line);
2235             continue;
2236         }
2237
2238         if (!service) {
2239             /* success */
2240             amfree(line);
2241             found = 1;
2242             break;
2243         }
2244
2245         /* get the services.  If no service specified, then use
2246          * noop/selfcheck/sendsize/sendbackup
2247          */
2248         aservice = strtok(NULL, " \t,");
2249         if (!aservice) {
2250             if (strcmp(service,"noop") == 0 ||
2251                strcmp(service,"selfcheck") == 0 ||
2252                strcmp(service,"sendsize") == 0 ||
2253                strcmp(service,"sendbackup") == 0) {
2254                 /* success */
2255                 found = 1;
2256                 amfree(line);
2257                 break;
2258             }
2259             else {
2260                 amfree(line);
2261                 break;
2262             }
2263         }
2264
2265         do {
2266             if (strcmp(aservice,service) == 0) {
2267                 found = 1;
2268                 break;
2269             }
2270             if (strcmp(aservice, "amdump") == 0 && 
2271                (strcmp(service, "noop") == 0 ||
2272                 strcmp(service, "selfcheck") == 0 ||
2273                 strcmp(service, "sendsize") == 0 ||
2274                 strcmp(service, "sendbackup") == 0)) {
2275                 found = 1;
2276                 break;
2277             }
2278         } while((aservice = strtok(NULL, " \t,")) != NULL);
2279
2280         if (aservice && strcmp(aservice, service) == 0) {
2281             /* success */
2282             found = 1;
2283             amfree(line);
2284             break;
2285         }
2286         amfree(line);
2287     }
2288     if (! found) {
2289         if (strcmp(service, "amindexd") == 0 ||
2290             strcmp(service, "amidxtaped") == 0) {
2291             result = vstralloc("Please add \"amindexd amidxtaped\" to "
2292                                "the line in ", ptmp, NULL);
2293         } else if (strcmp(service, "amdump") == 0 ||
2294                    strcmp(service, "noop") == 0 ||
2295                    strcmp(service, "selfcheck") == 0 ||
2296                    strcmp(service, "sendsize") == 0 ||
2297                    strcmp(service, "sendbackup") == 0) {
2298             result = vstralloc("Please add \"amdump\" to the line in ",
2299                                ptmp, NULL);
2300         } else {
2301             result = vstralloc(ptmp, ": ",
2302                                "invalid service ", service, NULL);
2303         }
2304     }
2305
2306 common_exit:
2307
2308     afclose(fp);
2309     amfree(ptmp);
2310
2311     return result;
2312 }
2313
2314 /* return 1 on success, 0 on failure */
2315 int
2316 check_security(
2317     struct sockaddr_in *addr,
2318     char *              str,
2319     unsigned long       cksum,
2320     char **             errstr)
2321 {
2322     char *              remotehost = NULL, *remoteuser = NULL;
2323     char *              bad_bsd = NULL;
2324     struct hostent *    hp;
2325     struct passwd *     pwptr;
2326     uid_t               myuid;
2327     int                 i;
2328     int                 j;
2329     char *              s;
2330     char *              fp;
2331     int                 ch;
2332
2333     (void)cksum;        /* Quiet unused parameter warning */
2334
2335     secprintf(("%s: check_security(addr=%p, str='%s', cksum=%ul, errstr=%p\n",
2336                 debug_prefix(NULL), addr, str, cksum, errstr));
2337     dump_sockaddr(addr);
2338
2339     *errstr = NULL;
2340
2341     /* what host is making the request? */
2342
2343     hp = gethostbyaddr((char *)&addr->sin_addr, SIZEOF(addr->sin_addr),
2344                        AF_INET);
2345     if (hp == NULL) {
2346         /* XXX include remote address in message */
2347         *errstr = vstralloc("[",
2348                             "addr ", inet_ntoa(addr->sin_addr), ": ",
2349                             "hostname lookup failed",
2350                             "]", NULL);
2351         return 0;
2352     }
2353     remotehost = stralloc(hp->h_name);
2354
2355     /* Now let's get the hostent for that hostname */
2356     hp = gethostbyname( remotehost );
2357     if (hp == NULL) {
2358         /* XXX include remote hostname in message */
2359         *errstr = vstralloc("[",
2360                             "host ", remotehost, ": ",
2361                             "hostname lookup failed",
2362                             "]", NULL);
2363         amfree(remotehost);
2364         return 0;
2365     }
2366
2367     /* Verify that the hostnames match -- they should theoretically */
2368     if (strncasecmp( remotehost, hp->h_name, strlen(remotehost)+1 ) != 0 ) {
2369         *errstr = vstralloc("[",
2370                             "hostnames do not match: ",
2371                             remotehost, " ", hp->h_name,
2372                             "]", NULL);
2373         amfree(remotehost);
2374         return 0;
2375     }
2376
2377     /* Now let's verify that the ip which gave us this hostname
2378      * is really an ip for this hostname; or is someone trying to
2379      * break in? (THIS IS THE CRUCIAL STEP)
2380      */
2381     for (i = 0; hp->h_addr_list[i]; i++) {
2382         if (memcmp(hp->h_addr_list[i],
2383                    (char *) &addr->sin_addr, SIZEOF(addr->sin_addr)) == 0)
2384             break;                     /* name is good, keep it */
2385     }
2386
2387     /* If we did not find it, your DNS is messed up or someone is trying
2388      * to pull a fast one on you. :(
2389      */
2390
2391    /*   Check even the aliases list. Work around for Solaris if dns goes over NIS */
2392
2393     if (!hp->h_addr_list[i] ) {
2394         for (j = 0; hp->h_aliases[j] !=0 ; j++) {
2395              if (strcmp(hp->h_aliases[j],inet_ntoa(addr->sin_addr)) == 0)
2396                  break;                          /* name is good, keep it */
2397         }
2398         if (!hp->h_aliases[j] ) {
2399             *errstr = vstralloc("[",
2400                                 "ip address ", inet_ntoa(addr->sin_addr),
2401                                 " is not in the ip list for ", remotehost,
2402                                 "]",
2403                                 NULL);
2404             amfree(remotehost);
2405             return 0;
2406         }
2407     }
2408
2409     /* next, make sure the remote port is a "reserved" one */
2410
2411     if (ntohs(addr->sin_port) >= IPPORT_RESERVED) {
2412         char number[NUM_STR_SIZE];
2413
2414         snprintf(number, SIZEOF(number), "%u",
2415                  (unsigned int)ntohs(addr->sin_port));
2416         *errstr = vstralloc("[",
2417                             "host ", remotehost, ": ",
2418                             "port ", number, " not secure",
2419                             "]", NULL);
2420         amfree(remotehost);
2421         return 0;
2422     }
2423
2424     /* extract the remote user name from the message */
2425
2426     s = str;
2427     ch = *s++;
2428
2429     bad_bsd = vstralloc("[",
2430                         "host ", remotehost, ": ",
2431                         "bad bsd security line",
2432                         "]", NULL);
2433
2434 #define sc "USER "
2435     if (strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
2436         *errstr = bad_bsd;
2437         bad_bsd = NULL;
2438         amfree(remotehost);
2439         return 0;
2440     }
2441     s += SIZEOF(sc)-1;
2442     ch = s[-1];
2443 #undef sc
2444
2445     skip_whitespace(s, ch);
2446     if (ch == '\0') {
2447         *errstr = bad_bsd;
2448         bad_bsd = NULL;
2449         amfree(remotehost);
2450         return 0;
2451     }
2452     fp = s - 1;
2453     skip_non_whitespace(s, ch);
2454     s[-1] = '\0';
2455     remoteuser = stralloc(fp);
2456     s[-1] = (char)ch;
2457     amfree(bad_bsd);
2458
2459     /* lookup our local user name */
2460
2461     myuid = getuid();
2462     if ((pwptr = getpwuid(myuid)) == NULL)
2463         error("error [getpwuid(%d) fails]", myuid);
2464
2465     secprintf(("%s: bsd security: remote host %s user %s local user %s\n",
2466               debug_prefix(NULL), remotehost, remoteuser, pwptr->pw_name));
2467
2468 #ifndef USE_AMANDAHOSTS
2469     s = check_user_ruserok(remotehost, pwptr, remoteuser);
2470 #else
2471     s = check_user_amandahosts(remotehost, addr->sin_addr, pwptr, remoteuser, NULL);
2472 #endif
2473
2474     if (s != NULL) {
2475         *errstr = vstralloc("[",
2476                             "access as ", pwptr->pw_name, " not allowed",
2477                             " from ", remoteuser, "@", remotehost,
2478                             ": ", s, "]", NULL);
2479     }
2480     amfree(s);
2481     amfree(remotehost);
2482     amfree(remoteuser);
2483     return *errstr == NULL;
2484 }
2485
2486 /*
2487  * Writes out the entire iovec
2488  */
2489 ssize_t
2490 net_writev(
2491     int                 fd,
2492     struct iovec *      iov,
2493     int                 iovcnt)
2494 {
2495     ssize_t delta, n, total;
2496
2497     assert(iov != NULL);
2498
2499     total = 0;
2500     while (iovcnt > 0) {
2501         /*
2502          * Write the iovec
2503          */
2504         n = writev(fd, iov, iovcnt);
2505         if (n < 0) {
2506             if (errno != EINTR)
2507                 return (-1);
2508             secprintf(("%s: net_writev got EINTR\n",
2509                        debug_prefix(NULL)));
2510         }
2511         else if (n == 0) {
2512             errno = EIO;
2513             return (-1);
2514         } else {
2515             total += n;
2516             /*
2517              * Iterate through each iov.  Figure out what we still need
2518              * to write out.
2519              */
2520             for (; n > 0; iovcnt--, iov++) {
2521                 /* 'delta' is the bytes written from this iovec */
2522                 delta = ((size_t)n < iov->iov_len) ? n : (ssize_t)iov->iov_len;
2523                 /* subtract from the total num bytes written */
2524                 n -= delta;
2525                 assert(n >= 0);
2526                 /* subtract from this iovec */
2527                 iov->iov_len -= delta;
2528                 iov->iov_base = (char *)iov->iov_base + delta;
2529                 /* if this iovec isn't empty, run the writev again */
2530                 if (iov->iov_len > 0)
2531                     break;
2532             }
2533         }
2534     }
2535     return (total);
2536 }
2537
2538 /*
2539  * Like read(), but waits until the entire buffer has been filled.
2540  */
2541 ssize_t
2542 net_read(
2543     int         fd,
2544     void *      vbuf,
2545     size_t      origsize,
2546     int         timeout)
2547 {
2548     char *buf = vbuf;   /* ptr arith */
2549     ssize_t nread;
2550     size_t size = origsize;
2551
2552     secprintf(("%s: net_read: begin %d\n", debug_prefix_time(NULL), origsize));
2553
2554     while (size > 0) {
2555         secprintf(("%s: net_read: while %d\n",
2556                    debug_prefix_time(NULL), size));
2557         nread = net_read_fillbuf(fd, timeout, buf, size);
2558         if (nread < 0) {
2559             secprintf(("%s: db: net_read: end return(-1)\n",
2560                        debug_prefix_time(NULL)));
2561             return (-1);
2562         }
2563         if (nread == 0) {
2564             secprintf(("%s: net_read: end return(0)\n",
2565                        debug_prefix_time(NULL)));
2566             return (0);
2567         }
2568         buf += nread;
2569         size -= nread;
2570     }
2571     secprintf(("%s: net_read: end %d\n",
2572                debug_prefix_time(NULL), origsize));
2573     return ((ssize_t)origsize);
2574 }
2575
2576 /*
2577  * net_read likes to do a lot of little reads.  Buffer it.
2578  */
2579 ssize_t
2580 net_read_fillbuf(
2581     int         fd,
2582     int         timeout,
2583     void *      buf,
2584     size_t      size)
2585 {
2586     fd_set readfds;
2587     struct timeval tv;
2588     ssize_t nread;
2589
2590     secprintf(("%s: net_read_fillbuf: begin\n", debug_prefix_time(NULL)));
2591     FD_ZERO(&readfds);
2592     FD_SET(fd, &readfds);
2593     tv.tv_sec = timeout;
2594     tv.tv_usec = 0;
2595     switch (select(fd + 1, &readfds, NULL, NULL, &tv)) {
2596     case 0:
2597         errno = ETIMEDOUT;
2598         /* FALLTHROUGH */
2599     case -1:
2600         secprintf(("%s: net_read_fillbuf: case -1\n",
2601                    debug_prefix_time(NULL)));
2602         return (-1);
2603     case 1:
2604         secprintf(("%s: net_read_fillbuf: case 1\n",
2605                    debug_prefix_time(NULL)));
2606         assert(FD_ISSET(fd, &readfds));
2607         break;
2608     default:
2609         secprintf(("%s: net_read_fillbuf: case default\n",
2610                    debug_prefix_time(NULL)));
2611         assert(0);
2612         break;
2613     }
2614     nread = read(fd, buf, size);
2615     if (nread < 0)
2616         return (-1);
2617     secprintf(("%s: net_read_fillbuf: end %d\n",
2618                debug_prefix_time(NULL), nread));
2619     return (nread);
2620 }
2621
2622
2623 /*
2624  * Display stat() information about a file.
2625  */
2626
2627 void
2628 show_stat_info(
2629     char *      a,
2630     char *      b)
2631 {
2632     char *name = vstralloc(a, b, NULL);
2633     struct stat sbuf;
2634     struct passwd *pwptr;
2635     char *owner;
2636     struct group *grptr;
2637     char *group;
2638
2639     if (stat(name, &sbuf) != 0) {
2640         secprintf(("%s: bsd: cannot stat %s: %s\n",
2641                    debug_prefix_time(NULL), name, strerror(errno)));
2642         amfree(name);
2643         return;
2644     }
2645     if ((pwptr = getpwuid(sbuf.st_uid)) == NULL) {
2646         owner = alloc(NUM_STR_SIZE + 1);
2647         snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid);
2648     } else {
2649         owner = stralloc(pwptr->pw_name);
2650     }
2651     if ((grptr = getgrgid(sbuf.st_gid)) == NULL) {
2652         group = alloc(NUM_STR_SIZE + 1);
2653         snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
2654     } else {
2655         group = stralloc(grptr->gr_name);
2656     }
2657     secprintf(("%s: bsd: processing file: %s\n", debug_prefix(NULL), name));
2658     secprintf(("%s: bsd:                  owner=%s group=%s mode=%03o\n",
2659                debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777)));
2660     amfree(name);
2661     amfree(owner);
2662     amfree(group);
2663 }