~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to services/plugins/dndcp/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
#if defined(linux)
 
174
   } else if (DnD_UriIsNonFileSchemes(nameStart)) {
 
175
      /* Do nothing. */
 
176
#endif
 
177
   } else {
 
178
      Warning("%s: the URI list did not begin with %s or %s\n", __func__,
 
179
              DND_URI_LIST_PRE, DND_URI_LIST_PRE_KDE);
 
180
 
 
181
      return NULL;
 
182
    }
 
183
 
 
184
   nameEnd = NULL;
 
185
 
 
186
   /* Walk the filename looking for the end */
 
187
   curr = nameStart;
 
188
   while (*curr != '\0' && *curr != '\r' && *curr != '\n') {
 
189
      curr++;
 
190
   }
 
191
 
 
192
   nameEnd = curr - 1;
 
193
 
 
194
   /* Bump curr based on trailing newline characters found */
 
195
   while (*curr == '\r' || *curr == '\n') {
 
196
      curr++;
 
197
   }
 
198
 
 
199
   *index = curr - uriList;
 
200
   *length = nameEnd - nameStart + 1;
 
201
 
 
202
   return (char *)nameStart;
 
203
}
 
204
 
 
205
 
 
206
/*
 
207
 *----------------------------------------------------------------------------
 
208
 *
 
209
 * DnD_UriListGetNextFile --
 
210
 *
 
211
 *    Retrieves and unescapes the next file from the provided test/uri-list
 
212
 *    mime type string.  The index provided is used to iteratively retrieve
 
213
 *    successive files from the list.
 
214
 *
 
215
 * Results:
 
216
 *    An allocated, unescaped, NUL-terminated string containing the filename
 
217
 *    within the uri-list after the specified index.  index is updated to point
 
218
 *    to the next entry of the uri-list, and length (if provided) is set to the
 
219
 *    length of the allocated string (not including the NUL terminator).
 
220
 *    NULL if there are no more entries in the list, or on error.
 
221
 *
 
222
 * Side effects:
 
223
 *    None.
 
224
 *
 
225
 *----------------------------------------------------------------------------
 
226
 */
 
227
 
 
228
char *
 
229
DnD_UriListGetNextFile(char const *uriList,  // IN    : text/uri-list string
 
230
                       size_t *index,        // IN/OUT: current index
 
231
                       size_t *length)       // OUT   : length of returned string
 
232
{
 
233
   char const *file;
 
234
   size_t nextIndex;
 
235
   size_t fileLength = 0;
 
236
   char *unescapedName;
 
237
   size_t unescapedLength;
 
238
 
 
239
   ASSERT(uriList);
 
240
   ASSERT(index);
 
241
 
 
242
   nextIndex = *index;
 
243
 
 
244
   /* Get pointer to and length of next filename */
 
245
   file = DnDUriListGetFile(uriList, &nextIndex, &fileLength);
 
246
   if (!file) {
 
247
      return NULL;
 
248
   }
 
249
 
 
250
   /*
 
251
    * Retrieve an allocated, unescaped name.  This undoes the ' ' -> "%20"
 
252
    * escaping as required by RFC 1630 for entries in a uri-list.
 
253
    */
 
254
 
 
255
   unescapedName = Escape_Undo('%', file, fileLength, &unescapedLength);
 
256
   if (!unescapedName) {
 
257
      Warning("%s: error unescaping filename\n", __func__);
 
258
 
 
259
      return NULL;
 
260
   }
 
261
 
 
262
   *index = nextIndex;
 
263
   if (length) {
 
264
      *length = unescapedLength;
 
265
   }
 
266
 
 
267
   return unescapedName;
 
268
}
 
269
 
 
270
 
 
271
/*
 
272
 *----------------------------------------------------------------------------
 
273
 *
 
274
 * DnD_UriIsNonFileSchemes --
 
275
 *
 
276
 *    Check if the uri contains supported non-file scheme.
 
277
 *
 
278
 * Results:
 
279
 *    TRUE if the uri contains supported non-file scheme. FALSE otherwise.
 
280
 *
 
281
 * Side effects:
 
282
 *    None.
 
283
 *
 
284
 *----------------------------------------------------------------------------
 
285
 */
 
286
 
 
287
Bool
 
288
DnD_UriIsNonFileSchemes(const char *uri)
 
289
{
 
290
   const char *schemes[] = DND_URI_NON_FILE_SCHEMES;
 
291
   int i = 0;
 
292
 
 
293
   while (schemes[i] != NULL) {
 
294
      if (strncmp(uri,
 
295
                  schemes[i],
 
296
                  strlen(schemes[i])) == 0) {
 
297
         return TRUE;
 
298
      }
 
299
      i++;
 
300
   }
 
301
   return FALSE;
 
302
}
 
303
 
 
304
 
 
305
/* We need to make this suck less. */
 
306
#if defined(linux) || defined(sun) || defined(__FreeBSD__)
 
307
 
 
308
/*
 
309
 *----------------------------------------------------------------------------
 
310
 *
 
311
 * DnD_AddBlockLegacy --
 
312
 *
 
313
 *    Adds a block to blockPath.
 
314
 *
 
315
 * Results:
 
316
 *    TRUE on success, FALSE on failure.
 
317
 *
 
318
 * Side effects:
 
319
 *    Processes trying to access this path will block until DnD_RemoveBlock
 
320
 *    is called.
 
321
 *
 
322
 *----------------------------------------------------------------------------
 
323
 */
 
324
 
 
325
Bool
 
326
DnD_AddBlockLegacy(int blockFd,                    // IN
 
327
                   const char *blockPath)          // IN
 
328
{
 
329
   ASSERT(blockFd >= 0);
 
330
 
 
331
   if (VMBLOCK_CONTROL(blockFd, VMBLOCK_ADD_FILEBLOCK, blockPath) != 0) {
 
332
      LOG(1, ("%s: Cannot add block on %s (%s)\n",
 
333
              __func__, blockPath, strerror(errno)));
 
334
 
 
335
      return FALSE;
 
336
   }
 
337
 
 
338
   return TRUE;
 
339
}
 
340
 
 
341
 
 
342
/*
 
343
 *----------------------------------------------------------------------------
 
344
 *
 
345
 * DnD_RemoveBlockLegacy --
 
346
 *
 
347
 *    Removes block on blockedPath.
 
348
 *
 
349
 * Results:
 
350
 *    TRUE on success, FALSE on failure.
 
351
 *
 
352
 * Side effects:
 
353
 *    Processes blocked on accessing this path will continue.
 
354
 *
 
355
 *----------------------------------------------------------------------------
 
356
 */
 
357
 
 
358
Bool
 
359
DnD_RemoveBlockLegacy(int blockFd,                    // IN
 
360
                      const char *blockedPath)        // IN
 
361
{
 
362
   if (blockFd >= 0) {
 
363
      if (VMBLOCK_CONTROL(blockFd, VMBLOCK_DEL_FILEBLOCK, blockedPath) != 0) {
 
364
         Log("%s: Cannot delete block on %s (%s)\n",
 
365
             __func__, blockedPath, strerror(errno));
 
366
 
 
367
         return FALSE;
 
368
      }
 
369
   } else {
 
370
      LOG(4, ("%s: Could not remove block on %s: "
 
371
              "fd to vmblock no longer exists.\n", __func__, blockedPath));
 
372
   }
 
373
 
 
374
   return TRUE;
 
375
}
 
376
 
 
377
 
 
378
/*
 
379
 *----------------------------------------------------------------------------
 
380
 *
 
381
 * DnD_CheckBlockLegacy --
 
382
 *
 
383
 *    Verifies that given file descriptor is truly a control file of
 
384
 *    kernel-based vmblock implementation. Just a stub, for now at
 
385
 *    least since we don't have a good way to check.
 
386
 *
 
387
 * Results:
 
388
 *    TRUE on success, FALSE on failure.
 
389
 *
 
390
 * Side effects:
 
391
 *    None.
 
392
 *
 
393
 *----------------------------------------------------------------------------
 
394
 */
 
395
 
 
396
static Bool
 
397
DnD_CheckBlockLegacy(int blockFd)                    // IN
 
398
{
 
399
   return TRUE;
 
400
}
 
401
 
 
402
 
 
403
/*
 
404
 *----------------------------------------------------------------------------
 
405
 *
 
406
 * DnD_AddBlockFuse --
 
407
 *
 
408
 *    Adds a block to blockPath.
 
409
 *
 
410
 * Results:
 
411
 *    TRUE on success, FALSE on failure.
 
412
 *
 
413
 * Side effects:
 
414
 *    Processes trying to access this path will block until DnD_RemoveBlock
 
415
 *    is called.
 
416
 *
 
417
 *----------------------------------------------------------------------------
 
418
 */
 
419
 
 
420
Bool
 
421
DnD_AddBlockFuse(int blockFd,                    // IN
 
422
                 const char *blockPath)          // IN
 
423
{
 
424
   ASSERT(blockFd >= 0);
 
425
 
 
426
   if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
 
427
                            blockPath) != 0) {
 
428
      LOG(1, ("%s: Cannot add block on %s (%s)\n",
 
429
              __func__, blockPath, strerror(errno)));
 
430
 
 
431
      return FALSE;
 
432
   }
 
433
 
 
434
   return TRUE;
 
435
}
 
436
 
 
437
 
 
438
/*
 
439
 *----------------------------------------------------------------------------
 
440
 *
 
441
 * DnD_RemoveBlockFuse --
 
442
 *
 
443
 *    Removes block on blockedPath.
 
444
 *
 
445
 * Results:
 
446
 *    TRUE on success, FALSE on failure.
 
447
 *
 
448
 * Side effects:
 
449
 *    Processes blocked on accessing this path will continue.
 
450
 *
 
451
 *----------------------------------------------------------------------------
 
452
 */
 
453
 
 
454
Bool
 
455
DnD_RemoveBlockFuse(int blockFd,                    // IN
 
456
                    const char *blockedPath)        // IN
 
457
{
 
458
   if (blockFd >= 0) {
 
459
      if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
 
460
                               blockedPath) != 0) {
 
461
         Log("%s: Cannot delete block on %s (%s)\n",
 
462
             __func__, blockedPath, strerror(errno));
 
463
 
 
464
         return FALSE;
 
465
      }
 
466
   } else {
 
467
      LOG(4, ("%s: Could not remove block on %s: "
 
468
              "fd to vmblock no longer exists.\n", __func__, blockedPath));
 
469
   }
 
470
 
 
471
   return TRUE;
 
472
}
 
473
 
 
474
 
 
475
/*
 
476
 *----------------------------------------------------------------------------
 
477
 *
 
478
 * DnD_CheckBlockFuse --
 
479
 *
 
480
 *    Verifies that given file descriptor is truly a control file of
 
481
 *    FUSE-based vmblock implementation.
 
482
 *
 
483
 * Results:
 
484
 *    TRUE on success, FALSE on failure.
 
485
 *
 
486
 * Side effects:
 
487
 *    None.
 
488
 *
 
489
 *----------------------------------------------------------------------------
 
490
 */
 
491
 
 
492
static Bool
 
493
DnD_CheckBlockFuse(int blockFd)                    // IN
 
494
{
 
495
   char buf[sizeof(VMBLOCK_FUSE_READ_RESPONSE)];
 
496
   size_t size;
 
497
 
 
498
   size = read(blockFd, buf, sizeof(VMBLOCK_FUSE_READ_RESPONSE));
 
499
   if (size < 0) {
 
500
      LOG(4, ("%s: read failed, error %s.\n",
 
501
              __func__, strerror(errno)));
 
502
 
 
503
      return FALSE;
 
504
   }
 
505
 
 
506
   if (size != sizeof(VMBLOCK_FUSE_READ_RESPONSE)) {
 
507
      LOG(4, ("%s: Response too short (%"FMTSZ"d vs. %"FMTSZ"u).\n",
 
508
              __func__, size, sizeof(VMBLOCK_FUSE_READ_RESPONSE)));
 
509
 
 
510
      return FALSE;
 
511
   }
 
512
 
 
513
   if (memcmp(buf, VMBLOCK_FUSE_READ_RESPONSE,
 
514
              sizeof(VMBLOCK_FUSE_READ_RESPONSE))) {
 
515
      LOG(4, ("%s: Invalid response %.*s",
 
516
              __func__, (int)sizeof(VMBLOCK_FUSE_READ_RESPONSE) - 1, buf));
 
517
 
 
518
      return FALSE;
 
519
   }
 
520
 
 
521
   return TRUE;
 
522
}
 
523
 
 
524
 
 
525
/*
 
526
 *----------------------------------------------------------------------------
 
527
 *
 
528
 * DnD_TryInitVmblock --
 
529
 *
 
530
 *    Initializes file blocking needed to prevent access to file before
 
531
 *    transfer has finished.
 
532
 *
 
533
 * Results:
 
534
 *    Block descriptor on success, -1 on failure.
 
535
 *
 
536
 * Side effects:
 
537
 *    None.
 
538
 *
 
539
 *----------------------------------------------------------------------------
 
540
 */
 
541
 
 
542
static int
 
543
DnD_TryInitVmblock(const char *vmbFsName,          // IN
 
544
                   const char *vmbMntPoint,        // IN
 
545
                   const char *vmbDevice,          // IN
 
546
                   mode_t vmbDeviceMode,           // IN
 
547
                   Bool (*verifyBlock)(int fd))    // IN
 
548
{
 
549
   Bool found = FALSE;
 
550
   int blockFd = -1;
 
551
   MNTHANDLE fp;
 
552
   DECLARE_MNTINFO(mnt);
 
553
 
 
554
   /* Make sure the vmblock file system is mounted. */
 
555
   fp = OPEN_MNTFILE("r");
 
556
   if (fp == NULL) {
 
557
      LOG(1, ("%s: could not open mount file\n", __func__));
 
558
 
 
559
      return -1;
 
560
   }
 
561
 
 
562
   while (GETNEXT_MNTINFO(fp, mnt)) {
 
563
      /*
 
564
       * In the future we can publish the mount point in VMDB so that the UI
 
565
       * can use it rather than enforcing the VMBLOCK_MOUNT_POINT check here.
 
566
       */
 
567
 
 
568
      if (strcmp(MNTINFO_FSTYPE(mnt), vmbFsName) == 0 &&
 
569
          strcmp(MNTINFO_MNTPT(mnt), vmbMntPoint) == 0) {
 
570
         found = TRUE;
 
571
         break;
 
572
      }
 
573
   }
 
574
 
 
575
   (void) CLOSE_MNTFILE(fp);
 
576
 
 
577
   if (found) {
 
578
      /* Open device node for communication with vmblock. */
 
579
      blockFd = Posix_Open(vmbDevice, vmbDeviceMode);
 
580
      if (blockFd < 0) {
 
581
         LOG(1, ("%s: Can not open blocker device (%s)\n",
 
582
                 __func__, strerror(errno)));
 
583
      } else {
 
584
         LOG(4, ("%s: Opened blocker device at %s\n",
 
585
                 __func__, VMBLOCK_DEVICE));
 
586
         if (verifyBlock && !verifyBlock(blockFd)) {
 
587
            LOG(4, ("%s: Blocker device at %s did not pass checks, closing.\n",
 
588
                    __func__, VMBLOCK_DEVICE));
 
589
            close(blockFd);
 
590
            blockFd = -1;
 
591
         }
 
592
      }
 
593
   }
 
594
 
 
595
   return blockFd;
 
596
}
 
597
 
 
598
 
 
599
/*
 
600
 *----------------------------------------------------------------------------
 
601
 *
 
602
 * DnD_InitializeBlocking --
 
603
 *
 
604
 *    Initializes file blocking needed to prevent access to file before
 
605
 *    transfer has finished.
 
606
 *
 
607
 * Results:
 
608
 *    TRUE on success, FALSE on failure.
 
609
 *
 
610
 * Side effects:
 
611
 *    None.
 
612
 *
 
613
 *----------------------------------------------------------------------------
 
614
 */
 
615
 
 
616
Bool
 
617
DnD_InitializeBlocking(DnDBlockControl *blkCtrl)   // OUT
 
618
{
 
619
   uid_t uid;
 
620
   int blockFd;
 
621
 
 
622
   /* Root access is needed for opening the vmblock device. */
 
623
   uid = Id_BeginSuperUser();
 
624
 
 
625
   /* Fitrst try FUSE and see if it is available. */
 
626
   blockFd = DnD_TryInitVmblock(VMBLOCK_FUSE_FS_NAME, VMBLOCK_FUSE_MOUNT_POINT,
 
627
                                VMBLOCK_FUSE_DEVICE, VMBLOCK_FUSE_DEVICE_MODE,
 
628
                                DnD_CheckBlockFuse);
 
629
   if (blockFd != -1) {
 
630
      blkCtrl->fd = blockFd;
 
631
      /* Setup FUSE methods. */
 
632
      blkCtrl->blockRoot = VMBLOCK_FUSE_FS_ROOT;
 
633
      blkCtrl->AddBlock = DnD_AddBlockFuse;
 
634
      blkCtrl->RemoveBlock = DnD_RemoveBlockFuse;
 
635
      goto out;
 
636
   }
 
637
 
 
638
   /* Now try OS-specific VMBlock driver. */
 
639
   blockFd = DnD_TryInitVmblock(VMBLOCK_FS_NAME, VMBLOCK_MOUNT_POINT,
 
640
                                VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE,
 
641
                                NULL);
 
642
   if (blockFd != -1) {
 
643
      blkCtrl->fd = blockFd;
 
644
      /* Setup legacy in-kernel methods. */
 
645
      blkCtrl->blockRoot = VMBLOCK_FS_ROOT;
 
646
      blkCtrl->AddBlock = DnD_AddBlockLegacy;
 
647
      blkCtrl->RemoveBlock = DnD_RemoveBlockLegacy;
 
648
      goto out;
 
649
   }
 
650
 
 
651
   LOG(4, ("%s: could not find vmblock mounted\n", __func__));
 
652
out:
 
653
   Id_EndSuperUser(uid);
 
654
 
 
655
   return blockFd != -1;
 
656
}
 
657
 
 
658
 
 
659
/*
 
660
 *----------------------------------------------------------------------------
 
661
 *
 
662
 * DnD_UninitializeBlocking --
 
663
 *
 
664
 *    Uninitialize file blocking.
 
665
 *
 
666
 * Results:
 
667
 *    TRUE on success, FALSE on failure.
 
668
 *
 
669
 * Side effects:
 
670
 *    All existing blocks will be removed.
 
671
 *
 
672
 *----------------------------------------------------------------------------
 
673
 */
 
674
 
 
675
Bool
 
676
DnD_UninitializeBlocking(DnDBlockControl *blkCtrl)    // IN
 
677
{
 
678
   Bool ret = TRUE;
 
679
 
 
680
   if (blkCtrl->fd >= 0) {
 
681
      if (close(blkCtrl->fd) < 0) {
 
682
         Log("%s: Can not close blocker device (%s)\n",
 
683
             __func__, strerror(errno));
 
684
         ret = FALSE;
 
685
      } else {
 
686
         blkCtrl->fd = -1;
 
687
      }
 
688
   }
 
689
 
 
690
   return ret;
 
691
}
 
692
 
 
693
/*
 
694
 * DnD_CompleteBlockInitialization --
 
695
 *
 
696
 *    Complete block initialization in case when we were handed
 
697
 *    blocking file descriptor (presumably opened for us by a
 
698
 *    suid application).
 
699
 *
 
700
 * Results:
 
701
 *    TRUE on success, FALSE on failure (invalid type).
 
702
 *
 
703
 * Side effects:
 
704
 *    Adjusts blkCtrl to match blocking device type (legacy or fuse).
 
705
 *
 
706
 */
 
707
 
 
708
Bool
 
709
DnD_CompleteBlockInitialization(int fd,                     // IN
 
710
                                DnDBlockControl *blkCtrl)   // OUT
 
711
{
 
712
   blkCtrl->fd = fd;
 
713
 
 
714
   if (DnD_CheckBlockFuse(fd)) {
 
715
      /* Setup FUSE methods. */
 
716
      blkCtrl->blockRoot = VMBLOCK_FUSE_FS_ROOT;
 
717
      blkCtrl->AddBlock = DnD_AddBlockFuse;
 
718
      blkCtrl->RemoveBlock = DnD_RemoveBlockFuse;
 
719
   } else if (DnD_CheckBlockLegacy(fd)) {
 
720
      /* Setup legacy methods. */
 
721
      blkCtrl->blockRoot = VMBLOCK_FS_ROOT;
 
722
      blkCtrl->AddBlock = DnD_AddBlockLegacy;
 
723
      blkCtrl->RemoveBlock = DnD_RemoveBlockLegacy;
 
724
   } else {
 
725
      Log("%s: Can't determine block type.\n", __func__);
 
726
 
 
727
      return FALSE;
 
728
   }
 
729
 
 
730
   return TRUE;
 
731
}
 
732
 
 
733
#endif /* linux || sun || FreeBSD */
 
734
 
 
735
 
 
736
/*
 
737
 *----------------------------------------------------------------------------
 
738
 *
 
739
 * DnDRootDirUsable --
 
740
 *
 
741
 *    Determines whether the provided directory is usable as the root for
 
742
 *    staging directories.
 
743
 *
 
744
 * Results:
 
745
 *    TRUE if the root directory is usable, FALSE otherwise.
 
746
 *
 
747
 * Side effects:
 
748
 *    None.
 
749
 *
 
750
 *----------------------------------------------------------------------------
 
751
 */
 
752
 
 
753
Bool
 
754
DnDRootDirUsable(ConstUnicode pathName)  // IN:
 
755
{
 
756
   struct stat buf;
 
757
 
 
758
   if (Posix_Stat(pathName, &buf) < 0) {
 
759
      return FALSE;
 
760
   }
 
761
 
 
762
   return S_ISDIR(buf.st_mode) &&
 
763
          (buf.st_mode & S_ISVTX) == S_ISVTX &&
 
764
          (buf.st_mode & ACCESSPERMS) == DND_ROOTDIR_PERMS;
 
765
}
 
766
 
 
767
 
 
768
/*
 
769
 *----------------------------------------------------------------------------
 
770
 *
 
771
 * DnDSetPermissionsOnRootDir --
 
772
 *
 
773
 *    Sets the correct permissions for the root staging directory.  We set the
 
774
 *    root directory to 1777 so that all users can create their own staging
 
775
 *    directories within it and that other users cannot delete that directory.
 
776
 *
 
777
 * Results:
 
778
 *    TRUE on success, FALSE on failure.
 
779
 *
 
780
 * Side effects:
 
781
 *    None.
 
782
 *
 
783
 *----------------------------------------------------------------------------
 
784
 */
 
785
 
 
786
Bool
 
787
DnDSetPermissionsOnRootDir(ConstUnicode pathName)  // IN:
 
788
{
 
789
   return Posix_Chmod(pathName, S_ISVTX | DND_ROOTDIR_PERMS) == 0;
 
790
}
 
791
 
 
792
 
 
793
/*
 
794
 *----------------------------------------------------------------------------
 
795
 *
 
796
 * DnDStagingDirectoryUsable --
 
797
 *
 
798
 *    Determines whether a staging directory is usable for the current
 
799
 *    process.  A directory is only usable by the current process if it is
 
800
 *    owned by the effective uid of the current process.
 
801
 *
 
802
 * Results:
 
803
 *    TRUE if the directory is usable, FALSE if it is not.
 
804
 *
 
805
 * Side effects:
 
806
 *    None.
 
807
 *
 
808
 *----------------------------------------------------------------------------
 
809
 */
 
810
 
 
811
Bool
 
812
DnDStagingDirectoryUsable(ConstUnicode pathName)  // IN:
 
813
{
 
814
   struct stat buf;
 
815
 
 
816
   if (Posix_Stat(pathName, &buf) < 0) {
 
817
      return FALSE;
 
818
   }
 
819
 
 
820
   return buf.st_uid == Id_GetEUid();
 
821
}
 
822
 
 
823
 
 
824
/*
 
825
 *----------------------------------------------------------------------------
 
826
 *
 
827
 * DnDSetPermissionsOnStagingDir --
 
828
 *
 
829
 *    Sets the correct permissions for staging directories.
 
830
 *
 
831
 * Results:
 
832
 *    TRUE on success, FALSE on failure.
 
833
 *
 
834
 * Side effects:
 
835
 *    None.
 
836
 *
 
837
 *----------------------------------------------------------------------------
 
838
 */
 
839
 
 
840
Bool
 
841
DnDSetPermissionsOnStagingDir(ConstUnicode pathName)  // IN:
 
842
{
 
843
   return Posix_Chmod(pathName, DND_STAGINGDIR_PERMS) == 0;
 
844
}