2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: security-util.c,v 1.25.2.10 2007/01/24 00:35:14 martinea Exp $
30 * sec-security.c - security and transport over sec or a sec-like command.
32 * XXX still need to check for initial keyword on connect so we can skip
33 * over shell garbage and other stuff that sec might want to spew out.
42 #include "security-util.h"
46 /* #define SEC_DEBUG */
47 #define SHOW_SECURITY_DETAIL
50 # define secprintf(x) dbprintf(x)
53 # define secprintf(x) (void)(x)
60 * Magic values for sec_conn->handle
62 #define H_TAKEN -1 /* sec_conn->tok was already read */
63 #define H_EOF -2 /* this connection has been shut down */
66 * This is a queue of open connections
68 struct connq_s connq = {
69 TAILQ_HEAD_INITIALIZER(connq.tailq), 0
71 static int newhandle = 1;
72 static int newevent = 1;
77 static void recvpkt_callback(void *, void *, ssize_t);
78 static void stream_read_callback(void *);
79 static void stream_read_sync_callback(void *);
81 static void sec_tcp_conn_read_cancel(struct tcp_conn *);
82 static void sec_tcp_conn_read_callback(void *);
86 * Authenticate a stream
87 * Nothing needed for sec. The connection is authenticated by secd
94 (void)s; /* Quiet unused parameter warning */
99 * Returns the stream id for this stream. This is just the local
106 struct sec_stream *rs = s;
114 * Setup to handle new incoming connections
118 const security_driver_t *driver,
121 void (*fn)(security_handle_t *, pkt_t *))
125 rc = sec_tcp_conn_get("unknown",0);
130 sec_tcp_conn_read(rc);
134 * frees a handle allocated by the above
140 struct sec_handle *rh = inst;
144 secprintf(("%s: sec: closing handle to %s\n", debug_prefix_time(NULL),
147 if (rh->rs != NULL) {
148 /* This may be null if we get here on an error */
149 stream_recvpkt_cancel(rh);
150 security_stream_close(&rh->rs->secstr);
152 /* keep us from getting here again */
153 rh->sech.driver = NULL;
154 amfree(rh->hostname);
159 * Called when a sec connection is finished connecting and is ready
160 * to be authenticated.
163 sec_connect_callback(
166 struct sec_handle *rh = cookie;
168 event_release(rh->rs->ev_read);
169 rh->rs->ev_read = NULL;
170 event_release(rh->ev_timeout);
171 rh->ev_timeout = NULL;
173 (*rh->fn.connect)(rh->arg, &rh->sech, S_OK);
177 * Called if a connection times out before completion.
183 struct sec_handle *rh = cookie;
185 event_release(rh->rs->ev_read);
186 rh->rs->ev_read = NULL;
187 event_release(rh->ev_timeout);
188 rh->ev_timeout = NULL;
190 (*rh->fn.connect)(rh->arg, &rh->sech, S_TIMEOUT);
194 sec_close_connection_none(
215 struct sec_handle *rh = cookie;
222 secprintf(("%s: sec: stream_sendpkt: enter\n", debug_prefix_time(NULL)));
224 if (rh->rc->prefix_packet)
225 s = rh->rc->prefix_packet(rh, pkt);
228 len = strlen(pkt->body) + strlen(s) + 2;
230 buf[0] = (char)pkt->type;
231 strncpy(&buf[1], s, len - 1);
232 strncpy(&buf[1 + strlen(s)], pkt->body, (len - strlen(s) - 1));
237 "%s: sec: stream_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
238 debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
239 strlen(pkt->body), pkt->body));
241 if (security_stream_write(&rh->rs->secstr, buf, len) < 0) {
242 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
250 * Set up to receive a packet asyncronously, and call back when
256 void (*fn)(void *, pkt_t *, security_status_t),
260 struct sec_handle *rh = cookie;
264 secprintf(("%s: sec: recvpkt registered for %s\n",
265 debug_prefix_time(NULL), rh->hostname));
268 * Reset any pending timeout on this handle
270 if (rh->ev_timeout != NULL)
271 event_release(rh->ev_timeout);
274 * Negative timeouts mean no timeout
277 rh->ev_timeout = NULL;
279 rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
280 stream_recvpkt_timeout, rh);
284 security_stream_read(&rh->rs->secstr, recvpkt_callback, rh);
288 * This is called when a handle times out before receiving a packet.
291 stream_recvpkt_timeout(
294 struct sec_handle *rh = cookie;
298 secprintf(("%s: sec: recvpkt timeout for %s\n",
299 debug_prefix_time(NULL), rh->hostname));
301 stream_recvpkt_cancel(rh);
302 (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);
306 * Remove a async receive request from the queue
309 stream_recvpkt_cancel(
312 struct sec_handle *rh = cookie;
314 secprintf(("%s: sec: cancelling recvpkt for %s\n",
315 debug_prefix_time(NULL), rh->hostname));
319 security_stream_read_cancel(&rh->rs->secstr);
320 if (rh->ev_timeout != NULL) {
321 event_release(rh->ev_timeout);
322 rh->ev_timeout = NULL;
327 * Write a chunk of data to a stream. Blocks until completion.
335 struct sec_stream *rs = s;
338 assert(rs->rc != NULL);
340 secprintf(("%s: sec: stream_write: writing %d bytes to %s:%d %d\n",
341 debug_prefix_time(NULL), size, rs->rc->hostname, rs->handle,
344 if (tcpm_send_token(rs->rc->write, rs->handle, &rs->rc->errmsg,
346 security_stream_seterror(&rs->secstr, rs->rc->errmsg);
353 * Submit a request to read some data. Calls back with the given
354 * function and arg when completed.
359 void (*fn)(void *, void *, ssize_t),
362 struct sec_stream *rs = s;
367 * Only one read request can be active per stream.
369 if (rs->ev_read == NULL) {
370 rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
371 stream_read_callback, rs);
372 sec_tcp_conn_read(rs->rc);
379 * Write a chunk of data to a stream. Blocks until completion.
382 tcpm_stream_read_sync(
386 struct sec_stream *rs = s;
391 * Only one read request can be active per stream.
393 if (rs->ev_read != NULL) {
396 rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
397 stream_read_sync_callback, rs);
398 sec_tcp_conn_read(rs->rc);
399 event_wait(rs->ev_read);
401 return (rs->rc->pktlen);
405 * Cancel a previous stream read request. It's ok if we didn't have a read
409 tcpm_stream_read_cancel(
412 struct sec_stream *rs = s;
416 if (rs->ev_read != NULL) {
417 event_release(rs->ev_read);
419 sec_tcp_conn_read_cancel(rs->rc);
424 * Transmits a chunk of data over a rsh_handle, adding
425 * the necessary headers to allow the remote end to decode it.
440 assert(SIZEOF(netlength) == 4);
444 * 32 bit length (network byte order)
445 * 32 bit handle (network byte order)
448 netlength = htonl(len);
449 iov[0].iov_base = (void *)&netlength;
450 iov[0].iov_len = SIZEOF(netlength);
452 nethandle = htonl((uint32_t)handle);
453 iov[1].iov_base = (void *)&nethandle;
454 iov[1].iov_len = SIZEOF(nethandle);
460 iov[2].iov_base = (void *)buf;
461 iov[2].iov_len = len;
465 if (net_writev(fd, iov, nb_iov) < 0) {
467 *errmsg = newvstralloc(*errmsg, "write error to ",
468 ": ", strerror(errno), NULL);
476 * return 0 on EOF: *handle = H_EOF && *size = 0 if socket closed
477 * return 0 on EOF: *handle = handle && *size = 0 if stream closed
478 * return size : *handle = handle && *size = size for data read
490 unsigned int netint[2];
492 assert(SIZEOF(netint) == 8);
494 switch (net_read(fd, &netint, SIZEOF(netint), timeout)) {
497 *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
499 secprintf(("%s: tcpm_recv_token: A return(-1)\n",
500 debug_prefix_time(NULL)));
505 *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
506 secprintf(("%s: tcpm_recv_token: A return(0)\n",
507 debug_prefix_time(NULL)));
513 *size = (ssize_t)ntohl(netint[0]);
514 *handle = (int)ntohl(netint[1]);
515 /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
516 if (*size > 128*NETWORK_BLOCK_BYTES || *size < 0) {
517 if (isprint((*size ) & 0xFF) &&
518 isprint((*size >> 8 ) & 0xFF) &&
519 isprint((*size >> 16) & 0xFF) &&
520 isprint((*size >> 24) & 0xFF) &&
521 isprint((*handle ) & 0xFF) &&
522 isprint((*handle >> 8 ) & 0xFF) &&
523 isprint((*handle >> 16) & 0xFF) &&
524 isprint((*handle >> 24) & 0xFF)) {
527 s[0] = (*size >> 24) & 0xFF;
528 s[1] = (*size >> 16) & 0xFF;
529 s[2] = (*size >> 8) & 0xFF;
530 s[3] = (*size ) & 0xFF;
531 s[4] = (*handle >> 24) & 0xFF;
532 s[5] = (*handle >> 16) & 0xFF;
533 s[6] = (*handle >> 8 ) & 0xFF;
534 s[7] = (*handle ) & 0xFF;
536 while(i<100 && isprint(s[i]) && s[i] != '\n') {
537 switch(net_read(fd, &s[i], 1, 0)) {
538 case -1: s[i] = '\0'; break;
539 case 0: s[i] = '\0'; break;
540 default: dbprintf(("read: %c\n", s[i])); i++; s[i]=' ';break;
544 *errmsg = newvstralloc(*errmsg, "tcpm_recv_token: invalid size: ",
546 dbprintf(("%s: tcpm_recv_token: invalid size: %s\n",
547 debug_prefix_time(NULL), s));
549 *errmsg = newvstralloc(*errmsg, "tcpm_recv_token: invalid size",
551 dbprintf(("%s: tcpm_recv_token: invalid size %zd\n",
552 debug_prefix_time(NULL), *size));
558 *buf = alloc((size_t)*size);
561 secprintf(("%s: tcpm_recv_token: read EOF from %d\n",
562 debug_prefix_time(NULL), *handle));
563 *errmsg = newvstralloc(*errmsg, "EOF",
567 switch (net_read(fd, *buf, (size_t)*size, timeout)) {
570 *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
572 secprintf(("%s: tcpm_recv_token: B return(-1)\n",
573 debug_prefix_time(NULL)));
577 *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
578 secprintf(("%s: tcpm_recv_token: B return(0)\n",
579 debug_prefix_time(NULL)));
585 secprintf(("%s: tcpm_recv_token: read %zd bytes from %d\n",
586 debug_prefix_time(NULL), *size, *handle));
591 tcpm_close_connection(
595 struct sec_handle *rh = h;
599 if(rh->rc->toclose == 0) {
601 sec_tcp_conn_put(rh->rc);
608 * Accept an incoming connection on a stream_server socket
609 * Nothing needed for tcpma.
615 (void)s; /* Quiet unused parameter warning */
621 * Return a connected stream. For sec, this means setup a stream
622 * with the supplied handle.
629 struct sec_handle *rh = h;
630 struct sec_stream *rs;
635 security_seterror(&rh->sech,
636 "%d: invalid security stream id", id);
640 rs = alloc(SIZEOF(*rs));
641 security_streaminit(&rs->secstr, rh->sech.driver);
644 rs->closed_by_me = 0;
645 rs->closed_by_network = 0;
651 rs->rc = sec_tcp_conn_get(rh->hostname, 0);
652 rs->rc->driver = rh->sech.driver;
656 secprintf(("%s: sec: stream_client: connected to stream %d\n",
657 debug_prefix_time(NULL), id));
663 * Create the server end of a stream. For sec, this means setup a stream
664 * object and allocate a new handle for it.
670 struct sec_handle *rh = h;
671 struct sec_stream *rs;
675 rs = alloc(SIZEOF(*rs));
676 security_streaminit(&rs->secstr, rh->sech.driver);
677 rs->closed_by_me = 0;
678 rs->closed_by_network = 0;
684 rs->rc = sec_tcp_conn_get(rh->hostname, 0);
685 rs->rc->driver = rh->sech.driver;
689 * Stream should already be setup!
691 if (rs->rc->read < 0) {
692 sec_tcp_conn_put(rs->rc);
694 security_seterror(&rh->sech, "lost connection to %s", rh->hostname);
697 assert(strcmp(rh->hostname, rs->rc->hostname) == 0);
699 * so as not to conflict with the amanda server's handle numbers,
700 * we start at 500000 and work down
702 rs->handle = 500000 - newhandle++;
704 secprintf(("%s: sec: stream_server: created stream %d\n",
705 debug_prefix_time(NULL), rs->handle));
710 * Close and unallocate resources for a stream.
716 struct sec_stream *rs = s;
721 secprintf(("%s: sec: tcpma_stream_close: closing stream %d\n",
722 debug_prefix_time(NULL), rs->handle));
724 if(rs->closed_by_network == 0 && rs->rc->write != -1)
725 tcpm_stream_write(rs, &buf, 0);
726 security_stream_read_cancel(&rs->secstr);
727 if(rs->closed_by_network == 0)
728 sec_tcp_conn_put(rs->rc);
733 * Create the server end of a stream. For bsdudp, this means setup a tcp
734 * socket for receiving a connection.
740 struct sec_stream *rs = NULL;
741 struct sec_handle *rh = h;
745 rs = alloc(SIZEOF(*rs));
746 security_streaminit(&rs->secstr, rh->sech.driver);
747 rs->closed_by_me = 0;
748 rs->closed_by_network = 0;
751 rs->handle = 500000 - newhandle++;
753 rs->socket = 0; /* the socket is already opened */
756 rh->rc = sec_tcp_conn_get(rh->hostname, 1);
757 rh->rc->driver = rh->sech.driver;
759 rs->socket = stream_server(&rs->port, STREAM_BUFSIZE,
761 if (rs->socket < 0) {
762 security_seterror(&rh->sech,
763 "can't create server stream: %s", strerror(errno));
767 rh->rc->read = rs->socket;
768 rh->rc->write = rs->socket;
769 rs->handle = (int)rs->port;
777 * Accepts a new connection on unconnected streams. Assumes it is ok to
784 struct sec_stream *bs = s;
787 assert(bs->socket != -1);
790 if (bs->socket > 0) {
791 bs->fd = stream_accept(bs->socket, 30, STREAM_BUFSIZE, STREAM_BUFSIZE);
793 security_stream_seterror(&bs->secstr,
794 "can't accept new stream connection: %s",
798 bs->rc->read = bs->fd;
799 bs->rc->write = bs->fd;
805 * Return a connected stream
812 struct sec_stream *rs = NULL;
813 struct sec_handle *rh = h;
817 rs = alloc(SIZEOF(*rs));
818 security_streaminit(&rs->secstr, rh->sech.driver);
821 rs->closed_by_me = 0;
822 rs->closed_by_network = 0;
828 rh->rc = sec_tcp_conn_get(rh->hostname, 1);
830 rh->rc->read = stream_client(rh->hostname, (in_port_t)id,
831 STREAM_BUFSIZE, STREAM_BUFSIZE, &rs->port, 0);
832 if (rh->rc->read < 0) {
833 security_seterror(&rh->sech,
834 "can't connect stream to %s port %d: %s",
835 rh->hostname, id, strerror(errno));
839 rh->rc->write = rh->rc->read;
841 rs->socket = -1; /* we're a client */
852 struct sec_stream *rs = s;
856 if (fullwrite(rs->fd, buf, size) < 0) {
857 security_stream_seterror(&rs->secstr,
858 "write error on stream %d: %s", rs->port, strerror(errno));
869 struct sec_handle *rh = h;
873 if (pkt->type != P_REQ)
876 if ((pwd = getpwuid(getuid())) == NULL) {
877 security_seterror(&rh->sech,
878 "can't get login name for my uid %ld",
882 buf = alloc(16+strlen(pwd->pw_name));
883 strncpy(buf, "SECURITY USER ", (16 + strlen(pwd->pw_name)));
884 strncpy(&buf[14], pwd->pw_name, (16 + strlen(pwd->pw_name) - 14));
885 buf[14 + strlen(pwd->pw_name)] = '\n';
886 buf[15 + strlen(pwd->pw_name)] = '\0';
893 * Check the security of a received packet. Returns negative on security
894 * violation, or returns 0 if ok. Removes the security info from the pkt_t.
897 bsd_recv_security_ok(
898 struct sec_handle * rh,
901 char *tok, *security, *body, *result;
902 char *service = NULL, *serviceX, *serviceY;
907 * Now, find the SECURITY line in the body, and parse it out
910 if (strncmp(pkt->body, "SECURITY ", SIZEOF("SECURITY ") - 1) == 0) {
911 security = pkt->body;
913 while(*security != '\n' && len < pkt->size) {
917 if(*security == '\n') {
920 security_line = stralloc(pkt->body);
921 security = pkt->body + strlen("SECURITY ");
924 security_line = NULL;
929 security_line = NULL;
934 * Now, find the SERVICE line in the body, and parse it out
937 if (strncmp(body, "SERVICE", SIZEOF("SERVICE") - 1) == 0) {
938 serviceX = stralloc(body + strlen("SERVICE "));
939 serviceY = strtok(serviceX, "\n");
941 service = stralloc(serviceY);
946 * We need to do different things depending on which type of packet
952 * Request packets must come from a reserved port
954 if (ntohs(rh->peer.sin_port) >= IPPORT_RESERVED) {
955 security_seterror(&rh->sech,
956 "host %s: port %d not secure", rh->hostname,
957 ntohs(rh->peer.sin_port));
959 amfree(security_line);
964 security_seterror(&rh->sech,
965 "packet as no SERVICE line");
966 amfree(security_line);
971 * Request packets contain a remote username. We need to check
972 * that we allow it in.
974 * They will look like:
975 * SECURITY USER [username]
978 /* there must be some security info */
979 if (security == NULL) {
980 security_seterror(&rh->sech,
981 "no bsd SECURITY for P_REQ");
986 /* second word must be USER */
987 if ((tok = strtok(security, " ")) == NULL) {
988 security_seterror(&rh->sech,
989 "SECURITY line: %s", security_line);
991 amfree(security_line);
992 return (-1); /* default errmsg */
994 if (strcmp(tok, "USER") != 0) {
995 security_seterror(&rh->sech,
996 "REQ SECURITY line parse error, expecting USER, got %s", tok);
998 amfree(security_line);
1002 /* the third word is the username */
1003 if ((tok = strtok(NULL, "")) == NULL) {
1004 security_seterror(&rh->sech,
1005 "SECURITY line: %s", security_line);
1006 amfree(security_line);
1007 return (-1); /* default errmsg */
1009 if ((result = check_user(rh, tok, service)) != NULL) {
1010 security_seterror(&rh->sech, "%s", result);
1013 amfree(security_line);
1017 /* we're good to go */
1023 amfree(security_line);
1026 * If there is security info at the front of the packet, we need to
1027 * shift the rest of the data up and nuke it.
1029 if (body != pkt->body)
1030 memmove(pkt->body, body, strlen(body) + 1);
1035 * Transmit a packet. Add security information first.
1042 struct sec_handle *rh = cookie;
1046 assert(pkt != NULL);
1048 secprintf(("%s: udpbsd_sendpkt: enter\n", get_pname()));
1050 * Initialize this datagram, and add the header
1052 dgram_zero(&rh->udp->dgram);
1053 dgram_cat(&rh->udp->dgram, pkthdr2str(rh, pkt));
1056 * Add the security info. This depends on which kind of packet we're
1059 switch (pkt->type) {
1062 * Requests get sent with our username in the body
1064 if ((pwd = getpwuid(geteuid())) == NULL) {
1065 security_seterror(&rh->sech,
1066 "can't get login name for my uid %ld", (long)getuid());
1069 dgram_cat(&rh->udp->dgram, "SECURITY USER %s\n", pwd->pw_name);
1077 * Add the body, and send it
1079 dgram_cat(&rh->udp->dgram, pkt->body);
1082 "%s: sec: udpbsd_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
1083 debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
1084 strlen(pkt->body), pkt->body));
1086 if (dgram_send_addr(rh->peer, &rh->udp->dgram) != 0) {
1087 security_seterror(&rh->sech,
1088 "send %s to %s failed: %s", pkt_type2str(pkt->type),
1089 rh->hostname, strerror(errno));
1099 struct sec_handle *rh = cookie;
1101 if (rh->proto_handle == NULL) {
1105 secprintf(("%s: udp: close handle '%s'\n",
1106 debug_prefix_time(NULL), rh->proto_handle));
1108 udp_recvpkt_cancel(rh);
1110 rh->next->prev = rh->prev;
1113 rh->udp->bh_last = rh->prev;
1116 rh->prev->next = rh->next;
1119 rh->udp->bh_first = rh->next;
1122 amfree(rh->proto_handle);
1123 amfree(rh->hostname);
1128 * Set up to receive a packet asynchronously, and call back when it has
1134 void (*fn)(void *, pkt_t *, security_status_t),
1138 struct sec_handle *rh = cookie;
1140 secprintf(("%s: udp_recvpkt(cookie=%p, fn=%p, arg=%p, timeout=%u)\n",
1141 debug_prefix(NULL), cookie, fn, arg, timeout));
1147 * Subsequent recvpkt calls override previous ones
1149 if (rh->ev_read == NULL) {
1150 udp_addref(rh->udp, &udp_netfd_read_callback);
1151 rh->ev_read = event_register(rh->event_id, EV_WAIT,
1152 udp_recvpkt_callback, rh);
1154 if (rh->ev_timeout != NULL)
1155 event_release(rh->ev_timeout);
1157 rh->ev_timeout = NULL;
1159 rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
1160 udp_recvpkt_timeout, rh);
1161 rh->fn.recvpkt = fn;
1166 * Remove a async receive request on this handle from the queue.
1167 * If it is the last one to be removed, then remove the event
1168 * handler for our network fd
1174 struct sec_handle *rh = cookie;
1178 if (rh->ev_read != NULL) {
1179 udp_delref(rh->udp);
1180 event_release(rh->ev_read);
1184 if (rh->ev_timeout != NULL) {
1185 event_release(rh->ev_timeout);
1186 rh->ev_timeout = NULL;
1191 * This is called when a handle is woken up because data read off of the
1195 udp_recvpkt_callback(
1198 struct sec_handle *rh = cookie;
1199 void (*fn)(void *, pkt_t *, security_status_t);
1202 secprintf(("%s: udp: receive handle '%s' netfd '%s'\n",
1203 debug_prefix_time(NULL), rh->proto_handle, rh->udp->handle));
1206 if (strcmp(rh->proto_handle, rh->udp->handle) != 0) assert(1);
1207 /* if it didn't come from the same host/port, forget it */
1208 if (memcmp(&rh->peer.sin_addr, &rh->udp->peer.sin_addr,
1209 SIZEOF(rh->udp->peer.sin_addr)) != 0 ||
1210 rh->peer.sin_port != rh->udp->peer.sin_port) {
1211 amfree(rh->udp->handle);
1216 * We need to cancel the recvpkt request before calling the callback
1217 * because the callback may reschedule us.
1219 fn = rh->fn.recvpkt;
1221 udp_recvpkt_cancel(rh);
1224 * Check the security of the packet. If it is bad, then pass NULL
1225 * to the packet handling function instead of a packet.
1227 if (rh->udp->recv_security_ok &&
1228 rh->udp->recv_security_ok(rh, &rh->udp->pkt) < 0)
1229 (*fn)(arg, NULL, S_ERROR);
1231 (*fn)(arg, &rh->udp->pkt, S_OK);
1235 * This is called when a handle times out before receiving a packet.
1238 udp_recvpkt_timeout(
1241 struct sec_handle *rh = cookie;
1242 void (*fn)(void *, pkt_t *, security_status_t);
1247 assert(rh->ev_timeout != NULL);
1248 fn = rh->fn.recvpkt;
1250 udp_recvpkt_cancel(rh);
1251 (*fn)(arg, NULL, S_TIMEOUT);
1255 * Given a hostname and a port, setup a udp_handle
1260 struct sec_handle * rh,
1261 struct hostent * he,
1269 * Save the hostname and port info
1271 secprintf(("%s: udp_inithandle port %u handle %s sequence %d\n",
1272 debug_prefix_time(NULL), (unsigned int)ntohs(port),
1276 rh->hostname = stralloc(he->h_name);
1277 memcpy(&rh->peer.sin_addr, he->h_addr, SIZEOF(rh->peer.sin_addr));
1278 rh->peer.sin_port = port;
1279 rh->peer.sin_family = (sa_family_t)AF_INET;
1282 * Do a forward lookup of the hostname. This is unnecessary if we
1283 * are initiating the connection, but is very serious if we are
1284 * receiving. We want to make sure the hostname
1285 * resolves back to the remote ip for security reasons.
1287 if ((he = gethostbyname(rh->hostname)) == NULL) {
1288 secprintf(("%s: udp: bb\n", debug_prefix_time(NULL)));
1289 security_seterror(&rh->sech,
1290 "%s: could not resolve hostname", rh->hostname);
1295 * Make sure the hostname matches. This should always work.
1297 if (strncasecmp(rh->hostname, he->h_name, strlen(rh->hostname)) != 0) {
1298 secprintf(("%s: udp: cc\n", debug_prefix_time(NULL)));
1299 security_seterror(&rh->sech,
1300 "%s: did not resolve to itself, it resolv to %s",
1301 rh->hostname, he->h_name);
1306 * Now look for a matching ip address.
1308 for (i = 0; he->h_addr_list[i] != NULL; i++) {
1309 if (memcmp(&rh->peer.sin_addr, he->h_addr_list[i],
1310 SIZEOF(struct in_addr)) == 0) {
1316 * If we didn't find it, try the aliases. This is a workaround for
1317 * Solaris if DNS goes over NIS.
1319 if (he->h_addr_list[i] == NULL) {
1320 const char *ipstr = inet_ntoa(rh->peer.sin_addr);
1321 for (i = 0; he->h_aliases[i] != NULL; i++) {
1322 if (strcmp(he->h_aliases[i], ipstr) == 0)
1326 * No aliases either. Failure. Someone is fooling with us or
1329 if (he->h_aliases[i] == NULL) {
1330 security_seterror(&rh->sech,
1331 "DNS check failed: no matching ip address for %s",
1337 rh->prev = udp->bh_last;
1339 rh->prev->next = rh;
1341 if (!udp->bh_first) {
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;
1354 rh->ev_timeout = NULL;
1356 secprintf(("%s: udp: adding handle '%s'\n",
1357 debug_prefix_time(NULL), rh->proto_handle));
1364 * Callback for received packets. This is the function bsd_recvpkt
1365 * registers with the event handler. It is called when the event handler
1366 * realizes that data is waiting to be read on the network socket.
1369 udp_netfd_read_callback(
1372 struct udp_handle *udp = cookie;
1373 struct sec_handle *rh;
1377 secprintf(("%s: udp_netfd_read_callback(cookie=%p)\n",
1378 debug_prefix(NULL), cookie));
1379 assert(udp != NULL);
1381 #ifndef TEST /* { */
1383 * Receive the packet.
1385 dgram_zero(&udp->dgram);
1386 if (dgram_recv(&udp->dgram, 0, &udp->peer) < 0)
1388 #endif /* !TEST */ /* } */
1393 if (str2pkthdr(udp) < 0)
1397 * If there are events waiting on this handle, we're done
1400 while(rh != NULL && (strcmp(rh->proto_handle, udp->handle) != 0 ||
1401 rh->sequence != udp->sequence ||
1402 rh->peer.sin_addr.s_addr != udp->peer.sin_addr.s_addr ||
1403 rh->peer.sin_port != udp->peer.sin_port)) {
1406 if (rh && event_wakeup(rh->event_id) > 0)
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.
1413 if (udp->accept_fn == NULL)
1416 he = gethostbyaddr((void *)&udp->peer.sin_addr,
1417 (socklen_t)sizeof(udp->peer.sin_addr), AF_INET);
1420 rh = alloc(SIZEOF(*rh));
1421 rh->proto_handle=NULL;
1424 security_handleinit(&rh->sech, udp->driver);
1425 a = udp_inithandle(udp, rh,
1431 secprintf(("%s: bsd: closeX handle '%s'\n",
1432 debug_prefix_time(NULL), rh->proto_handle));
1438 * Check the security of the packet. If it is bad, then pass NULL
1439 * to the accept function instead of a packet.
1441 if (rh->udp->recv_security_ok(rh, &udp->pkt) < 0)
1442 (*udp->accept_fn)(&rh->sech, NULL);
1444 (*udp->accept_fn)(&rh->sech, &udp->pkt);
1448 * Locate an existing connection to the given host, or create a new,
1449 * unconnected entry if none exists. The caller is expected to check
1450 * for the lack of a connection (rc->read == -1) and set one up.
1454 const char *hostname,
1457 struct tcp_conn *rc;
1459 secprintf(("%s: sec_tcp_conn_get: %s\n", debug_prefix_time(NULL), hostname));
1461 if (want_new == 0) {
1462 for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
1463 if (strcasecmp(hostname, rc->hostname) == 0)
1469 secprintf(("%s: sec_tcp_conn_get: exists, refcnt to %s is now %d\n",
1470 debug_prefix_time(NULL),
1471 rc->hostname, rc->refcnt));
1476 secprintf(("%s: sec_tcp_conn_get: creating new handle\n",
1477 debug_prefix_time(NULL)));
1479 * We can't be creating a new handle if we are the client
1481 rc = alloc(SIZEOF(*rc));
1482 rc->read = rc->write = -1;
1488 strncpy(rc->hostname, hostname, SIZEOF(rc->hostname) - 1);
1489 rc->hostname[SIZEOF(rc->hostname) - 1] = '\0';
1494 rc->accept_fn = NULL;
1495 rc->recv_security_ok = NULL;
1496 rc->prefix_packet = NULL;
1502 * Delete a reference to a connection, and close it if it is the last
1507 struct tcp_conn * rc)
1511 assert(rc->refcnt > 0);
1513 secprintf(("%s: sec_tcp_conn_put: decrementing refcnt for %s to %d\n",
1514 debug_prefix_time(NULL),
1515 rc->hostname, rc->refcnt));
1516 if (rc->refcnt > 0) {
1519 secprintf(("%s: sec_tcp_conn_put: closing connection to %s\n",
1520 debug_prefix_time(NULL), rc->hostname));
1523 if (rc->write != -1)
1525 if (rc->pid != -1) {
1526 waitpid(rc->pid, &status, WNOHANG);
1528 if (rc->ev_read != NULL)
1529 event_release(rc->ev_read);
1530 if (rc->errmsg != NULL)
1535 amfree(rc); /* someone might still use it */
1536 /* eg. in sec_tcp_conn_read_callback if */
1537 /* event_wakeup call us. */
1541 * Turn on read events for a conn. Or, increase a ev_read_refcnt if we are
1542 * already receiving read events.
1546 struct tcp_conn * rc)
1548 assert (rc != NULL);
1550 if (rc->ev_read != NULL) {
1551 rc->ev_read_refcnt++;
1553 "%s: sec: conn_read: incremented ev_read_refcnt to %d for %s\n",
1554 debug_prefix_time(NULL), rc->ev_read_refcnt, rc->hostname));
1557 secprintf(("%s: sec: conn_read registering event handler for %s\n",
1558 debug_prefix_time(NULL), rc->hostname));
1559 rc->ev_read = event_register((event_id_t)rc->read, EV_READFD,
1560 sec_tcp_conn_read_callback, rc);
1561 rc->ev_read_refcnt = 1;
1565 sec_tcp_conn_read_cancel(
1566 struct tcp_conn * rc)
1569 --rc->ev_read_refcnt;
1571 "%s: sec: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n",
1572 debug_prefix_time(NULL),
1573 rc->ev_read_refcnt, rc->hostname));
1574 if (rc->ev_read_refcnt > 0) {
1577 secprintf(("%s: sec: conn_read_cancel: releasing event handler for %s\n",
1578 debug_prefix_time(NULL), rc->hostname));
1579 event_release(rc->ev_read);
1584 * This is called when a handle is woken up because data read off of the
1594 struct sec_handle *rh = cookie;
1598 secprintf(("%s: sec: recvpkt_callback: %d\n",
1599 debug_prefix_time(NULL), bufsize));
1601 * We need to cancel the recvpkt request before calling
1602 * the callback because the callback may reschedule us.
1604 stream_recvpkt_cancel(rh);
1608 security_seterror(&rh->sech,
1609 "EOF on read from %s", rh->hostname);
1610 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1613 security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
1614 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1620 parse_pkt(&pkt, buf, (size_t)bufsize);
1622 "%s: sec: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n",
1623 debug_prefix_time(NULL), pkt_type2str(pkt.type), pkt.type,
1624 rh->hostname, pkt.body));
1625 if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
1626 (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
1628 (*rh->fn.recvpkt)(rh->arg, &pkt, S_OK);
1633 * Callback for tcpm_stream_read_sync
1636 stream_read_sync_callback(
1639 struct sec_stream *rs = s;
1642 secprintf(("%s: sec: stream_read_callback_sync: handle %d\n",
1643 debug_prefix_time(NULL), rs->handle));
1646 * Make sure this was for us. If it was, then blow away the handle
1647 * so it doesn't get claimed twice. Otherwise, leave it alone.
1649 * If the handle is EOF, pass that up to our callback.
1651 if (rs->rc->handle == rs->handle) {
1652 secprintf(("%s: sec: stream_read_callback_sync: it was for us\n",
1653 debug_prefix_time(NULL)));
1654 rs->rc->handle = H_TAKEN;
1655 } else if (rs->rc->handle != H_EOF) {
1656 secprintf(("%s: sec: stream_read_callback_sync: not for us\n",
1657 debug_prefix_time(NULL)));
1662 * Remove the event first, and then call the callback.
1663 * We remove it first because we don't want to get in their
1664 * way if they reschedule it.
1666 tcpm_stream_read_cancel(rs);
1668 if (rs->rc->pktlen <= 0) {
1669 secprintf(("%s: sec: stream_read_sync_callback: %s\n",
1670 debug_prefix_time(NULL), rs->rc->errmsg));
1671 security_stream_seterror(&rs->secstr, rs->rc->errmsg);
1672 if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
1673 sec_tcp_conn_put(rs->rc);
1674 rs->closed_by_network = 1;
1678 "%s: sec: stream_read_callback_sync: read %zd bytes from %s:%d\n",
1679 debug_prefix_time(NULL),
1680 rs->rc->pktlen, rs->rc->hostname, rs->handle));
1684 * Callback for tcpm_stream_read
1687 stream_read_callback(
1690 struct sec_stream *rs = arg;
1693 secprintf(("%s: sec: stream_read_callback: handle %d\n",
1694 debug_prefix_time(NULL), rs->handle));
1697 * Make sure this was for us. If it was, then blow away the handle
1698 * so it doesn't get claimed twice. Otherwise, leave it alone.
1700 * If the handle is EOF, pass that up to our callback.
1702 if (rs->rc->handle == rs->handle) {
1703 secprintf(("%s: sec: stream_read_callback: it was for us\n",
1704 debug_prefix_time(NULL)));
1705 rs->rc->handle = H_TAKEN;
1706 } else if (rs->rc->handle != H_EOF) {
1707 secprintf(("%s: sec: stream_read_callback: not for us\n",
1708 debug_prefix_time(NULL)));
1713 * Remove the event first, and then call the callback.
1714 * We remove it first because we don't want to get in their
1715 * way if they reschedule it.
1717 tcpm_stream_read_cancel(rs);
1719 if (rs->rc->pktlen <= 0) {
1720 secprintf(("%s: sec: stream_read_callback: %s\n",
1721 debug_prefix_time(NULL), rs->rc->errmsg));
1722 security_stream_seterror(&rs->secstr, rs->rc->errmsg);
1723 if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
1724 sec_tcp_conn_put(rs->rc);
1725 rs->closed_by_network = 1;
1726 (*rs->fn)(rs->arg, NULL, rs->rc->pktlen);
1729 secprintf(("%s: sec: stream_read_callback: read %zd bytes from %s:%d\n",
1730 debug_prefix_time(NULL),
1731 rs->rc->pktlen, rs->rc->hostname, rs->handle));
1732 (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen);
1733 secprintf(("%s: sec: after callback stream_read_callback\n",
1734 debug_prefix_time(NULL)));
1738 * The callback for the netfd for the event handler
1739 * Determines if this packet is for this security handle,
1740 * and does the real callback if so.
1743 sec_tcp_conn_read_callback(
1746 struct tcp_conn * rc = cookie;
1747 struct sec_handle * rh;
1752 assert(cookie != NULL);
1754 secprintf(("%s: sec: conn_read_callback\n", debug_prefix_time(NULL)));
1756 /* Read the data off the wire. If we get errors, shut down. */
1757 rval = tcpm_recv_token(rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
1759 secprintf(("%s: sec: conn_read_callback: tcpm_recv_token returned %d\n",
1760 debug_prefix_time(NULL), rval));
1761 if (rval < 0 || rc->handle == H_EOF) {
1764 revent = event_wakeup((event_id_t)rc);
1765 secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
1766 debug_prefix_time(NULL), revent));
1767 /* delete our 'accept' reference */
1768 if (rc->accept_fn != NULL) {
1769 if(rc->refcnt != 1) {
1770 dbprintf(("STRANGE, rc->refcnt should be 1, it is %d\n",
1774 rc->accept_fn = NULL;
1775 sec_tcp_conn_put(rc);
1782 revent = event_wakeup((event_id_t)rc);
1783 secprintf(("%s: 0 sec: conn_read_callback: event_wakeup return %d\n",
1784 debug_prefix_time(NULL), revent));
1788 /* If there are events waiting on this handle, we're done */
1790 revent = event_wakeup((event_id_t)rc);
1791 secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
1792 debug_prefix_time(NULL), rval));
1794 if (rc->handle == H_TAKEN || rc->pktlen == 0) {
1795 if(rc->refcnt == 0) amfree(rc);
1799 assert(rc->refcnt > 0);
1801 /* If there is no accept fn registered, then drop the packet */
1802 if (rc->accept_fn == NULL)
1805 rh = alloc(SIZEOF(*rh));
1806 security_handleinit(&rh->sech, rc->driver);
1807 rh->hostname = stralloc(rc->hostname);
1808 rh->ev_timeout = NULL;
1810 rh->peer = rc->peer;
1811 rh->rs = tcpma_stream_client(rh, rc->handle);
1813 secprintf(("%s: sec: new connection\n", debug_prefix_time(NULL)));
1815 parse_pkt(&pkt, rc->pkt, (size_t)rc->pktlen);
1816 secprintf(("%s: sec: calling accept_fn\n", debug_prefix_time(NULL)));
1817 if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
1818 (*rc->accept_fn)(&rh->sech, NULL);
1820 (*rc->accept_fn)(&rh->sech, &pkt);
1830 const unsigned char *bufp = buf;
1832 secprintf(("%s: sec: parse_pkt: parsing buffer of %d bytes\n",
1833 debug_prefix_time(NULL), bufsize));
1835 pkt->type = (pktype_t)*bufp++;
1838 pkt->packet_size = bufsize+1;
1839 pkt->body = alloc(pkt->packet_size);
1841 pkt->body[0] = '\0';
1843 memcpy(pkt->body, bufp, bufsize);
1844 pkt->body[pkt->packet_size - 1] = '\0';
1846 pkt->size = strlen(pkt->body);
1848 secprintf(("%s: sec: parse_pkt: %s (%d): \"%s\"\n",
1849 debug_prefix_time(NULL), pkt_type2str(pkt->type),
1850 pkt->type, pkt->body));
1854 * Convert a packet header into a string
1858 const struct sec_handle * rh,
1861 static char retbuf[256];
1864 assert(pkt != NULL);
1866 snprintf(retbuf, SIZEOF(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
1867 VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
1868 rh->proto_handle, rh->sequence);
1870 secprintf(("%s: bsd: pkthdr2str handle '%s'\n",
1871 debug_prefix_time(NULL), rh->proto_handle));
1873 /* check for truncation. If only we had asprintf()... */
1874 assert(retbuf[strlen(retbuf) - 1] == '\n');
1880 * Parses out the header line in 'str' into the pkt and handle
1881 * Returns negative on parse error.
1893 assert(udp->dgram.cur != NULL);
1894 str = stralloc(udp->dgram.cur);
1896 /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */
1898 /* Read in "Amanda" */
1899 if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0)
1902 /* nothing is done with the major/minor numbers currently */
1903 if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL)
1906 /* Read in the packet type */
1907 if ((tok = strtok(NULL, " ")) == NULL)
1910 pkt_init_empty(pkt, pkt_str2type(tok));
1911 if (pkt->type == (pktype_t)-1)
1914 /* Read in "HANDLE" */
1915 if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0)
1918 /* parse the handle */
1919 if ((tok = strtok(NULL, " ")) == NULL)
1921 amfree(udp->handle);
1922 udp->handle = stralloc(tok);
1925 if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)
1928 /* parse the sequence number */
1929 if ((tok = strtok(NULL, "\n")) == NULL)
1931 udp->sequence = atoi(tok);
1933 /* Save the body, if any */
1934 if ((tok = strtok(NULL, "")) != NULL)
1935 pkt_cat(pkt, "%s", tok);
1941 #if 0 /* XXX we have no way of passing this back up */
1942 security_seterror(&rh->sech,
1943 "parse error in packet header : '%s'", origstr);
1951 struct sec_handle * rh,
1952 const char * remoteuser,
1953 const char * service)
1957 char *result = NULL;
1958 char *localuser = NULL;
1960 /* lookup our local user name */
1961 if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
1962 return vstralloc("getpwnam(", CLIENT_LOGIN, ") fails", NULL);
1966 * Make a copy of the user name in case getpw* is called by
1967 * any of the lower level routines.
1969 localuser = stralloc(pwd->pw_name);
1971 #ifndef USE_AMANDAHOSTS
1972 r = check_user_ruserok(rh->hostname, pwd, remoteuser);
1974 r = check_user_amandahosts(rh->hostname, rh->peer.sin_addr, pwd, remoteuser, service);
1977 result = vstralloc("user ", remoteuser, " from ", rh->hostname,
1978 " is not allowed to execute the service ",
1979 service, ": ", r, NULL);
1987 * See if a remote user is allowed in. This version uses ruserok()
1990 * Returns 0 on success, or negative on error.
1995 struct passwd * pwd,
1996 const char * remoteuser)
2007 char number[NUM_STR_SIZE];
2008 uid_t myuid = getuid();
2011 * note that some versions of ruserok (eg SunOS 3.2) look in
2012 * "./.rhosts" rather than "~CLIENT_LOGIN/.rhosts", so we have to
2013 * chdir ourselves. Sigh.
2015 * And, believe it or not, some ruserok()'s try an initgroup just
2016 * for the hell of it. Since we probably aren't root at this point
2017 * it'll fail, and initgroup "helpfully" will blatt "Setgroups: Not owner"
2018 * into our stderr output even though the initgroup failure is not a
2019 * problem and is expected. Thanks a lot. Not.
2021 if (pipe(fd) != 0) {
2022 return stralloc2("pipe() fails: ", strerror(errno));
2024 if ((ruserok_pid = fork()) < 0) {
2025 return stralloc2("fork() fails: ", strerror(errno));
2026 } else if (ruserok_pid == 0) {
2030 fError = fdopen(fd[1], "w");
2032 error("Can't fdopen: %s", strerror(errno));
2035 /* pamper braindead ruserok's */
2036 if (chdir(pwd->pw_dir) != 0) {
2037 fprintf(fError, "chdir(%s) failed: %s",
2038 pwd->pw_dir, strerror(errno));
2043 #if defined(SHOW_SECURITY_DETAIL) /* { */
2045 char *dir = stralloc(pwd->pw_dir);
2047 secprintf(("%s: bsd: calling ruserok(%s, %d, %s, %s)\n",
2048 debug_prefix_time(NULL),
2049 host, ((myuid == 0) ? 1 : 0), remoteuser, pwd->pw_name));
2051 secprintf(("%s: bsd: because you are running as root, ",
2052 debug_prefix(NULL)));
2053 secprintf(("/etc/hosts.equiv will not be used\n"));
2055 show_stat_info("/etc/hosts.equiv", NULL);
2057 show_stat_info(dir, "/.rhosts");
2062 saved_stderr = dup(2);
2064 if (open("/dev/null", O_RDWR) == -1) {
2065 secprintf(("%s: Could not open /dev/null: %s\n",
2066 debug_prefix(NULL), strerror(errno)));
2069 ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN);
2076 (void)dup2(saved_stderr,2);
2077 close(saved_stderr);
2081 fError = fdopen(fd[0], "r");
2083 error("Can't fdopen: %s", strerror(errno));
2088 while ((es = agets(fError)) != NULL) {
2093 if (result == NULL) {
2094 result = stralloc("");
2096 strappend(result, ": ");
2098 strappend(result, es);
2103 pid = wait(&exitcode);
2104 while (pid != ruserok_pid) {
2105 if ((pid == (pid_t) -1) && (errno != EINTR)) {
2107 return stralloc2("ruserok wait failed: %s", strerror(errno));
2109 pid = wait(&exitcode);
2111 if (WIFSIGNALED(exitcode)) {
2113 snprintf(number, SIZEOF(number), "%d", WTERMSIG(exitcode));
2114 return stralloc2("ruserok child got signal ", number);
2116 if (WEXITSTATUS(exitcode) == 0) {
2118 } else if (result == NULL) {
2119 result = stralloc("ruserok failed");
2126 * Check to see if a user is allowed in. This version uses .amandahosts
2127 * Returns -1 on failure, or 0 on success.
2130 check_user_amandahosts(
2132 struct in_addr addr,
2133 struct passwd * pwd,
2134 const char * remoteuser,
2135 const char * service)
2139 const char *fileuser;
2141 char *result = NULL;
2145 char n1[NUM_STR_SIZE];
2146 char n2[NUM_STR_SIZE];
2149 char *aservice = NULL;
2151 secprintf(("check_user_amandahosts(host=%s, pwd=%p, "
2152 "remoteuser=%s, service=%s)\n",
2153 host, pwd, remoteuser, service));
2155 ptmp = stralloc2(pwd->pw_dir, "/.amandahosts");
2156 #if defined(SHOW_SECURITY_DETAIL) /* { */
2157 show_stat_info(ptmp, "");;
2159 if ((fp = fopen(ptmp, "r")) == NULL) {
2160 result = vstralloc("cannot open ", ptmp, ": ", strerror(errno), NULL);
2166 * Make sure the file is owned by the Amanda user and does not
2167 * have any group/other access allowed.
2169 if (fstat(fileno(fp), &sbuf) != 0) {
2170 result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
2173 if (sbuf.st_uid != pwd->pw_uid) {
2174 snprintf(n1, SIZEOF(n1), "%ld", (long)sbuf.st_uid);
2175 snprintf(n2, SIZEOF(n2), "%ld", (long)pwd->pw_uid);
2176 result = vstralloc(ptmp, ": ",
2182 if ((sbuf.st_mode & 077) != 0) {
2183 result = stralloc2(ptmp,
2184 ": incorrect permissions; file must be accessible only by its owner");
2189 * Now, scan the file for the host/user/service.
2192 while ((line = agets(fp)) != NULL) {
2198 #if defined(SHOW_SECURITY_DETAIL) /* { */
2199 secprintf(("%s: bsd: processing line: <%s>\n", debug_prefix(NULL), line));
2201 /* get the host out of the file */
2202 if ((filehost = strtok(line, " \t")) == NULL) {
2207 /* get the username. If no user specified, then use the local user */
2208 if ((fileuser = strtok(NULL, " \t")) == NULL) {
2209 fileuser = pwd->pw_name;
2212 hostmatch = (strcasecmp(filehost, host) == 0);
2213 /* ok if addr=127.0.0.1 and
2214 * either localhost or localhost.domain is in .amandahost */
2216 if (strcmp(inet_ntoa(addr), "127.0.0.1")== 0 &&
2217 (strcasecmp(filehost, "localhost")== 0 ||
2218 strcasecmp(filehost, "localhost.localdomain")== 0))
2223 usermatch = (strcasecmp(fileuser, remoteuser) == 0);
2224 #if defined(SHOW_SECURITY_DETAIL) /* { */
2225 secprintf(("%s: bsd: comparing \"%s\" with\n", debug_prefix(NULL), filehost));
2226 secprintf(("%s: bsd: \"%s\" (%s)\n", host,
2227 debug_prefix(NULL), hostmatch ? "match" : "no match"));
2228 secprintf(("%s: bsd: and \"%s\" with\n", fileuser, debug_prefix(NULL)));
2229 secprintf(("%s: bsd: \"%s\" (%s)\n", remoteuser,
2230 debug_prefix(NULL), usermatch ? "match" : "no match"));
2233 if (!hostmatch || !usermatch) {
2245 /* get the services. If no service specified, then use
2246 * noop/selfcheck/sendsize/sendbackup
2248 aservice = strtok(NULL, " \t,");
2250 if (strcmp(service,"noop") == 0 ||
2251 strcmp(service,"selfcheck") == 0 ||
2252 strcmp(service,"sendsize") == 0 ||
2253 strcmp(service,"sendbackup") == 0) {
2266 if (strcmp(aservice,service) == 0) {
2270 if (strcmp(aservice, "amdump") == 0 &&
2271 (strcmp(service, "noop") == 0 ||
2272 strcmp(service, "selfcheck") == 0 ||
2273 strcmp(service, "sendsize") == 0 ||
2274 strcmp(service, "sendbackup") == 0)) {
2278 } while((aservice = strtok(NULL, " \t,")) != NULL);
2280 if (aservice && strcmp(aservice, service) == 0) {
2289 if (strcmp(service, "amindexd") == 0 ||
2290 strcmp(service, "amidxtaped") == 0) {
2291 result = vstralloc("Please add \"amindexd amidxtaped\" to "
2292 "the line in ", ptmp, NULL);
2293 } else if (strcmp(service, "amdump") == 0 ||
2294 strcmp(service, "noop") == 0 ||
2295 strcmp(service, "selfcheck") == 0 ||
2296 strcmp(service, "sendsize") == 0 ||
2297 strcmp(service, "sendbackup") == 0) {
2298 result = vstralloc("Please add \"amdump\" to the line in ",
2301 result = vstralloc(ptmp, ": ",
2302 "invalid service ", service, NULL);
2314 /* return 1 on success, 0 on failure */
2317 struct sockaddr_in *addr,
2319 unsigned long cksum,
2322 char * remotehost = NULL, *remoteuser = NULL;
2323 char * bad_bsd = NULL;
2324 struct hostent * hp;
2325 struct passwd * pwptr;
2333 (void)cksum; /* Quiet unused parameter warning */
2335 secprintf(("%s: check_security(addr=%p, str='%s', cksum=%ul, errstr=%p\n",
2336 debug_prefix(NULL), addr, str, cksum, errstr));
2337 dump_sockaddr(addr);
2341 /* what host is making the request? */
2343 hp = gethostbyaddr((char *)&addr->sin_addr, SIZEOF(addr->sin_addr),
2346 /* XXX include remote address in message */
2347 *errstr = vstralloc("[",
2348 "addr ", inet_ntoa(addr->sin_addr), ": ",
2349 "hostname lookup failed",
2353 remotehost = stralloc(hp->h_name);
2355 /* Now let's get the hostent for that hostname */
2356 hp = gethostbyname( remotehost );
2358 /* XXX include remote hostname in message */
2359 *errstr = vstralloc("[",
2360 "host ", remotehost, ": ",
2361 "hostname lookup failed",
2367 /* Verify that the hostnames match -- they should theoretically */
2368 if (strncasecmp( remotehost, hp->h_name, strlen(remotehost)+1 ) != 0 ) {
2369 *errstr = vstralloc("[",
2370 "hostnames do not match: ",
2371 remotehost, " ", hp->h_name,
2377 /* Now let's verify that the ip which gave us this hostname
2378 * is really an ip for this hostname; or is someone trying to
2379 * break in? (THIS IS THE CRUCIAL STEP)
2381 for (i = 0; hp->h_addr_list[i]; i++) {
2382 if (memcmp(hp->h_addr_list[i],
2383 (char *) &addr->sin_addr, SIZEOF(addr->sin_addr)) == 0)
2384 break; /* name is good, keep it */
2387 /* If we did not find it, your DNS is messed up or someone is trying
2388 * to pull a fast one on you. :(
2391 /* Check even the aliases list. Work around for Solaris if dns goes over NIS */
2393 if (!hp->h_addr_list[i] ) {
2394 for (j = 0; hp->h_aliases[j] !=0 ; j++) {
2395 if (strcmp(hp->h_aliases[j],inet_ntoa(addr->sin_addr)) == 0)
2396 break; /* name is good, keep it */
2398 if (!hp->h_aliases[j] ) {
2399 *errstr = vstralloc("[",
2400 "ip address ", inet_ntoa(addr->sin_addr),
2401 " is not in the ip list for ", remotehost,
2409 /* next, make sure the remote port is a "reserved" one */
2411 if (ntohs(addr->sin_port) >= IPPORT_RESERVED) {
2412 char number[NUM_STR_SIZE];
2414 snprintf(number, SIZEOF(number), "%u",
2415 (unsigned int)ntohs(addr->sin_port));
2416 *errstr = vstralloc("[",
2417 "host ", remotehost, ": ",
2418 "port ", number, " not secure",
2424 /* extract the remote user name from the message */
2429 bad_bsd = vstralloc("[",
2430 "host ", remotehost, ": ",
2431 "bad bsd security line",
2435 if (strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
2445 skip_whitespace(s, ch);
2453 skip_non_whitespace(s, ch);
2455 remoteuser = stralloc(fp);
2459 /* lookup our local user name */
2462 if ((pwptr = getpwuid(myuid)) == NULL)
2463 error("error [getpwuid(%d) fails]", myuid);
2465 secprintf(("%s: bsd security: remote host %s user %s local user %s\n",
2466 debug_prefix(NULL), remotehost, remoteuser, pwptr->pw_name));
2468 #ifndef USE_AMANDAHOSTS
2469 s = check_user_ruserok(remotehost, pwptr, remoteuser);
2471 s = check_user_amandahosts(remotehost, addr->sin_addr, pwptr, remoteuser, NULL);
2475 *errstr = vstralloc("[",
2476 "access as ", pwptr->pw_name, " not allowed",
2477 " from ", remoteuser, "@", remotehost,
2478 ": ", s, "]", NULL);
2483 return *errstr == NULL;
2487 * Writes out the entire iovec
2495 ssize_t delta, n, total;
2497 assert(iov != NULL);
2500 while (iovcnt > 0) {
2504 n = writev(fd, iov, iovcnt);
2508 secprintf(("%s: net_writev got EINTR\n",
2509 debug_prefix(NULL)));
2517 * Iterate through each iov. Figure out what we still need
2520 for (; n > 0; iovcnt--, iov++) {
2521 /* 'delta' is the bytes written from this iovec */
2522 delta = ((size_t)n < iov->iov_len) ? n : (ssize_t)iov->iov_len;
2523 /* subtract from the total num bytes written */
2526 /* subtract from this iovec */
2527 iov->iov_len -= delta;
2528 iov->iov_base = (char *)iov->iov_base + delta;
2529 /* if this iovec isn't empty, run the writev again */
2530 if (iov->iov_len > 0)
2539 * Like read(), but waits until the entire buffer has been filled.
2548 char *buf = vbuf; /* ptr arith */
2550 size_t size = origsize;
2552 secprintf(("%s: net_read: begin %d\n", debug_prefix_time(NULL), origsize));
2555 secprintf(("%s: net_read: while %d\n",
2556 debug_prefix_time(NULL), size));
2557 nread = net_read_fillbuf(fd, timeout, buf, size);
2559 secprintf(("%s: db: net_read: end return(-1)\n",
2560 debug_prefix_time(NULL)));
2564 secprintf(("%s: net_read: end return(0)\n",
2565 debug_prefix_time(NULL)));
2571 secprintf(("%s: net_read: end %d\n",
2572 debug_prefix_time(NULL), origsize));
2573 return ((ssize_t)origsize);
2577 * net_read likes to do a lot of little reads. Buffer it.
2590 secprintf(("%s: net_read_fillbuf: begin\n", debug_prefix_time(NULL)));
2592 FD_SET(fd, &readfds);
2593 tv.tv_sec = timeout;
2595 switch (select(fd + 1, &readfds, NULL, NULL, &tv)) {
2600 secprintf(("%s: net_read_fillbuf: case -1\n",
2601 debug_prefix_time(NULL)));
2604 secprintf(("%s: net_read_fillbuf: case 1\n",
2605 debug_prefix_time(NULL)));
2606 assert(FD_ISSET(fd, &readfds));
2609 secprintf(("%s: net_read_fillbuf: case default\n",
2610 debug_prefix_time(NULL)));
2614 nread = read(fd, buf, size);
2617 secprintf(("%s: net_read_fillbuf: end %d\n",
2618 debug_prefix_time(NULL), nread));
2624 * Display stat() information about a file.
2632 char *name = vstralloc(a, b, NULL);
2634 struct passwd *pwptr;
2636 struct group *grptr;
2639 if (stat(name, &sbuf) != 0) {
2640 secprintf(("%s: bsd: cannot stat %s: %s\n",
2641 debug_prefix_time(NULL), name, strerror(errno)));
2645 if ((pwptr = getpwuid(sbuf.st_uid)) == NULL) {
2646 owner = alloc(NUM_STR_SIZE + 1);
2647 snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid);
2649 owner = stralloc(pwptr->pw_name);
2651 if ((grptr = getgrgid(sbuf.st_gid)) == NULL) {
2652 group = alloc(NUM_STR_SIZE + 1);
2653 snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
2655 group = stralloc(grptr->gr_name);
2657 secprintf(("%s: bsd: processing file: %s\n", debug_prefix(NULL), name));
2658 secprintf(("%s: bsd: owner=%s group=%s mode=%03o\n",
2659 debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777)));