~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to etc/afpd/afp_dsi.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: afp_dsi.c,v 1.24.2.4 2003/11/18 21:47:41 bfernhomberg 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
extern struct oforks    *writtenfork;
 
47
 
 
48
#define CHILD_DIE         (1 << 0)
 
49
#define CHILD_RUNNING     (1 << 1)
 
50
 
 
51
static struct {
 
52
    AFPObj *obj;
 
53
    unsigned char flags;
 
54
    int tickle;
 
55
} child;
 
56
 
 
57
 
 
58
static __inline__ void afp_dsi_close(AFPObj *obj)
 
59
{
 
60
    DSI *dsi = obj->handle;
 
61
 
 
62
    if (obj->logout)
 
63
        (*obj->logout)();
 
64
 
 
65
    /* UAM had syslog control; afpd needs to reassert itself */
 
66
    set_processname("afpd");
 
67
    syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid, logfacility_daemon);
 
68
    LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
 
69
        dsi->read_count/1024.0, dsi->write_count/1024.0);
 
70
 
 
71
    dsi_close(dsi);
 
72
}
 
73
 
 
74
/* a little bit of code duplication. */
 
75
static void afp_dsi_die(int sig)
 
76
{
 
77
    dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
 
78
    afp_dsi_close(child.obj);
 
79
    if (sig) /* if no signal, assume dieing because logins are disabled &
 
80
                don't log it (maintenance mode)*/
 
81
        LOG(log_info, logtype_afpd, "Connection terminated");
 
82
    if (sig == SIGTERM || sig == SIGALRM) {
 
83
        exit( 0 );
 
84
    }
 
85
    else {
 
86
        exit(sig);
 
87
    }
 
88
}
 
89
 
 
90
static void afp_dsi_timedown()
 
91
{
 
92
    struct sigaction    sv;
 
93
    struct itimerval    it;
 
94
 
 
95
    child.flags |= CHILD_DIE;
 
96
    /* shutdown and don't reconnect. server going down in 5 minutes. */
 
97
    setmessage("The server is going down for maintenance.");
 
98
    dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
 
99
                  AFPATTN_MESG | AFPATTN_TIME(5));
 
100
 
 
101
    it.it_interval.tv_sec = 0;
 
102
    it.it_interval.tv_usec = 0;
 
103
    it.it_value.tv_sec = 300;
 
104
    it.it_value.tv_usec = 0;
 
105
 
 
106
    if ( setitimer( ITIMER_REAL, &it, 0 ) < 0 ) {
 
107
        LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
 
108
        afp_dsi_die(1);
 
109
    }
 
110
 
 
111
    memset(&sv, 0, sizeof(sv));
 
112
    sv.sa_handler = afp_dsi_die;
 
113
    sigemptyset( &sv.sa_mask );
 
114
    sigaddset(&sv.sa_mask, SIGHUP);
 
115
    sigaddset(&sv.sa_mask, SIGTERM);
 
116
    sv.sa_flags = SA_RESTART;
 
117
    if ( sigaction( SIGALRM, &sv, 0 ) < 0 ) {
 
118
        LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
 
119
        afp_dsi_die(1);
 
120
    }
 
121
}
 
122
 
 
123
#ifdef SERVERTEXT
 
124
static void afp_dsi_getmesg (int sig)
 
125
{
 
126
    readmessage();
 
127
    dsi_attention(child.obj->handle, AFPATTN_MESG | AFPATTN_TIME(5));
 
128
}
 
129
#endif /* SERVERTEXT */
 
130
 
 
131
static void alarm_handler()
 
132
{
 
133
    int err;
 
134
 
 
135
    /* if we're in the midst of processing something,
 
136
       don't die. */
 
137
    if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
 
138
        if (!(err = pollvoltime(child.obj)))
 
139
            err = dsi_tickle(child.obj->handle);
 
140
        if (err <= 0) 
 
141
            afp_dsi_die(1);
 
142
        
 
143
    } else { /* didn't receive a tickle. close connection */
 
144
        LOG(log_error, logtype_afpd, "afp_alarm: child timed out");
 
145
        afp_dsi_die(1);
 
146
    }
 
147
}
 
148
 
 
149
 
 
150
/*
 
151
 *  Signal handler for SIGUSR1 - set the debug flag and 
 
152
 *  redirect stdout to <tmpdir>/afpd-debug-<pid>.
 
153
 */
 
154
void afp_set_debug (int sig)
 
155
{
 
156
    char        fname[MAXPATHLEN];
 
157
 
 
158
    snprintf(fname, MAXPATHLEN-1, "%s/afpd-debug-%d", P_tmpdir, getpid());
 
159
    freopen(fname, "w", stdout);
 
160
    child.obj->options.flags |= OPTION_DEBUG;
 
161
 
 
162
    return;
 
163
}
 
164
 
 
165
 
 
166
/* afp over dsi. this never returns. */
 
167
void afp_over_dsi(AFPObj *obj)
 
168
{
 
169
    DSI *dsi = (DSI *) obj->handle;
 
170
    u_int32_t err, cmd;
 
171
    u_int8_t function;
 
172
    struct sigaction action;
 
173
 
 
174
    obj->exit = afp_dsi_die;
 
175
    obj->reply = (int (*)()) dsi_cmdreply;
 
176
    obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
 
177
 
 
178
    child.obj = obj;
 
179
    child.tickle = child.flags = 0;
 
180
 
 
181
    /* install SIGTERM and SIGHUP */
 
182
    memset(&action, 0, sizeof(action));
 
183
    action.sa_handler = afp_dsi_timedown;
 
184
    sigemptyset( &action.sa_mask );
 
185
    sigaddset(&action.sa_mask, SIGALRM);
 
186
    sigaddset(&action.sa_mask, SIGTERM);
 
187
#ifdef SERVERTEXT
 
188
    sigaddset(&action.sa_mask, SIGUSR2);
 
189
#endif
 
190
    action.sa_flags = SA_RESTART;
 
191
    if ( sigaction( SIGHUP, &action, 0 ) < 0 ) {
 
192
        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
 
193
        afp_dsi_die(1);
 
194
    }
 
195
 
 
196
    action.sa_handler = afp_dsi_die;
 
197
    sigemptyset( &action.sa_mask );
 
198
    sigaddset(&action.sa_mask, SIGALRM);
 
199
    sigaddset(&action.sa_mask, SIGHUP);
 
200
#ifdef SERVERTEXT
 
201
    sigaddset(&action.sa_mask, SIGUSR2);
 
202
#endif
 
203
    action.sa_flags = SA_RESTART;
 
204
    if ( sigaction( SIGTERM, &action, 0 ) < 0 ) {
 
205
        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
 
206
        afp_dsi_die(1);
 
207
    }
 
208
 
 
209
#ifdef SERVERTEXT
 
210
    /* Added for server message support */
 
211
    action.sa_handler = afp_dsi_getmesg;
 
212
    sigemptyset( &action.sa_mask );
 
213
    sigaddset(&action.sa_mask, SIGTERM);
 
214
    sigaddset(&action.sa_mask, SIGALRM);
 
215
    sigaddset(&action.sa_mask, SIGHUP);
 
216
    action.sa_flags = SA_RESTART;
 
217
    if ( sigaction( SIGUSR2, &action, 0) < 0 ) {
 
218
        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
 
219
        afp_dsi_die(1);
 
220
    }
 
221
#endif /* SERVERTEXT */
 
222
 
 
223
    /*  SIGUSR1 - set "debug" flag on this process.  */
 
224
    action.sa_handler = afp_set_debug;
 
225
    sigemptyset( &action.sa_mask );
 
226
    sigaddset(&action.sa_mask, SIGUSR1);
 
227
    action.sa_flags = SA_RESTART;
 
228
    if ( sigaction( SIGUSR1, &action, 0) < 0 ) {
 
229
        LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
 
230
        afp_dsi_die(1);
 
231
    }
 
232
 
 
233
    /* tickle handler */
 
234
    action.sa_handler = alarm_handler;
 
235
    sigemptyset(&action.sa_mask);
 
236
    sigaddset(&action.sa_mask, SIGHUP);
 
237
    sigaddset(&action.sa_mask, SIGTERM);
 
238
#ifdef SERVERTEXT
 
239
    sigaddset(&action.sa_mask, SIGUSR2);
 
240
#endif
 
241
    action.sa_flags = SA_RESTART;
 
242
    if ((sigaction(SIGALRM, &action, NULL) < 0) ||
 
243
            (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
 
244
        afp_dsi_die(1);
 
245
    }
 
246
 
 
247
    /* get stuck here until the end */
 
248
    while ((cmd = dsi_receive(dsi))) {
 
249
        child.tickle = 0;
 
250
 
 
251
        if (cmd == DSIFUNC_TICKLE) {
 
252
            /* so we don't get killed on the client side. */
 
253
            if ((child.flags & CHILD_DIE))
 
254
                dsi_tickle(dsi);
 
255
            continue;
 
256
        } else if (!(child.flags & CHILD_DIE)) { /* reset tickle timer */
 
257
            setitimer(ITIMER_REAL, &dsi->timer, NULL);
 
258
        }
 
259
 
 
260
        switch(cmd) {
 
261
        case DSIFUNC_CLOSE:
 
262
            afp_dsi_close(obj);
 
263
            LOG(log_info, logtype_afpd, "done");
 
264
            if (obj->options.flags & OPTION_DEBUG )
 
265
                printf("done\n");
 
266
            return;
 
267
            break;
 
268
 
 
269
        case DSIFUNC_CMD:
 
270
#ifdef AFS
 
271
            if ( writtenfork ) {
 
272
                if ( flushfork( writtenfork ) < 0 ) {
 
273
                    LOG(log_error, logtype_afpd, "main flushfork: %s", strerror(errno) );
 
274
                }
 
275
                writtenfork = NULL;
 
276
            }
 
277
#endif /* AFS */
 
278
 
 
279
            function = (u_char) dsi->commands[0];
 
280
            if (obj->options.flags & OPTION_DEBUG ) {
 
281
                printf("command: %d (%s)\n", function, AfpNum2name(function));
 
282
                bprint((char *) dsi->commands, dsi->cmdlen);
 
283
            }
 
284
 
 
285
            /* send off an afp command. in a couple cases, we take advantage
 
286
             * of the fact that we're a stream-based protocol. */
 
287
            if (afp_switch[function]) {
 
288
                dsi->datalen = DSI_DATASIZ;
 
289
                child.flags |= CHILD_RUNNING;
 
290
 
 
291
                err = (*afp_switch[function])(obj,
 
292
                                              dsi->commands, dsi->cmdlen,
 
293
                                              dsi->data, &dsi->datalen);
 
294
#ifdef FORCE_UIDGID
 
295
                /* bring everything back to old euid, egid */
 
296
                if (obj->force_uid)
 
297
                    restore_uidgid ( &obj->uidgid );
 
298
#endif /* FORCE_UIDGID */
 
299
                child.flags &= ~CHILD_RUNNING;
 
300
            } else {
 
301
                LOG(log_error, logtype_afpd, "bad function %X", function);
 
302
                dsi->datalen = 0;
 
303
                err = AFPERR_NOOP;
 
304
            }
 
305
 
 
306
            /* single shot toggle that gets set by dsi_readinit. */
 
307
            if (dsi->noreply) {
 
308
                dsi->noreply = 0;
 
309
                break;
 
310
            }
 
311
 
 
312
            if (obj->options.flags & OPTION_DEBUG ) {
 
313
                printf( "reply: %d, %d\n", err, dsi->clientID);
 
314
                bprint((char *) dsi->data, dsi->datalen);
 
315
            }
 
316
 
 
317
            if (!dsi_cmdreply(dsi, err)) {
 
318
                LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
 
319
                afp_dsi_die(1);
 
320
            }
 
321
            break;
 
322
 
 
323
        case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
 
324
            function = (u_char) dsi->commands[0];
 
325
            if ( obj->options.flags & OPTION_DEBUG ) {
 
326
                printf("(write) command: %d, %d\n", function, dsi->cmdlen);
 
327
                bprint((char *) dsi->commands, dsi->cmdlen);
 
328
            }
 
329
 
 
330
            if ( afp_switch[ function ] != NULL ) {
 
331
                dsi->datalen = DSI_DATASIZ;
 
332
                child.flags |= CHILD_RUNNING;
 
333
                err = (*afp_switch[function])(obj, dsi->commands, dsi->cmdlen,
 
334
                                              dsi->data, &dsi->datalen);
 
335
                child.flags &= ~CHILD_RUNNING;
 
336
#ifdef FORCE_UIDGID
 
337
                /* bring everything back to old euid, egid */
 
338
                if (obj->force_uid)
 
339
                    restore_uidgid ( &obj->uidgid );
 
340
#endif /* FORCE_UIDGID */
 
341
            } else {
 
342
                LOG(log_error, logtype_afpd, "(write) bad function %x", function);
 
343
                dsi->datalen = 0;
 
344
                err = AFPERR_NOOP;
 
345
            }
 
346
 
 
347
            if (obj->options.flags & OPTION_DEBUG ) {
 
348
                printf( "(write) reply code: %d, %d\n", err, dsi->clientID);
 
349
                bprint((char *) dsi->data, dsi->datalen);
 
350
            }
 
351
 
 
352
            if (!dsi_wrtreply(dsi, err)) {
 
353
                LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
 
354
                afp_dsi_die(1);
 
355
            }
 
356
            break;
 
357
 
 
358
        case DSIFUNC_ATTN: /* attention replies */
 
359
            continue;
 
360
            break;
 
361
 
 
362
            /* error. this usually implies a mismatch of some kind
 
363
             * between server and client. if things are correct,
 
364
             * we need to flush the rest of the packet if necessary. */
 
365
        default:
 
366
            LOG(log_info, logtype_afpd,"afp_dsi: spurious command %d", cmd);
 
367
            dsi_writeinit(dsi, dsi->data, DSI_DATASIZ);
 
368
            dsi_writeflush(dsi);
 
369
            break;
 
370
        }
 
371
 
 
372
        if ( obj->options.flags & OPTION_DEBUG ) {
 
373
#ifdef notdef
 
374
            pdesc( stdout );
 
375
#endif /* notdef */
 
376
            of_pforkdesc( stdout );
 
377
            fflush( stdout );
 
378
        }
 
379
    }
 
380
 
 
381
    /* error */
 
382
    afp_dsi_die(1);
 
383
}