/* * Handle initial connection protocol. */ static int tftp(struct testcase *test, struct tftphdr *tp, int size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; /* store input protocol */ fprintf(test->server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(test->server, "filename: %s\n", filename); for (cp = mode; *cp; cp++) if (isupper((int)*cp)) *cp = tolower((int)*cp); /* store input protocol */ fprintf(test->server, "mode: %s\n", mode); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } if (tp->th_opcode == WRQ) recvtftp(test, pf); else sendtftp(test, pf); return 0; }
/* * WRQ - receive a file from the client */ void tftp_wrq(int peer, char *recvbuffer, ssize_t size) { char *cp; int has_options = 0, ecode; char *filename, *mode; char fnbuf[PATH_MAX]; cp = parse_header(peer, recvbuffer, size, &filename, &mode); size -= (cp - recvbuffer) + 1; strlcpy(fnbuf, filename, sizeof(fnbuf)); reduce_path(fnbuf); filename = fnbuf; if (size > 0) { if (options_rfc_enabled) has_options = !parse_options(peer, cp, size); else tftp_log(LOG_INFO, "Options found but not enabled"); } ecode = validate_access(peer, &filename, WRQ); if (ecode == 0) { if (has_options) send_oack(peer); else send_ack(peer, 0); } if (logging) { tftp_log(LOG_INFO, "%s: write request for %s: %s", peername, filename, errtomsg(ecode)); } if (ecode) { send_error(peer, ecode); exit(1); } tftp_recvfile(peer, mode); exit(0); }
/* * Handle initial connection protocol. */ static int tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = ERRNO; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); fclose(server); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for (cp = mode; cp && *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fprintf(server, "mode: %s\n", mode); fclose(server); for (pf = formata; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } if (tp->th_opcode == opcode_WRQ) recvtftp(test, pf); else sendtftp(test, pf); return 0; }
int serv_loop() { int cs, ss = 0; struct sockaddr_storage cl; fd_set readable; int i, n, len; char cl_addr[NI_MAXHOST]; char cl_name[NI_MAXHOST]; int error; pid_t pid; #ifdef USE_THREAD if (threading) { blocksignal(SIGHUP); blocksignal(SIGINT); blocksignal(SIGUSR1); } #endif for (;;) { readable = allsock; MUTEX_LOCK(mutex_select); n = select(maxsock+1, &readable, 0, 0, 0); if (n <= 0) { if (n < 0 && errno != EINTR) { msg_out(warn, "select: %m"); } MUTEX_UNLOCK(mutex_select); continue; } #ifdef USE_THREAD if ( ! threading ) { #endif /* handle any queued signal flags */ if (FD_ISSET(sig_queue[0], &readable)) { if (ioctl(sig_queue[0], FIONREAD, &i) != 0) { msg_out(crit, "ioctl: %m"); exit(-1); } while (--i >= 0) { char c; if (read(sig_queue[0], &c, 1) != 1) { msg_out(crit, "read: %m"); exit(-1); } switch(c) { case 'H': /* sighup */ reload(); break; case 'C': /* sigchld */ reapchild(); break; case 'T': /* sigterm */ cleanup(); break; default: break; } } } #ifdef USE_THREAD } #endif for ( i = 0; i < serv_sock_ind; i++ ) { if (FD_ISSET(serv_sock[i], &readable)) { n--; break; } } if ( n < 0 || i >= serv_sock_ind ) { MUTEX_UNLOCK(mutex_select); continue; } len = sizeof(struct sockaddr_storage); cs = accept(serv_sock[i], (struct sockaddr *)&cl, (socklen_t *)&len); if (cs < 0) { if (errno == EINTR #ifdef SOLARIS || errno == EPROTO #endif || errno == EWOULDBLOCK || errno == ECONNABORTED) { ; /* ignore */ } else { /* real accept error */ msg_out(warn, "accept: %m"); } MUTEX_UNLOCK(mutex_select); continue; } MUTEX_UNLOCK(mutex_select); #ifdef USE_THREAD if ( !threading ) { #endif if (max_child > 0 && cur_child >= max_child) { msg_out(warn, "child: cur %d; exeedeing max(%d)", cur_child, max_child); close(cs); continue; } #ifdef USE_THREAD } #endif error = getnameinfo((struct sockaddr *)&cl, len, cl_addr, sizeof(cl_addr), NULL, 0, NI_NUMERICHOST); if (resolv_client) { error = getnameinfo((struct sockaddr *)&cl, len, cl_name, sizeof(cl_name), NULL, 0, 0); msg_out(norm, "%s[%s] connected", cl_name, cl_addr); } else { msg_out(norm, "%s connected", cl_addr); strncpy(cl_name, cl_addr, sizeof(cl_name)); } i = validate_access(cl_addr, cl_name); if (i < 1) { /* access denied */ close(cs); continue; } set_blocking(cs); #ifdef USE_THREAD if (!threading ) { #endif blocksignal(SIGHUP); blocksignal(SIGCHLD); pid = fork(); switch (pid) { case -1: /* fork child failed */ printf("\nfork failed\n"); break; case 0: /* i am child */ for ( i = 0; i < serv_sock_ind; i++ ) { close(serv_sock[i]); } setsignal(SIGCHLD, SIG_DFL); setsignal(SIGHUP, SIG_DFL); releasesignal(SIGCHLD); releasesignal(SIGHUP); ss = proto_socks(cs); if ( ss == -1 ) { close(cs); /* may already be closed */ exit(1); } printf("\nrelaying\n"); relay(cs, ss); exit(0); default: /* may be parent */ printf("\nadding proc\n"); proclist_add(pid); break; } close(cs); releasesignal(SIGHUP); releasesignal(SIGCHLD); #ifdef USE_THREAD } else { ss = proto_socks(cs); if ( ss == -1 ) { close(cs); /* may already be closed */ continue; } relay(cs, ss); } #endif } }
/* Handle initial connection protocol */ void tftp( Client *cl ) { struct tftphdr *tp; char *cp, *cp2, *ep; int ecode; char *mode; char file[MAXPATHLEN]; tp = cl->tp; tp->th_opcode = ntohs((u_short)tp->th_opcode); if (tp->th_opcode != RRQ) { // nak( cl, EBADOP ); return; } errstr = NULL; cp = (char *)&tp->th_block; ep = (char *)cl->tp + cl->tpcc; if ( (ep - cp) > MAXPATHLEN ) { stats.badfilename++; nak( cl, EBADOP ); return; } if ( *cp == '/' ) { cp++; } /* Extract filename */ cp2 = file; while (cp < ep && *cp != '\0') *cp2++ = *cp++; if (cp >= ep) { ++stats.badfilename; nak(cl, EBADOP); return; } *cp2 = '\0'; ++cp; /* Make sure mode is in packet */ mode = cp; while (cp < ep && *cp != '\0') cp++; if (cp >= ep) { stats.badfilemode++; nak( cl, EBADOP ); return; } if (strcasecmp(mode, "octet") != 0) { stats.badfilemode++; nak( cl, EBADOP ); return; } ecode = validate_access( cl, file ); if (ecode) { my_syslog( MLOG_TFTP, "%s %s \"%s\" DENIED (%s)", inet_ntoa(cl->sin.sin_addr), tp->th_opcode == WRQ ? "write" : "read", file, errstr != NULL ? errstr : errtomsg(ecode)); cl->proc = CP_DONE; return; } if (cl->dynam == 0) my_TFTPlog( file, cl->sin.sin_addr.s_addr ); /* my_syslog( MLOG_TFTP, "%s-%s req for \"%s\" from %s", tp->th_opcode == WRQ ? "write" : "read", mode, file, inet_ntoa(cl->sin.sin_addr)); */ cl->state = ST_INIT; cl->tp = NULL; cl->tpcc = 0; cl->proc = CP_SENDFILE; // sendfile( cl ); }
/* * Handle initial connection protocol. */ static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; #ifdef USE_WINSOCK DWORD recvtimeout, recvtimeoutbak; #endif char *option = (char *)"mode"; /* mode is implicit */ int toggle = 1; /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = errno; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; do { bool endofit = true; while(cp < &buf.storage[size]) { if(*cp == '\0') { endofit = false; break; } cp++; } if(endofit) /* no more options */ break; /* before increasing pointer, make sure it is still within the legal space */ if((cp+1) < &buf.storage[size]) { ++cp; if(first) { /* store the mode since we need it later */ mode = cp; first = 0; } if(toggle) /* name/value pair: */ fprintf(server, "%s: %s\n", option, cp); else { /* store the name pointer */ option = cp; } toggle ^= 1; } else /* No more options */ break; } while(1); if(*cp) { nak(EBADOP); fclose(server); return 3; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for(cp = mode; cp && *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fclose(server); for(pf = formata; pf->f_mode; pf++) if(strcmp(pf->f_mode, mode) == 0) break; if(!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if(ecode) { nak(ecode); return 1; } #ifdef USE_WINSOCK recvtimeout = sizeof(recvtimeoutbak); getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (char*)&recvtimeoutbak, (int*)&recvtimeout); recvtimeout = TIMEOUT*1000; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif if(tp->th_opcode == opcode_WRQ) recvtftp(test, pf); else sendtftp(test, pf); #ifdef USE_WINSOCK recvtimeout = recvtimeoutbak; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif return 0; }
int serv_loop() { SOCKS_STATE state; SOCK_INFO si; CL_INFO client; int cs; fd_set readable; int i, n, len; int error; pid_t pid; memset(&state, 0, sizeof(state)); memset(&si, 0, sizeof(si)); memset(&client, 0, sizeof(client)); state.si = &si; #ifdef USE_THREAD if (threading) { blocksignal(SIGHUP); blocksignal(SIGINT); blocksignal(SIGUSR1); } #endif for (;;) { readable = allsock; MUTEX_LOCK(mutex_select); n = select(maxsock+1, &readable, 0, 0, 0); if (n <= 0) { if (n < 0 && errno != EINTR) { msg_out(warn, "select: %m"); } MUTEX_UNLOCK(mutex_select); continue; } #ifdef USE_THREAD if ( ! threading ) { #endif /* handle any queued signal flags */ if (FD_ISSET(sig_queue[0], &readable)) { if (ioctl(sig_queue[0], FIONREAD, &i) != 0) { msg_out(crit, "ioctl: %m"); exit(-1); } while (--i >= 0) { char c; if (read(sig_queue[0], &c, 1) != 1) { msg_out(crit, "read: %m"); exit(-1); } switch(c) { case 'H': /* sighup */ reload(); break; case 'C': /* sigchld */ reapchild(); break; case 'T': /* sigterm */ cleanup(); break; default: break; } } } #ifdef USE_THREAD } #endif for ( i = 0; i < serv_sock_ind; i++ ) { if (FD_ISSET(serv_sock[i], &readable)) { n--; break; } } if ( n < 0 || i >= serv_sock_ind ) { MUTEX_UNLOCK(mutex_select); continue; } len = SS_LEN; cs = accept(serv_sock[i], &si.prc.addr.sa, (socklen_t *)&len); si.prc.len = len; if (cs < 0) { if (errno == EINTR #ifdef SOLARIS || errno == EPROTO #endif || errno == EWOULDBLOCK || errno == ECONNABORTED) { ; /* ignore */ } else { /* real accept error */ msg_out(warn, "accept: %m"); } MUTEX_UNLOCK(mutex_select); continue; } MUTEX_UNLOCK(mutex_select); #ifdef USE_THREAD if ( !threading ) { #endif if (max_child > 0 && cur_child >= max_child) { msg_out(warn, "child: cur %d; exeedeing max(%d)", cur_child, max_child); close(cs); continue; } #ifdef USE_THREAD } #endif /* get downstream-side socket name */ len = SS_LEN; getsockname(cs, &si.myc.addr.sa, (socklen_t *)&len); si.myc.len = len; error = getnameinfo(&si.prc.addr.sa, si.prc.len, client.addr, sizeof(client.addr), NULL, 0, NI_NUMERICHOST); if (resolv_client) { error = getnameinfo(&si.prc.addr.sa, si.prc.len, client.name, sizeof(client.name), NULL, 0, 0); msg_out(norm, "%s[%s] connected", client.name, client.addr); } else { msg_out(norm, "%s connected", client.addr); strncpy(client.name, client.addr, sizeof(client.name)); } i = validate_access(&client); if (i < 1) { /* access denied */ close(cs); continue; } set_blocking(cs); state.s = cs; #ifdef USE_THREAD if (!threading ) { #endif blocksignal(SIGHUP); blocksignal(SIGCHLD); pid = fork(); switch (pid) { case -1: /* fork child failed */ break; case 0: /* i am child */ for ( i = 0; i < serv_sock_ind; i++ ) { close(serv_sock[i]); } setsignal(SIGCHLD, SIG_DFL); setsignal(SIGHUP, SIG_DFL); releasesignal(SIGCHLD); releasesignal(SIGHUP); error = proto_socks(&state); if ( error == -1 ) { close(state.s); /* may already be closed */ exit(1); } relay(&state); exit(0); default: /* may be parent */ proclist_add(pid); break; } close(state.s); releasesignal(SIGHUP); releasesignal(SIGCHLD); #ifdef USE_THREAD } else { error = proto_socks(&state); if ( error == -1 ) { close(state.s); /* may already be closed */ /* udp may be dynamically allocated */ if (state.sr.udp != NULL) free(state.sr.udp); continue; } relay(&state); } #endif } }
/* * RRQ - send a file to the client */ void tftp_rrq(int peer, char *recvbuffer, ssize_t size) { char *cp; int has_options = 0, ecode; char *filename, *mode; char fnbuf[PATH_MAX]; cp = parse_header(peer, recvbuffer, size, &filename, &mode); size -= (cp - recvbuffer) + 1; strcpy(fnbuf, filename); reduce_path(fnbuf); filename = fnbuf; if (size > 0) { if (options_rfc_enabled) has_options = !parse_options(peer, cp, size); else tftp_log(LOG_INFO, "Options found but not enabled"); } ecode = validate_access(peer, &filename, RRQ); if (ecode == 0) { if (has_options) { int n; char lrecvbuffer[MAXPKTSIZE]; struct tftphdr *rp = (struct tftphdr *)lrecvbuffer; send_oack(peer); n = receive_packet(peer, lrecvbuffer, MAXPKTSIZE, NULL, timeoutpacket); if (n < 0) { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Aborting: %s", rp_strerror(n)); return; } if (rp->th_opcode != ACK) { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Expected ACK, got %s on OACK", packettype(rp->th_opcode)); return; } } } if (logging) tftp_log(LOG_INFO, "%s: read request for %s: %s", peername, filename, errtomsg(ecode)); if (ecode) { /* * Avoid storms of naks to a RRQ broadcast for a relative * bootfile pathname from a diskless Sun. */ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) exit(0); send_error(peer, ecode); exit(1); } tftp_xmitfile(peer, mode); }
/* * Handle initial connection protocol. */ static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; #ifdef USE_WINSOCK DWORD recvtimeout, recvtimeoutbak; #endif /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = errno; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; again: while (cp < &buf.storage[size]) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); fclose(server); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for (cp = mode; cp && *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fprintf(server, "mode: %s\n", mode); fclose(server); for (pf = formata; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } #ifdef USE_WINSOCK recvtimeout = sizeof(recvtimeoutbak); getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (char*)&recvtimeoutbak, (int*)&recvtimeout); recvtimeout = TIMEOUT*1000; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif if (tp->th_opcode == opcode_WRQ) recvtftp(test, pf); else sendtftp(test, pf); #ifdef USE_WINSOCK recvtimeout = recvtimeoutbak; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif return 0; }