1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <arpa/inet.h> 28 #include <assert.h> 29 #include <atomic.h> 30 #include <ctype.h> 31 #include <errno.h> 32 #include <inet/ip.h> 33 #include <libintl.h> 34 #include <libproc.h> 35 #include <libscf.h> 36 #include <net/if_dl.h> 37 #include <netinet/in.h> 38 #include <pthread.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <strings.h> 42 #include <sys/mman.h> 43 #include <sys/socket.h> 44 #include <sys/types.h> 45 #include <unistd.h> 46 47 #include "libnwam_impl.h" 48 #include <libnwam_priv.h> 49 #include <libnwam.h> 50 51 /* 52 * Utility functions for door access, common validation functions etc. 53 */ 54 55 pthread_mutex_t door_mutex = PTHREAD_MUTEX_INITIALIZER; 56 int nwam_door_fd = -1; 57 58 static int 59 open_door(const char *door_name, int *door_fdp) 60 { 61 struct door_info dinfo; 62 int err = 0; 63 64 (void) pthread_mutex_lock(&door_mutex); 65 66 if (*door_fdp != -1) { 67 /* Check door fd is not old (from previous nwamd). */ 68 if (door_info(*door_fdp, &dinfo) != 0 || 69 (dinfo.di_attributes & DOOR_REVOKED) != 0) { 70 (void) close(*door_fdp); 71 *door_fdp = -1; 72 } 73 } 74 if (*door_fdp == -1) { 75 *door_fdp = open(door_name, 0); 76 if (*door_fdp == -1) 77 err = errno; 78 } 79 80 (void) pthread_mutex_unlock(&door_mutex); 81 82 return (err); 83 } 84 85 int 86 nwam_make_door_call(const char *door_name, int *door_fdp, 87 void *request, size_t request_size) 88 { 89 int err; 90 door_arg_t door_args; 91 92 door_args.data_ptr = (void *)request; 93 door_args.data_size = request_size; 94 door_args.desc_ptr = NULL; 95 door_args.desc_num = 0; 96 door_args.rbuf = (void *)request; 97 door_args.rsize = request_size; 98 99 if ((err = open_door(door_name, door_fdp)) != 0) 100 return (err); 101 102 if (door_call(*door_fdp, &door_args) == -1) 103 return (errno); 104 105 return (0); 106 } 107 108 static nwam_error_t 109 send_msg_to_nwam(nwamd_door_arg_t *request) 110 { 111 int err; 112 113 if ((err = nwam_make_door_call(NWAM_DOOR, &nwam_door_fd, 114 request, sizeof (nwamd_door_arg_t))) != 0) { 115 if (err == ENOENT) 116 return (NWAM_ERROR_BIND); 117 return (nwam_errno_to_nwam_error(err)); 118 } 119 120 switch (request->nwda_status) { 121 case NWAM_REQUEST_STATUS_OK: 122 return (NWAM_SUCCESS); 123 case NWAM_REQUEST_STATUS_UNKNOWN: 124 return (NWAM_INVALID_ARG); 125 case NWAM_REQUEST_STATUS_ALREADY: 126 return (NWAM_ENTITY_IN_USE); 127 case NWAM_REQUEST_STATUS_FAILED: 128 return (request->nwda_error); 129 default: 130 return (NWAM_ERROR_INTERNAL); 131 } 132 } 133 134 nwam_error_t 135 nwam_request_register_unregister(nwam_request_type_t type, 136 const char *event_msg_file) 137 { 138 nwamd_door_arg_t req; 139 140 req.nwda_type = type; 141 142 (void) strlcpy(req.nwda_data.nwdad_register_info.nwdad_name, 143 event_msg_file, 144 sizeof (req.nwda_data.nwdad_register_info.nwdad_name)); 145 146 return (send_msg_to_nwam(&req)); 147 } 148 149 nwam_error_t 150 nwam_request_action(nwam_object_type_t object_type, 151 const char *name, const char *parent, nwam_action_t action) 152 { 153 nwamd_door_arg_t req; 154 155 assert(name != NULL); 156 157 req.nwda_type = NWAM_REQUEST_TYPE_ACTION; 158 req.nwda_data.nwdad_object_action.nwdad_object_type = object_type; 159 req.nwda_data.nwdad_object_action.nwdad_action = action; 160 (void) strlcpy(req.nwda_data.nwdad_object_action.nwdad_name, name, 161 sizeof (req.nwda_data.nwdad_object_action.nwdad_name)); 162 if (parent != NULL) { 163 (void) strlcpy(req.nwda_data.nwdad_object_action.nwdad_parent, 164 parent, 165 sizeof (req.nwda_data.nwdad_object_action.nwdad_parent)); 166 } else { 167 req.nwda_data.nwdad_object_action.nwdad_parent[0] = '\0'; 168 } 169 170 return (send_msg_to_nwam(&req)); 171 } 172 173 nwam_error_t 174 nwam_request_state(nwam_object_type_t object_type, const char *name, 175 const char *parent, nwam_state_t *statep, nwam_aux_state_t *auxp) 176 { 177 nwamd_door_arg_t req; 178 nwam_error_t err; 179 180 assert(name != NULL && statep != NULL && auxp != NULL); 181 182 req.nwda_type = NWAM_REQUEST_TYPE_STATE; 183 184 req.nwda_data.nwdad_object_state.nwdad_object_type = object_type; 185 186 (void) strlcpy(req.nwda_data.nwdad_object_state.nwdad_name, name, 187 sizeof (req.nwda_data.nwdad_object_state.nwdad_name)); 188 if (parent != NULL) { 189 (void) strlcpy(req.nwda_data.nwdad_object_state.nwdad_parent, 190 parent, 191 sizeof (req.nwda_data.nwdad_object_state.nwdad_parent)); 192 } 193 194 err = send_msg_to_nwam(&req); 195 196 if (err == NWAM_SUCCESS) { 197 *statep = req.nwda_data.nwdad_object_state.nwdad_state; 198 *auxp = req.nwda_data.nwdad_object_state.nwdad_aux_state; 199 } 200 201 return (err); 202 } 203 204 nwam_error_t 205 nwam_request_wlan(nwam_request_type_t type, const char *name, 206 const char *essid, const char *bssid, uint32_t security_mode, 207 uint_t keyslot, const char *key, boolean_t add_to_known_wlans) 208 { 209 nwamd_door_arg_t req; 210 211 assert(name != NULL); 212 213 req.nwda_type = type; 214 215 (void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_name, name, 216 sizeof (req.nwda_data.nwdad_wlan_info)); 217 if (essid != NULL) { 218 (void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_essid, essid, 219 sizeof (req.nwda_data.nwdad_wlan_info.nwdad_essid)); 220 } else { 221 req.nwda_data.nwdad_wlan_info.nwdad_essid[0] = '\0'; 222 } 223 if (bssid != NULL) { 224 (void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_bssid, bssid, 225 sizeof (req.nwda_data.nwdad_wlan_info.nwdad_bssid)); 226 } else { 227 req.nwda_data.nwdad_wlan_info.nwdad_bssid[0] = '\0'; 228 } 229 if (key != NULL) { 230 (void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_key, key, 231 sizeof (req.nwda_data.nwdad_wlan_info.nwdad_key)); 232 req.nwda_data.nwdad_wlan_info.nwdad_keyslot = keyslot; 233 } else { 234 req.nwda_data.nwdad_wlan_info.nwdad_key[0] = '\0'; 235 } 236 237 req.nwda_data.nwdad_wlan_info.nwdad_security_mode = security_mode; 238 req.nwda_data.nwdad_wlan_info.nwdad_add_to_known_wlans = 239 add_to_known_wlans; 240 241 return (send_msg_to_nwam(&req)); 242 } 243 244 nwam_error_t 245 nwam_request_wlan_scan_results(const char *name, uint_t *num_wlansp, 246 nwam_wlan_t **wlansp) 247 { 248 nwamd_door_arg_t req; 249 nwam_error_t err; 250 251 assert(name != NULL && num_wlansp != NULL && wlansp != NULL); 252 253 req.nwda_type = NWAM_REQUEST_TYPE_WLAN_SCAN_RESULTS; 254 255 (void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_name, name, 256 sizeof (req.nwda_data.nwdad_wlan_info.nwdad_name)); 257 258 if ((err = send_msg_to_nwam(&req)) != NWAM_SUCCESS) 259 return (err); 260 261 *num_wlansp = req.nwda_data.nwdad_wlan_info.nwdad_num_wlans; 262 263 *wlansp = calloc(*num_wlansp, sizeof (nwam_wlan_t)); 264 if (*wlansp == NULL) 265 return (NWAM_NO_MEMORY); 266 267 (void) memcpy(*wlansp, req.nwda_data.nwdad_wlan_info.nwdad_wlans, 268 *num_wlansp * sizeof (nwam_wlan_t)); 269 270 return (NWAM_SUCCESS); 271 } 272 273 nwam_error_t 274 nwam_request_active_priority_group(int64_t *priorityp) 275 { 276 nwamd_door_arg_t req; 277 nwam_error_t err; 278 279 assert(priorityp != NULL); 280 281 req.nwda_type = NWAM_REQUEST_TYPE_PRIORITY_GROUP; 282 err = send_msg_to_nwam(&req); 283 284 if (err == NWAM_SUCCESS) 285 *priorityp = 286 req.nwda_data.nwdad_priority_group_info.nwdad_priority; 287 288 return (err); 289 } 290 291 /* String conversion functions */ 292 293 const char * 294 nwam_value_type_to_string(nwam_value_type_t type) 295 { 296 switch (type) { 297 case NWAM_VALUE_TYPE_BOOLEAN: 298 return ("boolean"); 299 case NWAM_VALUE_TYPE_INT64: 300 return ("int64"); 301 case NWAM_VALUE_TYPE_UINT64: 302 return ("uint64"); 303 case NWAM_VALUE_TYPE_STRING: 304 return ("string"); 305 default: 306 return ("unknown"); 307 } 308 } 309 310 nwam_value_type_t 311 nwam_string_to_value_type(const char *typestr) 312 { 313 if (strncmp(typestr, nwam_value_type_to_string(NWAM_VALUE_TYPE_BOOLEAN), 314 strlen(typestr)) == 0) 315 return (NWAM_VALUE_TYPE_BOOLEAN); 316 if (strncmp(typestr, nwam_value_type_to_string(NWAM_VALUE_TYPE_INT64), 317 strlen(typestr)) == 0) 318 return (NWAM_VALUE_TYPE_INT64); 319 if (strncmp(typestr, nwam_value_type_to_string(NWAM_VALUE_TYPE_UINT64), 320 strlen(typestr)) == 0) 321 return (NWAM_VALUE_TYPE_UINT64); 322 if (strncmp(typestr, nwam_value_type_to_string(NWAM_VALUE_TYPE_STRING), 323 strlen(typestr)) == 0) 324 return (NWAM_VALUE_TYPE_STRING); 325 return (NWAM_VALUE_TYPE_UNKNOWN); 326 } 327 328 const char * 329 nwam_action_to_string(nwam_action_t action) 330 { 331 switch (action) { 332 case NWAM_ACTION_ADD: 333 return ("add"); 334 case NWAM_ACTION_REMOVE: 335 return ("remove"); 336 case NWAM_ACTION_REFRESH: 337 return ("refresh"); 338 case NWAM_ACTION_ENABLE: 339 return ("enable"); 340 case NWAM_ACTION_DISABLE: 341 return ("disable"); 342 case NWAM_ACTION_DESTROY: 343 return ("destroy"); 344 default: 345 return ("unknown"); 346 } 347 } 348 349 const char * 350 nwam_event_type_to_string(int event_type) 351 { 352 switch (event_type) { 353 case NWAM_EVENT_TYPE_NOOP: 354 return ("NOOP"); 355 case NWAM_EVENT_TYPE_INIT: 356 return ("INIT"); 357 case NWAM_EVENT_TYPE_SHUTDOWN: 358 return ("SHUTDOWN"); 359 case NWAM_EVENT_TYPE_OBJECT_ACTION: 360 return ("OBJECT_ACTION"); 361 case NWAM_EVENT_TYPE_OBJECT_STATE: 362 return ("OBJECT_STATE"); 363 case NWAM_EVENT_TYPE_PRIORITY_GROUP: 364 return ("PRIORITY_GROUP"); 365 case NWAM_EVENT_TYPE_INFO: 366 return ("INFO"); 367 case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT: 368 return ("WLAN_SCAN_REPORT"); 369 case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE: 370 return ("WLAN_NEED_CHOICE"); 371 case NWAM_EVENT_TYPE_WLAN_NEED_KEY: 372 return ("WLAN_NEED_KEY"); 373 case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT: 374 return ("WLAN_CONNECTION_REPORT"); 375 case NWAM_EVENT_TYPE_IF_ACTION: 376 return ("IF_ACTION"); 377 case NWAM_EVENT_TYPE_IF_STATE: 378 return ("IF_STATE"); 379 case NWAM_EVENT_TYPE_LINK_ACTION: 380 return ("LINK_ACTION"); 381 case NWAM_EVENT_TYPE_LINK_STATE: 382 return ("LINK_STATE"); 383 default: 384 return ("UNKNOWN"); 385 } 386 } 387 388 const char * 389 nwam_state_to_string(nwam_state_t state) 390 { 391 switch (state) { 392 case NWAM_STATE_UNINITIALIZED: 393 return ("uninitialized"); 394 case NWAM_STATE_INITIALIZED: 395 return ("initialized"); 396 case NWAM_STATE_OFFLINE: 397 return ("offline"); 398 case NWAM_STATE_OFFLINE_TO_ONLINE: 399 return ("offline*"); 400 case NWAM_STATE_ONLINE_TO_OFFLINE: 401 return ("online*"); 402 case NWAM_STATE_ONLINE: 403 return ("online"); 404 case NWAM_STATE_MAINTENANCE: 405 return ("maintenance"); 406 case NWAM_STATE_DEGRADED: 407 return ("degraded"); 408 case NWAM_STATE_DISABLED: 409 return ("disabled"); 410 default: 411 return ("unknown"); 412 } 413 } 414 415 const char * 416 nwam_aux_state_to_string(nwam_aux_state_t aux_state) 417 { 418 switch (aux_state) { 419 case NWAM_AUX_STATE_UNINITIALIZED: 420 return ("uninitialized"); 421 case NWAM_AUX_STATE_INITIALIZED: 422 return ("(re)initialized but not configured"); 423 case NWAM_AUX_STATE_CONDITIONS_NOT_MET: 424 return ("conditions for activation are unmet"); 425 case NWAM_AUX_STATE_MANUAL_DISABLE: 426 return ("disabled by administrator"); 427 case NWAM_AUX_STATE_METHOD_FAILED: 428 return ("method/service failed"); 429 case NWAM_AUX_STATE_METHOD_MISSING: 430 return ("method or FMRI not specified"); 431 case NWAM_AUX_STATE_INVALID_CONFIG: 432 return ("invalid configuration values"); 433 case NWAM_AUX_STATE_METHOD_RUNNING: 434 return ("method/service executing"); 435 case NWAM_AUX_STATE_ACTIVE: 436 return ("active"); 437 case NWAM_AUX_STATE_LINK_WIFI_SCANNING: 438 return ("scanning for WiFi networks"); 439 case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION: 440 return ("need WiFi network selection"); 441 case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY: 442 return ("need WiFi security key"); 443 case NWAM_AUX_STATE_LINK_WIFI_CONNECTING: 444 return ("connecting to WiFi network"); 445 case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR: 446 return ("waiting for IP address to be set"); 447 case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT: 448 return ("DHCP wait timeout, still trying..."); 449 case NWAM_AUX_STATE_IF_DUPLICATE_ADDR: 450 return ("duplicate address detected"); 451 case NWAM_AUX_STATE_UP: 452 return ("interface/link is up"); 453 case NWAM_AUX_STATE_DOWN: 454 return ("interface/link is down"); 455 case NWAM_AUX_STATE_NOT_FOUND: 456 return ("interface/link not found"); 457 default: 458 return ("unknown"); 459 } 460 } 461 462 const char * 463 nwam_object_type_to_string(nwam_object_type_t type) 464 { 465 switch (type) { 466 case NWAM_OBJECT_TYPE_NCP: 467 return ("ncp"); 468 case NWAM_OBJECT_TYPE_NCU: 469 return ("ncu"); 470 case NWAM_OBJECT_TYPE_LOC: 471 return ("loc"); 472 case NWAM_OBJECT_TYPE_ENM: 473 return ("enm"); 474 case NWAM_OBJECT_TYPE_KNOWN_WLAN: 475 return ("known wlan"); 476 default: 477 return ("unknown"); 478 } 479 } 480 481 nwam_object_type_t 482 nwam_string_to_object_type(const char *typestr) 483 { 484 if (strcasecmp(typestr, 485 nwam_object_type_to_string(NWAM_OBJECT_TYPE_NCP)) == 0) 486 return (NWAM_OBJECT_TYPE_NCP); 487 if (strcasecmp(typestr, 488 nwam_object_type_to_string(NWAM_OBJECT_TYPE_NCU)) == 0) 489 return (NWAM_OBJECT_TYPE_NCU); 490 if (strcasecmp(typestr, 491 nwam_object_type_to_string(NWAM_OBJECT_TYPE_LOC)) == 0) 492 return (NWAM_OBJECT_TYPE_LOC); 493 if (strcasecmp(typestr, 494 nwam_object_type_to_string(NWAM_OBJECT_TYPE_ENM)) == 0) 495 return (NWAM_OBJECT_TYPE_ENM); 496 if (strcasecmp(typestr, 497 nwam_object_type_to_string(NWAM_OBJECT_TYPE_KNOWN_WLAN)) == 0) 498 return (NWAM_OBJECT_TYPE_KNOWN_WLAN); 499 return (NWAM_OBJECT_TYPE_UNKNOWN); 500 } 501 502 nwam_error_t 503 nwam_errno_to_nwam_error(int errnum) 504 { 505 switch (errnum) { 506 case 0: 507 return (NWAM_SUCCESS); 508 case EBADF: 509 return (NWAM_ERROR_BIND); 510 case EPERM: 511 case EACCES: 512 return (NWAM_PERMISSION_DENIED); 513 case ENOENT: 514 return (NWAM_ENTITY_NOT_FOUND); 515 case EIDRM: 516 return (NWAM_ENTITY_INVALID); 517 case EEXIST: 518 return (NWAM_ENTITY_EXISTS); 519 case EAGAIN: 520 case EBUSY: 521 return (NWAM_ENTITY_IN_USE); 522 case ENOMEM: 523 case ENOSPC: 524 return (NWAM_NO_MEMORY); 525 case EINVAL: 526 case E2BIG: 527 return (NWAM_INVALID_ARG); 528 default: 529 return (NWAM_ERROR_INTERNAL); 530 } 531 } 532 533 /* Common validation functions */ 534 535 /* 536 * Do the flags represent a subset of valid_flags? 537 */ 538 nwam_error_t 539 nwam_valid_flags(uint64_t flags, uint64_t valid_flags) 540 { 541 542 if ((flags | valid_flags) != valid_flags) 543 return (NWAM_INVALID_ARG); 544 return (NWAM_SUCCESS); 545 } 546 547 nwam_error_t 548 nwam_valid_condition(nwam_value_t value) 549 { 550 char **conditions; 551 uint_t i, numvalues; 552 nwam_condition_object_type_t object_type; 553 nwam_condition_t condition; 554 555 if (nwam_value_get_string_array(value, &conditions, &numvalues) 556 != NWAM_SUCCESS) 557 return (NWAM_ENTITY_INVALID_VALUE); 558 559 for (i = 0; i < numvalues; i++) { 560 char *object_name = NULL; 561 562 if (nwam_condition_string_to_condition(conditions[i], 563 &object_type, &condition, &object_name) != NWAM_SUCCESS) 564 return (NWAM_ENTITY_INVALID_VALUE); 565 if (object_name != NULL) 566 free(object_name); 567 } 568 return (NWAM_SUCCESS); 569 } 570 571 /* check if boolean values are correct, generalize for array of booleans */ 572 nwam_error_t 573 nwam_valid_boolean(nwam_value_t value) 574 { 575 boolean_t *val; 576 uint_t i, numvalues; 577 578 if (nwam_value_get_boolean_array(value, &val, &numvalues) 579 != NWAM_SUCCESS) 580 return (NWAM_ENTITY_INVALID_VALUE); 581 582 for (i = 0; i < numvalues; i++) { 583 if (val[i] != B_TRUE && val[i] != B_FALSE) 584 return (NWAM_ENTITY_INVALID_VALUE); 585 } 586 return (NWAM_SUCCESS); 587 } 588 589 /* check if uint64 values are correct, generalize for array of ints */ 590 nwam_error_t 591 nwam_valid_uint64(nwam_value_t value) 592 { 593 int64_t *val; 594 uint_t i, numvalues; 595 596 if (nwam_value_get_int64_array(value, &val, &numvalues) 597 != NWAM_SUCCESS) 598 return (NWAM_ENTITY_INVALID_VALUE); 599 600 for (i = 0; i < numvalues; i++) { 601 if (val[i] < 0) 602 return (NWAM_ENTITY_INVALID_VALUE); 603 } 604 return (NWAM_SUCCESS); 605 } 606 607 /* check if domain names are correct, generalize for array of domains */ 608 nwam_error_t 609 nwam_valid_domain(nwam_value_t value) 610 { 611 char **domainvalues, *domain; 612 uint_t i, numvalues; 613 int len, j; 614 615 if (nwam_value_get_string_array(value, &domainvalues, &numvalues) 616 != NWAM_SUCCESS) 617 return (NWAM_ENTITY_INVALID_VALUE); 618 619 for (i = 0; i < numvalues; i++) { 620 /* 621 * First and last character must be alphanumeric. 622 * Only '.' and '-' are allowed. 623 */ 624 domain = domainvalues[i]; 625 len = strlen(domain); 626 if (!isalnum(domain[0]) || !isalnum(domain[len-1])) 627 return (NWAM_ENTITY_INVALID_VALUE); 628 for (j = 0; j < len; j++) { 629 if (!isalnum(domain[j]) && 630 domain[j] != '.' && domain[j] != '-') 631 return (NWAM_ENTITY_INVALID_VALUE); 632 } 633 } 634 return (NWAM_SUCCESS); 635 } 636 637 /* check if address prefix is valid */ 638 static nwam_error_t 639 nwam_valid_prefix(char *addr, int max_plen) 640 { 641 char *prefix, *end; 642 int prefixlen; 643 644 if ((prefix = strchr(addr, '/')) != NULL) { 645 prefix++; 646 prefixlen = strtol(prefix, &end, 10); 647 if (prefix == end || prefixlen < 0 || prefixlen > max_plen) 648 return (NWAM_ENTITY_INVALID_VALUE); 649 } 650 return (NWAM_SUCCESS); 651 } 652 653 /* check if IPv4 addresses are correct, generalize for array of addresses */ 654 nwam_error_t 655 nwam_valid_host_v4(nwam_value_t value) 656 { 657 char **addrvalues, *addr; 658 uint_t i, numvalues; 659 struct sockaddr_in sa; 660 661 if (nwam_value_get_string_array(value, &addrvalues, &numvalues) 662 != NWAM_SUCCESS) 663 return (NWAM_ENTITY_INVALID_VALUE); 664 665 for (i = 0; i < numvalues; i++) { 666 addr = strdup(addrvalues[i]); 667 if (nwam_valid_prefix(addr, IP_ABITS) != NWAM_SUCCESS) { 668 free(addr); 669 return (NWAM_ENTITY_INVALID_VALUE); 670 } 671 /* replace '/' with '\0' */ 672 addr = strsep(&addr, "/"); 673 if (inet_pton(AF_INET, addr, &(sa.sin_addr)) != 1) { 674 free(addr); 675 return (NWAM_ENTITY_INVALID_VALUE); 676 } 677 free(addr); 678 } 679 return (NWAM_SUCCESS); 680 } 681 682 /* Check if IPv4 address for default route is valid */ 683 nwam_error_t 684 nwam_valid_route_v4(nwam_value_t value) 685 { 686 char *addrvalue; 687 struct sockaddr_in sa; 688 689 if (nwam_value_get_string(value, &addrvalue) != NWAM_SUCCESS) 690 return (NWAM_ENTITY_INVALID_VALUE); 691 692 if (inet_pton(AF_INET, addrvalue, &(sa.sin_addr)) != 1) 693 return (NWAM_ENTITY_INVALID_VALUE); 694 695 return (NWAM_SUCCESS); 696 } 697 698 /* check if IPv6 addresses are correct, generalize for array of addresses */ 699 nwam_error_t 700 nwam_valid_host_v6(nwam_value_t value) 701 { 702 char **addrvalues, *addr; 703 uint_t i, numvalues; 704 struct sockaddr_in6 sa; 705 706 if (nwam_value_get_string_array(value, &addrvalues, &numvalues) 707 != NWAM_SUCCESS) 708 return (NWAM_ENTITY_INVALID_VALUE); 709 710 for (i = 0; i < numvalues; i++) { 711 addr = strdup(addrvalues[i]); 712 if (nwam_valid_prefix(addr, IPV6_ABITS) != NWAM_SUCCESS) { 713 free(addr); 714 return (NWAM_ENTITY_INVALID_VALUE); 715 } 716 /* replace '/' with '\0' */ 717 addr = strsep(&addr, "/"); 718 if (inet_pton(AF_INET6, addr, &(sa.sin6_addr)) != 1) { 719 free(addr); 720 return (NWAM_ENTITY_INVALID_VALUE); 721 } 722 free(addr); 723 } 724 return (NWAM_SUCCESS); 725 } 726 727 /* Check if IPv4 address for default route is valid */ 728 nwam_error_t 729 nwam_valid_route_v6(nwam_value_t value) 730 { 731 char *addrvalue; 732 struct sockaddr_in6 sa; 733 734 if (nwam_value_get_string(value, &addrvalue) != NWAM_SUCCESS) 735 return (NWAM_ENTITY_INVALID_VALUE); 736 737 if (inet_pton(AF_INET6, addrvalue, &(sa.sin6_addr)) != 1) 738 return (NWAM_ENTITY_INVALID_VALUE); 739 740 return (NWAM_SUCCESS); 741 } 742 743 nwam_error_t 744 nwam_valid_host_any(nwam_value_t value) 745 { 746 if (nwam_valid_host_v4(value) != NWAM_SUCCESS && 747 nwam_valid_host_v6(value) != NWAM_SUCCESS) 748 return (NWAM_ENTITY_INVALID_VALUE); 749 return (NWAM_SUCCESS); 750 } 751 752 nwam_error_t 753 nwam_valid_host_or_domain(nwam_value_t value) 754 { 755 if (nwam_valid_host_any(value) != NWAM_SUCCESS && 756 nwam_valid_domain(value) != NWAM_SUCCESS) 757 return (NWAM_ENTITY_INVALID_VALUE); 758 return (NWAM_SUCCESS); 759 } 760 761 /* We do not validate file existence, merely that it is an absolute path. */ 762 nwam_error_t 763 nwam_valid_file(nwam_value_t value) 764 { 765 char **files; 766 uint_t i, numvalues; 767 768 if (nwam_value_get_string_array(value, &files, &numvalues) 769 != NWAM_SUCCESS) 770 return (NWAM_ENTITY_INVALID_VALUE); 771 772 for (i = 0; i < numvalues; i++) { 773 int j = 0; 774 while (isspace(files[i][j])) 775 j++; 776 if (files[i][j] != '/') 777 return (NWAM_ENTITY_INVALID_VALUE); 778 } 779 return (NWAM_SUCCESS); 780 } 781 782 /* 783 * We do not validate existence of the object pointed to by the FMRI 784 * but merely ensure that it is a valid FMRI. We do this by 785 * using scf_handle_decode_fmri(), but ignore all errors bar 786 * SCF_ERROR_INVALID_ARGUMENT (which indicates the FMRI is invalid). 787 */ 788 nwam_error_t 789 nwam_valid_fmri(nwam_value_t value) 790 { 791 char **valstr; 792 scf_handle_t *h = NULL; 793 scf_service_t *svc = NULL; 794 uint_t i, numvalues; 795 nwam_error_t err = NWAM_SUCCESS; 796 797 if ((err = nwam_value_get_string_array(value, &valstr, &numvalues)) 798 != NWAM_SUCCESS) 799 return (err); 800 801 h = scf_handle_create(SCF_VERSION); 802 if (h == NULL) 803 return (NWAM_ERROR_INTERNAL); 804 805 if (scf_handle_bind(h) != 0) { 806 err = NWAM_ERROR_INTERNAL; 807 goto out; 808 } 809 810 if ((svc = scf_service_create(h)) == NULL) { 811 err = NWAM_ERROR_INTERNAL; 812 goto out; 813 } 814 815 816 for (i = 0; i < numvalues; i++) { 817 if (scf_handle_decode_fmri(h, valstr[i], NULL, svc, 818 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == 0 || 819 scf_error() != SCF_ERROR_INVALID_ARGUMENT) { 820 err = NWAM_SUCCESS; 821 continue; 822 } 823 err = NWAM_ENTITY_INVALID_VALUE; 824 break; 825 } 826 out: 827 scf_service_destroy(svc); 828 scf_handle_destroy(h); 829 return (err); 830 } 831 832 /* verifies mac-address and bssids */ 833 nwam_error_t 834 nwam_valid_mac_addr(nwam_value_t value) 835 { 836 char **mac_addrs, *addr; 837 uchar_t *hwaddr; 838 int hwaddrlen, j; 839 uint_t i, numvalues; 840 841 if (nwam_value_get_string_array(value, &mac_addrs, &numvalues) 842 != NWAM_SUCCESS) 843 return (NWAM_ENTITY_INVALID_VALUE); 844 845 for (i = 0; i < numvalues; i++) { 846 addr = mac_addrs[i]; 847 j = 0; 848 849 /* validate that a-fA-F0-9 and ':' only */ 850 while (addr[j] != 0) { 851 if (!isxdigit(addr[j]) && addr[j] != ':') 852 return (NWAM_ENTITY_INVALID_VALUE); 853 j++; 854 } 855 856 if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) 857 return (NWAM_ENTITY_INVALID_VALUE); 858 free(hwaddr); 859 } 860 861 return (NWAM_SUCCESS); 862 } 863 864 boolean_t 865 nwam_uid_is_netadm(void) 866 { 867 return (getuid() == UID_NETADM); 868 } 869 870 nwam_error_t 871 nwam_get_smf_string_property(const char *fmri, const char *pgname, 872 const char *propname, char **valuep) 873 { 874 scf_handle_t *h = NULL; 875 scf_snapshot_t *snap = NULL; 876 scf_instance_t *inst = NULL; 877 scf_propertygroup_t *pg = NULL; 878 scf_property_t *prop = NULL; 879 scf_value_t *val = NULL; 880 nwam_error_t err = NWAM_SUCCESS; 881 882 if ((*valuep = malloc(NWAM_MAX_NAME_LEN)) == NULL) 883 return (NWAM_NO_MEMORY); 884 885 if ((h = scf_handle_create(SCF_VERSION)) == NULL || 886 scf_handle_bind(h) != 0 || 887 (inst = scf_instance_create(h)) == NULL || 888 (snap = scf_snapshot_create(h)) == NULL || 889 (pg = scf_pg_create(h)) == NULL || 890 (prop = scf_property_create(h)) == NULL || 891 (val = scf_value_create(h)) == NULL) { 892 err = NWAM_ERROR_INTERNAL; 893 goto out; 894 } 895 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, 896 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 897 err = NWAM_ENTITY_NOT_FOUND; 898 goto out; 899 } 900 /* Retrieve value from running snapshot (if present) */ 901 if (scf_instance_get_snapshot(inst, "running", snap) != 0) { 902 scf_snapshot_destroy(snap); 903 snap = NULL; 904 } 905 if (scf_instance_get_pg_composed(inst, snap, pgname, pg) != 0 || 906 scf_pg_get_property(pg, propname, prop) != 0 || 907 scf_property_get_value(prop, val) != 0 || 908 scf_value_get_astring(val, *valuep, NWAM_MAX_NAME_LEN) == -1) { 909 err = NWAM_ENTITY_NOT_FOUND; 910 } 911 out: 912 if (err != NWAM_SUCCESS) 913 free(*valuep); 914 915 scf_value_destroy(val); 916 scf_property_destroy(prop); 917 scf_pg_destroy(pg); 918 if (snap != NULL) 919 scf_snapshot_destroy(snap); 920 scf_instance_destroy(inst); 921 scf_handle_destroy(h); 922 923 return (err); 924 } 925 926 nwam_error_t 927 nwam_set_smf_string_property(const char *fmri, const char *pgname, 928 const char *propname, const char *propval) 929 { 930 scf_handle_t *h = NULL; 931 scf_instance_t *inst = NULL; 932 scf_propertygroup_t *pg = NULL; 933 scf_property_t *prop = NULL; 934 scf_value_t *val = NULL; 935 scf_transaction_t *tx = NULL; 936 scf_transaction_entry_t *ent = NULL; 937 nwam_error_t err = NWAM_SUCCESS; 938 int result; 939 940 if ((h = scf_handle_create(SCF_VERSION)) == NULL || 941 scf_handle_bind(h) != 0 || 942 (inst = scf_instance_create(h)) == NULL || 943 (pg = scf_pg_create(h)) == NULL || 944 (prop = scf_property_create(h)) == NULL || 945 (val = scf_value_create(h)) == NULL || 946 scf_value_set_astring(val, propval) != 0 || 947 (tx = scf_transaction_create(h)) == NULL || 948 (ent = scf_entry_create(h)) == NULL) { 949 err = NWAM_ERROR_INTERNAL; 950 goto out; 951 } 952 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, 953 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0 || 954 scf_instance_get_pg_composed(inst, NULL, pgname, pg) != 0) { 955 err = NWAM_ENTITY_NOT_FOUND; 956 goto out; 957 } 958 959 retry: 960 if (scf_transaction_start(tx, pg) == -1 || 961 scf_transaction_property_change(tx, ent, propname, SCF_TYPE_ASTRING) 962 == -1 || scf_entry_add_value(ent, val) != 0) { 963 err = NWAM_ERROR_INTERNAL; 964 goto out; 965 } 966 967 result = scf_transaction_commit(tx); 968 switch (result) { 969 case 1: 970 (void) smf_refresh_instance(fmri); 971 break; 972 case 0: 973 scf_transaction_reset(tx); 974 if (scf_pg_update(pg) == -1) { 975 err = NWAM_ERROR_INTERNAL; 976 goto out; 977 } 978 goto retry; 979 default: 980 err = NWAM_ERROR_INTERNAL; 981 break; 982 } 983 out: 984 scf_value_destroy(val); 985 scf_property_destroy(prop); 986 scf_pg_destroy(pg); 987 scf_instance_destroy(inst); 988 scf_handle_destroy(h); 989 990 return (err); 991 } 992