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