Commit 1726274e authored by Adam Wujek's avatar Adam Wujek 💬

lib/snmp: execute shell command via SNMP

Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parent 89683f4e
......@@ -232,6 +232,13 @@ config SNMP_SDB
help
This option adds a branch wrpcSdbGroup to the SNMP
config SNMP_CMD
depends on SNMP && SNMP_SET
default y
boolean "Allow to run any shell command via SNMP"
help
This option adds a branch wrpcShellCmdGroup to the SNMP
config SNMP_NETCONSOLE
depends on SNMP && NETCONSOLE
default y
......
......@@ -1314,6 +1314,58 @@ WR-WRPC-MIB::wrpcNetconsoleSetApply.0 = INTEGER: applySuccessful(100)
As today there is no possibility to set parameters like MAC, IP and port number
of netconsole's peer via SNMP.
% ==========================================================================
\subsubsection{Run shell command via SNMP}
\label{Run shell command via SNMP}
When options \texttt{CONFIG\_SNMP\_CMD} and \texttt{CONFIG\_SNMP\_SET} are
enabled in a dot-config, it is possible to trigger execution of any shell
command via SNMP.
To trigger an exectuion of a command, the command has to be set to
the OID \texttt{wrpcShellCmdLine.0}. To prevent accidential runs, the magic
number \texttt{44451} (literal \texttt{magic} can be used instead) has to be
set in the OID \texttt{wrpcShellCmdMagic.0}.
Finally, to trigger the execution set the OID \texttt{wrpcShellCmdRun.0} with
value 12 (or literal \texttt{execute}). The last set will return information
whether the triggering of a command was successful or not. To figure out if
the command succeeded, please check the return value stored in the OID
\texttt{wrpcShellCmdReturnCode.0}
The example below shows the execution of \texttt{ip} command via SNMP.
\begin{lstlisting}
$ snmpset $SNMP_OPT wrpcShellCmdLine.0 = "ip"
WR-WRPC-MIB::wrpcShellCmdLine.0 = STRING: ver
$ snmpset $SNMP_OPT wrpcShellCmdMagic.0 = magic
WR-WRPC-MIB::wrpcShellCmdMagic.0 = INTEGER: magic(44451)
$ snmpset $SNMP_OPT wrpcShellCmdRun.0 = execute
WR-WRPC-MIB::wrpcShellCmdRun.0 = INTEGER: executionSuccessful(100)
\end{lstlisting}
To check the return value:
\begin{lstlisting}
$ snmpget $SNMP_OPT WR-WRPC-MIB::wrpcShellCmdReturnCode
WR-WRPC-MIB::wrpcShellCmdReturnCode.0 = INTEGER: 0
\end{lstlisting}
The \texttt{ip} command triggered in the above example caused the following
output on a serial console:
\begin{lstlisting}
Execute command from SNMP: "ip"
IP-address: 192.168.1.20 (from bootp)
\end{lstlisting}
The output of the executed command is printed only on the serial
console\footnote{However, it can be also mirrored to the netconsole.
For details, please check the section~\ref{Netconsole}.}.
As today it cannot be forwarded via SNMP.
\textbf{Note:} the maximum supported length of a command is the same as for
the serial console's shell, which is 80 chars.
\textbf{Note:} Be careful with interactive commands. It is possible to start
such command (e.g. \texttt{gui}) via SNMP, but it is not possible to stop it.
% ==========================================================================
\newpage
\subsection{Syslog}
......
......@@ -897,6 +897,61 @@ wrpcNetconsoleSetApply OBJECT-TYPE
"
::= { wrpcNetconsoleSetGroup 1 }
-- ****************************************************************************
wrpcShellCmdGroup OBJECT IDENTIFIER ::= { wrpcCore 12 }
wrpcShellCmdRun OBJECT-TYPE
SYNTAX INTEGER {
na(0),
execute(12),
executionSuccessful(100),
executionFailed(200),
executionFailedEmptyLine(201)
executionFailedSetMagicTo44451(202)
}
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Run a shell command stored in wrpcShellCmdLine. Before command is run
OID wrpcShellCmdMagic has to be filled with 44451. This oid can have
the following values:
execute - to run the command stored in wrpcShellCmdLine
executionSuccessful - trigger of a command was successful,
but this has no information whether the command itslef was successful!
Check the wrpcShellCmdReturnCode!
executionFailed - failed to trigger the command
executionFailedEmptyLine - empty wrpcShellCmdLine
executionFailedSetMagicTo44451 - wrong magic in wrpcShellCmdMagic
"
::= { wrpcShellCmdGroup 1 }
wrpcShellCmdLine OBJECT-TYPE
SYNTAX DisplayString (SIZE(0..80))
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Specify the command to be run"
::= { wrpcShellCmdGroup 2 }
wrpcShellCmdMagic OBJECT-TYPE
SYNTAX INTEGER {
na(0),
magic(44451)
}
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"To be able to execute command this OID has to contain 44451. After a run of a command this OID is zeroed"
::= { wrpcShellCmdGroup 3 }
wrpcShellCmdReturnCode OBJECT-TYPE
SYNTAX Integer32
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Return code of last executed command"
::= { wrpcShellCmdGroup 4 }
-- ****************************************************************************
END
......@@ -131,6 +131,14 @@
* wrpcPtpConfigApply */
#define applyFailedEmptyParam 201
/* new defines for oid_wrpcShellCmdRun */
#define execute 12
#define executionSuccessful 100
#define executionFailed 200
#define executionFailedEmptyLine 201
#define executionFailedSetMagicTo44451 202
#define shellCmdReturnCodeMAGIC 44451
/* defines for wrpcTemperatureTable */
#define TABLE_ROW 1
#define TABLE_COL 0
......@@ -234,6 +242,12 @@ static int sdb_param = -1;
/* related to wrpcNetconsoleGroup */
static int netconsole_apply_status = 0;
/* related to wrpcShellCmdGroup */
static char shell_cmd_line[SH_MAX_LINE_LEN + 1];
static int shell_cmd_apply_status;
static int shell_cmd_magic;
static int shell_cmd_return_code;
/* Keep the number of aux diag registers available in the FPGA bitstream */
static uint32_t aux_diag_reg_ro_num;
static uint32_t aux_diag_reg_rw_num;
......@@ -286,6 +300,7 @@ static int set_ptp_config(uint8_t *buf, struct snmp_oid *obj);
static int set_init_script_config(uint8_t *buf, struct snmp_oid *obj);
static int set_sdb(uint8_t *buf, struct snmp_oid *obj);
static int set_netconsole(uint8_t *buf, struct snmp_oid *obj);
static int set_shell_cmd(uint8_t *buf, struct snmp_oid *obj);
static int set_aux_diag(uint8_t *buf, struct snmp_oid *obj);
static int data_aux_diag(uint8_t *buf, struct snmp_oid *obj, int mode);
......@@ -306,6 +321,7 @@ static uint8_t oid_wrpcInitScriptConfigGroup[] = {0x2B,6,1,4,1,96,101,1,9};
static uint8_t oid_wrpcSdbGroup[] = {0x2B,6,1,4,1,96,101,1,10};
static uint8_t oid_wrpcNetconsoleGetGroup[] = {0x2B,6,1,4,1,96,101,1,11,1};
static uint8_t oid_wrpcNetconsoleSetGroup[] = {0x2B,6,1,4,1,96,101,1,11,2};
static uint8_t oid_wrpcShellCmdGroup[] = {0x2B,6,1,4,1,96,101,1,12};
/* In below OIDs zeros will be replaced in the snmp_init function by values
* read from FPA */
static uint8_t oid_wrpcAuxRoTable[] = {0x2B,6,1,4,1,96,101,2,0,0,1,1};
......@@ -396,6 +412,12 @@ static uint8_t oid_wrpcNetconsoleGetPeerPort[] = {4,0};
/* oid_wrpcNetconsoleSetGroup */
static uint8_t oid_wrpcNetconsoleSetApply[] = {1,0};
/* oid_wrpcShellCmdGroup */
static uint8_t oid_wrpcShellCmdRun[] = {1,0};
static uint8_t oid_wrpcShellCmdLine[] = {2,0};
static uint8_t oid_wrpcShellCmdMagic[] = {3,0};
static uint8_t oid_wrpcShellCmdReturnCode[] = {4,0};
/* NOTE: to have SNMP_GET_NEXT working properly this array has to be sorted by
OIDs */
/* wrpcVersionGroup */
......@@ -520,6 +542,15 @@ static struct snmp_oid oid_array_wrpcNetconsoleSetGroup[] = {
{ 0, }
};
/* wrpcShellCmdGroup */
static struct snmp_oid oid_array_wrpcShellCmdGroup[] = {
OID_FIELD_VAR( oid_wrpcShellCmdRun, get_p, set_shell_cmd, ASN_INTEGER, &shell_cmd_apply_status),
OID_FIELD_VAR( oid_wrpcShellCmdLine, get_p, set_p, ASN_OCTET_STR, &shell_cmd_line),
OID_FIELD_VAR( oid_wrpcShellCmdMagic, get_p, set_p, ASN_INTEGER, &shell_cmd_magic),
OID_FIELD_VAR( oid_wrpcShellCmdReturnCode, get_p, set_p, ASN_INTEGER, &shell_cmd_return_code),
{ 0, }
};
static struct snmp_oid oid_array_wrpcAuxRoTable[] = {
OID_FIELD_VAR(NULL, get_aux_diag, NO_SET, ASN_UNSIGNED, AUX_DIAG_RO),
{ 0, }
......@@ -553,6 +584,9 @@ static struct snmp_oid_limb oid_limb_array[] = {
#if defined(CONFIG_SNMP_NETCONSOLE) && defined(CONFIG_SNMP_SET)
OID_LIMB_FIELD(oid_wrpcNetconsoleSetGroup, func_group, oid_array_wrpcNetconsoleSetGroup),
#endif
#if defined(CONFIG_SNMP_CMD) && defined(CONFIG_SNMP_SET)
OID_LIMB_FIELD(oid_wrpcShellCmdGroup, func_group, oid_array_wrpcShellCmdGroup),
#endif
#ifdef CONFIG_SNMP_AUX_DIAG
OID_LIMB_FIELD(oid_wrpcAuxRoTable, func_aux_diag, oid_array_wrpcAuxRoTable),
OID_LIMB_FIELD(oid_wrpcAuxRwTable, func_aux_diag, oid_array_wrpcAuxRwTable),
......@@ -1597,6 +1631,49 @@ static int set_netconsole(uint8_t *buf, struct snmp_oid *obj)
return ret;
}
static int set_shell_cmd(uint8_t *buf, struct snmp_oid *obj)
{
int ret;
int32_t *apply_mode;
apply_mode = obj->p;
ret = set_value(buf, obj, apply_mode);
if (ret <= 0)
return ret;
snmp_verbose("%s enter\n", __func__);
switch (*apply_mode) {
case execute:
if (shell_cmd_line[0]=='\0') {
snmp_verbose("%s empty command\n", __func__);
*apply_mode = executionFailedEmptyLine;
break;
}
if (shell_cmd_magic != shellCmdReturnCodeMAGIC) {
snmp_verbose("%s wrong magic %d in "
"wrpcShellCmdMagic\n",
__func__, shell_cmd_magic);
*apply_mode = executionFailedSetMagicTo44451;
break;
}
pp_printf("Execute command from SNMP: \"%s\"\n",
shell_cmd_line);
/* make sure cmd is null terminated */
shell_cmd_line[SH_MAX_LINE_LEN] = '\0';
shell_cmd_return_code = shell_exec(shell_cmd_line);
/* clean shell_cmd_magic */
shell_cmd_magic = 0;
*apply_mode = applySuccessful;
break;
default:
*apply_mode = executionFailed;
}
return ret;
}
/*
* Perverse... snmpwalk does getnext anyways.
*
......@@ -1777,6 +1854,8 @@ static int snmp_respond(uint8_t *buf)
(void) oid_wrpcNetconsoleGetGroup;
oid_array_wrpcNetconsoleSetGroup[0].oid_len = 0;
(void) oid_wrpcNetconsoleSetGroup;
oid_array_wrpcShellCmdGroup[0].oid_len = 0;
(void) oid_wrpcShellCmdGroup;
}
for (a_i = 0, h_i = 0; a_i < sizeof(match_array); a_i++, h_i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment