]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_config.c
fce: FCE version 2 with new event types and new config options
[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 #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  */
51 void 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  */
85 int 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, 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, lv_all);
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     r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce version", "1");
229     LOG(log_debug, logtype_afpd, "Fce version: %s", r);
230     obj->fce_version = atoi(r);
231
232     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce ignore names", ".DS_Store"))) {
233         obj->fce_ign_names = strdup(r);
234     }
235
236     if ((r = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "fce notify script", NULL))) {
237         obj->fce_notify_script = strdup(r);
238     }
239
240
241
242 EC_CLEANUP:
243     if (q)
244         free(q);
245     EC_EXIT;
246 }