/* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * add_allocatable - * a command-line interface to add device to device_allocate and * device_maps. */ #ifndef __EXTENSIONS__ #define __EXTENSIONS__ /* needed for _strtok_r */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NO_OVERRIDE -1 int check_args(da_args *); int process_args(int, char **, da_args *, char *); int scan_label(char *, char *); void usage(da_args *, char *); int system_labeled = 0; int main(int argc, char *argv[]) { int rc; uid_t uid; char *progname; char pwbuf[NSS_LINELEN_PASSWD]; struct passwd pwd; da_args dargs; devinfo_t devinfo; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; system_labeled = is_system_labeled(); if (system_labeled) { /* * this command can be run only in the global zone. */ if (getzoneid() != GLOBAL_ZONEID) { (void) fprintf(stderr, "%s%s", progname, gettext(" : must be run in global zone\n")); exit(1); } } else { /* * this command works in Trusted Extensions only. */ (void) fprintf(stderr, "%s%s", progname, gettext(" : need to install Trusted Extensions\n")); exit(1); } dargs.optflag = 0; dargs.rootdir = NULL; dargs.devnames = NULL; dargs.devinfo = &devinfo; if (strcmp(progname, "add_allocatable") == 0) { dargs.optflag |= DA_ADD; } else if (strcmp(progname, "remove_allocatable") == 0) { dargs.optflag |= DA_REMOVE; } else { usage(&dargs, progname); exit(1); } uid = getuid(); if ((getpwuid_r(uid, &pwd, pwbuf, sizeof (pwbuf))) == NULL) { (void) fprintf(stderr, "%s%s", progname, gettext(" : getpwuid_r failed: ")); (void) fprintf(stderr, "%s\n", strerror(errno)); exit(2); } if (chkauthattr(DEVICE_CONFIG_AUTH, pwd.pw_name) != 1) { (void) fprintf(stderr, "%s%s%s", progname, gettext(" : user lacks authorization: \n"), DEVICE_CONFIG_AUTH); exit(4); } if (process_args(argc, argv, &dargs, progname) != 0) { usage(&dargs, progname); exit(1); } if (dargs.optflag & DA_ADD) { if (check_args(&dargs) == NO_OVERRIDE) { (void) fprintf(stderr, "%s%s%s%s", progname, gettext(" : entry exists for "), dargs.devinfo->devname, gettext("\n")); usage(&dargs, progname); exit(3); } } if (dargs.optflag & DA_DEFATTRS) rc = da_update_defattrs(&dargs); else rc = da_update_device(&dargs); if ((rc != 0) && (!(dargs.optflag & DA_SILENT))) { if (rc == -2) (void) fprintf(stderr, "%s%s", progname, gettext(" : device name/type/list missing\n")); else if (dargs.optflag & DA_ADD) (void) fprintf(stderr, "%s%s", progname, gettext(" : error adding/updating device\n")); else if (dargs.optflag & DA_REMOVE) (void) fprintf(stderr, "%s%s", progname, gettext(" : error removing device\n")); rc = 2; /* exit code for 'Unknown system error' in man page */ } return (rc); } int process_args(int argc, char **argv, da_args *dargs, char *progname) { int c; int aflag, cflag, dflag, fflag, lflag, nflag, oflag, tflag; extern char *optarg; devinfo_t *devinfo; devinfo = dargs->devinfo; aflag = cflag = dflag = fflag = lflag = nflag = oflag = tflag = 0; devinfo->devname = devinfo->devtype = devinfo->devauths = devinfo->devexec = devinfo->devopts = devinfo->devlist = NULL; devinfo->instance = 0; while ((c = getopt(argc, argv, "a:c:dfl:n:o:st:")) != EOF) { switch (c) { case 'a': devinfo->devauths = optarg; aflag++; break; case 'c': devinfo->devexec = optarg; if (strlen(devinfo->devexec) == 0) { if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : device clean program" " name not found\n")); return (1); } cflag++; break; case 'd': dargs->optflag |= DA_DEFATTRS; dflag++; break; case 'l': devinfo->devlist = optarg; if (strlen(devinfo->devlist) == 0) { if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : device file list" " not found\n")); return (1); } lflag++; break; case 'f': dargs->optflag |= DA_FORCE; fflag++; break; case 'n': devinfo->devname = optarg; if (strlen(devinfo->devname) == 0) { if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : device name " "not found\n")); return (1); } nflag++; break; case 'o': /* check for field delimiters in the option */ if (strpbrk(optarg, ":;=") == NULL) { if (!(dargs->optflag & DA_SILENT)) { (void) fprintf(stderr, "%s%s%s", progname, gettext(" : invalid " "key=val string: "), optarg); (void) fprintf(stderr, "%s", gettext("\n")); } return (1); } devinfo->devopts = optarg; if (dargs->optflag & DA_ADD) { if (scan_label(devinfo->devopts, progname) != 0) return (1); } oflag++; break; case 's': dargs->optflag |= DA_SILENT; break; case 't': devinfo->devtype = optarg; if (strlen(devinfo->devtype) == 0) { if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : device type " "not found\n")); return (1); } tflag++; break; default : return (1); } } if (dargs->optflag & DA_ADD) { if (dflag) { /* -d requires -t, but does not like -n */ if (nflag || tflag == 0) return (1); } else if (nflag == 0 && tflag == 0 && lflag == 0) { /* require at least -n or -t or -l to be specified */ if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : required options missing\n")); return (1); } } else if (dargs->optflag & DA_REMOVE) { if (dflag) { /* -d requires -t, but does not like -n */ if (nflag || tflag == 0) return (1); } else if (nflag == 0 && tflag == 0) { /* require at least -n or -t to be specified */ if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : required options missing\n")); return (1); } /* there's a bunch not accepted by remove_allocatable */ if (aflag || cflag || lflag || oflag) return (1); } else { return (1); } /* check for option specified more than once */ if (aflag > 1 || cflag > 1 || lflag > 1 || fflag > 1 || nflag > 1 || tflag > 1) { if (!(dargs->optflag & DA_SILENT)) (void) fprintf(stderr, "%s%s", progname, gettext(" : multiple-defined options\n")); return (1); } return (0); } int verify_label(char *token, char *progname) { int error = 0; char *p, *val, *str; if ((strstr(token, DAOPT_MINLABEL) == NULL) && (strstr(token, DAOPT_MAXLABEL) == NULL)) { /* no label specified */ return (0); } if ((val = strchr(token, '=')) == NULL) return (1); val++; /* * if non-default labels are specified, check if they are correct */ if ((strcmp(val, DA_DEFAULT_MIN) != 0) && (strcmp(val, DA_DEFAULT_MAX) != 0)) { m_label_t *slabel = NULL; str = strdup(val); /* get rid of double quotes if they exist */ while (*str == '"') str++; if ((p = strchr(str, '"')) != NULL) *p = '\0'; if (str_to_label(str, &slabel, MAC_LABEL, L_NO_CORRECTION, &error) == -1) { (void) fprintf(stderr, "%s%s%s", progname, gettext(" : bad label input: "), val); (void) fprintf(stderr, "%s", gettext("\n")); free(str); m_label_free(slabel); return (1); } free(str); m_label_free(slabel); } return (0); } int scan_label(char *devopts, char *progname) { char *tok = NULL; char *lasts, *optsarg; if (devopts == NULL) return (0); if ((optsarg = strdup(devopts)) == NULL) return (1); if ((tok = strtok_r(optsarg, KV_TOKEN_DELIMIT, &lasts)) == NULL) return (1); if (verify_label(tok, progname) != 0) { free(optsarg); return (1); } while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, &lasts)) != NULL) { if (verify_label(tok, progname) != 0) { free(optsarg); return (1); } } return (0); } int check_args(da_args *dargs) { int nlen; char *kval, *nopts, *ntok, *nstr, *defmin, *defmax, *defauths, *defexec; kva_t *kva; devinfo_t *devinfo; devalloc_t *da = NULL; da_defs_t *da_defs = NULL; devinfo = dargs->devinfo; /* * check if we're updating an existing entry without -f */ setdaent(); da = getdanam(devinfo->devname); enddaent(); if (da && !(dargs->optflag & DA_FORCE)) { freedaent(da); return (NO_OVERRIDE); } if ((devinfo->devopts == NULL) || (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) || (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) || (devinfo->devauths == NULL) || (devinfo->devexec == NULL)) { /* fill in defaults as required */ defmin = DA_DEFAULT_MIN; defmax = DA_DEFAULT_MAX; defauths = DEFAULT_DEV_ALLOC_AUTH; defexec = DA_DEFAULT_CLEAN; setdadefent(); if (da_defs = getdadeftype(devinfo->devtype)) { kva = da_defs->devopts; if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) defmin = strdup(kval); if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) defmax = strdup(kval); if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) defauths = strdup(kval); if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) defexec = strdup(kval); freedadefent(da_defs); } enddadefent(); if (devinfo->devauths == NULL) devinfo->devauths = defauths; if (devinfo->devexec == NULL) devinfo->devexec = defexec; if (devinfo->devopts == NULL) { /* add default minlabel and maxlabel */ nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + strlen(defmin) + strlen(KV_TOKEN_DELIMIT) + strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(defmax) + 1; /* +1 for terminator */ if (nopts = (char *)malloc(nlen)) { (void) snprintf(nopts, nlen, "%s%s%s%s%s%s%s", DAOPT_MINLABEL, KV_ASSIGN, defmin, KV_TOKEN_DELIMIT, DAOPT_MAXLABEL, KV_ASSIGN, defmax); devinfo->devopts = nopts; } } else { if (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) { /* add default minlabel */ ntok = DAOPT_MINLABEL; nstr = defmin; nlen = strlen(devinfo->devopts) + strlen(KV_TOKEN_DELIMIT) + strlen(ntok) + strlen(KV_ASSIGN) + strlen(nstr) + 1; if (nopts = (char *)malloc(nlen)) { (void) snprintf(nopts, nlen, "%s%s%s%s%s", devinfo->devopts, KV_TOKEN_DELIMIT, ntok, KV_ASSIGN, nstr); devinfo->devopts = nopts; } } if (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) { /* add default maxlabel */ ntok = DAOPT_MAXLABEL; nstr = defmax; nlen = strlen(devinfo->devopts) + strlen(KV_TOKEN_DELIMIT) + strlen(ntok) + strlen(KV_ASSIGN) + strlen(nstr) + 1; if (nopts = (char *)malloc(nlen)) { (void) snprintf(nopts, nlen, "%s%s%s%s%s", devinfo->devopts, KV_TOKEN_DELIMIT, ntok, KV_ASSIGN, nstr); devinfo->devopts = nopts; } } } } return (0); } void usage(da_args *dargs, char *progname) { if (dargs->optflag & DA_SILENT) return; if (dargs->optflag & DA_ADD) (void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname, gettext(" [-f][-s][-d] -n name -t type -l device-list" "\n\t[-a authorization] [-c cleaning program] " "[-o key=value]\n")); else if (dargs->optflag & DA_REMOVE) (void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname, gettext(" [-f][-s][-d] [-n name|-t type]\n")); else (void) fprintf(stderr, gettext("Invalid usage\n"), progname); }