- bh = alloc(sizeof(*bh));
- bh->proto_handle=NULL;
- security_handleinit(&bh->sech, &bsd_security_driver);
-
- /*
- * Only init the socket once
- */
- if (netfd.dgram.socket == 0) {
- uid_t euid;
- dgram_zero(&netfd.dgram);
-
- euid = geteuid();
- seteuid(0);
- dgram_bind(&netfd.dgram, &port);
- seteuid(euid);
- /*
- * We must have a reserved port. Bomb if we didn't get one.
- */
- if (port >= IPPORT_RESERVED) {
- security_seterror(&bh->sech,
- "unable to bind to a reserved port (got port %d)",
- port);
- (*fn)(arg, &bh->sech, S_ERROR);
- return;
- }
- }
-
- if ((he = gethostbyname(hostname)) == NULL) {
- security_seterror(&bh->sech,
- "%s: could not resolve hostname", hostname);
- (*fn)(arg, &bh->sech, S_ERROR);
- return;
- }
- if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
- port = htons(AMANDA_SERVICE_DEFAULT);
- else
- port = se->s_port;
- amanda_gettimeofday(&sequence_time, &dontcare);
- sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
- handle=malloc(15);
- snprintf(handle,14,"000-%08x", newhandle++);
- if (inithandle(bh, he, port, handle, sequence) < 0)
- (*fn)(arg, &bh->sech, S_ERROR);
- else
- (*fn)(arg, &bh->sech, S_OK);
-}
-
-/*
- * Setup to accept new incoming connections
- */
-static void
-bsd_accept(in, out, fn)
- int in, out;
- void (*fn) P((security_handle_t *, pkt_t *));
-{
-
- assert(in >= 0 && out >= 0);
- assert(fn != NULL);
-
- /*
- * We assume in and out point to the same socket, and just use
- * in.
- */
- dgram_socket(&netfd.dgram, in);
-
- /*
- * Assign the function and return. When they call recvpkt later,
- * the recvpkt callback will call this function when it discovers
- * new incoming connections
- */
- accept_fn = fn;
-
- netfd_addref();
-}
-
-/*
- * Given a hostname and a port, setup a bsd_handle
- */
-static int
-inithandle(bh, he, port, handle, sequence)
- struct bsd_handle *bh;
- struct hostent *he;
- int port;
- char *handle;
- int sequence;
-{
- int i;
-
- assert(he != NULL);
- assert(port > 0);
-
- /*
- * Save the hostname and port info
- */
- strncpy(bh->hostname, he->h_name, sizeof(bh->hostname) - 1);
- bh->hostname[sizeof(bh->hostname) - 1] = '\0';
- bh->peer.sin_addr = *(struct in_addr *)he->h_addr;
- bh->peer.sin_port = port;
- bh->peer.sin_family = AF_INET;
-
- bh->prev = bh_last;
- if(bh_last) {bh->prev->next = bh;}
- if(!bh_first) {bh_first = bh;}
- bh->next = NULL;
- bh_last = bh;
-
- /*
- * Do a forward lookup of the hostname. This is unnecessary if we
- * are initiating the connection, but is very serious if we are
- * receiving. We want to make sure the hostname
- * resolves back to the remote ip for security reasons.
- */
- if ((he = gethostbyname(bh->hostname)) == NULL) {
- security_seterror(&bh->sech,
- "%s: could not resolve hostname", bh->hostname);
- return (-1);
- }
- /*
- * Make sure the hostname matches. This should always work.
- */
- if (strncasecmp(bh->hostname, he->h_name, strlen(bh->hostname)) != 0) {
- security_seterror(&bh->sech,
- "%s: did not resolve to %s", bh->hostname, bh->hostname);
- return (-1);
- }
-
- /*
- * Now look for a matching ip address.
- */
- for (i = 0; he->h_addr_list[i] != NULL; i++) {
- if (memcmp(&bh->peer.sin_addr, he->h_addr_list[i],
- sizeof(struct in_addr)) == 0) {
- break;
- }
- }
-
- /*
- * If we didn't find it, try the aliases. This is a workaround for
- * Solaris if DNS goes over NIS.
- */
- if (he->h_addr_list[i] == NULL) {
- const char *ipstr = inet_ntoa(bh->peer.sin_addr);
- for (i = 0; he->h_aliases[i] != NULL; i++) {
- if (strcmp(he->h_aliases[i], ipstr) == 0)
- break;
- }
- /*
- * No aliases either. Failure. Someone is fooling with us or
- * DNS is messed up.
- */
- if (he->h_aliases[i] == NULL) {
- security_seterror(&bh->sech,
- "DNS check failed: no matching ip address for %s",
- bh->hostname);
- return (-1);
- }
- }
-
- bh->sequence = sequence;
- bh->event_id = newevent++;
- bh->proto_handle = handle;
- bh->fn = NULL;
- bh->arg = NULL;
- bh->ev_read = NULL;
- bh->ev_timeout = NULL;
-
- bsdprintf(("%s: adding handle '%s'\n",
- debug_prefix_time(NULL), bh->proto_handle));
-
- return(0);
-}
-
-/*
- * Frees a handle allocated by the above
- */
-static void
-bsd_close(cookie)
- void *cookie;
-{
- struct bsd_handle *bh = cookie;
-
- if(bh->proto_handle == NULL) {
- return;
- }
-
- bsdprintf(("%s: close handle '%s'\n",
- debug_prefix_time(NULL), bh->proto_handle));
-
- bsd_recvpkt_cancel(bh);
- if(bh->next) {
- bh->next->prev = bh->prev;
- }
- else {
- bh_last = bh->prev;
- }
- if(bh->prev) {
- bh->prev->next = bh->next;
- }
- else {
- bh_first = bh->next;
- }
-
- amfree(bh);
-}
-
-/*
- * Transmit a packet. Add security information first.
- */
-static int
-bsd_sendpkt(cookie, pkt)
- void *cookie;
- pkt_t *pkt;
-{
- struct bsd_handle *bh = cookie;
- struct passwd *pwd;
-
- assert(bh != NULL);
- assert(pkt != NULL);
-
- /*
- * Initialize this datagram, and add the header
- */
- dgram_zero(&netfd.dgram);
- dgram_cat(&netfd.dgram, pkthdr2str(bh, pkt));
-
- /*
- * Add the security info. This depends on which kind of packet we're
- * sending.
- */
- switch (pkt->type) {
- case P_REQ:
- /*
- * Requests get sent with our username in the body
- */
- if ((pwd = getpwuid(geteuid())) == NULL) {
- security_seterror(&bh->sech,
- "can't get login name for my uid %ld", (long)getuid());
- return (-1);
- }
- dgram_cat(&netfd.dgram, "SECURITY USER %s\n", pwd->pw_name);
- break;
-
- default:
- break;
- }
-
- /*
- * Add the body, and send it
- */
- dgram_cat(&netfd.dgram, pkt->body);
- if (dgram_send_addr(bh->peer, &netfd.dgram) != 0) {
- security_seterror(&bh->sech,
- "send %s to %s failed: %s", pkt_type2str(pkt->type),
- bh->hostname, strerror(errno));
- return (-1);
- }
- return (0);
-}
-
-/*
- * Set up to receive a packet asynchronously, and call back when it has
- * been read.
- */
-static void
-bsd_recvpkt(cookie, fn, arg, timeout)
- void *cookie, *arg;
- void (*fn) P((void *, pkt_t *, security_status_t));
- int timeout;
-{
- struct bsd_handle *bh = cookie;
-
- assert(bh != NULL);
- assert(fn != NULL);
-
-
- /*
- * Subsequent recvpkt calls override previous ones
- */
- if (bh->ev_read == NULL) {
- netfd_addref();
- bh->ev_read = event_register(bh->event_id, EV_WAIT,
- recvpkt_callback, bh);
- }
- if (bh->ev_timeout != NULL)
- event_release(bh->ev_timeout);
- if (timeout < 0)
- bh->ev_timeout = NULL;
- else
- bh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, bh);
- bh->fn = fn;
- bh->arg = arg;
-}
-
-/*
- * Remove a async receive request on this handle from the queue.
- * If it is the last one to be removed, then remove the event
- * handler for our network fd
- */
-static void
-bsd_recvpkt_cancel(cookie)
- void *cookie;
-{
- struct bsd_handle *bh = cookie;
-
- assert(bh != NULL);