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