/* figure out how much data we have. do a couple checks for 0 * data */ header = ntohl(dsi->header.dsi_code); dsi->datasize = header ? ntohl(dsi->header.dsi_len) - header : 0; if (dsi->datasize > 0) { len = MIN(sizeof(dsi->commands) - header, dsi->datasize); /* write last part of command buffer into buf */ memcpy(buf, dsi->commands + header, len); // (4) buffer overflow /* .. */
/* protocol specific open/close, send/receive * send/receive fill in the header and use dsi->commands. * write/read just write/read data */ pid_t (*proto_open)(struct DSI *); void (*proto_close)(struct DSI *); /* ... */ } DSI;
voidafp_over_dsi(AFPObj *obj) { /* ... */ /* get stuck here until the end */ while (1) { /* Blocking read on the network socket */ cmd = dsi_stream_receive(dsi); // (1) if (cmd == 0) { /* 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 (dsi->flags & DSI_RECONINPROG) { LOG(log_note, logtype_afpd, "afp_over_dsi: failed reconnect"); afp_dsi_close(obj); exit(0); } 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); } /* ... */
voiddsi_close(DSI *dsi) { /* server generated. need to set all the fields. */ if (!(dsi->flags & DSI_SLEEPING) && !(dsi->flags & DSI_DISCONNECTED)) { dsi->header.dsi_flags = DSIFL_REQUEST; dsi->header.dsi_command = DSIFUNC_CLOSE; dsi->header.dsi_requestID = htons(dsi_serverID(dsi)); dsi->header.dsi_code = dsi->header.dsi_reserved = htonl(0); dsi->cmdlen = 0; dsi_send(dsi); dsi->proto_close(dsi); // hijack control flow /* ... */