1 /*
2  * basic_ui.c
3  *
4  * MontaVista IPMI basic UI to use the main UI code.
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2002,2003 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Lesser General Public License
14  *  as published by the Free Software Foundation; either version 2 of
15  *  the License, or (at your option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU Lesser General Public
30  *  License along with this program; if not, write to the Free
31  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33 
34 
35 #include <config.h>
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <OpenIPMI/selector.h>
42 #include <OpenIPMI/ipmi_ui.h>
43 #include <OpenIPMI/ipmi_auth.h>
44 #include <OpenIPMI/ipmi_conn.h>
45 #include <OpenIPMI/ipmi_debug.h>
46 #include <OpenIPMI/ipmiif.h>
47 
48 #include <OpenIPMI/internal/ipmi_malloc.h>
49 
50 #ifdef HAVE_UCDSNMP
51 # ifdef HAVE_NETSNMP
52 #  include <net-snmp/net-snmp-config.h>
53 #  include <net-snmp/net-snmp-includes.h>
54 # elif defined(HAVE_ALT_UCDSNMP_DIR)
55 #  include <ucd-snmp/asn1.h>
56 #  include <ucd-snmp/snmp_api.h>
57 #  include <ucd-snmp/snmp.h>
58 # else
59 #  include <asn1.h>
60 #  include <snmp_api.h>
61 #  include <snmp.h>
62 # endif
63 #endif
64 
65 extern struct selector_s *ui_sel;
66 
67 /* This is here because the POSIX library requires it, but we only
68    pull the posix library to get the selector code, so this is not
69    used. */
70 void
posix_vlog(char * format,enum ipmi_log_type_e log_type,va_list ap)71 posix_vlog(char *format,
72 	   enum ipmi_log_type_e log_type,
73 	   va_list ap)
74 {
75 }
76 
77 #ifdef HAVE_UCDSNMP
78 #define IPMI_OID_SIZE 9
79 static oid ipmi_oid[IPMI_OID_SIZE] = {1,3,6,1,4,1,3183,1,1};
snmp_input(int op,struct snmp_session * session,int reqid,struct snmp_pdu * pdu,void * magic)80 int snmp_input(int op,
81 	       struct snmp_session *session,
82 	       int reqid,
83 	       struct snmp_pdu *pdu,
84 	       void *magic)
85 {
86     struct sockaddr_in   *src_ip;
87     uint32_t             specific;
88     struct variable_list *var;
89 
90 #ifdef HAVE_NETSNMP
91     if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE)
92 	goto out;
93 #else
94     if (op != RECEIVED_MESSAGE)
95 	goto out;
96 #endif
97     if (pdu->command != SNMP_MSG_TRAP)
98 	goto out;
99     if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE,
100 			 pdu->enterprise, pdu->enterprise_length)
101 	!= 0)
102     {
103 	goto out;
104     }
105     if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC)
106 	goto out;
107 
108     src_ip = (struct sockaddr_in *) &pdu->agent_addr;
109     specific = pdu->specific_type;
110 
111     var = pdu->variables;
112     if (var == NULL)
113 	goto out;
114     if (var->type != ASN_OCTET_STR)
115 	goto out;
116     if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE, var->name, var->name_length)
117 	!= 0)
118     {
119 	goto out;
120     }
121     if (var->val_len < 46)
122 	goto out;
123 
124     ipmi_handle_snmp_trap_data(src_ip,
125 		    	       sizeof(*src_ip),
126 			       IPMI_EXTERN_ADDR_IP,
127 			       specific,
128 			       var->val.string,
129 			       var->val_len);
130 
131  out:
132     return 1;
133 }
134 
135 #ifdef HAVE_NETSNMP
136 static int
snmp_pre_parse(netsnmp_session * session,netsnmp_transport * transport,void * transport_data,int transport_data_length)137 snmp_pre_parse(netsnmp_session * session, netsnmp_transport *transport,
138 	       void *transport_data, int transport_data_length)
139 {
140     return 1;
141 }
142 #else
143 static int
snmp_pre_parse(struct snmp_session * session,snmp_ipaddr from)144 snmp_pre_parse(struct snmp_session *session, snmp_ipaddr from)
145 {
146     return 1;
147 }
148 #endif
149 
150 struct snmp_session *snmp_session;
151 
152 struct snmp_fd_data {
153     int fd;
154     os_hnd_fd_id_t *id;
155     struct snmp_fd_data *next;
156 };
157 
158 static struct snmp_fd_data *snmpfd = NULL;
159 os_hnd_timer_id_t *snmp_timer = NULL;
160 
161 static void
snmp_check_read_fds(int fd,void * cb_data,os_hnd_fd_id_t * id)162 snmp_check_read_fds(int fd, void *cb_data, os_hnd_fd_id_t *id)
163 {
164     fd_set fdset;
165 
166     FD_ZERO(&fdset);
167     FD_SET(fd, &fdset);
168     snmp_read(&fdset);
169 }
170 
171 static void
snmp_check_timeout(void * cb_data,os_hnd_timer_id_t * id)172 snmp_check_timeout(void *cb_data, os_hnd_timer_id_t *id)
173 {
174     snmp_timeout();
175 }
176 
177 static void
snmp_setup_fds(os_handler_t * os_hnd)178 snmp_setup_fds(os_handler_t *os_hnd)
179 {
180     int nfds = 0, block = 0, i, rv;
181     fd_set fdset;
182     struct timeval tv;
183     struct snmp_fd_data *fdd, *nfdd, *prev = NULL;
184 
185     FD_ZERO(&fdset);
186     tv.tv_sec = 0;
187     tv.tv_usec = 0;
188     snmp_select_info(&nfds, &fdset, &tv, &block);
189 
190     /* Run through the list.  Since the list is kept sorted, we only
191        need one pass. */
192     fdd = snmpfd;
193     for (i = 0; i < nfds; i++) {
194 	if (!FD_ISSET(i, &fdset))
195 	    continue;
196 
197 	if (fdd) {
198 	    if (fdd->fd == i) {
199 		/* Didn't change. */
200 		prev = fdd;
201 		fdd = fdd->next;
202 		continue;
203 	    }
204 	    if (fdd->fd < i) {
205 		/* Current one was deleted. */
206 		os_hnd->remove_fd_to_wait_for(os_hnd, fdd->id);
207 		if (prev)
208 		    prev->next = fdd->next;
209 		else
210 		    snmpfd = fdd->next;
211 		os_hnd->mem_free(fdd);
212 		continue;
213 	    }
214 	}
215 
216 	/* New one to add. */
217 	nfdd = os_hnd->mem_alloc(sizeof(*fdd));
218 	if (!nfdd) {
219 	    rv = ENOMEM;
220 	    goto err;
221 	}
222 	nfdd->fd = i;
223 	rv = os_hnd->add_fd_to_wait_for(os_hnd, i, snmp_check_read_fds,
224 					NULL, NULL, &nfdd->id);
225 	if (rv)
226 	    goto err;
227 
228 	/* Insert after */
229 	if (fdd) {
230 	    nfdd->next = fdd->next;
231 	    fdd->next = nfdd;
232 	} else {
233 	    nfdd->next = NULL;
234 	    snmpfd = fdd;
235 	}
236     }
237 
238     if (!block) {
239 	os_hnd->stop_timer(os_hnd, snmp_timer);
240     } else {
241 	os_hnd->stop_timer(os_hnd, snmp_timer);
242 	os_hnd->start_timer(os_hnd, snmp_timer, &tv, snmp_check_timeout, NULL);
243     }
244     return;
245 
246  err:
247     fprintf(stderr, "Error handling SNMP fd data: %s\n", strerror(rv));
248     exit(1);
249 }
250 
251 int
snmp_init(os_handler_t * os_hnd)252 snmp_init(os_handler_t *os_hnd)
253 {
254     struct snmp_session session;
255 #ifdef HAVE_NETSNMP
256     netsnmp_transport *transport = NULL;
257     static char *snmp_default_port = "udp:162";
258     int rv;
259 
260     rv = os_hnd->alloc_timer(os_hnd, &snmp_timer);
261     if (rv) {
262 	fprintf(stderr, "Could not allocate SNMP timer\n");
263 	return -1;
264     }
265 
266     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
267 			   NETSNMP_DS_LIB_MIB_ERRORS,
268 			   0);
269 
270     init_snmp("ipmi_ui");
271 
272     transport = netsnmp_tdomain_transport(snmp_default_port, 1, "udp");
273     if (!transport) {
274         snmp_sess_perror("ipmi_ui", &session);
275 	return -1;
276     }
277 #else
278     void *transport = NULL;
279 #endif
280     snmp_sess_init(&session);
281     session.peername = SNMP_DEFAULT_PEERNAME;
282     session.version = SNMP_DEFAULT_VERSION;
283     session.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
284     session.retries = SNMP_DEFAULT_RETRIES;
285     session.timeout = SNMP_DEFAULT_TIMEOUT;
286     session.local_port = SNMP_TRAP_PORT;
287     session.callback = snmp_input;
288     session.callback_magic = transport;
289     session.authenticator = NULL;
290     session.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
291 
292 #ifdef HAVE_NETSNMP
293     snmp_session = snmp_add(&session, transport, snmp_pre_parse, NULL);
294 #else
295     snmp_session = snmp_open_ex(&session, snmp_pre_parse,
296 				NULL, NULL, NULL, NULL);
297 #endif
298     if (snmp_session == NULL) {
299         snmp_sess_perror("ipmi_ui", &session);
300 	return -1;
301     }
302 
303     return 0;
304 }
305 #else
snmp_setup_fds(os_handler_t * os_hnd)306 static void snmp_setup_fds(os_handler_t *os_hnd) { }
307 #endif /* HAVE_UCDSNMP */
308 
309 int
main(int argc,char * argv[])310 main(int argc, char *argv[])
311 {
312     int              rv;
313     int              curr_arg = 1;
314     const char       *arg;
315     int              full_screen = 1;
316     ipmi_domain_id_t domain_id;
317     int              i;
318 #ifdef HAVE_UCDSNMP
319     int              init_snmp = 0;
320 #endif
321     ipmi_args_t      *con_parms[2];
322     ipmi_con_t       *con[2];
323     int              last_con = 0;
324 
325     while ((curr_arg < argc) && (argv[curr_arg][0] == '-')) {
326 	arg = argv[curr_arg];
327 	curr_arg++;
328 	if (strcmp(arg, "--") == 0) {
329 	    break;
330 	} else if (strcmp(arg, "-c") == 0) {
331 	    full_screen = 0;
332 	} else if (strcmp(arg, "-dlock") == 0) {
333 	    DEBUG_LOCKS_ENABLE();
334 	} else if (strcmp(arg, "-dmem") == 0) {
335 	    DEBUG_MALLOC_ENABLE();
336 	} else if (strcmp(arg, "-drawmsg") == 0) {
337 	    DEBUG_RAWMSG_ENABLE();
338 	} else if (strcmp(arg, "-dmsg") == 0) {
339 	    DEBUG_MSG_ENABLE();
340 #ifdef HAVE_UCDSNMP
341 	} else if (strcmp(arg, "-snmp") == 0) {
342 	    init_snmp = 1;
343 #endif
344 	} else {
345 	    fprintf(stderr, "Unknown option: %s\n", arg);
346 	    return 1;
347 	}
348     }
349 
350     rv = sel_alloc_selector_nothread(&ui_sel);
351     if (rv) {
352 	fprintf(stderr, "Could not allocate selector\n");
353 	exit(1);
354     }
355 
356     rv = ipmi_ui_init(&ipmi_ui_cb_handlers, full_screen);
357 
358 #ifdef HAVE_UCDSNMP
359     if (init_snmp) {
360 	if (snmp_init(&ipmi_ui_cb_handlers) < 0)
361 	    goto out;
362     }
363 #endif
364 
365  next_con:
366     rv = ipmi_parse_args2(&curr_arg, argc, argv, &con_parms[last_con]);
367     if (rv) {
368 	fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
369 		curr_arg, strerror(rv));
370 	exit(1);
371     }
372     last_con++;
373 
374     if (curr_arg < argc) {
375 	if (last_con == 2) {
376 	    fprintf(stderr, "Too many connections\n");
377 	    rv = EINVAL;
378 	    goto out;
379 	}
380 	goto next_con;
381     }
382 
383     for (i=0; i<last_con; i++) {
384 	rv = ipmi_args_setup_con(con_parms[i],
385 				 &ipmi_ui_cb_handlers,
386 				 NULL,
387 				 &con[i]);
388 	if (rv) {
389 	    fprintf(stderr, "ipmi_ip_setup_con: %s", strerror(rv));
390 	    exit(1);
391 	}
392     }
393 
394     for (i=0; i<last_con; i++)
395 	ipmi_free_args(con_parms[i]);
396 
397     rv = ipmi_open_domain("first", con, last_con, ipmi_ui_setup_done,
398 			  NULL, NULL, NULL, NULL, 0, &domain_id);
399     if (rv) {
400 	fprintf(stderr, "ipmi_open_domain: %s\n", strerror(rv));
401 	goto out;
402     }
403 
404     for (;;) {
405 #ifdef HAVE_UCDSNMP
406       if (init_snmp)
407 	  snmp_setup_fds(&ipmi_ui_cb_handlers);
408 #endif
409       ipmi_ui_cb_handlers.perform_one_op(&ipmi_ui_cb_handlers, NULL);
410     }
411 
412  out:
413     ipmi_ui_shutdown();
414 
415     if (rv)
416 	return 1;
417     return 0;
418 }
419