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

« back to all changes in this revision

Viewing changes to lib/procMgr/procMgrSolaris.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) 2010 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
/*
 
21
 * procMgrSolaris.c --
 
22
 *
 
23
 *    Solaris specific implementations of the process management lib methods.
 
24
 *
 
25
 */
 
26
 
 
27
 
 
28
#include <sys/types.h>
 
29
#include <dirent.h>
 
30
#include <errno.h>
 
31
#include <string.h>
 
32
#include <procfs.h>
 
33
#include <ctype.h>
 
34
#include <sys/param.h>
 
35
 
 
36
#include "vmware.h"
 
37
#include "procMgr.h"
 
38
#include "debug.h"
 
39
#include "util.h"
 
40
#undef offsetof
 
41
#include "dynbuf.h"
 
42
#include "dynarray.h"
 
43
#include "su.h"
 
44
#include "str.h"
 
45
#include "fileIO.h"
 
46
#include "codeset.h"
 
47
#include "unicode.h"
 
48
 
 
49
static Bool
 
50
ReadArgsFromAddressSpaceFile(FileIODescriptor asFd,
 
51
                             psinfo_t *psInfo,
 
52
                             DynBufArray *cmdLineArr);
 
53
 
 
54
static Bool
 
55
ReadOffsetsFromAddressSpaceFile(FileIODescriptor asFd,
 
56
                                psinfo_t *psInfo,
 
57
                                uintptr_t *argOffs);
 
58
 
 
59
static char *
 
60
ExtractArgStringFromAddressSpaceFile(FileIODescriptor asFd,
 
61
                                     uintptr_t offset);
 
62
 
 
63
static char *
 
64
ExtractCommandLineFromAddressSpaceFile(psinfo_t *procInfo);
 
65
 
 
66
/*
 
67
 *----------------------------------------------------------------------------
 
68
 *
 
69
 * ProcMgr_ListProcesses --
 
70
 *
 
71
 *      List all the processes that the calling client has privilege to
 
72
 *      enumerate. The strings in the returned structure should be all
 
73
 *      UTF-8 encoded, although we do not enforce it right now.
 
74
 *
 
75
 * Results:
 
76
 *
 
77
 *      On success, the process list is returned and the caller is responsible
 
78
 *      for freeing the memory used by calling ProcMgr_FreeProcList. On
 
79
 *      failure, NULL is returned.
 
80
 *
 
81
 * Side effects:
 
82
 *
 
83
 *      None
 
84
 *
 
85
 *----------------------------------------------------------------------------
 
86
 */
 
87
 
 
88
ProcMgr_ProcList *
 
89
ProcMgr_ListProcesses(void)
 
90
{
 
91
   ProcMgr_ProcList *procList = NULL;
 
92
 
 
93
   Bool failed = FALSE;
 
94
   DynBuf dbProcId;
 
95
   DynBuf dbProcCmd;
 
96
   DynBuf dbProcStartTime;
 
97
   DynBuf dbProcOwner;
 
98
   DIR *dir;
 
99
   struct dirent *ent;
 
100
 
 
101
   DynBuf_Init(&dbProcId);
 
102
   DynBuf_Init(&dbProcCmd);
 
103
   DynBuf_Init(&dbProcStartTime);
 
104
   DynBuf_Init(&dbProcOwner);
 
105
 
 
106
   dir = opendir("/proc");
 
107
   if (NULL == dir) {
 
108
      Warning("ProcMgr_ListProcesses unable to open /proc\n");
 
109
      failed = TRUE;
 
110
      goto exit;
 
111
   }
 
112
 
 
113
   while (TRUE) {
 
114
      pid_t pid;
 
115
      struct passwd *pwd;
 
116
      char *cmdLineTemp;
 
117
      char *userName = NULL;
 
118
      char tempPath[MAXPATHLEN];
 
119
      time_t processStartTime;
 
120
      psinfo_t procInfo;
 
121
      size_t strLen = 0;
 
122
      size_t numRead = 0;
 
123
      FileIODescriptor psInfoFd;
 
124
      FileIOResult res;
 
125
 
 
126
      errno = 0;
 
127
      FileIO_Invalidate(&psInfoFd);
 
128
 
 
129
      ent = readdir(dir);
 
130
      if (ent == NULL) {
 
131
         if (errno == 0) {
 
132
            break;
 
133
         } else {
 
134
            failed = TRUE;
 
135
            goto exit;
 
136
         }
 
137
      }
 
138
 
 
139
      if (Str_Snprintf(tempPath,
 
140
                       sizeof tempPath,
 
141
                       "/proc/%s/psinfo",
 
142
                       ent->d_name) == -1) {
 
143
         Debug("Process id '%s' too large\n", ent->d_name);
 
144
         continue;
 
145
      }
 
146
      res = FileIO_Open(&psInfoFd,
 
147
                        tempPath,
 
148
                        FILEIO_OPEN_ACCESS_READ,
 
149
                        FILEIO_OPEN);
 
150
      if (res != FILEIO_SUCCESS) {
 
151
         if ((res == FILEIO_FILE_NOT_FOUND) ||
 
152
             (res == FILEIO_NO_PERMISSION)) {
 
153
            continue;
 
154
         } else {
 
155
            failed = TRUE;
 
156
            goto exit;
 
157
         }
 
158
      }
 
159
 
 
160
      res = FileIO_Read(&psInfoFd, &procInfo, sizeof procInfo, &numRead);
 
161
      FileIO_Close(&psInfoFd);
 
162
      if (res != FILEIO_SUCCESS) {
 
163
         failed = TRUE;
 
164
         goto exit;
 
165
      }
 
166
 
 
167
      processStartTime = procInfo.pr_start.tv_sec;
 
168
 
 
169
      /*
 
170
       * Command line strings in procInfo.pr_psargs are truncated to PRARGZ
 
171
       * bytes. In this case we extract the arguments from the /proc/<pid>/as
 
172
       * file. Since most command line strings are expected to fit within
 
173
       * PRARGSZ bytes, we avoid calling
 
174
       * ExtractCommandLineFromAddressSpaceFile for every process.
 
175
       */
 
176
      if (strlen(procInfo.pr_psargs) + 1 == PRARGSZ) {
 
177
         char *tmp;
 
178
 
 
179
         tmp = ExtractCommandLineFromAddressSpaceFile(&procInfo);
 
180
         if (tmp != NULL) {
 
181
            cmdLineTemp = Unicode_Alloc(tmp, STRING_ENCODING_DEFAULT);
 
182
            free(tmp);
 
183
         } else {
 
184
            cmdLineTemp = Unicode_Alloc(procInfo.pr_psargs,
 
185
                                        STRING_ENCODING_DEFAULT);
 
186
         }
 
187
      } else {
 
188
         cmdLineTemp = Unicode_Alloc(procInfo.pr_psargs,
 
189
                                     STRING_ENCODING_DEFAULT);
 
190
      }
 
191
 
 
192
      /*
 
193
       * Store the command line string pointer in dynbuf.
 
194
       */
 
195
      DynBuf_Append(&dbProcCmd, &cmdLineTemp, sizeof cmdLineTemp);
 
196
 
 
197
      /*
 
198
       * Store the pid in dynbuf.
 
199
       */
 
200
      pid = procInfo.pr_pid;
 
201
      DynBuf_Append(&dbProcId, &pid, sizeof pid);
 
202
 
 
203
      /*
 
204
       * Store the owner of the process.
 
205
       */
 
206
      pwd = getpwuid(procInfo.pr_uid);
 
207
      userName = (NULL == pwd)
 
208
                 ? Str_Asprintf(&strLen, "%d", (int) procInfo.pr_uid)
 
209
                 : Unicode_Alloc(pwd->pw_name, STRING_ENCODING_DEFAULT);
 
210
      DynBuf_Append(&dbProcOwner, &userName, sizeof userName);
 
211
 
 
212
      /*
 
213
       * Store the time that the process started.
 
214
       */
 
215
      DynBuf_Append(&dbProcStartTime,
 
216
                    &processStartTime,
 
217
                    sizeof processStartTime);
 
218
   } // while (TRUE)
 
219
 
 
220
   closedir(dir);
 
221
 
 
222
   if (0 == DynBuf_GetSize(&dbProcId)) {
 
223
      failed = TRUE;
 
224
      goto exit;
 
225
   }
 
226
 
 
227
   /*
 
228
    * We're done adding to DynBuf.  Trim off any unused allocated space.
 
229
    * DynBuf_Trim() followed by DynBuf_Detach() avoids a memcpy().
 
230
    */
 
231
   DynBuf_Trim(&dbProcId);
 
232
   DynBuf_Trim(&dbProcCmd);
 
233
   DynBuf_Trim(&dbProcStartTime);
 
234
   DynBuf_Trim(&dbProcOwner);
 
235
 
 
236
   /*
 
237
    * Create a ProcMgr_ProcList and populate its fields.
 
238
    */
 
239
   procList = (ProcMgr_ProcList *) Util_SafeCalloc(1, sizeof(ProcMgr_ProcList));
 
240
   ASSERT_MEM_ALLOC(procList);
 
241
 
 
242
   procList->procCount = DynBuf_GetSize(&dbProcId) / sizeof(pid_t);
 
243
 
 
244
   procList->procIdList = (pid_t *) DynBuf_Detach(&dbProcId);
 
245
   ASSERT_MEM_ALLOC(procList->procIdList);
 
246
   procList->procCmdList = (char **) DynBuf_Detach(&dbProcCmd);
 
247
   ASSERT_MEM_ALLOC(procList->procCmdList);
 
248
   procList->startTime = (time_t *) DynBuf_Detach(&dbProcStartTime);
 
249
   ASSERT_MEM_ALLOC(procList->startTime);
 
250
   procList->procOwnerList = (char **) DynBuf_Detach(&dbProcOwner);
 
251
   ASSERT_MEM_ALLOC(procList->procOwnerList);
 
252
 
 
253
exit:
 
254
   DynBuf_Destroy(&dbProcId);
 
255
   DynBuf_Destroy(&dbProcCmd);
 
256
   DynBuf_Destroy(&dbProcStartTime);
 
257
   DynBuf_Destroy(&dbProcOwner);
 
258
 
 
259
   if (failed) {
 
260
      ProcMgr_FreeProcList(procList);
 
261
      procList = NULL;
 
262
   }
 
263
 
 
264
   return procList;
 
265
}
 
266
 
 
267
 
 
268
/*
 
269
 *----------------------------------------------------------------------------
 
270
 *
 
271
 * ExtractCommandLineFromAddressSpaceFile --
 
272
 *
 
273
 *      Read the address space file (/proc/<pid>/as) for a given process and
 
274
 *      return its command line string.
 
275
 *
 
276
 * Results:
 
277
 *
 
278
 *      On success, the command line string for the process is returned and the
 
279
 *      caller is responsible for freeing the memory used by this string. On
 
280
 *      failure, NULL is returned.
 
281
 *
 
282
 * Side effects:
 
283
 *
 
284
 *      None
 
285
 *
 
286
 *----------------------------------------------------------------------------
 
287
 */
 
288
 
 
289
static char *
 
290
ExtractCommandLineFromAddressSpaceFile(psinfo_t *procInfo) //IN: psinfo struct
 
291
{
 
292
   int argc;
 
293
   int i;
 
294
   char tempPath[MAXPATHLEN];
 
295
   char *buf;
 
296
   FileIODescriptor asFd;
 
297
   FileIOResult res;
 
298
   DynBuf cmdLine;
 
299
   DynBufArray args;
 
300
   pid_t pid;
 
301
 
 
302
   FileIO_Invalidate(&asFd);
 
303
   pid = procInfo->pr_pid;
 
304
 
 
305
   if (Str_Snprintf(tempPath,
 
306
                sizeof tempPath,
 
307
                "/proc/%"FMT64"d/as",
 
308
                (int64_t)pid) == -1) {
 
309
      /* This should not happen. MAXPATHLEN should be large enough. */
 
310
      ASSERT(FALSE);
 
311
   }
 
312
   res = FileIO_Open(&asFd,
 
313
                     tempPath,
 
314
                     FILEIO_OPEN_ACCESS_READ,
 
315
                     FILEIO_OPEN);
 
316
   if (res != FILEIO_SUCCESS) {
 
317
      Warning("Could not open address space file for pid %"FMT64"d, %s\n",
 
318
              (int64_t)pid,
 
319
              FileIO_MsgError(res));
 
320
      return NULL;
 
321
   }
 
322
 
 
323
   buf = NULL;
 
324
   if (ReadArgsFromAddressSpaceFile(asFd, procInfo, &args)) {
 
325
      /* Concatenate the strings in args into cmdLine. */
 
326
      DynBuf_Init(&cmdLine);
 
327
      argc = DynBufArray_Count(&args);
 
328
      for (i = 0; i < argc; i++) {
 
329
         buf = DynBuf_Get(DynBufArray_AddressOf(&args, i));
 
330
         DynBuf_Append(&cmdLine, buf, strlen(buf));
 
331
         if (i + 1 < argc) {
 
332
            DynBuf_Append(&cmdLine, " ", 1);
 
333
         }
 
334
         DynBuf_Destroy(DynBufArray_AddressOf(&args, i));
 
335
      }
 
336
      DynBuf_AppendString(&cmdLine,"");
 
337
      DynBufArray_Destroy(&args);
 
338
      DynBuf_Trim(&cmdLine);
 
339
      buf = DynBuf_Detach(&cmdLine);
 
340
      DynBuf_Destroy(&cmdLine);
 
341
   }
 
342
   FileIO_Close(&asFd);
 
343
   return buf;
 
344
}
 
345
 
 
346
 
 
347
/*
 
348
 *----------------------------------------------------------------------------
 
349
 *
 
350
 * ReadArgsFromAddressSpaceFile --
 
351
 *
 
352
 *      Read the command line arguments for a process and store them in the
 
353
 *      cmdLineArr array. The processes' address space file must be open with
 
354
 *      the file descriptor adFd. This function assumes that it runs in the
 
355
 *      same locale as the process being inspected.
 
356
 *
 
357
 * Results:
 
358
 *
 
359
 *      On success, TRUE is returned and the caller is responsible for
 
360
 *      de-allocating the memory used by the DynBufArray; by calling
 
361
 *      DynBuf_Destroy on each of its elements, and then DynBufArray_Destroy on
 
362
 *      the array itself. FALSE is returned on failure, and no de-allocation
 
363
 *      is needed.
 
364
 *
 
365
 * Side effects:
 
366
 *
 
367
 *      The cmdLineArr array is filled with the command line strings of the
 
368
 *      given process.
 
369
 *----------------------------------------------------------------------------
 
370
 */
 
371
 
 
372
static Bool
 
373
ReadArgsFromAddressSpaceFile(FileIODescriptor asFd,     //IN
 
374
                             psinfo_t *psInfo,          //IN
 
375
                             DynBufArray *cmdLineArr)   //OUT
 
376
{
 
377
   uintptr_t *argOffs;
 
378
   uintptr_t argOff;
 
379
   uintptr_t nextArgOff;
 
380
   int argc;
 
381
   int i;
 
382
   char *argBuf;
 
383
   char *argBufPtr;
 
384
   DynBuf *arg;
 
385
 
 
386
   argc = psInfo->pr_argc;
 
387
   DynBufArray_Init(cmdLineArr, argc);
 
388
   for (i = 0; i < argc; i++) {
 
389
      DynBuf_Init(DynBufArray_AddressOf(cmdLineArr, i));
 
390
   }
 
391
   if (argc == 0) {
 
392
      return TRUE;
 
393
   }
 
394
   argOffs = Util_SafeCalloc(argc, sizeof *argOffs);
 
395
   if (argOffs == NULL) {
 
396
      return FALSE;
 
397
   }
 
398
 
 
399
   if (!ReadOffsetsFromAddressSpaceFile(asFd, psInfo, argOffs)) {
 
400
      goto fail;
 
401
   }
 
402
 
 
403
   /* Read the command line arguments into the cmdLineArr array. */
 
404
   nextArgOff = argc > 0 ? argOffs[0] : 0;
 
405
   i = 0;
 
406
   while (i < argc) {
 
407
      argOff = argOffs[i];
 
408
 
 
409
      /*
 
410
       * The argument strings are contiguous in the address space file. So
 
411
       * argOff[i] + strlen(arg[i]) + 1 should be equal to argOff[i + 1].
 
412
       */
 
413
      if ((argOff == 0) || (argOff != nextArgOff)) {
 
414
         goto fail;
 
415
      }
 
416
      argBuf = ExtractArgStringFromAddressSpaceFile(asFd, argOff);
 
417
      if (argBuf == NULL) {
 
418
         goto fail;
 
419
      }
 
420
      nextArgOff = argOff + strlen(argBuf) + 1;
 
421
      argBufPtr = argBuf +  strlen(argBuf);
 
422
      while ((argBufPtr > argBuf) && isspace(*(argBufPtr - 1))) {
 
423
         argBufPtr--;
 
424
      }
 
425
      *argBufPtr = '\0';
 
426
      arg = DynBufArray_AddressOf(cmdLineArr, i);
 
427
      if (!DynBuf_Append(arg,
 
428
                         argBuf,
 
429
                         strlen(argBuf) + 1)) {
 
430
         free(argBuf);
 
431
         goto fail;
 
432
      }
 
433
      free(argBuf);
 
434
      i++;
 
435
   }
 
436
   return TRUE;
 
437
 
 
438
fail:
 
439
   Warning("Failed to read command line arguments\n");
 
440
   argc = DynBufArray_Count(cmdLineArr);
 
441
   for (i = 0; i < argc; i++) {
 
442
      arg = DynArray_AddressOf(cmdLineArr, i);
 
443
      DynBuf_Destroy(arg);
 
444
   }
 
445
   DynBufArray_SetCount(cmdLineArr, 0);
 
446
   DynBufArray_Destroy(cmdLineArr);
 
447
   free(argOffs);
 
448
   return FALSE;
 
449
}
 
450
 
 
451
 
 
452
/*
 
453
 *----------------------------------------------------------------------------
 
454
 *
 
455
 * ReadOffsetsFromAddressSpaceFile --
 
456
 *
 
457
 *      Read the offsets for the command line arguments strings of a process
 
458
 *      into the argOffs array. The processes' /proc/<pid>/as file must be
 
459
 *      open with the file descriptor asFd. The argOffs array must have enough
 
460
 *      space to store all the offsets for the process.
 
461
 *
 
462
 * Results:
 
463
 *
 
464
 *      TRUE on success, FALSE on error.
 
465
 *
 
466
 * Side Effects:
 
467
 *
 
468
 *      The argOffs array is filled with the offsets of the command line
 
469
 *      arguments.
 
470
 *
 
471
 *----------------------------------------------------------------------------
 
472
 */
 
473
 
 
474
static Bool
 
475
ReadOffsetsFromAddressSpaceFile(FileIODescriptor asFd, //IN
 
476
                                psinfo_t *psInfo,      //IN
 
477
                                uintptr_t *argOffs)    //OUT
 
478
{
 
479
   int argc;
 
480
   int i;
 
481
   uintptr_t argv;
 
482
   FileIOResult res;
 
483
 
 
484
   argc = psInfo->pr_argc;
 
485
   argv = psInfo->pr_argv;
 
486
   /*
 
487
    * The offsets for the command line argument are located at an offset of
 
488
    * argv in the /proc/<pid>/as file. If the process data model is NATIVE,
 
489
    * each offset is a unitptr_t; else if the data model is ILP32 or LP64, each
 
490
    * offset is uint32_t.
 
491
    */
 
492
   if (psInfo->pr_dmodel == PR_MODEL_NATIVE) {
 
493
      /*
 
494
       * The offset for each arguments is sizeof uintptr_t bytes.
 
495
       */
 
496
      res = FileIO_Pread(&asFd, argOffs, argc * sizeof argv, argv);
 
497
      if (res != FILEIO_SUCCESS) {
 
498
         return FALSE;
 
499
      }
 
500
   } else {
 
501
      /*
 
502
       * The offset for each arguments is sizeof uint32_t bytes.
 
503
       */
 
504
      uint32_t *argOffs32;
 
505
      argOffs32 = Util_SafeCalloc(argc, sizeof *argOffs32);
 
506
      if (argOffs32 == NULL) {
 
507
         return FALSE;
 
508
      }
 
509
      res = FileIO_Pread(&asFd, argOffs32, argc * sizeof *argOffs32, argv);
 
510
      if (res != FILEIO_SUCCESS) {
 
511
         free (argOffs32);
 
512
         return FALSE;
 
513
      }
 
514
      for (i = 0; i < argc; i++) {
 
515
         argOffs[i] = argOffs32[i];
 
516
      }
 
517
      free(argOffs32);
 
518
   }
 
519
   return TRUE;
 
520
}
 
521
 
 
522
 
 
523
/*
 
524
 *----------------------------------------------------------------------------
 
525
 *
 
526
 * ExtractArgStringFromAddressSpaceFile --
 
527
 *
 
528
 *      Extract a string at a given offset in the given file. The file must be
 
529
 *      open with file descriptor asFd.
 
530
 *
 
531
 * Results:
 
532
 *
 
533
 *      On success, the NULL terminated string is returned and the
 
534
 *      caller is responsible for freeing the memory used by this string. On
 
535
 *      failure, NULL is returned.
 
536
 *
 
537
 * Side effects:
 
538
 *
 
539
 *      None
 
540
 *
 
541
 *----------------------------------------------------------------------------
 
542
 */
 
543
 
 
544
static char *
 
545
ExtractArgStringFromAddressSpaceFile(FileIODescriptor asFd,     //IN
 
546
                                     uintptr_t offset)          //IN
 
547
{
 
548
   int readSize = 32;
 
549
   char *buf;
 
550
   FileIOResult res;
 
551
 
 
552
   buf = Util_SafeMalloc(readSize * sizeof *buf);
 
553
   while (1) {
 
554
      res = FileIO_Pread(&asFd, buf, readSize, offset);
 
555
      if (res != FILEIO_SUCCESS) {
 
556
         goto fail;
 
557
      }
 
558
      if (Str_Strlen(buf, readSize) == readSize) {
 
559
         readSize *= 2;
 
560
         free(buf);
 
561
         if (readSize > NCARGS) {
 
562
            return NULL;
 
563
         }
 
564
         buf = Util_SafeMalloc(readSize * sizeof *buf);
 
565
      } else {
 
566
         break;
 
567
      }
 
568
   }
 
569
   return buf;
 
570
 
 
571
fail:
 
572
   free(buf);
 
573
   return NULL;
 
574
}
 
575
 
 
576
 
 
577
/*
 
578
 *----------------------------------------------------------------------
 
579
 *
 
580
 * ProcMgr_ImpersonateUserStart --
 
581
 *
 
582
 *      Impersonate a user.  Much like bora/lib/impersonate, but
 
583
 *      changes the real and saved uid as well, to work with syscalls
 
584
 *      (access() and kill()) that look at real UID instead of effective.
 
585
 *      The user name should be UTF-8 encoded, although we do not enforce
 
586
 *      it right now. Solaris does not have setresuid/setresgid. So perform
 
587
 *      a two step process to set the real and effective uid/gid to given
 
588
 *      user and leave the saved uid/gid as root.
 
589
 *
 
590
 *      Assumes it will be called as root.
 
591
 *
 
592
 * Results:
 
593
 *      TRUE on success, FALSE on failure
 
594
 *
 
595
 * Side effects:
 
596
 *
 
597
 *      Uid/gid set to given user, saved uid/gid left as root.
 
598
 *
 
599
 *----------------------------------------------------------------------
 
600
 */
 
601
 
 
602
Bool
 
603
ProcMgr_ImpersonateUserStart(const char *user,  // IN: UTF-8 encoded user name
 
604
                             AuthToken token)   // IN
 
605
{
 
606
   char buffer[BUFSIZ];
 
607
   struct passwd pw;
 
608
   struct passwd *ppw;
 
609
   gid_t root_gid;
 
610
   int ret;
 
611
 
 
612
   ppw = &pw;
 
613
   if ((ppw = getpwuid_r(0, &pw, buffer, sizeof buffer)) == NULL) {
 
614
      return FALSE;
 
615
   }
 
616
 
 
617
   root_gid = ppw->pw_gid;
 
618
 
 
619
   if ((ppw = getpwnam_r(user, &pw, buffer, sizeof buffer)) == NULL) {
 
620
      return FALSE;
 
621
   }
 
622
 
 
623
   /* first change group. */
 
624
   ret = Id_SetGid(root_gid);
 
625
   if (ret < 0) {
 
626
      Warning("Failed to setregid() for root\n");
 
627
      return FALSE;
 
628
   }
 
629
 
 
630
   /*  Snippet from Solaris setregid man page --
 
631
    *
 
632
    *  A -1 argument does not change the corresponding gid. If the real user ID
 
633
    *  is being changed, or the effective user ID is being changed to a value
 
634
    *  not equal to the real user ID, the saved set-user ID is set equal to
 
635
    *  the new effective user ID.
 
636
    */
 
637
   ret = Id_SetREGid(ppw->pw_gid, -1);
 
638
   if (ret < 0) {
 
639
      Warning("Failed to setregid() for user %s\n", user);
 
640
      return FALSE;
 
641
   }
 
642
   ret = Id_SetREGid(-1, ppw->pw_gid);
 
643
   if (ret < 0) {
 
644
      Warning("Failed to setregid() for user %s\n", user);
 
645
      return FALSE;
 
646
   }
 
647
   ret = initgroups(ppw->pw_name, ppw->pw_gid);
 
648
   if (ret < 0) {
 
649
      Warning("Failed to initgroups() for user %s\n", user);
 
650
      goto failure;
 
651
   }
 
652
 
 
653
   /* now user. */
 
654
   ret = Id_SetUid(0);
 
655
   if (ret < 0) {
 
656
      Warning("Failed to setregid() for root\n");
 
657
      return FALSE;
 
658
   }
 
659
 
 
660
   /* Same as above. */
 
661
   ret = Id_SetREUid(ppw->pw_uid, -1);
 
662
   if (ret < 0) {
 
663
      Warning("Failed to setreuid() for user %s\n", user);
 
664
      goto failure;
 
665
   }
 
666
   ret = Id_SetREUid(-1, ppw->pw_uid);
 
667
   if (ret < 0) {
 
668
      Warning("Failed to setreuid() for user %s\n", user);
 
669
      goto failure;
 
670
   }
 
671
 
 
672
   /* set env. */
 
673
   setenv("USER", ppw->pw_name, 1);
 
674
   setenv("HOME", ppw->pw_dir, 1);
 
675
   setenv("SHELL", ppw->pw_shell, 1);
 
676
 
 
677
   return TRUE;
 
678
 
 
679
failure:
 
680
   /* try to restore on error. */
 
681
   ProcMgr_ImpersonateUserStop();
 
682
   return FALSE;
 
683
}
 
684
 
 
685
 
 
686
/*
 
687
 *----------------------------------------------------------------------
 
688
 *
 
689
 * ProcMgr_ImpersonateUserStop --
 
690
 *
 
691
 *      Stop impersonating a user and return to root. Solaris does not
 
692
 *      have setresuid/setresgid. So perform a two step process while
 
693
 *      restoring uids to root.
 
694
 *
 
695
 * Results:
 
696
 *      TRUE on success, FALSE on failure.
 
697
 *
 
698
 * Side effects:
 
699
 *
 
700
 *      Uid/gid restored to root.
 
701
 *
 
702
 *----------------------------------------------------------------------
 
703
 */
 
704
 
 
705
Bool
 
706
ProcMgr_ImpersonateUserStop(void)
 
707
{
 
708
   char buffer[BUFSIZ];
 
709
   struct passwd pw;
 
710
   struct passwd *ppw;
 
711
   int ret;
 
712
 
 
713
   ppw = &pw;
 
714
   if ((ppw = getpwuid_r(0, &pw, buffer, sizeof buffer)) == NULL) {
 
715
      return FALSE;
 
716
   }
 
717
 
 
718
   /* first change back user, Do the same two step process as above. */
 
719
   ret = Id_SetREUid(-1, ppw->pw_uid);
 
720
   if (ret < 0) {
 
721
      Warning("Failed setreuid() for root\n");
 
722
      return FALSE;
 
723
   }
 
724
   ret = Id_SetREUid(ppw->pw_uid, -1);
 
725
   if (ret < 0) {
 
726
      Warning("Failed to setreuid() for root\n");
 
727
      return FALSE;
 
728
   }
 
729
 
 
730
   /* now group. */
 
731
   ret = Id_SetGid(ppw->pw_gid);
 
732
   if (ret < 0) {
 
733
      Warning("Failed to setgid() for root\n");
 
734
      return FALSE;
 
735
   }
 
736
   ret = initgroups(ppw->pw_name, ppw->pw_gid);
 
737
   if (ret < 0) {
 
738
      Warning("Failed to initgroups() for root\n");
 
739
      return FALSE;
 
740
   }
 
741
 
 
742
   /* set env. */
 
743
   setenv("USER", ppw->pw_name, 1);
 
744
   setenv("HOME", ppw->pw_dir, 1);
 
745
   setenv("SHELL", ppw->pw_shell, 1);
 
746
 
 
747
   return TRUE;
 
748
}
 
749
 
 
750
 
 
751
/*
 
752
 *----------------------------------------------------------------------
 
753
 *
 
754
 * ProcMgr_GetImpersonatedUserInfo --
 
755
 *
 
756
 *      Return info about the impersonated user.
 
757
 *
 
758
 * Results:
 
759
 *      TRUE on success, FALSE on failure.
 
760
 *
 
761
 * Side effects:
 
762
 *
 
763
 *----------------------------------------------------------------------
 
764
 */
 
765
 
 
766
Bool
 
767
ProcMgr_GetImpersonatedUserInfo(char **userName,            // OUT
 
768
                                char **homeDir)             // OUT
 
769
{
 
770
   char buffer[BUFSIZ];
 
771
   struct passwd pw;
 
772
   struct passwd *ppw;
 
773
 
 
774
   *userName = NULL;
 
775
   *homeDir = NULL;
 
776
 
 
777
   ppw = &pw;
 
778
   if ((ppw = getpwuid_r(Id_GetEUid(), &pw, buffer, sizeof buffer)) == NULL) {
 
779
      return FALSE;
 
780
   }
 
781
 
 
782
   *userName = Unicode_Alloc(ppw->pw_name, STRING_ENCODING_DEFAULT);
 
783
   *homeDir = Unicode_Alloc(ppw->pw_dir, STRING_ENCODING_DEFAULT);
 
784
 
 
785
   return TRUE;
 
786
}
 
787