1/*
2 * $Id: afp_asp.c,v 1.29 2010-03-09 06:55:12 franklahm Exp $
3 *
4 * Copyright (c) 1997 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 asp.
9 */
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif /* HAVE_CONFIG_H */
14
15#ifndef NO_DDP
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <signal.h>
21#include <atalk/logger.h>
22#include <errno.h>
23#ifdef HAVE_SYS_TIME_H
24#include <sys/time.h>
25#endif /* HAVE_SYS_TIME_H */
26#ifdef HAVE_SYS_STAT_H
27#include <sys/stat.h>
28#endif /* HAVE_SYS_STAT_H */
29
30#include <netatalk/endian.h>
31#include <atalk/atp.h>
32#include <atalk/asp.h>
33#include <atalk/compat.h>
34#include <atalk/util.h>
35#include <atalk/globals.h>
36
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
46static AFPObj *child;
47
48static void afp_authprint_remove(AFPObj *);
49
50static void afp_asp_close(AFPObj *obj)
51{
52    ASP asp = obj->handle;
53
54    if (seteuid( obj->uid ) < 0) {
55        LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
56        exit(EXITERR_SYS);
57    }
58    close_all_vol();
59    if (obj->options.authprintdir) afp_authprint_remove(obj);
60
61    if (obj->logout)
62        (*obj->logout)();
63
64    LOG(log_info, logtype_afpd, "%.2fKB read, %.2fKB written",
65        asp->read_count / 1024.0, asp->write_count / 1024.0);
66    asp_close( asp );
67}
68
69/* removes the authprint trailing when appropriate */
70static void afp_authprint_remove(AFPObj *obj)
71{
72    ASP asp = obj->handle;
73    char addr_filename[256];
74    char addr_filename_buff[256];
75    struct stat cap_st;
76
77    sprintf(addr_filename, "%s/net%d.%dnode%d", obj->options.authprintdir,
78                ntohs( asp->asp_sat.sat_addr.s_net )/256,
79                ntohs( asp->asp_sat.sat_addr.s_net )%256,
80                asp->asp_sat.sat_addr.s_node );
81
82    memset( addr_filename_buff, 0, 256 );
83
84    if (stat(addr_filename, &cap_st) == 0) {
85	if( S_ISREG(cap_st.st_mode) ) {
86	    int len;
87	    int capfd = open( addr_filename, O_RDONLY );
88	    if ((len = read( capfd, addr_filename_buff, 256 )) > 0) {
89		int file_pid;
90		char *p_filepid;
91		addr_filename_buff[len] = 0;
92		if ( (p_filepid = strrchr(addr_filename_buff, ':')) != NULL) {
93		    *p_filepid = '\0';
94		    p_filepid++;
95		    file_pid = atoi(p_filepid);
96		    if (file_pid == (int)getpid()) {
97			if(unlink(addr_filename) == 0) {
98			    LOG(log_info, logtype_afpd, "removed %s", addr_filename);
99			} else {
100			    LOG(log_info, logtype_afpd, "error removing %s: %s",
101				    addr_filename, strerror(errno));
102			}
103		    } else {
104			LOG(log_info, logtype_afpd, "%s belongs to another pid %d",
105			     addr_filename, file_pid );
106		    }
107		} else { /* no pid info */
108		    if (unlink(addr_filename) == 0) {
109			LOG(log_info, logtype_afpd, "removed %s", addr_filename );
110		    } else {
111			LOG(log_info, logtype_afpd, "error removing %s: %s",
112				addr_filename, strerror(errno));
113		    }
114		}
115	    } else {
116		LOG(log_info, logtype_afpd, "couldn't read data from %s", addr_filename );
117	    }
118        if (capfd != -1)
119            close(capfd);
120	} else {
121	    LOG(log_info, logtype_afpd, "%s is not a regular file", addr_filename );
122	}
123    } else {
124        LOG(log_info, logtype_afpd, "error stat'ing %s: %s",
125                   addr_filename, strerror(errno));
126    }
127}
128
129/* ------------------------
130 * SIGTERM
131*/
132static void afp_asp_die(const int sig)
133{
134    ASP asp = child->handle;
135
136    asp_attention(asp, AFPATTN_SHUTDOWN);
137    if ( asp_shutdown( asp ) < 0 ) {
138        LOG(log_error, logtype_afpd, "afp_die: asp_shutdown: %s", strerror(errno) );
139    }
140
141    afp_asp_close(child);
142    if (sig == SIGTERM || sig == SIGALRM)
143        exit( 0 );
144    else
145        exit(sig);
146}
147
148/* -----------------------------
149 * SIGUSR1
150 */
151static void afp_asp_timedown(int sig _U_)
152{
153    struct sigaction	sv;
154    struct itimerval	it;
155
156    /* shutdown and don't reconnect. server going down in 5 minutes. */
157    asp_attention(child->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
158                  AFPATTN_TIME(5));
159
160    it.it_interval.tv_sec = 0;
161    it.it_interval.tv_usec = 0;
162    it.it_value.tv_sec = 300;
163    it.it_value.tv_usec = 0;
164    if ( setitimer( ITIMER_REAL, &it, NULL ) < 0 ) {
165        LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) );
166        afp_asp_die(EXITERR_SYS);
167    }
168
169    memset(&sv, 0, sizeof(sv));
170    sv.sa_handler = afp_asp_die;
171    sigemptyset( &sv.sa_mask );
172    sigaddset(&sv.sa_mask, SIGHUP);
173    sigaddset(&sv.sa_mask, SIGTERM);
174    sv.sa_flags = SA_RESTART;
175    if ( sigaction( SIGALRM, &sv, NULL ) < 0 ) {
176        LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) );
177        afp_asp_die(EXITERR_SYS);
178    }
179
180    /* ignore myself */
181    sv.sa_handler = SIG_IGN;
182    sigemptyset( &sv.sa_mask );
183    sv.sa_flags = SA_RESTART;
184    if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
185        LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGUSR1: %s", strerror(errno) );
186        afp_asp_die(EXITERR_SYS);
187    }
188}
189
190/* ---------------------------------
191 * SIGHUP reload configuration file
192*/
193extern volatile int reload_request;
194
195static void afp_asp_reload(int sig _U_)
196{
197    reload_request = 1;
198}
199
200/* ---------------------- */
201#ifdef SERVERTEXT
202static void afp_asp_getmesg (int sig _U_)
203{
204    readmessage(child);
205    asp_attention(child->handle, AFPATTN_MESG | AFPATTN_TIME(5));
206}
207#endif /* SERVERTEXT */
208
209/* ---------------------- */
210void afp_over_asp(AFPObj *obj)
211{
212    ASP asp;
213    struct sigaction  action;
214    int		func,  reply = 0;
215#ifdef DEBUG1
216    int ccnt = 0;
217#endif
218
219    AFPobj = obj;
220    obj->exit = afp_asp_die;
221    obj->reply = (int (*)()) asp_cmdreply;
222    obj->attention = (int (*)(void *, AFPUserBytes)) asp_attention;
223    child = obj;
224    asp = (ASP) obj->handle;
225
226    /* install signal handlers
227     * With ASP tickle handler is done in the parent process
228    */
229    memset(&action, 0, sizeof(action));
230
231    /* install SIGHUP */
232    action.sa_handler = afp_asp_reload;
233    sigemptyset( &action.sa_mask );
234    sigaddset(&action.sa_mask, SIGTERM);
235    sigaddset(&action.sa_mask, SIGUSR1);
236#ifdef SERVERTEXT
237    sigaddset(&action.sa_mask, SIGUSR2);
238#endif
239    action.sa_flags = SA_RESTART;
240    if ( sigaction( SIGHUP, &action, NULL ) < 0 ) {
241        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
242        afp_asp_die(EXITERR_SYS);
243    }
244
245    /*  install SIGTERM */
246    action.sa_handler = afp_asp_die;
247    sigemptyset( &action.sa_mask );
248    sigaddset(&action.sa_mask, SIGHUP);
249    sigaddset(&action.sa_mask, SIGUSR1);
250#ifdef SERVERTEXT
251    sigaddset(&action.sa_mask, SIGUSR2);
252#endif
253    action.sa_flags = SA_RESTART;
254    if ( sigaction( SIGTERM, &action, NULL ) < 0 ) {
255        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
256        afp_asp_die(EXITERR_SYS);
257    }
258
259#ifdef SERVERTEXT
260    /* Added for server message support */
261    action.sa_handler = afp_asp_getmesg;
262    sigemptyset( &action.sa_mask );
263    sigaddset(&action.sa_mask, SIGTERM);
264    sigaddset(&action.sa_mask, SIGUSR1);
265    sigaddset(&action.sa_mask, SIGHUP);
266    action.sa_flags = SA_RESTART;
267    if ( sigaction( SIGUSR2, &action, NULL) < 0 ) {
268        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
269        afp_asp_die(EXITERR_SYS);
270    }
271#endif /* SERVERTEXT */
272
273    /*  SIGUSR1 - set down in 5 minutes  */
274    action.sa_handler = afp_asp_timedown;
275    sigemptyset( &action.sa_mask );
276    sigaddset(&action.sa_mask, SIGHUP);
277    sigaddset(&action.sa_mask, SIGTERM);
278#ifdef SERVERTEXT
279    sigaddset(&action.sa_mask, SIGUSR2);
280#endif
281    action.sa_flags = SA_RESTART;
282    if ( sigaction( SIGUSR1, &action, NULL ) < 0 ) {
283        LOG(log_error, logtype_afpd, "afp_over_asp: sigaction: %s", strerror(errno) );
284        afp_asp_die(EXITERR_SYS);
285    }
286
287    if (dircache_init(obj->options.dircachesize) != 0) {
288        LOG(log_error, logtype_afpd, "afp_over_asp: dircache_init error");
289        afp_asp_die(EXITERR_SYS);
290    }
291
292    LOG(log_info, logtype_afpd, "session from %u.%u:%u on %u.%u:%u",
293        ntohs( asp->asp_sat.sat_addr.s_net ),
294        asp->asp_sat.sat_addr.s_node, asp->asp_sat.sat_port,
295        ntohs( atp_sockaddr( asp->asp_atp )->sat_addr.s_net ),
296        atp_sockaddr( asp->asp_atp )->sat_addr.s_node,
297        atp_sockaddr( asp->asp_atp )->sat_port );
298
299    while ((reply = asp_getrequest(asp))) {
300        if (reload_request) {
301            reload_request = 0;
302            load_volumes(child);
303        }
304        switch (reply) {
305        case ASPFUNC_CLOSE :
306            afp_asp_close(obj);
307            LOG(log_info, logtype_afpd, "done" );
308
309#ifdef DEBUG1
310            if ( obj->options.flags & OPTION_DEBUG ) {
311                printf( "done\n" );
312            }
313#endif
314            return;
315            break;
316
317        case ASPFUNC_CMD :
318#ifdef AFS
319            if ( writtenfork ) {
320                if ( flushfork( writtenfork ) < 0 ) {
321                    LOG(log_error, logtype_afpd, "main flushfork: %s",
322						strerror(errno));
323                }
324                writtenfork = NULL;
325            }
326#endif /* AFS */
327            func = (u_char) asp->commands[0];
328#ifdef DEBUG1
329            if ( obj->options.flags & OPTION_DEBUG ) {
330                printf("command: %d (%s)\n", func, AfpNum2name(func));
331                bprint( asp->commands, asp->cmdlen );
332            }
333#endif
334            if ( afp_switch[ func ] != NULL ) {
335                /*
336                 * The function called from afp_switch is expected to
337                 * read its parameters out of buf, put its
338                 * results in replybuf (updating rbuflen), and
339                 * return an error code.
340                */
341                asp->datalen = ASP_DATASIZ;
342                reply = (*afp_switch[ func ])(obj,
343                                              asp->commands, asp->cmdlen,
344                                              asp->data, &asp->datalen);
345#ifdef FORCE_UIDGID
346            	/* bring everything back to old euid, egid */
347		if (obj->force_uid)
348            	    restore_uidgid ( &obj->uidgid );
349#endif /* FORCE_UIDGID */
350            } else {
351                LOG(log_error, logtype_afpd, "bad function %X", func );
352                asp->datalen = 0;
353                reply = AFPERR_NOOP;
354            }
355#ifdef DEBUG1
356            if ( obj->options.flags & OPTION_DEBUG ) {
357                printf( "reply: %d, %d\n", reply, ccnt++ );
358                bprint( asp->data, asp->datalen );
359            }
360#endif
361            if ( asp_cmdreply( asp, reply ) < 0 ) {
362                LOG(log_error, logtype_afpd, "asp_cmdreply: %s", strerror(errno) );
363                afp_asp_die(EXITERR_CLNT);
364            }
365            break;
366
367        case ASPFUNC_WRITE :
368            func = (u_char) asp->commands[0];
369#ifdef DEBUG1
370            if ( obj->options.flags & OPTION_DEBUG ) {
371                printf( "(write) command: %d\n", func );
372                bprint( asp->commands, asp->cmdlen );
373            }
374#endif
375            if ( afp_switch[ func ] != NULL ) {
376                asp->datalen = ASP_DATASIZ;
377                reply = (*afp_switch[ func ])(obj,
378                                              asp->commands, asp->cmdlen,
379                                              asp->data, &asp->datalen);
380#ifdef FORCE_UIDGID
381            	/* bring everything back to old euid, egid */
382		if (obj->force_uid)
383            	    restore_uidgid ( &obj->uidgid );
384#endif /* FORCE_UIDGID */
385            } else {
386                LOG(log_error, logtype_afpd, "(write) bad function %X", func );
387                asp->datalen = 0;
388                reply = AFPERR_NOOP;
389            }
390#ifdef DEBUG1
391            if ( obj->options.flags & OPTION_DEBUG ) {
392                printf( "(write) reply code: %d, %d\n", reply, ccnt++ );
393                bprint( asp->data, asp->datalen );
394            }
395#endif
396            if ( asp_wrtreply( asp, reply ) < 0 ) {
397                LOG(log_error, logtype_afpd, "asp_wrtreply: %s", strerror(errno) );
398                afp_asp_die(EXITERR_CLNT);
399            }
400            break;
401        default:
402            /*
403               * Bad asp packet.  Probably should have asp filter them,
404               * since they are typically things like out-of-order packet.
405               */
406            LOG(log_info, logtype_afpd, "main: asp_getrequest: %d", reply );
407            break;
408        }
409#ifdef DEBUG1
410        if ( obj->options.flags & OPTION_DEBUG ) {
411#ifdef notdef
412            pdesc( stdout );
413#endif /* notdef */
414            of_pforkdesc( stdout );
415            fflush( stdout );
416        }
417#endif
418    }
419}
420
421#endif
422