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