]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_dsi.c
1) try a better workaround for deadlocks when both the server and the client are...
[netatalk.git] / etc / afpd / afp_dsi.c
1 /*
2  * $Id: afp_dsi.c,v 1.46 2009-10-25 06:12:51 didg Exp $
3  *
4  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
5  * Copyright (c) 1990,1993 Regents of The University of Michigan.
6  * All Rights Reserved.  See COPYRIGHT.
7  *
8  * modified from main.c. this handles afp over tcp.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif /* HAVE_CONFIG_H */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <signal.h>
18 #include <string.h>
19 #include <errno.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif /* HAVE_UNISTD_H */
23 #include <sys/socket.h>
24 #include <sys/time.h>
25 #ifdef HAVE_SYS_STAT_H
26 #include <sys/stat.h>
27 #endif /* HAVE_SYS_STAT_H */
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <atalk/logger.h>
31
32 #include <atalk/dsi.h>
33 #include <atalk/compat.h>
34 #include <atalk/util.h>
35
36 #include "globals.h"
37 #include "switch.h"
38 #include "auth.h"
39 #include "fork.h"
40
41 #ifdef FORCE_UIDGID
42 #warning UIDGID
43 #include "uid.h"
44 #endif /* FORCE_UIDGID */
45
46 #define CHILD_DIE         (1 << 0)
47 #define CHILD_RUNNING     (1 << 1)
48 #define CHILD_SLEEPING    (1 << 2)
49 #define CHILD_DATA        (1 << 3)
50
51 static struct {
52     AFPObj *obj;
53     unsigned char flags;
54     int tickle;
55 } child;
56
57
58 static void afp_dsi_close(AFPObj *obj)
59 {
60     DSI *dsi = obj->handle;
61
62     /* XXX we have to check we are not root here */
63     close_all_vol();
64     if (obj->logout)
65         (*obj->logout)();
66
67     LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
68         dsi->read_count/1024.0, dsi->write_count/1024.0);
69
70     dsi_close(dsi);
71 }
72
73 /* -------------------------------
74  * SIGTERM
75  * a little bit of code duplication. 
76  */
77 static void afp_dsi_die(int sig)
78 {
79 static volatile int in_handler;
80     
81     if (in_handler) {
82         return;
83     }
84     /* it's not atomic but we don't care because it's an exit function
85      * ie if a signal is received here, between the test and the affectation,
86      * it will not return.
87     */
88     in_handler = 1;
89
90     dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
91     afp_dsi_close(child.obj);
92     if (sig) /* if no signal, assume dieing because logins are disabled &
93                 don't log it (maintenance mode)*/
94         LOG(log_info, logtype_afpd, "Connection terminated");
95     if (sig == SIGTERM || sig == SIGALRM) {
96         exit( 0 );
97     }
98     else {
99         exit(sig);
100     }
101 }
102
103 /* */
104 static void afp_dsi_sleep(void)
105 {
106     child.flags |= CHILD_SLEEPING;
107     dsi_sleep(child.obj->handle, 1);
108 }
109
110 /* ------------------- */
111 static void afp_dsi_timedown(int sig _U_)
112 {
113     struct sigaction    sv;
114     struct itimerval    it;
115
116     child.flags |= CHILD_DIE;
117     /* shutdown and don't reconnect. server going down in 5 minutes. */
118     setmessage("The server is going down for maintenance.");
119     if (dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
120                   AFPATTN_MESG | AFPATTN_TIME(5)) < 0) {
121         DSI *dsi = (DSI *) child.obj->handle;
122         dsi->down_request = 1;
123     }                  
124
125     it.it_interval.tv_sec = 0;
126     it.it_interval.tv_usec = 0;
127     it.it_value.tv_sec = 300;
128     it.it_value.tv_usec = 0;
129
130     if ( setitimer( ITIMER_REAL, &it, NULL ) < 0 ) {
131         LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
132         afp_dsi_die(EXITERR_SYS);
133     }
134     memset(&sv, 0, sizeof(sv));
135     sv.sa_handler = afp_dsi_die;
136     sigemptyset( &sv.sa_mask );
137     sigaddset(&sv.sa_mask, SIGHUP);
138     sigaddset(&sv.sa_mask, SIGTERM);
139     sv.sa_flags = SA_RESTART;
140     if ( sigaction( SIGALRM, &sv, NULL ) < 0 ) {
141         LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
142         afp_dsi_die(EXITERR_SYS);
143     }
144
145     /* ignore myself */
146     sv.sa_handler = SIG_IGN;
147     sigemptyset( &sv.sa_mask );
148     sv.sa_flags = SA_RESTART;
149     if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
150         LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGHUP: %s", strerror(errno) );
151         afp_dsi_die(EXITERR_SYS);
152     }
153 }
154
155 /* ---------------------------------
156  * SIGHUP reload configuration file
157  * FIXME here or we wait ?
158 */
159 volatile int reload_request = 0;
160
161 static void afp_dsi_reload(int sig _U_)
162 {
163     reload_request = 1;
164 }
165
166 /* ---------------------- */
167 #ifdef SERVERTEXT
168 static void afp_dsi_getmesg (int sig _U_)
169 {
170     DSI *dsi = (DSI *) child.obj->handle;
171
172     dsi->msg_request = 1;
173     if (dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0)
174         dsi->msg_request = 2;
175 }
176 #endif /* SERVERTEXT */
177
178 static void alarm_handler(int sig _U_)
179 {
180     int err;
181     DSI *dsi = (DSI *) child.obj->handle;
182
183     /* we have to restart the timer because some libraries 
184      * may use alarm() */
185     setitimer(ITIMER_REAL, &dsi->timer, NULL);
186
187     /* we got some traffic from the client since the previous timer 
188      * tick. */
189     if ((child.flags & CHILD_DATA)) {
190         child.flags &= ~CHILD_DATA;
191         return;
192     }
193
194     /* if we're in the midst of processing something,
195        don't die. */
196     if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) {
197         return;
198     } 
199         
200     if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
201         if (!(err = pollvoltime(child.obj)))
202             err = dsi_tickle(child.obj->handle);
203         if (err <= 0) 
204             afp_dsi_die(EXITERR_CLNT);
205         
206     } else { /* didn't receive a tickle. close connection */
207         LOG(log_error, logtype_afpd, "afp_alarm: child timed out");
208         afp_dsi_die(EXITERR_CLNT);
209     }
210 }
211
212 /* ----------------- 
213    if dsi->in_write is set attention, tickle (and close?) msg
214    aren't sent. We don't care about tickle 
215 */
216 static void pending_request(DSI *dsi)
217 {
218     /* send pending attention */
219
220     /* read msg if any, it could be done in afp_getsrvrmesg */
221     if (dsi->msg_request) {
222         if (dsi->msg_request == 2) {
223             /* didn't send it in signal handler */
224             dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
225         }
226         dsi->msg_request = 0;
227         readmessage(child.obj);
228     }
229     if (dsi->down_request) {
230         dsi->down_request = 0;
231         dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
232                   AFPATTN_MESG | AFPATTN_TIME(5));
233     }
234 }
235
236 /* -------------------------------------------
237  afp over dsi. this never returns. 
238 */
239 void afp_over_dsi(AFPObj *obj)
240 {
241     DSI *dsi = (DSI *) obj->handle;
242     u_int32_t err, cmd;
243     u_int8_t function;
244     struct sigaction action;
245     const char *afpcmpstr;
246
247     obj->exit = afp_dsi_die;
248     obj->reply = (int (*)()) dsi_cmdreply;
249     obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
250
251     obj->sleep = afp_dsi_sleep;
252     child.obj = obj;
253     child.tickle = child.flags = 0;
254
255     memset(&action, 0, sizeof(action));
256
257     /* install SIGHUP */
258     action.sa_handler = afp_dsi_reload;
259     sigemptyset( &action.sa_mask );
260     sigaddset(&action.sa_mask, SIGALRM);
261     sigaddset(&action.sa_mask, SIGTERM);
262     sigaddset(&action.sa_mask, SIGUSR1);
263 #ifdef SERVERTEXT
264     sigaddset(&action.sa_mask, SIGUSR2);
265 #endif    
266     action.sa_flags = SA_RESTART;
267     if ( sigaction( SIGHUP, &action, NULL ) < 0 ) {
268         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
269         afp_dsi_die(EXITERR_SYS);
270     }
271
272     /* install SIGTERM */
273     action.sa_handler = afp_dsi_die;
274     sigemptyset( &action.sa_mask );
275     sigaddset(&action.sa_mask, SIGALRM);
276     sigaddset(&action.sa_mask, SIGHUP);
277     sigaddset(&action.sa_mask, SIGUSR1);
278 #ifdef SERVERTEXT
279     sigaddset(&action.sa_mask, SIGUSR2);
280 #endif    
281     action.sa_flags = SA_RESTART;
282     if ( sigaction( SIGTERM, &action, NULL ) < 0 ) {
283         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
284         afp_dsi_die(EXITERR_SYS);
285     }
286
287 #ifdef SERVERTEXT
288     /* Added for server message support */
289     action.sa_handler = afp_dsi_getmesg;
290     sigemptyset( &action.sa_mask );
291     sigaddset(&action.sa_mask, SIGALRM);
292     sigaddset(&action.sa_mask, SIGTERM);
293     sigaddset(&action.sa_mask, SIGUSR1);
294     sigaddset(&action.sa_mask, SIGHUP);
295     action.sa_flags = SA_RESTART;
296     if ( sigaction( SIGUSR2, &action, NULL) < 0 ) {
297         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
298         afp_dsi_die(EXITERR_SYS);
299     }
300 #endif /* SERVERTEXT */
301
302     /*  SIGUSR1 - set down in 5 minutes  */
303     action.sa_handler = afp_dsi_timedown;
304     sigemptyset( &action.sa_mask );
305     sigaddset(&action.sa_mask, SIGALRM);
306     sigaddset(&action.sa_mask, SIGHUP);
307     sigaddset(&action.sa_mask, SIGTERM);
308 #ifdef SERVERTEXT
309     sigaddset(&action.sa_mask, SIGUSR2);
310 #endif    
311     action.sa_flags = SA_RESTART;
312     if ( sigaction( SIGUSR1, &action, NULL) < 0 ) {
313         LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
314         afp_dsi_die(EXITERR_SYS);
315     }
316
317 #ifndef DEBUGGING
318     /* tickle handler */
319     action.sa_handler = alarm_handler;
320     sigemptyset(&action.sa_mask);
321     sigaddset(&action.sa_mask, SIGHUP);
322     sigaddset(&action.sa_mask, SIGTERM);
323     sigaddset(&action.sa_mask, SIGUSR1);
324 #ifdef SERVERTEXT
325     sigaddset(&action.sa_mask, SIGUSR2);
326 #endif    
327     action.sa_flags = SA_RESTART;
328     if ((sigaction(SIGALRM, &action, NULL) < 0) ||
329             (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
330         afp_dsi_die(EXITERR_SYS);
331     }
332 #endif /* DEBUGGING */
333
334     /* get stuck here until the end */
335     while ((cmd = dsi_receive(dsi))) {
336         child.tickle = 0;
337         child.flags &= ~CHILD_SLEEPING;
338         dsi_sleep(dsi, 0); /* wake up */
339         if (reload_request) {
340             reload_request = 0;
341             load_volumes(child.obj);
342         }
343
344         if (cmd == DSIFUNC_TICKLE) {
345             /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
346             if ((child.flags & CHILD_DIE))
347                 dsi_tickle(dsi);
348             pending_request(dsi);
349             continue;
350         } 
351
352         child.flags |= CHILD_DATA;
353         switch(cmd) {
354         case DSIFUNC_CLOSE:
355             afp_dsi_close(obj);
356             LOG(log_info, logtype_afpd, "done");
357             return;
358             break;
359
360         case DSIFUNC_CMD:
361 #ifdef AFS
362             if ( writtenfork ) {
363                 if ( flushfork( writtenfork ) < 0 ) {
364                     LOG(log_error, logtype_afpd, "main flushfork: %s", strerror(errno) );
365                 }
366                 writtenfork = NULL;
367             }
368 #endif /* AFS */
369
370             function = (u_char) dsi->commands[0];
371
372             /* send off an afp command. in a couple cases, we take advantage
373              * of the fact that we're a stream-based protocol. */
374             if (afp_switch[function]) {
375                 dsi->datalen = DSI_DATASIZ;
376                 child.flags |= CHILD_RUNNING;
377
378                 afpcmpstr = AfpNum2name(function);
379                 LOG(log_debug, logtype_afpd, "=> Start AFP command: %s", afpcmpstr);
380
381                 err = (*afp_switch[function])(obj,
382                                               (char *)&dsi->commands, dsi->cmdlen,
383                                               (char *)&dsi->data, &dsi->datalen);
384
385                 LOG(log_debug, logtype_afpd, "=> Finished AFP command: %s", afpcmpstr);
386 #ifdef FORCE_UIDGID
387                 /* bring everything back to old euid, egid */
388                 if (obj->force_uid)
389                     restore_uidgid ( &obj->uidgid );
390 #endif /* FORCE_UIDGID */
391                 child.flags &= ~CHILD_RUNNING;
392             } else {
393                 LOG(log_error, logtype_afpd, "bad function %X", function);
394                 dsi->datalen = 0;
395                 err = AFPERR_NOOP;
396             }
397
398             /* single shot toggle that gets set by dsi_readinit. */
399             if (dsi->noreply) {
400                 dsi->noreply = 0;
401                 break;
402             }
403
404             if (!dsi_cmdreply(dsi, err)) {
405                 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
406                 afp_dsi_die(EXITERR_CLNT);
407             }
408             break;
409
410         case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
411             function = (u_char) dsi->commands[0];
412             if ( afp_switch[ function ] != NULL ) {
413                 dsi->datalen = DSI_DATASIZ;
414                 child.flags |= CHILD_RUNNING;
415                 err = (*afp_switch[function])(obj,
416                                               (char *)&dsi->commands, dsi->cmdlen,
417                                               (char *)&dsi->data, &dsi->datalen);
418                 child.flags &= ~CHILD_RUNNING;
419 #ifdef FORCE_UIDGID
420                 /* bring everything back to old euid, egid */
421                 if (obj->force_uid)
422                     restore_uidgid ( &obj->uidgid );
423 #endif /* FORCE_UIDGID */
424             } else {
425                 LOG(log_error, logtype_afpd, "(write) bad function %x", function);
426                 dsi->datalen = 0;
427                 err = AFPERR_NOOP;
428             }
429
430             if (!dsi_wrtreply(dsi, err)) {
431                 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
432                 afp_dsi_die(EXITERR_CLNT);
433             }
434             break;
435
436         case DSIFUNC_ATTN: /* attention replies */
437             break;
438
439             /* error. this usually implies a mismatch of some kind
440              * between server and client. if things are correct,
441              * we need to flush the rest of the packet if necessary. */
442         default:
443             LOG(log_info, logtype_afpd,"afp_dsi: spurious command %d", cmd);
444             dsi_writeinit(dsi, dsi->data, DSI_DATASIZ);
445             dsi_writeflush(dsi);
446             break;
447         }
448         pending_request(dsi);
449     }
450
451     /* error */
452     afp_dsi_die(EXITERR_CLNT);
453 }