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