1 /*
2  * Stonith module for WTI MPC (SNMP)
3  * Copyright (c) 2001 Andreas Piesk <a.piesk@gmx.net>
4  * Mangled by Sun Jiang Dong <sunjd@cn.ibm.com>, IBM, 2005
5  *
6  * Modified for WTI MPC by Denis Chapligin <chollya@satgate.net>, SatGate, 2009
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.*
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 
24 #include <lha_internal.h>
25 
26 /* device ID */
27 #define	DEVICE				"WTI MPC"
28 
29 #include "stonith_plugin_common.h"
30 #undef FREE	/* defined by snmp stuff */
31 
32 #ifdef PACKAGE_BUGREPORT
33 #undef PACKAGE_BUGREPORT
34 #endif
35 #ifdef PACKAGE_NAME
36 #undef PACKAGE_NAME
37 #endif
38 #ifdef PACKAGE_STRING
39 #undef PACKAGE_STRING
40 #endif
41 #ifdef PACKAGE_TARNAME
42 #undef PACKAGE_TARNAME
43 #endif
44 #ifdef PACKAGE_VERSION
45 #undef PACKAGE_VERSION
46 #endif
47 
48 #ifdef HAVE_NET_SNMP_NET_SNMP_CONFIG_H
49 #       include <net-snmp/net-snmp-config.h>
50 #       include <net-snmp/net-snmp-includes.h>
51 #       include <net-snmp/agent/net-snmp-agent-includes.h>
52 #       define  INIT_AGENT()    init_master_agent()
53 #else
54 #       include <ucd-snmp/ucd-snmp-config.h>
55 #       include <ucd-snmp/ucd-snmp-includes.h>
56 #       include <ucd-snmp/ucd-snmp-agent-includes.h>
57 #       ifndef NETSNMP_DS_APPLICATION_ID
58 #               define NETSNMP_DS_APPLICATION_ID        DS_APPLICATION_ID
59 #       endif
60 #       ifndef NETSNMP_DS_AGENT_ROLE
61 #               define NETSNMP_DS_AGENT_ROLE    DS_AGENT_ROLE
62 #       endif
63 #       define netsnmp_ds_set_boolean   ds_set_boolean
64 #       define  INIT_AGENT()    init_master_agent(161, NULL, NULL)
65 #endif
66 
67 #define PIL_PLUGIN              wti_mpc
68 #define PIL_PLUGIN_S            "wti_mpc"
69 #define PIL_PLUGINLICENSE 	LICENSE_LGPL
70 #define PIL_PLUGINLICENSEURL 	URL_LGPL
71 #include <pils/plugin.h>
72 
73 #define	DEBUGCALL					\
74     if (Debug) {					\
75     	LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);	\
76     }
77 
78 static StonithPlugin *	wti_mpc_new(const char *);
79 static void	wti_mpc_destroy(StonithPlugin *);
80 static const char * const *	wti_mpc_get_confignames(StonithPlugin *);
81 static int	wti_mpc_set_config(StonithPlugin *, StonithNVpair *);
82 static const char *	wti_mpc_getinfo(StonithPlugin * s, int InfoType);
83 static int	wti_mpc_status(StonithPlugin * );
84 static int	wti_mpc_reset_req(StonithPlugin * s, int request, const char * host);
85 static char **	wti_mpc_hostlist(StonithPlugin  *);
86 
87 static struct stonith_ops wti_mpcOps ={
88 	wti_mpc_new,		/* Create new STONITH object	*/
89 	wti_mpc_destroy,		/* Destroy STONITH object	*/
90 	wti_mpc_getinfo,		/* Return STONITH info string	*/
91 	wti_mpc_get_confignames,	/* Get configuration parameters	*/
92 	wti_mpc_set_config,	/* Set configuration */
93 	wti_mpc_status,		/* Return STONITH device status	*/
94 	wti_mpc_reset_req,	/* Request a reset */
95 	wti_mpc_hostlist,		/* Return list of supported hosts */
96 };
97 
98 PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
99 static const PILPluginImports*  PluginImports;
100 static PILPlugin*               OurPlugin;
101 static PILInterface*		OurInterface;
102 static StonithImports*		OurImports;
103 static void*			interfprivate;
104 
105 PIL_rc
106 PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
107 
108 PIL_rc
PIL_PLUGIN_INIT(PILPlugin * us,const PILPluginImports * imports)109 PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
110 {
111 	/* Force the compiler to do a little type checking */
112 	(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
113 	DEBUGCALL;
114 
115 	PluginImports = imports;
116 	OurPlugin = us;
117 
118 	/* Register ourself as a plugin */
119 	imports->register_plugin(us, &OurPIExports);
120 
121 	/*  Register our interface implementation */
122  	return imports->register_interface(us, PIL_PLUGINTYPE_S
123 	,	PIL_PLUGIN_S
124 	,	&wti_mpcOps
125 	,	NULL		/*close */
126 	,	&OurInterface
127 	,	(void*)&OurImports
128 	,	&interfprivate);
129 }
130 
131 /*
132  * APCMaster tested with APC Masterswitch 9212
133  */
134 
135 /* outlet commands / status codes */
136 #define OUTLET_ON			5
137 #define OUTLET_OFF			6
138 #define OUTLET_REBOOT			7
139 
140 /* oids */
141 #define OID_IDENT			".1.3.6.1.2.1.1.5.0"
142 
143 #define OID_GROUP_NAMES_V1		".1.3.6.1.4.1.2634.3.1.3.1.2.%u"
144 #define OID_GROUP_STATE_V1		".1.3.6.1.4.1.2634.3.1.3.1.3.%i"
145 
146 #define OID_GROUP_NAMES_V3		".1.3.6.1.4.1.2634.3.100.300.1.2.%u"
147 #define OID_GROUP_STATE_V3		".1.3.6.1.4.1.2634.3.100.300.1.3.%i"
148 
149 #define MAX_OUTLETS 128
150 
151 /*
152 	snmpset -c private -v1 172.16.0.32:161
153 		".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.1" i 1
154 	The last octet in the OID is the plug number. The value can
155 	be 1 thru 8 because there are 8 power plugs on this device.
156 	The integer that can be set is as follows: 1=on, 2=off, and
157 	3=reset
158 */
159 
160 /* own defines */
161 #define MAX_STRING		128
162 #define ST_PORT			"port"
163 #define ST_MIBVERSION		"mib-version"
164 
165 /* structur of stonith object */
166 struct pluginDevice {
167 	StonithPlugin		sp;		/* StonithPlugin object */
168 	const char*		pluginid;	/* id of object		*/
169 	const char*		idinfo;		/* type of device	*/
170 	struct snmp_session*	sptr;		/* != NULL->session created */
171 	char *			hostname;	/* masterswitch's hostname  */
172 						/* or  ip addr		*/
173 	int			port;		/* snmp port		*/
174 	int			mib_version;	/* mib version to use   */
175 	char *			community;	/* snmp community (r/w)	*/
176 	int			num_outlets;	/* number of outlets	*/
177 };
178 
179 /* constant strings */
180 static const char *pluginid = "WTI-MPC-Stonith";
181 static const char *NOTpluginID = "WTI MPC device has been destroyed";
182 
183 #include "stonith_config_xml.h"
184 
185 #define XML_PORT_SHORTDESC \
186 	XML_PARM_SHORTDESC_BEGIN("en") \
187 	ST_PORT \
188 	XML_PARM_SHORTDESC_END
189 
190 #define XML_PORT_LONGDESC \
191 	XML_PARM_LONGDESC_BEGIN("en") \
192 	"The port number on which the SNMP server is running on the STONITH device" \
193 	XML_PARM_LONGDESC_END
194 
195 #define XML_PORT_PARM \
196 	XML_PARAMETER_BEGIN(ST_PORT, "string", "1", "0") \
197 	  XML_PORT_SHORTDESC \
198 	  XML_PORT_LONGDESC \
199 	XML_PARAMETER_END
200 
201 #define XML_MIBVERSION_SHORTDESC \
202 	XML_PARM_SHORTDESC_BEGIN("en") \
203 	ST_MIBVERSION \
204 	XML_PARM_SHORTDESC_END
205 
206 #define XML_MIBVERSION_LONGDESC \
207 	XML_MIBVERSION_LONGDESC_BEGIN("en") \
208 	"Version number of MPC MIB that we should use. Valid values are 1 (for 1.44 firmware) and 3 (for 1.62 firmware and later)" \
209 	XML_PARM_LONGDESC_END
210 
211 #define XML_MIBVERSION_PARM \
212 	XML_PARAMETER_BEGIN(ST_MIBVERSION, "string", "1", "0") \
213 	  XML_PORT_SHORTDESC \
214 	  XML_PORT_LONGDESC \
215 	XML_PARAMETER_END
216 
217 static const char *apcmastersnmpXML =
218   XML_PARAMETERS_BEGIN
219     XML_IPADDR_PARM
220     XML_PORT_PARM
221     XML_COMMUNITY_PARM
222     XML_MIBVERSION_PARM
223   XML_PARAMETERS_END;
224 
225 /*
226  * own prototypes
227  */
228 
229 static void MPC_error(struct snmp_session *sptr, const char *fn
230 ,	const char *msg);
231 static struct snmp_session *MPC_open(char *hostname, int port
232 ,	char *community);
233 static void *MPC_read(struct snmp_session *sptr, const char *objname
234 ,	int type);
235 static int MPC_write(struct snmp_session *sptr, const char *objname
236 ,	char type, char *value);
237 
238 static void
MPC_error(struct snmp_session * sptr,const char * fn,const char * msg)239 MPC_error(struct snmp_session *sptr, const char *fn, const char *msg)
240 {
241     int snmperr = 0;
242     int cliberr = 0;
243     char *errstr;
244 
245     snmp_error(sptr, &cliberr, &snmperr, &errstr);
246     LOG(PIL_CRIT
247     ,	"%s: %s (cliberr: %i / snmperr: %i / error: %s)."
248     ,	fn, msg, cliberr, snmperr, errstr);
249     free(errstr);
250 }
251 
252 
253 /*
254  *  creates a snmp session
255  */
256 static struct snmp_session *
MPC_open(char * hostname,int port,char * community)257 MPC_open(char *hostname, int port, char *community)
258 {
259     static struct snmp_session session;
260     struct snmp_session *sptr;
261 
262     DEBUGCALL;
263 
264     /* create session */
265     snmp_sess_init(&session);
266 
267     /* fill session */
268     session.peername = hostname;
269     session.version = SNMP_VERSION_1;
270     session.remote_port = port;
271     session.community = (u_char *)community;
272     session.community_len = strlen(community);
273     session.retries = 5;
274     session.timeout = 1000000;
275 
276     /* open session */
277     sptr = snmp_open(&session);
278 
279     if (sptr == NULL) {
280 	MPC_error(&session, __FUNCTION__, "cannot open snmp session");
281     }
282 
283     /* return pointer to opened session */
284     return (sptr);
285 }
286 
287 /*
288  * parse config
289  */
290 
291 /*
292  * read value of given oid and return it as string
293  */
294 static void *
MPC_read(struct snmp_session * sptr,const char * objname,int type)295 MPC_read(struct snmp_session *sptr, const char *objname, int type)
296 {
297     oid name[MAX_OID_LEN];
298     size_t namelen = MAX_OID_LEN;
299     struct variable_list *vars;
300     struct snmp_pdu *pdu;
301     struct snmp_pdu *resp;
302     static char response_str[MAX_STRING];
303     static int response_int;
304 
305     DEBUGCALL;
306 
307     /* convert objname into oid; return NULL if invalid */
308     if (!read_objid(objname, name, &namelen)) {
309         LOG(PIL_CRIT, "%s: cannot convert %s to oid.", __FUNCTION__, objname);
310 	return (NULL);
311     }
312 
313     /* create pdu */
314     if ((pdu = snmp_pdu_create(SNMP_MSG_GET)) != NULL) {
315 
316 	/* get-request have no values */
317 	snmp_add_null_var(pdu, name, namelen);
318 
319 	/* send pdu and get response; return NULL if error */
320 	if (snmp_synch_response(sptr, pdu, &resp) == SNMPERR_SUCCESS) {
321 
322 	    /* request succeed, got valid response ? */
323 	    if (resp->errstat == SNMP_ERR_NOERROR) {
324 
325 		/* go through the returned vars */
326 		for (vars = resp->variables; vars;
327 		     vars = vars->next_variable) {
328 
329 		    /* return response as string */
330 		    if ((vars->type == type) && (type == ASN_OCTET_STR)) {
331 			memset(response_str, 0, MAX_STRING);
332 			strncpy(response_str, (char *)vars->val.string,
333 				MIN(vars->val_len, MAX_STRING));
334 			snmp_free_pdu(resp);
335 			return ((void *) response_str);
336 		    }
337 		    /* return response as integer */
338 		    if ((vars->type == type) && (type == ASN_INTEGER)) {
339 			response_int = *vars->val.integer;
340 			snmp_free_pdu(resp);
341 			return ((void *) &response_int);
342 		    }
343 		}
344 	    }else{
345 		LOG(PIL_CRIT, "%s: error in response packet, reason %ld [%s]."
346 		,   __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat));
347 	    }
348 	}else{
349             MPC_error(sptr, __FUNCTION__, "error sending/receiving pdu");
350         }
351 	/* free repsonse pdu (necessary?) */
352 	snmp_free_pdu(resp);
353     }else{
354         MPC_error(sptr, __FUNCTION__, "cannot create pdu");
355     }
356     /* error: return nothing */
357     return (NULL);
358 }
359 
360 /*
361  * write value of given oid
362  */
363 static int
MPC_write(struct snmp_session * sptr,const char * objname,char type,char * value)364 MPC_write(struct snmp_session *sptr, const char *objname, char type,
365 	  char *value)
366 {
367     oid name[MAX_OID_LEN];
368     size_t namelen = MAX_OID_LEN;
369     struct snmp_pdu *pdu;
370     struct snmp_pdu *resp;
371 
372     DEBUGCALL;
373 
374     /* convert objname into oid; return FALSE if invalid */
375     if (!read_objid(objname, name, &namelen)) {
376         LOG(PIL_CRIT, "%s: cannot convert %s to oid.", __FUNCTION__, objname);
377         return (FALSE);
378     }
379 
380     /* create pdu */
381     if ((pdu = snmp_pdu_create(SNMP_MSG_SET)) != NULL) {
382 
383 	/* add to be written value to pdu */
384 	snmp_add_var(pdu, name, namelen, type, value);
385 
386 	/* send pdu and get response; return NULL if error */
387 	if (snmp_synch_response(sptr, pdu, &resp) == STAT_SUCCESS) {
388 
389 	    /* go through the returned vars */
390 	    if (resp->errstat == SNMP_ERR_NOERROR) {
391 
392 		/* request successful done */
393 		snmp_free_pdu(resp);
394 		return (TRUE);
395 
396 	    }else{
397 		LOG(PIL_CRIT, "%s: error in response packet, reason %ld [%s]."
398 		,   __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat));
399 	    }
400 	}else{
401             MPC_error(sptr, __FUNCTION__, "error sending/receiving pdu");
402         }
403 	/* free pdu (again: necessary?) */
404 	snmp_free_pdu(resp);
405     }else{
406         MPC_error(sptr, __FUNCTION__, "cannot create pdu");
407     }
408     /* error */
409     return (FALSE);
410 }
411 
412 /*
413  * return the status for this device
414  */
415 
416 static int
wti_mpc_status(StonithPlugin * s)417 wti_mpc_status(StonithPlugin * s)
418 {
419     struct pluginDevice *ad;
420     char *ident;
421 
422     DEBUGCALL;
423 
424     ERRIFNOTCONFIGED(s, S_OOPS);
425 
426     ad = (struct pluginDevice *) s;
427 
428     if ((ident = MPC_read(ad->sptr, OID_IDENT, ASN_OCTET_STR)) == NULL) {
429 	LOG(PIL_CRIT, "%s: cannot read ident.", __FUNCTION__);
430 	return (S_ACCESS);
431     }
432 
433     /* status ok */
434     return (S_OK);
435 }
436 
437 /*
438  * return the list of hosts configured for this device
439  */
440 
441 static char **
wti_mpc_hostlist(StonithPlugin * s)442 wti_mpc_hostlist(StonithPlugin * s)
443 {
444     char **hl;
445     struct pluginDevice *ad;
446     int j, h, num_outlets;
447     char *outlet_name;
448     char objname[MAX_STRING];
449 
450     DEBUGCALL;
451 
452     ERRIFNOTCONFIGED(s, NULL);
453 
454     ad = (struct pluginDevice *) s;
455 
456     /* allocate memory for array of up to NUM_OUTLETS strings */
457     if ((hl = (char **)MALLOC((ad->num_outlets+1) * sizeof(char *))) == NULL) {
458 	LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
459 	return (NULL);
460     }
461     /* clear hostlist array */
462     memset(hl, 0, (ad->num_outlets + 1) * sizeof(char *));
463     num_outlets = 0;
464 
465     /* read NUM_OUTLETS values and put them into hostlist array */
466     for (j = 0; j < ad->num_outlets; ++j) {
467 
468 	/* prepare objname */
469 	switch (ad->mib_version) {
470 	    case 3:
471                 snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V3,j+1);
472                 break;
473             case 1:
474             default:
475                 snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V1,j+1);
476 		break;
477 	}
478 	if (Debug) {
479 	    LOG(PIL_DEBUG, "%s: using %s as group names oid", __FUNCTION__, objname);
480 	}
481 
482 	/* read outlet name */
483 	if ((outlet_name = MPC_read(ad->sptr, objname, ASN_OCTET_STR)) ==
484 	    NULL) {
485 	    LOG(PIL_CRIT, "%s: cannot read name for outlet %d."
486             ,   __FUNCTION__, j+1);
487 	    stonith_free_hostlist(hl);
488 	    hl = NULL;
489 	    return (hl);
490 	}
491 
492 	/* Check whether the host is already listed */
493 	for (h = 0; h < num_outlets; ++h) {
494 		if (strcasecmp(hl[h],outlet_name) == 0)
495 			break;
496 	}
497 
498 	if (h >= num_outlets) {
499 		/* put outletname in hostlist */
500 		if (Debug) {
501 	            LOG(PIL_DEBUG, "%s: added %s to hostlist."
502 		    ,   __FUNCTION__, outlet_name);
503 		}
504 
505 		if ((hl[num_outlets] = STRDUP(outlet_name)) == NULL) {
506 		    LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
507 		    stonith_free_hostlist(hl);
508 		    hl = NULL;
509 		    return (hl);
510 		}
511 		strdown(hl[num_outlets]);
512 		num_outlets++;
513 	}
514     }
515 
516 
517     if (Debug) {
518     	LOG(PIL_DEBUG, "%s: %d unique hosts connected to %d outlets."
519 	,   __FUNCTION__, num_outlets, j);
520     }
521     /* return list */
522     return (hl);
523 }
524 
525 /*
526  * reset the host
527  */
528 
529 static int
wti_mpc_reset_req(StonithPlugin * s,int request,const char * host)530 wti_mpc_reset_req(StonithPlugin * s, int request, const char *host)
531 {
532     struct pluginDevice *ad;
533     char objname[MAX_STRING];
534     char value[MAX_STRING];
535     char *outlet_name;
536     int req_oid = OUTLET_REBOOT;
537     int outlet;
538     int found_outlet=-1;
539 
540     DEBUGCALL;
541 
542     ERRIFNOTCONFIGED(s, S_OOPS);
543 
544     ad = (struct pluginDevice *) s;
545 
546     /* read max. as->num_outlets values */
547     for (outlet = 1; outlet <= ad->num_outlets; outlet++) {
548 
549 	/* prepare objname */
550 	switch (ad->mib_version) {
551 	    case 3:
552                 snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V3,outlet);
553                 break;
554             case 1:
555             default:
556                 snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V1,outlet);
557 		break;
558 	}
559 
560 	/* read outlet name */
561 	if ((outlet_name = MPC_read(ad->sptr, objname, ASN_OCTET_STR))
562 	==	NULL) {
563 	    LOG(PIL_CRIT, "%s: cannot read name for outlet %d."
564             ,   __FUNCTION__, outlet);
565 	    return (S_ACCESS);
566 	}
567 	if (Debug) {
568 	    LOG(PIL_DEBUG, "%s: found outlet: %s.", __FUNCTION__, outlet_name);
569 	}
570 
571 	/* found one */
572 	if (strcasecmp(outlet_name, host) == 0) {
573 		if (Debug) {
574 		    LOG(PIL_DEBUG, "%s: found %s at outlet %d."
575 		    ,   __FUNCTION__, host, outlet);
576 		}
577 
578 		/* Ok, stop iterating over host list */
579         found_outlet=outlet;
580 		break;
581 	    }
582     }
583     if (Debug) {
584 	    LOG(PIL_DEBUG, "%s: outlet: %i.", __FUNCTION__, outlet);
585     }
586 
587     /* host not found in outlet names */
588     if (found_outlet == -1) {
589 	LOG(PIL_CRIT, "%s: no active outlet for '%s'.", __FUNCTION__, host);
590 	return (S_BADHOST);
591     }
592 
593 
594 	/* choose the OID for the stonith request */
595 	switch (request) {
596 		case ST_POWERON:
597 			req_oid = OUTLET_ON;
598 			break;
599 		case ST_POWEROFF:
600 			req_oid = OUTLET_OFF;
601 			break;
602 		case ST_GENERIC_RESET:
603 			req_oid = OUTLET_REBOOT;
604 			break;
605 		default: break;
606 	}
607 
608     /* Turn them all off */
609 
610 	    /* prepare objnames */
611 
612 	switch (ad->mib_version) {
613 	    case 3:
614                 snprintf(objname,MAX_STRING,OID_GROUP_STATE_V3,found_outlet);
615                 break;
616             case 1:
617             default:
618                 snprintf(objname,MAX_STRING,OID_GROUP_STATE_V1,found_outlet);
619 		break;
620 	}
621 
622 	    snprintf(value, MAX_STRING, "%i", req_oid);
623 
624 	    /* send reboot cmd */
625 	    if (!MPC_write(ad->sptr, objname, 'i', value)) {
626 		LOG(PIL_CRIT
627 		,	"%s: cannot send reboot command for outlet %d."
628 		,	__FUNCTION__, found_outlet);
629 		return (S_RESETFAIL);
630 	    }
631 
632         return (S_OK);
633 }
634 
635 /*
636  * Get the configuration parameter names.
637  */
638 
639 static const char * const *
wti_mpc_get_confignames(StonithPlugin * s)640 wti_mpc_get_confignames(StonithPlugin * s)
641 {
642 	static const char * ret[] = {ST_IPADDR, ST_PORT, ST_COMMUNITY, ST_MIBVERSION, NULL};
643 	return ret;
644 }
645 
646 /*
647  * Set the configuration parameters.
648  */
649 
650 static int
wti_mpc_set_config(StonithPlugin * s,StonithNVpair * list)651 wti_mpc_set_config(StonithPlugin * s, StonithNVpair * list)
652 {
653 	struct pluginDevice* sd = (struct pluginDevice *)s;
654 	int	rc;
655 	char *	i;
656     int mo;
657     char objname[MAX_STRING];
658 	StonithNamesToGet	namestocopy [] =
659 	{	{ST_IPADDR,	NULL}
660 	,	{ST_PORT,	NULL}
661 	,	{ST_COMMUNITY,	NULL}
662 	,	{ST_MIBVERSION,	NULL}
663 	,	{NULL,		NULL}
664 	};
665 
666 	DEBUGCALL;
667 	ERRIFWRONGDEV(s,S_INVAL);
668 	if (sd->sp.isconfigured) {
669 		return S_OOPS;
670 	}
671 
672 	if ((rc=OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
673 		return rc;
674 	}
675 	sd->hostname = namestocopy[0].s_value;
676 	sd->port = atoi(namestocopy[1].s_value);
677 	PluginImports->mfree(namestocopy[1].s_value);
678 	sd->community = namestocopy[2].s_value;
679 	sd->mib_version = atoi(namestocopy[3].s_value);
680 	PluginImports->mfree(namestocopy[3].s_value);
681 
682         /* try to resolve the hostname/ip-address */
683 	if (gethostbyname(sd->hostname) != NULL) {
684         	/* init snmp library */
685 		init_snmp("wti_mpc");
686 
687 		/* now try to get a snmp session */
688 		if ((sd->sptr = MPC_open(sd->hostname, sd->port, sd->community)) != NULL) {
689 
690 	    /* ok, get the number of groups from the mpc */
691             sd->num_outlets=0;
692             /* We scan goup names table starting from 1 to MAX_OUTLETS */
693             /* and increase num_outlet counter on every group entry with name */
694             /* first entry without name is the mark of the end of the group table */
695             for (mo=1;mo<MAX_OUTLETS;mo++) {
696 		switch (sd->mib_version) {
697 		    case 3:
698 	                snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V3,mo);
699 	                break;
700 	            case 1:
701 	            default:
702 	                snprintf(objname,MAX_STRING,OID_GROUP_NAMES_V1,mo);
703 			break;
704 		}
705 
706 		if (Debug) {
707 	            LOG(PIL_DEBUG, "%s: used for groupTable retrieval: %s."
708 		    ,   __FUNCTION__, objname);
709 		}
710 
711                 if ((i = MPC_read(sd->sptr, objname, ASN_OCTET_STR)) == NULL) {
712                     LOG(PIL_CRIT
713                     , "%s: cannot read number of outlets."
714                     ,       __FUNCTION__);
715                     return (S_ACCESS);
716                 }
717                 if (strlen(i)) {
718                     /* store the number of outlets */
719                     sd->num_outlets++;
720                 } else {
721                     break;
722                 }
723             }
724                 if (Debug) {
725                     LOG(PIL_DEBUG, "%s: number of outlets: %i."
726                     ,       __FUNCTION__, sd->num_outlets );
727                 }
728 
729                 /* Everything went well */
730                 return (S_OK);
731 		}else{
732 			LOG(PIL_CRIT, "%s: cannot create snmp session."
733 			,       __FUNCTION__);
734 		}
735 	}else{
736 		LOG(PIL_CRIT, "%s: cannot resolve hostname '%s', h_errno %d."
737 		,       __FUNCTION__, sd->hostname, h_errno);
738 	}
739 
740 	/* not a valid config */
741 	return (S_BADCONFIG);
742 }
743 
744 /*
745  * get info about the stonith device
746  */
747 
748 static const char *
wti_mpc_getinfo(StonithPlugin * s,int reqtype)749 wti_mpc_getinfo(StonithPlugin * s, int reqtype)
750 {
751     struct pluginDevice *ad;
752     const char *ret = NULL;
753 
754     DEBUGCALL;
755 
756     ERRIFWRONGDEV(s, NULL);
757 
758     ad = (struct pluginDevice *) s;
759 
760     switch (reqtype) {
761 	    case ST_DEVICEID:
762 		ret = ad->idinfo;
763 		break;
764 
765 	    case ST_DEVICENAME:
766 		ret = ad->hostname;
767 		break;
768 
769 	    case ST_DEVICEDESCR:
770 		ret = "WTI MPC (via SNMP)\n"
771 		      "The WTI MPC can accept multiple simultaneous SNMP clients";
772 		break;
773 
774 	    case ST_DEVICEURL:
775 		ret = "http://www.wti.com/";
776 		break;
777 
778 	    case ST_CONF_XML:		/* XML metadata */
779 		ret = apcmastersnmpXML;
780 		break;
781 
782 	}
783 	return ret;
784 }
785 
786 
787 /*
788  * APC StonithPlugin destructor...
789  */
790 
791 static void
wti_mpc_destroy(StonithPlugin * s)792 wti_mpc_destroy(StonithPlugin * s)
793 {
794 	struct pluginDevice *ad;
795 
796 	DEBUGCALL;
797 
798 	VOIDERRIFWRONGDEV(s);
799 
800 	ad = (struct pluginDevice *) s;
801 
802 	ad->pluginid = NOTpluginID;
803 
804 	/* release snmp session */
805 	if (ad->sptr != NULL) {
806 		snmp_close(ad->sptr);
807 		ad->sptr = NULL;
808 	}
809 
810 	/* reset defaults */
811 	if (ad->hostname != NULL) {
812 		PluginImports->mfree(ad->hostname);
813 		ad->hostname = NULL;
814 	}
815 	if (ad->community != NULL) {
816 		PluginImports->mfree(ad->community);
817 		ad->community = NULL;
818 	}
819 	ad->num_outlets = 0;
820 
821 	PluginImports->mfree(ad);
822 }
823 
824 /*
825  * Create a new APC StonithPlugin device.  Too bad this function can't be
826  * static
827  */
828 
829 static StonithPlugin *
wti_mpc_new(const char * subplugin)830 wti_mpc_new(const char *subplugin)
831 {
832 	struct pluginDevice *ad = ST_MALLOCT(struct pluginDevice);
833 
834 	DEBUGCALL;
835 
836 	/* no memory for stonith-object */
837 	if (ad == NULL) {
838 		LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
839 		return (NULL);
840 	}
841 
842 	/* clear stonith-object */
843 	memset(ad, 0, sizeof(*ad));
844 
845 	/* set defaults */
846 	ad->pluginid = pluginid;
847 	ad->sptr = NULL;
848 	ad->hostname = NULL;
849 	ad->community = NULL;
850 	ad->mib_version=1;
851 	ad->idinfo = DEVICE;
852 	ad->sp.s_ops = &wti_mpcOps;
853 
854 	/* return the object */
855 	return (&(ad->sp));
856 }
857