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