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