forked from mirrors/tftp-hpa-google
		
	- Fix bug in the handling of timeouts.
- Add support for \U..\E and \L..\E. - Add support for inverse rules.
This commit is contained in:
		
							parent
							
								
									bc8e3b32ee
								
							
						
					
					
						commit
						17b5188b65
					
				
					 4 changed files with 101 additions and 17 deletions
				
			
		
							
								
								
									
										7
									
								
								CHANGES
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								CHANGES
									
										
									
									
									
								
							|  | @ -1,5 +1,12 @@ | |||
| $Id$ | ||||
| 
 | ||||
| Changes in 0.39: | ||||
| 	Support Perl-style \U...\E and \L...\E, as well as allow | ||||
| 	matching rules to be inverted (execute if rule *doesn't* | ||||
| 	match.) | ||||
| 
 | ||||
| 	Fix a timeout bug. | ||||
| 
 | ||||
| Changes in 0.38: | ||||
| 	Portability fixes. | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| /* $Id$ */ | ||||
| /* ----------------------------------------------------------------------- *
 | ||||
|  *    | ||||
|  *   Copyright 2001-2002 H. Peter Anvin - All Rights Reserved | ||||
|  *   Copyright 2001-2004 H. Peter Anvin - All Rights Reserved | ||||
|  * | ||||
|  *   This program is free software available under the same license | ||||
|  *   as the "OpenBSD" operating system, distributed at | ||||
|  | @ -33,6 +33,7 @@ | |||
| #define RULE_ABORT	0x10	/* Terminate processing with an error */ | ||||
| #define RULE_GETONLY	0x20	/* Applicable to GET only */ | ||||
| #define RULE_PUTONLY	0x40	/* Applicable to PUT only */ | ||||
| #define RULE_INVERSE	0x80	/* Execute if regex *doesn't* match */ | ||||
| 
 | ||||
| struct rule { | ||||
|   struct rule *next; | ||||
|  | @ -42,12 +43,28 @@ struct rule { | |||
|   const char *pattern; | ||||
| }; | ||||
| 
 | ||||
| static int xform_null(int c) | ||||
| { | ||||
|   return c; | ||||
| } | ||||
| 
 | ||||
| static int xform_toupper(int c) | ||||
| { | ||||
|   return toupper(c); | ||||
| } | ||||
| 
 | ||||
| static int xform_tolower(int c) | ||||
| { | ||||
|   return tolower(c); | ||||
| } | ||||
| 
 | ||||
| /* Do \-substitution.  Call with string == NULL to get length only. */ | ||||
| static int genmatchstring(char *string, const char *pattern, const char *input, | ||||
| 			  const regmatch_t *pmatch, match_pattern_callback macrosub) | ||||
| { | ||||
|   int (*xform)(int) = xform_null; | ||||
|   int len = 0; | ||||
|   int n, mlen; | ||||
|   int n, mlen, sublen; | ||||
|   int endbytes; | ||||
| 
 | ||||
|   /* Get section before match; note pmatch[0] is the whole match */ | ||||
|  | @ -60,9 +77,13 @@ static int genmatchstring(char *string, const char *pattern, const char *input, | |||
| 
 | ||||
|   /* Transform matched section */ | ||||
|   while ( *pattern ) { | ||||
|     mlen = 0; | ||||
| 
 | ||||
|     if ( *pattern == '\\' && pattern[1] != '\0' ) { | ||||
|       char macro = pattern[1]; | ||||
|       if ( macro >= '0' && macro <= '9' ) { | ||||
|       switch ( macro ) { | ||||
|       case '0': case '1': case '2': case '3': case '4': | ||||
|       case '5': case '6': case '7': case '8': case '9': | ||||
| 	n = pattern[1] - '0'; | ||||
| 	 | ||||
| 	if ( pmatch[n].rm_so != -1 ) { | ||||
|  | @ -73,24 +94,41 @@ static int genmatchstring(char *string, const char *pattern, const char *input, | |||
| 	    string += mlen; | ||||
| 	  } | ||||
| 	} | ||||
|       } else { | ||||
| 	int sublen; | ||||
| 	break; | ||||
| 
 | ||||
|       case 'L': | ||||
| 	xform = xform_tolower; | ||||
| 	break; | ||||
| 
 | ||||
|       case 'U': | ||||
| 	xform = xform_toupper; | ||||
| 	break; | ||||
| 
 | ||||
|       case 'E': | ||||
| 	xform = xform_null; | ||||
| 	break; | ||||
| 
 | ||||
|       default: | ||||
| 	if ( macrosub && | ||||
| 	     (sublen = macrosub(macro, string)) >= 0 ) { | ||||
| 	  len += sublen; | ||||
| 	  if ( string ) | ||||
| 	    string += sublen; | ||||
| 	  while ( sublen-- ) { | ||||
| 	    len++; | ||||
| 	    if ( string ) { | ||||
| 	      *string = xform(*string); | ||||
| 	      string++; | ||||
| 	    } | ||||
| 	  } | ||||
| 	} else { | ||||
| 	  len++; | ||||
| 	  if ( string ) | ||||
| 	    *string++ = pattern[1]; | ||||
| 	    *string++ = xform(pattern[1]); | ||||
| 	} | ||||
|       } | ||||
|       pattern += 2; | ||||
|     } else { | ||||
|       len++; | ||||
|       if ( string ) | ||||
| 	*string++ = *pattern; | ||||
| 	*string++ = xform(*pattern); | ||||
|       pattern++; | ||||
|     } | ||||
|   } | ||||
|  | @ -181,6 +219,9 @@ static int parseline(char *line, struct rule *r, int lineno) | |||
|     case 'P': | ||||
|       r->rule_flags |= RULE_PUTONLY; | ||||
|       break; | ||||
|     case '~': | ||||
|       r->rule_flags |= RULE_INVERSE; | ||||
|       break; | ||||
|     default: | ||||
|       syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"", | ||||
| 	     buffer, lineno, *p); | ||||
|  | @ -193,6 +234,11 @@ static int parseline(char *line, struct rule *r, int lineno) | |||
|   if ( !(r->rule_flags & RULE_REWRITE) ) | ||||
|     r->rule_flags &= ~RULE_GLOBAL; | ||||
| 
 | ||||
|   if ( r->rule_flags & (RULE_INVERSE|RULE_REWRITE) ) { | ||||
|     syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line); | ||||
|     return -1;			/* Error */ | ||||
|   } | ||||
| 
 | ||||
|   /* Read and compile the regex */ | ||||
|   if ( !readescstring(buffer, &line) ) { | ||||
|     syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line); | ||||
|  | @ -303,10 +349,18 @@ char *rewrite_string(const char *input, const struct rule *rules, | |||
|     } | ||||
| 
 | ||||
|     do { | ||||
|       if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) == 0 ) { | ||||
|       if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) == | ||||
| 	   (ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0) ) { | ||||
| 	/* Match on this rule */ | ||||
| 	was_match = 1; | ||||
| 
 | ||||
| 	if ( ruleptr->rule_flags & RULE_INVERSE ) { | ||||
| 	  /* No actual match, so clear out the pmatch array */ | ||||
| 	  int i; | ||||
| 	  for ( i = 0 ; i < 10 ; i++ ) | ||||
| 	    pmatch[i].rm_so = pmatch[i].rm_eo = -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if ( ruleptr->rule_flags & RULE_ABORT ) { | ||||
| 	  if ( verbosity >= 3 ) { | ||||
| 	    syslog(LOG_INFO, "remap: rule %d: abort: %s", | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ | |||
| .\" SUCH DAMAGE. | ||||
| .\" | ||||
| .\"----------------------------------------------------------------------- */ | ||||
| .TH TFTPD 8 "23 October 2002" "tftp-hpa @@VERSION@@" "System Manager's Manual" | ||||
| .TH TFTPD 8 "3 September 2004" "tftp-hpa @@VERSION@@" "System Manager's Manual" | ||||
| .SH NAME | ||||
| .B tftpd | ||||
| \- IPv4 Trivial File Transfer Protocol server | ||||
|  | @ -261,6 +261,15 @@ This rule applies to GET (RRQ) requests only. | |||
| .TP | ||||
| .B P | ||||
| This rule applies to PUT (WRQ) requests only. | ||||
| .TP | ||||
| .B ~ | ||||
| Inverse the sense of this rule, i.e. execute the | ||||
| .I operation | ||||
| only if the | ||||
| .I regex | ||||
| .I doesn't | ||||
| match.  Cannot used together with  | ||||
| .BR r . | ||||
| .PP | ||||
| The following escape sequences are recognized as part of the | ||||
| .IR "replacement pattern" : | ||||
|  | @ -289,8 +298,17 @@ Literal backslash. | |||
| \fB\\\fP\fIwhitespace\fP | ||||
| Literal whitespace. | ||||
| .TP | ||||
| \fB\\#\fI | ||||
| \fB\\#\fP | ||||
| Literal hash mark. | ||||
| .TP | ||||
| \fB\\U\fP | ||||
| Turns all subsequent letters to upper case. | ||||
| .TP | ||||
| \fB\\L\fP | ||||
| Turns all subsequent letters to lower case. | ||||
| .TP | ||||
| \fB\\E\fP | ||||
| Cancels the effect of \fB\\U\fP or \fB\\L\fP. | ||||
| .PP | ||||
| If the mapping file is changed, you need to send | ||||
| .B SIGHUP | ||||
|  |  | |||
|  | @ -1180,18 +1180,20 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) | |||
|   struct tftphdr *ap;		/* ack packet */ | ||||
|   static u_short block = 1;	/* Static to avoid longjmp funnies */ | ||||
|   u_short ap_opcode, ap_block; | ||||
|   unsigned long r_timeout; | ||||
|   int size, n; | ||||
|    | ||||
|   if (oap) { | ||||
|     timeout = rexmtval; | ||||
|     (void)sigsetjmp(timeoutbuf,1); | ||||
|   oack: | ||||
|     r_timeout = timeout; | ||||
|     if (send(peer, oap, oacklen, 0) != oacklen) { | ||||
|       syslog(LOG_WARNING, "tftpd: oack: %m\n"); | ||||
|       goto abort; | ||||
|     } | ||||
|     for ( ; ; ) { | ||||
|       n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &timeout); | ||||
|       n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); | ||||
|       if (n < 0) { | ||||
| 	syslog(LOG_WARNING, "tftpd: read: %m\n"); | ||||
| 	goto abort; | ||||
|  | @ -1226,13 +1228,14 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) | |||
|     timeout = rexmtval; | ||||
|     (void) sigsetjmp(timeoutbuf,1); | ||||
|      | ||||
|     r_timeout = timeout; | ||||
|     if (send(peer, dp, size + 4, 0) != size + 4) { | ||||
|       syslog(LOG_WARNING, "tftpd: write: %m"); | ||||
|       goto abort; | ||||
|     } | ||||
|     read_ahead(file, pf->f_convert); | ||||
|     for ( ; ; ) { | ||||
|       n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &timeout); | ||||
|       n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &r_timeout); | ||||
|       if (n < 0) { | ||||
| 	syslog(LOG_WARNING, "tftpd: read(ack): %m"); | ||||
| 	goto abort; | ||||
|  | @ -1286,6 +1289,7 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) | |||
|   static u_short block = 0; | ||||
|   static int acksize; | ||||
|   u_short dp_opcode, dp_block; | ||||
|   unsigned long r_timeout; | ||||
| 
 | ||||
|   dp = w_init(); | ||||
|   do { | ||||
|  | @ -1303,13 +1307,14 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) | |||
|     block++; | ||||
|     (void) sigsetjmp(timeoutbuf,1); | ||||
|   send_ack: | ||||
|     r_timeout = timeout; | ||||
|     if (send(peer, ackbuf, acksize, 0) != acksize) { | ||||
|       syslog(LOG_WARNING, "tftpd: write(ack): %m"); | ||||
|       goto abort; | ||||
|     } | ||||
|     write_behind(file, pf->f_convert); | ||||
|     for ( ; ; ) { | ||||
|       n = recv_time(peer, dp, PKTSIZE, 0, &timeout); | ||||
|       n = recv_time(peer, dp, PKTSIZE, 0, &r_timeout); | ||||
|       if (n < 0) {		/* really? */ | ||||
| 	syslog(LOG_WARNING, "tftpd: read: %m"); | ||||
| 	goto abort; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 hpa
						hpa