1/* 2 * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) 3 * Copyright (c) 1990,1993 Regents of The University of Michigan. 4 * All Rights Reserved. See COPYRIGHT. 5 * 6 * modified from main.c. this handles afp over tcp. 7 */ 8 9#ifdef HAVE_CONFIG_H 10#include "config.h" 11#endif /* HAVE_CONFIG_H */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <signal.h> 16#include <string.h> 17#include <errno.h> 18#ifdef HAVE_UNISTD_H 19#include <unistd.h> 20#endif /* HAVE_UNISTD_H */ 21#include <sys/socket.h> 22#include <sys/time.h> 23#ifdef HAVE_SYS_STAT_H 24#include <sys/stat.h> 25#endif /* HAVE_SYS_STAT_H */ 26#include <netinet/in.h> 27#include <netinet/tcp.h> 28#include <arpa/inet.h> 29#include <setjmp.h> 30#include <time.h> 31 32#include <atalk/logger.h> 33#include <atalk/dsi.h> 34#include <atalk/compat.h> 35#include <atalk/util.h> 36#include <atalk/uuid.h> 37#include <atalk/paths.h> 38#include <atalk/server_ipc.h> 39#include <atalk/fce_api.h> 40 41#include <atalk/globals.h> 42#include "switch.h" 43#include "auth.h" 44#include "fork.h" 45#include "dircache.h" 46 47#define WOL 48#ifdef WOL 49time_t last_wol=0; 50#define WOL_INTERVAL 300 51#endif 52#ifdef FORCE_UIDGID 53#warning UIDGID 54#include "uid.h" 55#endif /* FORCE_UIDGID */ 56 57#ifndef SOL_TCP 58#define SOL_TCP IPPROTO_TCP 59#endif 60 61/* 62 * We generally pass this from afp_over_dsi to all afp_* funcs, so it should already be 63 * available everywhere. Unfortunately some funcs (eg acltoownermode) need acces to it 64 * but are deeply nested in the function chain with the caller already without acces to it. 65 * Changing this would require adding a reference to the caller which itself might be 66 * called in many places (eg acltoownermode is called from accessmode). 67 * The only sane way out is providing a copy of it here: 68 */ 69AFPObj *AFPobj = NULL; 70 71typedef struct { 72 uint16_t DSIreqID; 73 uint8_t AFPcommand; 74 uint32_t result; 75} rc_elem_t; 76 77/* 78 * AFP replay cache: 79 * - fix sized array 80 * - indexed just by taking DSIreqID mod REPLAYCACHE_SIZE 81 */ 82static rc_elem_t replaycache[REPLAYCACHE_SIZE]; 83 84static sigjmp_buf recon_jmp; 85static void afp_dsi_close(AFPObj *obj) 86{ 87 DSI *dsi = obj->handle; 88 sigset_t sigs; 89 90 close(obj->ipc_fd); 91 obj->ipc_fd = -1; 92 93 /* we may have been called from a signal handler caught when afpd was running 94 * as uid 0, that's the wrong user for volume's prexec_close scripts if any, 95 * restore our login user 96 */ 97 if (geteuid() != obj->uid) { 98 if (seteuid( obj->uid ) < 0) { 99 LOG(log_error, logtype_afpd, "can't seteuid(%u) back %s: uid: %u, euid: %u", 100 obj->uid, strerror(errno), getuid(), geteuid()); 101 exit(EXITERR_SYS); 102 } 103 } 104 105 close_all_vol(); 106 107 if (obj->logout) { 108 /* Block sigs, PAM/systemd/whoever might send us a SIG??? in (*obj->logout)() -> pam_close_session() */ 109 sigfillset(&sigs); 110 pthread_sigmask(SIG_BLOCK, &sigs, NULL); 111 (*obj->logout)(); 112 } 113 114 LOG(log_note, logtype_afpd, "AFP statistics: %.2f KB read, %.2f KB written", 115 dsi->read_count/1024.0, dsi->write_count/1024.0); 116 log_dircache_stat(); 117 118 dsi_close(dsi); 119} 120 121/* ------------------------------- 122 * SIGTERM 123 * a little bit of code duplication. 124 */ 125static void afp_dsi_die(int sig) 126{ 127 DSI *dsi = (DSI *)AFPobj->handle; 128 129 if (dsi->flags & DSI_RECONINPROG) { 130 /* Primary reconnect succeeded, got SIGTERM from afpd parent */ 131 dsi->flags &= ~DSI_RECONINPROG; 132 return; /* this returns to afp_disconnect */ 133 } 134 135 if (dsi->flags & DSI_DISCONNECTED) { 136 LOG(log_note, logtype_afpd, "Disconnected session terminating"); 137 exit(0); 138 } 139 140 dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN); 141 afp_dsi_close(AFPobj); 142 if (sig) /* if no signal, assume dieing because logins are disabled & 143 don't log it (maintenance mode)*/ 144 LOG(log_info, logtype_afpd, "Connection terminated"); 145 if (sig == SIGTERM || sig == SIGALRM) { 146 exit( 0 ); 147 } 148 else { 149 exit(sig); 150 } 151} 152 153/* SIGQUIT handler */ 154static void ipc_reconnect_handler(int sig _U_) 155{ 156 DSI *dsi = (DSI *)AFPobj->handle; 157 158 if (reconnect_ipc(AFPobj) != 0) { 159 LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect"); 160 afp_dsi_close(AFPobj); 161 exit(EXITERR_SYS); 162 } 163 164 if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) { 165 LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend"); 166 afp_dsi_close(AFPobj); 167 exit(EXITERR_SYS); 168 } 169 LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done"); 170} 171 172/* SIGURG handler (primary reconnect) */ 173static void afp_dsi_transfer_session(int sig _U_) 174{ 175 uint16_t dsiID; 176 int socket; 177 DSI *dsi = (DSI *)AFPobj->handle; 178 179 LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session"); 180 181 if (readt(AFPobj->ipc_fd, &dsiID, 2, 0, 2) != 2) { 182 LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive DSI id, goodbye"); 183 afp_dsi_close(AFPobj); 184 exit(EXITERR_SYS); 185 } 186 187 if ((socket = recv_fd(AFPobj->ipc_fd, 1)) == -1) { 188 LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive session fd, goodbye"); 189 afp_dsi_close(AFPobj); 190 exit(EXITERR_SYS); 191 } 192 193 LOG(log_debug, logtype_afpd, "afp_dsi_transfer_session: received socket fd: %i", socket); 194 195 dsi->proto_close(dsi); 196 dsi->socket = socket; 197 dsi->flags = DSI_RECONSOCKET; 198 dsi->datalen = 0; 199 dsi->eof = dsi->start = dsi->buffer; 200 dsi->in_write = 0; 201 dsi->header.dsi_requestID = dsiID; 202 dsi->header.dsi_command = DSIFUNC_CMD; 203 204 /* 205 * The session transfer happens in the middle of FPDisconnect old session, thus we 206 * have to send the reply now. 207 */ 208 if (!dsi_cmdreply(dsi, AFP_OK)) { 209 LOG(log_error, logtype_afpd, "dsi_cmdreply: %s", strerror(errno) ); 210 afp_dsi_close(AFPobj); 211 exit(EXITERR_CLNT); 212 } 213 214 LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: succesfull primary reconnect"); 215 /* 216 * Now returning from this signal handler return to dsi_receive which should start 217 * reading/continuing from the connected socket that was passed via the parent from 218 * another session. The parent will terminate that session. 219 */ 220 siglongjmp(recon_jmp, 1); 221} 222 223/* ------------------- */ 224static void afp_dsi_timedown(int sig _U_) 225{ 226 struct sigaction sv; 227 struct itimerval it; 228 DSI *dsi = (DSI *)AFPobj->handle; 229 dsi->flags |= DSI_DIE; 230 /* shutdown and don't reconnect. server going down in 5 minutes. */ 231 setmessage("The server is going down for maintenance."); 232 if (dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT | 233 AFPATTN_MESG | AFPATTN_TIME(5)) < 0) { 234 DSI *dsi = (DSI *)AFPobj->handle; 235 dsi->down_request = 1; 236 } 237 238 it.it_interval.tv_sec = 0; 239 it.it_interval.tv_usec = 0; 240 it.it_value.tv_sec = 300; 241 it.it_value.tv_usec = 0; 242 243 if ( setitimer( ITIMER_REAL, &it, NULL ) < 0 ) { 244 LOG(log_error, logtype_afpd, "afp_timedown: setitimer: %s", strerror(errno) ); 245 afp_dsi_die(EXITERR_SYS); 246 } 247 memset(&sv, 0, sizeof(sv)); 248 sv.sa_handler = afp_dsi_die; 249 sigemptyset( &sv.sa_mask ); 250 sigaddset(&sv.sa_mask, SIGHUP); 251 sigaddset(&sv.sa_mask, SIGTERM); 252 sv.sa_flags = SA_RESTART; 253 if ( sigaction( SIGALRM, &sv, NULL ) < 0 ) { 254 LOG(log_error, logtype_afpd, "afp_timedown: sigaction: %s", strerror(errno) ); 255 afp_dsi_die(EXITERR_SYS); 256 } 257 258 /* ignore myself */ 259 sv.sa_handler = SIG_IGN; 260 sigemptyset( &sv.sa_mask ); 261 sv.sa_flags = SA_RESTART; 262 if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) { 263 LOG(log_error, logtype_afpd, "afp_timedown: sigaction SIGHUP: %s", strerror(errno) ); 264 afp_dsi_die(EXITERR_SYS); 265 } 266} 267 268/* --------------------------------- 269 * SIGHUP reload configuration file 270 */ 271volatile int reload_request = 0; 272 273static void afp_dsi_reload(int sig _U_) 274{ 275 reload_request = 1; 276} 277 278/* --------------------------------- 279 * SIGINT: enable max_debug LOGging 280 */ 281static volatile sig_atomic_t debug_request = 0; 282 283static void afp_dsi_debug(int sig _U_) 284{ 285 debug_request = 1; 286} 287 288/* ---------------------- */ 289static void afp_dsi_getmesg (int sig _U_) 290{ 291 DSI *dsi = (DSI *)AFPobj->handle; 292 293 dsi->msg_request = 1; 294 if (dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5)) < 0) 295 dsi->msg_request = 2; 296} 297 298static void alarm_handler(int sig _U_) 299{ 300 int err; 301 DSI *dsi = (DSI *)AFPobj->handle; 302 303 /* we have to restart the timer because some libraries may use alarm() */ 304 setitimer(ITIMER_REAL, &dsi->timer, NULL); 305 306 /* we got some traffic from the client since the previous timer tick. */ 307 if ((dsi->flags & DSI_DATA)) { 308 dsi->flags &= ~DSI_DATA; 309 return; 310 } 311 312 dsi->tickle++; 313 LOG(log_maxdebug, logtype_afpd, "alarm: tickles: %u, flags: %s|%s|%s|%s|%s|%s|%s|%s|%s", 314 dsi->tickle, 315 (dsi->flags & DSI_DATA) ? "DSI_DATA" : "-", 316 (dsi->flags & DSI_RUNNING) ? "DSI_RUNNING" : "-", 317 (dsi->flags & DSI_SLEEPING) ? "DSI_SLEEPING" : "-", 318 (dsi->flags & DSI_EXTSLEEP) ? "DSI_EXTSLEEP" : "-", 319 (dsi->flags & DSI_DISCONNECTED) ? "DSI_DISCONNECTED" : "-", 320 (dsi->flags & DSI_DIE) ? "DSI_DIE" : "-", 321 (dsi->flags & DSI_NOREPLY) ? "DSI_NOREPLY" : "-", 322 (dsi->flags & DSI_RECONSOCKET) ? "DSI_RECONSOCKET" : "-", 323 (dsi->flags & DSI_RECONINPROG) ? "DSI_RECONINPROG" : "-"); 324 325 if (dsi->flags & DSI_SLEEPING) { 326 if (dsi->tickle > AFPobj->options.sleep) { 327 LOG(log_note, logtype_afpd, "afp_alarm: sleep time ended"); 328 afp_dsi_die(EXITERR_CLNT); 329 } 330 return; 331 } 332 333 if (dsi->flags & DSI_DISCONNECTED) { 334 if (geteuid() == 0) { 335 LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem"); 336 afp_dsi_die(EXITERR_CLNT); 337 } 338 if (dsi->tickle > AFPobj->options.disconnected) { 339 LOG(log_error, logtype_afpd, "afp_alarm: reconnect timer expired, goodbye"); 340 afp_dsi_die(EXITERR_CLNT); 341 } 342 return; 343 } 344 345 /* if we're in the midst of processing something, don't die. */ 346 if (dsi->tickle >= AFPobj->options.timeout) { 347 LOG(log_error, logtype_afpd, "afp_alarm: child timed out, entering disconnected state"); 348 if (dsi_disconnect(dsi) != 0) 349 afp_dsi_die(EXITERR_CLNT); 350 return; 351 } 352 353 if ((err = pollvoltime(AFPobj)) == 0) 354 LOG(log_debug, logtype_afpd, "afp_alarm: sending DSI tickle"); 355 err = dsi_tickle(AFPobj->handle); 356 if (err <= 0) { 357 if (geteuid() == 0) { 358 LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem"); 359 afp_dsi_die(EXITERR_CLNT); 360 } 361 LOG(log_error, logtype_afpd, "afp_alarm: connection problem, entering disconnected state"); 362 if (dsi_disconnect(dsi) != 0) 363 afp_dsi_die(EXITERR_CLNT); 364 } 365} 366 367/* ----------------- 368 if dsi->in_write is set attention, tickle (and close?) msg 369 aren't sent. We don't care about tickle 370*/ 371static void pending_request(DSI *dsi) 372{ 373 /* send pending attention */ 374 375 /* read msg if any, it could be done in afp_getsrvrmesg */ 376 if (dsi->msg_request) { 377 if (dsi->msg_request == 2) { 378 /* didn't send it in signal handler */ 379 dsi_attention(AFPobj->handle, AFPATTN_MESG | AFPATTN_TIME(5)); 380 } 381 dsi->msg_request = 0; 382 readmessage(AFPobj); 383 } 384 if (dsi->down_request) { 385 dsi->down_request = 0; 386 dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT | 387 AFPATTN_MESG | AFPATTN_TIME(5)); 388 } 389} 390 391void afp_over_dsi_sighandlers(AFPObj *obj) 392{ 393 DSI *dsi = (DSI *) obj->handle; 394 struct sigaction action; 395 396 memset(&action, 0, sizeof(action)); 397 sigfillset(&action.sa_mask); 398 action.sa_flags = SA_RESTART; 399 400 /* install SIGHUP */ 401 action.sa_handler = afp_dsi_reload; 402 if ( sigaction( SIGHUP, &action, NULL ) < 0 ) { 403 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 404 afp_dsi_die(EXITERR_SYS); 405 } 406 407 /* install SIGURG */ 408 action.sa_handler = afp_dsi_transfer_session; 409 if ( sigaction( SIGURG, &action, NULL ) < 0 ) { 410 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 411 afp_dsi_die(EXITERR_SYS); 412 } 413 414 /* install SIGTERM */ 415 action.sa_handler = afp_dsi_die; 416 if ( sigaction( SIGTERM, &action, NULL ) < 0 ) { 417 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 418 afp_dsi_die(EXITERR_SYS); 419 } 420 421 /* install SIGQUIT */ 422 action.sa_handler = ipc_reconnect_handler; 423 if ( sigaction(SIGQUIT, &action, NULL ) < 0 ) { 424 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 425 afp_dsi_die(EXITERR_SYS); 426 } 427 428 /* SIGUSR2 - server message support */ 429 action.sa_handler = afp_dsi_getmesg; 430 if ( sigaction( SIGUSR2, &action, NULL) < 0 ) { 431 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 432 afp_dsi_die(EXITERR_SYS); 433 } 434 435 /* SIGUSR1 - set down in 5 minutes */ 436 action.sa_handler = afp_dsi_timedown; 437 action.sa_flags = SA_RESTART; 438 if ( sigaction( SIGUSR1, &action, NULL) < 0 ) { 439 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 440 afp_dsi_die(EXITERR_SYS); 441 } 442 443 /* SIGINT - enable max_debug LOGging to /tmp/afpd.PID.XXXXXX */ 444 action.sa_handler = afp_dsi_debug; 445 if ( sigaction( SIGINT, &action, NULL) < 0 ) { 446 LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); 447 afp_dsi_die(EXITERR_SYS); 448 } 449 450#ifndef DEBUGGING 451 /* SIGALRM - tickle handler */ 452 action.sa_handler = alarm_handler; 453 if ((sigaction(SIGALRM, &action, NULL) < 0) || 454 (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) { 455 afp_dsi_die(EXITERR_SYS); 456 } 457#endif /* DEBUGGING */ 458} 459 460/* ------------------------------------------- 461 afp over dsi. this never returns. 462*/ 463void afp_over_dsi(AFPObj *obj) 464{ 465 DSI *dsi = (DSI *) obj->handle; 466 int rc_idx; 467 u_int32_t err, cmd; 468 u_int8_t function; 469#ifdef WOL 470 time_t now; 471#endif 472 473 AFPobj = obj; 474 obj->exit = afp_dsi_die; 475 obj->reply = (int (*)()) dsi_cmdreply; 476 obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention; 477 dsi->tickle = 0; 478 479 afp_over_dsi_sighandlers(obj); 480 481 if (dircache_init(obj->options.dircachesize) != 0) 482 afp_dsi_die(EXITERR_SYS); 483 484 /* set TCP snd/rcv buf */ 485 if (obj->options.tcp_rcvbuf) { 486 if (setsockopt(dsi->socket, 487 SOL_SOCKET, 488 SO_RCVBUF, 489 &obj->options.tcp_rcvbuf, 490 sizeof(obj->options.tcp_rcvbuf)) != 0) { 491 LOG(log_error, logtype_dsi, "afp_over_dsi: setsockopt(SO_RCVBUF): %s", strerror(errno)); 492 } 493 } 494 if (obj->options.tcp_sndbuf) { 495 if (setsockopt(dsi->socket, 496 SOL_SOCKET, 497 SO_SNDBUF, 498 &obj->options.tcp_sndbuf, 499 sizeof(obj->options.tcp_sndbuf)) != 0) { 500 LOG(log_error, logtype_dsi, "afp_over_dsi: setsockopt(SO_SNDBUF): %s", strerror(errno)); 501 } 502 } 503 504 /* set TCP_NODELAY */ 505 int flag = 1; 506 setsockopt(dsi->socket, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)); 507 508 /* get stuck here until the end */ 509 while (1) { 510 if (sigsetjmp(recon_jmp, 1) != 0) 511 /* returning from SIGALARM handler for a primary reconnect */ 512 continue; 513 514 /* Blocking read on the network socket */ 515 cmd = dsi_stream_receive(dsi); 516 517 if (cmd == 0) { 518 /* cmd == 0 is the error condition */ 519 if (dsi->flags & DSI_RECONSOCKET) { 520 /* we just got a reconnect so we immediately try again to receive on the new fd */ 521 dsi->flags &= ~DSI_RECONSOCKET; 522 continue; 523 } 524 525 /* the client sometimes logs out (afp_logout) but doesn't close the DSI session */ 526 if (dsi->flags & DSI_AFP_LOGGED_OUT) { 527 LOG(log_note, logtype_afpd, "afp_over_dsi: client logged out, terminating DSI session"); 528 afp_dsi_close(obj); 529 exit(0); 530 } 531 532#if 0 533 /* got ECONNRESET in read from client => exit*/ 534 if (dsi->flags & DSI_GOT_ECONNRESET) { 535 LOG(log_note, logtype_afpd, "afp_over_dsi: client connection reset"); 536 afp_dsi_close(obj); 537 exit(0); 538 } 539#endif 540 541 if (dsi->flags & DSI_RECONINPROG) { 542 LOG(log_note, logtype_afpd, "afp_over_dsi: failed reconnect"); 543 afp_dsi_close(obj); 544 exit(0); 545 } 546 547 /* Some error on the client connection, enter disconnected state */ 548 if (dsi_disconnect(dsi) != 0) 549 afp_dsi_die(EXITERR_CLNT); 550 551 while (dsi->flags & DSI_DISCONNECTED) 552 pause(); /* gets interrupted by SIGALARM or SIGURG tickle */ 553 continue; /* continue receiving until disconnect timer expires 554 * or a primary reconnect succeeds */ 555 } 556 557 if (!(dsi->flags & DSI_EXTSLEEP) && (dsi->flags & DSI_SLEEPING)) { 558 LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep"); 559 dsi->flags &= ~DSI_SLEEPING; 560 dsi->tickle = 0; 561 } 562 563 if (reload_request) { 564 reload_request = 0; 565 load_volumes(AFPobj); 566 } 567 568 /* The first SIGINT enables debugging, the next restores the config */ 569 if (debug_request) { 570 static int debugging = 0; 571 debug_request = 0; 572 573 dircache_dump(); 574 uuidcache_dump(); 575 576 if (debugging) { 577 if (obj->options.logconfig) 578 setuplog(obj->options.logconfig); 579 else 580 setuplog("default log_note"); 581 debugging = 0; 582 } else { 583 char logstr[50]; 584 debugging = 1; 585 sprintf(logstr, "default log_maxdebug /tmp/afpd.%u.XXXXXX", getpid()); 586 setuplog(logstr); 587 } 588 } 589 590 591 dsi->flags |= DSI_DATA; 592 dsi->tickle = 0; 593 594 switch(cmd) { 595 596 case DSIFUNC_CLOSE: 597 LOG(log_debug, logtype_afpd, "DSI: close session request"); 598 afp_dsi_close(obj); 599 LOG(log_note, logtype_afpd, "done"); 600 exit(0); 601 602 case DSIFUNC_TICKLE: 603 dsi->flags &= ~DSI_DATA; /* thats no data in the sense we use it in alarm_handler */ 604 LOG(log_debug, logtype_afpd, "DSI: client tickle"); 605 /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */ 606 if ((dsi->flags & DSI_DIE)) 607 dsi_tickle(dsi); 608 break; 609 610 case DSIFUNC_CMD: 611#ifdef AFS 612 if ( writtenfork ) { 613 if ( flushfork( writtenfork ) < 0 ) { 614 LOG(log_error, logtype_afpd, "main flushfork: %s", strerror(errno) ); 615 } 616 writtenfork = NULL; 617 } 618#endif /* AFS */ 619 620 function = (u_char) dsi->commands[0]; 621 622 /* AFP replay cache */ 623 rc_idx = dsi->clientID % REPLAYCACHE_SIZE; 624 LOG(log_debug, logtype_dsi, "DSI request ID: %u", dsi->clientID); 625 626 if (replaycache[rc_idx].DSIreqID == dsi->clientID 627 && replaycache[rc_idx].AFPcommand == function) { 628 LOG(log_note, logtype_afpd, "AFP Replay Cache match: id: %u / cmd: %s", 629 dsi->clientID, AfpNum2name(function)); 630 err = replaycache[rc_idx].result; 631 /* AFP replay cache end */ 632 } else { 633 /* send off an afp command. in a couple cases, we take advantage 634 * of the fact that we're a stream-based protocol. */ 635 if (afp_switch[function]) { 636 dsi->datalen = DSI_DATASIZ; 637 dsi->flags |= DSI_RUNNING; 638 639 LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function)); 640 641 err = (*afp_switch[function])(obj, 642 (char *)&dsi->commands, dsi->cmdlen, 643 (char *)&dsi->data, &dsi->datalen); 644 645 LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s", 646 AfpNum2name(function), AfpErr2name(err)); 647 648 dir_free_invalid_q(); 649 650#ifdef FORCE_UIDGID 651 /* bring everything back to old euid, egid */ 652 if (obj->force_uid) 653 restore_uidgid ( &obj->uidgid ); 654#endif /* FORCE_UIDGID */ 655 dsi->flags &= ~DSI_RUNNING; 656 657 /* Add result to the AFP replay cache */ 658 replaycache[rc_idx].DSIreqID = dsi->clientID; 659 replaycache[rc_idx].AFPcommand = function; 660 replaycache[rc_idx].result = err; 661 } else { 662 LOG(log_error, logtype_afpd, "bad function %X", function); 663 dsi->datalen = 0; 664 err = AFPERR_NOOP; 665 } 666 } 667 668 /* single shot toggle that gets set by dsi_readinit. */ 669 if (dsi->flags & DSI_NOREPLY) { 670 dsi->flags &= ~DSI_NOREPLY; 671 break; 672 } else if (!dsi_cmdreply(dsi, err)) { 673 LOG(log_error, logtype_afpd, "dsi_cmdreply(%d): %s", dsi->socket, strerror(errno) ); 674 if (dsi_disconnect(dsi) != 0) 675 afp_dsi_die(EXITERR_CLNT); 676 } 677 break; 678 679 case DSIFUNC_WRITE: /* FPWrite and FPAddIcon */ 680 function = (u_char) dsi->commands[0]; 681 if ( afp_switch[ function ] != NULL ) { 682 dsi->datalen = DSI_DATASIZ; 683 dsi->flags |= DSI_RUNNING; 684 685 LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function)); 686 687 err = (*afp_switch[function])(obj, 688 (char *)&dsi->commands, dsi->cmdlen, 689 (char *)&dsi->data, &dsi->datalen); 690 691 LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s", 692 AfpNum2name(function), AfpErr2name(err)); 693 694#ifdef WOL 695 time(&now); 696 if(difftime(now,last_wol)>= WOL_INTERVAL) 697 { 698 system("wol"); 699 last_wol=now; 700 } 701 702#endif 703 dsi->flags &= ~DSI_RUNNING; 704#ifdef FORCE_UIDGID 705 /* bring everything back to old euid, egid */ 706 if (obj->force_uid) 707 restore_uidgid ( &obj->uidgid ); 708#endif /* FORCE_UIDGID */ 709 } else { 710 LOG(log_error, logtype_afpd, "(write) bad function %x", function); 711 dsi->datalen = 0; 712 err = AFPERR_NOOP; 713 } 714 715 if (!dsi_wrtreply(dsi, err)) { 716 LOG(log_error, logtype_afpd, "dsi_wrtreply: %s", strerror(errno) ); 717 if (dsi_disconnect(dsi) != 0) 718 afp_dsi_die(EXITERR_CLNT); 719 } 720 break; 721 722 case DSIFUNC_ATTN: /* attention replies */ 723 break; 724 725 /* error. this usually implies a mismatch of some kind 726 * between server and client. if things are correct, 727 * we need to flush the rest of the packet if necessary. */ 728 default: 729 LOG(log_info, logtype_afpd,"afp_dsi: spurious command %d", cmd); 730 dsi_writeinit(dsi, dsi->data, DSI_DATASIZ); 731 dsi_writeflush(dsi); 732 break; 733 } 734 pending_request(dsi); 735 736 fce_pending_events(obj); 737 } 738 739 /* error */ 740 afp_dsi_die(EXITERR_CLNT); 741} 742