From: Ralph Boehme Date: Thu, 22 Nov 2012 10:31:49 +0000 (+0100) Subject: Fix SIGHUP config reloading X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=59ba70c884ca7356e28873fccab7d3611369e6cc Fix SIGHUP config reloading 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. --- diff --git a/etc/afpd/afp_config.c b/etc/afpd/afp_config.c index fa7da0c9..3d9aff81 100644 --- a/etc/afpd/afp_config.c +++ b/etc/afpd/afp_config.c @@ -41,31 +41,38 @@ /*! - * 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, diff --git a/etc/afpd/afp_mdns.c b/etc/afpd/afp_mdns.c index 1dc6cbbb..3158ce7b 100644 --- a/etc/afpd/afp_mdns.c +++ b/etc/afpd/afp_mdns.c @@ -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]); diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index 6361d18f..bac65d59 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -44,55 +44,6 @@ #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". diff --git a/etc/afpd/main.c b/etc/afpd/main.c index afbd90e0..106f725c 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -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); diff --git a/etc/netatalk/netatalk.c b/etc/netatalk/netatalk.c index b35d264c..bbae394c 100644 --- a/etc/netatalk/netatalk.c +++ b/etc/netatalk/netatalk.c @@ -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 */ diff --git a/etc/uams/uams_dhx2_pam.c b/etc/uams/uams_dhx2_pam.c index d033d96b..0de4b5ce 100644 --- a/etc/uams/uams_dhx2_pam.c +++ b/etc/uams/uams_dhx2_pam.c @@ -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); } diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h index 0e776c31..00c80d42 100644 --- a/include/atalk/dsi.h +++ b/include/atalk/dsi.h @@ -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 **); diff --git a/include/atalk/globals.h b/include/atalk/globals.h index a8313a36..e50b0a7d 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -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 *); diff --git a/include/atalk/ldapconfig.h b/include/atalk/ldapconfig.h index 16e5484f..adc2a99d 100644 --- a/include/atalk/ldapconfig.h +++ b/include/atalk/ldapconfig.h @@ -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 { diff --git a/include/atalk/netatalk_conf.h b/include/atalk/netatalk_conf.h index efa4dba4..858b4f1c 100644 --- a/include/atalk/netatalk_conf.h +++ b/include/atalk/netatalk_conf.h @@ -21,7 +21,7 @@ #include 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); diff --git a/include/atalk/unicode.h b/include/atalk/unicode.h index 0bb43b52..f842ce09 100644 --- a/include/atalk/unicode.h +++ b/include/atalk/unicode.h @@ -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 **); diff --git a/libatalk/acl/ldap.c b/libatalk/acl/ldap.c index 8743bafe..44caae83 100644 --- a/libatalk/acl/ldap.c +++ b/libatalk/acl/ldap.c @@ -23,6 +23,7 @@ #include #include #include +#include #define LDAP_DEPRECATED 1 #include @@ -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[] = { diff --git a/libatalk/acl/ldap_config.c b/libatalk/acl/ldap_config.c index bd9d414b..26a63fa9 100644 --- a/libatalk/acl/ldap_config.c +++ b/libatalk/acl/ldap_config.c @@ -30,6 +30,17 @@ #include #include +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; diff --git a/libatalk/dsi/dsi_tcp.c b/libatalk/dsi/dsi_tcp.c index e06e87d9..2dc5e15d 100644 --- a/libatalk/dsi/dsi_tcp.c +++ b/libatalk/dsi/dsi_tcp.c @@ -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) diff --git a/libatalk/unicode/charcnv.c b/libatalk/unicode/charcnv.c index 785e4772..d72848e9 100644 --- a/libatalk/unicode/charcnv.c +++ b/libatalk/unicode/charcnv.c @@ -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) diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 3e775e11..664fd3e5 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -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(); +}