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

« back to all changes in this revision

Viewing changes to lib/procMgr/procMgrPosix.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:
99
99
};
100
100
 
101
101
static pid_t ProcMgrStartProcess(char const *cmd,
102
 
                                 char * const  *envp);
 
102
                                 char * const  *envp,
 
103
                                 char const *workingDir);
103
104
 
104
105
static Bool ProcMgrWaitForProcCompletion(pid_t pid,
105
106
                                         Bool *validExitCode,
109
110
                        int sig,
110
111
                        int timeout);
111
112
 
 
113
#ifdef sun
 
114
#define  SOLARIS_BASH_PATH "/usr/bin/bash"
 
115
#endif
 
116
 
112
117
#if defined(linux) && !defined(GLIBC_VERSION_23)
113
118
/*
114
119
 * Implements the system calls (they are not wrapped by glibc til 2.3.2).
141
146
/*
142
147
 *----------------------------------------------------------------------
143
148
 *
 
149
 * ProcMgr_ReadProcFile --
 
150
 *
 
151
 *    Read the contents of a file in /proc/<pid>.
 
152
 *
 
153
 *    The size is essentially unbounded because of cmdline arguments.
 
154
 *    The only way to figure out the content size is to keep reading;
 
155
 *    stat(2) and lseek(2) lie.
 
156
 *
 
157
 *    The contents are NUL terminated -- in some distros may not include
 
158
 *    a NUL for some commands (eg. pid 1, /sbin/init) -- so add
 
159
 *    one to be safe.
 
160
 *
 
161
 * Results:
 
162
 *
 
163
 *    The length of the file.
 
164
 *
 
165
 *    -1 on error.
 
166
 *
 
167
 * Side effects:
 
168
 *
 
169
 *    The returned contents must be freed by caller.
 
170
 *
 
171
 *----------------------------------------------------------------------
 
172
 */
 
173
 
 
174
#if !defined(sun)
 
175
int
 
176
ProcMgr_ReadProcFile(int fd,                       // IN
 
177
                     char **contents)              // OUT
 
178
{
 
179
   int size = 0;
 
180
#if !defined(__FreeBSD__) && !defined(__APPLE__)
 
181
   char tmp[512];
 
182
   int numRead;
 
183
 
 
184
   *contents = NULL;
 
185
   numRead = read(fd, tmp, sizeof(tmp));
 
186
   size = numRead;
 
187
 
 
188
   if (numRead <= 0) {
 
189
      goto done;
 
190
   }
 
191
 
 
192
   /*
 
193
    * handle the 99% case
 
194
    */
 
195
   if (sizeof(tmp) > numRead) {
 
196
      char *result;
 
197
 
 
198
      result = malloc(numRead + 1);
 
199
      if (NULL == result) {
 
200
         size = -1;
 
201
         goto done;
 
202
      }
 
203
      memcpy(result, tmp, numRead);
 
204
      result[numRead] = '\0';
 
205
      *contents = result;
 
206
      goto done;
 
207
   } else {
 
208
      DynBuf dbuf;
 
209
 
 
210
      DynBuf_Init(&dbuf);
 
211
      DynBuf_Append(&dbuf, tmp, numRead);
 
212
      do {
 
213
         numRead = read(fd, tmp, sizeof(tmp));
 
214
         if (numRead > 0) {
 
215
            DynBuf_Append(&dbuf, tmp, numRead);
 
216
         }
 
217
         size += numRead;
 
218
      } while (numRead > 0);
 
219
      // add the NUL term
 
220
      DynBuf_Append(&dbuf, "", 1);
 
221
      DynBuf_Trim(&dbuf);
 
222
      *contents = DynBuf_Detach(&dbuf);
 
223
      DynBuf_Destroy(&dbuf);
 
224
   }
 
225
done:
 
226
#endif
 
227
   return size;
 
228
}
 
229
 
 
230
#endif   // !sun
 
231
 
 
232
/*
 
233
 *----------------------------------------------------------------------
 
234
 *
144
235
 * ProcMgr_ListProcesses --
145
236
 *
146
237
 *      List all the processes that the calling client has privilege to
156
247
 *----------------------------------------------------------------------
157
248
 */
158
249
 
 
250
#if !defined(sun)
159
251
ProcMgr_ProcList *
160
252
ProcMgr_ListProcesses(void)
161
253
{
162
254
   ProcMgr_ProcList *procList = NULL;
163
 
#if !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
 
255
#if !defined(__FreeBSD__) && !defined(__APPLE__)
164
256
   Bool failed = FALSE;
165
257
   DynBuf dbProcId;
166
258
   DynBuf dbProcCmd;
244
336
      pid_t pid;
245
337
      int replaceLoop;
246
338
      struct passwd *pwd;
247
 
      char cmdLineTemp[2048];
248
 
      char cmdStatTemp[2048];
 
339
      char *cmdLineTemp = NULL;
 
340
      char *cmdStatTemp = NULL;
249
341
      char *cmdLine;
250
342
      char *userName = NULL;
251
343
      size_t strLen = 0;
290
382
       * In the future, we could keep the NUL version around and pass it
291
383
       * back to the client for easier parsing when retrieving individual
292
384
       * command line parameters is needed.
293
 
       *
294
 
       * We read at most (sizeof cmdLineTemp) - 1 bytes to leave room
295
 
       * for NUL termination at the end.
296
385
       */
297
 
      numRead = read(cmdFd, cmdLineTemp, sizeof cmdLineTemp - sizeof(char));
 
386
      numRead = ProcMgr_ReadProcFile(cmdFd, &cmdLineTemp);
298
387
      close(cmdFd);
299
388
 
 
389
      if (numRead < 0) {
 
390
         continue;
 
391
      }
 
392
 
300
393
      if (numRead > 0) {
 
394
         /*
 
395
          * Stop before we hit the final '\0'; want to leave it alone.
 
396
          */
301
397
         for (replaceLoop = 0 ; replaceLoop < (numRead - 1) ; replaceLoop++) {
302
398
            if ('\0' == cmdLineTemp[replaceLoop]) {
303
399
               cmdLineTemp[replaceLoop] = ' ';
320
416
            cmdFd = open(cmdFilePath, O_RDONLY);
321
417
         }
322
418
         if (cmdFd != -1) {
323
 
            numRead = read(cmdFd, cmdLineTemp, sizeof(cmdLineTemp) - sizeof(char));
 
419
            numRead = ProcMgr_ReadProcFile(cmdFd, &cmdLineTemp);
324
420
            close(cmdFd);
325
 
 
326
 
            if (numRead < 0) {
327
 
               cmdLineTemp[0] = '\0';
328
 
            } else {
329
 
               cmdLineTemp[numRead] = '\0';
330
 
            }
331
421
         }
332
422
         if (numRead > 0) {
333
 
            /* 
 
423
            /*
334
424
             * Extract the part with just the name, by reading until the first
335
425
             * space, then reading the next non-space word after that, and
336
426
             * ignoring everything else. The format looks like this:
338
428
             * for example:
339
429
             *     "Name:    nfsd"
340
430
             */
341
 
            const char* nameStart = NULL;
342
 
            char* copyItr = NULL;
 
431
            const char *nameStart;
 
432
            char *copyItr;
343
433
 
344
434
            /* Skip non-whitespace. */
345
435
            for (nameStart = cmdLineTemp; *nameStart && 
360
450
      }
361
451
 
362
452
      /*
363
 
       * There is an edge case where /proc/#/cmdline does not NUL terminate
364
 
       * the command.  /sbin/init (process 1) is like that on some distros.
365
 
       * So let's guarantee that the string is NUL terminated, even if
366
 
       * the last character of the string might already be NUL.
367
 
       * This is safe to do because we read at most (sizeof cmdLineTemp) - 1
368
 
       * bytes from /proc/#/cmdline -- we left just enough space to add
369
 
       * NUL termination at the end.
370
 
       */
371
 
      if (numRead < 0) {
372
 
         cmdLineTemp[0] = '\0';
373
 
      } else {
374
 
         cmdLineTemp[numRead] = '\0';
375
 
      }
376
 
 
377
 
      /*
378
453
       * Get the inode information for this process.  This gives us
379
454
       * the process owner.
380
455
       */
383
458
                   "/proc/%s",
384
459
                   ent->d_name) == -1) {
385
460
         Debug("Giant process id '%s'\n", ent->d_name);
386
 
         continue;
 
461
         goto next_entry;
387
462
      }
388
463
 
389
464
      /*
393
468
       */
394
469
      statResult = stat(cmdFilePath, &fileStat);
395
470
      if (0 != statResult) {
396
 
         continue;
 
471
         goto next_entry;
397
472
      }
398
473
 
399
474
      /*
405
480
                   "/proc/%s/stat",
406
481
                   ent->d_name) == -1) {
407
482
         Debug("Giant process id '%s'\n", ent->d_name);
408
 
         continue;
 
483
         goto next_entry;
409
484
      }
410
485
      cmdFd = open(cmdFilePath, O_RDONLY);
411
486
      if (-1 == cmdFd) {
412
 
         continue;
 
487
         goto next_entry;
413
488
      }
414
 
      numRead = read(cmdFd, cmdStatTemp, sizeof cmdStatTemp);
 
489
      numRead = ProcMgr_ReadProcFile(cmdFd, &cmdStatTemp);
415
490
      close(cmdFd);
416
491
      if (0 >= numRead) {
417
 
         continue;
 
492
         goto next_entry;
418
493
      }
419
494
      /*
420
495
       * Skip over initial process id and process name.  "123 (bash) [...]".
421
496
       */
422
497
      stringBegin = strchr(cmdStatTemp, ')') + 2;
423
 
      
 
498
 
424
499
      numberFound = sscanf(stringBegin, "%c %d %d %d %d %d "
425
500
                           "%lu %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld "
426
501
                           "%d %ld %Lu",
437
512
                           (int *) &dummy, (long *) &dummy,
438
513
                           &relativeStartTime);
439
514
      if (20 != numberFound) {
440
 
         continue;
 
515
         goto next_entry;
441
516
      }
442
517
      processStartTime = hostStartTime + (relativeStartTime / hertz);
443
518
 
444
519
      /*
445
520
       * Store the command line string pointer in dynbuf.
446
521
       */
447
 
      cmdLine = strdup(cmdLineTemp);
 
522
      if (cmdLineTemp) {
 
523
         cmdLine = Unicode_Alloc(cmdLineTemp, STRING_ENCODING_DEFAULT);
 
524
      } else {
 
525
         cmdLine = Unicode_Alloc("", STRING_ENCODING_UTF8);
 
526
      }
448
527
      DynBuf_Append(&dbProcCmd, &cmdLine, sizeof cmdLine);
449
528
 
450
529
      /*
459
538
      pwd = getpwuid(fileStat.st_uid);
460
539
      userName = (NULL == pwd)
461
540
                 ? Str_Asprintf(&strLen, "%d", (int) fileStat.st_uid)
462
 
                 : Util_SafeStrdup(pwd->pw_name);
 
541
                 : Unicode_Alloc(pwd->pw_name, STRING_ENCODING_DEFAULT);
463
542
      DynBuf_Append(&dbProcOwner, &userName, sizeof userName);
464
543
 
465
544
      /*
468
547
      DynBuf_Append(&dbProcStartTime,
469
548
                    &processStartTime,
470
549
                    sizeof processStartTime);
 
550
 
 
551
next_entry:
 
552
      free(cmdLineTemp);
 
553
      free(cmdStatTemp);
471
554
   } // while readdir
472
555
 
473
556
   closedir(dir);
512
595
      ProcMgr_FreeProcList(procList);
513
596
      procList = NULL;
514
597
   }
515
 
#endif // !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
 
598
#endif // !defined(__FreeBSD__) && !defined(__APPLE__)
516
599
 
517
600
   return procList;
518
601
}
 
602
#endif // !defined(sun)
519
603
 
520
604
 
521
605
/*
581
665
 
582
666
   Debug("Executing sync command: %s\n", cmd);
583
667
 
584
 
   pid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
 
668
   pid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL,
 
669
                             userArgs ? userArgs->workingDirectory : NULL);
585
670
 
586
671
   if (pid == -1) {
587
672
      return FALSE;
610
695
 
611
696
static pid_t
612
697
ProcMgrStartProcess(char const *cmd,            // IN: UTF-8 encoded cmd
613
 
                    char * const *envp)         // IN: UTF-8 encoded env vars
 
698
                    char * const *envp,         // IN: UTF-8 encoded env vars
 
699
                    char const *workingDir)     // IN: UTF-8 working directory
614
700
{
615
701
   pid_t pid;
616
702
   char *cmdCurrent = NULL;
617
703
   char **envpCurrent = NULL;
 
704
   char *workDir = NULL;
618
705
 
619
706
   if (cmd == NULL) {
620
707
      ASSERT(FALSE);
631
718
      return -1;
632
719
   }
633
720
 
 
721
   if ((NULL != workingDir) &&
 
722
       !CodeSet_Utf8ToCurrent(workingDir, strlen(workingDir), &workDir, NULL)) {
 
723
      Warning("Could not convert workingDir from UTF-8 to current\n");
 
724
      return -1;
 
725
   }
 
726
 
634
727
   if (NULL != envp) {
635
728
      envpCurrent = Unicode_GetAllocList(envp, -1, STRING_ENCODING_DEFAULT);
636
729
   }
640
733
   if (pid == -1) {
641
734
      Warning("Unable to fork: %s.\n\n", strerror(errno));
642
735
   } else if (pid == 0) {
 
736
#ifdef sun
 
737
      /*
 
738
       * On Solaris, /bin/sh is the Bourne shell, and it
 
739
       * doesn't appear to have the optimization that bash does -- when
 
740
       * called with -c, bash appears to just use exec() to replace itself.
 
741
       * Bourne shell does a fork & exec, so 2 processes are started.
 
742
       * This is bad for us because we then see the PID of the shell, not the
 
743
       * app that it starts.  When this PID is returned to a user to
 
744
       * watch, they'll watch the wrong process.
 
745
       *
 
746
       * So for Solaris, use bash instead if possible.  We support
 
747
       * Solaris 10 and better; it contains bash, but not in its
 
748
       * minimal 'core' package, so it may not exist.
 
749
       */
 
750
      static const char bashShellPath[] = SOLARIS_BASH_PATH;
 
751
      char *bashArgs[] = { "bash", "-c", cmdCurrent, NULL };
 
752
      static const char bourneShellPath[] = "/bin/sh";
 
753
      char *bourneArgs[] = { "sh", "-c", cmdCurrent, NULL };
 
754
      const char *shellPath;
 
755
      char **args;
 
756
#else
643
757
      static const char shellPath[] = "/bin/sh";
644
758
      char *args[] = { "sh", "-c", cmdCurrent, NULL };
 
759
#endif
 
760
 
 
761
#ifdef sun
 
762
      if (File_Exists(SOLARIS_BASH_PATH)) {
 
763
         shellPath = bashShellPath;
 
764
         args = bashArgs;
 
765
      } else {
 
766
         shellPath = bourneShellPath;
 
767
         args = bourneArgs;
 
768
      }
 
769
#endif
645
770
 
646
771
      /*
647
772
       * Child
648
773
       */
649
774
 
 
775
      if (NULL != workDir) {
 
776
         if (chdir(workDir) != 0) {
 
777
            Warning("%s: Could not chdir(%s) %s\n", __FUNCTION__, workDir,
 
778
                    strerror(errno));
 
779
         }
 
780
      }
 
781
 
650
782
      if (NULL != envpCurrent) {
651
783
         execve(shellPath, args, envpCurrent);
652
784
      } else  {
663
795
    */
664
796
 
665
797
   free(cmdCurrent);
 
798
   free(workDir);
666
799
   Unicode_FreeList(envpCurrent, -1);
667
800
   return pid;
668
801
}
763
896
   FileIODescriptor readFd;
764
897
   FileIODescriptor writeFd;
765
898
 
766
 
   Debug("Executing async command: %s\n", cmd);
 
899
   Debug("Executing async command: '%s' in working dir '%s'\n",
 
900
         cmd, (userArgs && userArgs->workingDirectory) ? userArgs->workingDirectory : "");
767
901
   
768
902
   if (pipe(fds) == -1) {
769
903
      Warning("Unable to create the pipe to launch command: %s.\n", cmd);
819
953
       * Only run the program if we have not already experienced a failure.
820
954
       */
821
955
      if (status) {
822
 
         childPid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
 
956
         childPid = ProcMgrStartProcess(cmd,
 
957
                                        userArgs ? userArgs->envp : NULL,
 
958
                                        userArgs ? userArgs->workingDirectory : NULL);
823
959
         status = childPid != -1;
824
960
      }
825
961
 
1452
1588
   return TRUE;
1453
1589
}
1454
1590
 
 
1591
/*
 
1592
 *----------------------------------------------------------------------
 
1593
 *
 
1594
 * ProcMgr_GetImpersonatedUserInfo --
 
1595
 *
 
1596
 *      Return info about the impersonated user.
 
1597
 *
 
1598
 * Results:
 
1599
 *      TRUE on success
 
1600
 *
 
1601
 * Side effects:
 
1602
 *
 
1603
 *----------------------------------------------------------------------
 
1604
 */
 
1605
 
 
1606
Bool
 
1607
ProcMgr_GetImpersonatedUserInfo(char **userName,            // OUT
 
1608
                                char **homeDir)             // OUT
 
1609
{
 
1610
   uid_t uid = geteuid();
 
1611
   char buffer[BUFSIZ];
 
1612
   struct passwd pw;
 
1613
   struct passwd *ppw = &pw;
 
1614
   int error;
 
1615
 
 
1616
   *userName = NULL;
 
1617
   *homeDir = NULL;
 
1618
   if ((error = getpwuid_r(uid, &pw, buffer, sizeof buffer, &ppw)) != 0 ||
 
1619
       !ppw) {
 
1620
      /*
 
1621
       * getpwuid_r() and getpwnam_r() can return a 0 (success) but not
 
1622
       * set the return pointer (ppw) if there's no entry for the user,
 
1623
       * according to POSIX 1003.1-2003, so patch up the errno.
 
1624
       */
 
1625
      if (error == 0) {
 
1626
         error = ENOENT;
 
1627
      }
 
1628
      return FALSE;
 
1629
   }
 
1630
 
 
1631
   *userName = Unicode_Alloc(ppw->pw_name, STRING_ENCODING_DEFAULT);
 
1632
   *homeDir = Unicode_Alloc(ppw->pw_dir, STRING_ENCODING_DEFAULT);
 
1633
 
 
1634
   return TRUE;
 
1635
}
 
1636
 
1455
1637
#endif // linux