#include "ni_server.h"
#include "ni_globals.h"
#include "getstuff.h"
#include <NetInfo/system_log.h>
#include <NetInfo/network.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define NI_SEPARATOR '/'
#define DEFAULT_MAX_READALL_PROXIES 0
#define NAME_READALL_PROXIES "readall_proxies"
#define READALL_PROXIES_UNLIMITED_VALUE "unlimited"
#define READALL_PROXIES_STRICT "strict"
#define DEFAULT_READALL_PROXIES_STRICT TRUE
#define ABSOLUTE_MAX_SUBTHREADS 1024
#define NAME_SUBTHREADS "subthreads"
#define MAX_LATENCY 2*60*60
#define MIN_LATENCY 1
#define NAME_UPDATE_LATENCY "update_latency"
#define MAX_CUWAIT 10*60*60
#define MIN_CUWAIT 60
#define NAME_CLEANUPWAIT "cleanup_wait"
#define NAME_FORCED_ROOT "isRoot"
#define NAME_CLONE_READALL "cloneReplyReadall"
#define NAME_SANITYCHECK "sanitycheck"
#define NAME_LOCAL_BIND_ATTEMPTS "localBindAttempts"
#define NAME_PORT "port"
#define NAME_PORT_TCP "tcp_port"
#define NAME_PORT_UDP "udp_port"
#define NAME_PROMOTE_ADMINS "promote_admins"
static ni_status binding_status = NI_FAILED;
unsigned long getaddress(void *ni, ni_name name)
{
ni_id node;
ni_id root;
ni_idlist idlist;
ni_namelist nl;
u_long addr;
if (ni_root(ni, &root) != NI_OK) return (0);
NI_INIT(&idlist);
if (ni_lookup(ni, &root, NAME_NAME, NAME_MACHINES, &idlist) != NI_OK)
return (0);
node.nii_object = idlist.ni_idlist_val[0];
ni_idlist_free(&idlist);
NI_INIT(&idlist);
if (ni_lookup(ni, &node, NAME_NAME, name, &idlist) != NI_OK)
return (0);
node.nii_object = idlist.ni_idlist_val[0];
ni_idlist_free(&idlist);
NI_INIT(&nl);
if (ni_lookupprop(ni, &node, NAME_IP_ADDRESS, &nl) != NI_OK)
return (0);
if (nl.ni_namelist_len > 0) addr = inet_addr(nl.ni_namelist_val[0]);
else addr = 0;
ni_namelist_free(&nl);
return (addr);
}
int getmaster(void *ni, ni_name *master, ni_name *domain)
{
ni_id root;
ni_namelist nl;
ni_name sep;
if (ni_root(ni, &root) != NI_OK)
{
system_log(LOG_ALERT, "Can't get master: no root directory");
system_log(LOG_ALERT, "Aborting!");
abort();
return (0);
}
NI_INIT(&nl);
if (ni_lookupprop(ni, &root, NAME_MASTER, &nl) != NI_OK)
{
system_log(LOG_ALERT,
"Can't get master: no %s property", NAME_MASTER);
system_log(LOG_ALERT, "Aborting!");
abort();
return (0);
}
if (nl.ni_namelist_len == 0)
{
ni_namelist_free(&nl);
system_log(LOG_ALERT,
"Can't get master: no values in %s property", NAME_MASTER);
system_log(LOG_ALERT, "Aborting!");
abort();
return (0);
}
sep = strchr(nl.ni_namelist_val[0], NI_SEPARATOR);
if (sep == NULL)
{
ni_namelist_free(&nl);
system_log(LOG_ALERT,
"Can't get master: no '%c' in value '%s'",
NI_SEPARATOR, nl.ni_namelist_val[0]);
system_log(LOG_ALERT, "Aborting!");
abort();
return (0);
}
*sep = 0;
if (master != NULL) *master = ni_name_dup(nl.ni_namelist_val[0]);
if (domain != NULL) *domain = ni_name_dup(sep + 1);
ni_namelist_free(&nl);
return (1);
}
unsigned long getmasteraddr(void *ni, ni_name *domain)
{
unsigned long addr;
ni_name master = NULL;
if (getmaster(ni, &master, domain))
{
addr = getaddress(ni, master);
ni_name_free(&master);
}
else addr = 0;
return (addr);
}
static struct in_addr getnetwork(void *ni, ni_name name)
{
ni_id node;
ni_id root;
ni_idlist idlist;
ni_namelist nl;
struct in_addr addr;
addr.s_addr = 0;
if (ni_root(ni, &root) != NI_OK) return (addr);
NI_INIT(&idlist);
if (ni_lookup(ni, &root, NAME_NAME, NAME_NETWORKS, &idlist) != NI_OK)
return (addr);
node.nii_object = idlist.ni_idlist_val[0];
ni_idlist_free(&idlist);
NI_INIT(&idlist);
if (ni_lookup(ni, &node, NAME_NAME, name, &idlist) != NI_OK)
return (addr);
node.nii_object = idlist.ni_idlist_val[0];
ni_idlist_free(&idlist);
NI_INIT(&nl);
if (ni_lookupprop(ni, &node, NAME_ADDRESS, &nl) != NI_OK)
return (addr);
if (nl.ni_namelist_len > 0)
addr = inet_makeaddr(inet_network(nl.ni_namelist_val[0]), 0);
ni_namelist_free(&nl);
return (addr);
}
static int network_match(struct in_addr n, struct in_addr h)
{
union
{
char s_byte[4];
u_long s_address;
} net, host;
net.s_address = n.s_addr;
host.s_address = h.s_addr;
if (n.s_addr == 0) return (0);
if (net.s_byte[0] != host.s_byte[0]) return (0);
if (net.s_byte[1] == 0) return (1);
if (net.s_byte[1] != host.s_byte[1]) return (0);
if (net.s_byte[2] == 0) return (1);
if (net.s_byte[2] != host.s_byte[2]) return (0);
return (1);
}
bool_t is_desktop(void *ni)
{
ni_id root;
int i;
bool_t d;
ni_namelist nl;
ni_status status;
status = ni_root(ni, &root);
if (status != NI_OK)
{
system_log(LOG_ERR,
"trusted_networks for tag %s: cannot get root - %s",
ni_tagname(ni), ni_error(status));
return TRUE;
}
NI_INIT(&nl);
if (ni_lookupprop(ni, &root, NAME_TRUSTED_NETWORKS, &nl) != NI_OK)
{
return FALSE;
}
if (nl.ni_namelist_len == 0)
{
ni_namelist_free(&nl);
return TRUE;
}
d = TRUE;
for (i = 0; (i < nl.ni_namelist_len) && (d == 1); i++)
{
if (!strncmp(nl.ni_namelist_val[i], "127", 3)) continue;
d = FALSE;
}
return d;
}
int is_trusted_network(void *ni, struct sockaddr_in *host)
{
struct in_addr network;
ni_id root;
int i;
char *val, *temp;
ni_namelist nl;
ni_status status;
status = ni_root(ni, &root);
if (status != NI_OK)
{
system_log(LOG_ERR,
"trusted_networks for tag %s: cannot get root - %s",
ni_tagname(ni), ni_error(status));
return (0);
}
NI_INIT(&nl);
if (ni_lookupprop(ni, &root, NAME_TRUSTED_NETWORKS, &nl) != NI_OK)
{
return (1);
}
for (i = 0; i < nl.ni_namelist_len; i++)
{
val = nl.ni_namelist_val[i];
if (isdigit(*val)) {
if (NULL == strchr(val, '.'))
{
temp = malloc(strlen(val) + 2);
strcpy(temp, val);
strcat(temp, ".");
network = inet_makeaddr(inet_network(temp), 0);
free(temp);
}
else network = inet_makeaddr(inet_network(val), 0);
}
else
{
network = getnetwork(ni, val);
}
if (network_match(network, host->sin_addr))
{
ni_namelist_free(&nl);
return (1);
}
}
ni_namelist_free(&nl);
if (sys_is_my_address(&(host->sin_addr)))
{
return (1);
}
system_log(LOG_NOTICE,
"rejected connection from untrusted host %s",
inet_ntoa(host->sin_addr));
return (0);
}
static int get_intForKey(void *ni, char *name, int def, int min, int max)
{
ni_id root;
ni_namelist nl;
int i, len;
if (ni_root(ni, &root) != NI_OK) return(def);
NI_INIT(&nl);
if (ni_lookupprop(ni, &root, name, &nl) != NI_OK)
return(def);
if (nl.ni_namelist_len == 0)
{
ni_namelist_free(&nl);
return(def);
}
len = strlen(nl.ni_namelist_val[0]);
if (len == 0)
{
system_log(LOG_ERR,
"no value for property %s",
"using default %d", name, def);
ni_namelist_free(&nl);
return(def);
}
if (!strcmp(nl.ni_namelist_val[0], "unlimited")) return -1;
if (!((nl.ni_namelist_val[0][0] == '+') ||
(nl.ni_namelist_val[0][0] == '-') ||
isdigit(nl.ni_namelist_val[0][0])))
{
system_log(LOG_ERR,
"bad integer value for property %s",
"using default %d", name, def);
ni_namelist_free(&nl);
return(def);
}
for (i = 1; i < len; i++)
{
if (!isdigit(nl.ni_namelist_val[0][i]))
{
system_log(LOG_ERR,
"bad integer value for property %s,",
"using default %d", name, def);
ni_namelist_free(&nl);
return(def);
}
}
i = atoi(nl.ni_namelist_val[0]);
ni_namelist_free(&nl);
if (i == -1) return i;
if (i < min)
{
system_log(LOG_ERR,
"value %d for property %s is less than minimum allowed (%d),",
"using minimum %d", i, name, min, min);
return min;
}
if (i > max)
{
if (max == -1) return i;
system_log(LOG_ERR,
"value %d for property %s is greater than maximum allowed (%d),",
"using maximum %d", i, name, max, max);
return max;
}
return i;
}
void get_readall_info(void *ni, int *proxies, bool_t *strict)
{
ni_id root;
ni_namelist nl;
ni_status status;
*proxies = get_intForKey(ni, NAME_READALL_PROXIES,
DEFAULT_MAX_READALL_PROXIES, 0, MAX_READALL_PROXIES);
*strict = DEFAULT_READALL_PROXIES_STRICT;
status = ni_root(ni, &root);
if (status != NI_OK) return;
status = ni_lookupprop(ni, &root, NAME_READALL_PROXIES, &nl);
if (status != NI_OK) return;
if (nl.ni_namelist_len < 2)
{
ni_namelist_free(&nl);
return;
}
*strict = (!strcasecmp(nl.ni_namelist_val[1], READALL_PROXIES_STRICT));
ni_namelist_free(&nl);
switch (*proxies)
{
case -1:
system_log(LOG_WARNING,
"using unlimited %sreadall proxies",
*strict ? "strict " : "");
break;
case 0:
break;
default:
system_log(LOG_NOTICE,
"maximum %d %sreadall prox%s", *proxies,
*strict ? "strict " : "", (*proxies == 1) ? "y" : "ies");
break;
}
return;
}
int get_cleanupwait(void *ni)
{
int n;
n = get_intForKey(ni, NAME_CLEANUPWAIT, CLEANUPWAIT,
MIN_CUWAIT, MAX_CUWAIT);
if (n != CLEANUPWAIT) {
system_log(LOG_NOTICE,
"using cleanup wait of %d second%s", n,
1 == n ? "" : "s");
}
return n;
}
int get_localbindattempts(void *ni)
{
int n;
n = get_intForKey(ni, NAME_LOCAL_BIND_ATTEMPTS, LOCAL_BIND_ATTEMPTS, 0, -1);
if (n != LOCAL_BIND_ATTEMPTS) {
system_log(LOG_NOTICE, "allowing %d local bind attempt%s",
n, 1 == n ? "" : "s");
}
return n;
}
int get_update_latency(void *ni)
{
int n;
n = get_intForKey(ni, NAME_UPDATE_LATENCY, UPDATE_LATENCY_SECS,
MIN_LATENCY, MAX_LATENCY);
if (n == -1) n = UPDATE_LATENCY_SECS;
if (n != UPDATE_LATENCY_SECS) {
system_log(LOG_NOTICE,
"using cleanup update latency of %d second%s", n,
1 == n ? "" : "s");
}
return n;
}
int get_max_subthreads(void *ni)
{
int n;
n = get_intForKey(ni, NAME_SUBTHREADS, MAX_SUBTHREADS,
0, ABSOLUTE_MAX_SUBTHREADS);
if (n == -1) n = ABSOLUTE_MAX_SUBTHREADS;
if (n != MAX_SUBTHREADS) {
system_log(LOG_NOTICE,
"maximum %d notify subthread%s", n,
(n == 1) ? "" : "s");
}
return n;
}
static bool_t get_boolForKey(void *ni, ni_name name, bool_t def)
{
ni_id root;
ni_namelist nl;
bool_t ret;
ret = def;
if (ni_root(ni, &root) != NI_OK)
return(ret);
if (ni_lookupprop(ni, &root, name, &nl) != NI_OK)
return(ret);
if (nl.ni_namelist_len == 0)
{
ni_namelist_free(&nl);
return(ret);
}
if (!strcmp(nl.ni_namelist_val[0], "YES")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "yes")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "Yes")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "1")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "Y")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "y")) ret = TRUE;
else if (!strcmp(nl.ni_namelist_val[0], "NO")) ret = FALSE;
else if (!strcmp(nl.ni_namelist_val[0], "no")) ret = FALSE;
else if (!strcmp(nl.ni_namelist_val[0], "No")) ret = FALSE;
else if (!strcmp(nl.ni_namelist_val[0], "0")) ret = FALSE;
else if (!strcmp(nl.ni_namelist_val[0], "N")) ret = FALSE;
else if (!strcmp(nl.ni_namelist_val[0], "n")) ret = FALSE;
ni_namelist_free(&nl);
return(ret);
}
bool_t get_promote_admins(void *ni)
{
return get_boolForKey(ni, NAME_PROMOTE_ADMINS, TRUE);
}
bool_t get_forced_root(void *ni)
{
return get_boolForKey(ni, NAME_FORCED_ROOT, FALSE);
}
bool_t get_clone_readall(void *ni)
{
return get_boolForKey(ni, NAME_CLONE_READALL, FALSE);
}
bool_t
get_sanitycheck(void *ni)
{
return get_boolForKey(ni, NAME_SANITYCHECK, FALSE);
}
unsigned short
get_port(void *ni, char *proto)
{
unsigned short p;
if (proto == NULL)
{
p = get_intForKey(ni, NAME_PORT, 0, 0, 65535);
return p;
}
if (!strcmp(proto, "tcp"))
{
p = get_intForKey(ni, NAME_PORT_TCP, 0, 0, 65535);
if (p != 0) return p;
}
else if (!strcmp(proto, "udp"))
{
p = get_intForKey(ni, NAME_PORT_UDP, 0, 0, 65535);
if (p != 0) return p;
}
else return 0;
p = get_intForKey(ni, NAME_PORT, 0, 0, 65535);
return p;
}
ni_status
get_binding_status(void)
{
return binding_status;
}
void
set_binding_status(ni_status stat)
{
binding_status = stat;
}