1 /*
2  * Copyright (C) 2008-2015 FreeIPMI Core Team
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #if HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #if STDC_HEADERS
26 #include <string.h>
27 #endif /* STDC_HEADERS */
28 #include <limits.h>
29 #include <assert.h>
30 
31 #include <freeipmi/freeipmi.h>
32 
33 #include "ipmi-oem.h"
34 #include "ipmi-oem-argp.h"
35 #include "ipmi-oem-common.h"
36 
37 #include "freeipmi-portability.h"
38 #include "pstdout.h"
39 
40 int
ipmi_oem_check_response_and_completion_code(ipmi_oem_state_data_t * state_data,const void * bytes_rs,unsigned int bytes_rs_len,unsigned int expected_bytes_rs_len,uint8_t cmd,uint8_t netfn,Ipmi_oem_comp_code_strerror comp_code_strerror)41 ipmi_oem_check_response_and_completion_code (ipmi_oem_state_data_t *state_data,
42                                              const void *bytes_rs,
43                                              unsigned int bytes_rs_len,
44                                              unsigned int expected_bytes_rs_len,
45                                              uint8_t cmd,
46                                              uint8_t netfn,
47                                              Ipmi_oem_comp_code_strerror comp_code_strerror)
48 {
49   const uint8_t *bytes_rs_ptr = bytes_rs;
50 
51   assert (state_data);
52   assert (bytes_rs);
53 
54   if (bytes_rs_len < expected_bytes_rs_len)
55     {
56       if (bytes_rs_len >= 2 && bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
57         goto output_comp_code_error;
58 
59       pstdout_fprintf (state_data->pstate,
60                        stderr,
61                        "%s:%s invalid response length: %u, expected %u\n",
62                        state_data->prog_data->args->oem_id,
63                        state_data->prog_data->args->oem_command,
64                        bytes_rs_len,
65                        expected_bytes_rs_len);
66       return (-1);
67     }
68 
69  output_comp_code_error:
70   if (bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
71     {
72       char errbuf[IPMI_OEM_ERR_BUFLEN + 1];
73 
74       memset (errbuf, '\0', IPMI_OEM_ERR_BUFLEN + 1);
75 
76       if (comp_code_strerror)
77         {
78           int ret;
79 
80           if ((ret = comp_code_strerror (state_data,
81                                          bytes_rs_ptr[1], /* completion code */
82                                          cmd,
83                                          netfn,
84                                          errbuf,
85                                          IPMI_OEM_ERR_BUFLEN)) < 0)
86             snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
87 
88           if (!ret)
89             goto standard_output_comp_code_error;
90         }
91       else
92         {
93         standard_output_comp_code_error:
94           if (ipmi_completion_code_strerror_r (cmd, /* cmd */
95                                                netfn, /* network function */
96                                                bytes_rs_ptr[1], /* completion code */
97                                                errbuf,
98                                                IPMI_OEM_ERR_BUFLEN) < 0)
99             {
100 #if 0
101               pstdout_perror (state_data->pstate, "ipmi_completion_code_strerror_r");
102 #endif
103               snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
104             }
105         }
106 
107       pstdout_fprintf (state_data->pstate,
108                        stderr,
109                        "%s:%s failed: %s\n",
110                        state_data->prog_data->args->oem_id,
111                        state_data->prog_data->args->oem_command,
112                        errbuf);
113       return (-1);
114     }
115 
116   return (0);
117 }
118 
119 int
ipmi_oem_parse_key_value(ipmi_oem_state_data_t * state_data,unsigned int option_num,char ** key,char ** value)120 ipmi_oem_parse_key_value (ipmi_oem_state_data_t *state_data,
121                           unsigned int option_num,
122                           char **key,
123                           char **value)
124 {
125   char *tempstr = NULL;
126   char *tempptr = NULL;
127   char *tempkey = NULL;
128   char *tempvalue = NULL;
129   int rv = -1;
130 
131   assert (state_data);
132   assert (key);
133   assert (value);
134 
135   if (!(tempstr = strdup (state_data->prog_data->args->oem_options[option_num])))
136     {
137       pstdout_perror (state_data->pstate, "strdup");
138       goto cleanup;
139     }
140 
141   tempptr = strchr (tempstr, '=');
142   if (!tempptr)
143     {
144       pstdout_fprintf (state_data->pstate,
145                        stderr,
146                        "%s:%s invalid OEM option argument '%s' : no equal sign\n",
147                        state_data->prog_data->args->oem_id,
148                        state_data->prog_data->args->oem_command,
149                        state_data->prog_data->args->oem_options[option_num]);
150       goto cleanup;
151     }
152 
153   (*tempptr) = '\0';
154   tempptr++;
155 
156   if (!(tempkey = strdup (tempstr)))
157     {
158       pstdout_perror (state_data->pstate, "strdup");
159       goto cleanup;
160     }
161 
162   if (!(tempvalue = strdup (tempptr)))
163     {
164       pstdout_perror (state_data->pstate, "strdup");
165       goto cleanup;
166     }
167 
168   (*key) = tempkey;
169   (*value) = tempvalue;
170 
171   rv = 0;
172  cleanup:
173   free (tempstr);
174   if (rv < 0)
175     {
176       free (tempkey);
177       free (tempvalue);
178     }
179   return (rv);
180 }
181 
182 int
ipmi_oem_parse_enable(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * enable)183 ipmi_oem_parse_enable (ipmi_oem_state_data_t *state_data,
184                        unsigned int option_num,
185                        const char *value,
186                        uint8_t *enable)
187 {
188   assert (state_data);
189   assert (value);
190   assert (enable);
191 
192   if (strcasecmp (value, "enable") && strcasecmp (value, "disable"))
193     {
194       pstdout_fprintf (state_data->pstate,
195                        stderr,
196                        "%s:%s invalid OEM option argument '%s' : invalid value\n",
197                        state_data->prog_data->args->oem_id,
198                        state_data->prog_data->args->oem_command,
199                        state_data->prog_data->args->oem_options[option_num]);
200       return (-1);
201     }
202 
203   if (!strcasecmp (value, "enable"))
204     (*enable) = 1;
205   else
206     (*enable) = 0;
207 
208   return (0);
209 }
210 
211 int
ipmi_oem_parse_1_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * value_out)212 ipmi_oem_parse_1_byte_field (ipmi_oem_state_data_t *state_data,
213                              unsigned int option_num,
214                              const char *value,
215                              uint8_t *value_out)
216 {
217   unsigned int temp;
218   char *ptr = NULL;
219 
220   assert (state_data);
221   assert (value);
222   assert (value_out);
223 
224   errno = 0;
225 
226   temp = strtoul (value, &ptr, 10);
227 
228   if (errno
229       || ptr[0] != '\0'
230       || temp > UCHAR_MAX)
231     {
232       pstdout_fprintf (state_data->pstate,
233                        stderr,
234                        "%s:%s invalid OEM option argument '%s' : invalid value\n",
235                        state_data->prog_data->args->oem_id,
236                        state_data->prog_data->args->oem_command,
237                        state_data->prog_data->args->oem_options[option_num]);
238       return (-1);
239     }
240 
241   (*value_out) = temp;
242   return (0);
243 }
244 
245 int
ipmi_oem_parse_2_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint16_t * value_out)246 ipmi_oem_parse_2_byte_field (ipmi_oem_state_data_t *state_data,
247                              unsigned int option_num,
248                              const char *value,
249                              uint16_t *value_out)
250 {
251   unsigned int temp;
252   char *ptr = NULL;
253 
254   assert (state_data);
255   assert (value);
256   assert (value_out);
257 
258   errno = 0;
259 
260   temp = strtoul (value, &ptr, 10);
261 
262   if (errno
263       || ptr[0] != '\0'
264       || temp > USHRT_MAX)
265     {
266       pstdout_fprintf (state_data->pstate,
267                        stderr,
268                        "%s:%s invalid OEM option argument '%s' : invalid value\n",
269                        state_data->prog_data->args->oem_id,
270                        state_data->prog_data->args->oem_command,
271                        state_data->prog_data->args->oem_options[option_num]);
272       return (-1);
273     }
274 
275   (*value_out) = temp;
276   return (0);
277 }
278 
279 int
ipmi_oem_parse_4_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * value_out)280 ipmi_oem_parse_4_byte_field (ipmi_oem_state_data_t *state_data,
281                              unsigned int option_num,
282                              const char *value,
283                              uint32_t *value_out)
284 {
285   unsigned int temp;
286   char *ptr = NULL;
287 
288   assert (state_data);
289   assert (value);
290   assert (value_out);
291 
292   errno = 0;
293 
294   temp = strtoul (value, &ptr, 10);
295 
296   if (errno
297       || ptr[0] != '\0')
298     {
299       pstdout_fprintf (state_data->pstate,
300                        stderr,
301                        "%s:%s invalid OEM option argument '%s' : invalid value\n",
302                        state_data->prog_data->args->oem_id,
303                        state_data->prog_data->args->oem_command,
304                        state_data->prog_data->args->oem_options[option_num]);
305       return (-1);
306     }
307 
308   (*value_out) = temp;
309   return (0);
310 }
311 
312 int
ipmi_oem_parse_unsigned_int_range(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * value_out,unsigned int min,unsigned int max)313 ipmi_oem_parse_unsigned_int_range (ipmi_oem_state_data_t *state_data,
314                                    unsigned int option_num,
315                                    const char *value,
316                                    uint32_t *value_out,
317                                    unsigned int min,
318                                    unsigned int max)
319 {
320   unsigned int temp;
321   char *ptr = NULL;
322 
323   assert (state_data);
324   assert (value);
325   assert (value_out);
326   assert (min < max);
327 
328   errno = 0;
329 
330   temp = strtoul (value, &ptr, 10);
331 
332   if (errno
333       || ptr[0] != '\0')
334     {
335       pstdout_fprintf (state_data->pstate,
336                        stderr,
337                        "%s:%s invalid OEM option argument '%s' : invalid value\n",
338                        state_data->prog_data->args->oem_id,
339                        state_data->prog_data->args->oem_command,
340                        state_data->prog_data->args->oem_options[option_num]);
341       return (-1);
342     }
343 
344   if (temp < min
345       || temp > max)
346     {
347       pstdout_fprintf (state_data->pstate,
348                        stderr,
349                        "%s:%s invalid OEM option argument '%s' : out of range\n",
350                        state_data->prog_data->args->oem_id,
351                        state_data->prog_data->args->oem_command,
352                        state_data->prog_data->args->oem_options[option_num]);
353       return (-1);
354     }
355 
356   (*value_out) = temp;
357   return (0);
358 }
359 
360 int
ipmi_oem_parse_ip_address(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * ip_address)361 ipmi_oem_parse_ip_address (ipmi_oem_state_data_t *state_data,
362                            unsigned int option_num,
363                            const char *value,
364                            uint32_t *ip_address)
365 {
366   unsigned int b1, b2, b3, b4;
367   uint32_t temp;
368   int ret;
369 
370   assert (state_data);
371   assert (value);
372   assert (ip_address);
373 
374   if ((ret = sscanf (value,
375                      "%u.%u.%u.%u",
376                      &b1,
377                      &b2,
378                      &b3,
379                      &b4)) < 0)
380     {
381       pstdout_fprintf (state_data->pstate,
382                        stderr,
383                        "%s:%s invalid IP address '%s'\n",
384                        state_data->prog_data->args->oem_id,
385                        state_data->prog_data->args->oem_command,
386                        state_data->prog_data->args->oem_options[option_num]);
387       return (-1);
388     }
389 
390   if (ret != 4)
391     {
392       pstdout_fprintf (state_data->pstate,
393                        stderr,
394                        "%s:%s invalid IP address '%s'\n",
395                        state_data->prog_data->args->oem_id,
396                        state_data->prog_data->args->oem_command,
397                        state_data->prog_data->args->oem_options[option_num]);
398       return (-1);
399     }
400 
401   temp = 0;
402   temp |= (uint32_t)b1;
403   temp |= ((uint32_t)b2 << 8);
404   temp |= ((uint32_t)b3 << 16);
405   temp |= ((uint32_t)b4 << 24);
406 
407   (*ip_address) = temp;
408   return (0);
409 
410 }
411 
412 int
ipmi_oem_parse_string(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * string_length,char * stringbuf,unsigned int stringbuflen)413 ipmi_oem_parse_string (ipmi_oem_state_data_t *state_data,
414                        unsigned int option_num,
415                        const char *value,
416                        uint8_t *string_length,
417                        char *stringbuf,
418                        unsigned int stringbuflen)
419 {
420   assert (state_data);
421   assert (value);
422   assert (string_length);
423   assert (stringbuf);
424   assert (stringbuflen);
425 
426   if (strlen (value) > stringbuflen)
427     {
428       pstdout_fprintf (state_data->pstate,
429                        stderr,
430                        "%s:%s invalid OEM option argument '%s' : string length too long\n",
431                        state_data->prog_data->args->oem_id,
432                        state_data->prog_data->args->oem_command,
433                        state_data->prog_data->args->oem_options[option_num]);
434       return (-1);
435     }
436 
437   (*string_length) = strlen (value);
438 
439   /* use memcpy, do not need NULL termination */
440   if ((*string_length))
441     memcpy (stringbuf,
442             value,
443             (*string_length));
444 
445   return (0);
446 }
447 
448 int
ipmi_oem_get_system_info_string(ipmi_oem_state_data_t * state_data,uint8_t parameter_selector,uint8_t set_selector,uint8_t block_selector,char * string,unsigned int string_len,unsigned int * string_len_ret)449 ipmi_oem_get_system_info_string (ipmi_oem_state_data_t *state_data,
450                                  uint8_t parameter_selector,
451                                  uint8_t set_selector,
452                                  uint8_t block_selector,
453                                  char *string,
454                                  unsigned int string_len,
455                                  unsigned int *string_len_ret)
456 {
457   fiid_obj_t obj_cmd_rs = NULL;
458   uint8_t configuration_parameter_data[IPMI_OEM_MAX_BYTES];
459   int len;
460   int rv = -1;
461 
462   assert (state_data);
463   assert (string);
464   assert (string_len);
465 
466   if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_system_info_parameters_rs)))
467     {
468       pstdout_fprintf (state_data->pstate,
469                        stderr,
470                        "fiid_obj_create: %s\n",
471                        strerror (errno));
472       goto cleanup;
473     }
474 
475   if (ipmi_cmd_get_system_info_parameters (state_data->ipmi_ctx,
476                                            IPMI_GET_SYSTEM_INFO_PARAMETER,
477                                            parameter_selector,
478                                            set_selector,
479                                            block_selector,
480                                            obj_cmd_rs) < 0)
481     {
482       if ((ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
483            && ipmi_check_completion_code (obj_cmd_rs,
484                                           IPMI_COMP_CODE_GET_SYSTEM_INFO_PARAMETERS_PARAMETER_NOT_SUPPORTED) == 1)
485           || (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
486               && ipmi_check_completion_code (obj_cmd_rs,
487                                              IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
488         {
489           pstdout_fprintf (state_data->pstate,
490                            stderr,
491                            "%s:%s '%s' option not supported on this system\n",
492                            state_data->prog_data->args->oem_id,
493                            state_data->prog_data->args->oem_command,
494                            state_data->prog_data->args->oem_options[0]);
495           goto cleanup;
496         }
497 
498       pstdout_fprintf (state_data->pstate,
499                        stderr,
500                        "ipmi_cmd_get_system_info_parameters: %s\n",
501                        ipmi_ctx_errormsg (state_data->ipmi_ctx));
502       goto cleanup;
503     }
504 
505   if ((len = fiid_obj_get_data (obj_cmd_rs,
506                                 "configuration_parameter_data",
507                                 configuration_parameter_data,
508                                 IPMI_OEM_MAX_BYTES)) < 0)
509     {
510       pstdout_fprintf (state_data->pstate,
511                        stderr,
512                        "fiid_obj_get_data: 'configuration_parameter_data': %s\n",
513                        fiid_obj_errormsg (obj_cmd_rs));
514       goto cleanup;
515     }
516 
517   if (len > string_len)
518     {
519       pstdout_fprintf (state_data->pstate,
520                        stderr,
521                        "buffer overflow\n");
522       goto cleanup;
523     }
524 
525   memcpy (string,
526           &(configuration_parameter_data[0]),
527           len);
528 
529   if (string_len_ret)
530     (*string_len_ret) = len;
531 
532   rv = 0;
533  cleanup:
534   fiid_obj_destroy (obj_cmd_rs);
535   return (rv);
536 }
537