forked from osmocom/wireshark
412 lines
9.5 KiB
Plaintext
412 lines
9.5 KiB
Plaintext
%option noyywrap
|
|
%option nounput
|
|
%option prefix="Snmp_UE_file_"
|
|
%option never-interactive
|
|
%option caseless
|
|
|
|
%{
|
|
/*
|
|
* load_snmp_users_file.l
|
|
*
|
|
* User-based Security Model for SNMPv3
|
|
* SNMP user-engine association file parser
|
|
*
|
|
* Copyright 2007, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
|
|
#include <glib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
#include <epan/tvbuff.h>
|
|
#include <epan/proto.h>
|
|
#include <epan/packet_info.h>
|
|
#include <epan/emem.h>
|
|
|
|
#include <epan/dissectors/packet-snmp.h>
|
|
|
|
#define AUTH_MD5 1
|
|
#define AUTH_SHA 2
|
|
#define PRIV_DES 4
|
|
#define PRIV_AES 5
|
|
|
|
static GString* error;
|
|
static GArray* assoc_arr = NULL;
|
|
|
|
static guint8* engine = NULL;
|
|
static guint engine_len = 0;
|
|
static guint8* user = NULL;
|
|
static guint user_len = 0;
|
|
static guint8* auth_password = NULL;
|
|
static guint auth_password_len = 0;
|
|
static guint8* priv_password = NULL;
|
|
static guint priv_password_len = 0;
|
|
static int auth = AUTH_MD5;
|
|
static int enc = PRIV_DES;
|
|
static guint linenum = 0;
|
|
static const gchar* filename = "";
|
|
static guint loaded = 0;
|
|
|
|
static void add_engine(void);
|
|
static guint8* unhexbytes(const char* s, guint len, guint* len_p);
|
|
static guint8* undquote(const char* s, guint in_len, guint* len_p);
|
|
|
|
static snmp_usm_auth_model_t model_md5 = {snmp_usm_password_to_key_md5, snmp_usm_auth_md5, 16};
|
|
static snmp_usm_auth_model_t model_sha1 = {snmp_usm_password_to_key_sha1, snmp_usm_auth_sha1, 20};
|
|
|
|
#define ERR(str)
|
|
#define START_LINE() { \
|
|
linenum++; \
|
|
engine = NULL;\
|
|
engine_len = 0;\
|
|
user = NULL;\
|
|
user_len = 0;\
|
|
auth_password = NULL;\
|
|
auth_password_len = 0;\
|
|
priv_password = NULL;\
|
|
priv_password_len = 0;\
|
|
auth = AUTH_MD5;\
|
|
enc = PRIV_DES;\
|
|
BEGIN START_ENGINE;\
|
|
}
|
|
|
|
%}
|
|
|
|
hex_bytes [0-9A-Fa-f]+
|
|
quoted_string \042([^\042]|\134\042)*\042
|
|
any_engine \052
|
|
whitespace [ \t]+
|
|
newline [\r]?\n
|
|
dash -
|
|
des [dD][Ee][Ss]
|
|
aes [aA][Ee][Ss]
|
|
md5 [mM][dD]5
|
|
sha [sS][hH][aA][1]?
|
|
comment [ \t]*\043[^\n]*\n
|
|
|
|
%START START_ENGINE STOP_ENGINE
|
|
%START START_USER STOP_USER
|
|
%START START_AUTHPASSWORD STOP_AUTHPASSWORD
|
|
%START START_PRIVPASSWORD STOP_PRIVPASSWORD
|
|
%START ATTRIBUTES
|
|
%START ERRORED
|
|
%%
|
|
|
|
<ERRORED>. ;
|
|
<ERRORED>{newline} { START_LINE(); }
|
|
|
|
<START_ENGINE>{newline} { START_LINE(); }
|
|
<START_ENGINE>{comment} { START_LINE(); }
|
|
|
|
<START_ENGINE>{quoted_string} { engine = undquote(yytext, yyleng, &engine_len); BEGIN STOP_ENGINE; }
|
|
<START_ENGINE>{hex_bytes} { engine = unhexbytes(yytext, yyleng, &engine_len); BEGIN STOP_ENGINE; }
|
|
<START_ENGINE>{any_engine} { engine = NULL; engine_len = 0; BEGIN STOP_ENGINE; }
|
|
<START_ENGINE>. { ERR("Invalid engineId"); }
|
|
|
|
<STOP_ENGINE>{whitespace} { BEGIN START_USER; }
|
|
|
|
<START_USER>{quoted_string} { user = undquote(yytext, yyleng,&user_len); BEGIN STOP_USER; }
|
|
<START_USER>{hex_bytes} { user = unhexbytes(yytext, yyleng, &user_len); BEGIN STOP_USER; }
|
|
<START_USER>. { ERR("Invalid userName"); }
|
|
|
|
<STOP_USER>{whitespace} { BEGIN START_AUTHPASSWORD; }
|
|
|
|
<START_AUTHPASSWORD>{quoted_string} { auth_password = undquote(yytext, yyleng, &auth_password_len); BEGIN STOP_AUTHPASSWORD; }
|
|
<START_AUTHPASSWORD>{hex_bytes} { auth_password = unhexbytes(yytext, yyleng, &auth_password_len); BEGIN STOP_AUTHPASSWORD; }
|
|
<START_AUTHPASSWORD>. { ERR("Invalid authPassword"); }
|
|
|
|
<STOP_AUTHPASSWORD>{whitespace} { BEGIN START_PRIVPASSWORD; }
|
|
|
|
<START_PRIVPASSWORD>{quoted_string} { priv_password = undquote(yytext, yyleng, &priv_password_len); BEGIN STOP_PRIVPASSWORD; }
|
|
<START_PRIVPASSWORD>{hex_bytes} { priv_password = unhexbytes(yytext, yyleng, &priv_password_len); BEGIN STOP_PRIVPASSWORD; }
|
|
<START_PRIVPASSWORD>. { ERR("Invalid privPassword"); }
|
|
|
|
<STOP_PRIVPASSWORD>{whitespace} { BEGIN ATTRIBUTES; }
|
|
<STOP_PRIVPASSWORD>{newline} { add_engine(); START_LINE(); }
|
|
|
|
<ATTRIBUTES>{whitespace} ;
|
|
<ATTRIBUTES>{md5} { auth = AUTH_MD5; }
|
|
<ATTRIBUTES>{sha} { auth = AUTH_SHA; }
|
|
<ATTRIBUTES>{des} { enc = PRIV_DES; }
|
|
<ATTRIBUTES>{aes} { enc = PRIV_AES; }
|
|
<ATTRIBUTES>{newline} { add_engine(); START_LINE(); }
|
|
<ATTRIBUTES>. { ERR("Invalid char in attributes"); }
|
|
|
|
%%
|
|
|
|
static guint8* unhexbytes(const char* si, guint len, guint* len_p) {
|
|
guint8* buf;
|
|
guint8* p;
|
|
const guint8* s = (void*)si;
|
|
unsigned i;
|
|
|
|
if (len % 2) {
|
|
ERR("Uneven number of chars hex string");
|
|
return NULL;
|
|
}
|
|
|
|
buf = g_malloc(len);
|
|
p = buf;
|
|
|
|
for (i = 0; i<len ; i += 2) {
|
|
guint8 lo = s[i+1];
|
|
guint8 hi = s[i];
|
|
|
|
if (hi >= '0' && hi <= '9') {
|
|
hi -= '0';
|
|
} else if (hi >= 'a' && hi <= 'f') {
|
|
hi -= 'a';
|
|
hi += 0xa;
|
|
} else if (hi >= 'A' && hi <= 'F') {
|
|
hi -= 'A';
|
|
hi += 0xa;
|
|
} else {
|
|
goto on_error;
|
|
}
|
|
|
|
if (lo >= '0' && lo <= '9') {
|
|
lo -= '0';
|
|
} else if (lo >= 'a' && lo <= 'f') {
|
|
lo -= 'a';
|
|
lo += 0xa;
|
|
} else if (lo >= 'A' && lo <= 'F') {
|
|
lo -= 'A';
|
|
lo += 0xa;
|
|
} else {
|
|
goto on_error;
|
|
}
|
|
|
|
*(p++) = (hi*0x10) + lo;
|
|
}
|
|
|
|
len /= 2;
|
|
|
|
if (len_p) *len_p = len;
|
|
|
|
return buf;
|
|
|
|
on_error:
|
|
ERR("Error parsing hex string");
|
|
g_free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
static guint8* undquote(const char* si, guint in_len, guint* len_p) {
|
|
guint8* buf = g_malloc(in_len); /* wastes one byte for every '\\' in text */
|
|
guint8* p = buf;
|
|
guint len = 0;
|
|
guint8* end = buf+in_len;
|
|
const guint8* s = (void*)si;
|
|
|
|
for (s++; p < end; s++) {
|
|
switch(*s) {
|
|
case '\0':
|
|
*(p-1) = '\0';
|
|
goto done;
|
|
case '\\':
|
|
switch(*(++s)) {
|
|
case 'a': *(p++) = '\a'; len++; break;
|
|
case 'b': *(p++) = '\b'; len++; break;
|
|
case 'e': *(p++) = '\e'; len++; break;
|
|
case 'f': *(p++) = '\f'; len++; break;
|
|
case 'n': *(p++) = '\n'; len++; break;
|
|
case 'r': *(p++) = '\r'; len++; break;
|
|
case 't': *(p++) = '\t'; len++; break;
|
|
case 'v': *(p++) = '\v'; len++; break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
{
|
|
int c0 = 0;
|
|
int c1 = 0;
|
|
int c2 = 0;
|
|
int c = 0;
|
|
|
|
c0 = (*s) - '0';
|
|
|
|
if ( s[1] >= '0' && s[1] <= '7' ) {
|
|
c1 = c0;
|
|
c0 = (*++s) - '0';
|
|
|
|
if ( s[1] >= '0' && s[1] <= '7' ) {
|
|
c2 = c1;
|
|
c1 = c0;
|
|
c0 = (*++s) - '0';
|
|
}
|
|
}
|
|
c = (64 * c2) + (8 * c1) + c0;
|
|
*(p++) = (char) (c > 255 ? 255 : c);
|
|
len++;
|
|
break;
|
|
}
|
|
default:
|
|
*p++ = *s;
|
|
len++;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
*(p++) = *s;
|
|
len++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:
|
|
|
|
while ( p < end ) *(p++) = '\0';
|
|
buf[len] = '\0';
|
|
len--;
|
|
if (len_p) *len_p = len;
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
static void add_engine(void) {
|
|
snmp_ue_assoc_t a;
|
|
|
|
|
|
|
|
a.user.userName.data = user;
|
|
a.user.userName.len = user_len;
|
|
|
|
a.user.authPassword.data = auth_password;
|
|
a.user.authPassword.len = auth_password_len;
|
|
|
|
a.user.privPassword.data = priv_password;
|
|
a.user.privPassword.len = priv_password_len;
|
|
|
|
switch (auth) {
|
|
case AUTH_MD5:
|
|
a.user.authModel = &model_md5;
|
|
break;
|
|
case AUTH_SHA:
|
|
a.user.authModel = &model_sha1;
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
break;
|
|
}
|
|
|
|
switch(enc) {
|
|
case PRIV_DES:
|
|
a.user.privProtocol = snmp_usm_priv_des;
|
|
break;
|
|
case PRIV_AES:
|
|
a.user.privProtocol = snmp_usm_priv_aes;
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
break;
|
|
}
|
|
|
|
if (engine) {
|
|
a.engine.data = engine;
|
|
a.engine.len = engine_len;
|
|
|
|
if (a.user.authModel) {
|
|
a.user.authKey.data = g_malloc(a.user.authModel->key_size);
|
|
a.user.authKey.len = a.user.authModel->key_size;
|
|
a.user.privKey.data = g_malloc(a.user.authModel->key_size);
|
|
a.user.privKey.len = a.user.authModel->key_size;
|
|
a.user.authModel->pass2key( auth_password, auth_password_len, engine, engine_len, a.user.authKey.data);
|
|
a.user.authModel->pass2key( priv_password, priv_password_len, engine, engine_len, a.user.privKey.data);
|
|
} else {
|
|
a.user.authKey.data = NULL;
|
|
a.user.authKey.len = 0;
|
|
a.user.privKey.data = NULL;
|
|
a.user.privKey.len = 0;
|
|
}
|
|
|
|
} else {
|
|
a.engine.data = NULL;
|
|
a.engine.len = 0;
|
|
a.user.authKey.data = NULL;
|
|
a.user.authKey.len = 0;
|
|
a.user.privKey.data = NULL;
|
|
a.user.privKey.len = 0;
|
|
}
|
|
|
|
a.next = NULL;
|
|
|
|
g_array_append_val(assoc_arr,a);
|
|
loaded++;
|
|
|
|
return;
|
|
}
|
|
|
|
gchar* load_snmp_users_file(const char* fname, snmp_ue_assoc_t** assocs) {
|
|
gchar* err_str = NULL;
|
|
|
|
*assocs = NULL;
|
|
|
|
assoc_arr = g_array_new(TRUE,FALSE,sizeof(snmp_ue_assoc_t));
|
|
filename = fname;
|
|
|
|
yyin = fopen(filename,"r");
|
|
|
|
if (!yyin) {
|
|
return ep_strdup_printf("Could not open file: '%s', error: %s",filename,strerror(errno));
|
|
}
|
|
|
|
error = g_string_new("");
|
|
loaded = 0;
|
|
|
|
START_LINE();
|
|
|
|
yylex();
|
|
|
|
fclose(yyin);
|
|
|
|
yyrestart(NULL);
|
|
|
|
if (loaded) {
|
|
*assocs = (snmp_ue_assoc_t*)assoc_arr->data;
|
|
g_array_free(assoc_arr,FALSE);
|
|
} else {
|
|
*assocs = NULL;
|
|
g_array_free(assoc_arr,TRUE);
|
|
}
|
|
|
|
|
|
if (error->len) {
|
|
err_str = error->str;
|
|
}
|
|
|
|
|
|
|
|
return err_str;
|
|
}
|