(file) Return to preexec.c CVS log (file) (dir) Up to [OMI] / omi / disp

  1 krisbash 1.1 /*
  2              **==============================================================================
  3              **
  4              ** Open Management Infrastructure (OMI)
  5              **
  6              ** Copyright (c) Microsoft Corporation
  7              ** 
  8              ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  9              ** use this file except in compliance with the License. You may obtain a copy 
 10              ** of the License at 
 11              **
 12              **     http://www.apache.org/licenses/LICENSE-2.0 
 13              **
 14              ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15              ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
 16              ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
 17              ** MERCHANTABLITY OR NON-INFRINGEMENT. 
 18              **
 19              ** See the Apache 2 License for the specific language governing permissions 
 20              ** and limitations under the License.
 21              **
 22 krisbash 1.1 **==============================================================================
 23              */
 24              
 25              #include "preexec.h"
 26              #include <common.h>
 27              #include <base/base.h>
 28              #include <pal/strings.h>
 29              #include <base/paths.h>
 30              #include <base/strarr.h>
 31              
 32              #if defined(CONFIG_POSIX)
 33              # include <pthread.h>
 34              # include <errno.h>
 35              # include <unistd.h>
 36              # include <sys/types.h>
 37              # include <sys/wait.h>
 38              # include <signal.h>
 39              #endif
 40              
 41              /*
 42              **==============================================================================
 43 krisbash 1.1 **
 44              ** Local Definitions:
 45              **
 46              **==============================================================================
 47              */
 48              
 49              static pid_t _Exec(
 50                  const char* path,
 51                  const char* uidStr,
 52                  const char* gidStr)
 53              {
 54                  pid_t pid = fork();
 55              
 56                  /* Return if failure */
 57                  if (pid < 0)
 58                      return -1;
 59              
 60                  /* Return if parent */
 61                  if (pid > 0)
 62                      return pid;
 63              
 64 krisbash 1.1     /* In child process here... */
 65              
 66                  /* Close any open file descriptors */
 67                  {
 68                      int fd;
 69                      int n = getdtablesize();
 70              
 71                      if (n > 2500 || n < 0)
 72                          n = 2500;
 73              
 74                      /* Leave stdin(0), stdout(1), stderr(2) open (for debugging) */
 75                      for (fd = 3; fd < n; ++fd)
 76                          close(fd);
 77                  }
 78              
 79                  /* Execute the program */
 80                  execl(
 81                      path,   /* path of program */
 82                      path,   /* argv[0] */
 83                      uidStr, /* argv[1] */
 84                      gidStr, /* argv[2] */
 85 krisbash 1.1         NULL);
 86              
 87                  _exit(1); 
 88                  /* Unreachable */
 89                  return -1;
 90              }
 91              
 92              static void _BlockSIGCHLD()
 93              {
 94                  sigset_t set;
 95                  sigemptyset(&set);
 96                  sigaddset(&set, SIGCHLD);
 97                  sigprocmask(SIG_BLOCK, &set, NULL);
 98              }
 99              
100              static void _UnblockSIGCHLD()
101              {
102                  sigset_t set;
103                  sigemptyset(&set);
104                  sigaddset(&set, SIGCHLD);
105                  sigprocmask(SIG_UNBLOCK, &set, NULL);
106 krisbash 1.1 }
107              
108              typedef struct _Bucket /* derives from HashBucket */
109              {
110                  struct _Bucket* next;
111                  char* key;
112              }
113              Bucket;
114              
115              static size_t _Hash(
116                  const HashBucket* bucket_)
117              {
118                  Bucket* bucket = (Bucket*)bucket_;
119                  size_t h = 0;
120                  char* key = bucket->key;
121              
122                  while (*key)
123                      h += 5 * *key++;
124              
125                  return h;
126              }
127 krisbash 1.1 
128              static int _Equal(
129                  const HashBucket* bucket1_,
130                  const HashBucket* bucket2_)
131              {
132                  Bucket* bucket1 = (Bucket*)bucket1_;
133                  Bucket* bucket2 = (Bucket*)bucket2_;
134                  return strcmp(bucket1->key, bucket2->key) == 0;
135              }
136              
137              static void _Release(
138                  HashBucket* bucket_)
139              {
140                  Bucket* bucket = (Bucket*)bucket_;
141                  PAL_Free(bucket->key);
142                  PAL_Free(bucket);
143              }
144              
145              static MI_Boolean _Contains(
146                  HashMap* self,
147                  const char* key)
148 krisbash 1.1 {
149                  Bucket bucket;
150                  bucket.key = (char*)key;
151                  return HashMap_Find(self, (const HashBucket*)&bucket) ? MI_TRUE : MI_FALSE;
152              }
153              
154              static int _Insert(
155                  HashMap* self,
156                  const char* key)
157              {
158                  Bucket* bucket = (Bucket*)PAL_Calloc(1, sizeof(Bucket));
159              
160                  if (!bucket)
161                      return -1;
162              
163                  bucket->key = PAL_Strdup(key);
164              
165                  if (!bucket->key)
166                  {
167                      PAL_Free(bucket);
168                      return -1;
169 krisbash 1.1     }
170              
171                  if (HashMap_Insert(self, (HashBucket*)bucket) != 0)
172                  {
173                      PAL_Free(bucket);
174                      PAL_Free(bucket->key);
175                      return -1;
176                  }
177              
178                  return 0;
179              }
180              
181              /*
182              **==============================================================================
183              **
184              ** Public Definitions:
185              **
186              **==============================================================================
187              */
188              
189              int PreExec_Construct(
190 krisbash 1.1     PreExec* self)
191              {
192                  const size_t NUMLISTS = 32;
193                  memset(self, 0, sizeof(*self));
194              
195                  if (HashMap_Init(&self->cache, NUMLISTS, _Hash, _Equal, _Release) != 0)
196                      return -1;
197              
198                  return 0;
199              }
200              
201              void PreExec_Destruct(
202                  PreExec* self)
203              {
204                  HashMap_Destroy(&self->cache);
205              }
206              
207              int PreExec_Exec(
208                  PreExec* self,
209                  const char* programPath,
210                  uid_t uid,
211 krisbash 1.1     uid_t gid)
212              {
213                  char path[PAL_MAX_PATH_SIZE];
214                  char key[PAL_MAX_PATH_SIZE];
215                  char uidBuf[11];
216                  const char* uidStr;
217                  char gidBuf[11];
218                  const char* gidStr;
219              
220                  /* If no pre-exec program, nothing to do */
221                  if (programPath == NULL)
222                      return 0;
223              
224                  /* Form the UID string */
225                  {
226                      size_t dummy;
227                      uidStr = Uint32ToStr(uidBuf, (PAL_Uint32)uid, &dummy);
228                  }
229              
230                  /* Form the GID string */
231                  {
232 krisbash 1.1         size_t dummy;
233                      gidStr = Uint32ToStr(gidBuf, (PAL_Uint32)gid, &dummy);
234                  }
235              
236                  /* Form a hash key from PREEXEC+UID+GID */
237                  {
238                      key[0] = '\0';
239                      Strlcat(key, programPath, PAL_MAX_PATH_SIZE);
240                      Strlcat(key, "+", PAL_MAX_PATH_SIZE);
241                      Strlcat(key, uidStr, PAL_MAX_PATH_SIZE);
242                      Strlcat(key, "+", PAL_MAX_PATH_SIZE);
243                      Strlcat(key, gidStr, PAL_MAX_PATH_SIZE);
244                  }
245              
246                  /* If key already in cache, then return without doing anything */
247                  {
248                      static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
249              
250                      pthread_mutex_lock(&s_mutex);
251              
252                      if (_Contains(&self->cache, key))
253 krisbash 1.1         {
254                          pthread_mutex_unlock(&s_mutex);
255                          return 0;
256                      }
257              
258                      /* Add key to cache */
259                      _Insert(&self->cache, key);
260                      pthread_mutex_unlock(&s_mutex);
261                  }
262              
263                  /* If programPath is relative, form the full path of the pre-exec program */
264                  {
265                      path[0] = '\0';
266                      if (*programPath != '/')
267                      {
268                          const char* bindir = OMI_GetPath(ID_BINDIR);
269              
270                          if (bindir != NULL)
271                          {
272                              Strlcpy(path, bindir, PAL_MAX_PATH_SIZE);
273                              Strlcat(path, "/", PAL_MAX_PATH_SIZE);
274 krisbash 1.1             }
275                      }
276              
277                      Strlcat(path, programPath, PAL_MAX_PATH_SIZE);
278                  }
279              
280                  /* Execute and wait on the pre-exec program to exit */
281                  _BlockSIGCHLD();
282                  {
283                      pid_t pid = _Exec(path, uidStr, gidStr);
284              
285                      if (pid == -1)
286                      {
287                          _UnblockSIGCHLD();
288                          trace_PreExecFailed(path);
289                          return -1;
290                      }
291              
292                      {
293                          pid_t r;
294                          int status;
295 krisbash 1.1 
296                          r = waitpid(pid, &status, 0);
297              
298                          if (r != pid || WEXITSTATUS(status) != 0)
299                          {
300                              _UnblockSIGCHLD();
301                              trace_PreExecFailed(path);
302                              return -1;
303                          }
304                      }
305                  }
306                  _UnblockSIGCHLD();
307              
308                  trace_PreExecOk(path);
309                  return 0;
310              }

ViewCVS 0.9.2