diff options
author | xc151355 <none@none> | 2006-11-20 22:51:46 -0800 |
---|---|---|
committer | xc151355 <none@none> | 2006-11-20 22:51:46 -0800 |
commit | 0ba2cbe97e0678a691742f98d2532caed0a2c4aa (patch) | |
tree | 999e927888ff26967f593246afc931402e17b50e /usr/src/lib/libdladm/common/secobj.c | |
parent | 0c64a9b435314788e185507d40ef9fae71507f5a (diff) | |
download | illumos-joyent-0ba2cbe97e0678a691742f98d2532caed0a2c4aa.tar.gz |
PSARC/2006/406 WiFi for GLDv3
PSARC/2006/517 WiFi for GLDv3 Addendum
PSARC/2006/623 WiFi for GLDv3 Addendum #2
6253476 dladm exec_attr entry doesn't allow show-link to work
6362391 ath driver needs to be updated to use the latest HAL
6364198 system crashes if multiple ath driver instances are modunload'ed
6367259 ath driver needs to support GLDv3
6407181 ath driver panics in ath_rate_update function
6421983 ath driver needs shared_key authmode support
6472427 ath driver causes watchdog timeout error
6484943 integrate WiFi/GLDv3
--HG--
rename : usr/src/uts/common/io/ath/ath_ieee80211.c => deleted_files/usr/src/uts/common/io/ath/ath_ieee80211.c
rename : usr/src/uts/common/io/ath/ath_ieee80211.h => deleted_files/usr/src/uts/common/io/ath/ath_ieee80211.h
rename : usr/src/uts/common/io/ath/ath_wificonfig.c => deleted_files/usr/src/uts/common/io/ath/ath_wificonfig.c
Diffstat (limited to 'usr/src/lib/libdladm/common/secobj.c')
-rw-r--r-- | usr/src/lib/libdladm/common/secobj.c | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/usr/src/lib/libdladm/common/secobj.c b/usr/src/lib/libdladm/common/secobj.c new file mode 100644 index 0000000000..3f122ca347 --- /dev/null +++ b/usr/src/lib/libdladm/common/secobj.c @@ -0,0 +1,634 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <unistd.h> +#include <stdlib.h> +#include <strings.h> +#include <errno.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/dld.h> +#include <libinetutil.h> +#include <libdladm_impl.h> + +static dladm_status_t i_dladm_set_secobj_db(const char *, + dladm_secobj_class_t, uint8_t *, uint_t); +static dladm_status_t i_dladm_get_secobj_db(const char *, + dladm_secobj_class_t *, uint8_t *, uint_t *); +static dladm_status_t i_dladm_unset_secobj_db(const char *); +static dladm_status_t i_dladm_walk_secobj_db(void *, + boolean_t (*)(void *, const char *)); + +typedef struct secobj_class_info { + const char *sc_name; + dld_secobj_class_t sc_dldclass; +} secobj_class_info_t; + +static secobj_class_info_t secobj_class_table[] = { + {"wep", DLD_SECOBJ_CLASS_WEP} +}; + +#define NSECOBJCLASS \ + (sizeof (secobj_class_table) / sizeof (secobj_class_info_t)) + +static boolean_t +dladm_check_secobjclass(dladm_secobj_class_t class) +{ + return (class >= 0 && class < NSECOBJCLASS); +} + +dladm_status_t +dladm_str2secobjclass(const char *str, dladm_secobj_class_t *class) +{ + int i; + secobj_class_info_t *sp; + + for (i = 0; i < NSECOBJCLASS; i++) { + sp = &secobj_class_table[i]; + if (strcasecmp(str, sp->sc_name) == 0) { + *class = i; + return (DLADM_STATUS_OK); + } + } + return (DLADM_STATUS_BADARG); +} + +const char * +dladm_secobjclass2str(dladm_secobj_class_t class, char *buf) +{ + const char *s; + + if (!dladm_check_secobjclass(class)) + s = ""; + else + s = secobj_class_table[class].sc_name; + + (void) snprintf(buf, DLADM_STRSIZE, "%s", s); + return (buf); +} + +static boolean_t +dladm_convert_secobjclass(dladm_secobj_class_t class, + dld_secobj_class_t *dldclass) +{ + if (!dladm_check_secobjclass(class)) + return (B_FALSE); + + *dldclass = secobj_class_table[class].sc_dldclass; + return (B_TRUE); +} + +static boolean_t +dladm_convert_dldsecobjclass(dld_secobj_class_t dldclass, + dladm_secobj_class_t *class) +{ + int i; + secobj_class_info_t *sp; + + for (i = 0; i < NSECOBJCLASS; i++) { + sp = &secobj_class_table[i]; + if (dldclass == sp->sc_dldclass) { + *class = i; + return (B_TRUE); + } + } + return (B_FALSE); +} + +dladm_status_t +dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class, + uint8_t *obj_val, uint_t obj_len, uint_t flags) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_secobj_set_t secobj_set; + dld_secobj_t *objp; + + if (!dladm_check_secobjclass(class) || flags == 0 || + obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX || + obj_val == NULL || obj_len == 0 || obj_len > DLD_SECOBJ_VAL_MAX) + return (DLADM_STATUS_BADARG); + + if ((flags & DLADM_OPT_TEMP) == 0) + goto persist; + + bzero(&secobj_set, sizeof (secobj_set)); + objp = &secobj_set.ss_obj; + if (!dladm_convert_secobjclass(class, &objp->so_class)) + return (DLADM_STATUS_BADARG); + + (void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX); + bcopy(obj_val, objp->so_val, obj_len); + objp->so_len = obj_len; + + if ((flags & DLADM_OPT_CREATE) != 0) + secobj_set.ss_flags = DLD_SECOBJ_OPT_CREATE; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + if (i_dladm_ioctl(fd, DLDIOCSECOBJSET, &secobj_set, + sizeof (secobj_set)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + if (status != DLADM_STATUS_OK) + return (status); + +persist: + if ((flags & DLADM_OPT_PERSIST) != 0) { + status = i_dladm_set_secobj_db(obj_name, class, + obj_val, obj_len); + } + return (status); +} + +dladm_status_t +dladm_get_secobj(const char *obj_name, dladm_secobj_class_t *classp, + uint8_t *obj_val, uint_t *obj_lenp, uint_t flags) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_secobj_get_t secobj_get; + dld_secobj_t *objp; + + if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX || + obj_val == NULL || obj_lenp == NULL || *obj_lenp == 0 || + *obj_lenp > DLD_SECOBJ_VAL_MAX) + return (DLADM_STATUS_BADARG); + + if ((flags & DLADM_OPT_PERSIST) != 0) { + return (i_dladm_get_secobj_db(obj_name, classp, + obj_val, obj_lenp)); + } + + bzero(&secobj_get, sizeof (secobj_get)); + objp = &secobj_get.sg_obj; + (void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, &secobj_get, + sizeof (secobj_get)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + if (objp->so_len > *obj_lenp) + return (DLADM_STATUS_TOOSMALL); + + if (!dladm_convert_dldsecobjclass(objp->so_class, classp)) + return (DLADM_STATUS_FAILED); + + *obj_lenp = objp->so_len; + bcopy(objp->so_val, obj_val, *obj_lenp); + return (status); +} + +dladm_status_t +dladm_unset_secobj(const char *obj_name, uint_t flags) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_secobj_unset_t secobj_unset; + + if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX || + flags == 0) + return (DLADM_STATUS_BADARG); + + if ((flags & DLADM_OPT_TEMP) == 0) + goto persist; + + bzero(&secobj_unset, sizeof (secobj_unset)); + (void) strlcpy(secobj_unset.su_name, obj_name, DLD_SECOBJ_NAME_MAX); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + if (i_dladm_ioctl(fd, DLDIOCSECOBJUNSET, &secobj_unset, + sizeof (secobj_unset)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + if (status != DLADM_STATUS_OK) + return (status); + +persist: + if ((flags & DLADM_OPT_PERSIST) != 0) + status = i_dladm_unset_secobj_db(obj_name); + + return (status); +} + +#define SECOBJ_BUFSZ 65536 +dladm_status_t +dladm_walk_secobj(void *arg, boolean_t (*func)(void *, const char *), + uint_t flags) +{ + int fd = -1; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_secobj_get_t *secobj_getp; + dld_secobj_t *objp; + + if ((flags & DLADM_OPT_PERSIST) != 0) + return (i_dladm_walk_secobj_db(arg, func)); + + secobj_getp = calloc(1, SECOBJ_BUFSZ); + if (secobj_getp == NULL) + return (DLADM_STATUS_NOMEM); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, secobj_getp, + SECOBJ_BUFSZ) < 0) { + status = dladm_errno2status(errno); + goto done; + } + + objp = (dld_secobj_t *)(secobj_getp + 1); + while (secobj_getp->sg_count > 0) { + if (!func(arg, objp->so_name)) + goto done; + secobj_getp->sg_count--; + objp++; + } +done: + (void) close(fd); + free(secobj_getp); + return (status); +} + +/* + * Data structures used for implementing persistent secure objects + */ +typedef struct secobj_info { + const char *si_name; + dladm_secobj_class_t *si_classp; + uint8_t *si_val; + uint_t *si_lenp; +} secobj_info_t; + +typedef struct secobj_name { + char *sn_name; + struct secobj_name *sn_next; +} secobj_name_t; + +typedef struct secobj_db_state secobj_db_state_t; + +typedef boolean_t (*secobj_db_op_t)(struct secobj_db_state *, char *, + secobj_info_t *, dladm_status_t *); + +struct secobj_db_state { + secobj_db_op_t ss_op; + secobj_info_t ss_info; + secobj_name_t **ss_namelist; +}; + +/* + * Update or generate a secobj entry using the info in ssp->ss_info. + */ +/* ARGSUSED */ +static boolean_t +process_secobj_set(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, + dladm_status_t *statusp) +{ + char tmpbuf[MAXLINELEN]; + char classbuf[DLADM_STRSIZE]; + char *ptr = tmpbuf, *lim = tmpbuf + MAXLINELEN; + int i; + + sip = &ssp->ss_info; + + ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", sip->si_name); + ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", + dladm_secobjclass2str(*sip->si_classp, classbuf)); + + ptr += snprintf(ptr, BUFLEN(lim, ptr), "0x"); + for (i = 0; i < *sip->si_lenp; i++) { + ptr += snprintf(ptr, BUFLEN(lim, ptr), "%02x", + sip->si_val[i] & 0xff); + } + if (ptr > lim) { + *statusp = DLADM_STATUS_TOOSMALL; + return (B_FALSE); + } + (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); + return (B_FALSE); +} + +/* ARGSUSED */ +static boolean_t +process_secobj_get(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, + dladm_status_t *statusp) +{ + if (*sip->si_lenp > *ssp->ss_info.si_lenp) { + *statusp = DLADM_STATUS_TOOSMALL; + return (B_FALSE); + } + bcopy(sip->si_val, ssp->ss_info.si_val, *sip->si_lenp); + *ssp->ss_info.si_lenp = *sip->si_lenp; + *ssp->ss_info.si_classp = *sip->si_classp; + return (B_FALSE); +} + +/* ARGSUSED */ +static boolean_t +process_secobj_unset(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, + dladm_status_t *statusp) +{ + /* + * Delete line. + */ + buf[0] = '\0'; + return (B_FALSE); +} + +/* ARGSUSED */ +static boolean_t +process_secobj_walk(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, + dladm_status_t *statusp) +{ + secobj_name_t *snp; + + if ((snp = malloc(sizeof (*snp))) == NULL) + return (B_TRUE); + + if ((snp->sn_name = strdup(sip->si_name)) == NULL) { + free(snp); + return (B_TRUE); + } + + snp->sn_next = NULL; + *ssp->ss_namelist = snp; + ssp->ss_namelist = &snp->sn_next; + return (B_TRUE); +} + +/* ARGSUSED */ +static boolean_t +process_secobj_init(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, + dladm_status_t *statusp) +{ + *statusp = dladm_set_secobj(sip->si_name, *sip->si_classp, sip->si_val, + *sip->si_lenp, DLADM_OPT_TEMP | DLADM_OPT_CREATE); + return (B_TRUE); +} + +static int +parse_secobj_val(char *buf, secobj_info_t *sip) +{ + if (strncmp(buf, "0x", 2) != 0) + return (EINVAL); + + return (hexascii_to_octet(buf + 2, strlen(buf) - 2, + sip->si_val, sip->si_lenp)); +} + +static boolean_t +process_secobj_line(secobj_db_state_t *ssp, char *buf, + dladm_status_t *statusp) +{ + secobj_info_t sinfo; + dladm_secobj_class_t class; + uint8_t val[DLADM_SECOBJ_VAL_MAX]; + uint_t vlen; + int i, len, nlen; + char *str, *lasts; + + /* + * Skip leading spaces, blank lines, and comments. + */ + len = strlen(buf); + for (i = 0; i < len; i++) { + if (!isspace(buf[i])) + break; + } + if (i == len || buf[i] == '#') + return (B_TRUE); + + str = buf + i; + if (ssp->ss_info.si_name != NULL) { + /* + * Skip objects we're not interested in. + */ + nlen = strlen(ssp->ss_info.si_name); + if (strncmp(str, ssp->ss_info.si_name, nlen) != 0 || + !isspace(str[nlen])) + return (B_TRUE); + + sinfo.si_name = ssp->ss_info.si_name; + } else { + /* + * If an object is not specified, find the object name + * and assign it to sinfo.si_name. + */ + if (strtok_r(str, " \n\t", &lasts) == NULL) + goto fail; + + nlen = strlen(str); + sinfo.si_name = str; + } + str += nlen + 1; + if (str >= buf + len) + goto fail; + + /* + * Find the class name. + */ + if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) + goto fail; + + *statusp = dladm_str2secobjclass(str, &class); + if (*statusp != DLADM_STATUS_OK) + goto fail; + + /* + * Find the object value. + */ + if ((str = strtok_r(NULL, " \n\t", &lasts)) == NULL) + goto fail; + + vlen = DLADM_SECOBJ_VAL_MAX; + sinfo.si_classp = &class; + sinfo.si_val = val; + sinfo.si_lenp = &vlen; + if (parse_secobj_val(str, &sinfo) != 0) + goto fail; + + return ((*ssp->ss_op)(ssp, buf, &sinfo, statusp)); + +fail: + /* + * Delete corrupted line. + */ + buf[0] = '\0'; + return (B_TRUE); +} + +static dladm_status_t +process_secobj_db(void *arg, FILE *fp, FILE *nfp) +{ + secobj_db_state_t *ssp = arg; + dladm_status_t status = DLADM_STATUS_OK; + char buf[MAXLINELEN]; + boolean_t cont = B_TRUE; + + /* + * This loop processes each line of the configuration file. + * buf can potentially be modified by process_secobj_line(). + * If this is a write operation and buf is not truncated, buf will + * be written to disk. process_secobj_line() will no longer be + * called after it returns B_FALSE; at which point the remainder + * of the file will continue to be read and, if necessary, written + * to disk as well. + */ + while (fgets(buf, MAXLINELEN, fp) != NULL) { + if (cont) + cont = process_secobj_line(ssp, buf, &status); + + if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) { + status = dladm_errno2status(errno); + break; + } + } + if (status != DLADM_STATUS_OK || !cont) + return (status); + + if (ssp->ss_op == process_secobj_set) { + /* + * If the specified object is not found above, we add the + * object to the configuration file. + */ + (void) (*ssp->ss_op)(ssp, buf, NULL, &status); + if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF) + status = dladm_errno2status(errno); + } + + if (ssp->ss_op == process_secobj_unset || + ssp->ss_op == process_secobj_get) + status = DLADM_STATUS_NOTFOUND; + + return (status); +} + +#define SECOBJ_RW_DB(statep, writeop) \ + (i_dladm_rw_db("/etc/dladm/secobj.conf", S_IRUSR | S_IWUSR, \ + process_secobj_db, (statep), (writeop))) + +static dladm_status_t +i_dladm_set_secobj_db(const char *obj_name, dladm_secobj_class_t class, + uint8_t *obj_val, uint_t obj_len) +{ + secobj_db_state_t state; + + state.ss_op = process_secobj_set; + state.ss_info.si_name = obj_name; + state.ss_info.si_classp = &class; + state.ss_info.si_val = obj_val; + state.ss_info.si_lenp = &obj_len; + state.ss_namelist = NULL; + + return (SECOBJ_RW_DB(&state, B_TRUE)); +} + +static dladm_status_t +i_dladm_get_secobj_db(const char *obj_name, dladm_secobj_class_t *classp, + uint8_t *obj_val, uint_t *obj_lenp) +{ + secobj_db_state_t state; + + state.ss_op = process_secobj_get; + state.ss_info.si_name = obj_name; + state.ss_info.si_classp = classp; + state.ss_info.si_val = obj_val; + state.ss_info.si_lenp = obj_lenp; + state.ss_namelist = NULL; + + return (SECOBJ_RW_DB(&state, B_FALSE)); +} + +static dladm_status_t +i_dladm_unset_secobj_db(const char *obj_name) +{ + secobj_db_state_t state; + + state.ss_op = process_secobj_unset; + state.ss_info.si_name = obj_name; + state.ss_info.si_classp = NULL; + state.ss_info.si_val = NULL; + state.ss_info.si_lenp = NULL; + state.ss_namelist = NULL; + + return (SECOBJ_RW_DB(&state, B_TRUE)); +} + +static dladm_status_t +i_dladm_walk_secobj_db(void *arg, boolean_t (*func)(void *, const char *)) +{ + secobj_db_state_t state; + secobj_name_t *snp = NULL, *fsnp; + dladm_status_t status; + boolean_t cont = B_TRUE; + + state.ss_op = process_secobj_walk; + state.ss_info.si_name = NULL; + state.ss_info.si_classp = NULL; + state.ss_info.si_val = NULL; + state.ss_info.si_lenp = NULL; + state.ss_namelist = &snp; + + status = SECOBJ_RW_DB(&state, B_FALSE); + if (status != DLADM_STATUS_OK) + return (status); + + while (snp != NULL) { + fsnp = snp; + snp = snp->sn_next; + if (cont) + cont = func(arg, fsnp->sn_name); + free(fsnp->sn_name); + free(fsnp); + } + return (status); +} + +dladm_status_t +dladm_init_secobj(void) +{ + secobj_db_state_t state; + + state.ss_op = process_secobj_init; + state.ss_info.si_name = NULL; + state.ss_info.si_classp = NULL; + state.ss_info.si_val = NULL; + state.ss_info.si_lenp = NULL; + state.ss_namelist = NULL; + + return (SECOBJ_RW_DB(&state, B_FALSE)); +} |