/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* General skeleton for adding options to the access control language. The
* features offered by this module are documented in the hosts_options(5)
* manual page (source file: hosts_options.5, "nroff -man" format).
*
* Notes and warnings for those who want to add features:
*
* In case of errors, abort options processing and deny access. There are too
* many irreversible side effects to make error recovery feasible. For
* example, it makes no sense to continue after we have already changed the
* userid.
*
* In case of errors, do not terminate the process: the routines might be
* called from a long-running daemon that should run forever. Instead, call
* tcpd_jump() which does a non-local goto back into the hosts_access()
* routine.
*
* In case of severe errors, use clean_exit() instead of directly calling
* exit(), or the inetd may loop on an UDP request.
*
* In verification mode (for example, with the "tcpdmatch" command) the
* "dry_run" flag is set. In this mode, an option function should just "say"
* what it is going to do instead of really doing it.
*
* Some option functions do not return (for example, the twist option passes
* control to another program). In verification mode (dry_run flag is set)
* such options should clear the "dry_run" flag to inform the caller of this
* course of action.
*/
#ifndef lint
#endif
/* System libraries. */
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
#include <setjmp.h>
#include <string.h>
#ifndef MAXPATHNAMELEN
#endif
/* Local stuff. */
#include "tcpd.h"
/* Options runtime support. */
/* Options parser support. */
static char *get_field(); /* chew :-delimited field off string */
static char *chop_string(); /* strip leading and trailing blanks */
/* List of functions that implement the options. Add yours here. */
static void user_option(); /* execute "user name.group" option */
static void group_option(); /* execute "group name" option */
static void umask_option(); /* execute "umask mask" option */
static void linger_option(); /* execute "linger time" option */
static void keepalive_option(); /* execute "keepalive" option */
static void spawn_option(); /* execute "spawn command" option */
static void twist_option(); /* execute "twist command" option */
static void rfc931_option(); /* execute "rfc931" option */
static void setenv_option(); /* execute "setenv name value" */
static void nice_option(); /* execute "nice" option */
static void severity_option(); /* execute "severity value" */
static void allow_option(); /* execute "allow" option */
static void deny_option(); /* execute "deny" option */
static void banners_option(); /* execute "banners path" option */
/* Structure of the options table. */
struct option {
};
/* List of known keywords. Add yours here. */
"keepalive", keepalive_option, 0,
0,
};
/* process_options - process access control options */
char *options;
struct request_info *request;
{
char *key;
char *value;
char *curr_opt;
char *next_opt;
/*
* Separate the option into name and value parts. For backwards
* compatibility we ignore exactly one '=' between name and value.
*/
if (*value != '=') {
*value++ = 0;
}
if (*value == '=') {
*value++ = 0;
}
}
if (*value == 0)
value = 0;
/*
* Disallow missing option names (and empty option fields).
*/
if (*key == 0)
tcpd_jump("missing option name");
/*
* Lookup the option-specific info and do some common error checks.
* Delegate option-specific processing to the specific functions.
*/
/* VOID */ ;
if (hosts_access_verbose)
}
}
/* allow_option - grant access */
/* ARGSUSED */
char *value;
struct request_info *request;
{
}
/* deny_option - deny access */
/* ARGSUSED */
char *value;
struct request_info *request;
{
}
/* banners_option - expand %<char>, terminate each line with CRLF */
char *value;
struct request_info *request;
{
int ch;
}
}
}
/* group_option - switch group id */
/* ARGSUSED */
char *value;
struct request_info *request;
{
endgrent();
}
/* user_option - switch user id */
/* ARGSUSED */
char *value;
struct request_info *request;
{
char *group;
endpwent();
}
/* umask_option - set file creation mask */
/* ARGSUSED */
char *value;
struct request_info *request;
{
unsigned mask;
char junk;
}
/* spawn_option - spawn a shell command and wait */
/* ARGSUSED */
char *value;
struct request_info *request;
{
if (dry_run == 0)
}
/* linger_option - set the socket linger time (Marc Boucher <marc@cam.org>) */
/* ARGSUSED */
char *value;
struct request_info *request;
{
char junk;
if (dry_run == 0) {
sizeof(linger)) < 0)
}
}
/* keepalive_option - set the socket keepalive option */
/* ARGSUSED */
char *value;
struct request_info *request;
{
tcpd_warn("setsockopt SO_KEEPALIVE: %m");
}
/* nice_option - set nice value */
/* ARGSUSED */
char *value;
struct request_info *request;
{
char junk;
}
/* twist_option - replace process by shell command */
char *value;
struct request_info *request;
{
char *error;
if (dry_run != 0) {
dry_run = 0;
} else {
if (resident > 0)
tcpd_jump("twist option in resident process");
/* Before switching to the shell, set up stdin, stdout and stderr. */
error = "twist_option: dup: %m";
} else {
}
/* Something went wrong: we MUST terminate the process. */
}
}
/* rfc931_option - look up remote user name */
char *value;
struct request_info *request;
{
int timeout;
char junk;
if (value != 0) {
}
}
/* setenv_option - set environment variable */
/* ARGSUSED */
char *value;
struct request_info *request;
{
extern int setenv(const char *, const char *, int);
char *var_value;
*var_value++ = 0;
tcpd_jump("memory allocation failure");
}
/*
* The severity option goes last because it comes with a huge amount of ugly
* #ifdefs and tables.
*/
struct syslog_names {
char *name;
int value;
};
#ifdef LOG_KERN
"kern", LOG_KERN,
#endif
#ifdef LOG_USER
"user", LOG_USER,
#endif
#ifdef LOG_MAIL
"mail", LOG_MAIL,
#endif
#ifdef LOG_DAEMON
"daemon", LOG_DAEMON,
#endif
#ifdef LOG_AUTH
"auth", LOG_AUTH,
#endif
#ifdef LOG_LPR
"lpr", LOG_LPR,
#endif
#ifdef LOG_NEWS
"news", LOG_NEWS,
#endif
#ifdef LOG_UUCP
"uucp", LOG_UUCP,
#endif
#ifdef LOG_CRON
"cron", LOG_CRON,
#endif
#ifdef LOG_LOCAL0
"local0", LOG_LOCAL0,
#endif
#ifdef LOG_LOCAL1
"local1", LOG_LOCAL1,
#endif
#ifdef LOG_LOCAL2
"local2", LOG_LOCAL2,
#endif
#ifdef LOG_LOCAL3
"local3", LOG_LOCAL3,
#endif
#ifdef LOG_LOCAL4
"local4", LOG_LOCAL4,
#endif
#ifdef LOG_LOCAL5
"local5", LOG_LOCAL5,
#endif
#ifdef LOG_LOCAL6
"local6", LOG_LOCAL6,
#endif
#ifdef LOG_LOCAL7
"local7", LOG_LOCAL7,
#endif
0,
};
#ifdef LOG_EMERG
"emerg", LOG_EMERG,
#endif
#ifdef LOG_ALERT
"alert", LOG_ALERT,
#endif
#ifdef LOG_CRIT
"crit", LOG_CRIT,
#endif
#ifdef LOG_ERR
"err", LOG_ERR,
#endif
#ifdef LOG_WARNING
"warning", LOG_WARNING,
#endif
#ifdef LOG_NOTICE
"notice", LOG_NOTICE,
#endif
#ifdef LOG_INFO
"info", LOG_INFO,
#endif
#ifdef LOG_DEBUG
"debug", LOG_DEBUG,
#endif
0,
};
/* severity_map - lookup facility or severity value */
struct syslog_names *table;
char *name;
{
struct syslog_names *t;
return (t->value);
/* NOTREACHED */
}
/* severity_option - change logging severity for this event (Dave Mitchell) */
/* ARGSUSED */
char *value;
struct request_info *request;
{
}
/* get_field - return pointer to next field in string */
char *string;
{
char *src;
char *dst;
char *ret;
int ch;
/*
* This function returns pointers to successive fields within a given
* string. ":" is the field separator; warn if the rule ends in one. It
* replaces a "\:" sequence by ":", without treating the result of
* substitution as field terminator. A null argument means resume search
* where the previous call terminated. This function destroys its
* argument.
*
* Work from explicit source or from memory. While processing \: we
* overwrite the input. This way we do not have to maintain buffers for
* copies of input fields.
*/
if (src[0] == 0)
return (0);
if (ch == ':') {
if (*++src == 0)
tcpd_warn("rule ends in \":\"");
break;
}
src++;
}
*dst = 0;
return (ret);
}
/* chop_string - strip leading and trailing blanks from string */
register char *string;
{
char *start = 0;
char *end;
char *cp;
if (start == 0)
}
}
}