144743Smarkm /*
244743Smarkm  * percent_x() takes a string and performs %<char> expansions. It aborts the
344743Smarkm  * program when the expansion would overflow the output buffer. The result
444743Smarkm  * of %<char> expansion may be passed on to a shell process. For this
544743Smarkm  * reason, characters with a special meaning to shells are replaced by
644743Smarkm  * underscores.
744743Smarkm  *
844743Smarkm  * Diagnostics are reported through syslog(3).
944743Smarkm  *
1044743Smarkm  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
1144743Smarkm  */
1244743Smarkm
1344743Smarkm#ifndef lint
1444743Smarkmstatic char sccsid[] = "@(#) percent_x.c 1.4 94/12/28 17:42:37";
1544743Smarkm#endif
1644743Smarkm
1744743Smarkm/* System libraries. */
1844743Smarkm
1944743Smarkm#include <stdio.h>
2044743Smarkm#include <syslog.h>
2144743Smarkm#include <string.h>
2244743Smarkm
2344743Smarkmextern void exit();
2444743Smarkm
2544743Smarkm/* Local stuff. */
2644743Smarkm
2744743Smarkm#include "tcpd.h"
2844743Smarkm
2944743Smarkm/* percent_x - do %<char> expansion, abort if result buffer is too small */
3044743Smarkm
3144743Smarkmchar   *percent_x(result, result_len, string, request)
3244743Smarkmchar   *result;
3344743Smarkmint     result_len;
3444743Smarkmchar   *string;
3544743Smarkmstruct request_info *request;
3644743Smarkm{
3744743Smarkm    char   *bp = result;
3844743Smarkm    char   *end = result + result_len - 1;	/* end of result buffer */
3944743Smarkm    char   *expansion;
4044743Smarkm    int     expansion_len;
4144743Smarkm    static char ok_chars[] = "1234567890!@%-_=+:,./\
4244743Smarkmabcdefghijklmnopqrstuvwxyz\
4344743SmarkmABCDEFGHIJKLMNOPQRSTUVWXYZ";
4444743Smarkm    char   *str = string;
4544743Smarkm    char   *cp;
4644743Smarkm    int     ch;
4744743Smarkm
4844743Smarkm    /*
4944743Smarkm     * Warning: we may be called from a child process or after pattern
5044743Smarkm     * matching, so we cannot use clean_exit() or tcpd_jump().
5144743Smarkm     */
5244743Smarkm
5344743Smarkm    while (*str) {
5444743Smarkm	if (*str == '%' && (ch = str[1]) != 0) {
5544743Smarkm	    str += 2;
5644743Smarkm	    expansion =
5744743Smarkm		ch == 'a' ? eval_hostaddr(request->client) :
5844743Smarkm		ch == 'A' ? eval_hostaddr(request->server) :
5944743Smarkm		ch == 'c' ? eval_client(request) :
6044743Smarkm		ch == 'd' ? eval_daemon(request) :
6144743Smarkm		ch == 'h' ? eval_hostinfo(request->client) :
6244743Smarkm		ch == 'H' ? eval_hostinfo(request->server) :
6344743Smarkm		ch == 'n' ? eval_hostname(request->client) :
6444743Smarkm		ch == 'N' ? eval_hostname(request->server) :
6544743Smarkm		ch == 'p' ? eval_pid(request) :
6644743Smarkm		ch == 's' ? eval_server(request) :
6744743Smarkm		ch == 'u' ? eval_user(request) :
6844743Smarkm		ch == '%' ? "%" : (tcpd_warn("unrecognized %%%c", ch), "");
6944743Smarkm	    for (cp = expansion; *(cp += strspn(cp, ok_chars)); /* */ )
7044743Smarkm		*cp = '_';
7144743Smarkm	    expansion_len = cp - expansion;
7244743Smarkm	} else {
7344743Smarkm	    expansion = str++;
7444743Smarkm	    expansion_len = 1;
7544743Smarkm	}
7644743Smarkm	if (bp + expansion_len >= end) {
7744743Smarkm	    tcpd_warn("percent_x: expansion too long: %.30s...", result);
7844743Smarkm	    sleep(5);
7944743Smarkm	    exit(0);
8044743Smarkm	}
8144743Smarkm	memcpy(bp, expansion, expansion_len);
8244743Smarkm	bp += expansion_len;
8344743Smarkm    }
8444743Smarkm    *bp = 0;
8544743Smarkm    return (result);
8644743Smarkm}
87