OpenVAS Scanner  7.0.1~git
nasl_snmp.c
Go to the documentation of this file.
1 /* Copyright (C) 2014-2019 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
25 #ifdef HAVE_NETSNMP
26 
27 #include "../misc/plugutils.h"
28 #include "nasl_lex_ctxt.h"
29 
30 #include <assert.h>
31 #include <gvm/base/logging.h>
32 #include <net-snmp/net-snmp-config.h>
33 #include <net-snmp/net-snmp-includes.h>
34 
35 /*
36  * @brief SNMP Get query value.
37  *
38  * param[in] session SNMP session.
39  * param[in] oid_str OID string.
40  * param[out] result Result of query.
41  *
42  * @return 0 if success and result value, -1 otherwise.
43  */
44 static int
45 snmp_get (struct snmp_session *session, const char *oid_str, char **result)
46 {
47  struct snmp_session *ss;
48  struct snmp_pdu *query, *response;
49  oid oid_buf[MAX_OID_LEN];
50  size_t oid_size = MAX_OID_LEN;
51  int status;
52 
53  ss = snmp_open (session);
54  if (!ss)
55  {
56  snmp_error (session, &status, &status, result);
57  return -1;
58  }
59  query = snmp_pdu_create (SNMP_MSG_GET);
60  read_objid (oid_str, oid_buf, &oid_size);
61  snmp_add_null_var (query, oid_buf, oid_size);
62  status = snmp_synch_response (ss, query, &response);
63  if (status != STAT_SUCCESS)
64  {
65  snmp_error (ss, &status, &status, result);
66  snmp_close (ss);
67  return -1;
68  }
69  snmp_close (ss);
70 
71  if (response->errstat == SNMP_ERR_NOERROR)
72  {
73  struct variable_list *vars = response->variables;
74  size_t res_len = 0, buf_len = 0;
75 
76  netsnmp_ds_set_boolean (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT,
77  1);
78  sprint_realloc_value ((u_char **) result, &buf_len, &res_len, 1,
79  vars->name, vars->name_length, vars);
80  snmp_free_pdu (response);
81  return 0;
82  }
83  *result = g_strdup (snmp_errstring (response->errstat));
84  snmp_free_pdu (response);
85  return -1;
86 }
87 
88 /*
89  * @brief SNMPv3 Get query value.
90  *
91  * param[in] peername Target host in [protocol:]address[:port] format.
92  * param[in] username Username value.
93  * param[in] authpass Authentication password.
94  * param[in] authproto Authentication protocol. 0 for md5, 1 for sha1.
95  * param[in] privpass Privacy password.
96  * param[in] privproto Privacy protocol. 0 for des, 1 for aes.
97  * param[in] oid_str OID of value to get.
98  * param[out] result Result of query.
99  *
100  * @return 0 if success and result value, -1 otherwise.
101  */
102 static int
103 snmpv3_get (const char *peername, const char *username, const char *authpass,
104  int authproto, const char *privpass, int privproto,
105  const char *oid_str, char **result)
106 {
107  struct snmp_session session;
108 
109  assert (peername);
110  assert (username);
111  assert (authpass);
112  assert (authproto == 0 || authproto == 1);
113  assert (oid_str);
114  assert (result);
115 
116  setenv ("MIBS", "", 1);
117  init_snmp ("openvas");
118  snmp_sess_init (&session);
119  session.version = SNMP_VERSION_3;
120  session.peername = (char *) peername;
121  session.securityName = (char *) username;
122  session.securityNameLen = strlen (session.securityName);
123 
124  if (privpass)
125  session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
126  else
127  session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
128  if (authproto == 0)
129  {
130  session.securityAuthProto = usmHMACMD5AuthProtocol;
131  session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
132  }
133  else
134  {
135  session.securityAuthProto = usmHMACSHA1AuthProtocol;
136  session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
137  }
138  session.securityAuthKeyLen = USM_AUTH_KU_LEN;
139  if (generate_Ku (session.securityAuthProto, session.securityAuthProtoLen,
140  (u_char *) authpass, strlen (authpass),
141  session.securityAuthKey, &session.securityAuthKeyLen)
142  != SNMPERR_SUCCESS)
143  {
144  *result = g_strdup ("generate_Ku: Error");
145  return -1;
146  }
147  if (privpass)
148  {
149  if (privproto)
150  {
151  session.securityPrivProto = usmAESPrivProtocol;
152  session.securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
153  }
154  else
155  {
156  session.securityPrivProto = usmDESPrivProtocol;
157  session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
158  }
159  session.securityPrivKeyLen = USM_PRIV_KU_LEN;
160  if (generate_Ku (session.securityAuthProto, session.securityAuthProtoLen,
161  (unsigned char *) privpass, strlen (privpass),
162  session.securityPrivKey, &session.securityPrivKeyLen)
163  != SNMPERR_SUCCESS)
164  {
165  *result = g_strdup ("generate_Ku: Error");
166  return -1;
167  }
168  }
169 
170  return snmp_get (&session, oid_str, result);
171 }
172 
173 /*
174  * @brief SNMP v1 or v2c Get query value.
175  *
176  * param[in] peername Target host in [protocol:]address[:port] format.
177  * param[in] community SNMP community string.
178  * param[in] oid_str OID string of value to get.
179  * param[in] version SNMP_VERSION_1 or SNMP_VERSION_2c.
180  * param[out] result Result of query.
181  *
182  * @return 0 if success and result value, -1 otherwise.
183  */
184 static int
185 snmpv1v2c_get (const char *peername, const char *community, const char *oid_str,
186  int version, char **result)
187 {
188  struct snmp_session session;
189 
190  assert (peername);
191  assert (community);
192  assert (oid_str);
193  assert (version == SNMP_VERSION_1 || version == SNMP_VERSION_2c);
194 
195  setenv ("MIBS", "", 1);
196  snmp_sess_init (&session);
197  session.version = version;
198  session.peername = (char *) peername;
199  session.community = (u_char *) community;
200  session.community_len = strlen (community);
201 
202  return snmp_get (&session, oid_str, result);
203 }
204 
205 /*
206  * @brief Check that protocol value is valid.
207  *
208  * param[in] proto Protocol string.
209  *
210  * @return 1 if proto is udp, udp6, tcp or tcp6. 0 otherwise.
211  */
212 static int
213 proto_is_valid (const char *proto)
214 {
215  if (strcmp (proto, "tcp") && strcmp (proto, "udp") && strcmp (proto, "tcp6")
216  && strcmp (proto, "udp6"))
217  return 0;
218  return 1;
219 }
220 
221 /*
222  * @brief Create a NASL array from a snmp result.
223  *
224  * param[in] ret Return value.
225  * param[in] result Result string.
226  *
227  * @return NASL array.
228  */
229 static tree_cell *
230 array_from_snmp_result (int ret, char *result)
231 {
232  anon_nasl_var v;
233 
234  assert (result);
236  retc->x.ref_val = g_malloc0 (sizeof (nasl_array));
237  /* Return code */
238  memset (&v, 0, sizeof (v));
239  v.var_type = VAR2_INT;
240  v.v.v_int = ret;
241  add_var_to_list (retc->x.ref_val, 0, &v);
242  /* Return value */
243  memset (&v, 0, sizeof v);
244  v.var_type = VAR2_STRING;
245  v.v.v_str.s_val = (unsigned char *) result;
246  v.v.v_str.s_siz = strlen (result);
247  add_var_to_list (retc->x.ref_val, 1, &v);
248 
249  return retc;
250 }
251 
252 tree_cell *
253 nasl_snmpv1v2c_get (lex_ctxt *lexic, int version)
254 {
255  const char *proto, *community, *oid_str;
256  char *result = NULL, peername[2048];
257  int port, ret;
258 
259  port = get_int_var_by_name (lexic, "port", -1);
260  proto = get_str_var_by_name (lexic, "protocol");
261  community = get_str_var_by_name (lexic, "community");
262  oid_str = get_str_var_by_name (lexic, "oid");
263  if (!proto || !community || !oid_str)
264  return array_from_snmp_result (-2, "Missing function argument");
265  if (port < 0 || port > 65535)
266  return array_from_snmp_result (-2, "Invalid port value");
267  if (!proto_is_valid (proto))
268  return array_from_snmp_result (-2, "Invalid protocol value");
269 
270  g_snprintf (peername, sizeof (peername), "%s:%s:%d", proto,
271  plug_get_host_ip_str (lexic->script_infos), port);
272  ret = snmpv1v2c_get (peername, community, oid_str, version, &result);
273  return array_from_snmp_result (ret, result);
274 }
275 
276 tree_cell *
277 nasl_snmpv1_get (lex_ctxt *lexic)
278 {
279  return nasl_snmpv1v2c_get (lexic, SNMP_VERSION_1);
280 }
281 
282 tree_cell *
283 nasl_snmpv2c_get (lex_ctxt *lexic)
284 {
285  return nasl_snmpv1v2c_get (lexic, SNMP_VERSION_2c);
286 }
287 
288 tree_cell *
289 nasl_snmpv3_get (lex_ctxt *lexic)
290 {
291  const char *proto, *username, *authpass, *authproto, *oid_str;
292  const char *privpass, *privproto;
293  char *result = NULL, peername[2048];
294  int port, ret, aproto, pproto = 0;
295 
296  port = get_int_var_by_name (lexic, "port", -1);
297  proto = get_str_var_by_name (lexic, "protocol");
298  username = get_str_var_by_name (lexic, "username");
299  authpass = get_str_var_by_name (lexic, "authpass");
300  oid_str = get_str_var_by_name (lexic, "oid");
301  authproto = get_str_var_by_name (lexic, "authproto");
302  privpass = get_str_var_by_name (lexic, "privpass");
303  privproto = get_str_var_by_name (lexic, "privproto");
304  if (!proto || !username || !authpass || !oid_str || !authproto)
305  return array_from_snmp_result (-2, "Missing function argument");
306  if (port < 0 || port > 65535)
307  return array_from_snmp_result (-2, "Invalid port value");
308  if (!proto_is_valid (proto))
309  return array_from_snmp_result (-2, "Invalid protocol value");
310  if ((privpass && !privproto) || (!privpass && privproto))
311  return array_from_snmp_result (-2, "Missing privproto or privpass");
312  if (!strcasecmp (authproto, "md5"))
313  aproto = 0;
314  else if (!strcasecmp (authproto, "sha1"))
315  aproto = 1;
316  else
317  return array_from_snmp_result (-2, "authproto should be md5 or sha1");
318  if (privproto)
319  {
320  if (!strcasecmp (privproto, "des"))
321  pproto = 0;
322  else if (!strcasecmp (privproto, "aes"))
323  pproto = 1;
324  else
325  return array_from_snmp_result (-2, "privproto should be des or aes");
326  }
327 
328  g_snprintf (peername, sizeof (peername), "%s:%s:%d", proto,
329  plug_get_host_ip_str (lexic->script_infos), port);
330  ret = snmpv3_get (peername, username, authpass, aproto, privpass, pproto,
331  oid_str, &result);
332  return array_from_snmp_result (ret, result);
333 }
334 
335 #endif /* HAVE_NETSNMP */
const char * oid
void * ref_val
Definition: nasl_tree.h:114
nasl_string_t v_str
Definition: nasl_var.h:58
struct script_infos * script_infos
Definition: nasl_lex_ctxt.h:41
char * get_str_var_by_name(lex_ctxt *, const char *)
Definition: nasl_var.c:1127
int add_var_to_list(nasl_array *a, int i, const anon_nasl_var *v)
Definition: nasl_var.c:1254
tree_cell * alloc_typed_cell(int typ)
Definition: nasl_tree.c:40
int var_type
Definition: nasl_var.h:52
Definition: nasl_tree.h:104
union TC::@2 x
long int get_int_var_by_name(lex_ctxt *, const char *, int)
Definition: nasl_var.c:1113
union st_a_nasl_var::@4 v
char * plug_get_host_ip_str(struct script_infos *desc)
Definition: plugutils.c:291
unsigned char * s_val
Definition: nasl_var.h:37
long int v_int
Definition: nasl_var.h:59