495 lines
10 KiB
C
495 lines
10 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <pwd.h>
|
|
#include <netax25/ax25.h> /* axutils.h needs this... */
|
|
#include <netrose/rose.h>
|
|
#include <netax25/axlib.h>
|
|
#include <netax25/axconfig.h>
|
|
|
|
#include "node.h"
|
|
|
|
long IdleTimeout = 360L; /* default to 6 mins */
|
|
long ConnTimeout = 300L; /* default to 5 mins */
|
|
int ReConnectTo = 0;
|
|
int LogLevel = LOGLVL_ERROR;
|
|
int EscChar = 20; /* CTRL-T */
|
|
|
|
char *Email = NULL;
|
|
char *HostName = NULL;
|
|
char *NodeId = NULL;
|
|
char *NrPort = NULL; /* first netrom port */
|
|
char *FlexId = NULL;
|
|
char *RoseId = NULL;
|
|
|
|
#ifdef HAVEMOTD
|
|
char *Prompt = "\n=> "; /* Prompt by IZ5AWZ */
|
|
#else
|
|
char *Prompt = "\n";
|
|
#endif
|
|
char *PassPrompt = "\nPassword >"; /* Prompt Password by IZ5AWZ */
|
|
|
|
static unsigned long Permissions = 0L;
|
|
static unsigned long LocalNet = 0L;
|
|
static unsigned long LocalMask = ~0L;
|
|
static char *HiddenPorts[32] = {0};
|
|
|
|
/*
|
|
* Return non-zero if `port' is a hidden port.
|
|
*/
|
|
|
|
int is_hidden(const char *port)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; HiddenPorts[i] != NULL && i < 31; i++)
|
|
if (!strcmp(port, HiddenPorts[i]))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Return non-zero if peer is on "local" or loopback network.
|
|
*/
|
|
|
|
static int is_local(unsigned long peer)
|
|
{
|
|
return ((peer & LocalMask) == LocalNet) || ((peer & 0xff) == 127);
|
|
}
|
|
|
|
/*
|
|
* Return non-zero if peer is on amprnet.
|
|
*/
|
|
static int is_ampr(unsigned long peer)
|
|
{
|
|
return ((peer & 0xff) == 44);
|
|
}
|
|
|
|
/*
|
|
* Convert NOS style width to a netmask in network byte order.
|
|
*/
|
|
static unsigned long bits_to_mask(int bits)
|
|
{
|
|
return htonl(~0L << (32 - bits));
|
|
}
|
|
|
|
int check_perms(int what, unsigned long peer)
|
|
{
|
|
if (what == PERM_TELNET) {
|
|
if (is_local(peer)) {
|
|
if (Permissions & PERM_TELNET_LOCAL)
|
|
return 0;
|
|
} else if (is_ampr(peer)) {
|
|
if (Permissions & PERM_TELNET_AMPR)
|
|
return 0;
|
|
} else {
|
|
if (Permissions & PERM_TELNET_INET)
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
if ((Permissions & what) == 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read permissions file and return a password if needed or "*" if not.
|
|
* If user access is denied return NULL.
|
|
*/
|
|
char *read_perms(struct user *up, unsigned long peer)
|
|
{
|
|
FILE *fp;
|
|
char line[256], *argv[32], *cp;
|
|
int argc, n = 0;
|
|
|
|
if ((fp = fopen(CONF_NODE_PERMS_FILE, "r")) == NULL) {
|
|
node_perror(CONF_NODE_PERMS_FILE, errno);
|
|
return NULL;
|
|
}
|
|
if ((cp = strchr(up->call, '-')) != NULL)
|
|
*cp = 0;
|
|
while (fgets(line, 256, fp) != NULL) {
|
|
n++;
|
|
argc = parse_args(argv, line);
|
|
if (argc == 0 || *argv[0] == '#')
|
|
continue;
|
|
if (argc != 5) {
|
|
node_msg("Configuration error");
|
|
node_log(LOGLVL_ERROR, "Syntax error in permission file at line %d", n);
|
|
break;
|
|
}
|
|
if (strcmp(argv[0], "*") && strcasecmp(argv[0], up->call))
|
|
continue;
|
|
switch (up->ul_type) {
|
|
case AF_FLEXNET:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "flexnet"))
|
|
break;
|
|
continue;
|
|
case AF_AX25:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "ax25"))
|
|
break;
|
|
continue;
|
|
case AF_NETROM:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "netrom"))
|
|
break;
|
|
continue;
|
|
#ifdef HAVE_ROSE
|
|
case AF_ROSE:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "rose"))
|
|
break;
|
|
continue;
|
|
#endif
|
|
// case AF_INET6:
|
|
// if (!strcmp(argv[1], "*"))
|
|
// break;
|
|
// if (!strcasecmp(argv[1], ""))
|
|
// break;
|
|
// continue;
|
|
case AF_INET:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "local") && is_local(peer))
|
|
break;
|
|
if (!strcasecmp(argv[1], "ampr") && is_ampr(peer))
|
|
break;
|
|
if (!strcasecmp(argv[1], "inet") && !is_local(peer) && !is_ampr(peer))
|
|
break;
|
|
continue;
|
|
case AF_UNSPEC:
|
|
if (!strcmp(argv[1], "*"))
|
|
break;
|
|
if (!strcasecmp(argv[1], "host"))
|
|
break;
|
|
continue;
|
|
}
|
|
if (up->ul_type == AF_AX25) {
|
|
if (strcmp(argv[2], "*") && strcmp(argv[2], up->ul_name))
|
|
continue;
|
|
}
|
|
if (cp != NULL)
|
|
*cp = '-';
|
|
if ((Permissions = strtoul(argv[4], NULL, 10)) == 0)
|
|
return NULL;
|
|
else
|
|
return strdup(argv[3]);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int do_alias(int argc, char **argv)
|
|
{
|
|
struct cmd *new;
|
|
int len = 0;
|
|
|
|
if (argc < 3)
|
|
return -1;
|
|
if ((new = calloc(1, sizeof(struct cmd))) == NULL) {
|
|
node_perror("do_alias: malloc", errno);
|
|
// return -2;
|
|
return -1; /* ve3tok 31 Mar,2016 - tnx Brian */
|
|
}
|
|
new->name = strdup(argv[1]);
|
|
while (isupper(new->name[len]))
|
|
len++;
|
|
/* Ok. So they can't read... */
|
|
if (len == 0) {
|
|
strupr(new->name);
|
|
len = strlen(new->name);
|
|
}
|
|
new->len = len;
|
|
new->command = strdup(argv[2]);
|
|
new->type = CMD_ALIAS;
|
|
insert_cmd(&Nodecmds, new);
|
|
return 0;
|
|
}
|
|
|
|
static int do_loglevel(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
LogLevel = atoi(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
int get_escape(char *s)
|
|
{
|
|
int escape;
|
|
char *endptr[1];
|
|
|
|
if (isdigit(*s)) {
|
|
escape = strtol(s, endptr, 0);
|
|
if (**endptr)
|
|
return -2;
|
|
else
|
|
return escape;
|
|
}
|
|
|
|
if (strlen(s) == 1)
|
|
return *s;
|
|
|
|
if (strlen(s) == 2 && *s == '^')
|
|
return (toupper(*++s) - 'A' + 1);
|
|
|
|
if (strcasecmp(s, "off") == 0 || strcmp(s, "-1") == 0)
|
|
return -1;
|
|
|
|
return -2;
|
|
}
|
|
|
|
|
|
static int do_escapechar(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
|
|
EscChar = get_escape(argv[1]);
|
|
|
|
if (EscChar < -1 || EscChar > 255) {
|
|
node_msg("Configuration error");
|
|
node_log(LOGLVL_ERROR, "do_escapechar: Invalid escape character %s",
|
|
argv[1]);
|
|
return -2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_idletimeout(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
IdleTimeout = atol(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int do_conntimeout(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
ConnTimeout = atol(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int do_hostname(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
HostName = strdup(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int do_localnet(int argc, char **argv)
|
|
{
|
|
char *cp;
|
|
|
|
if (argc < 2)
|
|
return -1;
|
|
if ((cp = strchr(argv[1], '/')) != NULL) {
|
|
*cp = 0;
|
|
LocalMask = bits_to_mask(atoi(++cp));
|
|
}
|
|
LocalNet = inet_addr(argv[1]);
|
|
LocalNet &= LocalMask;
|
|
return 0;
|
|
}
|
|
|
|
static int do_reconnect(int argc, char **argv)
|
|
{
|
|
#ifdef HAVEMOTD
|
|
if (argc < 2)
|
|
return -1;
|
|
if (!strcasecmp(argv[1], "on"))
|
|
ReConnectTo = 1;
|
|
else
|
|
#endif
|
|
ReConnectTo = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int do_hiddenports(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
if (argc < 2)
|
|
return -1;
|
|
for (i = 1; i < argc && i < 31; i++) {
|
|
if (ax25_config_get_dev(argv[i]) == NULL) {
|
|
node_msg("Configuration error");
|
|
node_log(LOGLVL_ERROR, "do_hiddenports: invalid port %s", argv[i]);
|
|
return -2;
|
|
}
|
|
HiddenPorts[i - 1] = strdup(argv[i]);
|
|
}
|
|
HiddenPorts[i - 1] = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static int do_extcmd(int argc, char **argv)
|
|
{
|
|
struct cmd *new;
|
|
struct passwd *pw;
|
|
char buf[1024];
|
|
int i, len;
|
|
|
|
if (argc < 6)
|
|
return -1;
|
|
if ((new = calloc(1, sizeof(struct cmd))) == NULL) {
|
|
node_perror("do_extcmd: malloc", errno);
|
|
return -2;
|
|
}
|
|
new->name = strdup(argv[1]);
|
|
len = 0;
|
|
while (isupper(new->name[len]))
|
|
len++;
|
|
/* Ok. So they can't read... */
|
|
if (len == 0) {
|
|
strupr(new->name);
|
|
len = strlen(new->name);
|
|
}
|
|
new->len = len;
|
|
new->flags = atoi(argv[2]);
|
|
if ((pw = getpwnam(argv[3])) == NULL) {
|
|
node_msg("Configuration error");
|
|
node_log(LOGLVL_ERROR, "do_extcmd: Unknown user %s", argv[3]);
|
|
return -2;
|
|
}
|
|
new->uid = pw->pw_uid;
|
|
new->gid = pw->pw_gid;
|
|
new->path = strdup(argv[4]);
|
|
len = 0;
|
|
for (i = 0; argv[i + 5] != NULL; i++) {
|
|
sprintf(&buf[len], "\"%s\" ", argv[i + 5]);
|
|
len = strlen(buf);
|
|
}
|
|
new->command = strdup(buf);
|
|
new->type = CMD_EXTERNAL;
|
|
insert_cmd(&Nodecmds, new);
|
|
return 0;
|
|
}
|
|
|
|
static int do_nodeid(int argc, char **argv)
|
|
{
|
|
if (User.ul_type == AF_NETROM) {
|
|
if (argc < 2)
|
|
return -1;
|
|
NodeId = strdup(argv[1]);
|
|
} else if (User.ul_type != AF_NETROM) {
|
|
NodeId = strdup(argv[1]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_flexid(int argc, char **argv)
|
|
{
|
|
if (argc < 2 )
|
|
return -1;
|
|
FlexId = ("%s ;" , strdup(argv[1]));
|
|
return 0;
|
|
}
|
|
|
|
static int do_roseid(int argc, char **argv)
|
|
{
|
|
if (argc < 2 )
|
|
return -1;
|
|
RoseId = ("%s ;" , strdup(argv[1]));
|
|
return 0;
|
|
}
|
|
|
|
static int do_prompt(int argc, char **argv)
|
|
{
|
|
if ((User.ul_type != AF_NETROM) || (User.ul_type != AF_INET) || (User.ul_type != AF_INET6)) {
|
|
if (argc < 2) {
|
|
return -1;
|
|
Prompt = strdup(argv[1]);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int do_passprompt(int argc, char **argv)
|
|
{
|
|
if (User.ul_type != AF_NETROM) {
|
|
if (argc < 2)
|
|
return -1;
|
|
PassPrompt = strdup(argv[1]);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int do_nrport(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
NrPort = strdup(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int do_email(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
return -1;
|
|
Email = strdup(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
int read_config(void)
|
|
{
|
|
struct cmd *cfg_cmds = NULL;
|
|
FILE *fp;
|
|
char line[256];
|
|
int ret, n = 0;
|
|
|
|
add_internal_cmd(&cfg_cmds, "alias", 5, do_alias);
|
|
add_internal_cmd(&cfg_cmds, "conntimeout", 11, do_conntimeout);
|
|
add_internal_cmd(&cfg_cmds, "email", 5, do_email);
|
|
add_internal_cmd(&cfg_cmds, "escapechar", 10, do_escapechar);
|
|
add_internal_cmd(&cfg_cmds, "extcmd", 6, do_extcmd);
|
|
add_internal_cmd(&cfg_cmds, "hiddenports", 11, do_hiddenports);
|
|
add_internal_cmd(&cfg_cmds, "hostname", 8, do_hostname);
|
|
add_internal_cmd(&cfg_cmds, "idletimeout", 11, do_idletimeout);
|
|
add_internal_cmd(&cfg_cmds, "localnet", 8, do_localnet);
|
|
add_internal_cmd(&cfg_cmds, "loglevel", 8, do_loglevel);
|
|
add_internal_cmd(&cfg_cmds, "nodeid", 6, do_nodeid);
|
|
add_internal_cmd(&cfg_cmds, "flexid", 6, do_flexid);
|
|
add_internal_cmd(&cfg_cmds, "roseid", 6, do_roseid);
|
|
add_internal_cmd(&cfg_cmds, "prompt", 6, do_prompt);
|
|
add_internal_cmd(&cfg_cmds, "nrport", 6, do_nrport);
|
|
add_internal_cmd(&cfg_cmds, "reconnect", 8, do_reconnect);
|
|
add_internal_cmd(&cfg_cmds, "passprompt", 6, do_passprompt);
|
|
|
|
if ((fp = fopen(CONF_NODE_FILE, "r")) == NULL) {
|
|
node_perror(CONF_NODE_FILE, errno);
|
|
return -1;
|
|
}
|
|
while (fgets(line, 256, fp) != NULL) {
|
|
n++;
|
|
ret = cmdparse(cfg_cmds, line);
|
|
if (ret == -1) {
|
|
node_msg("Configuration error");
|
|
node_log(LOGLVL_ERROR, "Syntax error in config file at line %d: %s", n, line);
|
|
}
|
|
if (ret < 0) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
free_cmdlist(cfg_cmds);
|
|
cfg_cmds = NULL;
|
|
return 0;
|
|
}
|