Ejemplo n.º 1
0
int avahi_netlink_work(AvahiNetlink *nl, int block) {
    ssize_t bytes;
    struct msghdr smsg;
    struct cmsghdr *cmsg;
    struct ucred *cred;
    struct iovec iov;
    struct nlmsghdr *p;
    char cred_msg[CMSG_SPACE(sizeof(struct ucred))];

    assert(nl);

    iov.iov_base = nl->buffer;
    iov.iov_len = nl->buffer_length;

    smsg.msg_name = NULL;
    smsg.msg_namelen = 0;
    smsg.msg_iov = &iov;
    smsg.msg_iovlen = 1;
    smsg.msg_control = cred_msg;
    smsg.msg_controllen = sizeof(cred_msg);
    smsg.msg_flags = (block ? 0 : MSG_DONTWAIT);

    if ((bytes = recvmsg(nl->fd, &smsg, 0)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            return 0;

        avahi_log_error(__FILE__": recvmsg() failed: %s", strerror(errno));
        return -1;
    }

    cmsg = CMSG_FIRSTHDR(&smsg);

    if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
        avahi_log_warn("No sender credentials received, ignoring data.");
        return -1;
    }

    cred = (struct ucred*) CMSG_DATA(cmsg);

    if (cred->pid != 0)
        return -1;

    p = (struct nlmsghdr *) nl->buffer;

    assert(nl->callback);

    for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
        if (!NLMSG_OK(p, (size_t) bytes)) {
            avahi_log_warn(__FILE__": packet truncated");
            return -1;
        }

        nl->callback(nl, p, nl->userdata);
    }

    return 0;
}
Ejemplo n.º 2
0
void static_service_load(int in_chroot) {
    StaticServiceGroup *g, *n;
    glob_t globbuf;
    int globret;
    char **p;

    for (g = groups; g; g = n) {
        struct stat st;

        n = g->groups_next;

        if (stat(g->filename, &st) < 0) {

            if (errno == ENOENT)
                avahi_log_info("Service group file %s vanished, removing services.", g->filename);
            else
                avahi_log_warn("Failed to stat() file %s, ignoring: %s", g->filename, strerror(errno));

            static_service_group_free(g);
        } else if (st.st_mtime != g->mtime) {
            avahi_log_info("Service group file %s changed, reloading.", g->filename);

            if (static_service_group_load(g) < 0) {
                avahi_log_warn("Failed to load service group file %s, removing service.", g->filename);
                static_service_group_free(g);
            }
        }
    }

    memset(&globbuf, 0, sizeof(globbuf));

    if ((globret = glob(in_chroot ? "/services/*.service" : AVAHI_SERVICE_DIR "/*.service", GLOB_ERR, NULL, &globbuf)) != 0)

        switch (globret) {
#ifdef GLOB_NOSPACE
	    case GLOB_NOSPACE:
	        avahi_log_error("Not enough memory to read service directory "AVAHI_SERVICE_DIR".");
	        break;
#endif
#ifdef GLOB_NOMATCH
            case GLOB_NOMATCH:
	        avahi_log_info("No service file found in "AVAHI_SERVICE_DIR".");
	        break;
#endif
            default:
	        avahi_log_error("Failed to read "AVAHI_SERVICE_DIR".");
	        break;
        }

    else {
        for (p = globbuf.gl_pathv; *p; p++)
            load_file(*p);

        globfree(&globbuf);
    }
}
Ejemplo n.º 3
0
DBusHandlerResult avahi_dbus_msg_record_browser_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
    DBusError error;
    RecordBrowserInfo *i = userdata;

    assert(c);
    assert(m);
    assert(i);

    dbus_error_init(&error);

    avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
                    dbus_message_get_interface(m),
                    dbus_message_get_path(m),
                    dbus_message_get_member(m));

    /* Introspection */
    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
        return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.RecordBrowser.xml");

    /* Access control */
    if (strcmp(dbus_message_get_sender(m), i->client->name))
        return avahi_dbus_respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);

    if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Free")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing RecordBrowser::Free message");
            goto fail;
        }

        avahi_dbus_record_browser_free(i);
        return avahi_dbus_respond_ok(c, m);

    }

    if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Start")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing RecordBrowser::Start message");
            goto fail;
        }

        avahi_dbus_record_browser_start(i);
        return avahi_dbus_respond_ok(c, m);

    }


    avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));

fail:
    if (dbus_error_is_set(&error))
        dbus_error_free(&error);

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
Ejemplo n.º 4
0
int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int idx, int join) {
#ifdef HAVE_STRUCT_IP_MREQN
    struct ip_mreqn mreq;
#else
    struct ip_mreq mreq;
#endif
    struct sockaddr_in sa;

    assert(fd >= 0);
    assert(idx >= 0);
    assert(a);

    memset(&mreq, 0, sizeof(mreq));
#ifdef HAVE_STRUCT_IP_MREQN
    mreq.imr_ifindex = idx;
    mreq.imr_address.s_addr = a->address;
#else
    mreq.imr_interface.s_addr = a->address;
#endif
    mdns_mcast_group_ipv4(&sa);
    mreq.imr_multiaddr = sa.sin_addr;

    /* Some network drivers have issues with dropping membership of
     * mcast groups when the iface is down, but don't allow rejoining
     * when it comes back up. This is an ugly workaround */
    if (join)
        setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));

    if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        avahi_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", strerror(errno));
        return -1;
    }

    return 0;
}
Ejemplo n.º 5
0
int avahi_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int idx, int join, AvahiPublishProtocol proto) {
    struct ipv6_mreq mreq6;
    struct sockaddr_in6 sa6;

    assert(fd >= 0);
    assert(idx >= 0);
    assert(a);

    memset(&mreq6, 0, sizeof(mreq6));
/*
	send proto for 'sa6' to join appropiate
	multicast group
*/
    mcast_group_ipv6 (&sa6, proto);
    mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
    mreq6.ipv6mr_interface = idx;

    if (join)
        setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));

    if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
        avahi_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", strerror(errno));
        return -1;
    }

    return 0;
}
Ejemplo n.º 6
0
int avahi_netlink_work(AvahiNetlink *nl, int block) {
    ssize_t bytes;
    struct nlmsghdr *p;
    
    assert(nl);
    
    if ((bytes = recv(nl->fd, nl->buffer, nl->buffer_length, block ? 0 : MSG_DONTWAIT)) < 0) {
        
        if (errno == EAGAIN || errno == EINTR)
            return 0;
        
        avahi_log_error(__FILE__": recv() failed: %s", strerror(errno));
        return -1;
    }

    p = (struct nlmsghdr *) nl->buffer;
    
    assert(nl->callback);
    
    for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
        if (!NLMSG_OK(p, (size_t) bytes)) {
            avahi_log_warn(__FILE__": packet truncated");
            return -1;
        }
        
        nl->callback(nl, p, nl->userdata);
    }
    
    return 0;
}
Ejemplo n.º 7
0
static void set_one_rlimit(int resource, rlim_t limit, const char *name) {
    struct rlimit rl;
    rl.rlim_cur = rl.rlim_max = limit;

    if (setrlimit(resource, &rl) < 0)
        avahi_log_warn("setrlimit(%s, {%u, %u}) failed: %s", name, (unsigned) limit, (unsigned) limit, strerror(errno));
}
Ejemplo n.º 8
0
static void sender_timeout_callback(AvahiTimeEvent *e, void *userdata) {
    AvahiWideAreaLookup *l = userdata;
    struct timeval tv;

    assert(l);

    /* Try another DNS server after three retries */
    if (l->n_send >= 3 && avahi_address_cmp(&l->engine->dns_servers[l->engine->current_dns_server], &l->dns_server_used) == 0) {
        next_dns_server(l->engine);

        if (avahi_address_cmp(&l->engine->dns_servers[l->engine->current_dns_server], &l->dns_server_used) == 0)
            /* There is no other DNS server, fail */
            l->n_send = 1000;
    }
    
    if (l->n_send >= 6) {
        avahi_log_warn(__FILE__": Query timed out.");
        avahi_server_set_errno(l->engine->server, AVAHI_ERR_TIMEOUT);
        l->callback(l->engine, AVAHI_BROWSER_FAILURE, AVAHI_LOOKUP_RESULT_WIDE_AREA, NULL, l->userdata);
        lookup_stop(l);
        return;
    }

    assert(l->packet);
    send_to_dns_server(l, l->packet);
    l->n_send++;

    avahi_time_event_update(e, avahi_elapse_time(&tv, 1000, 0));
}
Ejemplo n.º 9
0
static AvahiSEntryGroup* add_dns_servers(AvahiServer *s, AvahiSEntryGroup* g, char **l) {
    char **p;

    assert(s);
    assert(l);

    if (!g)
        g = avahi_s_entry_group_new(s, NULL, NULL);

    assert(avahi_s_entry_group_is_empty(g));

    for (p = l; *p; p++) {
        AvahiAddress a;

        if (!avahi_address_parse(*p, AVAHI_PROTO_UNSPEC, &a))
            avahi_log_warn("Failed to parse address '%s', ignoring.", *p);
        else
            if (avahi_server_add_dns_server_address(s, g, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, NULL, AVAHI_DNS_SERVER_RESOLVE, &a, 53) < 0) {
                avahi_s_entry_group_free(g);
                avahi_log_error("Failed to add DNS server address: %s", avahi_strerror(avahi_server_errno(s)));
                return NULL;
            }
    }

    avahi_s_entry_group_commit(g);

    return g;
}
Ejemplo n.º 10
0
static void client_work(AvahiWatch *watch, AVAHI_GCC_UNUSED int fd, AvahiWatchEvent events, void *userdata) {
    Client *c = userdata;

    assert(c);

    if ((events & AVAHI_WATCH_IN) && c->inbuf_length < sizeof(c->inbuf)) {
        ssize_t r;

        if ((r = read(c->fd, c->inbuf + c->inbuf_length, sizeof(c->inbuf) - c->inbuf_length)) <= 0) {
            if (r < 0)
                avahi_log_warn("read(): %s", strerror(errno));
            client_free(c);
            return;
        }

        c->inbuf_length += r;
        assert(c->inbuf_length <= sizeof(c->inbuf));

        handle_input(c);
    }

    if ((events & AVAHI_WATCH_OUT) && c->outbuf_length > 0) {
        ssize_t r;

        if ((r = write(c->fd, c->outbuf, c->outbuf_length)) < 0) {
            avahi_log_warn("write(): %s", strerror(errno));
            client_free(c);
            return;
        }

        assert((size_t) r <= c->outbuf_length);
        c->outbuf_length -= r;

        if (c->outbuf_length)
            memmove(c->outbuf, c->outbuf + r, c->outbuf_length - r);

        if (c->outbuf_length == 0 && c->state == CLIENT_DEAD) {
            client_free(c);
            return;
        }
    }

    c->server->poll_api->watch_update(
        watch,
        (c->outbuf_length > 0 ? AVAHI_WATCH_OUT : 0) |
        (c->inbuf_length < sizeof(c->inbuf) ? AVAHI_WATCH_IN : 0));
}
Ejemplo n.º 11
0
static int ipv4_pktinfo(int fd) {
    int yes;

#ifdef IP_PKTINFO
    yes = 1;
    if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IP_PKTINFO failed: %s", strerror(errno));
        return -1;
    }
#else

#ifdef IP_RECVINTERFACE
    yes = 1;
    if (setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IP_RECVINTERFACE failed: %s", strerror(errno));
        return -1;
    }
#elif defined(IP_RECVIF)
    yes = 1;
    if (setsockopt (fd, IPPROTO_IP, IP_RECVIF, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IP_RECVIF failed: %s", strerror(errno));
        return -1;
    }
#endif

#ifdef IP_RECVDSTADDR
    yes = 1;
    if (setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IP_RECVDSTADDR failed: %s", strerror(errno));
        return -1;
    }
#endif

#endif /* IP_PKTINFO */

#ifdef IP_RECVTTL
    yes = 1;
    if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IP_RECVTTL failed: %s", strerror(errno));
        return -1;
    }
#endif

    return 0;
}
Ejemplo n.º 12
0
int avahi_open_unicast_socket_ipv6(void) {
    struct sockaddr_in6 local;
    int fd = -1, yes;

    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin6_family = AF_INET6;

    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
        avahi_log_warn("bind() failed: %s", strerror(errno));
        goto fail;
    }

    if (ipv6_pktinfo(fd) < 0)
        goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Ejemplo n.º 13
0
static int reuseaddr(int fd) {
    int yes;

    yes = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("SO_REUSEADDR failed: %s", strerror(errno));
        return -1;
    }

#ifdef SO_REUSEPORT
    yes = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("SO_REUSEPORT failed: %s", strerror(errno));
        return -1;
    }
#endif

    return 0;
}
Ejemplo n.º 14
0
int avahi_open_unicast_socket_ipv4(void) {
    struct sockaddr_in local;
    int fd = -1;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;

    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
        avahi_log_warn("bind() failed: %s", strerror(errno));
        goto fail;
    }

    if (ipv4_pktinfo(fd) < 0) {
         goto fail;
    }

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}
Ejemplo n.º 15
0
static int ipv6_pktinfo(int fd) {
    int yes;

#ifdef IPV6_RECVPKTINFO
    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_RECVPKTINFO failed: %s", strerror(errno));
        return -1;
    }
#elif defined(IPV6_PKTINFO)
    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_PKTINFO failed: %s", strerror(errno));
        return -1;
    }
#endif

#ifdef IPV6_RECVHOPS
    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_RECVHOPS failed: %s", strerror(errno));
        return -1;
    }
#elif defined(IPV6_RECVHOPLIMIT)
    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_RECVHOPLIMIT failed: %s", strerror(errno));
        return -1;
    }
#elif defined(IPV6_HOPLIMIT)
    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_HOPLIMIT failed: %s", strerror(errno));
        return -1;
    }
#endif

    return 0;
}
Ejemplo n.º 16
0
char *avahi_get_host_name(char *ret_s, size_t size) {
    assert(ret_s);
    assert(size > 0);

    if (gethostname(ret_s, size) >= 0) {
        ret_s[size-1] = 0;
        strip_bad_chars(ret_s);
    } else
        *ret_s = 0;

    if (strcmp(ret_s, "localhost") == 0 || strncmp(ret_s, "localhost.", 10) == 0) {
        *ret_s = 0;
        avahi_log_warn("System host name is set to 'localhost'. This is not a suitable mDNS host name, looking for alternatives.");
    }
    
    if (*ret_s == 0) {
        /* No hostname was set, so let's take the OS name */

#ifdef __linux__

        /* Try LSB distribution name first */
        if (load_lsb_distrib_id(ret_s, size) >= 0) {
            strip_bad_chars(ret_s);
            avahi_strdown(ret_s);
        }

        if (*ret_s == 0)
#endif

        {
            /* Try uname() second */
            struct utsname utsname;
            
            if (uname(&utsname) >= 0) {
                snprintf(ret_s, size, "%s", utsname.sysname);
                strip_bad_chars(ret_s);
                avahi_strdown(ret_s);
            }

            /* Give up */
            if (*ret_s == 0)
                snprintf(ret_s, size, "unnamed");
        }
    }

    if (size >= AVAHI_LABEL_MAX)
	ret_s[AVAHI_LABEL_MAX-1] = 0;    
    
    return ret_s;
}
Ejemplo n.º 17
0
static int bind_with_warn(int fd, const struct sockaddr *sa, socklen_t l) {

    assert(fd >= 0);
    assert(sa);
    assert(l > 0);

    if (bind(fd, sa, l) < 0) {

        if (errno != EADDRINUSE) {
            avahi_log_warn("bind() failed: %s", strerror(errno));
            return -1;
        }

        avahi_log_warn("*** WARNING: Detected another %s mDNS stack running on this host. This makes mDNS unreliable and is thus not recommended. ***",
                       sa->sa_family == AF_INET ? "IPv4" : "IPv6");

        /* Try again, this time with SO_REUSEADDR set */
        if (reuseaddr(fd) < 0)
            return -1;

        if (bind(fd, sa, l) < 0) {
            avahi_log_warn("bind() failed: %s", strerror(errno));
            return -1;
        }
    } else {

        /* We enable SO_REUSEADDR afterwards, to make sure that the
         * user may run other mDNS implementations if he really
         * wants. */

        if (reuseaddr(fd) < 0)
            return -1;
    }

    return 0;
}
Ejemplo n.º 18
0
static void send_response_packet(AvahiResponseScheduler *s, AvahiResponseJob *rj) {
    AvahiDnsPacket *p;
    unsigned n;

    assert(s);
    assert(rj);

    if (!(p = avahi_dns_packet_new_response(s->interface->hardware->mtu, 1)))
        return; /* OOM */
    n = 1;

    /* Put it in the packet. */
    if (packet_add_response_job(s, p, rj)) {

        /* Try to fill up packet with more responses, if available */
        while (s->jobs) {
            
            if (!packet_add_response_job(s, p, s->jobs))
                break;
            
            n++;
        }
        
    } else {
        size_t size;
        
        avahi_dns_packet_free(p);

        /* OK, the packet was too small, so create one that fits */
        size = avahi_record_get_estimate_size(rj->record) + AVAHI_DNS_PACKET_HEADER_SIZE;

        if (!(p = avahi_dns_packet_new_response(size + AVAHI_DNS_PACKET_EXTRA_SIZE, 1)))
            return; /* OOM */

        if (!packet_add_response_job(s, p, rj)) {
            avahi_dns_packet_free(p);

            avahi_log_warn("Record too large, cannot send");
            job_mark_done(s, rj);
            return;
        }
    }

    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ANCOUNT, n);
    avahi_interface_send_packet(s->interface, p, AVAHI_MDNS);
    avahi_dns_packet_free(p);
}
Ejemplo n.º 19
0
static void update_wide_area_servers(void) {
    AvahiAddress a[AVAHI_WIDE_AREA_SERVERS_MAX];
    unsigned n = 0;
    char **p;

    if (!resolv_conf_name_servers) {
        avahi_server_set_wide_area_servers(avahi_server, NULL, 0);
        return;
    }

    for (p = resolv_conf_name_servers; *p && n < AVAHI_WIDE_AREA_SERVERS_MAX; p++) {
        if (!avahi_address_parse(*p, AVAHI_PROTO_UNSPEC, &a[n]))
            avahi_log_warn("Failed to parse address '%s', ignoring.", *p);
        else
            n++;
    }

    avahi_server_set_wide_area_servers(avahi_server, a, n);
}
Ejemplo n.º 20
0
static void signal_callback(AvahiWatch *watch, AVAHI_GCC_UNUSED int fd, AVAHI_GCC_UNUSED AvahiWatchEvent event, AVAHI_GCC_UNUSED void *userdata) {
    int sig;
    const AvahiPoll *poll_api;

    assert(watch);
    assert(simple_poll_api);

    poll_api = avahi_simple_poll_get(simple_poll_api);

    if ((sig = daemon_signal_next()) <= 0) {
        avahi_log_error("daemon_signal_next() failed");
        poll_api->watch_free(watch);
        return;
    }

    switch (sig) {
        case SIGINT:
        case SIGQUIT:
        case SIGTERM:
            avahi_log_info(
                    "Got %s, quitting.",
                    sig == SIGINT ? "SIGINT" :
                    (sig == SIGQUIT ? "SIGQUIT" : "SIGTERM"));
            avahi_simple_poll_quit(simple_poll_api);
            break;

        case SIGHUP:
            avahi_log_info("Got SIGHUP, reloading.");

            reload_config();
            break;

        case SIGUSR1:
            avahi_log_info("Got SIGUSR1, dumping record data.");
            avahi_server_dump(avahi_server, dump, NULL);
            break;

        default:
            avahi_log_warn("Got spurious signal, ignoring.");
            break;
    }
}
Ejemplo n.º 21
0
static void update_browse_domains(void) {
    AvahiStringList *l;
    int n;
    char **p;

    if (!resolv_conf_search_domains) {
        avahi_server_set_browse_domains(avahi_server, NULL);
        return;
    }

    l = avahi_string_list_copy(config.server_config.browse_domains);

    for (p = resolv_conf_search_domains, n = 0; *p && n < BROWSE_DOMAINS_MAX; p++, n++) {
        if (!avahi_is_valid_domain_name(*p))
            avahi_log_warn("'%s' is no valid domain name, ignoring.", *p);
        else
            l = avahi_string_list_add(l, *p);
    }

    l = filter_duplicate_domains(l);

    avahi_server_set_browse_domains(avahi_server, l);
}
Ejemplo n.º 22
0
static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) {
    StaticServiceGroup *g = userdata;

    assert(s);
    assert(g);

    switch (state) {

        case AVAHI_ENTRY_GROUP_COLLISION: {
            char *n;

            remove_static_service_group_from_server(g);

            n = avahi_alternative_service_name(g->chosen_name);
            avahi_free(g->chosen_name);
            g->chosen_name = n;

            avahi_log_notice("Service name conflict for \"%s\" (%s), retrying with \"%s\".", g->name, g->filename, g->chosen_name);

            add_static_service_group_to_server(g);
            break;
        }

        case AVAHI_ENTRY_GROUP_ESTABLISHED:
            avahi_log_info("Service \"%s\" (%s) successfully established.", g->chosen_name, g->filename);
            break;

        case AVAHI_ENTRY_GROUP_FAILURE:
            avahi_log_warn("Failed to publish service \"%s\" (%s): %s", g->chosen_name, g->filename, avahi_strerror(avahi_server_errno(s)));
            remove_static_service_group_from_server(g);
            break;

        case AVAHI_ENTRY_GROUP_UNCOMMITED:
        case AVAHI_ENTRY_GROUP_REGISTERING:
            ;
    }
}
Ejemplo n.º 23
0
static void server_callback(AvahiServer *s, AvahiServerState state, void *userdata) {
    DaemonConfig *c = userdata;

    assert(s);
    assert(c);

    /* This function is possibly called before the global variable
     * avahi_server has been set, therefore we do it explicitly */

    avahi_server = s;

#ifdef HAVE_DBUS
    if (c->enable_dbus && state != AVAHI_SERVER_INVALID && state != AVAHI_SERVER_FAILURE)
        dbus_protocol_server_state_changed(state);
#endif

    switch (state) {
        case AVAHI_SERVER_RUNNING:
            avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s));
            sd_notifyf(0, "STATUS=Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s));
            avahi_set_proc_title(argv0, "%s: running [%s]", argv0, avahi_server_get_host_name_fqdn(s));

            static_service_add_to_server();
            static_hosts_add_to_server();

            remove_dns_server_entry_groups();

            if (c->publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0])
                resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf_name_servers);

            if (c->publish_dns_servers && c->publish_dns_servers[0])
                dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers);

            simple_protocol_restart_queries();
            break;

        case AVAHI_SERVER_COLLISION: {
            char *n;

            static_service_remove_from_server();
            static_hosts_remove_from_server();
            remove_dns_server_entry_groups();

            n = avahi_alternative_host_name(avahi_server_get_host_name(s));

            avahi_log_warn("Host name conflict, retrying with %s", n);
            sd_notifyf(0, "STATUS=Host name conflict, retrying with %s", n);
            avahi_set_proc_title(argv0, "%s: collision [%s]", argv0, n);

            avahi_server_set_host_name(s, n);
            avahi_free(n);

            break;
        }

        case AVAHI_SERVER_FAILURE:

            avahi_log_error("Server error: %s", avahi_strerror(avahi_server_errno(s)));
            sd_notifyf(0, "STATUS=Server error: %s", avahi_strerror(avahi_server_errno(s)));

            avahi_simple_poll_quit(simple_poll_api);
            break;

        case AVAHI_SERVER_REGISTERING:

            sd_notifyf(0, "STATUS=Registering host name %s", avahi_server_get_host_name_fqdn(s));
            avahi_set_proc_title(argv0, "%s: registering [%s]", argv0, avahi_server_get_host_name_fqdn(s));

            static_service_remove_from_server();
            static_hosts_remove_from_server();
            remove_dns_server_entry_groups();

            break;

        case AVAHI_SERVER_INVALID:
            break;

    }
}
Ejemplo n.º 24
0
static int load_resolv_conf(void) {
    int ret = -1;
    FILE *f;
    int i = 0, j = 0;

    avahi_strfreev(resolv_conf_name_servers);
    resolv_conf_name_servers = NULL;

    avahi_strfreev(resolv_conf_search_domains);
    resolv_conf_search_domains = NULL;

#ifdef ENABLE_CHROOT
    f = avahi_chroot_helper_get_file(RESOLV_CONF);
#else
    f = fopen(RESOLV_CONF, "r");
#endif

    if (!f) {
        avahi_log_warn("Failed to open "RESOLV_CONF": %s", strerror(errno));
        goto finish;
    }

    resolv_conf_name_servers = avahi_new0(char*, AVAHI_WIDE_AREA_SERVERS_MAX+1);
    resolv_conf_search_domains = avahi_new0(char*, BROWSE_DOMAINS_MAX+1);

    while (!feof(f)) {
        char ln[128];
        char *p;

        if (!(fgets(ln, sizeof(ln), f)))
            break;

        ln[strcspn(ln, "\r\n#")] = 0;
        p = ln + strspn(ln, "\t ");

        if ((has_prefix(p, "nameserver ") || has_prefix(p, "nameserver\t")) && i < AVAHI_WIDE_AREA_SERVERS_MAX) {
            p += 10;
            p += strspn(p, "\t ");
            p[strcspn(p, "\t ")] = 0;
            resolv_conf_name_servers[i++] = avahi_strdup(p);
        }

        if ((has_prefix(p, "search ") || has_prefix(p, "search\t") ||
             has_prefix(p, "domain ") || has_prefix(p, "domain\t"))) {

            p += 6;

            while (j < BROWSE_DOMAINS_MAX) {
                size_t k;

                p += strspn(p, "\t ");
                k = strcspn(p, "\t ");

                if (k > 0) {
                    resolv_conf_search_domains[j++] = avahi_strndup(p, k);
                    p += k;
                }

                if (!*p)
                    break;
            }
        }
    }

    ret = 0;

finish:

    if (ret != 0) {
        avahi_strfreev(resolv_conf_name_servers);
        resolv_conf_name_servers = NULL;

        avahi_strfreev(resolv_conf_search_domains);
        resolv_conf_search_domains = NULL;
    }

    if (f)
        fclose(f);

    return ret;
}
Ejemplo n.º 25
0
int main(int argc, char *argv[]) {
    int r = 255;
    int wrote_pid_file = 0;

    avahi_set_log_function(log_function);

    init_rand_seed();

    avahi_server_config_init(&config.server_config);
    config.command = DAEMON_RUN;
    config.daemonize = 0;
    config.config_file = NULL;
#ifdef HAVE_DBUS
    config.enable_dbus = 1;
    config.fail_on_missing_dbus = 1;
    config.n_clients_max = 0;
    config.n_objects_per_client_max = 0;
    config.n_entries_per_entry_group_max = 0;
#endif

    config.drop_root = 1;
    config.set_rlimits = 1;
#ifdef ENABLE_CHROOT
    config.use_chroot = 1;
#endif
    config.modify_proc_title = 1;

    config.disable_user_service_publishing = 0;
    config.publish_dns_servers = NULL;
    config.publish_resolv_conf = 0;
    config.use_syslog = 0;
    config.debug = 0;
    config.rlimit_as_set = 0;
    config.rlimit_core_set = 0;
    config.rlimit_data_set = 0;
    config.rlimit_fsize_set = 0;
    config.rlimit_nofile_set = 0;
    config.rlimit_stack_set = 0;
#ifdef RLIMIT_NPROC
    config.rlimit_nproc_set = 0;
#endif

    if ((argv0 = strrchr(argv[0], '/')))
        argv0 = avahi_strdup(argv0 + 1);
    else
        argv0 = avahi_strdup(argv[0]);

    daemon_pid_file_ident = (const char *) argv0;
    daemon_log_ident = (char*) argv0;
    daemon_pid_file_proc = pid_file_proc;

    if (parse_command_line(&config, argc, argv) < 0)
        goto finish;

    if (config.modify_proc_title)
        avahi_init_proc_title(argc, argv);

#ifdef ENABLE_CHROOT
    config.use_chroot = config.use_chroot && config.drop_root;
#endif

    if (config.command == DAEMON_HELP) {
        help(stdout);
        r = 0;
    } else if (config.command == DAEMON_VERSION) {
        printf("%s "PACKAGE_VERSION"\n", argv0);
        r = 0;
    } else if (config.command == DAEMON_KILL) {
        if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
            avahi_log_warn("Failed to kill daemon: %s", strerror(errno));
            goto finish;
        }

        r = 0;

    } else if (config.command == DAEMON_RELOAD) {
        if (daemon_pid_file_kill(SIGHUP) < 0) {
            avahi_log_warn("Failed to kill daemon: %s", strerror(errno));
            goto finish;
        }

        r = 0;

    } else if (config.command == DAEMON_CHECK)
        r = (daemon_pid_file_is_running() >= 0) ? 0 : 1;
    else if (config.command == DAEMON_RUN) {
        pid_t pid;

        if (getuid() != 0 && config.drop_root) {
            avahi_log_error("This program is intended to be run as root.");
            goto finish;
        }

        if ((pid = daemon_pid_file_is_running()) >= 0) {
            avahi_log_error("Daemon already running on PID %u", pid);
            goto finish;
        }

        if (load_config_file(&config) < 0)
            goto finish;

        if (config.daemonize) {
            daemon_retval_init();

            if ((pid = daemon_fork()) < 0)
                goto finish;
            else if (pid != 0) {
                int ret;
                /** Parent **/

                if ((ret = daemon_retval_wait(20)) < 0) {
                    avahi_log_error("Could not receive return value from daemon process.");
                    goto finish;
                }

                r = ret;
                goto finish;
            }

            /* Child */
        }

        if (config.use_syslog || config.daemonize)
            daemon_log_use = DAEMON_LOG_SYSLOG;

        if (sd_listen_fds(0) <= 0)
            if (daemon_close_all(-1) < 0)
                avahi_log_warn("Failed to close all remaining file descriptors: %s", strerror(errno));

        daemon_reset_sigs(-1);
        daemon_unblock_sigs(-1);

        if (make_runtime_dir() < 0)
            goto finish;

        if (config.drop_root) {
#ifdef ENABLE_CHROOT
            if (config.use_chroot)
                if (avahi_caps_reduce() < 0)
                    goto finish;
#endif

            if (drop_root() < 0)
                goto finish;

#ifdef ENABLE_CHROOT
            if (config.use_chroot)
                if (avahi_caps_reduce2() < 0)
                    goto finish;
#endif
        }

        if (daemon_pid_file_create() < 0) {
            avahi_log_error("Failed to create PID file: %s", strerror(errno));

            if (config.daemonize)
                daemon_retval_send(1);
            goto finish;
        } else
            wrote_pid_file = 1;

        if (config.set_rlimits)
            enforce_rlimits();

        chdir("/");

#ifdef ENABLE_CHROOT
        if (config.drop_root && config.use_chroot)
            if (avahi_chroot_helper_start(argv0) < 0) {
                avahi_log_error("failed to start chroot() helper daemon.");
                goto finish;
            }
#endif
        avahi_log_info("%s "PACKAGE_VERSION" starting up.", argv0);
        sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" starting up.", argv0);
        avahi_set_proc_title(argv0, "%s: starting up", argv0);

        if (run_server(&config) == 0)
            r = 0;

        avahi_log_info("%s "PACKAGE_VERSION" exiting.", argv0);
        sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" exiting.", argv0);
    }

finish:

    if (config.daemonize)
        daemon_retval_done();

    avahi_server_config_free(&config.server_config);
    avahi_free(config.config_file);
    avahi_strfreev(config.publish_dns_servers);
    avahi_strfreev(resolv_conf_name_servers);
    avahi_strfreev(resolv_conf_search_domains);

    if (wrote_pid_file) {
#ifdef ENABLE_CHROOT
        avahi_chroot_helper_unlink(pid_file_proc());
#else
        daemon_pid_file_remove();
#endif
    }

#ifdef ENABLE_CHROOT
    avahi_chroot_helper_shutdown();
#endif

    avahi_free(argv0);

    return r;
}
Ejemplo n.º 26
0
static int run_server(DaemonConfig *c) {
    int r = -1;
    int error;
    const AvahiPoll *poll_api = NULL;
    AvahiWatch *sig_watch = NULL;
    int retval_is_sent = 0;
#ifdef HAVE_INOTIFY
    AvahiWatch *inotify_watch = NULL;
#endif
#ifdef HAVE_KQUEUE
    int i;
    AvahiWatch *kqueue_watch = NULL;
#endif

    assert(c);

    ignore_signal(SIGPIPE);

    if (!(nss_support = avahi_nss_support()))
        avahi_log_warn("WARNING: No NSS support for mDNS detected, consider installing nss-mdns!");

    if (!(simple_poll_api = avahi_simple_poll_new())) {
        avahi_log_error("Failed to create main loop object.");
        goto finish;
    }

    poll_api = avahi_simple_poll_get(simple_poll_api);

    if (daemon_signal_init(SIGINT, SIGHUP, SIGTERM, SIGUSR1, 0) < 0) {
        avahi_log_error("Could not register signal handlers (%s).", strerror(errno));
        goto finish;
    }

    if (!(sig_watch = poll_api->watch_new(poll_api, daemon_signal_fd(), AVAHI_WATCH_IN, signal_callback, simple_poll_api))) {
        avahi_log_error( "Failed to create signal watcher");
        goto finish;
    }

    if (simple_protocol_setup(poll_api) < 0)
        goto finish;

#ifdef HAVE_DBUS
    if (c->enable_dbus) {
        if (dbus_protocol_setup(poll_api,
                                config.disable_user_service_publishing,
                                config.n_clients_max,
                                config.n_objects_per_client_max,
                                config.n_entries_per_entry_group_max,
                                !c->fail_on_missing_dbus
#ifdef ENABLE_CHROOT
                                && !config.use_chroot
#endif
            ) < 0) {

            avahi_log_warn("WARNING: Failed to contact D-Bus daemon.");

            if (c->fail_on_missing_dbus)
                goto finish;
        }
    }
#endif

#ifdef ENABLE_CHROOT

    if (config.drop_root && config.use_chroot) {
        if (chroot(AVAHI_CONFIG_DIR) < 0) {
            avahi_log_error("Failed to chroot(): %s", strerror(errno));
            goto finish;
        }

        avahi_log_info("Successfully called chroot().");
        chdir("/");

        if (avahi_caps_drop_all() < 0) {
            avahi_log_error("Failed to drop capabilities.");
            goto finish;
        }
        avahi_log_info("Successfully dropped remaining capabilities.");
    }

#endif

#ifdef HAVE_INOTIFY
    if ((inotify_fd = inotify_init()) < 0)
        avahi_log_warn( "Failed to initialize inotify: %s", strerror(errno));
    else {
        add_inotify_watches();

        if (!(inotify_watch = poll_api->watch_new(poll_api, inotify_fd, AVAHI_WATCH_IN, inotify_callback, NULL))) {
            avahi_log_error( "Failed to create inotify watcher");
            goto finish;
        }
    }
#endif

#ifdef HAVE_KQUEUE
    if ((kq = kqueue()) < 0)
        avahi_log_warn( "Failed to initialize kqueue: %s", strerror(errno));
    else {
        add_kqueue_watches();

        if (!(kqueue_watch = poll_api->watch_new(poll_api, kq, AVAHI_WATCH_IN, kqueue_callback, NULL))) {
            avahi_log_error( "Failed to create kqueue watcher");
            goto finish;
        }
    }
#endif

    load_resolv_conf();
#ifdef ENABLE_CHROOT
    static_service_load(config.use_chroot);
    static_hosts_load(config.use_chroot);
#else
    static_service_load(0);
    static_hosts_load(0);
#endif

    if (!(avahi_server = avahi_server_new(poll_api, &c->server_config, server_callback, c, &error))) {
        avahi_log_error("Failed to create server: %s", avahi_strerror(error));
        goto finish;
    }

    update_wide_area_servers();
    update_browse_domains();

    if (c->daemonize) {
        daemon_retval_send(0);
        retval_is_sent = 1;
    }

    for (;;) {
        if ((r = avahi_simple_poll_iterate(simple_poll_api, -1)) < 0) {

            /* We handle signals through an FD, so let's continue */
            if (errno == EINTR)
                continue;

            avahi_log_error("poll(): %s", strerror(errno));
            goto finish;
        } else if (r > 0)
            /* Quit */
            break;
    }

    r = 0;

finish:

    static_service_remove_from_server();
    static_service_free_all();

    static_hosts_remove_from_server();
    static_hosts_free_all();

    remove_dns_server_entry_groups();

    simple_protocol_shutdown();

#ifdef HAVE_DBUS
    if (c->enable_dbus)
        dbus_protocol_shutdown();
#endif

    if (avahi_server) {
        avahi_server_free(avahi_server);
        avahi_server = NULL;
    }

    daemon_signal_done();

    if (sig_watch)
        poll_api->watch_free(sig_watch);

#ifdef HAVE_INOTIFY
    if (inotify_watch)
        poll_api->watch_free(inotify_watch);
    if (inotify_fd >= 0)
        close(inotify_fd);
#endif

#ifdef HAVE_KQUEUE
    if (kqueue_watch)
        poll_api->watch_free(kqueue_watch);
    if (kq >= 0)
        close(kq);
    for (i = 0; i < num_kfds; i++) {
        if (kfds[i] >= 0)
            close(kfds[i]);
    }
#endif

    if (simple_poll_api) {
        avahi_simple_poll_free(simple_poll_api);
        simple_poll_api = NULL;
    }

    if (!retval_is_sent && c->daemonize)
        daemon_retval_send(1);

    return r;
}
Ejemplo n.º 27
0
DBusHandlerResult avahi_dbus_msg_entry_group_impl(DBusConnection *c, DBusMessage *m, void *userdata) {
    DBusError error;
    EntryGroupInfo *i = userdata;

    assert(c);
    assert(m);
    assert(i);

    dbus_error_init(&error);

    avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
                    dbus_message_get_interface(m),
                    dbus_message_get_path(m),
                    dbus_message_get_member(m));

    /* Introspection */
    if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
        return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.EntryGroup.xml");

    /* Access control */
    if (strcmp(dbus_message_get_sender(m), i->client->name))
        return avahi_dbus_respond_error(c, m, AVAHI_ERR_ACCESS_DENIED, NULL);

    if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Free")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Free message");
            goto fail;
        }

        avahi_dbus_entry_group_free(i);
        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Commit")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Commit message");
            goto fail;
        }

        if (avahi_s_entry_group_commit(i->entry_group) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        return avahi_dbus_respond_ok(c, m);


    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::Reset message");
            goto fail;
        }

        avahi_s_entry_group_reset(i->entry_group);
        i->n_entries = 0;
        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
            goto fail;
        }

        return avahi_dbus_respond_boolean(c, m, !!avahi_s_entry_group_is_empty(i->entry_group));

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
        AvahiEntryGroupState state;

        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
            avahi_log_warn("Error parsing EntryGroup::GetState message");
            goto fail;
        }

        state = avahi_s_entry_group_get_state(i->entry_group);
        return avahi_dbus_respond_int32(c, m, (int32_t) state);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddService")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain, *host;
        uint16_t port;
        AvahiStringList *strlst = NULL;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_STRING, &host,
                DBUS_TYPE_UINT16, &port,
                DBUS_TYPE_INVALID) ||
            !type || !name ||
            avahi_dbus_read_strlst(m, 8, &strlst) < 0) {
            avahi_log_warn("Error parsing EntryGroup::AddService message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);
        }

        if (domain && !*domain)
            domain = NULL;

        if (host && !*host)
            host = NULL;

        if (avahi_server_add_service_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, host, port, strlst) < 0) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        avahi_string_list_free(strlst);

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddServiceSubtype")) {

        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain, *subtype;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_STRING, &subtype,
                DBUS_TYPE_INVALID) || !type || !name || !subtype) {
            avahi_log_warn("Error parsing EntryGroup::AddServiceSubtype message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (domain && !*domain)
            domain = NULL;

        if (avahi_server_add_service_subtype(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, subtype) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "UpdateServiceTxt")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *type, *name, *domain;
        AvahiStringList *strlst;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &type,
                DBUS_TYPE_STRING, &domain,
                DBUS_TYPE_INVALID) ||
            !type || !name ||
            avahi_dbus_read_strlst(m, 6, &strlst)) {
            avahi_log_warn("Error parsing EntryGroup::UpdateServiceTxt message");
            goto fail;
        }

        if (domain && !*domain)
            domain = NULL;

        if (avahi_server_update_service_txt_strlst(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, type, domain, strlst) < 0) {
            avahi_string_list_free(strlst);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        avahi_string_list_free(strlst);

        return avahi_dbus_respond_ok(c, m);

    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddAddress")) {
        int32_t interface, protocol;
        uint32_t flags;
        char *name, *address;
        AvahiAddress a;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &address,
                DBUS_TYPE_INVALID) || !name || !address) {
            avahi_log_warn("Error parsing EntryGroup::AddAddress message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (!(avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a)))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);

        if (avahi_server_add_address(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, name, &a) < 0)
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        return avahi_dbus_respond_ok(c, m);
    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "AddRecord")) {
        int32_t interface, protocol;
        uint32_t flags, ttl, size;
        uint16_t clazz, type;
        char *name;
        void *rdata;
        AvahiRecord *r;

        if (!dbus_message_get_args(
                m, &error,
                DBUS_TYPE_INT32, &interface,
                DBUS_TYPE_INT32, &protocol,
                DBUS_TYPE_UINT32, &flags,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_UINT16, &clazz,
                DBUS_TYPE_UINT16, &type,
                DBUS_TYPE_UINT32, &ttl,
                DBUS_TYPE_INVALID) || !name ||
            avahi_dbus_read_rdata (m, 7, &rdata, &size)) {
            avahi_log_warn("Error parsing EntryGroup::AddRecord message");
            goto fail;
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE) && i->n_entries >= server->n_entries_per_entry_group_max)
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL);

        if (!avahi_is_valid_domain_name (name))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL);

        if (!(r = avahi_record_new_full (name, clazz, type, ttl)))
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_NO_MEMORY, NULL);

        if (avahi_rdata_parse (r, rdata, size) < 0) {
            avahi_record_unref (r);
            return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_RDATA, NULL);
        }

        if (avahi_server_add(avahi_server, i->entry_group, (AvahiIfIndex) interface, (AvahiProtocol) protocol, (AvahiPublishFlags) flags, r) < 0) {
            avahi_record_unref (r);
            return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
        }

        if (!(flags & AVAHI_PUBLISH_UPDATE))
            i->n_entries ++;

        avahi_record_unref (r);

        return avahi_dbus_respond_ok(c, m);
    }


    avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));

fail:
    if (dbus_error_is_set(&error))
        dbus_error_free(&error);

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
Ejemplo n.º 28
0
static void handle_packet(AvahiWideAreaLookupEngine *e, AvahiDnsPacket *p) {
    AvahiWideAreaLookup *l = NULL;
    int i, r;

    AvahiBrowserEvent final_event = AVAHI_BROWSER_ALL_FOR_NOW;
    
    assert(e);
    assert(p);

    /* Some superficial validity tests */
    if (avahi_dns_packet_check_valid(p) < 0 || avahi_dns_packet_is_query(p)) {
        avahi_log_warn(__FILE__": Ignoring invalid response for wide area datagram.");
        goto finish;
    }

    /* Look for the lookup that issued this query */
    if (!(l = find_lookup(e, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID))) || l->dead)
        goto finish;

    /* Check whether this a packet indicating a failure */
    if ((r = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & 15) != 0 ||
        avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) == 0) {

        avahi_server_set_errno(e->server, r == 0 ? AVAHI_ERR_NOT_FOUND : map_dns_error(r));
        /* Tell the user about the failure */
        final_event = AVAHI_BROWSER_FAILURE;

        /* We go on here, since some of the records contained in the
           reply might be interesting in some way */
    }

    /* Skip over the question */
    for (i = (int) avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); i > 0; i--) {
        AvahiKey *k;
        
        if (!(k = avahi_dns_packet_consume_key(p, NULL))) {
            avahi_log_warn(__FILE__": Wide area response packet too short or invalid while reading question key. (Maybe a UTF-8 problem?)");
            avahi_server_set_errno(e->server, AVAHI_ERR_INVALID_PACKET);
            final_event = AVAHI_BROWSER_FAILURE;
            goto finish;
        }

        avahi_key_unref(k);
    }

    /* Process responses */
    for (i = (int) avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) +
             (int) avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) +
             (int) avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); i > 0; i--) {

        AvahiRecord *rr;

        if (!(rr = avahi_dns_packet_consume_record(p, NULL))) {
            avahi_log_warn(__FILE__": Wide area response packet too short or invalid while reading response record. (Maybe a UTF-8 problem?)");
            avahi_server_set_errno(e->server, AVAHI_ERR_INVALID_PACKET);
            final_event = AVAHI_BROWSER_FAILURE;
            goto finish;
        }

        add_to_cache(e, rr);
        avahi_record_unref(rr);
    }

finish:
    
    if (l && !l->dead) {
        if (l->callback)
            l->callback(e, final_event, AVAHI_LOOKUP_RESULT_WIDE_AREA, NULL, l->userdata);

        lookup_stop(l);
    }
}
Ejemplo n.º 29
0
static void elapse_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* data) {
    AvahiProbeJob *pj = data, *next;
    AvahiProbeScheduler *s;
    AvahiDnsPacket *p;
    unsigned n;

    assert(pj);
    s = pj->scheduler;

    if (pj->done) {
        /* Lets remove it  from the history */
        job_free(s, pj);
        return;
    }

    if (!(p = avahi_dns_packet_new_query(s->interface->hardware->mtu)))
        return; /* OOM */
    n = 1;
    
    /* Add the import probe */
    if (!packet_add_probe_query(s, p, pj)) {
        size_t size;
        AvahiKey *k;
        int b;

        avahi_dns_packet_free(p);

        /* The probe didn't fit in the package, so let's allocate a larger one */

        size =
            avahi_key_get_estimate_size(pj->record->key) +
            avahi_record_get_estimate_size(pj->record) +
            AVAHI_DNS_PACKET_HEADER_SIZE;
        
        if (size > AVAHI_DNS_PACKET_SIZE_MAX)
            size = AVAHI_DNS_PACKET_SIZE_MAX;

        if (!(p = avahi_dns_packet_new_query(size)))
            return; /* OOM */

        if (!(k = avahi_key_new(pj->record->key->name, pj->record->key->clazz, AVAHI_DNS_TYPE_ANY))) {
            avahi_dns_packet_free(p);
            return;  /* OOM */
        }
        
        b = avahi_dns_packet_append_key(p, k, 0) && avahi_dns_packet_append_record(p, pj->record, 0, 0);
        avahi_key_unref(k);

        if (b) {
            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, 1);
            avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, 1);
            avahi_interface_send_packet(s->interface, p);
        } else
            avahi_log_warn("Probe record too large, cannot send");   
        
        avahi_dns_packet_free(p);
        job_mark_done(s, pj);

        return;
    }

    /* Try to fill up packet with more probes, if available */
    for (pj = s->jobs; pj; pj = pj->jobs_next) {

        if (pj->chosen)
            continue;
        
        if (!packet_add_probe_query(s, p, pj))
            break;
        
        n++;
    }

    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);

    n = 0;

    /* Now add the chosen records to the authorative section */
    for (pj = s->jobs; pj; pj = next) {

        next = pj->jobs_next;

        if (!pj->chosen)
            continue;

        if (!avahi_dns_packet_append_record(p, pj->record, 0, 0)) {
/*             avahi_log_warn("Bad probe size estimate!"); */

            /* Unmark all following jobs */
            for (; pj; pj = pj->jobs_next)
                pj->chosen = 0;
            
            break;
        }

        job_mark_done(s, pj);
        
        n ++;
    }
    
    avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, n);

    /* Send it now */
    avahi_interface_send_packet(s->interface, p);
    avahi_dns_packet_free(p);
}
Ejemplo n.º 30
0
int simple_protocol_setup(const AvahiPoll *poll_api) {
    struct sockaddr_un sa;
    mode_t u;
    int n;

    assert(!server);

    server = avahi_new(Server, 1);
    server->poll_api = poll_api;
    server->remove_socket = 0;
    server->fd = -1;
    server->n_clients = 0;
    AVAHI_LLIST_HEAD_INIT(Client, server->clients);
    server->watch = NULL;

    u = umask(0000);

    if ((n = sd_listen_fds(1)) < 0) {
        avahi_log_warn("Failed to acquire systemd file descriptors: %s", strerror(-n));
        goto fail;
    }

    if (n > 1) {
        avahi_log_warn("Too many systemd file descriptors passed.");
        goto fail;
    }

    if (n == 1) {
        int r;

        if ((r = sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_STREAM, 1)) < 0) {
            avahi_log_warn("Passed systemd file descriptor is of wrong type: %s", strerror(-r));
            goto fail;
        }

        server->fd = SD_LISTEN_FDS_START;

    } else {

        if ((server->fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
            avahi_log_warn("socket(AF_LOCAL, SOCK_STREAM, 0): %s", strerror(errno));
            goto fail;
        }

        memset(&sa, 0, sizeof(sa));
        sa.sun_family = AF_LOCAL;
        strncpy(sa.sun_path, AVAHI_SOCKET, sizeof(sa.sun_path)-1);

        /* We simply remove existing UNIX sockets under this name. The
           Avahi daemon makes sure that it runs only once on a host,
           therefore sockets that already exist are stale and may be
           removed without any ill effects */

        unlink(AVAHI_SOCKET);

        if (bind(server->fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
            avahi_log_warn("bind(): %s", strerror(errno));
            goto fail;
        }

        server->remove_socket = 1;

        if (listen(server->fd, SOMAXCONN) < 0) {
            avahi_log_warn("listen(): %s", strerror(errno));
            goto fail;
        }
    }

    umask(u);

    server->watch = poll_api->watch_new(poll_api, server->fd, AVAHI_WATCH_IN, server_work, server);

    return 0;

fail:

    umask(u);
    simple_protocol_shutdown();

    return -1;
}