1 /*
2  * DisMan Event MIB:
3  *     Implementation of the mteTriggerBooleanTable MIB interface
4  * See 'mteTrigger.c' for active behaviour of this table.
5  *
6  * (based on mib2c.table_data.conf output)
7  */
8 
9 #include <net-snmp/net-snmp-config.h>
10 #include <net-snmp/net-snmp-features.h>
11 #include <net-snmp/net-snmp-includes.h>
12 #include <net-snmp/agent/net-snmp-agent-includes.h>
13 #include "disman/event/mteTrigger.h"
14 #include "disman/event/mteTriggerBooleanTable.h"
15 
16 netsnmp_feature_require(table_tdata);
17 #ifndef NETSNMP_NO_WRITE_SUPPORT
18 netsnmp_feature_require(check_vb_type_and_max_size);
19 netsnmp_feature_require(check_vb_truthvalue);
20 #endif /* NETSNMP_NO_WRITE_SUPPORT */
21 
22 static netsnmp_table_registration_info *table_info;
23 
24 /** Initializes the mteTriggerBooleanTable module */
25 void
init_mteTriggerBooleanTable(void)26 init_mteTriggerBooleanTable(void)
27 {
28     static oid mteTBoolTable_oid[]    = { 1, 3, 6, 1, 2, 1, 88, 1, 2, 5 };
29     size_t     mteTBoolTable_oid_len  = OID_LENGTH(mteTBoolTable_oid);
30     netsnmp_handler_registration    *reg;
31 
32     /*
33      * Ensure the (combined) table container is available...
34      */
35     init_trigger_table_data();
36 
37     /*
38      * ... then set up the MIB interface to the mteTriggerBooleanTable slice
39      */
40 #ifndef NETSNMP_NO_WRITE_SUPPORT
41     reg = netsnmp_create_handler_registration("mteTriggerBooleanTable",
42                                             mteTriggerBooleanTable_handler,
43                                             mteTBoolTable_oid,
44                                             mteTBoolTable_oid_len,
45                                             HANDLER_CAN_RWRITE);
46 #else /* !NETSNMP_NO_WRITE_SUPPORT */
47     reg = netsnmp_create_handler_registration("mteTriggerBooleanTable",
48                                             mteTriggerBooleanTable_handler,
49                                             mteTBoolTable_oid,
50                                             mteTBoolTable_oid_len,
51                                             HANDLER_CAN_RWRITE);
52 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
53 
54     table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
55     netsnmp_table_helper_add_indexes(table_info,
56                                      ASN_OCTET_STR, /* index: mteOwner       */
57                                                     /* index: mteTriggerName */
58                                      ASN_PRIV_IMPLIED_OCTET_STR,
59                                      0);
60 
61     table_info->min_column = COLUMN_MTETRIGGERBOOLEANCOMPARISON;
62     table_info->max_column = COLUMN_MTETRIGGERBOOLEANEVENT;
63 
64     /* Register this using the (common) trigger_table_data container */
65     netsnmp_tdata_register(reg, trigger_table_data, table_info);
66     DEBUGMSGTL(("disman:event:init", "Trigger Bool Table\n"));
67 }
68 
69 void
shutdown_mteTriggerBooleanTable(void)70 shutdown_mteTriggerBooleanTable(void)
71 {
72     if (table_info) {
73 	netsnmp_table_registration_info_free(table_info);
74 	table_info = NULL;
75     }
76 }
77 
78 /** handles requests for the mteTriggerBooleanTable table */
79 int
mteTriggerBooleanTable_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)80 mteTriggerBooleanTable_handler(netsnmp_mib_handler *handler,
81                                netsnmp_handler_registration *reginfo,
82                                netsnmp_agent_request_info *reqinfo,
83                                netsnmp_request_info *requests)
84 {
85 
86     netsnmp_request_info       *request;
87     netsnmp_table_request_info *tinfo;
88     struct mteTrigger          *entry;
89     int ret;
90 
91     DEBUGMSGTL(("disman:event:mib", "Boolean Table handler (%d)\n",
92                                      reqinfo->mode));
93 
94     switch (reqinfo->mode) {
95         /*
96          * Read-support (also covers GetNext requests)
97          */
98     case MODE_GET:
99         for (request = requests; request; request = request->next) {
100             if (request->processed)
101                 continue;
102 
103             entry = (struct mteTrigger *) netsnmp_tdata_extract_entry(request);
104             tinfo = netsnmp_extract_table_info(request);
105 
106             /*
107              * The mteTriggerBooleanTable should only contains entries for
108              *   rows where the mteTriggerTest 'boolean(1)' bit is set.
109              * So skip entries where this isn't the case.
110              */
111             if (!entry || !(entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN )) {
112                 netsnmp_request_set_error(request, SNMP_NOSUCHINSTANCE);
113                 continue;
114             }
115 
116             switch (tinfo->colnum) {
117             case COLUMN_MTETRIGGERBOOLEANCOMPARISON:
118                 snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
119                                            entry->mteTBoolComparison);
120                 break;
121             case COLUMN_MTETRIGGERBOOLEANVALUE:
122                 snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
123                                            entry->mteTBoolValue);
124                 break;
125             case COLUMN_MTETRIGGERBOOLEANSTARTUP:
126                 ret = (entry->flags & MTE_TRIGGER_FLAG_BSTART ) ?
127                            TV_TRUE : TV_FALSE;
128                 snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, ret);
129                 break;
130             case COLUMN_MTETRIGGERBOOLEANOBJECTSOWNER:
131                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
132                               (u_char *) entry->mteTBoolObjOwner,
133                                   strlen(entry->mteTBoolObjOwner));
134                 break;
135             case COLUMN_MTETRIGGERBOOLEANOBJECTS:
136                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
137                               (u_char *) entry->mteTBoolObjects,
138                                   strlen(entry->mteTBoolObjects));
139                 break;
140             case COLUMN_MTETRIGGERBOOLEANEVENTOWNER:
141                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
142                               (u_char *) entry->mteTBoolEvOwner,
143                                   strlen(entry->mteTBoolEvOwner));
144                 break;
145             case COLUMN_MTETRIGGERBOOLEANEVENT:
146                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
147                               (u_char *) entry->mteTBoolEvent,
148                                   strlen(entry->mteTBoolEvent));
149                 break;
150             }
151         }
152         break;
153 
154 #ifndef NETSNMP_NO_WRITE_SUPPORT
155         /*
156          * Write-support
157          */
158     case MODE_SET_RESERVE1:
159         for (request = requests; request; request = request->next) {
160             if (request->processed)
161                 continue;
162 
163             entry = (struct mteTrigger *) netsnmp_tdata_extract_entry(request);
164             tinfo = netsnmp_extract_table_info(request);
165 
166             /*
167              * Since the mteTriggerBooleanTable only contains entries for
168              *   rows where the mteTriggerTest 'boolean(1)' bit is set,
169              *   strictly speaking we should reject assignments where
170              *   this isn't the case.
171              * But SET requests that include an assignment of the
172              *   'boolean(1)' bit at the same time are valid, so would
173              *    need to be accepted. Unfortunately, this assignment
174              *   is only applied in the COMMIT pass, so it's difficult
175              *   to detect whether this holds or not.
176              *
177              * Let's fudge things for now, by processing assignments
178              *   even if the 'boolean(1)' bit isn't set.
179              */
180             switch (tinfo->colnum) {
181             case COLUMN_MTETRIGGERBOOLEANCOMPARISON:
182                 ret = netsnmp_check_vb_int_range(request->requestvb,
183                               MTE_BOOL_UNEQUAL, MTE_BOOL_GREATEREQUAL);
184                 if (ret != SNMP_ERR_NOERROR) {
185                     netsnmp_set_request_error(reqinfo, request, ret);
186                     return SNMP_ERR_NOERROR;
187                 }
188                 break;
189             case COLUMN_MTETRIGGERBOOLEANVALUE:
190                 ret = netsnmp_check_vb_int(request->requestvb);
191                 if (ret != SNMP_ERR_NOERROR) {
192                     netsnmp_set_request_error(reqinfo, request, ret);
193                     return SNMP_ERR_NOERROR;
194                 }
195                 break;
196             case COLUMN_MTETRIGGERBOOLEANSTARTUP:
197                 ret = netsnmp_check_vb_truthvalue(request->requestvb);
198                 if (ret != SNMP_ERR_NOERROR) {
199                     netsnmp_set_request_error(reqinfo, request, ret);
200                     return SNMP_ERR_NOERROR;
201                 }
202                 break;
203             case COLUMN_MTETRIGGERBOOLEANOBJECTSOWNER:
204             case COLUMN_MTETRIGGERBOOLEANOBJECTS:
205             case COLUMN_MTETRIGGERBOOLEANEVENTOWNER:
206             case COLUMN_MTETRIGGERBOOLEANEVENT:
207                 ret = netsnmp_check_vb_type_and_max_size(
208                           request->requestvb, ASN_OCTET_STR, MTE_STR1_LEN);
209                 if (ret != SNMP_ERR_NOERROR) {
210                     netsnmp_set_request_error(reqinfo, request, ret);
211                     return SNMP_ERR_NOERROR;
212                 }
213                 break;
214             default:
215                 netsnmp_set_request_error(reqinfo, request,
216                                           SNMP_ERR_NOTWRITABLE);
217                 return SNMP_ERR_NOERROR;
218             }
219 
220             /*
221              * The Event MIB is somewhat ambiguous as to whether the
222              *  various trigger table entries can be modified once the
223              *  main mteTriggerTable entry has been marked 'active'.
224              * But it's clear from discussion on the DisMan mailing
225              *  list is that the intention is not.
226              *
227              * So check for whether this row is already active,
228              *  and reject *all* SET requests if it is.
229              */
230             entry = (struct mteTrigger *) netsnmp_tdata_extract_entry(request);
231             if (entry &&
232                 entry->flags & MTE_TRIGGER_FLAG_ACTIVE ) {
233                 netsnmp_set_request_error(reqinfo, request,
234                                           SNMP_ERR_INCONSISTENTVALUE);
235                 return SNMP_ERR_NOERROR;
236             }
237         }
238         break;
239 
240     case MODE_SET_RESERVE2:
241     case MODE_SET_FREE:
242     case MODE_SET_UNDO:
243         break;
244 
245     case MODE_SET_ACTION:
246         for (request = requests; request; request = request->next) {
247             if (request->processed)
248                 continue;
249 
250             entry = (struct mteTrigger *) netsnmp_tdata_extract_entry(request);
251             if (!entry) {
252                 /*
253                  * New rows must be created via the RowStatus column
254                  *   (in the main mteTriggerTable)
255                  */
256                 netsnmp_set_request_error(reqinfo, request,
257                                           SNMP_ERR_NOCREATION);
258                                       /* or inconsistentName? */
259                 return SNMP_ERR_NOERROR;
260             }
261         }
262         break;
263 
264     case MODE_SET_COMMIT:
265         /*
266          * All these assignments are "unfailable", so it's
267          *  (reasonably) safe to apply them in the Commit phase
268          */
269         for (request = requests; request; request = request->next) {
270             if (request->processed)
271                 continue;
272 
273             entry = (struct mteTrigger *) netsnmp_tdata_extract_entry(request);
274             tinfo = netsnmp_extract_table_info(request);
275 
276             switch (tinfo->colnum) {
277             case COLUMN_MTETRIGGERBOOLEANCOMPARISON:
278                 entry->mteTBoolComparison = *request->requestvb->val.integer;
279                 break;
280             case COLUMN_MTETRIGGERBOOLEANVALUE:
281                 entry->mteTBoolValue      = *request->requestvb->val.integer;
282                 break;
283             case COLUMN_MTETRIGGERBOOLEANSTARTUP:
284                 if (*request->requestvb->val.integer == TV_TRUE)
285                     entry->flags |=  MTE_TRIGGER_FLAG_BSTART;
286                 else
287                     entry->flags &= ~MTE_TRIGGER_FLAG_BSTART;
288                 break;
289             case COLUMN_MTETRIGGERBOOLEANOBJECTSOWNER:
290                 memset(entry->mteTBoolObjOwner, 0, sizeof(entry->mteTBoolObjOwner));
291                 memcpy(entry->mteTBoolObjOwner, request->requestvb->val.string,
292                                                 request->requestvb->val_len);
293                 break;
294             case COLUMN_MTETRIGGERBOOLEANOBJECTS:
295                 memset(entry->mteTBoolObjects, 0, sizeof(entry->mteTBoolObjects));
296                 memcpy(entry->mteTBoolObjects, request->requestvb->val.string,
297                                                request->requestvb->val_len);
298                 break;
299             case COLUMN_MTETRIGGERBOOLEANEVENTOWNER:
300                 memset(entry->mteTBoolEvOwner, 0, sizeof(entry->mteTBoolEvOwner));
301                 memcpy(entry->mteTBoolEvOwner, request->requestvb->val.string,
302                                                request->requestvb->val_len);
303                 break;
304             case COLUMN_MTETRIGGERBOOLEANEVENT:
305                 memset(entry->mteTBoolEvent, 0, sizeof(entry->mteTBoolEvent));
306                 memcpy(entry->mteTBoolEvent, request->requestvb->val.string,
307                                              request->requestvb->val_len);
308                 break;
309             }
310         }
311         break;
312 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
313     }
314     return SNMP_ERR_NOERROR;
315 }
316