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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <locale.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <sys/types.h> 33 #include <string.h> 34 #include "addrem.h" 35 #include "errmsg.h" 36 #include "plcysubr.h" 37 38 /* function prototypes */ 39 static void usage(); 40 static int unload_drv(char *, int, int); 41 42 43 /* 44 * try to modunload driver. 45 * return -1 on failure and 0 on success 46 */ 47 static int 48 unload_drv(char *driver_name, int force_flag, int verbose_flag) 49 { 50 int modid; 51 52 get_modid(driver_name, &modid); 53 if (modid != -1) { 54 if (modctl(MODUNLOAD, modid) < 0) { 55 (void) fprintf(stderr, gettext(ERR_MODUN), driver_name); 56 if (force_flag == 0) { /* no force flag */ 57 if (verbose_flag) { 58 (void) fprintf(stderr, 59 gettext(NOUPDATE), driver_name); 60 } 61 /* clean up and exit. remove lock file */ 62 err_exit(); 63 } 64 (void) fprintf(stderr, gettext(FORCE_UPDATE), 65 driver_name); 66 67 return (-1); 68 } 69 } 70 71 return (0); 72 } 73 74 75 static void 76 usage() 77 { 78 (void) fprintf(stderr, gettext(UPD_DRV_USAGE)); 79 exit(1); 80 } 81 82 83 int 84 main(int argc, char *argv[]) 85 { 86 int error, opt, major; 87 int cleanup_flag = 0; 88 int update_conf = 1; /* reload driver.conf by default */ 89 int verbose_flag = 0; /* -v option */ 90 int force_flag = 0; /* -f option */ 91 int a_flag = 0; /* -a option */ 92 int d_flag = 0; /* -d option */ 93 int i_flag = 0; /* -i option */ 94 int l_flag = 0; /* -l option */ 95 int m_flag = 0; /* -m option */ 96 char *perms = NULL; 97 char *aliases = 0; 98 char *basedir = NULL; 99 char *policy = NULL; 100 char *priv = NULL; 101 char *driver_name; 102 int found; 103 major_t major_num; 104 int rval; 105 106 (void) setlocale(LC_ALL, ""); 107 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 108 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 109 #endif 110 (void) textdomain(TEXT_DOMAIN); 111 112 /* must be run by root */ 113 if (getuid() != 0) { 114 (void) fprintf(stderr, gettext(ERR_NOT_ROOT)); 115 exit(1); 116 } 117 118 while ((opt = getopt(argc, argv, "m:i:b:p:adlfuvP:")) != EOF) { 119 switch (opt) { 120 case 'a': 121 a_flag++; 122 break; 123 case 'b': 124 update_conf = 0; /* don't update .conf file */ 125 basedir = optarg; 126 break; 127 case 'd': 128 d_flag++; 129 break; 130 case 'f': 131 force_flag++; 132 break; 133 case 'i': 134 i_flag++; 135 aliases = optarg; 136 if (check_space_within_quote(aliases) == ERROR) { 137 (void) fprintf(stderr, gettext(ERR_NO_SPACE), 138 aliases); 139 exit(1); 140 } 141 break; 142 case 'l': /* private option */ 143 l_flag++; 144 break; 145 case 'm': 146 m_flag++; 147 perms = optarg; 148 break; 149 case 'p': 150 policy = optarg; 151 break; 152 case 'v': 153 verbose_flag++; 154 break; 155 case 'P': 156 priv = optarg; 157 break; 158 case '?' : 159 default: 160 usage(); 161 } 162 } 163 164 /* 165 * check for flags and extra args 166 */ 167 if ((argv[optind] == NULL) || (optind + 1 != argc)) { 168 usage(); 169 } 170 171 /* 172 * - cannot be adding and removing at the same time 173 * - if -a or -d is specified, it's an error if none of 174 * -i/-m/-p/-P is specified. 175 */ 176 if ((a_flag && d_flag) || 177 ((a_flag || d_flag) && 178 !m_flag && !i_flag && priv == NULL && policy == NULL)) { 179 usage(); 180 } 181 182 /* 183 * - with -d option or -a option either -i 'identify_name', 184 * -m 'permission', -p 'policy' or -P 'priv' should be specified 185 */ 186 if (m_flag || i_flag || policy != NULL || priv != NULL) { 187 if (!(a_flag || d_flag)) 188 usage(); 189 } 190 191 driver_name = argv[optind]; 192 193 /* set up update_drv filenames */ 194 if ((build_filenames(basedir)) == ERROR) { 195 exit(1); 196 } 197 198 /* no lock is needed for listing minor perm entry */ 199 if (l_flag) { 200 list_entry(minor_perm, driver_name, ":"); 201 202 return (NOERR); 203 } 204 205 /* must be only running version of add_drv/update_drv/rem_drv */ 206 enter_lock(); 207 208 if ((check_perms_aliases(m_flag, i_flag)) == ERROR) { 209 err_exit(); 210 } 211 212 /* update_drv doesn't modify /etc/name_to_major file */ 213 if ((check_name_to_major(R_OK)) == ERROR) 214 err_exit(); 215 216 if (priv != NULL && check_priv_entry(priv, a_flag) != 0) 217 err_exit(); 218 219 if (policy != NULL && (policy = check_plcy_entry(policy, driver_name, 220 d_flag ? B_TRUE : B_FALSE)) == NULL) 221 err_exit(); 222 223 /* 224 * ADD: -a option 225 * i_flag: update /etc/driver_aliases 226 * m_flag: update /etc/minor_perm 227 * -p: update /etc/security/device_policy 228 * -P: update /etc/security/extra_privs 229 * if force_flag is specified continue w/ the next operation 230 */ 231 if (a_flag) { 232 if (m_flag) { 233 /* check if the permissions are valid */ 234 if ((error = check_perm_opts(perms)) == ERROR) { 235 if (force_flag == 0) { /* no force flag */ 236 exit_unlock(); 237 238 return (error); 239 } 240 } 241 242 /* 243 * update the file, if and only if 244 * we didn't run into error earlier. 245 */ 246 if ((error != ERROR) && 247 (error = update_minor_entry(driver_name, perms))) { 248 if (force_flag == 0) { /* no force flag */ 249 exit_unlock(); 250 251 return (error); 252 } 253 } 254 cleanup_flag |= CLEAN_NAM_MAJ; 255 256 /* 257 * Notify running system of minor perm change 258 */ 259 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 260 rval = devfs_add_minor_perm(driver_name, 261 log_minorperm_error); 262 if (rval) { 263 (void) fprintf(stderr, 264 gettext(ERR_UPDATE_PERM), 265 driver_name); 266 } 267 } 268 } 269 270 if (priv != NULL) { 271 (void) append_to_file(driver_name, priv, extra_privs, 272 ',', ":", 0); 273 cleanup_flag |= CLEAN_DRV_PRIV; 274 } 275 276 if (policy != NULL) { 277 if ((error = update_device_policy(device_policy, 278 policy, B_TRUE)) != 0) { 279 exit_unlock(); 280 return (error); 281 } 282 cleanup_flag |= CLEAN_DEV_POLICY; 283 } 284 285 if (i_flag) { 286 found = get_major_no(driver_name, name_to_major); 287 if (found == ERROR) { 288 (void) fprintf(stderr, gettext(ERR_MAX_MAJOR), 289 name_to_major); 290 err_exit(); 291 } 292 293 if (found == UNIQUE) { 294 (void) fprintf(stderr, 295 gettext(ERR_NOT_INSTALLED), driver_name); 296 err_exit(); 297 } 298 299 major_num = (major_t)found; 300 301 /* check if the alias is unique */ 302 if ((error = aliases_unique(aliases)) == ERROR) { 303 exit_unlock(); 304 305 return (error); 306 } 307 308 /* 309 * unless force_flag is specified check that 310 * path-oriented aliases we are adding exist 311 */ 312 if ((force_flag == 0) && 313 ((error = aliases_paths_exist(aliases)) == ERROR)) { 314 exit_unlock(); 315 316 return (error); 317 } 318 319 /* update the file */ 320 if ((error = update_driver_aliases(driver_name, 321 aliases)) == ERROR) { 322 exit_unlock(); 323 return (error); 324 } 325 326 /* paranoia - if we crash whilst configuring */ 327 sync(); 328 329 /* optionally update the running system - not -b */ 330 if (update_conf) { 331 cleanup_flag |= CLEAN_DRV_ALIAS; 332 if (config_driver(driver_name, major_num, 333 aliases, NULL, cleanup_flag, 334 verbose_flag) == ERROR) { 335 err_exit(); 336 } 337 } 338 339 } 340 if (update_conf && (i_flag || policy != NULL)) { 341 /* load the driver */ 342 load_driver(driver_name, verbose_flag); 343 } 344 345 exit_unlock(); 346 347 return (0); 348 } 349 350 351 /* 352 * DELETE: -d option 353 * i_flag: update /etc/driver_aliases 354 * m_flag: update /etc/minor_perm 355 * -p: update /etc/security/device_policy 356 * -P: update /etc/security/extra_privs 357 */ 358 if (d_flag) { 359 int err = NOERR; 360 361 if (m_flag) { 362 /* 363 * On a running system, we first need to 364 * remove devfs's idea of the minor perms. 365 * We don't have any ability to do this singly 366 * at this point. 367 */ 368 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 369 rval = devfs_rm_minor_perm(driver_name, 370 log_minorperm_error); 371 if (rval) { 372 (void) fprintf(stderr, 373 gettext(ERR_UPDATE_PERM), 374 driver_name); 375 } 376 } 377 378 if ((error = delete_entry(minor_perm, 379 driver_name, ":", perms)) != NOERR) { 380 (void) fprintf(stderr, gettext(ERR_NO_ENTRY), 381 driver_name, minor_perm); 382 err = error; 383 } 384 /* 385 * Notify running system of new minor perm state 386 */ 387 if (basedir == NULL || (strcmp(basedir, "/") == 0)) { 388 rval = devfs_add_minor_perm(driver_name, 389 log_minorperm_error); 390 if (rval) { 391 (void) fprintf(stderr, 392 gettext(ERR_UPDATE_PERM), 393 driver_name); 394 } 395 } 396 } 397 398 if (i_flag) { 399 if ((error = delete_entry(driver_aliases, 400 driver_name, ":", aliases)) != NOERR) { 401 (void) fprintf(stderr, gettext(ERR_NO_ENTRY), 402 driver_name, driver_aliases); 403 if (err != NOERR) 404 err = error; 405 } 406 } 407 408 if (priv != NULL) { 409 if ((error = delete_entry(extra_privs, driver_name, ":", 410 priv)) != NOERR) { 411 (void) fprintf(stderr, gettext(ERR_NO_ENTRY), 412 driver_name, extra_privs); 413 if (err != NOERR) 414 err = error; 415 } 416 } 417 418 if (policy != NULL) { 419 if ((error = delete_plcy_entry(device_policy, 420 policy)) != NOERR) { 421 (void) fprintf(stderr, gettext(ERR_NO_ENTRY), 422 driver_name, device_policy); 423 if (err != NOERR) 424 err = error; 425 } 426 } 427 428 if (err == NOERR && update_conf) { 429 if (i_flag || m_flag) { 430 /* try to unload the driver */ 431 (void) unload_drv(driver_name, 432 force_flag, verbose_flag); 433 } 434 /* reload the policy */ 435 if (policy != NULL) 436 load_driver(driver_name, verbose_flag); 437 } 438 exit_unlock(); 439 440 return (err); 441 } 442 443 /* driver name must exist (for update_conf stuff) */ 444 major = get_major_no(driver_name, name_to_major); 445 if (major == ERROR) { 446 err_exit(); 447 } 448 449 /* 450 * Update driver.conf file: 451 * First try to unload driver module. If it fails, there may 452 * be attached devices using the old driver.conf properties, 453 * so we cannot safely update driver.conf 454 * 455 * The user may specify -f to force a driver.conf update. 456 * In this case, we will update driver.conf cache. All attached 457 * devices still reference old driver.conf properties, including 458 * driver global properties. Devices attached in the future will 459 * referent properties in the updated driver.conf file. 460 */ 461 if (update_conf) { 462 (void) unload_drv(driver_name, force_flag, verbose_flag); 463 464 if ((modctl(MODUNLOADDRVCONF, major) != 0) || 465 (modctl(MODLOADDRVCONF, major) != 0)) { 466 (void) fprintf(stderr, gettext(ERR_DRVCONF), 467 driver_name); 468 err_exit(); 469 } 470 471 if (verbose_flag) { 472 (void) fprintf(stderr, gettext(DRVCONF_UPDATED), 473 driver_name); 474 } 475 load_driver(driver_name, verbose_flag); 476 } 477 478 479 exit_unlock(); 480 481 return (NOERR); 482 } 483