1#
2# This file is part of snmpclitools software.
3#
4# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/snmpclitools/license.html
6#
7import sys
8from pyasn1.type import univ
9from pyasn1.error import PyAsn1Error
10from pysnmp.proto import rfc1902
11from pysnmp import error
12from snmpclitools.cli import base
13
14# Read class
15
16
17def getReadUsage():
18    return """\
19Management parameters:
20   [mib-module::]object-name|oid ...
21              mib-module:           MIB name (e.g. SNMPv2-MIB)
22              object-name:          MIB symbol (e.g. sysDescr.0) or OID
23"""
24
25# Scanner
26
27
28class ReadPduScannerMixIn:
29    pass
30
31# Parser
32
33
34class ReadPduParserMixIn:
35    def p_varBindSpec(self, args):
36        '''
37        VarBind ::= VarName
38        '''
39
40    def p_paramsSpec(self, args):
41        '''
42        Params ::= VarBinds
43        '''
44
45    def p_pduSpec(self, args):
46        '''
47        VarBinds ::= VarBind whitespace VarBinds
48        VarBinds ::= VarBind
49        VarBinds ::=
50        VarName ::= ModName semicolon semicolon NodeName
51        VarName ::= ModName semicolon semicolon
52        VarName ::= semicolon semicolon NodeName
53        VarName ::= NodeName
54        ModName ::= string
55        NodeName ::= ObjectName ObjectIndices
56        ObjectName ::= string
57        ObjectIndices ::= ObjectIndex string ObjectIndices
58        ObjectIndices ::= ObjectIndex ObjectIndices
59        ObjectIndices ::= ObjectIndex
60        ObjectIndices ::=
61        ObjectIndex ::= quote string quote
62        '''
63
64# Generator
65
66
67class __ReadPduGenerator(base.GeneratorTemplate):
68    def n_ModName(self, cbCtx, node):
69        snmpEngine, ctx = cbCtx
70        ctx['modName'] = node[0].attr
71
72    def n_ObjectName(self, cbCtx, node):
73        snmpEngine, ctx = cbCtx
74        objectName = []
75        for subOid in node[0].attr.split('.'):
76            if not subOid:
77                continue
78            try:
79                objectName.append(int(subOid))
80            except ValueError:
81                objectName.append(subOid)
82        ctx['objectName'] = tuple(objectName)
83
84    def n_ObjectIndex(self, cbCtx, node):
85        snmpEngine, ctx = cbCtx
86        if 'objectIndices' not in ctx:
87            ctx['objectIndices'] = []
88        ctx['objectIndices'].append(node[1].attr)
89
90    def n_VarName_exit(self, cbCtx, node):
91        snmpEngine, ctx = cbCtx
92        mibViewCtl = ctx['mibViewController']
93        if 'modName' in ctx:
94            mibViewCtl.mibBuilder.loadModules(ctx['modName'])
95        if 'objectName' in ctx:
96            objectName = ctx['objectName']
97        else:
98            objectName = None
99
100        modName = ctx.get('modName', '')
101
102        if objectName:
103            oid, label, suffix = mibViewCtl.getNodeName(objectName, modName)
104        else:
105            oid, label, suffix = mibViewCtl.getFirstNodeName(modName)
106        if sys.version_info[0] < 3:
107            intTypes = (int, long)
108        else:
109            intTypes = (int,)
110        if [x for x in suffix if not isinstance(x, intTypes)]:
111            raise error.PySnmpError(
112                'Cant resolve object at: %s' % (suffix,)
113            )
114        modName, nodeDesc, _suffix = mibViewCtl.getNodeLocation(oid)
115        mibNode, = mibViewCtl.mibBuilder.importSymbols(modName, nodeDesc)
116        if not hasattr(self, '_MibTableColumn'):
117            self._MibTableColumn, = mibViewCtl.mibBuilder.importSymbols(
118                'SNMPv2-SMI', 'MibTableColumn'
119            )
120        if isinstance(mibNode, self._MibTableColumn):
121            # Table column
122            if 'objectIndices' in ctx:
123                modName, nodeDesc, _suffix = mibViewCtl.getNodeLocation(
124                    mibNode.name[:-1]
125                )
126                mibNode, = mibViewCtl.mibBuilder.importSymbols(
127                    modName, nodeDesc
128                )
129                suffix = suffix + mibNode.getInstIdFromIndices(
130                    *ctx['objectIndices']
131                )
132        else:
133            if 'objectIndices' in ctx:
134                raise error.PySnmpError(
135                    'Cant resolve indices: %s' % (ctx['objectIndices'],)
136                )
137        ctx['varName'] = oid + suffix
138        if 'objectName' in ctx:
139            del ctx['objectName']
140        if 'objectIndices' in ctx:
141            del ctx['objectIndices']
142
143    def n_VarBind_exit(self, cbCtx, node):
144        snmpEngine, ctx = cbCtx
145        if 'varBinds' not in ctx:
146            ctx['varBinds'] = [(ctx['varName'], None)]
147        else:
148            ctx['varBinds'].append((ctx['varName'], None))
149        del ctx['varName']
150
151    def n_VarBinds_exit(self, cbCtx, node):
152        snmpEngine, ctx = cbCtx
153        if 'varBinds' not in ctx or not ctx['varBinds']:
154            ctx['varBinds'] = [((1, 3, 6), None)]
155
156
157def readPduGenerator(cbCtx, ast):
158    __ReadPduGenerator().preorder(cbCtx, ast)
159
160# Write class
161
162
163def getWriteUsage():
164    return """\
165Management parameters:
166   <[mib-module::]object-name|oid type| = value> ...
167              mib-module:           MIB name (e.g. SNMPv2-MIB)
168              object-name:          MIB symbol (e.g. sysDescr.0) or OID
169              type:                 MIB value type
170                    i               integer
171                    u               unsigned integer
172                    s               string
173                    n               NULL
174                    o               ObjectIdentifier
175                    t               TimeTicks
176                    a               IP address
177              =:                    use MIB for value type lookup
178              value:                value to write
179"""
180
181# Scanner
182
183WritePduScannerMixIn = ReadPduScannerMixIn
184
185# Parser
186
187
188class WritePduParserMixIn(ReadPduParserMixIn):
189    def p_varBindSpec(self, args):
190        '''
191        VarBind ::= VarName whitespace VarType whitespace VarValue
192        VarType ::= string
193        VarValue ::= string
194        '''
195
196# Generator
197
198
199class __WritePduGenerator(__ReadPduGenerator):
200    _typeMap = {
201        'i': rfc1902.Integer(),
202        'u': rfc1902.Integer32(),
203        's': rfc1902.OctetString(),
204        'n': univ.Null(),
205        'o': univ.ObjectIdentifier(),
206        't': rfc1902.TimeTicks(),
207        'a': rfc1902.IpAddress()
208    }
209
210    def n_VarType(self, cbCtx, node):
211        snmpEngine, ctx = cbCtx
212        ctx['varType'] = node[0].attr
213
214    def n_VarValue(self, cbCtx, node):
215        snmpEngine, ctx = cbCtx
216        ctx['varValue'] = node[0].attr
217
218    def n_VarBind_exit(self, cbCtx, node):
219        snmpEngine, ctx = cbCtx
220        mibViewCtl = ctx['mibViewController']
221        if ctx['varType'] == '=':
222            modName, nodeDesc, suffix = mibViewCtl.getNodeLocation(ctx['varName'])
223            mibNode, = mibViewCtl.mibBuilder.importSymbols(modName, nodeDesc)
224            if hasattr(mibNode, 'syntax'):
225                MibTableColumn, = mibViewCtl.mibBuilder.importSymbols('SNMPv2-SMI', 'MibTableColumn')
226                if isinstance(mibNode, MibTableColumn) or suffix == (0,):
227                    val = mibNode.syntax
228                else:
229                    raise error.PySnmpError(
230                        'Found MIB scalar %s but non-scalar given %s' %
231                        (mibNode.name + (0,), ctx['varName'])
232                    )
233            else:
234                raise error.PySnmpError(
235                    'Variable %s has no syntax' % (ctx['varName'],)
236                )
237        else:
238            try:
239                val = self._typeMap[ctx['varType']]
240            except KeyError:
241                raise error.PySnmpError('unsupported SNMP value type "%s"' % ctx['varType'])
242        try:
243            val = val.clone(ctx['varValue'])
244        except PyAsn1Error:
245            raise error.PySnmpError(sys.exc_info()[1])
246
247        if 'varBinds' not in ctx:
248            ctx['varBinds'] = [(ctx['varName'], val)]
249        else:
250            ctx['varBinds'].append((ctx['varName'], val))
251
252
253def writePduGenerator(cbCtx, ast):
254    snmpEngine, ctx = cbCtx
255    __WritePduGenerator().preorder((snmpEngine, ctx), ast)
256