X-Git-Url: https://arthur.barton.de/gitweb/?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Fafp_config.c;h=c7246f1f2d4c4206292fb69ac3c063d5dd39865b;hp=0001eb13a05a2d2c53580eb73a19787fb758e97d;hb=980548c882a297d26e67397d0f72e0b991f36bf2;hpb=edf01c724768d494e522ec84380e8e49b37a2bd6 diff --git a/etc/afpd/afp_config.c b/etc/afpd/afp_config.c index 0001eb13..c7246f1f 100644 --- a/etc/afpd/afp_config.c +++ b/etc/afpd/afp_config.c @@ -17,6 +17,9 @@ #include #include #include +#ifdef HAVE_GETIFADDRS +#include +#endif #include #include @@ -39,34 +42,41 @@ #include "volume.h" #include "afp_zeroconf.h" - /*! - * 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 */ + if (!dsi) { + /* Master afpd reloading config */ + auth_unload(); + if (! (obj->options.flags & OPTION_NOZEROCONF)) { + zeroconf_deregister(); + } + } + unload_volumes(obj); + /* 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); } - } /*! @@ -75,48 +85,123 @@ void configfree(AFPObj *obj, DSI *dsi) int configinit(AFPObj *obj) { EC_INIT; - DSI *dsi, **next = &obj->dsi; - char *p = NULL, *q = NULL; + DSI *dsi = NULL; + DSI **next = &obj->dsi; + char *p = NULL, *q = NULL, *savep; const char *r; + struct ifaddrs *ifaddr, *ifa; + int family, s; + static char interfaddr[NI_MAXHOST]; - auth_load(obj->options.uampath, obj->options.uamlist); + auth_load(obj, 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", + LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, interfaces: %s, port: %s", obj->options.hostname, - obj->options.listen ? obj->options.listen : "(default: hostname)", + obj->options.listen ? obj->options.listen : "-", + obj->options.interfaces ? obj->options.interfaces : "-", obj->options.port); - /* obj->options->listen is of the from "IP[:port][,IP:[PORT], ...]" */ - /* obj->options->port is the default port to listen (548) */ - + /* + * Setup addresses we listen on from hostname and/or "afp listen" option + */ if (obj->options.listen) { EC_NULL( q = p = strdup(obj->options.listen) ); - EC_NULL( p = strtok(p, ", ") ); + EC_NULL( p = strtok_r(p, ", ", &savep) ); + while (p) { + if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL) + break; + + status_init(obj, dsi); + *next = dsi; + next = &dsi->next; + dsi->AFPobj = obj; + + LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d", + getip_string((struct sockaddr *)&dsi->server), + getip_port((struct sockaddr *)&dsi->server)); + + p = strtok_r(NULL, ", ", &savep); + } + if (q) { + free(q); + q = NULL; + } } - while (1) { - if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL) - break; + /* + * Setup addresses we listen on from "afp interfaces". + * We use getifaddrs() instead of if_nameindex() because the latter appears still + * to be unable to return ipv4 addresses + */ + if (obj->options.interfaces) { +#ifndef HAVE_GETIFADDRS + LOG(log_error, logtype_afpd, "option \"afp interfaces\" not supported"); +#else + if (getifaddrs(&ifaddr) == -1) { + LOG(log_error, logtype_afpd, "getinterfaddr: getifaddrs() failed: %s", strerror(errno)); + EC_FAIL; + } + + EC_NULL( q = p = strdup(obj->options.interfaces) ); + EC_NULL( p = strtok_r(p, ", ", &savep) ); + while (p) { + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + if (STRCMP(ifa->ifa_name, !=, p)) + continue; + + family = ifa->ifa_addr->sa_family; + if (family == AF_INET || family == AF_INET6) { + if (getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), + interfaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { + LOG(log_error, logtype_afpd, "getinterfaddr: getnameinfo() failed %s", gai_strerror(errno)); + continue; + } + + if ((dsi = dsi_init(obj, obj->options.hostname, interfaddr, obj->options.port)) == NULL) + continue; + + status_init(obj, dsi); + *next = dsi; + next = &dsi->next; + dsi->AFPobj = obj; + + LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on interface %s with address %s:%d", + p, + getip_string((struct sockaddr *)&dsi->server), + getip_port((struct sockaddr *)&dsi->server)); + } /* if (family == AF_INET || family == AF_INET6) */ + } /* for (ifa != NULL) */ + p = strtok_r(NULL, ", ", &savep); + } + freeifaddrs(ifaddr); +#endif + } + /* + * Check whether we got a valid DSI from options.listen or options.interfaces, + * if not add a DSI that accepts all connections and goes though the list of + * network interaces for determining an IP we can advertise in DSIStatus + */ + if (dsi == NULL) { + if ((dsi = dsi_init(obj, obj->options.hostname, NULL, obj->options.port)) == NULL) + EC_FAIL_LOG("no suitable network address found, use \"afp listen\" or \"afp interfaces\"", 0); status_init(obj, dsi); *next = dsi; next = &dsi->next; + dsi->AFPobj = obj; LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d", getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server)); - - if (p) - /* p is NULL if ! obj->options.listen */ - p = strtok(NULL, ", "); - if (!p) - break; } - if (obj->dsi == NULL) - EC_FAIL; - #ifdef HAVE_LDAP /* Parse afp.conf */ acl_ldap_readconfig(obj->iniconfig); @@ -124,24 +209,23 @@ int configinit(AFPObj *obj) /* Now register with zeroconf, we also need the volumes for that */ if (! (obj->options.flags & OPTION_NOZEROCONF)) { - load_volumes(obj, NULL); + load_volumes(obj, lv_all); zeroconf_register(obj); } - if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fcelistener", NULL))) { + if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce listener", NULL))) { LOG(log_note, logtype_afpd, "Adding FCE listener: %s", r); fce_add_udp_socket(r); } - if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fcecoalesce", NULL))) { + if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce coalesce", NULL))) { LOG(log_note, logtype_afpd, "Fce coalesce: %s", r); fce_set_coalesce(r); } - if ((r = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fceevents", NULL))) { + if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce events", NULL))) { LOG(log_note, logtype_afpd, "Fce events: %s", r); fce_set_events(r); } - EC_CLEANUP: if (q) free(q);