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
open_door(const char * door_name,int * door_fdp)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
nwam_make_door_call(const char * door_name,int * door_fdp,void * request,size_t request_size)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
send_msg_to_nwam(nwamd_door_arg_t * request)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
nwam_request_register_unregister(nwam_request_type_t type,const char * event_msg_file)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
nwam_request_action(nwam_object_type_t object_type,const char * name,const char * parent,nwam_action_t action)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
nwam_request_state(nwam_object_type_t object_type,const char * name,const char * parent,nwam_state_t * statep,nwam_aux_state_t * auxp)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
nwam_request_wlan(nwam_request_type_t type,const char * name,const char * essid,const char * bssid,uint32_t security_mode,uint_t keyslot,const char * key,boolean_t add_to_known_wlans)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
nwam_request_wlan_scan_results(const char * name,uint_t * num_wlansp,nwam_wlan_t ** wlansp)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
nwam_request_active_priority_group(int64_t * priorityp)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 *
nwam_value_type_to_string(nwam_value_type_t type)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
nwam_string_to_value_type(const char * typestr)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 *
nwam_action_to_string(nwam_action_t action)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 *
nwam_event_type_to_string(int event_type)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 *
nwam_state_to_string(nwam_state_t state)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 *
nwam_aux_state_to_string(nwam_aux_state_t aux_state)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 *
nwam_object_type_to_string(nwam_object_type_t type)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
nwam_string_to_object_type(const char * typestr)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
nwam_errno_to_nwam_error(int errnum)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
nwam_valid_flags(uint64_t flags,uint64_t valid_flags)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
nwam_valid_condition(nwam_value_t value)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
nwam_valid_boolean(nwam_value_t value)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
nwam_valid_uint64(nwam_value_t value)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
nwam_valid_domain(nwam_value_t value)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
nwam_valid_prefix(char * addr,int max_plen)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
nwam_valid_host_v4(nwam_value_t value)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
nwam_valid_route_v4(nwam_value_t value)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
nwam_valid_host_v6(nwam_value_t value)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
nwam_valid_route_v6(nwam_value_t value)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
nwam_valid_host_any(nwam_value_t value)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
nwam_valid_host_or_domain(nwam_value_t value)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
nwam_valid_file(nwam_value_t value)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
nwam_valid_fmri(nwam_value_t value)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
nwam_valid_mac_addr(nwam_value_t value)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
nwam_uid_is_special(void)865 nwam_uid_is_special(void)
866 {
867 uid_t uid = getuid();
868 return (uid == UID_NETADM || uid == 0);
869 }
870
871 nwam_error_t
nwam_get_smf_string_property(const char * fmri,const char * pgname,const char * propname,char ** valuep)872 nwam_get_smf_string_property(const char *fmri, const char *pgname,
873 const char *propname, char **valuep)
874 {
875 scf_handle_t *h = NULL;
876 scf_snapshot_t *snap = NULL;
877 scf_instance_t *inst = NULL;
878 scf_propertygroup_t *pg = NULL;
879 scf_property_t *prop = NULL;
880 scf_value_t *val = NULL;
881 nwam_error_t err = NWAM_SUCCESS;
882
883 if ((*valuep = malloc(NWAM_MAX_NAME_LEN)) == NULL)
884 return (NWAM_NO_MEMORY);
885
886 if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
887 scf_handle_bind(h) != 0 ||
888 (inst = scf_instance_create(h)) == NULL ||
889 (snap = scf_snapshot_create(h)) == NULL ||
890 (pg = scf_pg_create(h)) == NULL ||
891 (prop = scf_property_create(h)) == NULL ||
892 (val = scf_value_create(h)) == NULL) {
893 err = NWAM_ERROR_INTERNAL;
894 goto out;
895 }
896 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst,
897 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
898 err = NWAM_ENTITY_NOT_FOUND;
899 goto out;
900 }
901 /* Retrieve value from running snapshot (if present) */
902 if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
903 scf_snapshot_destroy(snap);
904 snap = NULL;
905 }
906 if (scf_instance_get_pg_composed(inst, snap, pgname, pg) != 0 ||
907 scf_pg_get_property(pg, propname, prop) != 0 ||
908 scf_property_get_value(prop, val) != 0 ||
909 scf_value_get_astring(val, *valuep, NWAM_MAX_NAME_LEN) == -1) {
910 err = NWAM_ENTITY_NOT_FOUND;
911 }
912 out:
913 if (err != NWAM_SUCCESS)
914 free(*valuep);
915
916 scf_value_destroy(val);
917 scf_property_destroy(prop);
918 scf_pg_destroy(pg);
919 if (snap != NULL)
920 scf_snapshot_destroy(snap);
921 scf_instance_destroy(inst);
922 scf_handle_destroy(h);
923
924 return (err);
925 }
926
927 nwam_error_t
nwam_set_smf_string_property(const char * fmri,const char * pgname,const char * propname,const char * propval)928 nwam_set_smf_string_property(const char *fmri, const char *pgname,
929 const char *propname, const char *propval)
930 {
931 scf_handle_t *h = NULL;
932 scf_instance_t *inst = NULL;
933 scf_propertygroup_t *pg = NULL;
934 scf_property_t *prop = NULL;
935 scf_value_t *val = NULL;
936 scf_transaction_t *tx = NULL;
937 scf_transaction_entry_t *ent = NULL;
938 nwam_error_t err = NWAM_SUCCESS;
939 int result;
940
941 if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
942 scf_handle_bind(h) != 0 ||
943 (inst = scf_instance_create(h)) == NULL ||
944 (pg = scf_pg_create(h)) == NULL ||
945 (prop = scf_property_create(h)) == NULL ||
946 (val = scf_value_create(h)) == NULL ||
947 scf_value_set_astring(val, propval) != 0 ||
948 (tx = scf_transaction_create(h)) == NULL ||
949 (ent = scf_entry_create(h)) == NULL) {
950 err = NWAM_ERROR_INTERNAL;
951 goto out;
952 }
953 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst,
954 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0 ||
955 scf_instance_get_pg_composed(inst, NULL, pgname, pg) != 0) {
956 err = NWAM_ENTITY_NOT_FOUND;
957 goto out;
958 }
959
960 retry:
961 if (scf_transaction_start(tx, pg) == -1 ||
962 scf_transaction_property_change(tx, ent, propname, SCF_TYPE_ASTRING)
963 == -1 || scf_entry_add_value(ent, val) != 0) {
964 err = NWAM_ERROR_INTERNAL;
965 goto out;
966 }
967
968 result = scf_transaction_commit(tx);
969 switch (result) {
970 case 1:
971 (void) smf_refresh_instance(fmri);
972 break;
973 case 0:
974 scf_transaction_reset(tx);
975 if (scf_pg_update(pg) == -1) {
976 err = NWAM_ERROR_INTERNAL;
977 goto out;
978 }
979 goto retry;
980 default:
981 err = NWAM_ERROR_INTERNAL;
982 break;
983 }
984 out:
985 scf_value_destroy(val);
986 scf_property_destroy(prop);
987 scf_pg_destroy(pg);
988 scf_instance_destroy(inst);
989 scf_handle_destroy(h);
990
991 return (err);
992 }
993