]> arthur.barton.de Git - netatalk.git/commitdiff
Fix SIGHUP config reloading
authorRalph Boehme <sloowfranklin@gmail.com>
Thu, 22 Nov 2012 10:31:49 +0000 (11:31 +0100)
committerRalph Boehme <sloowfranklin@gmail.com>
Tue, 27 Nov 2012 14:11:34 +0000 (15:11 +0100)
Add SIGHUP handler to master 'netatalk' process and let it distribute
the signal to it's childs, eg afpd.

Add function afp_config_free() which releases ressources allocated
by afp_config_parse().
Additionally fix configinit()/configfree() which deal with ressources
only used in the afpd fileserver (eg sockets, zeroconf registration).

Fix an error in the mdns unregister code where pthread_kill() was
used but that somehow killed the whole process not just the mdns
thread. Use pthread_cancel() instead which seems to work.

Fix any ressource leak reported by libumem.

16 files changed:
etc/afpd/afp_config.c
etc/afpd/afp_mdns.c
etc/afpd/afp_options.c
etc/afpd/main.c
etc/netatalk/netatalk.c
etc/uams/uams_dhx2_pam.c
include/atalk/dsi.h
include/atalk/globals.h
include/atalk/ldapconfig.h
include/atalk/netatalk_conf.h
include/atalk/unicode.h
libatalk/acl/ldap.c
libatalk/acl/ldap_config.c
libatalk/dsi/dsi_tcp.c
libatalk/unicode/charcnv.c
libatalk/util/netatalk_conf.c

index fa7da0c9816679975cd9de02722dd3192e546d89..3d9aff81e32b35c762655829cb391271af81c672 100644 (file)
 
 
 /*!
- * Free and cleanup all linked DSI objects from config
+ * Free and cleanup config and DSI
  *
- * Preserve object pointed to by "dsi".
- * "dsi" can be NULL in which case all DSI objects _and_ the options object are freed 
+ * "dsi" can be NULL in which case all DSI objects and the config object is freed,
+ * otherwise its an afpd session child and only any unneeded DSI objects are freed
  */
 void configfree(AFPObj *obj, DSI *dsi)
 {
     DSI *p, *q;
 
-    /* the master loaded the volumes for zeroconf, get rid of that */
-    unload_volumes(obj);
+    if (!dsi) {
+        /* Master afpd reloading config */
+        auth_unload();
+        if (! (obj->options.flags & OPTION_NOZEROCONF)) {
+            unload_volumes(obj);
+            zeroconf_deregister();
+        }
+    }
 
+    /* Master and child releasing unneeded DSI handles */
     for (p = obj->dsi; p; p = q) {
         q = p->next;
         if (p == dsi)
             continue;
-        close(p->socket);
+        dsi_free(p);
         free(p);
     }
+    obj->dsi = NULL;
 
+    /* afpd session child passes dsi handle to obj handle */
     if (dsi) {
         dsi->next = NULL;
         obj->dsi = dsi;
-    } else {
-        afp_options_free(&obj->options);
     }
 }
 
@@ -81,6 +88,9 @@ int configinit(AFPObj *obj)
 
     auth_load(obj->options.uampath, obj->options.uamlist);
     set_signature(&obj->options);
+#ifdef HAVE_LDAP
+    acl_ldap_freeconfig();
+#endif /* HAVE_LDAP */
 
     LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, port: %s",
         obj->options.hostname,
index 1dc6cbbb768714637f89e5077f1769abef9cd72b..3158ce7b7fee9ef3058563309151defdc211b53b 100644 (file)
@@ -50,15 +50,16 @@ static pthread_t       poller;
         free(str); free(key);                           \
     }
 
+static struct pollfd *fds;
 
 /*
  * This is the thread that polls the filehandles
  */
-void *polling_thread(void *arg) {
+static void *polling_thread(void *arg) {
     // First we loop through getting the filehandles and adding them to our poll, we
     // need to allocate our pollfd's
     DNSServiceErrorType error;
-    struct pollfd           *fds = calloc(svc_ref_count, sizeof(struct pollfd));
+    fds = calloc(svc_ref_count, sizeof(struct pollfd));
     assert(fds);
 
     for(int i=0; i < svc_ref_count; i++) {
@@ -78,28 +79,32 @@ void *polling_thread(void *arg) {
     return(NULL);
 }
 
-
 /*
  * This is the callback for the service register function ... actually there isn't a lot
  * we can do if we get problems, so we don't really need to do anything other than report
  * the issue.
  */
-void RegisterReply(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
-                   const char *name, const char *regtype, const char *domain, void *context) {
-
-    if(errorCode != kDNSServiceErr_NoError) {
+static void RegisterReply(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+                          const char *name, const char *regtype, const char *domain, void *context)
+{
+    if (errorCode != kDNSServiceErr_NoError) {
         LOG(log_error, logtype_afpd, "Failed to register mDNS service: %s%s%s: code=%d",
             name, regtype, domain, errorCode);
     }
 }
 
-
 /*
  * This function unregisters anything we have already
  * registered and frees associated memory
  */
 static void unregister_stuff() {
-    pthread_kill(poller, SIGKILL);
+    pthread_cancel(poller);    
+
+    for (int i = 0; i < svc_ref_count; i++)
+        close(fds[i].fd);
+    free(fds);
+    fds = NULL;
+
     if(svc_refs) {
         for(int i=0; i < svc_ref_count; i++) {
             DNSServiceRefDeallocate(svc_refs[i]);
index 6361d18fe538dbb16f55a55465aad855ef5ee826..bac65d590e14ca122668a36b6c3dddb41d4075b2 100644 (file)
 
 #define LENGTH 512
 
-/* get rid of any allocated afp_option buffers. */
-void afp_options_free(struct afp_options *opt)
-{
-       if (opt->hostname)
-        free(opt->hostname);
-       if (opt->adminauthuser)
-        free(opt->adminauthuser);
-       if (opt->configfile)
-        free(opt->configfile);
-    if (opt->fqdn)
-        free(opt->fqdn);
-    if (opt->guest)
-        free(opt->guest);
-    if (opt->listen)
-        free(opt->listen);
-    if (opt->k5realm)
-        free(opt->k5realm);
-    if (opt->k5keytab)
-        free(opt->k5keytab);
-    if (opt->k5service)
-        free(opt->k5service);
-    if (opt->logconfig)
-        free(opt->logconfig);
-    if (opt->logfile)
-        free(opt->logfile);
-    if (opt->loginmesg)
-        free(opt->loginmesg);
-    if (opt->maccodepage)
-        free(opt->maccodepage);
-       if (opt->mimicmodel)
-        free(opt->mimicmodel);
-    if (opt->ntdomain)
-        free(opt->ntdomain);
-    if (opt->ntseparator)
-        free(opt->ntseparator);
-    if (opt->passwdfile)
-        free(opt->passwdfile);
-    if (opt->port)
-        free(opt->port);
-    if (opt->signatureopt)
-        free(opt->signatureopt);
-    if (opt->uamlist)
-        free(opt->uamlist);
-    if (opt->uampath)
-        free(opt->uampath);
-    if (opt->unixcodepage)
-        free(opt->unixcodepage);
-}
-
 /*
  * Show version information about afpd.
  * Used by "afp -v".
index afbd90e059331d30183bcacbac3c09562ebbc1dc..106f725c4189dea53f72ee423777864fce132a3f 100644 (file)
@@ -389,12 +389,17 @@ int main(int ac, char **av)
 
         if (reloadconfig) {
             nologin++;
-            auth_unload();
+
             fd_reset_listening_sockets(&obj);
 
             LOG(log_info, logtype_afpd, "re-reading configuration file");
 
             configfree(&obj, NULL);
+            afp_config_free(&obj);
+
+            if (afp_config_parse(&obj, "afpd") != 0)
+                afp_exit(EXITERR_CONF);
+
             if (configinit(&obj) != 0) {
                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
                 afp_exit(EXITERR_CONF);
index b35d264c81819787dbd2197d7f5de21bb640926a..bbae394ccc49b4a4802b3382e522c60fd45ef852 100644 (file)
@@ -116,6 +116,13 @@ static void sigquit_cb(evutil_socket_t fd, short what, void *arg)
     kill_childs(SIGQUIT, &afpd_pid, &cnid_metad_pid, NULL);
 }
 
+/* SIGQUIT callback */
+static void sighup_cb(evutil_socket_t fd, short what, void *arg)
+{
+    LOG(log_note, logtype_afpd, "Received SIGHUP, sending all processes signal to reload config");
+    kill_childs(SIGHUP, &afpd_pid, &cnid_metad_pid, NULL);
+}
+
 /* SIGCHLD callback */
 static void sigchld_cb(evutil_socket_t fd, short what, void *arg)
 {
@@ -296,6 +303,7 @@ int main(int argc, char **argv)
 
     sigterm_ev = event_new(base, SIGTERM, EV_SIGNAL, sigterm_cb, NULL);
     sigquit_ev = event_new(base, SIGQUIT, EV_SIGNAL | EV_PERSIST, sigquit_cb, NULL);
+    sigquit_ev = event_new(base, SIGHUP,  EV_SIGNAL | EV_PERSIST, sighup_cb, NULL);
     sigchld_ev = event_new(base, SIGCHLD, EV_SIGNAL | EV_PERSIST, sigchld_cb, NULL);
     timer_ev = event_new(base, -1, EV_PERSIST, timer_cb, NULL);
 
@@ -311,6 +319,7 @@ int main(int argc, char **argv)
     sigdelset(&blocksigs, SIGTERM);
     sigdelset(&blocksigs, SIGQUIT);
     sigdelset(&blocksigs, SIGCHLD);
+    sigdelset(&blocksigs, SIGHUP);
     sigprocmask(SIG_SETMASK, &blocksigs, NULL);
 
     /* run the event loop */
index d033d96b12c76e322a8fd143b90e283ff8847738..0de4b5ceb0edaa02cbcfb1f031305514b7280398 100644 (file)
@@ -927,9 +927,6 @@ static int uam_setup(const char *path)
     if (uam_register(UAM_SERVER_CHANGEPW, path, "DHX2", dhx2_changepw) < 0)
         return -1;
 
-    p = gcry_mpi_new(0);
-    g = gcry_mpi_new(0);
-
     LOG(log_debug, logtype_uams, "DHX2: generating mersenne primes");
     /* Generate p and g for DH */
     if (dh_params_generate(PRIMEBITS) != 0) {
@@ -945,6 +942,8 @@ static void uam_cleanup(void)
     uam_unregister(UAM_SERVER_LOGIN, "DHX2");
     uam_unregister(UAM_SERVER_CHANGEPW, "DHX2");
 
+    LOG(log_debug, logtype_uams, "DHX2: uam_cleanup");
+
     gcry_mpi_release(p);
     gcry_mpi_release(g);
 }
index 0e776c31cca07667a43926f5ad96d493163a25ba..00c80d423e80c1f345bbfca261ecdfe9b0a6d725 100644 (file)
@@ -162,6 +162,7 @@ typedef struct DSI {
 extern DSI *dsi_init(AFPObj *obj, const char *hostname, const char *address, const char *port);
 extern void dsi_setstatus (DSI *, char *, const size_t);
 extern int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address, const char *port);
+extern void dsi_free(DSI *dsi);
 
 /* in dsi_getsess.c */
 extern int dsi_getsession (DSI *, server_child *, const int, afp_child_t **);
index a8313a36b6d24f34875c36479aecd2bd8e5de0b6..e50b0a7d75efcaf9a92701f0617cb48b97695209 100644 (file)
@@ -147,7 +147,6 @@ extern const char         *Cnid_port;
 extern int  get_afp_errno   (const int param);
 extern void afp_options_init (struct afp_options *);
 extern void afp_options_parse_cmdline(AFPObj *obj, int ac, char **av);
-extern void afp_options_free(struct afp_options *);
 extern void setmessage (const char *);
 extern void readmessage (AFPObj *);
 
index 16e5484f6dd24822874f465a221918bac251ab9d..adc2a99d441ad31414b6ea392800db191a790c50 100644 (file)
@@ -7,6 +7,7 @@
 
 /* One function does the whole job */
 extern int acl_ldap_readconfig(dictionary *iniconfig);
+extern void acl_ldap_freeconfig(void);
 
 /* These are the prefvalues */
 extern char *ldap_server;
@@ -33,6 +34,7 @@ struct ldap_pref {
     int strorint;     /* string to just store in char * or convert to int ? */
     int intfromarray; /* convert to int, but use string to int mapping array pref_array[] */
     int valid;        /* -1 = mandatory, 0 = omittable/valid */
+    int valid_save;   /* copy of 'valid', used when resettting config */
 };
 
 struct pref_array {
index efa4dba49456dddcb8b0b580083e5fb9b1a2ad08..858b4f1cd17a1107dbd017023c9c8ef77b2f7f28 100644 (file)
@@ -21,7 +21,7 @@
 #include <atalk/volume.h>
 
 extern int        afp_config_parse(AFPObj *obj, char *processname);
-
+extern void       afp_config_free(AFPObj *obj);
 extern int        load_charset(struct vol *vol);
 extern int        load_volumes(AFPObj *obj);
 extern void       unload_volumes(AFPObj *obj);
index 0bb43b52de51419d59c73c93ed527722793e6d15..f842ce096fec1da82112b5ff7d99268e83a80c99 100644 (file)
@@ -125,6 +125,7 @@ extern size_t   utf8_strlen_validate ( char *);
 
 /* from charcnv.c */
 extern int      set_charset_name(charset_t, const char *);
+extern void     free_charset_names(void);
 extern void     init_iconv (void);
 extern size_t   convert_string (charset_t, charset_t, void const *, size_t, void *, size_t);
 extern size_t   convert_string_allocate (charset_t, charset_t, void const *, size_t, char **);
index 8743bafeabcd90b7f0e16afd6fa79bf3738b332a..44caae8334df4a11f36158ee0f07ccd44dd85a7c 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/time.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 #define LDAP_DEPRECATED 1
 #include <ldap.h>
 
@@ -56,21 +57,22 @@ char *ldap_uid_attr;
 int  ldap_uuid_encoding;
 
 struct ldap_pref ldap_prefs[] = {
-    {&ldap_server,     "ldap server",      0, 0, -1},
-    {&ldap_auth_method,"ldap auth method", 1, 1, -1},
-    {&ldap_auth_dn,    "ldap auth dn",     0, 0,  0},
-    {&ldap_auth_pw,    "ldap auth pw",     0, 0,  0},
-    {&ldap_userbase,   "ldap userbase",    0, 0, -1},
-    {&ldap_userscope,  "ldap userscope",   1 ,1, -1},
-    {&ldap_groupbase,  "ldap groupbase",   0, 0, -1},
-    {&ldap_groupscope, "ldap groupscope",  1 ,1, -1},
-    {&ldap_uuid_attr,  "ldap uuid attr",   0, 0, -1},
-    {&ldap_uuid_string,"ldap uuid string", 0, 0,  0},
-    {&ldap_name_attr,  "ldap name attr",   0, 0, -1},
-    {&ldap_group_attr, "ldap group attr",  0, 0, -1},
-    {&ldap_uid_attr,   "ldap uid attr",    0, 0,  0},
-    {&ldap_uuid_encoding,"ldap uuid encoding", 1, 1,  0},
-    {NULL,             NULL,               0, 0, -1}
+    /* pointer to pref,    prefname,              strorint, intfromarray, valid, valid_save */
+    {&ldap_server,         "ldap server",         0, 0, -1, -1},
+    {&ldap_auth_method,    "ldap auth method",    1, 1, -1, -1},
+    {&ldap_auth_dn,        "ldap auth dn",        0, 0,  0,  0},
+    {&ldap_auth_pw,        "ldap auth pw",        0, 0,  0,  0},
+    {&ldap_userbase,       "ldap userbase",       0, 0, -1, -1},
+    {&ldap_userscope,      "ldap userscope",      1 ,1, -1, -1},
+    {&ldap_groupbase,      "ldap groupbase",      0, 0, -1, -1},
+    {&ldap_groupscope,     "ldap groupscope",     1 ,1, -1, -1},
+    {&ldap_uuid_attr,      "ldap uuid attr",      0, 0, -1, -1},
+    {&ldap_uuid_string,    "ldap uuid string",    0, 0,  0,  0},
+    {&ldap_name_attr,      "ldap name attr",      0, 0, -1, -1},
+    {&ldap_group_attr,     "ldap group attr",     0, 0, -1, -1},
+    {&ldap_uid_attr,       "ldap uid attr",       0, 0,  0,  0},
+    {&ldap_uuid_encoding,  "ldap uuid encoding",  1, 1,  0,  0},
+    {NULL,                 NULL,                  0, 0,  0,  0}
 };
 
 struct pref_array prefs_array[] = {
index bd9d414b85758ce8439863100e9752f33b0785af..26a63fa9c76dab72f94af1fb812943d50f2ba804 100644 (file)
 #include <atalk/logger.h>
 #include <atalk/iniparser.h>
 
+void acl_ldap_freeconfig(void)
+{
+    for (int i = 0; ldap_prefs[i].name != NULL; i++) {
+        if (ldap_prefs[i].intfromarray == 0 && ldap_prefs[i].strorint == 0) {
+            free(*((char **)(ldap_prefs[i].pref)));
+            *((char **)(ldap_prefs[i].pref)) = NULL;
+        }
+        ldap_prefs[i].valid = ldap_prefs[i].valid_save;
+    }
+}
+
 int acl_ldap_readconfig(dictionary *iniconfig)
 {
     int i, j;
index e06e87d92420187948611b9d044995ab158065c6..2dc5e15ddbafd72888f73d13f29db347d0ad88e1 100644 (file)
@@ -103,6 +103,24 @@ static void dsi_init_buffer(DSI *dsi)
     dsi->end = dsi->buffer + (dsi->dsireadbuf * dsi->server_quantum);
 }
 
+/*!
+ * Free any allocated ressources of the master afpd DSI objects and close server socket
+ */
+void dsi_free(DSI *dsi)
+{
+    close(dsi->serversock);
+    dsi->serversock = -1;
+
+    free(dsi->commands);
+    dsi->commands = NULL;
+
+    free(dsi->buffer);
+    dsi->buffer = NULL;
+
+    free(dsi->bonjourname);
+    dsi->bonjourname = NULL;
+}
+
 static struct itimerval itimer;
 /* accept the socket and do a little sanity checking */
 static int dsi_tcp_open(DSI *dsi)
index 785e47720f1d7ab2e74ce2be611c93164386fdb9..d72848e936c257f2a465944c0c2a2ca9f31ee954 100644 (file)
@@ -95,6 +95,16 @@ int set_charset_name(charset_t ch, const char *name)
     return 0;
 }
 
+void free_charset_names(void)
+{
+    for (int ch = 0; ch < MAX_CHARSETS; ch++) {
+        if (charset_names[ch]) {
+            free(charset_names[ch]);
+            charset_names[ch] = NULL;
+        }
+    }
+}
+
 static struct charset_functions* get_charset_functions (charset_t ch)
 {
     if (charsets[ch] != NULL)
index 3e775e11a618601ed881ea776e337026fe721f65..664fd3e57cd1ff2a1d9413ef81e3c86fdccab508 100644 (file)
@@ -1754,11 +1754,11 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
             LOG(log_debug, logtype_afpd, "Locale charset is '%s'", p);
 #else /* system doesn't have LOCALE support */
             LOG(log_warning, logtype_afpd, "system doesn't have LOCALE support");
-            p = strdup("UTF8");
+            p = "UTF8";
 #endif
         }
         if (strcasecmp(p, "UTF-8") == 0) {
-            p = strdup("UTF8");
+            p = "UTF8";
         }
         options->unixcodepage = strdup(p);
         set_charset_name(CH_UNIX, p);
@@ -1771,7 +1771,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
         options->volcodepage = strdup(options->unixcodepage);
     } else {
         if (strcasecmp(p, "UTF-8") == 0) {
-            p = strdup("UTF8");
+            p = "UTF8";
         }
         options->volcodepage = strdup(p);
     }
@@ -1815,3 +1815,78 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
 EC_CLEANUP:
     EC_EXIT;
 }
+
+#define CONFIG_ARG_FREE(a) do {                     \
+    free(a);                                        \
+    a = NULL;                                       \
+    } while (0);
+
+/* get rid of any allocated afp_option buffers. */
+void afp_config_free(AFPObj *obj)
+{
+    if (obj->options.configfile)
+        CONFIG_ARG_FREE(obj->options.configfile);
+    if (obj->options.sigconffile)
+        CONFIG_ARG_FREE(obj->options.sigconffile);
+    if (obj->options.uuidconf)
+        CONFIG_ARG_FREE(obj->options.uuidconf);
+    if (obj->options.logconfig)
+        CONFIG_ARG_FREE(obj->options.logconfig);
+    if (obj->options.logfile)
+        CONFIG_ARG_FREE(obj->options.logfile);
+    if (obj->options.loginmesg)
+        CONFIG_ARG_FREE(obj->options.loginmesg);
+    if (obj->options.guest)
+        CONFIG_ARG_FREE(obj->options.guest);
+    if (obj->options.extmapfile)
+        CONFIG_ARG_FREE(obj->options.extmapfile);
+    if (obj->options.passwdfile)
+        CONFIG_ARG_FREE(obj->options.passwdfile);
+    if (obj->options.uampath)
+        CONFIG_ARG_FREE(obj->options.uampath);
+    if (obj->options.uamlist)
+        CONFIG_ARG_FREE(obj->options.uamlist);
+    if (obj->options.port)
+        CONFIG_ARG_FREE(obj->options.port);
+    if (obj->options.signatureopt)
+        CONFIG_ARG_FREE(obj->options.signatureopt);
+    if (obj->options.k5service)
+        CONFIG_ARG_FREE(obj->options.k5service);
+    if (obj->options.k5realm)
+        CONFIG_ARG_FREE(obj->options.k5realm);
+    if (obj->options.listen)
+        CONFIG_ARG_FREE(obj->options.listen);
+    if (obj->options.ntdomain)
+        CONFIG_ARG_FREE(obj->options.ntdomain);
+    if (obj->options.ntseparator)
+        CONFIG_ARG_FREE(obj->options.ntseparator);
+    if (obj->options.mimicmodel)
+        CONFIG_ARG_FREE(obj->options.mimicmodel);
+    if (obj->options.adminauthuser)
+        CONFIG_ARG_FREE(obj->options.adminauthuser);
+    if (obj->options.hostname)
+        CONFIG_ARG_FREE(obj->options.hostname);
+    if (obj->options.k5keytab)
+        CONFIG_ARG_FREE(obj->options.k5keytab);
+    if (obj->options.Cnid_srv)
+        CONFIG_ARG_FREE(obj->options.Cnid_srv);
+    if (obj->options.Cnid_port)
+        CONFIG_ARG_FREE(obj->options.Cnid_port);
+    if (obj->options.fqdn)
+        CONFIG_ARG_FREE(obj->options.fqdn);
+
+    if (obj->options.unixcodepage)
+        CONFIG_ARG_FREE(obj->options.unixcodepage);
+    if (obj->options.maccodepage)
+        CONFIG_ARG_FREE(obj->options.maccodepage);
+    if (obj->options.volcodepage)
+        CONFIG_ARG_FREE(obj->options.volcodepage);
+
+    obj->options.flags = 0;
+    obj->options.passwdbits = 0;
+
+    /* Free everything called from afp_config_parse() */
+    free_extmap();
+    iniparser_freedict(obj->iniconfig);
+    free_charset_names();
+}