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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
34 #include <sys/dld_ioc.h>
35 #include <libinetutil.h>
36 #include <libdllink.h>
37 #include <libdladm_impl.h>
39 static dladm_status_t
i_dladm_set_secobj_db(dladm_handle_t
, const char *,
40 dladm_secobj_class_t
, uint8_t *, uint_t
);
41 static dladm_status_t
i_dladm_get_secobj_db(dladm_handle_t
, const char *,
42 dladm_secobj_class_t
*, uint8_t *, uint_t
*);
43 static dladm_status_t
i_dladm_unset_secobj_db(dladm_handle_t
, const char *);
44 static dladm_status_t
i_dladm_walk_secobj_db(dladm_handle_t
, void *,
45 boolean_t (*)(dladm_handle_t
, void *,
48 typedef struct secobj_class_info
{
50 dld_secobj_class_t sc_dldclass
;
51 } secobj_class_info_t
;
53 static secobj_class_info_t secobj_class_table
[] = {
54 {"wep", DLD_SECOBJ_CLASS_WEP
},
55 {"wpa", DLD_SECOBJ_CLASS_WPA
}
58 #define SECOBJ_MAXBUFSZ 65536
59 #define NSECOBJCLASS \
60 (sizeof (secobj_class_table) / sizeof (secobj_class_info_t))
63 dladm_check_secobjclass(dladm_secobj_class_t
class)
65 return (class >= 0 && class < NSECOBJCLASS
);
69 dladm_str2secobjclass(const char *str
, dladm_secobj_class_t
*class)
72 secobj_class_info_t
*sp
;
74 for (i
= 0; i
< NSECOBJCLASS
; i
++) {
75 sp
= &secobj_class_table
[i
];
76 if (strcasecmp(str
, sp
->sc_name
) == 0) {
78 return (DLADM_STATUS_OK
);
81 return (DLADM_STATUS_BADARG
);
85 dladm_secobjclass2str(dladm_secobj_class_t
class, char *buf
)
89 if (!dladm_check_secobjclass(class))
92 s
= secobj_class_table
[class].sc_name
;
94 (void) snprintf(buf
, DLADM_STRSIZE
, "%s", s
);
99 dladm_convert_secobjclass(dladm_secobj_class_t
class,
100 dld_secobj_class_t
*dldclass
)
102 if (!dladm_check_secobjclass(class))
105 *dldclass
= secobj_class_table
[class].sc_dldclass
;
110 dladm_convert_dldsecobjclass(dld_secobj_class_t dldclass
,
111 dladm_secobj_class_t
*class)
114 secobj_class_info_t
*sp
;
116 for (i
= 0; i
< NSECOBJCLASS
; i
++) {
117 sp
= &secobj_class_table
[i
];
118 if (dldclass
== sp
->sc_dldclass
) {
127 dladm_set_secobj(dladm_handle_t handle
, const char *obj_name
,
128 dladm_secobj_class_t
class, uint8_t *obj_val
, uint_t obj_len
, uint_t flags
)
130 dladm_status_t status
= DLADM_STATUS_OK
;
131 dld_ioc_secobj_set_t secobj_set
;
134 if (!dladm_valid_secobj_name(obj_name
))
135 return (DLADM_STATUS_BADARG
);
137 if (!dladm_check_secobjclass(class) || flags
== 0 ||
138 obj_name
== NULL
|| strlen(obj_name
) > DLD_SECOBJ_NAME_MAX
||
139 obj_val
== NULL
|| obj_len
== 0 || obj_len
> DLD_SECOBJ_VAL_MAX
)
140 return (DLADM_STATUS_BADARG
);
142 if ((flags
& DLADM_OPT_ACTIVE
) == 0)
145 bzero(&secobj_set
, sizeof (secobj_set
));
146 objp
= &secobj_set
.ss_obj
;
147 if (!dladm_convert_secobjclass(class, &objp
->so_class
))
148 return (DLADM_STATUS_BADARG
);
150 (void) strlcpy(objp
->so_name
, obj_name
, DLD_SECOBJ_NAME_MAX
);
151 bcopy(obj_val
, objp
->so_val
, obj_len
);
152 objp
->so_len
= obj_len
;
154 if ((flags
& DLADM_OPT_CREATE
) != 0)
155 secobj_set
.ss_flags
= DLD_SECOBJ_OPT_CREATE
;
157 if (ioctl(dladm_dld_fd(handle
), DLDIOC_SECOBJ_SET
, &secobj_set
) < 0)
158 status
= dladm_errno2status(errno
);
160 if (status
!= DLADM_STATUS_OK
)
164 if ((flags
& DLADM_OPT_PERSIST
) != 0) {
165 status
= i_dladm_set_secobj_db(handle
, obj_name
, class,
172 dladm_get_secobj(dladm_handle_t handle
, const char *obj_name
,
173 dladm_secobj_class_t
*classp
, uint8_t *obj_val
, uint_t
*obj_lenp
,
176 dladm_status_t status
= DLADM_STATUS_OK
;
177 dld_ioc_secobj_get_t secobj_get
;
180 if (obj_name
== NULL
|| strlen(obj_name
) > DLD_SECOBJ_NAME_MAX
||
181 obj_val
== NULL
|| obj_lenp
== NULL
|| *obj_lenp
== 0 ||
182 *obj_lenp
> DLD_SECOBJ_VAL_MAX
)
183 return (DLADM_STATUS_BADARG
);
185 if ((flags
& DLADM_OPT_PERSIST
) != 0) {
186 return (i_dladm_get_secobj_db(handle
, obj_name
, classp
,
190 bzero(&secobj_get
, sizeof (secobj_get
));
191 objp
= &secobj_get
.sg_obj
;
192 (void) strlcpy(objp
->so_name
, obj_name
, DLD_SECOBJ_NAME_MAX
);
194 secobj_get
.sg_size
= sizeof (secobj_get
);
195 if (ioctl(dladm_dld_fd(handle
), DLDIOC_SECOBJ_GET
, &secobj_get
) < 0)
196 status
= dladm_errno2status(errno
);
198 if (objp
->so_len
> *obj_lenp
)
199 return (DLADM_STATUS_TOOSMALL
);
201 if (!dladm_convert_dldsecobjclass(objp
->so_class
, classp
))
202 return (DLADM_STATUS_FAILED
);
204 *obj_lenp
= objp
->so_len
;
205 bcopy(objp
->so_val
, obj_val
, *obj_lenp
);
210 dladm_unset_secobj(dladm_handle_t handle
, const char *obj_name
, uint_t flags
)
212 dladm_status_t status
= DLADM_STATUS_OK
;
213 dld_ioc_secobj_unset_t secobj_unset
;
215 if (obj_name
== NULL
|| strlen(obj_name
) > DLD_SECOBJ_NAME_MAX
||
217 return (DLADM_STATUS_BADARG
);
219 if ((flags
& DLADM_OPT_ACTIVE
) == 0)
222 bzero(&secobj_unset
, sizeof (secobj_unset
));
223 (void) strlcpy(secobj_unset
.su_name
, obj_name
, DLD_SECOBJ_NAME_MAX
);
225 if (ioctl(dladm_dld_fd(handle
), DLDIOC_SECOBJ_UNSET
, &secobj_unset
) < 0)
226 status
= dladm_errno2status(errno
);
228 if (status
!= DLADM_STATUS_OK
)
232 if ((flags
& DLADM_OPT_PERSIST
) != 0)
233 status
= i_dladm_unset_secobj_db(handle
, obj_name
);
239 dladm_walk_secobj(dladm_handle_t handle
, void *arg
,
240 boolean_t (*func
)(dladm_handle_t
, void *, const char *), uint_t flags
)
242 dladm_status_t status
= DLADM_STATUS_OK
;
243 dld_ioc_secobj_get_t
*secobj_getp
;
247 if ((flags
& DLADM_OPT_PERSIST
) != 0)
248 return (i_dladm_walk_secobj_db(handle
, arg
, func
));
250 /* Start with enough room for 10 objects, increase if necessary. */
251 secobj_bufsz
= sizeof (*secobj_getp
) + (10 * sizeof (*objp
));
252 secobj_getp
= calloc(1, secobj_bufsz
);
253 if (secobj_getp
== NULL
) {
254 status
= dladm_errno2status(errno
);
259 secobj_getp
->sg_size
= secobj_bufsz
;
260 if (ioctl(dladm_dld_fd(handle
), DLDIOC_SECOBJ_GET
, secobj_getp
) < 0) {
261 if (errno
== ENOSPC
) {
262 /* Increase the buffer size and try again. */
264 if (secobj_bufsz
> SECOBJ_MAXBUFSZ
) {
265 status
= dladm_errno2status(errno
);
268 secobj_getp
= realloc(secobj_getp
, secobj_bufsz
);
269 if (secobj_getp
== NULL
) {
270 status
= dladm_errno2status(errno
);
273 bzero(secobj_getp
, secobj_bufsz
);
276 status
= dladm_errno2status(errno
);
280 objp
= (dld_secobj_t
*)(secobj_getp
+ 1);
281 while (secobj_getp
->sg_count
> 0) {
282 if (!func(handle
, arg
, objp
->so_name
))
284 secobj_getp
->sg_count
--;
293 * Data structures used for implementing persistent secure objects
295 typedef struct secobj_info
{
297 dladm_secobj_class_t
*si_classp
;
302 typedef struct secobj_name
{
304 struct secobj_name
*sn_next
;
307 typedef struct secobj_db_state secobj_db_state_t
;
309 typedef boolean_t (*secobj_db_op_t
)(dladm_handle_t
, struct secobj_db_state
*,
310 char *, secobj_info_t
*, dladm_status_t
*);
312 struct secobj_db_state
{
313 secobj_db_op_t ss_op
;
314 secobj_info_t ss_info
;
315 secobj_name_t
**ss_namelist
;
319 * Update or generate a secobj entry using the info in ssp->ss_info.
323 process_secobj_set(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
324 secobj_info_t
*sip
, dladm_status_t
*statusp
)
326 char tmpbuf
[MAXLINELEN
];
327 char classbuf
[DLADM_STRSIZE
];
328 char *ptr
= tmpbuf
, *lim
= tmpbuf
+ MAXLINELEN
;
333 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%s\t", sip
->si_name
);
334 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%s\t",
335 dladm_secobjclass2str(*sip
->si_classp
, classbuf
));
337 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "0x");
338 for (i
= 0; i
< *sip
->si_lenp
; i
++) {
339 ptr
+= snprintf(ptr
, BUFLEN(lim
, ptr
), "%02x",
340 sip
->si_val
[i
] & 0xff);
343 *statusp
= DLADM_STATUS_TOOSMALL
;
346 (void) snprintf(buf
, MAXLINELEN
, "%s\n", tmpbuf
);
352 process_secobj_get(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
353 secobj_info_t
*sip
, dladm_status_t
*statusp
)
355 if (*sip
->si_lenp
> *ssp
->ss_info
.si_lenp
) {
356 *statusp
= DLADM_STATUS_TOOSMALL
;
359 bcopy(sip
->si_val
, ssp
->ss_info
.si_val
, *sip
->si_lenp
);
360 *ssp
->ss_info
.si_lenp
= *sip
->si_lenp
;
361 *ssp
->ss_info
.si_classp
= *sip
->si_classp
;
367 process_secobj_unset(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
368 secobj_info_t
*sip
, dladm_status_t
*statusp
)
379 process_secobj_walk(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
380 secobj_info_t
*sip
, dladm_status_t
*statusp
)
384 if ((snp
= malloc(sizeof (*snp
))) == NULL
)
387 if ((snp
->sn_name
= strdup(sip
->si_name
)) == NULL
) {
393 *ssp
->ss_namelist
= snp
;
394 ssp
->ss_namelist
= &snp
->sn_next
;
400 process_secobj_init(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
401 secobj_info_t
*sip
, dladm_status_t
*statusp
)
403 *statusp
= dladm_set_secobj(handle
, sip
->si_name
, *sip
->si_classp
,
404 sip
->si_val
, *sip
->si_lenp
,
405 DLADM_OPT_ACTIVE
| DLADM_OPT_CREATE
);
410 parse_secobj_val(char *buf
, secobj_info_t
*sip
)
412 if (strncmp(buf
, "0x", 2) != 0)
415 return (hexascii_to_octet(buf
+ 2, strlen(buf
) - 2,
416 sip
->si_val
, sip
->si_lenp
));
420 process_secobj_line(dladm_handle_t handle
, secobj_db_state_t
*ssp
, char *buf
,
421 dladm_status_t
*statusp
)
424 dladm_secobj_class_t
class;
425 uint8_t val
[DLADM_SECOBJ_VAL_MAX
];
431 * Skip leading spaces, blank lines, and comments.
434 for (i
= 0; i
< len
; i
++) {
435 if (!isspace(buf
[i
]))
438 if (i
== len
|| buf
[i
] == '#')
442 if (ssp
->ss_info
.si_name
!= NULL
) {
444 * Skip objects we're not interested in.
446 nlen
= strlen(ssp
->ss_info
.si_name
);
447 if (strncmp(str
, ssp
->ss_info
.si_name
, nlen
) != 0 ||
451 sinfo
.si_name
= ssp
->ss_info
.si_name
;
454 * If an object is not specified, find the object name
455 * and assign it to sinfo.si_name.
457 if (strtok_r(str
, " \n\t", &lasts
) == NULL
)
464 if (str
>= buf
+ len
)
468 * Find the class name.
470 if ((str
= strtok_r(str
, " \n\t", &lasts
)) == NULL
)
473 *statusp
= dladm_str2secobjclass(str
, &class);
474 if (*statusp
!= DLADM_STATUS_OK
)
478 * Find the object value.
480 if ((str
= strtok_r(NULL
, " \n\t", &lasts
)) == NULL
)
483 vlen
= DLADM_SECOBJ_VAL_MAX
;
484 sinfo
.si_classp
= &class;
486 sinfo
.si_lenp
= &vlen
;
487 if (parse_secobj_val(str
, &sinfo
) != 0)
490 return ((*ssp
->ss_op
)(handle
, ssp
, buf
, &sinfo
, statusp
));
494 * Delete corrupted line.
500 static dladm_status_t
501 process_secobj_db(dladm_handle_t handle
, void *arg
, FILE *fp
, FILE *nfp
)
503 secobj_db_state_t
*ssp
= arg
;
504 dladm_status_t status
= DLADM_STATUS_OK
;
505 char buf
[MAXLINELEN
];
506 boolean_t cont
= B_TRUE
;
509 * This loop processes each line of the configuration file.
510 * buf can potentially be modified by process_secobj_line().
511 * If this is a write operation and buf is not truncated, buf will
512 * be written to disk. process_secobj_line() will no longer be
513 * called after it returns B_FALSE; at which point the remainder
514 * of the file will continue to be read and, if necessary, written
517 while (fgets(buf
, MAXLINELEN
, fp
) != NULL
) {
519 cont
= process_secobj_line(handle
, ssp
, buf
, &status
);
521 if (nfp
!= NULL
&& buf
[0] != '\0' && fputs(buf
, nfp
) == EOF
) {
522 status
= dladm_errno2status(errno
);
526 if (status
!= DLADM_STATUS_OK
|| !cont
)
529 if (ssp
->ss_op
== process_secobj_set
) {
531 * If the specified object is not found above, we add the
532 * object to the configuration file.
534 (void) (*ssp
->ss_op
)(handle
, ssp
, buf
, NULL
, &status
);
535 if (status
== DLADM_STATUS_OK
&& fputs(buf
, nfp
) == EOF
)
536 status
= dladm_errno2status(errno
);
539 if (ssp
->ss_op
== process_secobj_unset
||
540 ssp
->ss_op
== process_secobj_get
)
541 status
= DLADM_STATUS_NOTFOUND
;
546 #define SECOBJ_RW_DB(handle, statep, writeop) \
547 (i_dladm_rw_db(handle, "/etc/dladm/secobj.conf", \
548 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, \
549 process_secobj_db, (statep), (writeop)))
551 static dladm_status_t
552 i_dladm_set_secobj_db(dladm_handle_t handle
, const char *obj_name
,
553 dladm_secobj_class_t
class, uint8_t *obj_val
, uint_t obj_len
)
555 secobj_db_state_t state
;
557 state
.ss_op
= process_secobj_set
;
558 state
.ss_info
.si_name
= obj_name
;
559 state
.ss_info
.si_classp
= &class;
560 state
.ss_info
.si_val
= obj_val
;
561 state
.ss_info
.si_lenp
= &obj_len
;
562 state
.ss_namelist
= NULL
;
564 return (SECOBJ_RW_DB(handle
, &state
, B_TRUE
));
567 static dladm_status_t
568 i_dladm_get_secobj_db(dladm_handle_t handle
, const char *obj_name
,
569 dladm_secobj_class_t
*classp
, uint8_t *obj_val
, uint_t
*obj_lenp
)
571 secobj_db_state_t state
;
573 state
.ss_op
= process_secobj_get
;
574 state
.ss_info
.si_name
= obj_name
;
575 state
.ss_info
.si_classp
= classp
;
576 state
.ss_info
.si_val
= obj_val
;
577 state
.ss_info
.si_lenp
= obj_lenp
;
578 state
.ss_namelist
= NULL
;
580 return (SECOBJ_RW_DB(handle
, &state
, B_FALSE
));
583 static dladm_status_t
584 i_dladm_unset_secobj_db(dladm_handle_t handle
, const char *obj_name
)
586 secobj_db_state_t state
;
588 state
.ss_op
= process_secobj_unset
;
589 state
.ss_info
.si_name
= obj_name
;
590 state
.ss_info
.si_classp
= NULL
;
591 state
.ss_info
.si_val
= NULL
;
592 state
.ss_info
.si_lenp
= NULL
;
593 state
.ss_namelist
= NULL
;
595 return (SECOBJ_RW_DB(handle
, &state
, B_TRUE
));
598 static dladm_status_t
599 i_dladm_walk_secobj_db(dladm_handle_t handle
, void *arg
,
600 boolean_t (*func
)(dladm_handle_t
, void *, const char *))
602 secobj_db_state_t state
;
603 secobj_name_t
*snp
= NULL
, *fsnp
;
604 dladm_status_t status
;
605 boolean_t cont
= B_TRUE
;
607 state
.ss_op
= process_secobj_walk
;
608 state
.ss_info
.si_name
= NULL
;
609 state
.ss_info
.si_classp
= NULL
;
610 state
.ss_info
.si_val
= NULL
;
611 state
.ss_info
.si_lenp
= NULL
;
612 state
.ss_namelist
= &snp
;
614 status
= SECOBJ_RW_DB(handle
, &state
, B_FALSE
);
615 if (status
!= DLADM_STATUS_OK
)
618 while (snp
!= NULL
) {
622 cont
= func(handle
, arg
, fsnp
->sn_name
);
630 dladm_init_secobj(dladm_handle_t handle
)
632 secobj_db_state_t state
;
634 state
.ss_op
= process_secobj_init
;
635 state
.ss_info
.si_name
= NULL
;
636 state
.ss_info
.si_classp
= NULL
;
637 state
.ss_info
.si_val
= NULL
;
638 state
.ss_info
.si_lenp
= NULL
;
639 state
.ss_namelist
= NULL
;
641 return (SECOBJ_RW_DB(handle
, &state
, B_FALSE
));
645 dladm_valid_secobj_name(const char *secobj_name
)
647 size_t len
= strlen(secobj_name
);
650 if (len
+ 1 > DLADM_SECOBJ_NAME_MAX
)
654 * The legal characters in a secobj name are:
655 * alphanumeric (a-z, A-Z, 0-9), '.', '_', '-'.
657 for (cp
= secobj_name
; *cp
!= '\0'; cp
++) {
659 (*cp
!= '.') && (*cp
!= '_') && (*cp
!= '-'))