~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools-precise.sid-merge1

« back to all changes in this revision

Viewing changes to lib/dnd/dndLinux.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********************************************************
2
 
 * Copyright (C) 2005 VMware, Inc. All rights reserved.
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or modify it
5
 
 * under the terms of the GNU Lesser General Public License as published
6
 
 * by the Free Software Foundation version 2.1 and no later version.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful, but
9
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
11
 
 * License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this program; if not, write to the Free Software Foundation, Inc.,
15
 
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
16
 
 *
17
 
 *********************************************************/
18
 
 
19
 
/*
20
 
 * dndLinux.c --
21
 
 *
22
 
 *     Some common dnd functions for UNIX guests and hosts.
23
 
 */
24
 
 
25
 
 
26
 
#include <stdlib.h>
27
 
#include <time.h>
28
 
#include <errno.h>
29
 
#include <fcntl.h>
30
 
#include <sys/stat.h>
31
 
 
32
 
#include "vmware.h"
33
 
#include "dndInt.h"
34
 
#include "dnd.h"
35
 
#include "posix.h"
36
 
#include "file.h"
37
 
#include "strutil.h"
38
 
#include "vm_assert.h"
39
 
#include "util.h"
40
 
#include "escape.h"
41
 
#include "su.h"
42
 
#if defined(linux) || defined(sun) || defined(__FreeBSD__)
43
 
#include "vmblock_user.h"
44
 
#include "mntinfo.h"
45
 
#endif
46
 
 
47
 
#define LOGLEVEL_MODULE dnd
48
 
#include "loglevel_user.h"
49
 
#include "unicodeOperations.h"
50
 
 
51
 
 
52
 
#define DND_ROOTDIR_PERMS     (S_IRWXU | S_IRWXG | S_IRWXO)
53
 
#define DND_STAGINGDIR_PERMS  (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
54
 
#ifdef sun
55
 
#define ACCESSPERMS           (S_IRWXU | S_IRWXG | S_IRWXO)
56
 
#endif
57
 
 
58
 
 
59
 
/*
60
 
 *-----------------------------------------------------------------------------
61
 
 *
62
 
 * DnD_GetFileRoot --
63
 
 *
64
 
 *       Gets the root path of the staging directory for DnD file transfers.
65
 
 *
66
 
 * Results:
67
 
 *       The path to the staging directory.
68
 
 *
69
 
 * Side effects:
70
 
 *       None
71
 
 *
72
 
 *-----------------------------------------------------------------------------
73
 
 */
74
 
 
75
 
ConstUnicode
76
 
DnD_GetFileRoot(void)
77
 
{
78
 
   return "/tmp/VMwareDnD/";
79
 
}
80
 
 
81
 
 
82
 
/*
83
 
 *-----------------------------------------------------------------------------
84
 
 *
85
 
 * DnD_PrependFileRoot --
86
 
 *
87
 
 *    Given a buffer of '\0' delimited filenames, this prepends the file root
88
 
 *    to each one and uses '\0' delimiting for the output buffer.  The buffer
89
 
 *    pointed to by *src will be freed and *src will point to a new buffer
90
 
 *    containing the results.  *srcSize is set to the size of the new buffer,
91
 
 *    not including the NUL-terminator.
92
 
 *
93
 
 * Results:
94
 
 *    TRUE on success, FALSE on failure.
95
 
 *
96
 
 * Side effects:
97
 
 *    *src will be freed, and a new buffer will be allocated. This buffer must
98
 
 *    be freed by the caller.
99
 
 *
100
 
 *-----------------------------------------------------------------------------
101
 
 */
102
 
 
103
 
Bool
104
 
DnD_PrependFileRoot(const char *fileRoot,  // IN    : file root to append
105
 
                    char **src,            // IN/OUT: NUL-delimited list of paths
106
 
                    size_t *srcSize)       // IN/OUT: size of list
107
 
{
108
 
   ASSERT(fileRoot);
109
 
   ASSERT(src);
110
 
   ASSERT(*src);
111
 
   ASSERT(srcSize);
112
 
 
113
 
   return DnDPrependFileRoot(fileRoot, '\0', src, srcSize);
114
 
}
115
 
 
116
 
 
117
 
/*
118
 
 *----------------------------------------------------------------------------
119
 
 *
120
 
 * DnDUriListGetFile --
121
 
 *
122
 
 *    Retrieves the filename and length from the file scheme (file://) entry at
123
 
 *    the specified index in a text/uri-list string.
124
 
 *
125
 
 * Results:
126
 
 *    The address of the beginning of the next filename on success, NULL if
127
 
 *    there are no more entries or on error.  index is updated with the
128
 
 *    location of the next entry in the list, and length is updated with the
129
 
 *    size of the filename starting at the returned value.
130
 
 *
131
 
 * Side effects:
132
 
 *    None.
133
 
 *
134
 
 *----------------------------------------------------------------------------
135
 
 */
136
 
 
137
 
static char *
138
 
DnDUriListGetFile(char const *uriList,  // IN    : text/uri-list string
139
 
                  size_t *index,        // IN/OUT: current index
140
 
                  size_t *length)       // OUT   : length of returned string
141
 
{
142
 
   char const *nameStart;
143
 
   char const *nameEnd;
144
 
   char const *curr;
145
 
 
146
 
   ASSERT(uriList);
147
 
   ASSERT(index);
148
 
   ASSERT(length);
149
 
 
150
 
   /* The common case on the last entry */
151
 
   if (uriList[*index] == '\0') {
152
 
      return NULL;
153
 
   }
154
 
 
155
 
   /*
156
 
    * Ensure the URI list is formatted properly.  This is ugly, but we have to
157
 
    * special case for KDE (which doesn't follow the standard).
158
 
    *
159
 
    * XXX Note that this assumes we only support dropping files, based on the
160
 
    * definition of the macro that is used.
161
 
    */
162
 
 
163
 
   nameStart = &uriList[*index];
164
 
 
165
 
   if (strncmp(nameStart,
166
 
               DND_URI_LIST_PRE,
167
 
               sizeof DND_URI_LIST_PRE - 1) == 0) {
168
 
      nameStart += sizeof DND_URI_LIST_PRE - 1;
169
 
   } else if (strncmp(nameStart,
170
 
                      DND_URI_LIST_PRE_KDE,
171
 
                      sizeof DND_URI_LIST_PRE_KDE - 1) == 0) {
172
 
      nameStart += sizeof DND_URI_LIST_PRE_KDE - 1;
173
 
   } else {
174
 
      Warning("%s: the URI list did not begin with %s or %s\n", __func__,
175
 
              DND_URI_LIST_PRE, DND_URI_LIST_PRE_KDE);
176
 
 
177
 
      return NULL;
178
 
    }
179
 
 
180
 
   nameEnd = NULL;
181
 
 
182
 
   /* Walk the filename looking for the end */
183
 
   curr = nameStart;
184
 
   while (*curr != '\0' && *curr != '\r' && *curr != '\n') {
185
 
      curr++;
186
 
   }
187
 
 
188
 
   nameEnd = curr - 1;
189
 
 
190
 
   /* Bump curr based on trailing newline characters found */
191
 
   while (*curr == '\r' || *curr == '\n') {
192
 
      curr++;
193
 
   }
194
 
 
195
 
   *index = curr - uriList;
196
 
   *length = nameEnd - nameStart + 1;
197
 
 
198
 
   return (char *)nameStart;
199
 
}
200
 
 
201
 
 
202
 
/*
203
 
 *----------------------------------------------------------------------------
204
 
 *
205
 
 * DnD_UriListGetNextFile --
206
 
 *
207
 
 *    Retrieves and unescapes the next file from the provided test/uri-list
208
 
 *    mime type string.  The index provided is used to iteratively retrieve
209
 
 *    successive files from the list.
210
 
 *
211
 
 * Results:
212
 
 *    An allocated, unescaped, NUL-terminated string containing the filename
213
 
 *    within the uri-list after the specified index.  index is updated to point
214
 
 *    to the next entry of the uri-list, and length (if provided) is set to the
215
 
 *    length of the allocated string (not including the NUL terminator).
216
 
 *    NULL if there are no more entries in the list, or on error.
217
 
 *
218
 
 * Side effects:
219
 
 *    None.
220
 
 *
221
 
 *----------------------------------------------------------------------------
222
 
 */
223
 
 
224
 
char *
225
 
DnD_UriListGetNextFile(char const *uriList,  // IN    : text/uri-list string
226
 
                       size_t *index,        // IN/OUT: current index
227
 
                       size_t *length)       // OUT   : length of returned string
228
 
{
229
 
   char const *file;
230
 
   size_t nextIndex;
231
 
   size_t fileLength = 0;
232
 
   char *unescapedName;
233
 
   size_t unescapedLength;
234
 
 
235
 
   ASSERT(uriList);
236
 
   ASSERT(index);
237
 
 
238
 
   nextIndex = *index;
239
 
 
240
 
   /* Get pointer to and length of next filename */
241
 
   file = DnDUriListGetFile(uriList, &nextIndex, &fileLength);
242
 
   if (!file) {
243
 
      return NULL;
244
 
   }
245
 
 
246
 
   /*
247
 
    * Retrieve an allocated, unescaped name.  This undoes the ' ' -> "%20"
248
 
    * escaping as required by RFC 1630 for entries in a uri-list.
249
 
    */
250
 
 
251
 
   unescapedName = Escape_Undo('%', file, fileLength, &unescapedLength);
252
 
   if (!unescapedName) {
253
 
      Warning("%s: error unescaping filename\n", __func__);
254
 
 
255
 
      return NULL;
256
 
   }
257
 
 
258
 
   *index = nextIndex;
259
 
   if (length) {
260
 
      *length = unescapedLength;
261
 
   }
262
 
 
263
 
   return unescapedName;
264
 
}
265
 
 
266
 
 
267
 
/* We need to make this suck less. */
268
 
#if defined(linux) || defined(sun) || defined(__FreeBSD__)
269
 
 
270
 
/*
271
 
 *----------------------------------------------------------------------------
272
 
 *
273
 
 * DnD_AddBlockLegacy --
274
 
 *
275
 
 *    Adds a block to blockPath.
276
 
 *
277
 
 * Results:
278
 
 *    TRUE on success, FALSE on failure.
279
 
 *
280
 
 * Side effects:
281
 
 *    Processes trying to access this path will block until DnD_RemoveBlock
282
 
 *    is called.
283
 
 *
284
 
 *----------------------------------------------------------------------------
285
 
 */
286
 
 
287
 
Bool
288
 
DnD_AddBlockLegacy(int blockFd,                    // IN
289
 
                   const char *blockPath)          // IN
290
 
{
291
 
   ASSERT(blockFd >= 0);
292
 
 
293
 
   if (VMBLOCK_CONTROL(blockFd, VMBLOCK_ADD_FILEBLOCK, blockPath) != 0) {
294
 
      LOG(1, ("%s: Cannot add block on %s (%s)\n",
295
 
              __func__, blockPath, strerror(errno)));
296
 
 
297
 
      return FALSE;
298
 
   }
299
 
 
300
 
   return TRUE;
301
 
}
302
 
 
303
 
 
304
 
/*
305
 
 *----------------------------------------------------------------------------
306
 
 *
307
 
 * DnD_RemoveBlockLegacy --
308
 
 *
309
 
 *    Removes block on blockedPath.
310
 
 *
311
 
 * Results:
312
 
 *    TRUE on success, FALSE on failure.
313
 
 *
314
 
 * Side effects:
315
 
 *    Processes blocked on accessing this path will continue.
316
 
 *
317
 
 *----------------------------------------------------------------------------
318
 
 */
319
 
 
320
 
Bool
321
 
DnD_RemoveBlockLegacy(int blockFd,                    // IN
322
 
                      const char *blockedPath)        // IN
323
 
{
324
 
   if (blockFd >= 0) {
325
 
      if (VMBLOCK_CONTROL(blockFd, VMBLOCK_DEL_FILEBLOCK, blockedPath) != 0) {
326
 
         Log("%s: Cannot delete block on %s (%s)\n",
327
 
             __func__, blockedPath, strerror(errno));
328
 
 
329
 
         return FALSE;
330
 
      }
331
 
   } else {
332
 
      LOG(4, ("%s: Could not remove block on %s: "
333
 
              "fd to vmblock no longer exists.\n", __func__, blockedPath));
334
 
   }
335
 
 
336
 
   return TRUE;
337
 
}
338
 
 
339
 
 
340
 
/*
341
 
 *----------------------------------------------------------------------------
342
 
 *
343
 
 * DnD_CheckBlockLegacy --
344
 
 *
345
 
 *    Verifies that given file descriptor is truly a control file of
346
 
 *    kernel-based vmblock implementation. Just a stub, for now at
347
 
 *    least since we don't have a good way to check.
348
 
 *
349
 
 * Results:
350
 
 *    TRUE on success, FALSE on failure.
351
 
 *
352
 
 * Side effects:
353
 
 *    None.
354
 
 *
355
 
 *----------------------------------------------------------------------------
356
 
 */
357
 
 
358
 
static Bool
359
 
DnD_CheckBlockLegacy(int blockFd)                    // IN
360
 
{
361
 
   return TRUE;
362
 
}
363
 
 
364
 
 
365
 
/*
366
 
 *----------------------------------------------------------------------------
367
 
 *
368
 
 * DnD_AddBlockFuse --
369
 
 *
370
 
 *    Adds a block to blockPath.
371
 
 *
372
 
 * Results:
373
 
 *    TRUE on success, FALSE on failure.
374
 
 *
375
 
 * Side effects:
376
 
 *    Processes trying to access this path will block until DnD_RemoveBlock
377
 
 *    is called.
378
 
 *
379
 
 *----------------------------------------------------------------------------
380
 
 */
381
 
 
382
 
Bool
383
 
DnD_AddBlockFuse(int blockFd,                    // IN
384
 
                 const char *blockPath)          // IN
385
 
{
386
 
   ASSERT(blockFd >= 0);
387
 
 
388
 
   if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
389
 
                            blockPath) != 0) {
390
 
      LOG(1, ("%s: Cannot add block on %s (%s)\n",
391
 
              __func__, blockPath, strerror(errno)));
392
 
 
393
 
      return FALSE;
394
 
   }
395
 
 
396
 
   return TRUE;
397
 
}
398
 
 
399
 
 
400
 
/*
401
 
 *----------------------------------------------------------------------------
402
 
 *
403
 
 * DnD_RemoveBlockFuse --
404
 
 *
405
 
 *    Removes block on blockedPath.
406
 
 *
407
 
 * Results:
408
 
 *    TRUE on success, FALSE on failure.
409
 
 *
410
 
 * Side effects:
411
 
 *    Processes blocked on accessing this path will continue.
412
 
 *
413
 
 *----------------------------------------------------------------------------
414
 
 */
415
 
 
416
 
Bool
417
 
DnD_RemoveBlockFuse(int blockFd,                    // IN
418
 
                    const char *blockedPath)        // IN
419
 
{
420
 
   if (blockFd >= 0) {
421
 
      if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
422
 
                               blockedPath) != 0) {
423
 
         Log("%s: Cannot delete block on %s (%s)\n",
424
 
             __func__, blockedPath, strerror(errno));
425
 
 
426
 
         return FALSE;
427
 
      }
428
 
   } else {
429
 
      LOG(4, ("%s: Could not remove block on %s: "
430
 
              "fd to vmblock no longer exists.\n", __func__, blockedPath));
431
 
   }
432
 
 
433
 
   return TRUE;
434
 
}
435
 
 
436
 
 
437
 
/*
438
 
 *----------------------------------------------------------------------------
439
 
 *
440
 
 * DnD_CheckBlockFuse --
441
 
 *
442
 
 *    Verifies that given file descriptor is truly a control file of
443
 
 *    FUSE-based vmblock implementation.
444
 
 *
445
 
 * Results:
446
 
 *    TRUE on success, FALSE on failure.
447
 
 *
448
 
 * Side effects:
449
 
 *    None.
450
 
 *
451
 
 *----------------------------------------------------------------------------
452
 
 */
453
 
 
454
 
static Bool
455
 
DnD_CheckBlockFuse(int blockFd)                    // IN
456
 
{
457
 
   char buf[sizeof(VMBLOCK_FUSE_READ_RESPONSE)];
458
 
   size_t size;
459
 
 
460
 
   size = read(blockFd, buf, sizeof(VMBLOCK_FUSE_READ_RESPONSE));
461
 
   if (size < 0) {
462
 
      LOG(4, ("%s: read failed, error %s.\n",
463
 
              __func__, strerror(errno)));
464
 
 
465
 
      return FALSE;
466
 
   }
467
 
 
468
 
   if (size != sizeof(VMBLOCK_FUSE_READ_RESPONSE)) {
469
 
      LOG(4, ("%s: Response too short (%"FMTSZ"d vs. %"FMTSZ"u).\n",
470
 
              __func__, size, sizeof(VMBLOCK_FUSE_READ_RESPONSE)));
471
 
 
472
 
      return FALSE;
473
 
   }
474
 
 
475
 
   if (memcmp(buf, VMBLOCK_FUSE_READ_RESPONSE,
476
 
              sizeof(VMBLOCK_FUSE_READ_RESPONSE))) {
477
 
      LOG(4, ("%s: Invalid response %.*s",
478
 
              __func__, (int)sizeof(VMBLOCK_FUSE_READ_RESPONSE) - 1, buf));
479
 
 
480
 
      return FALSE;
481
 
   }
482
 
 
483
 
   return TRUE;
484
 
}
485
 
 
486
 
 
487
 
/*
488
 
 *----------------------------------------------------------------------------
489
 
 *
490
 
 * DnD_TryInitVmblock --
491
 
 *
492
 
 *    Initializes file blocking needed to prevent access to file before
493
 
 *    transfer has finished.
494
 
 *
495
 
 * Results:
496
 
 *    Block descriptor on success, -1 on failure.
497
 
 *
498
 
 * Side effects:
499
 
 *    None.
500
 
 *
501
 
 *----------------------------------------------------------------------------
502
 
 */
503
 
 
504
 
static int
505
 
DnD_TryInitVmblock(const char *vmbFsName,          // IN
506
 
                   const char *vmbMntPoint,        // IN
507
 
                   const char *vmbDevice,          // IN
508
 
                   mode_t vmbDeviceMode,           // IN
509
 
                   Bool (*verifyBlock)(int fd))    // IN
510
 
{
511
 
   Bool found = FALSE;
512
 
   int blockFd = -1;
513
 
   MNTHANDLE fp;
514
 
   DECLARE_MNTINFO(mnt);
515
 
 
516
 
   /* Make sure the vmblock file system is mounted. */
517
 
   fp = OPEN_MNTFILE("r");
518
 
   if (fp == NULL) {
519
 
      LOG(1, ("%s: could not open mount file\n", __func__));
520
 
 
521
 
      return -1;
522
 
   }
523
 
 
524
 
   while (GETNEXT_MNTINFO(fp, mnt)) {
525
 
      /*
526
 
       * In the future we can publish the mount point in VMDB so that the UI
527
 
       * can use it rather than enforcing the VMBLOCK_MOUNT_POINT check here.
528
 
       */
529
 
 
530
 
      if (strcmp(MNTINFO_FSTYPE(mnt), vmbFsName) == 0 &&
531
 
          strcmp(MNTINFO_MNTPT(mnt), vmbMntPoint) == 0) {
532
 
         found = TRUE;
533
 
         break;
534
 
      }
535
 
   }
536
 
 
537
 
   (void) CLOSE_MNTFILE(fp);
538
 
 
539
 
   if (found) {
540
 
      /* Open device node for communication with vmblock. */
541
 
      blockFd = Posix_Open(vmbDevice, vmbDeviceMode);
542
 
      if (blockFd < 0) {
543
 
         LOG(1, ("%s: Can not open blocker device (%s)\n",
544
 
                 __func__, strerror(errno)));
545
 
      } else {
546
 
         LOG(4, ("%s: Opened blocker device at %s\n",
547
 
                 __func__, VMBLOCK_DEVICE));
548
 
         if (verifyBlock && !verifyBlock(blockFd)) {
549
 
            LOG(4, ("%s: Blocker device at %s did not pass checks, closing.\n",
550
 
                    __func__, VMBLOCK_DEVICE));
551
 
            close(blockFd);
552
 
            blockFd = -1;
553
 
         }
554
 
      }
555
 
   }
556
 
 
557
 
   return blockFd;
558
 
}
559
 
 
560
 
 
561
 
/*
562
 
 *----------------------------------------------------------------------------
563
 
 *
564
 
 * DnD_InitializeBlocking --
565
 
 *
566
 
 *    Initializes file blocking needed to prevent access to file before
567
 
 *    transfer has finished.
568
 
 *
569
 
 * Results:
570
 
 *    TRUE on success, FALSE on failure.
571
 
 *
572
 
 * Side effects:
573
 
 *    None.
574
 
 *
575
 
 *----------------------------------------------------------------------------
576
 
 */
577
 
 
578
 
Bool
579
 
DnD_InitializeBlocking(DnDBlockControl *blkCtrl)   // OUT
580
 
{
581
 
   uid_t uid;
582
 
   int blockFd;
583
 
 
584
 
   /* Root access is needed for opening the vmblock device. */
585
 
   uid = Id_BeginSuperUser();
586
 
 
587
 
   /* Fitrst try FUSE and see if it is available. */
588
 
   blockFd = DnD_TryInitVmblock(VMBLOCK_FUSE_FS_NAME, VMBLOCK_FUSE_MOUNT_POINT,
589
 
                                VMBLOCK_FUSE_DEVICE, VMBLOCK_FUSE_DEVICE_MODE,
590
 
                                DnD_CheckBlockFuse);
591
 
   if (blockFd != -1) {
592
 
      blkCtrl->fd = blockFd;
593
 
      /* Setup FUSE methods. */
594
 
      blkCtrl->blockRoot = VMBLOCK_FUSE_FS_ROOT;
595
 
      blkCtrl->AddBlock = DnD_AddBlockFuse;
596
 
      blkCtrl->RemoveBlock = DnD_RemoveBlockFuse;
597
 
      goto out;
598
 
   }
599
 
 
600
 
   /* Now try OS-specific VMBlock driver. */
601
 
   blockFd = DnD_TryInitVmblock(VMBLOCK_FS_NAME, VMBLOCK_MOUNT_POINT,
602
 
                                VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE,
603
 
                                NULL);
604
 
   if (blockFd != -1) {
605
 
      blkCtrl->fd = blockFd;
606
 
      /* Setup legacy in-kernel methods. */
607
 
      blkCtrl->blockRoot = VMBLOCK_FS_ROOT;
608
 
      blkCtrl->AddBlock = DnD_AddBlockLegacy;
609
 
      blkCtrl->RemoveBlock = DnD_RemoveBlockLegacy;
610
 
      goto out;
611
 
   }
612
 
 
613
 
   LOG(4, ("%s: could not find vmblock mounted\n", __func__));
614
 
out:
615
 
   Id_EndSuperUser(uid);
616
 
 
617
 
   return blockFd != -1;
618
 
}
619
 
 
620
 
 
621
 
/*
622
 
 *----------------------------------------------------------------------------
623
 
 *
624
 
 * DnD_UninitializeBlocking --
625
 
 *
626
 
 *    Uninitialize file blocking.
627
 
 *
628
 
 * Results:
629
 
 *    TRUE on success, FALSE on failure.
630
 
 *
631
 
 * Side effects:
632
 
 *    All existing blocks will be removed.
633
 
 *
634
 
 *----------------------------------------------------------------------------
635
 
 */
636
 
 
637
 
Bool
638
 
DnD_UninitializeBlocking(DnDBlockControl *blkCtrl)    // IN
639
 
{
640
 
   Bool ret = TRUE;
641
 
 
642
 
   if (blkCtrl->fd >= 0) {
643
 
      if (close(blkCtrl->fd) < 0) {
644
 
         Log("%s: Can not close blocker device (%s)\n",
645
 
             __func__, strerror(errno));
646
 
         ret = FALSE;
647
 
      } else {
648
 
         blkCtrl->fd = -1;
649
 
      }
650
 
   }
651
 
 
652
 
   return ret;
653
 
}
654
 
 
655
 
/*
656
 
 * DnD_CompleteBlockInitialization --
657
 
 *
658
 
 *    Complete block initialization in case when we were handed
659
 
 *    blocking file descriptor (presumably opened for us by a
660
 
 *    suid application).
661
 
 *
662
 
 * Results:
663
 
 *    TRUE on success, FALSE on failure (invalid type).
664
 
 *
665
 
 * Side effects:
666
 
 *    Adjusts blkCtrl to match blocking device type (legacy or fuse).
667
 
 *
668
 
 */
669
 
 
670
 
Bool
671
 
DnD_CompleteBlockInitialization(int fd,                     // IN
672
 
                                DnDBlockControl *blkCtrl)   // OUT
673
 
{
674
 
   blkCtrl->fd = fd;
675
 
 
676
 
   if (DnD_CheckBlockFuse(fd)) {
677
 
      /* Setup FUSE methods. */
678
 
      blkCtrl->blockRoot = VMBLOCK_FUSE_FS_ROOT;
679
 
      blkCtrl->AddBlock = DnD_AddBlockFuse;
680
 
      blkCtrl->RemoveBlock = DnD_RemoveBlockFuse;
681
 
   } else if (DnD_CheckBlockLegacy(fd)) {
682
 
      /* Setup legacy methods. */
683
 
      blkCtrl->blockRoot = VMBLOCK_FS_ROOT;
684
 
      blkCtrl->AddBlock = DnD_AddBlockLegacy;
685
 
      blkCtrl->RemoveBlock = DnD_RemoveBlockLegacy;
686
 
   } else {
687
 
      Log("%s: Can't determine block type.\n", __func__);
688
 
 
689
 
      return FALSE;
690
 
   }
691
 
 
692
 
   return TRUE;
693
 
}
694
 
 
695
 
#endif /* linux || sun || FreeBSD */
696
 
 
697
 
 
698
 
/*
699
 
 *----------------------------------------------------------------------------
700
 
 *
701
 
 * DnDRootDirUsable --
702
 
 *
703
 
 *    Determines whether the provided directory is usable as the root for
704
 
 *    staging directories.
705
 
 *
706
 
 * Results:
707
 
 *    TRUE if the root directory is usable, FALSE otherwise.
708
 
 *
709
 
 * Side effects:
710
 
 *    None.
711
 
 *
712
 
 *----------------------------------------------------------------------------
713
 
 */
714
 
 
715
 
Bool
716
 
DnDRootDirUsable(ConstUnicode pathName)  // IN:
717
 
{
718
 
   struct stat buf;
719
 
 
720
 
   if (Posix_Stat(pathName, &buf) < 0) {
721
 
      return FALSE;
722
 
   }
723
 
 
724
 
   return S_ISDIR(buf.st_mode) &&
725
 
          (buf.st_mode & S_ISVTX) == S_ISVTX &&
726
 
          (buf.st_mode & ACCESSPERMS) == DND_ROOTDIR_PERMS;
727
 
}
728
 
 
729
 
 
730
 
/*
731
 
 *----------------------------------------------------------------------------
732
 
 *
733
 
 * DnDSetPermissionsOnRootDir --
734
 
 *
735
 
 *    Sets the correct permissions for the root staging directory.  We set the
736
 
 *    root directory to 1777 so that all users can create their own staging
737
 
 *    directories within it and that other users cannot delete that directory.
738
 
 *
739
 
 * Results:
740
 
 *    TRUE on success, FALSE on failure.
741
 
 *
742
 
 * Side effects:
743
 
 *    None.
744
 
 *
745
 
 *----------------------------------------------------------------------------
746
 
 */
747
 
 
748
 
Bool
749
 
DnDSetPermissionsOnRootDir(ConstUnicode pathName)  // IN:
750
 
{
751
 
   return Posix_Chmod(pathName, S_ISVTX | DND_ROOTDIR_PERMS) == 0;
752
 
}
753
 
 
754
 
 
755
 
/*
756
 
 *----------------------------------------------------------------------------
757
 
 *
758
 
 * DnDStagingDirectoryUsable --
759
 
 *
760
 
 *    Determines whether a staging directory is usable for the current
761
 
 *    process.  A directory is only usable by the current process if it is
762
 
 *    owned by the effective uid of the current process.
763
 
 *
764
 
 * Results:
765
 
 *    TRUE if the directory is usable, FALSE if it is not.
766
 
 *
767
 
 * Side effects:
768
 
 *    None.
769
 
 *
770
 
 *----------------------------------------------------------------------------
771
 
 */
772
 
 
773
 
Bool
774
 
DnDStagingDirectoryUsable(ConstUnicode pathName)  // IN:
775
 
{
776
 
   struct stat buf;
777
 
 
778
 
   if (Posix_Stat(pathName, &buf) < 0) {
779
 
      return FALSE;
780
 
   }
781
 
 
782
 
   return buf.st_uid == Id_GetEUid();
783
 
}
784
 
 
785
 
 
786
 
/*
787
 
 *----------------------------------------------------------------------------
788
 
 *
789
 
 * DnDSetPermissionsOnStagingDir --
790
 
 *
791
 
 *    Sets the correct permissions for staging directories.
792
 
 *
793
 
 * Results:
794
 
 *    TRUE on success, FALSE on failure.
795
 
 *
796
 
 * Side effects:
797
 
 *    None.
798
 
 *
799
 
 *----------------------------------------------------------------------------
800
 
 */
801
 
 
802
 
Bool
803
 
DnDSetPermissionsOnStagingDir(ConstUnicode pathName)  // IN:
804
 
{
805
 
   return Posix_Chmod(pathName, DND_STAGINGDIR_PERMS) == 0;
806
 
}