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