Example #1
0
/* SIGURG handler (primary reconnect) */
static void afp_dsi_transfer_session(int sig _U_)
{
    uint16_t dsiID;
    int socket;
    DSI *dsi = (DSI *)AFPobj->handle;

    LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session");

    if (readt(AFPobj->ipc_fd, &dsiID, 2, 0, 2) != 2) {
        LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive DSI id, goodbye");
        afp_dsi_close(AFPobj);
        exit(EXITERR_SYS);
    }

    if ((socket = recv_fd(AFPobj->ipc_fd, 1)) == -1) {
        LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive session fd, goodbye");
        afp_dsi_close(AFPobj);
        exit(EXITERR_SYS);
    }

    LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: received socket fd: %i", socket);

    dsi->proto_close(dsi);
    dsi->socket = socket;
    dsi->flags = DSI_RECONSOCKET;
    dsi->datalen = 0;
    dsi->eof = dsi->start = dsi->buffer;
    dsi->in_write = 0;
    dsi->header.dsi_requestID = dsiID;
    dsi->header.dsi_command = DSIFUNC_CMD;

    /*
     * The session transfer happens in the middle of FPDisconnect old session, thus we
     * have to send the reply now.
     */
    if (!dsi_cmdreply(dsi, AFP_OK)) {
        LOG(log_error, logtype_afpd, "dsi_cmdreply: %s", strerror(errno) );
        afp_dsi_close(AFPobj);
        exit(EXITERR_CLNT);
    }

    LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: succesfull primary reconnect");
    /* 
     * Now returning from this signal handler return to dsi_receive which should start
     * reading/continuing from the connected socket that was passed via the parent from
     * another session. The parent will terminate that session.
     */
    siglongjmp(recon_jmp, 1);
}
Example #2
0
/* SIGQUIT handler */
static void ipc_reconnect_handler(int sig _U_)
{
    if (reconnect_ipc(AFPobj) != 0) {
        LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect");
        afp_dsi_close(AFPobj);
        exit(EXITERR_SYS);        
    }

    if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) {
        LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend");
        afp_dsi_close(AFPobj);
        exit(EXITERR_SYS);        
    }
    LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done");
}
Example #3
0
/* -------------------------------
 * SIGTERM
 * a little bit of code duplication. 
 */
static void afp_dsi_die(int sig)
{
    DSI *dsi = (DSI *)AFPobj->handle;

    if (dsi->flags & DSI_RECONINPROG) {
        /* Primary reconnect succeeded, got SIGTERM from afpd parent */
        dsi->flags &= ~DSI_RECONINPROG;
        return; /* this returns to afp_disconnect */
    }

    if (dsi->flags & DSI_DISCONNECTED) {
        LOG(log_note, logtype_afpd, "Disconnected session terminating");
        exit(0);
    }

    dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN);
    afp_dsi_close(AFPobj);
   if (sig) /* if no signal, assume dieing because logins are disabled &
                don't log it (maintenance mode)*/
        LOG(log_info, logtype_afpd, "Connection terminated");
    if (sig == SIGTERM || sig == SIGALRM) {
        exit( 0 );
    }
    else {
        exit(sig);
    }
}
Example #4
0
/* -------------------------------------------
 afp over dsi. this never returns. 
*/
void afp_over_dsi(AFPObj *obj)
{
    DSI *dsi = (DSI *) obj->handle;
    int rc_idx;
    u_int32_t err, cmd;
    u_int8_t function;

    AFPobj = obj;
    obj->exit = afp_dsi_die;
    obj->reply = (int (*)()) dsi_cmdreply;
    obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
    dsi->tickle = 0;

    afp_over_dsi_sighandlers(obj);

    if (dircache_init(obj->options.dircachesize) != 0)
        afp_dsi_die(EXITERR_SYS);

    /* set TCP snd/rcv buf */
    if (obj->options.tcp_rcvbuf) {
        if (setsockopt(dsi->socket,
                       SOL_SOCKET,
                       SO_RCVBUF,
                       &obj->options.tcp_rcvbuf,
                       sizeof(obj->options.tcp_rcvbuf)) != 0) {
            LOG(log_error, logtype_dsi, "afp_over_dsi: setsockopt(SO_RCVBUF): %s", strerror(errno));
        }
    }
    if (obj->options.tcp_sndbuf) {
        if (setsockopt(dsi->socket,
                       SOL_SOCKET,
                       SO_SNDBUF,
                       &obj->options.tcp_sndbuf,
                       sizeof(obj->options.tcp_sndbuf)) != 0) {
            LOG(log_error, logtype_dsi, "afp_over_dsi: setsockopt(SO_SNDBUF): %s", strerror(errno));
        }
    }

    /* set TCP_NODELAY */
    int flag = 1;
    setsockopt(dsi->socket, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));

    /* get stuck here until the end */
    while (1) {
        if (sigsetjmp(recon_jmp, 1) != 0)
            /* returning from SIGALARM handler for a primary reconnect */
            continue;

        /* Blocking read on the network socket */
        cmd = dsi_stream_receive(dsi);

        if (cmd == 0) {
            /* cmd == 0 is the error condition */
            if (dsi->flags & DSI_RECONSOCKET) {
                /* we just got a reconnect so we immediately try again to receive on the new fd */
                dsi->flags &= ~DSI_RECONSOCKET;
                continue;
            }

            /* the client sometimes logs out (afp_logout) but doesn't close the DSI session */
            if (dsi->flags & DSI_AFP_LOGGED_OUT) {
                LOG(log_note, logtype_afpd, "afp_over_dsi: client logged out, terminating DSI session");
                afp_dsi_close(obj);
                exit(0);
            }

#if 0
            /*  got ECONNRESET in read from client => exit*/
            if (dsi->flags & DSI_GOT_ECONNRESET) {
                LOG(log_note, logtype_afpd, "afp_over_dsi: client connection reset");
                afp_dsi_close(obj);
                exit(0);
            }
#endif

            if (dsi->flags & DSI_RECONINPROG) {
                LOG(log_note, logtype_afpd, "afp_over_dsi: failed reconnect");
                afp_dsi_close(obj);
                exit(0);
            }

            /* Some error on the client connection, enter disconnected state */
            if (dsi_disconnect(dsi) != 0)
                afp_dsi_die(EXITERR_CLNT);

            while (dsi->flags & DSI_DISCONNECTED)
                pause(); /* gets interrupted by SIGALARM or SIGURG tickle */
            continue; /* continue receiving until disconnect timer expires
                       * or a primary reconnect succeeds  */
        }

        if (!(dsi->flags & DSI_EXTSLEEP) && (dsi->flags & DSI_SLEEPING)) {
            LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep");
            dsi->flags &= ~DSI_SLEEPING;
            dsi->tickle = 0;
        }

        if (reload_request) {
            reload_request = 0;
            load_volumes(AFPobj);
        }

        /* The first SIGINT enables debugging, the next restores the config */
        if (debug_request) {
            static int debugging = 0;
            debug_request = 0;

            dircache_dump();
            uuidcache_dump();

            if (debugging) {
                if (obj->options.logconfig)
                    setuplog(obj->options.logconfig);
                else
                    setuplog("default log_note");
                debugging = 0;
            } else {
                char logstr[50];
                debugging = 1;
                sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid());
                setuplog(logstr);
            }
        }


        dsi->flags |= DSI_DATA;
        dsi->tickle = 0;

        switch(cmd) {

        case DSIFUNC_CLOSE:
            LOG(log_debug, logtype_afpd, "DSI: close session request");
            afp_dsi_close(obj);
            LOG(log_note, logtype_afpd, "done");
            exit(0);

        case DSIFUNC_TICKLE:
            dsi->flags &= ~DSI_DATA; /* thats no data in the sense we use it in alarm_handler */
            LOG(log_debug, logtype_afpd, "DSI: client tickle");
            /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
            if ((dsi->flags & DSI_DIE))
                dsi_tickle(dsi);
            break;

        case DSIFUNC_CMD:
#ifdef AFS
            if ( writtenfork ) {
                if ( flushfork( writtenfork ) < 0 ) {
                    LOG(log_error, logtype_afpd, "main flushfork: %s", strerror(errno) );
                }
                writtenfork = NULL;
            }
#endif /* AFS */

            function = (u_char) dsi->commands[0];

            /* AFP replay cache */
            rc_idx = dsi->clientID % REPLAYCACHE_SIZE;
            LOG(log_debug, logtype_dsi, "DSI request ID: %u", dsi->clientID);

            if (replaycache[rc_idx].DSIreqID == dsi->clientID
                && replaycache[rc_idx].AFPcommand == function) {
                LOG(log_note, logtype_afpd, "AFP Replay Cache match: id: %u / cmd: %s",
                    dsi->clientID, AfpNum2name(function));
                err = replaycache[rc_idx].result;
            /* AFP replay cache end */
            } else {
                /* send off an afp command. in a couple cases, we take advantage
                 * of the fact that we're a stream-based protocol. */
                if (afp_switch[function]) {
                    dsi->datalen = DSI_DATASIZ;
                    dsi->flags |= DSI_RUNNING;

                    LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));

                    err = (*afp_switch[function])(obj,
                                                  (char *)&dsi->commands, dsi->cmdlen,
                                                  (char *)&dsi->data, &dsi->datalen);

                    LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
                        AfpNum2name(function), AfpErr2name(err));

                    dir_free_invalid_q();

#ifdef FORCE_UIDGID
                    /* bring everything back to old euid, egid */
                    if (obj->force_uid)
                        restore_uidgid ( &obj->uidgid );
#endif /* FORCE_UIDGID */
                    dsi->flags &= ~DSI_RUNNING;

                    /* Add result to the AFP replay cache */
                    replaycache[rc_idx].DSIreqID = dsi->clientID;
                    replaycache[rc_idx].AFPcommand = function;
                    replaycache[rc_idx].result = err;
                } else {
                    LOG(log_error, logtype_afpd, "bad function %X", function);
                    dsi->datalen = 0;
                    err = AFPERR_NOOP;
                }
            }

            /* single shot toggle that gets set by dsi_readinit. */
            if (dsi->flags & DSI_NOREPLY) {
                dsi->flags &= ~DSI_NOREPLY;
                break;
            } else if (!dsi_cmdreply(dsi, err)) {
                LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) );
                if (dsi_disconnect(dsi) != 0)
                    afp_dsi_die(EXITERR_CLNT);
            }
            break;

        case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */
            function = (u_char) dsi->commands[0];
            if ( afp_switch[ function ] != NULL ) {
                dsi->datalen = DSI_DATASIZ;
                dsi->flags |= DSI_RUNNING;

                LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));

                err = (*afp_switch[function])(obj,
                                              (char *)&dsi->commands, dsi->cmdlen,
                                              (char *)&dsi->data, &dsi->datalen);

                LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
                    AfpNum2name(function), AfpErr2name(err));

                dsi->flags &= ~DSI_RUNNING;
#ifdef FORCE_UIDGID
            	/* bring everything back to old euid, egid */
		if (obj->force_uid)
            	    restore_uidgid ( &obj->uidgid );
#endif /* FORCE_UIDGID */
            } else {
                LOG(log_error, logtype_afpd, "(write) bad function %x", function);
                dsi->datalen = 0;
                err = AFPERR_NOOP;
            }

            if (!dsi_wrtreply(dsi, err)) {
                LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) );
                if (dsi_disconnect(dsi) != 0)
                    afp_dsi_die(EXITERR_CLNT);
            }
            break;

        case DSIFUNC_ATTN: /* attention replies */
            break;

            /* error. this usually implies a mismatch of some kind
             * between server and client. if things are correct,
             * we need to flush the rest of the packet if necessary. */
        default:
            LOG(log_info, logtype_afpd,"afp_dsi: spurious command %d", cmd);
            dsi_writeinit(dsi, dsi->data, DSI_DATASIZ);
            dsi_writeflush(dsi);
            break;
        }
        pending_request(dsi);

        fce_pending_events(obj);
    }

    /* error */
    afp_dsi_die(EXITERR_CLNT);
}