1/* 2 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) 3 * All Rights Reserved. See COPYRIGHT. 4 */ 5 6#ifdef HAVE_CONFIG_H 7#include "config.h" 8#endif /* HAVE_CONFIG_H */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <errno.h> 14#include <string.h> 15#include <unistd.h> 16#include <ctype.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include <arpa/inet.h> 20#ifdef HAVE_GETIFADDRS 21#include <ifaddrs.h> 22#endif 23 24#include <atalk/logger.h> 25#include <atalk/util.h> 26#include <atalk/dsi.h> 27#include <atalk/afp.h> 28#include <atalk/compat.h> 29#include <atalk/server_child.h> 30#include <atalk/globals.h> 31#include <atalk/errchk.h> 32#include <atalk/netatalk_conf.h> 33#include <atalk/fce_api.h> 34 35#ifdef HAVE_LDAP 36#include <atalk/ldapconfig.h> 37#endif 38 39#include "afp_config.h" 40#include "uam_auth.h" 41#include "status.h" 42#include "volume.h" 43#include "afp_zeroconf.h" 44 45/*! 46 * Free and cleanup config and DSI 47 * 48 * "dsi" can be NULL in which case all DSI objects and the config object is freed, 49 * otherwise its an afpd session child and only any unneeded DSI objects are freed 50 */ 51void configfree(AFPObj *obj, DSI *dsi) 52{ 53 DSI *p, *q; 54 55 if (!dsi) { 56 /* Master afpd reloading config */ 57 auth_unload(); 58 if (! (obj->options.flags & OPTION_NOZEROCONF)) { 59 zeroconf_deregister(); 60 } 61 } 62 63 unload_volumes(obj); 64 65 /* Master and child releasing unneeded DSI handles */ 66 for (p = obj->dsi; p; p = q) { 67 q = p->next; 68 if (p == dsi) 69 continue; 70 dsi_free(p); 71 free(p); 72 } 73 obj->dsi = NULL; 74 75 /* afpd session child passes dsi handle to obj handle */ 76 if (dsi) { 77 dsi->next = NULL; 78 obj->dsi = dsi; 79 } 80} 81 82/*! 83 * Get everything running 84 */ 85int configinit(AFPObj *obj) 86{ 87 EC_INIT; 88 DSI *dsi = NULL; 89 DSI **next = &obj->dsi; 90 char *p = NULL, *q = NULL, *savep; 91 const char *r; 92 struct ifaddrs *ifaddr, *ifa; 93 int family, s; 94 static char interfaddr[NI_MAXHOST]; 95 96 auth_load(obj->options.uampath, obj->options.uamlist); 97 set_signature(&obj->options); 98#ifdef HAVE_LDAP 99 acl_ldap_freeconfig(); 100#endif /* HAVE_LDAP */ 101 102 LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, interfaces: %s, port: %s", 103 obj->options.hostname, 104 obj->options.listen ? obj->options.listen : "-", 105 obj->options.interfaces ? obj->options.interfaces : "-", 106 obj->options.port); 107 108 /* 109 * Setup addresses we listen on from hostname and/or "afp listen" option 110 */ 111 if (obj->options.listen) { 112 EC_NULL( q = p = strdup(obj->options.listen) ); 113 EC_NULL( p = strtok_r(p, ", ", &savep) ); 114 while (p) { 115 if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL) 116 break; 117 118 status_init(obj, dsi); 119 *next = dsi; 120 next = &dsi->next; 121 dsi->AFPobj = obj; 122 123 LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d", 124 getip_string((struct sockaddr *)&dsi->server), 125 getip_port((struct sockaddr *)&dsi->server)); 126 127 p = strtok_r(NULL, ", ", &savep); 128 } 129 if (q) { 130 free(q); 131 q = NULL; 132 } 133 } 134 135 /* 136 * Setup addresses we listen on from "afp interfaces". 137 * We use getifaddrs() instead of if_nameindex() because the latter appears still 138 * to be unable to return ipv4 addresses 139 */ 140 if (obj->options.interfaces) { 141#ifndef HAVE_GETIFADDRS 142 LOG(log_error, logtype_afpd, "option \"afp interfaces\" not supported"); 143#else 144 if (getifaddrs(&ifaddr) == -1) { 145 LOG(log_error, logtype_afpd, "getinterfaddr: getifaddrs() failed: %s", strerror(errno)); 146 EC_FAIL; 147 } 148 149 EC_NULL( q = p = strdup(obj->options.interfaces) ); 150 EC_NULL( p = strtok_r(p, ", ", &savep) ); 151 while (p) { 152 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { 153 if (ifa->ifa_addr == NULL) 154 continue; 155 if (STRCMP(ifa->ifa_name, !=, p)) 156 continue; 157 158 family = ifa->ifa_addr->sa_family; 159 if (family == AF_INET || family == AF_INET6) { 160 if (getnameinfo(ifa->ifa_addr, 161 (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), 162 interfaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { 163 LOG(log_error, logtype_afpd, "getinterfaddr: getnameinfo() failed %s", gai_strerror(errno)); 164 continue; 165 } 166 167 if ((dsi = dsi_init(obj, obj->options.hostname, interfaddr, obj->options.port)) == NULL) 168 continue; 169 170 status_init(obj, dsi); 171 *next = dsi; 172 next = &dsi->next; 173 dsi->AFPobj = obj; 174 175 LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on interface %s with address %s:%d", 176 p, 177 getip_string((struct sockaddr *)&dsi->server), 178 getip_port((struct sockaddr *)&dsi->server)); 179 } /* if (family == AF_INET || family == AF_INET6) */ 180 } /* for (ifa != NULL) */ 181 p = strtok_r(NULL, ", ", &savep); 182 } 183 freeifaddrs(ifaddr); 184#endif 185 } 186 187 /* 188 * Check whether we got a valid DSI from options.listen or options.interfaces, 189 * if not add a DSI that accepts all connections and goes though the list of 190 * network interaces for determining an IP we can advertise in DSIStatus 191 */ 192 if (dsi == NULL) { 193 if ((dsi = dsi_init(obj, obj->options.hostname, NULL, obj->options.port)) == NULL) 194 EC_FAIL_LOG("no suitable network address found, use \"afp listen\" or \"afp interfaces\"", 0); 195 status_init(obj, dsi); 196 *next = dsi; 197 next = &dsi->next; 198 dsi->AFPobj = obj; 199 200 LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d", 201 getip_string((struct sockaddr *)&dsi->server), 202 getip_port((struct sockaddr *)&dsi->server)); 203 } 204 205#ifdef HAVE_LDAP 206 /* Parse afp.conf */ 207 acl_ldap_readconfig(obj->iniconfig); 208#endif /* HAVE_LDAP */ 209 210 /* Now register with zeroconf, we also need the volumes for that */ 211 if (! (obj->options.flags & OPTION_NOZEROCONF)) { 212 load_volumes(obj); 213 zeroconf_register(obj); 214 } 215 216 if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce listener", NULL))) { 217 LOG(log_note, logtype_afpd, "Adding FCE listener: %s", r); 218 fce_add_udp_socket(r); 219 } 220 if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce coalesce", NULL))) { 221 LOG(log_note, logtype_afpd, "Fce coalesce: %s", r); 222 fce_set_coalesce(r); 223 } 224 if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce events", NULL))) { 225 LOG(log_note, logtype_afpd, "Fce events: %s", r); 226 fce_set_events(r); 227 } 228 229EC_CLEANUP: 230 if (q) 231 free(q); 232 EC_EXIT; 233} 234