s3/smbd: register Time Machine shares with Avahi
authorOmri Mor <omri50@gmail.com>
Mon, 2 Oct 2017 02:39:47 +0000 (21:39 -0500)
committerRalph Boehme <slow@samba.org>
Wed, 4 Oct 2017 08:06:15 +0000 (10:06 +0200)
Adds support for automatically registering the required _adisk._tcp
mDNS record based on the setting of "fruit:time machine".

Signed-off-by: Omri Mor <omri50@gmail.com>
Reviewed-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/avahi_register.c

index c118e61ccc26e3e7367c84ed5350b7e364ce0b18..91e8a439b84cb4dd4d46f1f920ee433184d18df4 100644 (file)
@@ -24,6 +24,8 @@
 #include <avahi-client/client.h>
 #include <avahi-client/publish.h>
 #include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/strlst.h>
 
 struct avahi_state_struct {
        struct AvahiPoll *poll;
@@ -32,6 +34,39 @@ struct avahi_state_struct {
        uint16_t port;
 };
 
+static void *avahi_allocator_ctx = NULL;
+
+static void * avahi_allocator_malloc(size_t size)
+{
+       return talloc_size(avahi_allocator_ctx, size);
+}
+
+static void avahi_allocator_free(void *p)
+{
+       TALLOC_FREE(p);
+}
+
+static void * avahi_allocator_realloc(void *p, size_t size)
+{
+       return talloc_realloc_size(avahi_allocator_ctx, p, size);
+}
+
+static void * avahi_allocator_calloc(size_t count, size_t size)
+{
+       void *p = talloc_array_size(avahi_allocator_ctx, size, count);
+       if (p) {
+               memset(p, 0, size * count);
+       }
+       return p;
+}
+
+static const struct AvahiAllocator avahi_talloc_allocator = {
+       &avahi_allocator_malloc,
+       &avahi_allocator_free,
+       &avahi_allocator_realloc,
+       &avahi_allocator_calloc
+};
+
 static void avahi_entry_group_callback(AvahiEntryGroup *g,
                                       AvahiEntryGroupState status,
                                       void *userdata)
@@ -70,7 +105,13 @@ static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
        int error;
 
        switch (status) {
-       case AVAHI_CLIENT_S_RUNNING:
+       case AVAHI_CLIENT_S_RUNNING: {
+               int snum;
+               int num_services = lp_numservices();
+               int dk = 0;
+               AvahiStringList *adisk = NULL;
+               AvahiStringList *adisk2 = NULL;
+
                DBG_DEBUG("AVAHI_CLIENT_S_RUNNING\n");
 
                state->entry_group = avahi_entry_group_new(
@@ -94,6 +135,53 @@ static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
                        break;
                }
 
+               for (snum = 0; snum < num_services; snum++) {
+                       if (lp_snum_ok(snum) &&
+                           lp_parm_bool(snum, "fruit", "time machine", false))
+                       {
+                               adisk2 = avahi_string_list_add_printf(
+                                           adisk, "dk%d=adVN=%s,adVF=0x82",
+                                           dk++, lp_const_servicename(snum));
+                               if (adisk2 == NULL) {
+                                       DBG_DEBUG("avahi_string_list_add_printf"
+                                                 "failed: returned NULL\n");
+                                       avahi_string_list_free(adisk);
+                                       avahi_entry_group_free(state->entry_group);
+                                       state->entry_group = NULL;
+                                       break;
+                               }
+                               adisk = adisk2;
+                               adisk2 = NULL;
+                       }
+               }
+               if (dk > 0) {
+                       adisk2 = avahi_string_list_add(adisk, "sys=adVF=0x100");
+                       if (adisk2 == NULL) {
+                               DBG_DEBUG("avahi_string_list_add failed: "
+                                         "returned NULL\n");
+                               avahi_string_list_free(adisk);
+                               avahi_entry_group_free(state->entry_group);
+                               state->entry_group = NULL;
+                               break;
+                       }
+                       adisk = adisk2;
+                       adisk2 = NULL;
+
+                       error = avahi_entry_group_add_service_strlst(
+                                   state->entry_group, AVAHI_IF_UNSPEC,
+                                   AVAHI_PROTO_UNSPEC, 0, lp_netbios_name(),
+                                   "_adisk._tcp", NULL, NULL, 0, adisk);
+                       avahi_string_list_free(adisk);
+                       adisk = NULL;
+                       if (error != AVAHI_OK) {
+                               DBG_DEBUG("avahi_entry_group_add_service_strlst "
+                                         "failed: %s\n", avahi_strerror(error));
+                               avahi_entry_group_free(state->entry_group);
+                               state->entry_group = NULL;
+                               break;
+                       }
+               }
+
                error = avahi_entry_group_commit(state->entry_group);
                if (error != AVAHI_OK) {
                        DBG_DEBUG("avahi_entry_group_commit failed: %s\n",
@@ -103,6 +191,7 @@ static void avahi_client_callback(AvahiClient *c, AvahiClientState status,
                        break;
                }
                break;
+       }
        case AVAHI_CLIENT_FAILURE:
                error = avahi_client_errno(c);
 
@@ -139,6 +228,12 @@ void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        struct avahi_state_struct *state;
        int error;
 
+       avahi_allocator_ctx = talloc_new(mem_ctx);
+       if (avahi_allocator_ctx == NULL) {
+               return NULL;
+       }
+       avahi_set_allocator(&avahi_talloc_allocator);
+
        state = talloc(mem_ctx, struct avahi_state_struct);
        if (state == NULL) {
                return state;