]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_config.c
netatalk: fix a crash on Solaris when registering with mDNS
[netatalk.git] / etc / afpd / afp_config.c
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
44 /*!
45  * Free and cleanup config and DSI
46  *
47  * "dsi" can be NULL in which case all DSI objects and the config object is freed,
48  * otherwise its an afpd session child and only any unneeded DSI objects are freed
49  */
50 void configfree(AFPObj *obj, DSI *dsi)
51 {
52     DSI *p, *q;
53
54     if (!dsi) {
55         /* Master afpd reloading config */
56         auth_unload();
57     }
58
59     unload_volumes(obj);
60
61     /* Master and child releasing unneeded DSI handles */
62     for (p = obj->dsi; p; p = q) {
63         q = p->next;
64         if (p == dsi)
65             continue;
66         dsi_free(p);
67         free(p);
68     }
69     obj->dsi = NULL;
70
71     /* afpd session child passes dsi handle to obj handle */
72     if (dsi) {
73         dsi->next = NULL;
74         obj->dsi = dsi;
75     }
76 }
77
78 /*!
79  * Get everything running
80  */
81 int configinit(AFPObj *obj)
82 {
83     EC_INIT;
84     DSI *dsi = NULL;
85     DSI **next = &obj->dsi;
86     char *p = NULL, *q = NULL, *savep;
87     const char *r;
88     struct ifaddrs *ifaddr, *ifa;
89     int family, s;
90     static char interfaddr[NI_MAXHOST];
91
92     auth_load(obj, obj->options.uampath, obj->options.uamlist);
93     set_signature(&obj->options);
94 #ifdef HAVE_LDAP
95     acl_ldap_freeconfig();
96 #endif /* HAVE_LDAP */
97
98     LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, listen: %s, interfaces: %s, port: %s",
99         obj->options.hostname,
100         obj->options.listen ? obj->options.listen : "-",
101         obj->options.interfaces ? obj->options.interfaces : "-",
102         obj->options.port);
103
104     /*
105      * Setup addresses we listen on from hostname and/or "afp listen" option
106      */
107     if (obj->options.listen) {
108         EC_NULL( q = p = strdup(obj->options.listen) );
109         EC_NULL( p = strtok_r(p, ", ", &savep) );
110         while (p) {
111             if ((dsi = dsi_init(obj, obj->options.hostname, p, obj->options.port)) == NULL)
112                 break;
113
114             status_init(obj, dsi);
115             *next = dsi;
116             next = &dsi->next;
117             dsi->AFPobj = obj;
118
119             LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
120                 getip_string((struct sockaddr *)&dsi->server),
121                 getip_port((struct sockaddr *)&dsi->server));
122
123             p = strtok_r(NULL, ", ", &savep);
124         }
125         if (q) {
126             free(q);
127             q = NULL;
128         }
129     }
130
131    /*
132     * Setup addresses we listen on from "afp interfaces".
133     * We use getifaddrs() instead of if_nameindex() because the latter appears still
134     * to be unable to return ipv4 addresses
135     */
136     if (obj->options.interfaces) {
137 #ifndef HAVE_GETIFADDRS
138         LOG(log_error, logtype_afpd, "option \"afp interfaces\" not supported");
139 #else
140         if (getifaddrs(&ifaddr) == -1) {
141             LOG(log_error, logtype_afpd, "getinterfaddr: getifaddrs() failed: %s", strerror(errno));
142             EC_FAIL;
143         }
144
145         EC_NULL( q = p = strdup(obj->options.interfaces) );
146         EC_NULL( p = strtok_r(p, ", ", &savep) );
147         while (p) {
148             for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
149                 if (ifa->ifa_addr == NULL)
150                     continue;
151                 if (STRCMP(ifa->ifa_name, !=, p))
152                     continue;
153
154                 family = ifa->ifa_addr->sa_family;
155                 if (family == AF_INET || family == AF_INET6) {
156                     if (getnameinfo(ifa->ifa_addr,
157                                     (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
158                                     interfaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) {
159                         LOG(log_error, logtype_afpd, "getinterfaddr: getnameinfo() failed %s", gai_strerror(errno));
160                         continue;
161                     }
162
163                     if ((dsi = dsi_init(obj, obj->options.hostname, interfaddr, obj->options.port)) == NULL)
164                         continue;
165
166                     status_init(obj, dsi);
167                     *next = dsi;
168                     next = &dsi->next;
169                     dsi->AFPobj = obj;
170
171                     LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on interface %s with address %s:%d",
172                         p,
173                         getip_string((struct sockaddr *)&dsi->server),
174                         getip_port((struct sockaddr *)&dsi->server));
175                 } /* if (family == AF_INET || family == AF_INET6) */
176             } /* for (ifa != NULL) */
177             p = strtok_r(NULL, ", ", &savep);
178         }
179         freeifaddrs(ifaddr);
180 #endif
181     }
182
183     /*
184      * Check whether we got a valid DSI from options.listen or options.interfaces,
185      * if not add a DSI that accepts all connections and goes though the list of
186      * network interaces for determining an IP we can advertise in DSIStatus
187      */
188     if (dsi == NULL) {
189         if ((dsi = dsi_init(obj, obj->options.hostname, NULL, obj->options.port)) == NULL)
190             EC_FAIL_LOG("no suitable network address found, use \"afp listen\" or \"afp interfaces\"", 0);
191         status_init(obj, dsi);
192         *next = dsi;
193         next = &dsi->next;
194         dsi->AFPobj = obj;
195
196         LOG(log_note, logtype_afpd, "Netatalk AFP/TCP listening on %s:%d",
197             getip_string((struct sockaddr *)&dsi->server),
198             getip_port((struct sockaddr *)&dsi->server));
199     }
200
201 #ifdef HAVE_LDAP
202     /* Parse afp.conf */
203     acl_ldap_readconfig(obj->iniconfig);
204 #endif /* HAVE_LDAP */
205
206     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce listener", NULL))) {
207                 LOG(log_note, logtype_afpd, "Adding FCE listener: %s", r);
208                 fce_add_udp_socket(r);
209     }
210     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce coalesce", NULL))) {
211                 LOG(log_note, logtype_afpd, "Fce coalesce: %s", r);
212                 fce_set_coalesce(r);
213     }
214     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce events", NULL))) {
215                 LOG(log_note, logtype_afpd, "Fce events: %s", r);
216                 fce_set_events(r);
217     }
218     r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce version", "1");
219     LOG(log_debug, logtype_afpd, "Fce version: %s", r);
220     obj->fce_version = atoi(r);
221
222     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce ignore names", ".DS_Store"))) {
223         obj->fce_ign_names = strdup(r);
224     }
225
226     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce notify script", NULL))) {
227         obj->fce_notify_script = strdup(r);
228     }
229
230
231
232 EC_CLEANUP:
233     if (q)
234         free(q);
235     EC_EXIT;
236 }