1 /* $NetBSD: percent_x.c,v 1.5 2012/03/21 10:10:37 matt Exp $ */ 2 3 /* 4 * percent_x() takes a string and performs %<char> expansions. It aborts the 5 * program when the expansion would overflow the output buffer. The result 6 * of %<char> expansion may be passed on to a shell process. For this 7 * reason, characters with a special meaning to shells are replaced by 8 * underscores. 9 * 10 * Diagnostics are reported through syslog(3). 11 * 12 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 13 */ 14 15 #include <sys/cdefs.h> 16 #ifndef lint 17 #if 0 18 static char sccsid[] = "@(#) percent_x.c 1.4 94/12/28 17:42:37"; 19 #else 20 __RCSID("$NetBSD: percent_x.c,v 1.5 2012/03/21 10:10:37 matt Exp $"); 21 #endif 22 #endif 23 24 /* System libraries. */ 25 26 #include <stdio.h> 27 #include <syslog.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 32 /* Local stuff. */ 33 34 #include "tcpd.h" 35 36 /* percent_x - do %<char> expansion, abort if result buffer is too small */ 37 38 char * 39 percent_x(char *result, int result_len, char *string, 40 struct request_info *request) 41 { 42 char *bp = result; 43 char *end = result + result_len - 1; /* end of result buffer */ 44 char *expansion; 45 size_t expansion_len; 46 static const char ok_chars[] = "1234567890!@%-_=+:,./" 47 "abcdefghijklmnopqrstuvwxyz" 48 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 49 char *str = string; 50 char *cp; 51 int ch; 52 53 /* 54 * Warning: we may be called from a child process or after pattern 55 * matching, so we cannot use clean_exit() or tcpd_jump(). 56 */ 57 58 while (*str) { 59 if (*str == '%' && (ch = str[1]) != 0) { 60 str += 2; 61 expansion = 62 ch == 'a' ? eval_hostaddr(request->client) : 63 ch == 'A' ? eval_hostaddr(request->server) : 64 ch == 'c' ? eval_client(request) : 65 ch == 'd' ? eval_daemon(request) : 66 ch == 'h' ? eval_hostinfo(request->client) : 67 ch == 'H' ? eval_hostinfo(request->server) : 68 ch == 'n' ? eval_hostname(request->client) : 69 ch == 'N' ? eval_hostname(request->server) : 70 ch == 'p' ? eval_pid(request) : 71 ch == 's' ? eval_server(request) : 72 ch == 'u' ? eval_user(request) : 73 ch == '%' ? __UNCONST("%") 74 : (tcpd_warn("unrecognized %%%c", ch), __UNCONST("")); 75 for (cp = expansion; *(cp += strspn(cp, ok_chars)); /* */ ) 76 *cp = '_'; 77 expansion_len = cp - expansion; 78 } else { 79 expansion = str++; 80 expansion_len = 1; 81 } 82 if (bp + expansion_len >= end) { 83 tcpd_warn("percent_x: expansion too long: %.30s...", result); 84 sleep(5); 85 exit(0); 86 } 87 memcpy(bp, expansion, expansion_len); 88 bp += expansion_len; 89 } 90 *bp = 0; 91 return (result); 92 } 93