Print this page
4833 Remove volrmmount
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/rmvolmgr/vold.c
+++ new/usr/src/cmd/rmvolmgr/vold.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 - */
21 -/*
20 + *
21 + *
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + *
25 + * Copyright 2014 Andrew Stormont
24 26 */
25 27
26 28 /*
27 29 * Vold compatibility for rmvolmgr: emulate old commands as well as
28 30 * action_filemgr.so to notify legacy apps via /tmp/.removable pipes.
29 31 * A lot of this code is copied verbatim from vold sources.
30 32 *
31 33 * Here's the original description of action_filemgr.so:
32 34 *
33 35 * action_filemgr.so - filemgr interface routines for rmmount
34 36 *
35 37 * This shared object allows rmmount to communicate with filemgr.
36 38 * This is done by communicating over a named pipe that filemgr
37 39 * creates in directory NOTIFY_DIR. The name of the pipe must
38 40 * begin with NOTIFY_NAME. This source file contains #define
39 41 * compiler directives set the values of NOTIFY_DIR and NOTIFY_NAME.
40 42 *
41 43 * After a partition on a medium has been mounted as a result of
42 44 * either insertion or remounting of the medium, the action()
43 45 * method creates a file named with the symbolic name of the
44 46 * device in which the medium is inserted and the partition name
45 47 * (e.g. "jaz0-s2") in NOTIFY_DIR. The file consists of one text
46 48 * line containing a string naming the mount point of the partition,
47 49 * a string giving the raw device path to the partition, and a
48 50 * string naming the file system type on the partition. The action()
49 51 * method then sends a single character ('i' for insertion, 'r' for
50 52 * remounting) through the named pipe NOTIFY_NAME to tell filemgr to
51 53 * look for new files in NOTIFY_DIR.
52 54 *
53 55 * If a medium containing no mountable partitions is inserted
54 56 * or remounted in a device, the action() method creates a file
55 57 * named with the symbolic name of the device in NOTIFY_DIR.
56 58 * The file consists of one text line containing a string
57 59 * giving the symbolic name of the device and a string naming
58 60 * the reason that the medium couldn't be mounted. The action
59 61 * method then sends either an 'i' or an 'r' through the named
60 62 * pipe to tell filemgr to look for new files in NOTIFY_DIR.
61 63 *
62 64 * When a medium is ejected or unmounted, the action() method
63 65 * removes the files that were created in NOTIFY_DIR when the medium
64 66 * was inserted or remounted and sends a single character ('e' for
65 67 * ejection, 'u' for unmounting) through the named pipe.
66 68 *
67 69 * The following environment variables must be set before calling action():
68 70 *
69 71 * VOLUME_ACTION action that occurred (e.g. "insert", "eject")
70 72 * VOLUME_SYMDEV symbolic name (e.g. "cdrom0", "floppy1")
71 73 * VOLUME_NAME volume name (e.g. "unnamed_cdrom", "s2")
72 74 */
73 75
74 76
75 77 #include <stdio.h>
76 78 #include <stdlib.h>
77 79 #include <unistd.h>
78 80 #include <fcntl.h>
79 81 #include <string.h>
80 82 #include <strings.h>
81 83 #include <dirent.h>
82 84 #include <signal.h>
83 85 #include <errno.h>
84 86 #include <libintl.h>
85 87 #include <zone.h>
86 88 #include <pwd.h>
87 89 #include <sys/types.h>
88 90 #include <sys/stat.h>
89 91 #include <sys/dkio.h>
90 92 #include <sys/cdio.h>
91 93 #include <sys/vtoc.h>
92 94 #include <sys/param.h>
93 95 #include <sys/wait.h>
94 96 #include <libcontract.h>
95 97 #include <sys/contract/process.h>
96 98 #include <sys/ctfs.h>
97 99 #include <tsol/label.h>
98 100
99 101 #include "vold.h"
100 102 #include "rmm_common.h"
101 103
102 104 int rmm_debug = 0;
103 105 boolean_t rmm_vold_actions_enabled = B_FALSE;
104 106 boolean_t rmm_vold_mountpoints_enabled = B_FALSE;
105 107
106 108 static char *prog_name = NULL;
107 109 static pid_t prog_pid = 0;
108 110 static int system_labeled = 0;
109 111 static uid_t mnt_uid = (uid_t)-1;
110 112 static gid_t mnt_gid = (gid_t)-1;
111 113 static zoneid_t mnt_zoneid = -1;
112 114 static char mnt_zoneroot[MAXPATHLEN];
113 115 static char mnt_userdir[MAXPATHLEN];
114 116
115 117 /*
116 118 * Private attribute types and attributes.
117 119 */
118 120 static const char notify_characters[] = {
119 121 'e',
120 122 'i',
121 123 'r',
122 124 'u'
↓ open down ↓ |
89 lines elided |
↑ open up ↑ |
123 125 };
124 126
125 127 static const char *result_strings[] = {
126 128 "FALSE",
127 129 "TRUE"
128 130 };
129 131
130 132 #define NOTIFY_DIR "/tmp/.removable" /* dir where filemgr looks */
131 133 #define NOTIFY_NAME "notify" /* named pipe to talk over */
132 134
133 -static void volrmmount_usage();
134 135 static void volcheck_usage();
135 136 static int vold_action(struct action_arg *aap);
136 137 static void vold_update_mountpoints(struct action_arg *aap);
137 138 static char *not_mountable(struct action_arg *aa);
138 139 static int create_one_notify_file(char *fstype,
139 140 char *mount_point,
140 141 char *notify_file,
141 142 char *raw_partitionp,
142 143 char *reason,
143 144 char *symdev);
144 145 static int create_notify_files(struct action_arg **aa);
145 146 static boolean_t notify_clients(action_t action, int do_notify);
146 147 static void popdir(int fd);
147 148 static int pushdir(const char *dir);
148 149 static boolean_t remove_notify_files(struct action_arg **aa);
149 150
150 151 /*
151 152 * should be called once from main()
152 153 */
153 154 /* ARGSUSED */
154 155 void
155 156 vold_init(int argc, char **argv)
156 157 {
157 158 system_labeled = is_system_labeled();
158 159 }
159 160
160 161 /*
161 162 * Old version of rmmount(1M)
162 163 */
163 164 /* ARGSUSED */
164 165 int
165 166 vold_rmmount(int argc, char **argv)
166 167 {
167 168 char *volume_action;
168 169 char *volume_mediatype;
169 170 char *volume_mount_mode;
170 171 char *volume_name;
171 172 char *volume_path;
172 173 char *volume_pcfs_id;
173 174 char *volume_symdev;
174 175 char *volume_zonename;
175 176 char *volume_user;
176 177 action_t action;
177 178 char mountpoint[MAXPATHLEN];
178 179 char *zonemountpoint;
179 180 char *arg_mountpoint = NULL;
180 181 LibHalContext *hal_ctx;
181 182 DBusError error;
182 183 rmm_error_t rmm_error;
183 184 int ret;
184 185
185 186 prog_name = argv[0];
186 187 prog_pid = getpid();
187 188
188 189 mnt_zoneroot[0] = '\0';
189 190 mnt_userdir[0] = '\0';
190 191
191 192 volume_action = getenv("VOLUME_ACTION");
192 193 volume_mediatype = getenv("VOLUME_MEDIATYPE");
193 194 volume_mount_mode = getenv("VOLUME_MOUNT_MODE");
194 195 volume_name = getenv("VOLUME_NAME");
195 196 volume_path = getenv("VOLUME_PATH");
196 197 volume_pcfs_id = getenv("VOLUME_PCFS_ID");
197 198 volume_symdev = getenv("VOLUME_SYMDEV");
198 199
199 200 if (system_labeled) {
200 201 volume_zonename = getenv("VOLUME_ZONE_NAME");
201 202 volume_user = getenv("VOLUME_USER");
202 203 }
203 204 if (volume_action == NULL) {
204 205 dprintf("%s(%ld): VOLUME_ACTION was null!!\n",
205 206 prog_name, prog_pid);
206 207 return (-1);
207 208 }
208 209 if (volume_mediatype == NULL) {
209 210 dprintf("%s(%ld): VOLUME_MEDIATYPE was null!!\n",
210 211 prog_name, prog_pid);
211 212 return (-1);
212 213 }
213 214 if (volume_mount_mode == NULL) {
214 215 volume_mount_mode = "rw";
215 216 }
216 217 if (volume_name == NULL) {
217 218 dprintf("%s(%ld): VOLUME_NAME was null!!\n",
218 219 prog_name, prog_pid);
219 220 return (-1);
220 221 }
221 222 if (volume_path == NULL) {
222 223 dprintf("%s(%ld): VOLUME_PATH was null!!\n",
223 224 prog_name, prog_pid);
224 225 return (-1);
225 226 }
226 227 if (volume_pcfs_id == NULL) {
227 228 volume_pcfs_id = "";
228 229 }
229 230 if (volume_symdev == NULL) {
230 231 dprintf("%s(%ld): VOLUME_SYMDEV was null!!\n",
231 232 prog_name, prog_pid);
232 233 return (-1);
233 234 }
234 235
235 236 if (system_labeled) {
236 237 if (volume_zonename != NULL &&
237 238 strcmp(volume_zonename, GLOBAL_ZONENAME) != 0) {
238 239 if ((mnt_zoneid =
239 240 getzoneidbyname(volume_zonename)) != -1) {
240 241 if (zone_getattr(mnt_zoneid, ZONE_ATTR_ROOT,
241 242 mnt_zoneroot, MAXPATHLEN) == -1) {
242 243 dprintf("%s(%ld): NO ZONEPATH!!\n",
243 244 prog_name, prog_pid);
244 245 return (-1);
245 246 }
246 247 }
247 248 } else {
248 249 mnt_zoneid = GLOBAL_ZONEID;
249 250 mnt_zoneroot[0] = '\0';
250 251 }
251 252 if (volume_user != NULL) {
252 253 struct passwd *pw;
253 254
254 255 if ((pw = getpwnam(volume_user)) == NULL) {
255 256 dprintf("%s(%ld) %s\n", prog_name, prog_pid,
256 257 ": VOLUME_USER was not a valid user!");
257 258 return (-1);
258 259 }
259 260 mnt_uid = pw->pw_uid;
260 261 mnt_gid = pw->pw_gid;
261 262
262 263 if (snprintf(mnt_userdir, sizeof (mnt_userdir),
263 264 "/%s-%s", volume_user, volume_symdev) >=
264 265 sizeof (mnt_userdir))
265 266 return (-1);
266 267 } else {
267 268 mnt_uid = 0;
268 269 mnt_userdir[0] = '\0';
269 270 }
270 271
271 272 rmm_vold_mountpoints_enabled = B_FALSE;
272 273 rmm_vold_actions_enabled = B_TRUE;
273 274 } else {
274 275 rmm_vold_mountpoints_enabled = B_TRUE;
275 276 rmm_vold_actions_enabled = B_TRUE;
276 277 }
277 278
278 279 if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
279 280 rmm_dbus_error_free(&error);
280 281
281 282 /* if HAL's not running, must be root */
282 283 if (geteuid() != 0) {
283 284 (void) fprintf(stderr,
284 285 gettext("%s(%ld) error: must be root to execute\n"),
285 286 prog_name, prog_pid);
286 287 return (-1);
287 288 }
288 289 }
289 290
290 291 if (strcmp(volume_action, "eject") == 0) {
291 292 action = EJECT;
292 293 } else if (strcmp(volume_action, "insert") == 0) {
293 294 action = INSERT;
294 295
295 296 if (system_labeled) {
296 297 /*
297 298 * create mount point
298 299 */
299 300 if (strlen(mnt_userdir) > 0) {
300 301 if (snprintf(mountpoint, MAXPATHLEN,
301 302 "%s/%s%s", mnt_zoneroot, volume_mediatype,
302 303 mnt_userdir) > MAXPATHLEN) {
303 304 return (-1);
304 305
305 306 }
306 307 (void) makepath(mountpoint, 0700);
307 308 (void) chown(mountpoint, mnt_uid, mnt_gid);
308 309 /*
309 310 * set the top level directory bits to 0755
310 311 * so user can access it.
311 312 */
312 313 if (snprintf(mountpoint, MAXPATHLEN,
313 314 "%s/%s", mnt_zoneroot,
314 315 volume_mediatype) <= MAXPATHLEN) {
315 316 (void) chmod(mountpoint, 0755);
316 317 }
317 318 }
318 319 if (snprintf(mountpoint, MAXPATHLEN,
319 320 "%s/%s%s/%s", mnt_zoneroot, volume_mediatype,
320 321 mnt_userdir, volume_name) > MAXPATHLEN) {
321 322 (void) fprintf(stderr,
322 323 gettext("%s(%ld) error: path too long\n"),
323 324 prog_name, prog_pid);
324 325 return (-1);
325 326 }
326 327
327 328 /* make our mountpoint */
328 329 (void) makepath(mountpoint, 0755);
329 330
330 331 arg_mountpoint = mountpoint;
331 332 }
332 333 } else if (strcmp(volume_action, "remount") == 0) {
333 334 action = REMOUNT;
334 335 } else if (strcmp(volume_action, "unmount") == 0) {
335 336 action = UNMOUNT;
336 337 }
337 338
338 339 ret = rmm_action(hal_ctx, volume_symdev, action, 0, 0, 0,
339 340 arg_mountpoint) ? 0 : 1;
340 341
341 342 if (hal_ctx != NULL) {
342 343 rmm_hal_fini(hal_ctx);
343 344 }
344 345
345 346 return (ret);
346 347 }
347 348
348 349
349 350 /*
350 351 * this should be called after rmm_hal_{mount,unmount,eject}
351 352 */
352 353 int
353 354 vold_postprocess(LibHalContext *hal_ctx, const char *udi,
354 355 struct action_arg *aap)
355 356 {
356 357 int ret = 0;
357 358
358 359 /* valid mountpoint required */
359 360 if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
360 361 rmm_volume_aa_update_mountpoint(hal_ctx, udi, aap);
361 362 if ((aap->aa_mountpoint == NULL) ||
362 363 (strlen(aap->aa_mountpoint) == 0)) {
363 364 return (1);
364 365 }
365 366 }
366 367
367 368 if (rmm_vold_mountpoints_enabled) {
368 369 vold_update_mountpoints(aap);
369 370 }
370 371 if (rmm_vold_actions_enabled) {
371 372 ret = vold_action(aap);
372 373 }
373 374
374 375 return (ret);
375 376 }
376 377
377 378 /*
378 379 * update legacy symlinks
379 380 *
380 381 * For cdrom:
381 382 *
382 383 * /cdrom/<name> -> original mountpoint
383 384 * /cdrom/cdrom0 -> ./<name>
384 385 * /cdrom/cdrom -> cdrom0 (only for cdrom0)
385 386 *
386 387 * If it's a slice or partition, /cdrom/<name> becomes a directory:
387 388 *
388 389 * /cdrom/<name>/s0
389 390 *
390 391 * Same for rmdisk and floppy.
391 392 *
392 393 * On labeled system (Trusted Solaris), links are in a user directory.
393 394 */
394 395 static void
395 396 vold_update_mountpoints(struct action_arg *aap)
396 397 {
397 398 boolean_t is_partition;
398 399 char part_dir[2 * MAXNAMELEN];
399 400 char symname_mp[2 * MAXNAMELEN];
400 401 char symcontents_mp[MAXNAMELEN];
401 402 char symname[2 * MAXNAMELEN];
402 403 char symcontents[MAXNAMELEN];
403 404
404 405 is_partition = (aap->aa_partname != NULL);
405 406
406 407 if (!system_labeled) {
407 408 if (!is_partition) {
408 409 /* /cdrom/<name> -> original mountpoint */
409 410 (void) snprintf(symcontents_mp, sizeof (symcontents_mp),
410 411 "%s", aap->aa_mountpoint);
411 412 (void) snprintf(symname_mp, sizeof (symname_mp),
412 413 "/%s/%s", aap->aa_media, aap->aa_name);
413 414 } else {
414 415 /* /cdrom/<name>/slice -> original mountpoint */
415 416 (void) snprintf(part_dir, sizeof (part_dir),
416 417 "/%s/%s", aap->aa_media, aap->aa_name);
417 418 (void) snprintf(symcontents_mp, sizeof (symcontents_mp),
418 419 "%s", aap->aa_mountpoint);
419 420 (void) snprintf(symname_mp, sizeof (symname_mp),
420 421 "/%s/%s/%s", aap->aa_media, aap->aa_name,
421 422 aap->aa_partname);
422 423
423 424 }
424 425 /* /cdrom/cdrom0 -> ./<name> */
425 426 (void) snprintf(symcontents, sizeof (symcontents),
426 427 "./%s", aap->aa_name);
427 428 (void) snprintf(symname, sizeof (symname),
428 429 "/%s/%s", aap->aa_media, aap->aa_symdev);
429 430 } else {
430 431 if (!is_partition) {
431 432 /* /cdrom/<user>/<name> -> original mountpoint */
432 433 (void) snprintf(symcontents_mp, sizeof (symcontents_mp),
433 434 "%s", aap->aa_mountpoint);
434 435 (void) snprintf(symname_mp, sizeof (symname_mp),
435 436 "%s/%s/%s", mnt_zoneroot, aap->aa_media,
436 437 aap->aa_symdev);
437 438 } else {
438 439 /* /cdrom/<user>/<name>/slice -> original mountpoint */
439 440 (void) snprintf(symcontents_mp, sizeof (symcontents_mp),
440 441 "%s", aap->aa_mountpoint);
441 442 (void) snprintf(symname_mp, sizeof (symname_mp),
442 443 "%s/%s/%s", mnt_zoneroot, aap->aa_media,
443 444 aap->aa_symdev, aap->aa_partname);
444 445 }
445 446
446 447 /* /cdrom/<user>/cdrom0 -> ./<user>/<name> */
447 448 (void) snprintf(symcontents, sizeof (symcontents),
448 449 ".%s/%s", mnt_userdir, aap->aa_name);
449 450 (void) snprintf(symname, sizeof (symname), "%s/%s/%s",
450 451 mnt_zoneroot, aap->aa_media, aap->aa_symdev);
451 452 }
452 453
453 454 (void) unlink(symname);
454 455 (void) unlink(symname_mp);
455 456 if (is_partition) {
456 457 (void) rmdir(part_dir);
457 458 }
458 459
459 460 if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
460 461 (void) mkdir(aap->aa_media, 0755);
461 462 if (is_partition) {
462 463 (void) mkdir(part_dir, 0755);
463 464 }
464 465 (void) symlink(symcontents_mp, symname_mp);
465 466 (void) symlink(symcontents, symname);
466 467 }
467 468 }
468 469
469 470
470 471 static int
471 472 vold_action(struct action_arg *aap)
472 473 {
473 474 action_t action;
474 475 int result;
475 476 int do_notify = FALSE;
476 477 action_t notify_act = EJECT;
477 478 struct action_arg *aa[2];
478 479 struct action_arg a1;
479 480
480 481 dprintf("%s[%d]: entering action()\n", __FILE__, __LINE__);
481 482
482 483 /*
483 484 * on Trusted Extensions, actions are executed in the user's zone
484 485 */
485 486 if (mnt_zoneid > GLOBAL_ZONEID) {
486 487 pid_t pid;
487 488 int status;
488 489 int ifx;
489 490 int tmpl_fd;
490 491 int err = 0;
491 492
492 493 tmpl_fd = open64(CTFS_ROOT "/process/template",
493 494 O_RDWR);
494 495 if (tmpl_fd == -1)
495 496 return (1);
496 497
497 498 /*
498 499 * Deliver no events, don't inherit,
499 500 * and allow it to be orphaned.
500 501 */
501 502 err |= ct_tmpl_set_critical(tmpl_fd, 0);
502 503 err |= ct_tmpl_set_informative(tmpl_fd, 0);
503 504 err |= ct_pr_tmpl_set_fatal(tmpl_fd,
504 505 CT_PR_EV_HWERR);
505 506 err |= ct_pr_tmpl_set_param(tmpl_fd,
506 507 CT_PR_PGRPONLY |
507 508 CT_PR_REGENT);
508 509 if (err || ct_tmpl_activate(tmpl_fd)) {
509 510 (void) close(tmpl_fd);
510 511 return (1);
511 512 }
512 513 switch (pid = fork1()) {
513 514 case 0:
514 515 (void) ct_tmpl_clear(tmpl_fd);
515 516 for (ifx = 0; ifx < _NFILE; ifx++)
516 517 (void) close(ifx);
517 518
518 519 if (zone_enter(mnt_zoneid) == -1)
519 520 _exit(0);
520 521
521 522 /* entered zone, proceed to action */
522 523 break;
523 524 case -1:
524 525 dprintf("fork1 failed \n ");
525 526 return (1);
526 527 default :
527 528 (void) ct_tmpl_clear(tmpl_fd);
528 529 (void) close(tmpl_fd);
529 530 if (waitpid(pid, &status, 0) < 0) {
530 531 dprintf("%s(%ld): waitpid() "
531 532 "failed (errno %d) \n",
532 533 prog_name, prog_pid, errno);
533 534 return (1);
534 535 }
535 536 }
536 537 }
537 538
538 539 /* only support one action at a time XXX */
539 540 a1.aa_path = NULL;
540 541 aa[0] = aap;
541 542 aa[1] = &a1;
542 543
543 544 action = aa[0]->aa_action;
544 545
545 546 if (action == CLEAR_MOUNTS) {
546 547 /*
547 548 * Remove the notifications files, but don't
548 549 * notify the client. The "clear_mounts" action
549 550 * simply clears all existing mounts of a medium's
550 551 * partitions after a medium has been repartitioned.
551 552 * Then vold builds a new file system that reflects
552 553 * the medium's new partition structure and mounts
553 554 * the new partitions by calling rmmount, and therefore
554 555 * action(), with the VOLUME_ACTION environment variable
555 556 * set to "remount".
556 557 */
557 558 result = remove_notify_files(aa);
558 559 result = TRUE;
559 560 } else if (action == EJECT) {
560 561 result = remove_notify_files(aa);
561 562 if (result == TRUE) {
562 563 do_notify = TRUE;
563 564 notify_act = EJECT;
564 565 }
565 566 } else if (action = INSERT) {
566 567 result = create_notify_files(aa);
567 568 if (result == TRUE) {
568 569 do_notify = TRUE;
569 570 notify_act = INSERT;
570 571 }
571 572 } else if (action == REMOUNT) {
572 573 result = create_notify_files(aa);
573 574 if (result == TRUE) {
574 575 do_notify = TRUE;
575 576 notify_act = REMOUNT;
576 577 }
577 578 } else if (action == UNMOUNT) {
578 579 result = remove_notify_files(aa);
579 580 if (result == TRUE) {
580 581 do_notify = TRUE;
581 582 notify_act = UNMOUNT;
582 583 }
583 584 } else {
584 585 dprintf("%s[%d]: action(): invalid action: %s\n",
585 586 __FILE__, __LINE__, action);
586 587 result = FALSE;
587 588 }
588 589
589 590 if (result == TRUE) {
590 591 result = notify_clients(notify_act, do_notify);
591 592 }
592 593
593 594 dprintf("%s[%d]: leaving action(), result = %s\n",
594 595 __FILE__, __LINE__, result_strings[result]);
595 596
596 597 if (mnt_zoneid > GLOBAL_ZONEID) {
597 598 /* exit forked local zone process */
598 599 _exit(0);
599 600 }
600 601
601 602 if (result == TRUE) {
602 603 /*
603 604 * File Manager is running. return 0.
604 605 * see man page rmmount.conf(4).
605 606 */
606 607 return (0);
607 608 } else {
608 609 return (1);
609 610 }
610 611 }
611 612
612 613
613 614 /*
614 615 * Returns NULL if a medium or partition is mountable
615 616 * and a string stating the reason the medium or partition
616 617 * can't be mounted if the medium or partition isn't mountable.
617 618 *
618 619 * If the volume_name of the medium or partition is one of the
619 620 * following, the medium or partition isn't mountable.
620 621 *
621 622 * unlabeled_<media_type>
622 623 * unknown_format
623 624 * password_protected
624 625 */
625 626 /* ARGSUSED */
626 627 static char *
627 628 not_mountable(struct action_arg *aa)
628 629 {
629 630 return (NULL);
630 631 }
631 632
632 633 static int
633 634 create_notify_files(struct action_arg **aa)
634 635 {
635 636 int ai;
636 637 char *fstype;
637 638 char *mount_point;
638 639 char notify_file[64];
639 640 char *raw_partitionp;
640 641 char *reason; /* Why the medium wasn't mounted */
641 642 int result;
642 643 char *symdev;
643 644
644 645 dprintf("%s[%d]: entering create_notify_files()\n", __FILE__, __LINE__);
645 646
646 647 ai = 0;
647 648 result = FALSE;
648 649 symdev = aa[ai]->aa_symdev;
649 650 while ((aa[ai] != NULL) && (aa[ai]->aa_path != NULL)) {
650 651 if (aa[ai]->aa_mountpoint != NULL) {
651 652 if (aa[ai]->aa_type) {
652 653 fstype = aa[ai]->aa_type;
653 654 } else {
654 655 fstype = "unknown";
655 656 }
656 657 mount_point = aa[ai]->aa_mountpoint;
657 658 if (aa[ai]->aa_partname != NULL) {
658 659 /*
659 660 * Is aa_partname ever NULL?
660 661 * When time permits, check.
661 662 * If it is, the action taken
662 663 * in the else clause could produce
663 664 * file name conflicts.
664 665 */
665 666 sprintf(notify_file, "%s-%s", symdev,
666 667 aa[ai]->aa_partname);
667 668 } else {
668 669 sprintf(notify_file, "%s-0", symdev);
669 670 }
670 671 reason = NULL;
671 672 } else {
672 673 /*
673 674 * The partition isn't mounted.
674 675 */
675 676 fstype = "none";
676 677 mount_point = "none";
677 678 reason = not_mountable(aa[ai]);
678 679 if (reason != NULL) {
679 680 sprintf(notify_file, "%s-0", symdev);
680 681 } else {
681 682 /*
682 683 * Either the partition is a backup slice, or
683 684 * rmmount tried to mount the partition, but
684 685 * idenf_fs couldn't identify the file system
685 686 * type; that can occur when rmmount is
686 687 * trying to mount all the slices in a Solaris
687 688 * VTOC, and one or more partitions don't have
688 689 * file systems in them.
689 690 */
690 691 if (aa[0]->aa_partname != NULL) {
691 692 /*
692 693 * Is aa_partname ever NULL?
693 694 * When time permits, check.
694 695 * If it is, the action taken
695 696 * in the else clause could produce
696 697 * file name conflicts.
697 698 */
698 699 sprintf(notify_file, "%s-%s", symdev,
699 700 aa[0]->aa_partname);
700 701 } else {
701 702 sprintf(notify_file, "%s-0", symdev);
702 703 }
703 704 if ((aa[0]->aa_type != NULL) &&
704 705 (strcmp(aa[0]->aa_type, "backup_slice")
705 706 == 0)) {
706 707 reason = "backup_slice";
707 708 } else {
708 709 reason = "unformatted_media";
709 710 }
710 711 /*
711 712 * "unformatted_media" should be
712 713 * changed to "unformmated_medium" for
713 714 * grammatical correctness, but
714 715 * "unformatted_media" is now specified
715 716 * in the interface to filemgr, so the
716 717 * change can't be made without the
717 718 * approval of the CDE group.
718 719 */
719 720 }
720 721 }
721 722 raw_partitionp = aa[0]->aa_rawpath;
722 723 result = create_one_notify_file(fstype,
723 724 mount_point,
724 725 notify_file,
725 726 raw_partitionp,
726 727 reason,
727 728 symdev);
728 729 ai++;
729 730 }
730 731 dprintf("%s[%d]: leaving create_notify_files(), result = %s\n",
731 732 __FILE__, __LINE__, result_strings[result]);
732 733 return (result);
733 734 }
734 735
735 736 static int
736 737 create_one_notify_file(char *fstype,
737 738 char *mount_point,
738 739 char *notify_file,
739 740 char *raw_partitionp,
740 741 char *reason,
741 742 char *symdev)
742 743 {
743 744 /*
744 745 * For a mounted partition, create a notification file
745 746 * indicating the mount point, the raw device pathname
746 747 * of the partition, and the partition's file system
747 748 * type. For an unmounted partition, create a
748 749 * notification file containing the reason that the
749 750 * partition wasn't mounted and the raw device pathname
750 751 * of the partition.
751 752 *
752 753 * Create the file as root in a world-writable
753 754 * directory that resides in a world-writable directory.
754 755 *
755 756 * Handle two possible race conditions that could
756 757 * allow security breaches.
757 758 */
758 759
759 760 int current_working_dir_fd;
760 761 int file_descriptor;
761 762 FILE *filep;
762 763 int result;
763 764
764 765 dprintf("%s[%d]:Entering create_one_notify_file()\n",
765 766 __FILE__, __LINE__);
766 767 dprintf("\tcreate_one_notify_file(): fstype = %s\n", fstype);
767 768 dprintf("\tcreate_one_notify_file(): mount_point = %s\n", mount_point);
768 769 dprintf("\tcreate_one_notify_file(): notify_file = %s\n", notify_file);
769 770 dprintf("\tcreate_one_notify_file(): raw_partitionp = %s\n",
770 771 raw_partitionp);
771 772 if (reason != NULL) {
772 773 dprintf("\tcreate_one_notify_file(): reason = %s\n", reason);
773 774 } else {
774 775 dprintf("\tcreate_one_notify_file(): reason = NULL\n");
775 776 }
776 777 dprintf("\tcreate_one_notify_file(): symdev = %s\n", symdev);
777 778
778 779 result = TRUE;
779 780 /*
780 781 * Handle Race Condition One:
781 782 *
782 783 * If NOTIFY_DIR exists, make sure it is not a symlink.
783 784 * if it is, remove it and try to create it. Check
784 785 * again to make sure NOTIFY_DIR isn't a symlink.
785 786 * If it is, remove it and return without creating
786 787 * a notification file. The condition can only occur if
787 788 * someone is trying to break into the system by running
788 789 * a program that repeatedly creates NOTIFY_DIR as a
789 790 * symlink. If NOTIFY_DIR exists and isn't a symlink,
790 791 * change the working directory to NOTIFY_DIR.
791 792 */
792 793 current_working_dir_fd = pushdir(NOTIFY_DIR);
793 794 if (current_working_dir_fd < 0) {
794 795 (void) makepath(NOTIFY_DIR, 0777);
795 796 current_working_dir_fd = pushdir(NOTIFY_DIR);
796 797 if (current_working_dir_fd < 0) {
797 798 result = FALSE;
798 799 }
799 800 }
800 801 /*
801 802 * Handle Race Condition Two:
802 803 *
803 804 * Create the notification file in NOTIFY_DIR.
804 805 * Remove any files with the same name that may already be
805 806 * there, using remove(), as it safely removes directories.
806 807 * Then open the file O_CREAT|O_EXCL, which doesn't follow
807 808 * symlinks and requires that the file not exist already,
808 809 * so the new file actually resides in the current working
809 810 * directory. Create the file with access mode 644, which
810 811 * renders it unusable by anyone trying to break into the
811 812 * system.
812 813 */
813 814 if (result == TRUE) {
814 815 /*
815 816 * The current working directory is now NOTIFY_DIR.
816 817 */
817 818 (void) remove(notify_file);
818 819 file_descriptor =
819 820 open(notify_file, O_CREAT|O_EXCL|O_WRONLY, 0644);
820 821 if (file_descriptor < 0) {
821 822 dprintf("%s[%d]: can't create %s/%s; %m\n",
822 823 __FILE__, __LINE__, NOTIFY_DIR, notify_file);
823 824 result = FALSE;
824 825 } else {
825 826 filep = fdopen(file_descriptor, "w");
826 827 if (filep != NULL) {
827 828 if (reason == NULL) {
828 829 (void) fprintf(filep, "%s %s %s",
829 830 mount_point,
830 831 raw_partitionp,
831 832 fstype);
832 833 (void) fclose(filep);
833 834 dprintf("%s[%d]: Just wrote %s %s %s to %s\n",
834 835 __FILE__,
835 836 __LINE__,
836 837 mount_point,
837 838 raw_partitionp,
838 839 fstype,
839 840 notify_file);
840 841 } else {
841 842 (void) fprintf(filep, "%s %s",
842 843 reason, raw_partitionp);
843 844 (void) fclose(filep);
844 845 dprintf("%s[%d]: Just wrote %s %s to %s\n",
845 846 __FILE__,
846 847 __LINE__,
847 848 reason,
848 849 raw_partitionp,
849 850 notify_file);
850 851 }
851 852 } else {
852 853 dprintf("%s[%d]: can't write %s/%s; %m\n",
853 854 __FILE__, __LINE__,
854 855 NOTIFY_DIR, notify_file);
855 856 (void) close(file_descriptor);
856 857 result = FALSE;
857 858 }
858 859 }
859 860 popdir(current_working_dir_fd);
860 861 }
861 862 dprintf("%s[%d]: leaving create_one_notify_file, result = %s\n",
862 863 __FILE__, __LINE__, result_strings[result]);
863 864 return (result);
864 865 }
865 866
866 867 static boolean_t
867 868 notify_clients(action_t action, int do_notify)
868 869 {
869 870 /*
870 871 * Notify interested applications of changes in the state
871 872 * of removable media. Interested applications are those
872 873 * that create a named pipe in NOTIFY_DIR with a name that
873 874 * begins with "notify". Open the pipe and write a
874 875 * character through it that indicates the type of state
875 876 * change = 'e' for ejections, 'i' for insertions, 'r'
876 877 * for remounts of the file systems on repartitioned media,
877 878 * and 'u' for unmounts of file systems.
878 879 */
879 880
880 881 int current_working_dir_fd;
881 882 DIR *dirp;
882 883 struct dirent *dir_entryp;
883 884 size_t len;
884 885 int fd;
885 886 char namebuf[MAXPATHLEN];
886 887 char notify_character;
887 888 void (*old_signal_handler)();
888 889 int result;
889 890 struct stat sb;
890 891
891 892 dprintf("%s[%d]: entering notify_clients()\n", __FILE__, __LINE__);
892 893
893 894 result = TRUE;
894 895 /*
895 896 * Use relative pathnames after changing the
896 897 * working directory to the notification directory.
897 898 * Check to make sure that each "notify" file is a
898 899 * named pipe to make sure that it hasn't changed
899 900 * its file type, which could mean that someone is
900 901 * trying to use "notify" files to break into the
901 902 * system.
902 903 */
903 904 if ((current_working_dir_fd = pushdir(NOTIFY_DIR)) < 0) {
904 905 result = FALSE;
905 906 }
906 907 if (result == TRUE) {
907 908 dirp = opendir(".");
908 909 if (dirp == NULL) {
909 910 dprintf("%s[%d]:opendir failed on '.'; %m\n",
910 911 __FILE__, __LINE__);
911 912 popdir(current_working_dir_fd);
912 913 result = FALSE;
913 914 }
914 915 }
915 916 if (result == TRUE) {
916 917 /*
917 918 * Read through the directory and write a notify
918 919 * character to all files whose names start with "notify".
919 920 */
920 921 result = FALSE;
921 922 old_signal_handler = signal(SIGPIPE, SIG_IGN);
922 923 len = strlen(NOTIFY_NAME);
923 924 while (dir_entryp = readdir(dirp)) {
924 925 if (strncmp(dir_entryp->d_name, NOTIFY_NAME, len)
925 926 != 0) {
926 927 continue;
927 928 }
928 929 result = TRUE;
929 930 if (do_notify != TRUE) {
930 931 continue;
931 932 }
932 933 (void) sprintf(namebuf, "%s/%s",
933 934 NOTIFY_DIR, dir_entryp->d_name);
934 935 if ((fd = open(namebuf, O_WRONLY|O_NDELAY)) < 0) {
935 936 dprintf("%s[%d]: open failed for %s; %m\n",
936 937 __FILE__, __LINE__, namebuf);
937 938 continue;
938 939 }
939 940 /*
940 941 * Check to be sure that the entry is a named pipe.
941 942 * That closes a small security hole that could
942 943 * enable unauthorized access to the system root.
943 944 */
944 945 if ((fstat(fd, &sb) < 0) || (!S_ISFIFO(sb.st_mode))) {
945 946 dprintf("%s[%d]: %s isn't a named pipe\n",
946 947 __FILE__, __LINE__, namebuf);
947 948
948 949 (void) close(fd);
949 950 continue;
950 951 }
951 952 notify_character = notify_characters[action];
952 953 if (write(fd, ¬ify_character, 1) < 0) {
953 954 dprintf("%s[%d]: write failed for %s; %m\n",
954 955 __FILE__, __LINE__, namebuf);
955 956 (void) close(fd);
956 957 continue;
957 958 }
958 959 (void) close(fd);
959 960 }
960 961 (void) closedir(dirp);
961 962 (void) signal(SIGPIPE, old_signal_handler);
962 963 popdir(current_working_dir_fd);
963 964 }
964 965 dprintf("%s[%d]: leaving notify_clients(), result = %s\n",
965 966 __FILE__, __LINE__, result_strings[result]);
966 967 return (result);
967 968 }
968 969
969 970 static void
970 971 popdir(int fd)
971 972 {
972 973 /*
973 974 * Change the current working directory to the directory
974 975 * specified by fd and close the fd. Exit the program
975 976 * on failure.
976 977 */
977 978 if (fchdir(fd) < 0) {
978 979 dprintf("%s[%d]: popdir() failed\n", __FILE__, __LINE__);
979 980 exit(1);
980 981 }
981 982 (void) close(fd);
982 983 }
983 984
984 985 static int
985 986 pushdir(const char *dir)
986 987 {
987 988 /*
988 989 * Change the current working directory to dir and
989 990 * return a file descriptor for the old working
990 991 * directory.
991 992 *
992 993 * Exception handling:
993 994 *
994 995 * If dir doesn't exist, leave the current working
995 996 * directory the same and return -1.
996 997 *
997 998 * If dir isn't a directory, remove it, leave the
998 999 * current working directory the same, and return -1.
999 1000 *
1000 1001 * If open() fails on the current working directory
1001 1002 * or the chdir operation fails on dir, leave the
1002 1003 * current working directory the same and return -1.
1003 1004 */
1004 1005
1005 1006 int current_working_dir_fd;
1006 1007 struct stat stat_buf;
1007 1008
1008 1009 if (lstat(dir, &stat_buf) < 0) {
1009 1010 dprintf("%s[%d]: push_dir_and_check(): %s does not exist\n",
1010 1011 __FILE__, __LINE__, dir);
1011 1012 return (-1);
1012 1013 }
1013 1014
1014 1015 if (!(S_ISDIR(stat_buf.st_mode))) {
1015 1016 dprintf("%s[%d]: push_dir_and_check(): %s not a directory.\n",
1016 1017 __FILE__, __LINE__, dir);
1017 1018 (void) remove(dir);
1018 1019 return (-1);
1019 1020 }
1020 1021 if ((current_working_dir_fd = open(".", O_RDONLY)) < 0) {
1021 1022 dprintf("%s[%d]: push_dir_and_check(): can't open %s.\n",
1022 1023 __FILE__, __LINE__, dir);
1023 1024 return (-1);
1024 1025 }
1025 1026 if (chdir(dir) < 0) {
1026 1027 (void) close(current_working_dir_fd);
1027 1028 dprintf("%s[%d]: push_dir_and_check(): can't chdir() to %s.\n",
1028 1029 __FILE__, __LINE__, dir);
1029 1030 return (-1);
1030 1031 }
1031 1032 return (current_working_dir_fd);
1032 1033 }
1033 1034
1034 1035 static boolean_t
1035 1036 remove_notify_files(struct action_arg **aa)
1036 1037 {
1037 1038 int ai;
1038 1039 int current_working_dir_fd;
1039 1040 char notify_file[64];
1040 1041 int result;
1041 1042 char *symdev;
1042 1043
1043 1044 dprintf("%s[%d]: entering remove_notify_files()\n", __FILE__, __LINE__);
1044 1045
1045 1046 ai = 0;
1046 1047 result = TRUE;
1047 1048 symdev = aa[ai]->aa_symdev;
1048 1049 while ((result == TRUE) &&
1049 1050 (aa[ai] != NULL) &&
1050 1051 (aa[ai]->aa_path != NULL)) {
1051 1052
1052 1053 if (not_mountable(aa[ai])) {
1053 1054 sprintf(notify_file, "%s-0", symdev);
1054 1055 } else if (aa[ai]->aa_partname != NULL) {
1055 1056 /*
1056 1057 * Is aa_partname ever NULL?
1057 1058 * When time permits, check.
1058 1059 * If it is, the action taken
1059 1060 * in the else clause could produce
1060 1061 * file name conflicts.
1061 1062 */
1062 1063 sprintf(notify_file, "%s-%s",
1063 1064 symdev, aa[0]->aa_partname);
1064 1065 } else {
1065 1066 sprintf(notify_file, "%s-0", symdev);
1066 1067 }
1067 1068
1068 1069 current_working_dir_fd = pushdir(NOTIFY_DIR);
1069 1070 if (current_working_dir_fd < 0) {
1070 1071 result = FALSE;
1071 1072 }
1072 1073 if ((result == TRUE) && (remove(notify_file) < 0)) {
1073 1074 dprintf("%s[%d]: remove %s/%s; %m\n",
1074 1075 __FILE__, __LINE__, NOTIFY_DIR, notify_file);
1075 1076 result = FALSE;
1076 1077 }
1077 1078 if (current_working_dir_fd != -1) {
1078 1079 popdir(current_working_dir_fd);
1079 1080 }
1080 1081 ai++;
1081 1082 }
1082 1083 dprintf("%s[%d]: leaving remove_notify_files(), result = %s\n",
1083 1084 __FILE__, __LINE__, result_strings[result]);
1084 1085
1085 1086 return (result);
1086 1087 }
↓ open down ↓ |
943 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX