/* Unix SMB/CIFS implementation. DNS-SD registration Copyright (C) Rishi Srivatsavai 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "smbd/smbd.h" /* Uses DNS service discovery (libdns_sd) to * register the SMB service. SMB service is registered * on ".local" domain via Multicast DNS & any * other unicast DNS domains available. * * Users use the smbclient -B (Browse) option to * browse for advertised SMB services. */ #define DNS_REG_RETRY_INTERVAL (5*60) /* in seconds */ #ifdef WITH_DNSSD_SUPPORT #include struct dns_reg_state { struct tevent_context *event_ctx; uint16_t port; DNSServiceRef srv_ref; struct tevent_timer *te; int fd; struct tevent_fd *fde; }; static int dns_reg_state_destructor(struct dns_reg_state *dns_state) { if (dns_state->srv_ref != NULL) { /* Close connection to the mDNS daemon */ DNSServiceRefDeallocate(dns_state->srv_ref); dns_state->srv_ref = NULL; } /* Clear event handler */ TALLOC_FREE(dns_state->te); TALLOC_FREE(dns_state->fde); dns_state->fd = -1; return 0; } static void dns_register_smbd_retry(struct tevent_context *ctx, struct tevent_timer *te, struct timeval now, void *private_data); static void dns_register_smbd_fde_handler(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, void *private_data); static bool dns_register_smbd_schedule(struct dns_reg_state *dns_state, struct timeval tval) { dns_reg_state_destructor(dns_state); dns_state->te = tevent_add_timer(dns_state->event_ctx, dns_state, tval, dns_register_smbd_retry, dns_state); if (!dns_state->te) { return false; } return true; } static void dns_register_smbd_retry(struct tevent_context *ctx, struct tevent_timer *te, struct timeval now, void *private_data) { struct dns_reg_state *dns_state = talloc_get_type_abort(private_data, struct dns_reg_state); DNSServiceErrorType err; dns_reg_state_destructor(dns_state); DEBUG(6, ("registering _smb._tcp service on port %d\n", dns_state->port)); /* Register service with DNS. Connects with the mDNS * daemon running on the local system to perform DNS * service registration. */ err = DNSServiceRegister(&dns_state->srv_ref, 0 /* flags */, kDNSServiceInterfaceIndexAny, NULL /* service name */, "_smb._tcp" /* service type */, NULL /* domain */, "" /* SRV target host name */, htons(dns_state->port), 0 /* TXT record len */, NULL /* TXT record data */, NULL /* callback func */, NULL /* callback context */); if (err != kDNSServiceErr_NoError) { /* Failed to register service. Schedule a re-try attempt. */ DEBUG(3, ("unable to register with mDNS (err %d)\n", err)); goto retry; } dns_state->fd = DNSServiceRefSockFD(dns_state->srv_ref); if (dns_state->fd == -1) { goto retry; } dns_state->fde = tevent_add_fd(dns_state->event_ctx, dns_state, dns_state->fd, TEVENT_FD_READ, dns_register_smbd_fde_handler, dns_state); if (!dns_state->fde) { goto retry; } return; retry: dns_register_smbd_schedule(dns_state, timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0)); } /* Processes reply from mDNS daemon. Returns true if a reply was received */ static void dns_register_smbd_fde_handler(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, void *private_data) { struct dns_reg_state *dns_state = talloc_get_type_abort(private_data, struct dns_reg_state); DNSServiceErrorType err; err = DNSServiceProcessResult(dns_state->srv_ref); if (err != kDNSServiceErr_NoError) { DEBUG(3, ("failed to process mDNS result (err %d), re-trying\n", err)); goto retry; } talloc_free(dns_state); return; retry: dns_register_smbd_schedule(dns_state, timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0)); } bool smbd_setup_mdns_registration(struct tevent_context *ev, TALLOC_CTX *mem_ctx, uint16_t port) { struct dns_reg_state *dns_state; dns_state = talloc_zero(mem_ctx, struct dns_reg_state); if (dns_state == NULL) { return false; } dns_state->event_ctx = ev; dns_state->port = port; dns_state->fd = -1; talloc_set_destructor(dns_state, dns_reg_state_destructor); return dns_register_smbd_schedule(dns_state, timeval_zero()); } #else /* WITH_DNSSD_SUPPORT */ bool smbd_setup_mdns_registration(struct tevent_context *ev, TALLOC_CTX *mem_ctx, uint16_t port) { return true; } #endif /* WITH_DNSSD_SUPPORT */