Home | History | Annotate | Download | only in allocate
      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 2007 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * add_allocatable -
     31  *	a command-line interface to add device to device_allocate and
     32  *	device_maps.
     33  */
     34 
     35 #ifndef	__EXTENSIONS__
     36 #define	__EXTENSIONS__		/* needed for _strtok_r */
     37 #endif
     38 
     39 #include <sys/types.h>
     40 #include <unistd.h>
     41 #include <stdlib.h>
     42 #include <strings.h>
     43 #include <string.h>
     44 #include <locale.h>
     45 #include <libintl.h>
     46 #include <pwd.h>
     47 #include <nss_dbdefs.h>
     48 #include <auth_attr.h>
     49 #include <auth_list.h>
     50 #include <zone.h>
     51 #include <tsol/label.h>
     52 #include <bsm/devices.h>
     53 #include <bsm/devalloc.h>
     54 
     55 #define	NO_OVERRIDE	-1
     56 
     57 int check_args(da_args *);
     58 int process_args(int, char **, da_args *, char *);
     59 int scan_label(char *, char *);
     60 void usage(da_args *, char *);
     61 
     62 int system_labeled = 0;
     63 
     64 int
     65 main(int argc, char *argv[])
     66 {
     67 	int		rc;
     68 	uid_t		uid;
     69 	char		*progname;
     70 	char		pwbuf[NSS_LINELEN_PASSWD];
     71 	struct passwd	pwd;
     72 	da_args		dargs;
     73 	devinfo_t	devinfo;
     74 
     75 	(void) setlocale(LC_ALL, "");
     76 #if !defined(TEXT_DOMAIN)
     77 #define	TEXT_DOMAIN	"SYS_TEST"
     78 #endif
     79 	(void) textdomain(TEXT_DOMAIN);
     80 	if ((progname = strrchr(argv[0], '/')) == NULL)
     81 		progname = argv[0];
     82 	else
     83 		progname++;
     84 
     85 	system_labeled = is_system_labeled();
     86 	if (system_labeled) {
     87 		/*
     88 		 * this command can be run only in the global zone.
     89 		 */
     90 		if (getzoneid() != GLOBAL_ZONEID) {
     91 			(void) fprintf(stderr, "%s%s", progname,
     92 			    gettext(" : must be run in global zone\n"));
     93 			exit(1);
     94 		}
     95 	} else {
     96 		/*
     97 		 * this command works in Trusted Extensions only.
     98 		 */
     99 		(void) fprintf(stderr, "%s%s", progname,
    100 		    gettext(" : need to install Trusted Extensions\n"));
    101 		exit(1);
    102 	}
    103 
    104 	dargs.optflag = 0;
    105 	dargs.rootdir = NULL;
    106 	dargs.devnames = NULL;
    107 	dargs.devinfo = &devinfo;
    108 
    109 	if (strcmp(progname, "add_allocatable") == 0) {
    110 		dargs.optflag |= DA_ADD;
    111 	} else if (strcmp(progname, "remove_allocatable") == 0) {
    112 		dargs.optflag |= DA_REMOVE;
    113 	} else {
    114 		usage(&dargs, progname);
    115 		exit(1);
    116 	}
    117 
    118 	uid = getuid();
    119 	if ((getpwuid_r(uid, &pwd, pwbuf, sizeof (pwbuf))) == NULL) {
    120 		(void) fprintf(stderr, "%s%s", progname,
    121 		    gettext(" : getpwuid_r failed: "));
    122 		(void) fprintf(stderr, "%s\n", strerror(errno));
    123 		exit(2);
    124 	}
    125 
    126 	if (chkauthattr(DEVICE_CONFIG_AUTH, pwd.pw_name) != 1) {
    127 		(void) fprintf(stderr, "%s%s%s", progname,
    128 		    gettext(" : user lacks authorization:  \n"),
    129 		    DEVICE_CONFIG_AUTH);
    130 		exit(4);
    131 	}
    132 
    133 	if (process_args(argc, argv, &dargs, progname) != 0) {
    134 		usage(&dargs, progname);
    135 		exit(1);
    136 	}
    137 
    138 	if (dargs.optflag & DA_ADD) {
    139 		if (check_args(&dargs) == NO_OVERRIDE) {
    140 			(void) fprintf(stderr, "%s%s%s%s", progname,
    141 			    gettext(" : entry exists for "),
    142 			    dargs.devinfo->devname, gettext("\n"));
    143 			usage(&dargs, progname);
    144 			exit(3);
    145 		}
    146 	}
    147 
    148 	if (dargs.optflag & DA_DEFATTRS)
    149 		rc = da_update_defattrs(&dargs);
    150 	else
    151 		rc = da_update_device(&dargs);
    152 
    153 	if ((rc != 0) && (!(dargs.optflag & DA_SILENT))) {
    154 		if (rc == -2)
    155 			(void) fprintf(stderr, "%s%s", progname,
    156 			    gettext(" : device name/type/list missing\n"));
    157 		else if (dargs.optflag & DA_ADD)
    158 			(void) fprintf(stderr, "%s%s", progname,
    159 			    gettext(" : error adding/updating device\n"));
    160 		else if (dargs.optflag & DA_REMOVE)
    161 			(void) fprintf(stderr, "%s%s", progname,
    162 			    gettext(" : error removing device\n"));
    163 		rc = 2;	/* exit code for 'Unknown system error' in man page */
    164 	}
    165 
    166 	return (rc);
    167 }
    168 
    169 int
    170 process_args(int argc, char **argv, da_args *dargs, char *progname)
    171 {
    172 	int 		c;
    173 	int		aflag, cflag, dflag, fflag, lflag, nflag, oflag, tflag;
    174 	extern char	*optarg;
    175 	devinfo_t	*devinfo;
    176 
    177 	devinfo = dargs->devinfo;
    178 	aflag = cflag = dflag = fflag = lflag = nflag = oflag = tflag = 0;
    179 	devinfo->devname = devinfo->devtype = devinfo->devauths =
    180 	    devinfo->devexec = devinfo->devopts = devinfo->devlist = NULL;
    181 	devinfo->instance = 0;
    182 
    183 	while ((c = getopt(argc, argv, "a:c:dfl:n:o:st:")) != EOF) {
    184 		switch (c) {
    185 		case 'a':
    186 			devinfo->devauths = optarg;
    187 			aflag++;
    188 			break;
    189 		case 'c':
    190 			devinfo->devexec = optarg;
    191 			if (strlen(devinfo->devexec) == 0) {
    192 				if (!(dargs->optflag & DA_SILENT))
    193 					(void) fprintf(stderr, "%s%s", progname,
    194 					    gettext(" : device clean program"
    195 					    " name not found\n"));
    196 				return (1);
    197 			}
    198 			cflag++;
    199 			break;
    200 		case 'd':
    201 			dargs->optflag |= DA_DEFATTRS;
    202 			dflag++;
    203 			break;
    204 		case 'l':
    205 			devinfo->devlist = optarg;
    206 			if (strlen(devinfo->devlist) == 0) {
    207 				if (!(dargs->optflag & DA_SILENT))
    208 					(void) fprintf(stderr, "%s%s", progname,
    209 					    gettext(" : device file list"
    210 					    " not found\n"));
    211 				return (1);
    212 			}
    213 			lflag++;
    214 			break;
    215 		case 'f':
    216 			dargs->optflag |= DA_FORCE;
    217 			fflag++;
    218 			break;
    219 		case 'n':
    220 			devinfo->devname = optarg;
    221 			if (strlen(devinfo->devname) == 0) {
    222 				if (!(dargs->optflag & DA_SILENT))
    223 					(void) fprintf(stderr, "%s%s", progname,
    224 					    gettext(" : device name "
    225 					    "not found\n"));
    226 				return (1);
    227 			}
    228 			nflag++;
    229 			break;
    230 		case 'o':
    231 			/* check for field delimiters in the option */
    232 			if (strpbrk(optarg, ":;=") == NULL) {
    233 				if (!(dargs->optflag & DA_SILENT)) {
    234 					(void) fprintf(stderr, "%s%s%s",
    235 					    progname,
    236 					    gettext(" : invalid "
    237 					    "key=val string: "),
    238 					    optarg);
    239 					(void) fprintf(stderr, "%s",
    240 					    gettext("\n"));
    241 				}
    242 				return (1);
    243 			}
    244 			devinfo->devopts = optarg;
    245 			if (dargs->optflag & DA_ADD) {
    246 				if (scan_label(devinfo->devopts, progname) != 0)
    247 					return (1);
    248 			}
    249 			oflag++;
    250 			break;
    251 		case 's':
    252 			dargs->optflag |= DA_SILENT;
    253 			break;
    254 		case 't':
    255 			devinfo->devtype = optarg;
    256 			if (strlen(devinfo->devtype) == 0) {
    257 				if (!(dargs->optflag & DA_SILENT))
    258 					(void) fprintf(stderr, "%s%s", progname,
    259 					    gettext(" : device type "
    260 					    "not found\n"));
    261 				return (1);
    262 			}
    263 			tflag++;
    264 			break;
    265 		default	:
    266 			return (1);
    267 		}
    268 	}
    269 
    270 
    271 	if (dargs->optflag & DA_ADD) {
    272 		if (dflag) {
    273 			/* -d requires -t, but does not like -n */
    274 			if (nflag || tflag == 0)
    275 				return (1);
    276 		} else if (nflag == 0 && tflag == 0 && lflag == 0) {
    277 			/* require at least -n or -t or -l to be specified */
    278 			if (!(dargs->optflag & DA_SILENT))
    279 				(void) fprintf(stderr, "%s%s", progname,
    280 				    gettext(" : required options missing\n"));
    281 			return (1);
    282 		}
    283 	} else if (dargs->optflag & DA_REMOVE) {
    284 		if (dflag) {
    285 			/* -d requires -t, but does not like -n */
    286 			if (nflag || tflag == 0)
    287 				return (1);
    288 		} else if (nflag == 0 && tflag == 0) {
    289 			/* require at least -n or -t to be specified */
    290 			if (!(dargs->optflag & DA_SILENT))
    291 				(void) fprintf(stderr, "%s%s", progname,
    292 				    gettext(" : required options missing\n"));
    293 			return (1);
    294 		}
    295 		/* there's a bunch not accepted by remove_allocatable */
    296 		if (aflag || cflag || lflag || oflag)
    297 			return (1);
    298 	} else {
    299 		return (1);
    300 	}
    301 
    302 	/* check for option specified more than once */
    303 	if (aflag > 1 || cflag > 1 || lflag > 1 || fflag > 1 ||
    304 	    nflag > 1 || tflag > 1) {
    305 		if (!(dargs->optflag & DA_SILENT))
    306 			(void) fprintf(stderr, "%s%s", progname,
    307 			    gettext(" : multiple-defined options\n"));
    308 		return (1);
    309 	}
    310 
    311 	return (0);
    312 }
    313 
    314 int
    315 verify_label(char *token, char *progname)
    316 {
    317 	int		error = 0;
    318 	char		*p, *val, *str;
    319 
    320 	if ((strstr(token, DAOPT_MINLABEL) == NULL) &&
    321 	    (strstr(token, DAOPT_MAXLABEL) == NULL)) {
    322 		/* no label specified */
    323 		return (0);
    324 	}
    325 	if ((val = strchr(token, '=')) == NULL)
    326 		return (1);
    327 	val++;
    328 	/*
    329 	 * if non-default labels are specified, check if they are correct
    330 	 */
    331 	if ((strcmp(val, DA_DEFAULT_MIN) != 0) &&
    332 	    (strcmp(val, DA_DEFAULT_MAX) != 0)) {
    333 		m_label_t	*slabel = NULL;
    334 
    335 		str = strdup(val);
    336 		/* get rid of double quotes if they exist */
    337 		while (*str == '"')
    338 			str++;
    339 		if ((p = strchr(str, '"')) != NULL)
    340 			*p = '\0';
    341 		if (str_to_label(str, &slabel, MAC_LABEL, L_NO_CORRECTION,
    342 		    &error) == -1) {
    343 			(void) fprintf(stderr, "%s%s%s", progname,
    344 			    gettext(" : bad label input: "),
    345 			    val);
    346 			(void) fprintf(stderr, "%s", gettext("\n"));
    347 			free(str);
    348 			m_label_free(slabel);
    349 			return (1);
    350 		}
    351 		free(str);
    352 		m_label_free(slabel);
    353 	}
    354 
    355 	return (0);
    356 }
    357 
    358 int
    359 scan_label(char *devopts, char *progname)
    360 {
    361 	char		*tok = NULL;
    362 	char		*lasts, *optsarg;
    363 
    364 	if (devopts == NULL)
    365 		return (0);
    366 
    367 	if ((optsarg = strdup(devopts)) == NULL)
    368 		return (1);
    369 
    370 	if ((tok = strtok_r(optsarg, KV_TOKEN_DELIMIT, &lasts)) == NULL)
    371 		return (1);
    372 
    373 	if (verify_label(tok, progname) != 0) {
    374 		free(optsarg);
    375 		return (1);
    376 	}
    377 
    378 	while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, &lasts)) != NULL) {
    379 		if (verify_label(tok, progname) != 0) {
    380 			free(optsarg);
    381 			return (1);
    382 		}
    383 	}
    384 
    385 	return (0);
    386 }
    387 
    388 int
    389 check_args(da_args *dargs)
    390 {
    391 	int		nlen;
    392 	char		*kval, *nopts, *ntok, *nstr,
    393 	    *defmin, *defmax, *defauths, *defexec;
    394 	kva_t		*kva;
    395 	devinfo_t	*devinfo;
    396 	devalloc_t	*da = NULL;
    397 	da_defs_t	*da_defs = NULL;
    398 
    399 	devinfo = dargs->devinfo;
    400 	/*
    401 	 * check if we're updating an existing entry without -f
    402 	 */
    403 	setdaent();
    404 	da = getdanam(devinfo->devname);
    405 	enddaent();
    406 	if (da && !(dargs->optflag & DA_FORCE)) {
    407 		freedaent(da);
    408 		return (NO_OVERRIDE);
    409 	}
    410 	if ((devinfo->devopts == NULL) ||
    411 	    (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) ||
    412 	    (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) ||
    413 	    (devinfo->devauths == NULL) ||
    414 	    (devinfo->devexec == NULL)) {
    415 		/* fill in defaults as required */
    416 		defmin = DA_DEFAULT_MIN;
    417 		defmax = DA_DEFAULT_MAX;
    418 		defauths = DEFAULT_DEV_ALLOC_AUTH;
    419 		defexec = DA_DEFAULT_CLEAN;
    420 		setdadefent();
    421 		if (da_defs = getdadeftype(devinfo->devtype)) {
    422 			kva = da_defs->devopts;
    423 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
    424 				defmin = strdup(kval);
    425 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
    426 				defmax = strdup(kval);
    427 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
    428 				defauths = strdup(kval);
    429 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
    430 				defexec = strdup(kval);
    431 			freedadefent(da_defs);
    432 		}
    433 		enddadefent();
    434 		if (devinfo->devauths == NULL)
    435 			devinfo->devauths = defauths;
    436 		if (devinfo->devexec == NULL)
    437 			devinfo->devexec = defexec;
    438 		if (devinfo->devopts == NULL) {
    439 			/* add default minlabel and maxlabel */
    440 			nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
    441 			    strlen(defmin) + strlen(KV_TOKEN_DELIMIT) +
    442 			    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) +
    443 			    strlen(defmax) + 1;		/* +1 for terminator */
    444 			if (nopts = (char *)malloc(nlen)) {
    445 				(void) snprintf(nopts, nlen, "%s%s%s%s%s%s%s",
    446 				    DAOPT_MINLABEL, KV_ASSIGN, defmin,
    447 				    KV_TOKEN_DELIMIT,
    448 				    DAOPT_MAXLABEL, KV_ASSIGN, defmax);
    449 				devinfo->devopts = nopts;
    450 			}
    451 		} else {
    452 			if (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) {
    453 				/* add default minlabel */
    454 				ntok = DAOPT_MINLABEL;
    455 				nstr = defmin;
    456 				nlen = strlen(devinfo->devopts) +
    457 				    strlen(KV_TOKEN_DELIMIT) +
    458 				    strlen(ntok) + strlen(KV_ASSIGN) +
    459 				    strlen(nstr) + 1;
    460 				if (nopts = (char *)malloc(nlen)) {
    461 					(void) snprintf(nopts, nlen,
    462 					    "%s%s%s%s%s",
    463 					    devinfo->devopts, KV_TOKEN_DELIMIT,
    464 					    ntok, KV_ASSIGN, nstr);
    465 					devinfo->devopts = nopts;
    466 				}
    467 			}
    468 			if (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) {
    469 				/* add default maxlabel */
    470 				ntok = DAOPT_MAXLABEL;
    471 				nstr = defmax;
    472 				nlen = strlen(devinfo->devopts) +
    473 				    strlen(KV_TOKEN_DELIMIT) +
    474 				    strlen(ntok) + strlen(KV_ASSIGN) +
    475 				    strlen(nstr) + 1;
    476 				if (nopts = (char *)malloc(nlen)) {
    477 					(void) snprintf(nopts, nlen,
    478 					    "%s%s%s%s%s",
    479 					    devinfo->devopts, KV_TOKEN_DELIMIT,
    480 					    ntok, KV_ASSIGN, nstr);
    481 					devinfo->devopts = nopts;
    482 				}
    483 			}
    484 		}
    485 	}
    486 
    487 	return (0);
    488 }
    489 
    490 void
    491 usage(da_args *dargs, char *progname)
    492 {
    493 	if (dargs->optflag & DA_SILENT)
    494 		return;
    495 	if (dargs->optflag & DA_ADD)
    496 		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
    497 		    gettext(" [-f][-s][-d] -n name -t type -l device-list"
    498 		    "\n\t[-a authorization] [-c cleaning program] "
    499 		    "[-o key=value]\n"));
    500 	else if (dargs->optflag & DA_REMOVE)
    501 		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
    502 		    gettext(" [-f][-s][-d] [-n name|-t type]\n"));
    503 	else
    504 		(void) fprintf(stderr, gettext("Invalid usage\n"), progname);
    505 }
    506