|
|
@@ -158,6 +158,7 @@ static char *msg_buffer = NULL;
|
|
|
static SOCKETTYPE sock = INVSOCK;
|
|
|
|
|
|
static const char *UNAVAILABLE = " - API will not be available";
|
|
|
+static const char *GROUPDIS = " - groups will be disabled";
|
|
|
|
|
|
static const char *BLANK = "";
|
|
|
static const char *COMMA = ",";
|
|
|
@@ -165,7 +166,7 @@ static const char SEPARATOR = '|';
|
|
|
#define SEPSTR "|"
|
|
|
static const char GPUSEP = ',';
|
|
|
|
|
|
-static const char *APIVERSION = "1.12";
|
|
|
+static const char *APIVERSION = "1.13";
|
|
|
static const char *DEAD = "Dead";
|
|
|
static const char *SICK = "Sick";
|
|
|
static const char *NOSTART = "NoStart";
|
|
|
@@ -243,6 +244,7 @@ static const char *OSINFO =
|
|
|
#define _BYE "BYE"
|
|
|
#define _RESTART "RESTART"
|
|
|
#define _MINESTATS "STATS"
|
|
|
+#define _CHECK "CHECK"
|
|
|
|
|
|
static const char ISJSON = '{';
|
|
|
#define JSON0 "{"
|
|
|
@@ -277,6 +279,7 @@ static const char ISJSON = '{';
|
|
|
#define JSON_RESTART JSON1 _RESTART JSON1
|
|
|
#define JSON_CLOSE JSON3
|
|
|
#define JSON_MINESTATS JSON1 _MINESTATS JSON2
|
|
|
+#define JSON_CHECK JSON1 _CHECK JSON2
|
|
|
#define JSON_END JSON4
|
|
|
|
|
|
static const char *JSON_COMMAND = "command";
|
|
|
@@ -364,6 +367,8 @@ static const char *JSON_PARAMETER = "parameter";
|
|
|
#define MSG_REMPOOL 68
|
|
|
#define MSG_DEVDETAILS 69
|
|
|
#define MSG_MINESTATS 70
|
|
|
+#define MSG_MISCHK 71
|
|
|
+#define MSG_CHECK 72
|
|
|
|
|
|
enum code_severity {
|
|
|
SEVERITY_ERR,
|
|
|
@@ -507,6 +512,8 @@ struct CODES {
|
|
|
{ SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" },
|
|
|
{ SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" },
|
|
|
{ SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "CGMiner stats" },
|
|
|
+ { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" },
|
|
|
+ { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" },
|
|
|
{ SEVERITY_FAIL, 0, 0, NULL }
|
|
|
};
|
|
|
|
|
|
@@ -525,9 +532,25 @@ static time_t when = 0; // when the request occurred
|
|
|
struct IP4ACCESS {
|
|
|
in_addr_t ip;
|
|
|
in_addr_t mask;
|
|
|
- bool writemode;
|
|
|
+ char group;
|
|
|
};
|
|
|
|
|
|
+#define GROUP(g) (toupper(g))
|
|
|
+#define PRIVGROUP GROUP('W')
|
|
|
+#define NOPRIVGROUP GROUP('R')
|
|
|
+#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP)
|
|
|
+#define GROUPOFFSET(g) (GROUP(g) - GROUP('A'))
|
|
|
+#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z'))
|
|
|
+#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands)
|
|
|
+#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL)
|
|
|
+
|
|
|
+struct APIGROUPS {
|
|
|
+ // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search
|
|
|
+ char *commands;
|
|
|
+} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs)
|
|
|
+
|
|
|
+static bool groups_enabled = false;
|
|
|
+
|
|
|
static struct IP4ACCESS *ipaccess = NULL;
|
|
|
static int ips = 0;
|
|
|
|
|
|
@@ -796,7 +819,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
|
|
|
return msg_buffer;
|
|
|
}
|
|
|
|
|
|
-static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
sprintf(io_buffer, isjson
|
|
|
? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE
|
|
|
@@ -805,7 +828,7 @@ static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|
|
VERSION, APIVERSION);
|
|
|
}
|
|
|
|
|
|
-static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
int gpucount = 0;
|
|
|
@@ -1003,7 +1026,7 @@ static void cpustatus(int cpu, bool isjson)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int devcount = 0;
|
|
|
int numgpu = 0;
|
|
|
@@ -1069,7 +1092,7 @@ static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b
|
|
|
}
|
|
|
|
|
|
#ifdef HAVE_OPENCL
|
|
|
-static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int id;
|
|
|
|
|
|
@@ -1103,7 +1126,7 @@ static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
}
|
|
|
#endif
|
|
|
#ifdef HAVE_AN_FPGA
|
|
|
-static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int numpga = numpgas();
|
|
|
int id;
|
|
|
@@ -1137,7 +1160,7 @@ static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcat(io_buffer, JSON_CLOSE);
|
|
|
}
|
|
|
|
|
|
-static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int numpga = numpgas();
|
|
|
struct thr_info *thr;
|
|
|
@@ -1193,7 +1216,7 @@ static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_PGAENA, id, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int numpga = numpgas();
|
|
|
int id;
|
|
|
@@ -1234,7 +1257,7 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
#endif
|
|
|
|
|
|
#ifdef WANT_CPUMINE
|
|
|
-static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int id;
|
|
|
|
|
|
@@ -1268,7 +1291,7 @@ static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
char *status, *lp;
|
|
|
@@ -1345,7 +1368,7 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|
|
strcat(io_buffer, JSON_CLOSE);
|
|
|
}
|
|
|
|
|
|
-static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
double utility, mhs;
|
|
|
|
|
|
@@ -1379,7 +1402,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
|
|
|
#endif
|
|
|
}
|
|
|
#ifdef HAVE_OPENCL
|
|
|
-static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
struct thr_info *thr;
|
|
|
int gpu;
|
|
|
@@ -1425,7 +1448,7 @@ static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_GPUREN, id, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int id;
|
|
|
|
|
|
@@ -1455,7 +1478,7 @@ static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_GPUDIS, id, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int id;
|
|
|
|
|
|
@@ -1480,7 +1503,7 @@ static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_GPUREI, id, NULL, isjson));
|
|
|
}
|
|
|
#endif
|
|
|
-static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
int numgpu = 0;
|
|
|
@@ -1499,8 +1522,7 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
|
|
|
strcat(io_buffer, buf);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
int count = 0;
|
|
|
@@ -1519,7 +1541,7 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
|
|
|
strcat(io_buffer, buf);
|
|
|
}
|
|
|
|
|
|
-static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
int count = 0;
|
|
|
@@ -1538,7 +1560,7 @@ static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
|
|
|
strcat(io_buffer, buf);
|
|
|
}
|
|
|
|
|
|
-static void switchpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void switchpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
struct pool *pool;
|
|
|
int id;
|
|
|
@@ -1619,7 +1641,7 @@ exitsama:
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char *url, *user, *pass;
|
|
|
char *ptr;
|
|
|
@@ -1647,7 +1669,7 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
ptr = NULL;
|
|
|
}
|
|
|
|
|
|
-static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
struct pool *pool;
|
|
|
int id;
|
|
|
@@ -1681,7 +1703,7 @@ static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_ENAPOOL, id, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
struct pool *pool;
|
|
|
int id;
|
|
|
@@ -1720,7 +1742,7 @@ static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_DISPOOL, id, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-static void removepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void removepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
struct pool *pool;
|
|
|
char *rpc_url;
|
|
|
@@ -1806,7 +1828,7 @@ static bool splitgpuvalue(char *param, int *gpu, char **value, bool isjson)
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
-static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int id;
|
|
|
char *value;
|
|
|
@@ -1835,7 +1857,7 @@ static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
strcpy(io_buffer, message(MSG_GPUINT, id, intensitystr, isjson));
|
|
|
}
|
|
|
|
|
|
-static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
#ifdef HAVE_ADL
|
|
|
int id;
|
|
|
@@ -1856,7 +1878,7 @@ static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
#ifdef HAVE_ADL
|
|
|
int id;
|
|
|
@@ -1877,7 +1899,7 @@ static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
#ifdef HAVE_ADL
|
|
|
int id;
|
|
|
@@ -1898,7 +1920,7 @@ static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
#ifdef HAVE_ADL
|
|
|
int id;
|
|
|
@@ -1919,7 +1941,7 @@ static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
|
|
|
#endif
|
|
|
}
|
|
|
#endif
|
|
|
-void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
if (isjson)
|
|
|
strcpy(io_buffer, JSON_START JSON_BYE);
|
|
|
@@ -1930,7 +1952,7 @@ void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson
|
|
|
do_a_quit = true;
|
|
|
}
|
|
|
|
|
|
-void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
if (isjson)
|
|
|
strcpy(io_buffer, JSON_START JSON_RESTART);
|
|
|
@@ -1941,12 +1963,12 @@ void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isj
|
|
|
do_a_restart = true;
|
|
|
}
|
|
|
|
|
|
-void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
strcpy(io_buffer, message(MSG_ACCOK, 0, NULL, isjson));
|
|
|
}
|
|
|
|
|
|
-void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
|
|
|
+void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
char *reason;
|
|
|
@@ -2000,7 +2022,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
|
|
|
strcat(io_buffer, buf);
|
|
|
}
|
|
|
|
|
|
-static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
@@ -2017,13 +2039,13 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < total_devices; i++)
|
|
|
- notifystatus(i, devices[i], isjson);
|
|
|
+ notifystatus(i, devices[i], isjson, group);
|
|
|
|
|
|
if (isjson)
|
|
|
strcat(io_buffer, JSON_CLOSE);
|
|
|
}
|
|
|
|
|
|
-static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char buf[TMPBUFSIZ];
|
|
|
struct cgpu_info *cgpu;
|
|
|
@@ -2059,7 +2081,7 @@ static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|
|
strcat(io_buffer, JSON_CLOSE);
|
|
|
}
|
|
|
|
|
|
-void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|
|
+void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char filename[PATH_MAX];
|
|
|
FILE *fcfg;
|
|
|
@@ -2135,7 +2157,8 @@ static int itemstats(int i, char *id, struct cgminer_stats *stats, struct cgmine
|
|
|
|
|
|
return i;
|
|
|
}
|
|
|
-static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+
|
|
|
+static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
|
|
|
{
|
|
|
char extra[TMPBUFSIZ];
|
|
|
char id[20];
|
|
|
@@ -2174,10 +2197,12 @@ static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|
|
strcat(io_buffer, JSON_CLOSE);
|
|
|
}
|
|
|
|
|
|
+static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
|
|
|
+
|
|
|
struct CMDS {
|
|
|
char *name;
|
|
|
- void (*func)(SOCKETTYPE, char *, bool);
|
|
|
- bool requires_writemode;
|
|
|
+ void (*func)(SOCKETTYPE, char *, bool, char);
|
|
|
+ bool iswritemode;
|
|
|
} cmds[] = {
|
|
|
{ "version", apiversion, false },
|
|
|
{ "config", minerconfig, false },
|
|
|
@@ -2220,9 +2245,50 @@ struct CMDS {
|
|
|
{ "devdetails", devdetails, false },
|
|
|
{ "restart", dorestart, true },
|
|
|
{ "stats", minerstats, false },
|
|
|
+ { "check", checkcommand, false },
|
|
|
{ NULL, NULL, false }
|
|
|
};
|
|
|
|
|
|
+static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group)
|
|
|
+{
|
|
|
+ char buf[TMPBUFSIZ];
|
|
|
+ char cmdbuf[100];
|
|
|
+ bool found, access;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (param == NULL || *param == '\0') {
|
|
|
+ strcpy(io_buffer, message(MSG_MISCHK, 0, NULL, isjson));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ found = false;
|
|
|
+ access = false;
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++) {
|
|
|
+ if (strcmp(cmds[i].name, param) == 0) {
|
|
|
+ found = true;
|
|
|
+
|
|
|
+ sprintf(cmdbuf, "|%s|", param);
|
|
|
+ if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf))
|
|
|
+ access = true;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ strcpy(io_buffer, message(MSG_CHECK, 0, NULL, isjson));
|
|
|
+
|
|
|
+ sprintf(buf, isjson
|
|
|
+ ? "," JSON_CHECK "{\"Exists\":\"%s\",\"Access\":\"%s\"}" JSON_CLOSE
|
|
|
+ : _CHECK ",Exists=%s,Access=%s" SEPSTR,
|
|
|
+ found ? YES : NO,
|
|
|
+ access ? YES : NO);
|
|
|
+
|
|
|
+ strcat(io_buffer, buf);
|
|
|
+
|
|
|
+ if (isjson)
|
|
|
+ strcat(io_buffer, JSON_CLOSE);
|
|
|
+}
|
|
|
+
|
|
|
static void send_result(SOCKETTYPE c, bool isjson)
|
|
|
{
|
|
|
int n;
|
|
|
@@ -2277,7 +2343,154 @@ static void tidyup(__maybe_unused void *arg)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Interpret [R|W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option
|
|
|
+ * Interpret --api-groups G:cmd1:cmd2:cmd3,P:cmd4,*,...
|
|
|
+ */
|
|
|
+static void setup_groups()
|
|
|
+{
|
|
|
+ char *buf, *ptr, *next, *colon;
|
|
|
+ char group;
|
|
|
+ char commands[TMPBUFSIZ];
|
|
|
+ char cmdbuf[100];
|
|
|
+ char *cmd;
|
|
|
+ bool addstar, did;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ buf = malloc(strlen(opt_api_groups) + 1);
|
|
|
+ if (unlikely(!buf))
|
|
|
+ quit(1, "Failed to malloc ipgroups buf");
|
|
|
+
|
|
|
+ strcpy(buf, opt_api_groups);
|
|
|
+
|
|
|
+ next = buf;
|
|
|
+ // for each group defined
|
|
|
+ while (next && *next) {
|
|
|
+ ptr = next;
|
|
|
+ next = strchr(ptr, ',');
|
|
|
+ if (next)
|
|
|
+ *(next++) = '\0';
|
|
|
+
|
|
|
+ // Validate the group
|
|
|
+ if (*(ptr+1) != ':') {
|
|
|
+ colon = strchr(ptr, ':');
|
|
|
+ if (colon)
|
|
|
+ *colon = '\0';
|
|
|
+ applog(LOG_WARNING, "API invalid group name '%s'%s", ptr, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+
|
|
|
+ group = GROUP(*ptr);
|
|
|
+ if (!VALIDGROUP(group)) {
|
|
|
+ applog(LOG_WARNING, "API invalid group name '%c'%s", *ptr, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (group == PRIVGROUP) {
|
|
|
+ applog(LOG_WARNING, "API group name can't be '%c'%s", PRIVGROUP, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (group == NOPRIVGROUP) {
|
|
|
+ applog(LOG_WARNING, "API group name can't be '%c'%s", NOPRIVGROUP, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (apigroups[GROUPOFFSET(group)].commands != NULL) {
|
|
|
+ applog(LOG_WARNING, "API duplicate group name '%c'%s", *ptr, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr += 2;
|
|
|
+
|
|
|
+ // Validate the command list (and handle '*')
|
|
|
+ cmd = &(commands[0]);
|
|
|
+ *(cmd++) = SEPARATOR;
|
|
|
+ *cmd = '\0';
|
|
|
+ addstar = false;
|
|
|
+ while (ptr && *ptr) {
|
|
|
+ colon = strchr(ptr, ':');
|
|
|
+ if (colon)
|
|
|
+ *(colon++) = '\0';
|
|
|
+
|
|
|
+ if (strcmp(ptr, "*") == 0)
|
|
|
+ addstar = true;
|
|
|
+ else {
|
|
|
+ did = false;
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++) {
|
|
|
+ if (strcasecmp(ptr, cmds[i].name) == 0) {
|
|
|
+ did = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (did) {
|
|
|
+ // skip duplicates
|
|
|
+ sprintf(cmdbuf, "|%s|", cmds[i].name);
|
|
|
+ if (strstr(commands, cmdbuf) == NULL) {
|
|
|
+ strcpy(cmd, cmds[i].name);
|
|
|
+ cmd += strlen(cmds[i].name);
|
|
|
+ *(cmd++) = SEPARATOR;
|
|
|
+ *cmd = '\0';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ applog(LOG_WARNING, "API unknown command '%s' in group '%c'%s", ptr, group, GROUPDIS);
|
|
|
+ goto shin;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr = colon;
|
|
|
+ }
|
|
|
+
|
|
|
+ // * = allow all non-iswritemode commands
|
|
|
+ if (addstar) {
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++) {
|
|
|
+ if (cmds[i].iswritemode == false) {
|
|
|
+ // skip duplicates
|
|
|
+ sprintf(cmdbuf, "|%s|", cmds[i].name);
|
|
|
+ if (strstr(commands, cmdbuf) == NULL) {
|
|
|
+ strcpy(cmd, cmds[i].name);
|
|
|
+ cmd += strlen(cmds[i].name);
|
|
|
+ *(cmd++) = SEPARATOR;
|
|
|
+ *cmd = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr = apigroups[GROUPOFFSET(group)].commands = malloc(strlen(commands) + 1);
|
|
|
+ if (unlikely(!ptr))
|
|
|
+ quit(1, "Failed to malloc group commands buf");
|
|
|
+
|
|
|
+ strcpy(ptr, commands);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now define R (NOPRIVGROUP) as all non-iswritemode commands
|
|
|
+ cmd = &(commands[0]);
|
|
|
+ *(cmd++) = SEPARATOR;
|
|
|
+ *cmd = '\0';
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++) {
|
|
|
+ if (cmds[i].iswritemode == false) {
|
|
|
+ strcpy(cmd, cmds[i].name);
|
|
|
+ cmd += strlen(cmds[i].name);
|
|
|
+ *(cmd++) = SEPARATOR;
|
|
|
+ *cmd = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr = apigroups[GROUPOFFSET(NOPRIVGROUP)].commands = malloc(strlen(commands) + 1);
|
|
|
+ if (unlikely(!ptr))
|
|
|
+ quit(1, "Failed to malloc noprivgroup commands buf");
|
|
|
+
|
|
|
+ strcpy(ptr, commands);
|
|
|
+
|
|
|
+ // W (PRIVGROUP) is handled as a special case since it simply means all commands
|
|
|
+
|
|
|
+ groups_enabled = true;
|
|
|
+shin:
|
|
|
+ free(buf);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Interpret [W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option
|
|
|
* special case of 0/0 allows /0 (means all IP addresses)
|
|
|
*/
|
|
|
#define ALLIP4 "0/0"
|
|
|
@@ -2288,7 +2501,7 @@ static void setup_ipaccess()
|
|
|
{
|
|
|
char *buf, *ptr, *comma, *slash, *dot;
|
|
|
int ipcount, mask, octet, i;
|
|
|
- bool writemode;
|
|
|
+ char group;
|
|
|
|
|
|
buf = malloc(strlen(opt_api_allow) + 1);
|
|
|
if (unlikely(!buf))
|
|
|
@@ -2322,16 +2535,16 @@ static void setup_ipaccess()
|
|
|
if (comma)
|
|
|
*(comma++) = '\0';
|
|
|
|
|
|
- writemode = false;
|
|
|
+ group = NOPRIVGROUP;
|
|
|
|
|
|
if (isalpha(*ptr) && *(ptr+1) == ':') {
|
|
|
- if (tolower(*ptr) == 'w')
|
|
|
- writemode = true;
|
|
|
+ if (DEFINEDGROUP(*ptr))
|
|
|
+ group = GROUP(*ptr);
|
|
|
|
|
|
ptr += 2;
|
|
|
}
|
|
|
|
|
|
- ipaccess[ips].writemode = writemode;
|
|
|
+ ipaccess[ips].group = group;
|
|
|
|
|
|
if (strcmp(ptr, ALLIP4) == 0)
|
|
|
ipaccess[ips].ip = ipaccess[ips].mask = 0;
|
|
|
@@ -2421,10 +2634,11 @@ void api(int api_thr_id)
|
|
|
struct sockaddr_in serv;
|
|
|
struct sockaddr_in cli;
|
|
|
socklen_t clisiz;
|
|
|
+ char cmdbuf[100];
|
|
|
char *cmd;
|
|
|
char *param;
|
|
|
bool addrok;
|
|
|
- bool writemode;
|
|
|
+ char group;
|
|
|
json_error_t json_err;
|
|
|
json_t *json_config;
|
|
|
json_t *json_val;
|
|
|
@@ -2445,6 +2659,9 @@ void api(int api_thr_id)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ if (opt_api_groups)
|
|
|
+ setup_groups();
|
|
|
+
|
|
|
if (opt_api_allow) {
|
|
|
setup_ipaccess();
|
|
|
|
|
|
@@ -2523,15 +2740,16 @@ void api(int api_thr_id)
|
|
|
connectaddr = inet_ntoa(cli.sin_addr);
|
|
|
|
|
|
addrok = false;
|
|
|
- writemode = false;
|
|
|
+ group = NOPRIVGROUP;
|
|
|
if (opt_api_allow) {
|
|
|
- for (i = 0; i < ips; i++) {
|
|
|
- if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) {
|
|
|
- addrok = true;
|
|
|
- writemode = ipaccess[i].writemode;
|
|
|
- break;
|
|
|
+ if (groups_enabled)
|
|
|
+ for (i = 0; i < ips; i++) {
|
|
|
+ if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) {
|
|
|
+ addrok = true;
|
|
|
+ group = ipaccess[i].group;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
} else {
|
|
|
if (opt_api_network)
|
|
|
addrok = true;
|
|
|
@@ -2622,12 +2840,13 @@ void api(int api_thr_id)
|
|
|
if (!did)
|
|
|
for (i = 0; cmds[i].name != NULL; i++) {
|
|
|
if (strcmp(cmd, cmds[i].name) == 0) {
|
|
|
- if (cmds[i].requires_writemode && !writemode) {
|
|
|
+ sprintf(cmdbuf, "|%s|", cmd);
|
|
|
+ if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf))
|
|
|
+ (cmds[i].func)(c, param, isjson, group);
|
|
|
+ else {
|
|
|
strcpy(io_buffer, message(MSG_ACCDENY, 0, cmds[i].name, isjson));
|
|
|
applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name);
|
|
|
}
|
|
|
- else
|
|
|
- (cmds[i].func)(c, param, isjson);
|
|
|
|
|
|
send_result(c, isjson);
|
|
|
did = true;
|