1 /* 2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistribution of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistribution in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * Neither the name of Sun Microsystems, Inc. or the names of 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * This software is provided "AS IS," without a warranty of any kind. 20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #if defined(HAVE_CONFIG_H) 37 # include <config.h> 38 #endif 39 40 #if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <ifaddrs.h> 46 #include <unistd.h> 47 #include <netdb.h> 48 #endif 49 50 51 #include <ipmitool/ipmi_intf.h> 52 #include <ipmitool/ipmi.h> 53 #include <ipmitool/ipmi_sdr.h> 54 #include <ipmitool/log.h> 55 56 #ifdef IPMI_INTF_OPEN 57 extern struct ipmi_intf ipmi_open_intf; 58 #endif 59 #ifdef IPMI_INTF_IMB 60 extern struct ipmi_intf ipmi_imb_intf; 61 #endif 62 #ifdef IPMI_INTF_LIPMI 63 extern struct ipmi_intf ipmi_lipmi_intf; 64 #endif 65 #ifdef IPMI_INTF_BMC 66 extern struct ipmi_intf ipmi_bmc_intf; 67 #endif 68 #ifdef IPMI_INTF_LAN 69 extern struct ipmi_intf ipmi_lan_intf; 70 #endif 71 #ifdef IPMI_INTF_LANPLUS 72 extern struct ipmi_intf ipmi_lanplus_intf; 73 #endif 74 #ifdef IPMI_INTF_FREE 75 extern struct ipmi_intf ipmi_free_intf; 76 #endif 77 #ifdef IPMI_INTF_SERIAL 78 extern struct ipmi_intf ipmi_serial_term_intf; 79 extern struct ipmi_intf ipmi_serial_bm_intf; 80 #endif 81 #ifdef IPMI_INTF_DUMMY 82 extern struct ipmi_intf ipmi_dummy_intf; 83 #endif 84 85 struct ipmi_intf * ipmi_intf_table[] = { 86 #ifdef IPMI_INTF_OPEN 87 &ipmi_open_intf, 88 #endif 89 #ifdef IPMI_INTF_IMB 90 &ipmi_imb_intf, 91 #endif 92 #ifdef IPMI_INTF_LIPMI 93 &ipmi_lipmi_intf, 94 #endif 95 #ifdef IPMI_INTF_BMC 96 &ipmi_bmc_intf, 97 #endif 98 #ifdef IPMI_INTF_LAN 99 &ipmi_lan_intf, 100 #endif 101 #ifdef IPMI_INTF_LANPLUS 102 &ipmi_lanplus_intf, 103 #endif 104 #ifdef IPMI_INTF_FREE 105 &ipmi_free_intf, 106 #endif 107 #ifdef IPMI_INTF_SERIAL 108 &ipmi_serial_term_intf, 109 &ipmi_serial_bm_intf, 110 #endif 111 #ifdef IPMI_INTF_DUMMY 112 &ipmi_dummy_intf, 113 #endif 114 NULL 115 }; 116 117 /* ipmi_intf_print - Print list of interfaces 118 * 119 * no meaningful return code 120 */ 121 void ipmi_intf_print(struct ipmi_intf_support * intflist) 122 { 123 struct ipmi_intf ** intf; 124 struct ipmi_intf_support * sup; 125 int def = 1; 126 int found; 127 128 lprintf(LOG_NOTICE, "Interfaces:"); 129 130 for (intf = ipmi_intf_table; intf && *intf; intf++) { 131 132 if (intflist != NULL) { 133 found = 0; 134 for (sup=intflist; sup->name != NULL; sup++) { 135 if (strncmp(sup->name, (*intf)->name, strlen(sup->name)) == 0 && 136 strncmp(sup->name, (*intf)->name, strlen((*intf)->name)) == 0 && 137 sup->supported == 1) 138 found = 1; 139 } 140 if (found == 0) 141 continue; 142 } 143 144 lprintf(LOG_NOTICE, "\t%-12s %s %s", 145 (*intf)->name, (*intf)->desc, 146 def ? "[default]" : ""); 147 def = 0; 148 } 149 lprintf(LOG_NOTICE, ""); 150 } 151 152 /* ipmi_intf_load - Load an interface from the interface table above 153 * If no interface name is given return first entry 154 * 155 * @name: interface name to try and load 156 * 157 * returns pointer to inteface structure if found 158 * returns NULL on error 159 */ 160 struct ipmi_intf * ipmi_intf_load(char * name) 161 { 162 struct ipmi_intf ** intf; 163 struct ipmi_intf * i; 164 165 if (name == NULL) { 166 i = ipmi_intf_table[0]; 167 if (i->setup != NULL && (i->setup(i) < 0)) { 168 lprintf(LOG_ERR, "Unable to setup " 169 "interface %s", name); 170 return NULL; 171 } 172 return i; 173 } 174 175 for (intf = ipmi_intf_table; 176 ((intf != NULL) && (*intf != NULL)); 177 intf++) { 178 i = *intf; 179 if (strncmp(name, i->name, strlen(name)) == 0) { 180 if (i->setup != NULL && (i->setup(i) < 0)) { 181 lprintf(LOG_ERR, "Unable to setup " 182 "interface %s", name); 183 return NULL; 184 } 185 return i; 186 } 187 } 188 189 return NULL; 190 } 191 192 void 193 ipmi_intf_session_set_hostname(struct ipmi_intf * intf, char * hostname) 194 { 195 if (intf->session == NULL) 196 return; 197 198 memset(intf->session->hostname, 0, 16); 199 200 if (hostname != NULL) { 201 memcpy(intf->session->hostname, hostname, 202 __min(strlen(hostname), 64)); 203 } 204 } 205 206 void 207 ipmi_intf_session_set_username(struct ipmi_intf * intf, char * username) 208 { 209 if (intf->session == NULL) 210 return; 211 212 memset(intf->session->username, 0, 17); 213 214 if (username == NULL) 215 return; 216 217 memcpy(intf->session->username, username, __min(strlen(username), 16)); 218 } 219 220 void 221 ipmi_intf_session_set_password(struct ipmi_intf * intf, char * password) 222 { 223 if (intf->session == NULL) 224 return; 225 226 memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE); 227 228 if (password == NULL) { 229 intf->session->password = 0; 230 return; 231 } 232 233 intf->session->password = 1; 234 memcpy(intf->session->authcode, password, 235 __min(strlen(password), IPMI_AUTHCODE_BUFFER_SIZE)); 236 } 237 238 void 239 ipmi_intf_session_set_privlvl(struct ipmi_intf * intf, uint8_t level) 240 { 241 if (intf->session == NULL) 242 return; 243 244 intf->session->privlvl = level; 245 } 246 247 void 248 ipmi_intf_session_set_lookupbit(struct ipmi_intf * intf, uint8_t lookupbit) 249 { 250 if (intf->session == NULL) 251 return; 252 253 intf->session->v2_data.lookupbit = lookupbit; 254 } 255 256 void 257 ipmi_intf_session_set_cipher_suite_id(struct ipmi_intf * intf, uint8_t cipher_suite_id) 258 { 259 if (intf->session == NULL) 260 return; 261 262 intf->session->cipher_suite_id = cipher_suite_id; 263 } 264 265 void 266 ipmi_intf_session_set_sol_escape_char(struct ipmi_intf * intf, char sol_escape_char) 267 { 268 if (intf->session == NULL) 269 return; 270 271 intf->session->sol_escape_char = sol_escape_char; 272 } 273 274 void 275 ipmi_intf_session_set_kgkey(struct ipmi_intf * intf, char * kgkey) 276 { 277 if (intf->session == NULL) 278 return; 279 280 memset(intf->session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE); 281 282 if (kgkey == NULL) 283 return; 284 285 memcpy(intf->session->v2_data.kg, kgkey, 286 __min(strlen(kgkey), IPMI_KG_BUFFER_SIZE)); 287 } 288 289 void 290 ipmi_intf_session_set_port(struct ipmi_intf * intf, int port) 291 { 292 if (intf->session == NULL) 293 return; 294 295 intf->session->port = port; 296 } 297 298 void 299 ipmi_intf_session_set_authtype(struct ipmi_intf * intf, uint8_t authtype) 300 { 301 if (intf->session == NULL) 302 return; 303 304 /* clear password field if authtype NONE specified */ 305 if (authtype == IPMI_SESSION_AUTHTYPE_NONE) { 306 memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE); 307 intf->session->password = 0; 308 } 309 310 intf->session->authtype_set = authtype; 311 } 312 313 void 314 ipmi_intf_session_set_timeout(struct ipmi_intf * intf, uint32_t timeout) 315 { 316 if (intf->session == NULL) 317 return; 318 319 intf->session->timeout = timeout; 320 } 321 322 void 323 ipmi_intf_session_set_retry(struct ipmi_intf * intf, int retry) 324 { 325 if (intf->session == NULL) 326 return; 327 328 intf->session->retry = retry; 329 } 330 331 void 332 ipmi_cleanup(struct ipmi_intf * intf) 333 { 334 ipmi_sdr_list_empty(intf); 335 } 336 337 #if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) 338 int 339 ipmi_intf_socket_connect(struct ipmi_intf * intf) 340 { 341 struct ipmi_session *session; 342 343 struct sockaddr_storage addr; 344 struct addrinfo hints; 345 struct addrinfo *rp0 = NULL, *rp; 346 char service[NI_MAXSERV]; 347 int rc; 348 349 if (!intf || intf->session == NULL) { 350 return -1; 351 } 352 353 session = intf->session; 354 355 if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) { 356 lprintf(LOG_ERR, "No hostname specified!"); 357 return -1; 358 } 359 360 /* open port to BMC */ 361 memset(&addr, 0, sizeof(addr)); 362 363 sprintf(service, "%d", session->port); 364 /* Obtain address(es) matching host/port */ 365 memset(&hints, 0, sizeof(hints)); 366 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 367 hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ 368 hints.ai_flags = 0; /* use AI_NUMERICSERV for no name resolution */ 369 hints.ai_protocol = IPPROTO_UDP; /* */ 370 371 if (getaddrinfo(session->hostname, service, &hints, &rp0) != 0) { 372 lprintf(LOG_ERR, "Address lookup for %s failed", 373 session->hostname); 374 return -1; 375 } 376 377 /* getaddrinfo() returns a list of address structures. 378 * Try each address until we successfully connect(2). 379 * If socket(2) (or connect(2)) fails, we (close the socket 380 * and) try the next address. 381 */ 382 383 session->ai_family = AF_UNSPEC; 384 for (rp = rp0; rp != NULL; rp = rp->ai_next) { 385 /* We are only interested in IPv4 and IPv6 */ 386 if ((rp->ai_family != AF_INET6) && (rp->ai_family != AF_INET)) { 387 continue; 388 } 389 390 intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 391 if (intf->fd == -1) { 392 continue; 393 } 394 395 if (rp->ai_family == AF_INET) { 396 if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { 397 memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); 398 session->addrlen = rp->ai_addrlen; 399 session->ai_family = rp->ai_family; 400 break; /* Success */ 401 } 402 } else if (rp->ai_family == AF_INET6) { 403 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr; 404 char hbuf[NI_MAXHOST]; 405 socklen_t len; 406 407 /* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */ 408 if (addr6->sin6_scope_id != 0) { 409 len = sizeof(struct sockaddr_in6); 410 if (getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { 411 lprintf(LOG_DEBUG, "Trying address: %s scope=%d", 412 hbuf, 413 addr6->sin6_scope_id); 414 } 415 if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { 416 memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); 417 session->addrlen = rp->ai_addrlen; 418 session->ai_family = rp->ai_family; 419 break; /* Success */ 420 } 421 } else { 422 /* No scope specified, try to get this from the list of interfaces */ 423 struct ifaddrs *ifaddrs = NULL; 424 struct ifaddrs *ifa = NULL; 425 426 if (getifaddrs(&ifaddrs) < 0) { 427 lprintf(LOG_ERR, "Interface address lookup for %s failed", 428 session->hostname); 429 break; 430 } 431 432 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 433 if (ifa->ifa_addr == NULL) { 434 continue; 435 } 436 437 if (ifa->ifa_addr->sa_family == AF_INET6) { 438 struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr; 439 440 /* Skip unwanted addresses */ 441 if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) { 442 continue; 443 } 444 if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) { 445 continue; 446 } 447 len = sizeof(struct sockaddr_in6); 448 if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { 449 lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d", 450 ifa->ifa_name != NULL ? ifa->ifa_name : "???", 451 hbuf, 452 tmp6->sin6_scope_id); 453 } 454 455 if (tmp6->sin6_scope_id != 0) { 456 addr6->sin6_scope_id = tmp6->sin6_scope_id; 457 } else { 458 /* 459 * No scope information in interface address information 460 * On some OS'es, getifaddrs() is returning out the 'kernel' representation 461 * of scoped addresses which stores the scope in the 3rd and 4th 462 * byte. See also this page: 463 * http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html 464 */ 465 if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr) 466 && (tmp6->sin6_addr.s6_addr16[1] != 0)) { 467 addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr16[1]); 468 } 469 } 470 471 /* OK, now try to connect with the scope id from this interface address */ 472 if (addr6->sin6_scope_id != 0) { 473 if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { 474 memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); 475 session->addrlen = rp->ai_addrlen; 476 session->ai_family = rp->ai_family; 477 lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id); 478 break; /* Success */ 479 } 480 } 481 } 482 } 483 freeifaddrs(ifaddrs); 484 } 485 } 486 if (session->ai_family != AF_UNSPEC) { 487 break; 488 } 489 close(intf->fd); 490 intf->fd = -1; 491 } 492 493 /* No longer needed */ 494 freeaddrinfo(rp0); 495 496 return ((intf->fd != -1) ? 0 : -1); 497 } 498 #endif 499 500