1 /*
2  * Portions of this file are subject to the following copyright(s).  See
3  * the Net-SNMP's COPYING file for more details and other copyrights
4  * that may apply:
5  *
6  * Portions of this file are copyrighted by:
7  * Copyright (c) 2016 VMware, Inc. All rights reserved.
8  * Use is subject to license terms specified in the COPYING file
9  * distributed with the Net-SNMP package.
10  */
11 
12 #include <net-snmp/net-snmp-config.h>
13 #include <net-snmp/net-snmp-features.h>
14 
15 #include <net-snmp/net-snmp-includes.h>
16 #include <net-snmp/agent/net-snmp-agent-includes.h>
17 
18 #include <net-snmp/agent/watcher.h>
19 
20 #include <net-snmp/agent/instance.h>
21 #include <net-snmp/agent/scalar.h>
22 
23 #include <string.h>
24 
25 #ifdef HAVE_DMALLOC_H
free_wrapper(void * p)26 static void free_wrapper(void * p)
27 {
28     free(p);
29 }
30 #else
31 #define free_wrapper free
32 #endif
33 
34 netsnmp_feature_provide(watcher_all);
35 netsnmp_feature_child_of(watcher_all, mib_helpers);
36 netsnmp_feature_child_of(watcher_create_info6, watcher_all);
37 netsnmp_feature_child_of(watcher_register_timestamp, watcher_all);
38 netsnmp_feature_child_of(watcher_ulong_scalar, watcher_all);
39 netsnmp_feature_child_of(watcher_read_only_ulong_scalar, watcher_all);
40 netsnmp_feature_child_of(watcher_read_only_int_scalar, watcher_all);
41 netsnmp_feature_child_of(watcher_long_scalar, watcher_all);
42 netsnmp_feature_child_of(watcher_read_only_long_scalar, watcher_all);
43 netsnmp_feature_child_of(watcher_int_scalar, watcher_all);
44 netsnmp_feature_child_of(read_only_counter32_scalar, watcher_all);
45 netsnmp_feature_child_of(watcher_spinlock, watcher_all);
46 
47 /** @defgroup watcher watcher
48  *  Watch a specified variable and process it as an instance or scalar object
49  *  @ingroup leaf
50  *  @{
51  */
52 netsnmp_mib_handler *
netsnmp_get_watcher_handler(void)53 netsnmp_get_watcher_handler(void)
54 {
55     netsnmp_mib_handler *ret = NULL;
56 
57     ret = netsnmp_create_handler("watcher",
58                                  netsnmp_watcher_helper_handler);
59     if (ret) {
60         ret->flags |= MIB_HANDLER_AUTO_NEXT;
61     }
62     return ret;
63 }
64 
65 netsnmp_watcher_info *
netsnmp_init_watcher_info6(netsnmp_watcher_info * winfo,void * data,size_t size,u_char type,int flags,size_t max_size,size_t * size_p)66 netsnmp_init_watcher_info6(netsnmp_watcher_info *winfo,
67                            void *data, size_t size, u_char type,
68                            int flags, size_t max_size, size_t* size_p)
69 {
70     winfo->data = data;
71     winfo->data_size = size;
72     winfo->max_size = max_size;
73     winfo->type = type;
74     winfo->flags = flags;
75     winfo->data_size_p = size_p;
76     return winfo;
77 }
78 
79 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_CREATE_INFO6
80 netsnmp_watcher_info *
netsnmp_create_watcher_info6(void * data,size_t size,u_char type,int flags,size_t max_size,size_t * size_p)81 netsnmp_create_watcher_info6(void *data, size_t size, u_char type,
82                              int flags, size_t max_size, size_t* size_p)
83 {
84     netsnmp_watcher_info *winfo = SNMP_MALLOC_TYPEDEF(netsnmp_watcher_info);
85     if (winfo)
86         netsnmp_init_watcher_info6(winfo, data, size, type, flags, max_size,
87                                    size_p);
88     return winfo;
89 }
90 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_CREATE_INFO6 */
91 
92 netsnmp_watcher_info *
netsnmp_init_watcher_info(netsnmp_watcher_info * winfo,void * data,size_t size,u_char type,int flags)93 netsnmp_init_watcher_info(netsnmp_watcher_info *winfo,
94                           void *data, size_t size, u_char type, int flags)
95 {
96   return netsnmp_init_watcher_info6(winfo, data, size,
97 				    type, (flags ? flags : WATCHER_FIXED_SIZE),
98 				    size,  /* Probably wrong for non-fixed
99 					    * size data */
100 				    NULL);
101 }
102 
103 netsnmp_watcher_info *
netsnmp_create_watcher_info(void * data,size_t size,u_char type,int flags)104 netsnmp_create_watcher_info(void *data, size_t size, u_char type, int flags)
105 {
106     netsnmp_watcher_info *winfo = SNMP_MALLOC_TYPEDEF(netsnmp_watcher_info);
107     if (winfo)
108         netsnmp_init_watcher_info(winfo, data, size, type, flags);
109     return winfo;
110 }
111 
112 /**
113  * Register a watched scalar. The caller remains the owner of watchinfo.
114  *
115  * @see netsnmp_register_watched_instance2()
116  */
117 int
netsnmp_register_watched_instance(netsnmp_handler_registration * reginfo,netsnmp_watcher_info * watchinfo)118 netsnmp_register_watched_instance(netsnmp_handler_registration *reginfo,
119                                   netsnmp_watcher_info         *watchinfo)
120 {
121     netsnmp_mib_handler *whandler = NULL;
122 
123     if (reginfo && watchinfo) {
124         whandler = netsnmp_get_watcher_handler();
125         if (whandler) {
126             whandler->myvoid = (void *)watchinfo;
127             if (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS)
128                 return netsnmp_register_instance(reginfo);
129         }
130     }
131 
132     snmp_log(LOG_ERR, "could not create watched instance handler\n");
133     netsnmp_handler_free(whandler);
134     netsnmp_handler_registration_free(reginfo);
135 
136     return MIB_REGISTRATION_FAILED;
137 }
138 
139 /**
140  * Register a watched scalar. Ownership of watchinfo is transferred to the handler.
141  *
142  * @see netsnmp_register_watched_instance()
143  */
144 int
netsnmp_register_watched_instance2(netsnmp_handler_registration * reginfo,netsnmp_watcher_info * watchinfo)145 netsnmp_register_watched_instance2(netsnmp_handler_registration *reginfo,
146 				   netsnmp_watcher_info         *watchinfo)
147 {
148     netsnmp_mib_handler *whandler = NULL;
149 
150     if (reginfo && watchinfo) {
151         whandler = netsnmp_get_watcher_handler();
152         if (whandler) {
153             whandler->myvoid = (void *)watchinfo;
154             netsnmp_owns_watcher_info(whandler);
155             if (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS)
156                 return netsnmp_register_instance(reginfo);
157         }
158     }
159 
160     snmp_log(LOG_ERR, "could not create watched instance2 handler\n");
161     netsnmp_handler_free(whandler);
162     netsnmp_handler_registration_free(reginfo);
163 
164     return MIB_REGISTRATION_FAILED;
165 }
166 
167 /**
168  * Register a watched scalar. The caller remains the owner of watchinfo.
169  *
170  * @see netsnmp_register_watched_scalar2()
171  */
172 int
netsnmp_register_watched_scalar(netsnmp_handler_registration * reginfo,netsnmp_watcher_info * watchinfo)173 netsnmp_register_watched_scalar(netsnmp_handler_registration *reginfo,
174                                   netsnmp_watcher_info         *watchinfo)
175 {
176     netsnmp_mib_handler *whandler = NULL;
177 
178     if (reginfo && watchinfo) {
179         whandler = netsnmp_get_watcher_handler();
180         if (whandler) {
181             whandler->myvoid = (void *)watchinfo;
182             if (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS)
183                 return netsnmp_register_scalar(reginfo);
184         }
185     }
186 
187     snmp_log(LOG_ERR, "could not create watched scalar handler\n");
188     netsnmp_handler_free(whandler);
189     netsnmp_handler_registration_free(reginfo);
190 
191     return MIB_REGISTRATION_FAILED;
192 }
193 
194 /**
195  * Register a watched scalar. Ownership of watchinfo is transferred to the handler.
196  *
197  * @see netsnmp_register_watched_scalar()
198  */
199 int
netsnmp_register_watched_scalar2(netsnmp_handler_registration * reginfo,netsnmp_watcher_info * watchinfo)200 netsnmp_register_watched_scalar2(netsnmp_handler_registration *reginfo,
201                                   netsnmp_watcher_info         *watchinfo)
202 {
203     netsnmp_mib_handler *whandler = NULL;
204 
205     if (reginfo && watchinfo) {
206         whandler = netsnmp_get_watcher_handler();
207         if (whandler) {
208             whandler->myvoid = (void *)watchinfo;
209             netsnmp_owns_watcher_info(whandler);
210             if (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS)
211                 return netsnmp_register_scalar(reginfo);
212         }
213     }
214 
215     snmp_log(LOG_ERR, "could not create watched scalar2 handler\n");
216     netsnmp_handler_free(whandler);
217     netsnmp_handler_registration_free(reginfo);
218 
219     return MIB_REGISTRATION_FAILED;
220 }
221 
222 void
netsnmp_owns_watcher_info(netsnmp_mib_handler * handler)223 netsnmp_owns_watcher_info(netsnmp_mib_handler *handler)
224 {
225     netsnmp_assert(handler);
226     netsnmp_assert(handler->myvoid);
227     handler->data_clone = (void *(*)(void *))netsnmp_clone_watcher_info;
228     handler->data_free = free;
229 }
230 
231 /** @cond */
232 
233 NETSNMP_STATIC_INLINE size_t
get_data_size(const netsnmp_watcher_info * winfo)234 get_data_size(const netsnmp_watcher_info* winfo)
235 {
236     if (winfo->flags & WATCHER_SIZE_STRLEN)
237         return strlen((const char*)winfo->data);
238     else {
239         size_t res;
240         if (winfo->flags & WATCHER_SIZE_IS_PTR)
241             res = *winfo->data_size_p;
242         else
243             res = winfo->data_size;
244         if (winfo->flags & WATCHER_SIZE_UNIT_OIDS)
245           res *= sizeof(oid);
246         return res;
247     }
248 }
249 
250 NETSNMP_STATIC_INLINE void
set_data(netsnmp_watcher_info * winfo,void * data,size_t size)251 set_data(netsnmp_watcher_info* winfo, void* data, size_t size)
252 {
253     memcpy(winfo->data, data, size);
254     if (winfo->flags & WATCHER_SIZE_STRLEN)
255         ((char*)winfo->data)[size] = '\0';
256     else {
257         if (winfo->flags & WATCHER_SIZE_UNIT_OIDS)
258           size /= sizeof(oid);
259         if (winfo->flags & WATCHER_SIZE_IS_PTR)
260             *winfo->data_size_p = size;
261         else
262             winfo->data_size = size;
263     }
264 }
265 
266 typedef struct {
267     size_t size;
268     char data[1];
269 } netsnmp_watcher_cache;
270 
271 NETSNMP_STATIC_INLINE netsnmp_watcher_cache*
netsnmp_watcher_cache_create(const void * data,size_t size)272 netsnmp_watcher_cache_create(const void* data, size_t size)
273 {
274     netsnmp_watcher_cache *res = (netsnmp_watcher_cache*)
275         malloc(sizeof(netsnmp_watcher_cache) + size - 1);
276     if (res) {
277         res->size = size;
278         memcpy(res->data, data, size);
279     }
280     return res;
281 }
282 
283 /** @endcond */
284 
285 int
netsnmp_watcher_helper_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)286 netsnmp_watcher_helper_handler(netsnmp_mib_handler *handler,
287                                netsnmp_handler_registration *reginfo,
288                                netsnmp_agent_request_info *reqinfo,
289                                netsnmp_request_info *requests)
290 {
291     netsnmp_watcher_info  *winfo = (netsnmp_watcher_info *) handler->myvoid;
292 #ifndef NETSNMP_NO_WRITE_SUPPORT
293     netsnmp_watcher_cache *old_data;
294 #endif /* NETSNMP_NO_WRITE_SUPPORT */
295 
296     DEBUGMSGTL(("helper:watcher", "Got request:  %d\n", reqinfo->mode));
297     DEBUGMSGTL(( "helper:watcher", "  oid:"));
298     DEBUGMSGOID(("helper:watcher", requests->requestvb->name,
299                                    requests->requestvb->name_length));
300     DEBUGMSG((   "helper:watcher", "\n"));
301 
302     switch (reqinfo->mode) {
303         /*
304          * data requests
305          */
306     case MODE_GET:
307         snmp_set_var_typed_value(requests->requestvb,
308                                  winfo->type,
309                                  winfo->data,
310                                  get_data_size(winfo));
311         break;
312 
313         /*
314          * SET requests.  Should only get here if registered RWRITE
315          */
316 #ifndef NETSNMP_NO_WRITE_SUPPORT
317     case MODE_SET_RESERVE1:
318         if (requests->requestvb->type != winfo->type) {
319             netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
320             handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
321         } else if (((winfo->flags & WATCHER_MAX_SIZE) &&
322                      requests->requestvb->val_len > winfo->max_size) ||
323             ((winfo->flags & WATCHER_FIXED_SIZE) &&
324                 requests->requestvb->val_len != get_data_size(winfo))) {
325             netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGLENGTH);
326             handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
327         } else if ((winfo->flags & WATCHER_SIZE_STRLEN) &&
328             (memchr(requests->requestvb->val.string, '\0',
329                 requests->requestvb->val_len) != NULL)) {
330             netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGVALUE);
331             handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
332         }
333         break;
334 
335     case MODE_SET_RESERVE2:
336         /*
337          * store old info for undo later
338          */
339         old_data =
340             netsnmp_watcher_cache_create(winfo->data, get_data_size(winfo));
341         if (old_data == NULL) {
342             netsnmp_set_request_error(reqinfo, requests,
343                                       SNMP_ERR_RESOURCEUNAVAILABLE);
344             handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
345         } else
346             netsnmp_request_add_list_data(requests,
347                                           netsnmp_create_data_list
348                                           ("watcher", old_data, &free_wrapper));
349         break;
350 
351     case MODE_SET_FREE:
352         /*
353          * nothing to do
354          */
355         break;
356 
357     case MODE_SET_ACTION:
358         /*
359          * update current
360          */
361         set_data(winfo, (void *)requests->requestvb->val.string,
362                                 requests->requestvb->val_len);
363         break;
364 
365     case MODE_SET_UNDO:
366         old_data = (netsnmp_watcher_cache*)netsnmp_request_get_list_data(requests, "watcher");
367         set_data(winfo, old_data->data, old_data->size);
368         break;
369 
370     case MODE_SET_COMMIT:
371         break;
372 #endif /* NETSNMP_NO_WRITE_SUPPORT */
373 
374     default:
375         snmp_log(LOG_ERR, "watcher handler called with an unknown mode: %d\n",
376                  reqinfo->mode);
377         return SNMP_ERR_GENERR;
378 
379     }
380 
381     /* next handler called automatically - 'AUTO_NEXT' */
382     return SNMP_ERR_NOERROR;
383 }
384 
385 
386     /***************************
387      *
388      * A specialised form of the above, reporting
389      *   the sysUpTime indicated by a given timestamp
390      *
391      ***************************/
392 
393 netsnmp_mib_handler *
netsnmp_get_watched_timestamp_handler(void)394 netsnmp_get_watched_timestamp_handler(void)
395 {
396     netsnmp_mib_handler *ret = NULL;
397 
398     ret = netsnmp_create_handler("watcher-timestamp",
399                                  netsnmp_watched_timestamp_handler);
400     if (ret) {
401         ret->flags |= MIB_HANDLER_AUTO_NEXT;
402     }
403     return ret;
404 }
405 
406 int
netsnmp_watched_timestamp_register(netsnmp_mib_handler * whandler,netsnmp_handler_registration * reginfo,marker_t timestamp)407 netsnmp_watched_timestamp_register(netsnmp_mib_handler *whandler,
408                                    netsnmp_handler_registration *reginfo,
409                                    marker_t timestamp)
410 {
411     if (reginfo && whandler && timestamp) {
412         whandler->myvoid = (void *)timestamp;
413         if (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS)
414             return netsnmp_register_scalar(reginfo);   /* XXX - or instance? */
415     }
416 
417     snmp_log(LOG_ERR, "could not create watched timestamp handler\n");
418     netsnmp_handler_registration_free(reginfo);
419 
420     return MIB_REGISTRATION_FAILED;
421 }
422 
423 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_REGISTER_TIMESTAMP
424 int
netsnmp_register_watched_timestamp(netsnmp_handler_registration * reginfo,marker_t timestamp)425 netsnmp_register_watched_timestamp(netsnmp_handler_registration *reginfo,
426                                    marker_t timestamp)
427 {
428     netsnmp_mib_handler *whandler;
429 
430     whandler         = netsnmp_get_watched_timestamp_handler();
431 
432     return netsnmp_watched_timestamp_register(whandler, reginfo, timestamp);
433 }
434 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_REGISTER_TIMESTAMP */
435 
436 
437 int
netsnmp_watched_timestamp_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)438 netsnmp_watched_timestamp_handler(netsnmp_mib_handler *handler,
439                                netsnmp_handler_registration *reginfo,
440                                netsnmp_agent_request_info *reqinfo,
441                                netsnmp_request_info *requests)
442 {
443     marker_t timestamp = (marker_t) handler->myvoid;
444     long     uptime;
445 
446     DEBUGMSGTL(("helper:watcher:timestamp",
447                                "Got request:  %d\n", reqinfo->mode));
448     DEBUGMSGTL(( "helper:watcher:timestamp", "  oid:"));
449     DEBUGMSGOID(("helper:watcher:timestamp", requests->requestvb->name,
450                                    requests->requestvb->name_length));
451     DEBUGMSG((   "helper:watcher:timestamp", "\n"));
452 
453     switch (reqinfo->mode) {
454         /*
455          * data requests
456          */
457     case MODE_GET:
458         if (handler->flags & NETSNMP_WATCHER_DIRECT)
459             uptime = * (long*)timestamp;
460         else
461             uptime = netsnmp_marker_uptime( timestamp );
462         snmp_set_var_typed_value(requests->requestvb,
463                                  ASN_TIMETICKS,
464                                  (u_char *) &uptime,
465                                  sizeof(uptime));
466         break;
467 
468         /*
469          * Timestamps are inherently Read-Only,
470          *  so don't need to support SET requests.
471          */
472 #ifndef NETSNMP_NO_WRITE_SUPPORT
473     case MODE_SET_RESERVE1:
474         netsnmp_set_request_error(reqinfo, requests,
475                                   SNMP_ERR_NOTWRITABLE);
476         handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
477         return SNMP_ERR_NOTWRITABLE;
478 #endif /* NETSNMP_NO_WRITE_SUPPORT */
479     }
480 
481     /* next handler called automatically - 'AUTO_NEXT' */
482     return SNMP_ERR_NOERROR;
483 }
484 
485     /***************************
486      *
487      * Another specialised form of the above,
488      *   implementing a 'TestAndIncr' spinlock
489      *
490      ***************************/
491 
492 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_SPINLOCK
493 
494 netsnmp_mib_handler *
netsnmp_get_watched_spinlock_handler(void)495 netsnmp_get_watched_spinlock_handler(void)
496 {
497     netsnmp_mib_handler *ret = NULL;
498 
499     ret = netsnmp_create_handler("watcher-spinlock",
500                                  netsnmp_watched_spinlock_handler);
501     if (ret) {
502         ret->flags |= MIB_HANDLER_AUTO_NEXT;
503     }
504     return ret;
505 }
506 
507 int
netsnmp_register_watched_spinlock(netsnmp_handler_registration * reginfo,int * spinlock)508 netsnmp_register_watched_spinlock(netsnmp_handler_registration *reginfo,
509                                    int *spinlock)
510 {
511     netsnmp_mib_handler  *whandler = NULL;
512     netsnmp_watcher_info *winfo = NULL;
513 
514     if (reginfo && spinlock) {
515         whandler = netsnmp_get_watched_spinlock_handler();
516         if (whandler) {
517             whandler->myvoid = (void *)spinlock;
518             winfo = netsnmp_create_watcher_info((void *)spinlock, sizeof(int),
519                                                 ASN_INTEGER,
520                                                 WATCHER_FIXED_SIZE);
521             if (winfo &&
522                 (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS))
523                 return netsnmp_register_watched_scalar2(reginfo, winfo);
524         }
525     }
526 
527     snmp_log(LOG_ERR, "could not create watched spinlock handler\n");
528     SNMP_FREE(winfo);
529     netsnmp_handler_free(whandler);
530     netsnmp_handler_registration_free(reginfo);
531 
532     return MIB_REGISTRATION_FAILED;
533 }
534 
535 
536 int
netsnmp_watched_spinlock_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)537 netsnmp_watched_spinlock_handler(netsnmp_mib_handler *handler,
538                                netsnmp_handler_registration *reginfo,
539                                netsnmp_agent_request_info *reqinfo,
540                                netsnmp_request_info *requests)
541 {
542 #ifndef NETSNMP_NO_WRITE_SUPPORT
543     int     *spinlock = (int *) handler->myvoid;
544     netsnmp_request_info *request;
545 #endif /* NETSNMP_NO_WRITE_SUPPORT */
546 
547     DEBUGMSGTL(("helper:watcher:spinlock",
548                                "Got request:  %d\n", reqinfo->mode));
549     DEBUGMSGTL(( "helper:watcher:spinlock", "  oid:"));
550     DEBUGMSGOID(("helper:watcher:spinlock", requests->requestvb->name,
551                                    requests->requestvb->name_length));
552     DEBUGMSG((   "helper:watcher:spinlock", "\n"));
553 
554     switch (reqinfo->mode) {
555         /*
556          * Ensure the assigned value matches the current one
557          */
558 #ifndef NETSNMP_NO_WRITE_SUPPORT
559     case MODE_SET_RESERVE1:
560         for (request=requests; request; request=request->next) {
561             if (request->processed)
562                 continue;
563 
564             if (*request->requestvb->val.integer != *spinlock) {
565                 netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGVALUE);
566                 handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
567                 return SNMP_ERR_WRONGVALUE;
568 
569             }
570         }
571         break;
572 
573         /*
574          * Everything else worked, so increment the spinlock
575          */
576     case MODE_SET_COMMIT:
577 	(*spinlock)++;
578 	break;
579 #endif /* NETSNMP_NO_WRITE_SUPPORT */
580     }
581 
582     /* next handler called automatically - 'AUTO_NEXT' */
583     return SNMP_ERR_NOERROR;
584 }
585 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_SPINLOCK */
586 
587     /***************************
588      *
589      *   Convenience registration routines - modelled on
590      *   the equivalent netsnmp_register_*_instance() calls
591      *
592      ***************************/
593 
594 netsnmp_watcher_info *
netsnmp_clone_watcher_info(netsnmp_watcher_info * winfo)595 netsnmp_clone_watcher_info(netsnmp_watcher_info *winfo)
596 {
597     netsnmp_watcher_info *copy = malloc(sizeof(*copy));
598     if (copy)
599 	*copy = *winfo;
600     return copy;
601 }
602 
603 static int
register_scalar_watcher(const char * name,const oid * reg_oid,size_t reg_oid_len,void * data,size_t size,u_char type,Netsnmp_Node_Handler * subhandler,int mode)604 register_scalar_watcher(const char* name,
605                         const oid* reg_oid, size_t reg_oid_len,
606                         void *data, size_t size, u_char type,
607                         Netsnmp_Node_Handler * subhandler, int mode)
608 {
609     netsnmp_handler_registration *reginfo = NULL;
610     netsnmp_mib_handler *whandler = NULL;
611     netsnmp_watcher_info* watchinfo;
612 
613     if (!name || !reg_oid || !data)
614         return MIB_REGISTRATION_FAILED;
615 
616     watchinfo = netsnmp_create_watcher_info(data, size, type,
617                                             WATCHER_FIXED_SIZE);
618     if (watchinfo) {
619         whandler = netsnmp_get_watcher_handler();
620         if (whandler) {
621             whandler->myvoid = watchinfo;
622             netsnmp_owns_watcher_info(whandler);
623             reginfo =
624                 netsnmp_create_handler_registration(name, subhandler,
625                                                     reg_oid, reg_oid_len,
626                                                     mode);
627             if (reginfo &&
628                 (netsnmp_inject_handler(reginfo, whandler) == SNMPERR_SUCCESS))
629                 return netsnmp_register_scalar(reginfo);
630         }
631     }
632 
633     snmp_log(LOG_ERR, "failed to register scalar watcher\n");
634     netsnmp_handler_free(whandler);
635     SNMP_FREE(watchinfo);
636     netsnmp_handler_registration_free(reginfo);
637 
638     return MIB_REGISTRATION_FAILED;
639 }
640 
641 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_ULONG_SCALAR
642 int
netsnmp_register_ulong_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,u_long * it,Netsnmp_Node_Handler * subhandler)643 netsnmp_register_ulong_scalar(const char *name,
644                               const oid * reg_oid, size_t reg_oid_len,
645                               u_long * it,
646                               Netsnmp_Node_Handler * subhandler)
647 {
648     return register_scalar_watcher(
649         name, reg_oid, reg_oid_len,
650         (void *)it, sizeof( u_long ),
651         ASN_UNSIGNED, subhandler, HANDLER_CAN_RWRITE);
652 }
653 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_ULONG_SCALAR */
654 
655 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_ULONG_SCALAR
656 int
netsnmp_register_read_only_ulong_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,u_long * it,Netsnmp_Node_Handler * subhandler)657 netsnmp_register_read_only_ulong_scalar(const char *name,
658                               const oid * reg_oid, size_t reg_oid_len,
659                               u_long * it,
660                               Netsnmp_Node_Handler * subhandler)
661 {
662     return register_scalar_watcher(
663         name, reg_oid, reg_oid_len,
664         (void *)it, sizeof( u_long ),
665         ASN_UNSIGNED, subhandler, HANDLER_CAN_RONLY);
666 }
667 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_ULONG_SCALAR */
668 
669 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_LONG_SCALAR
670 int
netsnmp_register_long_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,long * it,Netsnmp_Node_Handler * subhandler)671 netsnmp_register_long_scalar(const char *name,
672                               const oid * reg_oid, size_t reg_oid_len,
673                               long * it,
674                               Netsnmp_Node_Handler * subhandler)
675 {
676     return register_scalar_watcher(
677         name, reg_oid, reg_oid_len,
678         (void *)it, sizeof( long ),
679         ASN_INTEGER, subhandler, HANDLER_CAN_RWRITE);
680 }
681 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_LONG_SCALAR */
682 
683 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_LONG_SCALAR
684 int
netsnmp_register_read_only_long_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,long * it,Netsnmp_Node_Handler * subhandler)685 netsnmp_register_read_only_long_scalar(const char *name,
686                               const oid * reg_oid, size_t reg_oid_len,
687                               long * it,
688                               Netsnmp_Node_Handler * subhandler)
689 {
690     return register_scalar_watcher(
691         name, reg_oid, reg_oid_len,
692         (void *)it, sizeof( long ),
693         ASN_INTEGER, subhandler, HANDLER_CAN_RONLY);
694 }
695 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_LONG_SCALAR */
696 
697 
698 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_INT_SCALAR
699 int
netsnmp_register_int_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,int * it,Netsnmp_Node_Handler * subhandler)700 netsnmp_register_int_scalar(const char *name,
701                               const oid * reg_oid, size_t reg_oid_len,
702                               int * it,
703                               Netsnmp_Node_Handler * subhandler)
704 {
705     return register_scalar_watcher(
706         name, reg_oid, reg_oid_len,
707         (void *)it, sizeof( int ),
708         ASN_INTEGER, subhandler, HANDLER_CAN_RWRITE);
709 }
710 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_INT_SCALAR */
711 
712 #ifndef NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_INT_SCALAR
713 int
netsnmp_register_read_only_int_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,int * it,Netsnmp_Node_Handler * subhandler)714 netsnmp_register_read_only_int_scalar(const char *name,
715                               const oid * reg_oid, size_t reg_oid_len,
716                               int * it,
717                               Netsnmp_Node_Handler * subhandler)
718 {
719     return register_scalar_watcher(
720         name, reg_oid, reg_oid_len,
721         (void *)it, sizeof( int ),
722         ASN_INTEGER, subhandler, HANDLER_CAN_RONLY);
723 }
724 #endif /* NETSNMP_FEATURE_REMOVE_WATCHER_READ_ONLY_INT_SCALAR */
725 
726 #ifndef NETSNMP_FEATURE_REMOVE_READ_ONLY_COUNTER32_SCALAR
727 int
netsnmp_register_read_only_counter32_scalar(const char * name,const oid * reg_oid,size_t reg_oid_len,u_long * it,Netsnmp_Node_Handler * subhandler)728 netsnmp_register_read_only_counter32_scalar(const char *name,
729                               const oid * reg_oid, size_t reg_oid_len,
730                               u_long * it,
731                               Netsnmp_Node_Handler * subhandler)
732 {
733     return register_scalar_watcher(
734         name, reg_oid, reg_oid_len,
735         (void *)it, sizeof( u_long ),
736         ASN_COUNTER, subhandler, HANDLER_CAN_RONLY);
737 }
738 #endif /* NETSNMP_FEATURE_REMOVE_READ_ONLY_COUNTER32_SCALAR */
739 /**  @} */
740 
741