Subversion Repositories public

Rev

Rev 65 | Rev 69 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 65 Rev 67
1
1
2
/// inotify cron daemon user tables implementation
2
/// inotify cron daemon user tables implementation
3
/**
3
/**
4
 * \file usertable.cpp
4
 * \file usertable.cpp
5
 *
5
 *
6
 * inotify cron system
6
 * inotify cron system
7
 *
7
 *
8
 * Copyright (C) 2006, 2007 Lukas Jelinek, <lukas@aiken.cz>
8
 * Copyright (C) 2006, 2007 Lukas Jelinek, <lukas@aiken.cz>
9
 *
9
 *
10
 * This program is free software; you can use it, redistribute
10
 * This program is free software; you can use it, redistribute
11
 * it and/or modify it under the terms of the GNU General Public
11
 * it and/or modify it under the terms of the GNU General Public
12
 * License, version 2 (see LICENSE-GPL).
12
 * License, version 2 (see LICENSE-GPL).
13
 *  
13
 *  
14
 */
14
 */
15
15
16
16
17
#include <pwd.h>
17
#include <pwd.h>
18
#include <syslog.h>
18
#include <syslog.h>
19
#include <errno.h>
19
#include <errno.h>
20
#include <sys/wait.h>
20
#include <sys/wait.h>
21
#include <unistd.h>
21
#include <unistd.h>
22
#include <grp.h>
22
#include <grp.h>
23
#include <sys/stat.h>
23
#include <sys/stat.h>
24
24
25
#include "usertable.h"
25
#include "usertable.h"
26
26
27
#ifdef IN_DONT_FOLLOW
27
#ifdef IN_DONT_FOLLOW
28
#define NO_FOLLOW(mask) InotifyEvent::IsType(mask, IN_DONT_FOLLOW)
28
#define DONT_FOLLOW(mask) InotifyEvent::IsType(mask, IN_DONT_FOLLOW)
29
#else // IN_DONT_FOLLOW
29
#else // IN_DONT_FOLLOW
30
#define NO_FOLLOW(mask) (false)
30
#define DONT_FOLLOW(mask) (false)
31
#endif // IN_DONT_FOLLOW
31
#endif // IN_DONT_FOLLOW
32
32
33
33
34
PROC_LIST UserTable::s_procList;
34
PROC_LIST UserTable::s_procList;
35
35
-
 
36
extern volatile bool g_fFinish;
-
 
37
extern SUT_MAP g_ut;
-
 
38
36
39
37
void on_proc_done(InotifyWatch* pW)
40
void on_proc_done(InotifyWatch* pW)
38
{
41
{
39
  pW->SetEnabled(true);
42
  pW->SetEnabled(true);
40
}
43
}
41
44
42
45
43
EventDispatcher::EventDispatcher(Inotify* pIn)
46
EventDispatcher::EventDispatcher(int iPipeFd, Inotify* pIn, InotifyWatch* pSys, InotifyWatch* pUser)
44
{
47
{
-
 
48
  m_iPipeFd = iPipeFd;
-
 
49
  m_iMgmtFd = pIn->GetDescriptor();
45
 m_pIn = pIn;
50
  m_pIn = pIn;
-
 
51
  m_pSys = pSys;
-
 
52
  m_pUser = pUser;
-
 
53
  m_size = 0;
-
 
54
  m_pPoll = NULL;
46
}
55
}
47
56
48
void EventDispatcher::DispatchEvent(InotifyEvent& rEvt)
57
EventDispatcher::~EventDispatcher()
49
{
58
{
50
  if (m_pIn == NULL)
59
  if (m_pPoll != NULL)
51
    return;
60
    delete[] m_pPoll;
-
 
61
}
52
   
62
53
  InotifyWatch* pW = rEvt.GetWatch();
63
bool EventDispatcher::ProcessEvents()
-
 
64
{
-
 
65
  // consume pipe events if any (and report back)
-
 
66
  bool pipe = (m_pPoll[0].revents & POLLIN);
54
  if (pW == NULL)
67
  if (pipe) {
55
    return;
68
    char c;
-
 
69
    while (read(m_pPoll[0].fd, &c, 1) > 0) {}
-
 
70
    m_pPoll[0].revents = 0;
-
 
71
  }
56
   
72
 
57
  UserTable* pT = FindTable(pW);
73
  // process table management events if any
58
  if (pT == NULL)
74
  if (m_pPoll[1].revents & POLLIN) {
59
    return;
75
    ProcessMgmtEvents();
-
 
76
    m_pPoll[1].revents = 0;
-
 
77
  }
-
 
78
   
-
 
79
  InotifyEvent evt;
-
 
80
   
-
 
81
  for (size_t i=2; i<m_size; i++) {
-
 
82
   
-
 
83
    // process events if occurred
-
 
84
    if (m_pPoll[i].revents & POLLIN) {
-
 
85
      FDUT_MAP::iterator it = m_maps.find(m_pPoll[i].fd);
-
 
86
      if (it != m_maps.end()) {
-
 
87
        Inotify* pIn = ((*it).second)->GetInotify();
-
 
88
        pIn->WaitForEvents(true);
60
   
89
       
-
 
90
        // process events for this object
-
 
91
        while (pIn->GetEvent(evt)) {
61
  pT->OnEvent(rEvt);
92
          ((*it).second)->OnEvent(evt);
-
 
93
        }
-
 
94
      }
-
 
95
      m_pPoll[i].revents = 0;
-
 
96
    }
62
}
97
  }
63
 
98
   
64
void EventDispatcher::Register(InotifyWatch* pWatch, UserTable* pTab)
-
 
65
{
-
 
66
  if (pWatch != NULL && pTab != NULL)
99
  return pipe;
67
    m_maps.insert(IWUT_MAP::value_type(pWatch, pTab));
-
 
68
}
100
}
69
 
101
 
70
void EventDispatcher::Unregister(InotifyWatch* pWatch)
102
void EventDispatcher::Register(UserTable* pTab)
71
{
103
{
-
 
104
  if (pTab != NULL) {
72
  IWUT_MAP::iterator it = m_maps.find(pWatch);
105
    Inotify* pIn = pTab->GetInotify();
73
  if (it == m_maps.end())
106
    if (pIn != NULL) {
-
 
107
      int fd = pIn->GetDescriptor();
-
 
108
      if (fd != -1) {
-
 
109
        m_maps.insert(FDUT_MAP::value_type(fd, pTab));
74
    m_maps.erase(it);
110
        Rebuild();
-
 
111
      }
-
 
112
    }
-
 
113
  }
75
}
114
}
76
 
115
 
77
void EventDispatcher::UnregisterAll(UserTable* pTab)
116
void EventDispatcher::Unregister(UserTable* pTab)
78
{
117
{
79
  IWUT_MAP::iterator it = m_maps.begin();
118
  FDUT_MAP::iterator it = m_maps.find(pTab->GetInotify()->GetDescriptor());
80
  while (it != m_maps.end()) {
119
  if (it != m_maps.end()) {
81
    if ((*it).second == pTab) {
-
 
82
      IWUT_MAP::iterator it2 = it;
120
    m_maps.erase(it);
83
      it++;
121
    Rebuild();
84
      m_maps.erase(it2);
-
 
85
    }
122
  }
86
    else {
-
 
87
      it++;
-
 
88
    }
123
}
-
 
124
-
 
125
void EventDispatcher::Rebuild()
-
 
126
{
-
 
127
  // delete old data if exists
-
 
128
  if (m_pPoll != NULL)
-
 
129
    delete[] m_pPoll;
-
 
130
   
-
 
131
  // allocate memory
-
 
132
  m_size = m_maps.size() + 2;
-
 
133
  m_pPoll = new struct pollfd[m_size];
-
 
134
 
-
 
135
  // add pipe descriptor
-
 
136
  m_pPoll[0].fd = m_iPipeFd;
-
 
137
  m_pPoll[0].events = POLLIN;
-
 
138
  m_pPoll[0].revents = 0;
-
 
139
 
-
 
140
  // add table management descriptor
-
 
141
  m_pPoll[1].fd = m_iMgmtFd;
-
 
142
  m_pPoll[1].events = POLLIN;
-
 
143
  m_pPoll[1].revents = 0;
-
 
144
 
-
 
145
  // add all inotify descriptors
-
 
146
  FDUT_MAP::iterator it = m_maps.begin();
-
 
147
  for (size_t i=2; i<m_size; i++, it++) {
-
 
148
    m_pPoll[i].fd = (*it).first;
-
 
149
    m_pPoll[i].events = POLLIN;
-
 
150
    m_pPoll[i].revents = 0;
89
  }
151
  }
90
}
152
}
91
153
92
UserTable* EventDispatcher::FindTable(InotifyWatch* pW)
154
void EventDispatcher::ProcessMgmtEvents()
93
{
155
{
94
  IWUT_MAP::iterator it = m_maps.find(pW);
-
 
95
  if (it == m_maps.end())
156
  m_pIn->WaitForEvents(true);
96
    return NULL;
-
 
97
   
157
 
-
 
158
  InotifyEvent e;
-
 
159
 
-
 
160
  while (m_pIn->GetEvent(e)) {
-
 
161
    if (e.GetWatch() == m_pSys) {
-
 
162
      if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
-
 
163
        syslog(LOG_CRIT, "base directory destroyed, exitting");
-
 
164
        g_fFinish = true;
-
 
165
      }
-
 
166
      else if (!e.GetName().empty()) {
-
 
167
        SUT_MAP::iterator it = g_ut.find(m_pSys->GetPath() + e.GetName());
-
 
168
        if (it != g_ut.end()) {
-
 
169
          UserTable* pUt = (*it).second;
-
 
170
          if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
171
            syslog(LOG_INFO, "system table %s changed, reloading", e.GetName().c_str());
-
 
172
            pUt->Dispose();
-
 
173
            pUt->Load();
-
 
174
          }
-
 
175
          else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) {
-
 
176
            syslog(LOG_INFO, "system table %s destroyed, removing", e.GetName().c_str());
-
 
177
            delete pUt;
-
 
178
            g_ut.erase(it);
-
 
179
          }
-
 
180
        }
-
 
181
        else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
182
          syslog(LOG_INFO, "system table %s created, loading", e.GetName().c_str());
-
 
183
          UserTable* pUt = new UserTable(this, e.GetName(), true);
-
 
184
          g_ut.insert(SUT_MAP::value_type(std::string(INCRON_SYS_TABLE_BASE) + e.GetName(), pUt));
-
 
185
          pUt->Load();
-
 
186
        }
-
 
187
      }
-
 
188
    }
-
 
189
    else if (e.GetWatch() == m_pUser) {
-
 
190
      if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
-
 
191
        syslog(LOG_CRIT, "base directory destroyed, exitting");
-
 
192
        g_fFinish = true;
-
 
193
      }
-
 
194
      else if (!e.GetName().empty()) {
-
 
195
        SUT_MAP::iterator it = g_ut.find(m_pUser->GetPath() + e.GetName());
-
 
196
        if (it != g_ut.end()) {
98
  return (*it).second;
197
          UserTable* pUt = (*it).second;
-
 
198
          if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
199
            syslog(LOG_INFO, "table for user %s changed, reloading", e.GetName().c_str());
-
 
200
            pUt->Dispose();
-
 
201
            pUt->Load();
-
 
202
          }
-
 
203
          else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) {
-
 
204
            syslog(LOG_INFO, "table for user %s destroyed, removing",  e.GetName().c_str());
-
 
205
            delete pUt;
-
 
206
            g_ut.erase(it);
-
 
207
          }
-
 
208
        }
-
 
209
        else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
210
          if (UserTable::CheckUser(e.GetName().c_str())) {
-
 
211
            syslog(LOG_INFO, "table for user %s created, loading", e.GetName().c_str());
-
 
212
            UserTable* pUt = new UserTable(this, e.GetName(), false);
-
 
213
            g_ut.insert(SUT_MAP::value_type(std::string(INCRON_USER_TABLE_BASE) + e.GetName(), pUt));
-
 
214
            pUt->Load();
-
 
215
          }
-
 
216
        }
-
 
217
      }
-
 
218
    }
-
 
219
  }
99
}
220
}
100
221
101
222
102
223
103
224
104
UserTable::UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser)
225
UserTable::UserTable(EventDispatcher* pEd, const std::string& rUser, bool fSysTable)
105
: m_user(rUser)
226
: m_user(rUser),
-
 
227
  m_fSysTable(fSysTable)
106
{
228
{
107
  m_pIn = pIn;
-
 
108
  m_pEd = pEd;
229
  m_pEd = pEd;
-
 
230
 
-
 
231
  m_in.SetNonBlock(true);
-
 
232
  m_in.SetCloseOnExec(true);
109
}
233
}
110
234
111
UserTable::~UserTable()
235
UserTable::~UserTable()
112
{
236
{
113
  Dispose();
237
  Dispose();
114
}
238
}
115
 
239
 
116
void UserTable::Load()
240
void UserTable::Load()
117
{
241
{
-
 
242
  m_tab.Load(m_fSysTable
-
 
243
      ? InCronTab::GetSystemTablePath(m_user)
118
  m_tab.Load(InCronTab::GetUserTablePath(m_user));
244
      : InCronTab::GetUserTablePath(m_user));
119
 
245
 
120
  int cnt = m_tab.GetCount();
246
  int cnt = m_tab.GetCount();
121
  for (int i=0; i<cnt; i++) {
247
  for (int i=0; i<cnt; i++) {
122
    InCronTabEntry& rE = m_tab.GetEntry(i);
248
    InCronTabEntry& rE = m_tab.GetEntry(i);
123
    InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask());
249
    InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask());
124
   
250
   
125
    // warning only - permissions may change later
251
    // warning only - permissions may change later
126
    if (!MayAccess(rE.GetPath(), NO_FOLLOW(rE.GetMask())))
252
    if (!(m_fSysTable || MayAccess(rE.GetPath(), DONT_FOLLOW(rE.GetMask()))))
127
      syslog(LOG_WARNING, "access denied on %s - events will be discarded silently", rE.GetPath().c_str());
253
      syslog(LOG_WARNING, "access denied on %s - events will be discarded silently", rE.GetPath().c_str());
128
   
254
   
129
    try {
255
    try {
130
      m_pIn->Add(pW);
256
      m_in.Add(pW);
131
      m_pEd->Register(pW, this);
-
 
132
      m_map.insert(IWCE_MAP::value_type(pW, &rE));
257
      m_map.insert(IWCE_MAP::value_type(pW, &rE));
133
    } catch (InotifyException e) {
258
    } catch (InotifyException e) {
-
 
259
      if (m_fSysTable)
-
 
260
        syslog(LOG_ERR, "cannot create watch for system table %s: (%i) %s", m_user.c_str(), e.GetErrorNumber(), strerror(e.GetErrorNumber()));
-
 
261
      else
134
      syslog(LOG_ERR, "cannot create watch for user %s", m_user.c_str());
262
        syslog(LOG_ERR, "cannot create watch for user %s: (%i) %s", m_user.c_str(), e.GetErrorNumber(), strerror(e.GetErrorNumber()));
135
      delete pW;
263
      delete pW;
136
    }
264
    }
137
  }
265
  }
-
 
266
 
-
 
267
  m_pEd->Register(this);
138
}
268
}
139
269
140
void UserTable::Dispose()
270
void UserTable::Dispose()
141
{
271
{
-
 
272
  m_pEd->Unregister(this);
-
 
273
 
142
  IWCE_MAP::iterator it = m_map.begin();
274
  IWCE_MAP::iterator it = m_map.begin();
143
  while (it != m_map.end()) {
275
  while (it != m_map.end()) {
144
    InotifyWatch* pW = (*it).first;
276
    InotifyWatch* pW = (*it).first;
145
    m_pEd->Unregister(pW);
-
 
146
    m_pIn->Remove(pW);
277
    m_in.Remove(pW);
147
    delete pW;
278
    delete pW;
148
    it++;
279
    it++;
149
  }
280
  }
150
 
281
 
151
  m_map.clear();
282
  m_map.clear();
152
}
283
}
153
 
284
 
154
void UserTable::OnEvent(InotifyEvent& rEvt)
285
void UserTable::OnEvent(InotifyEvent& rEvt)
155
{
286
{
156
  InotifyWatch* pW = rEvt.GetWatch();
287
  InotifyWatch* pW = rEvt.GetWatch();
157
  InCronTabEntry* pE = FindEntry(pW);
288
  InCronTabEntry* pE = FindEntry(pW);
158
 
289
 
159
  // no entry found - this shouldn't occur
290
  // no entry found - this shouldn't occur
160
  if (pE == NULL)
291
  if (pE == NULL)
161
    return;
292
    return;
162
 
293
 
163
  // discard event if user has no access rights to watch path
294
  // discard event if user has no access rights to watch path
164
  if (!MayAccess(pW->GetPath(), NO_FOLLOW(rEvt.GetMask())))
295
  if (!(m_fSysTable || MayAccess(pW->GetPath(), DONT_FOLLOW(rEvt.GetMask()))))
165
    return;
296
    return;
166
 
297
 
167
  std::string cmd;
298
  std::string cmd;
168
  const std::string& cs = pE->GetCmd();
299
  const std::string& cs = pE->GetCmd();
169
  size_t pos = 0;
300
  size_t pos = 0;
170
  size_t oldpos = 0;
301
  size_t oldpos = 0;
171
  size_t len = cs.length();
302
  size_t len = cs.length();
172
  while ((pos = cs.find('$', oldpos)) != std::string::npos) {
303
  while ((pos = cs.find('$', oldpos)) != std::string::npos) {
173
    if (pos < len - 1) {
304
    if (pos < len - 1) {
174
      size_t px = pos + 1;
305
      size_t px = pos + 1;
175
      if (cs[px] == '$') {
306
      if (cs[px] == '$') {
176
        cmd.append(cs.substr(oldpos, pos-oldpos+1));
307
        cmd.append(cs.substr(oldpos, pos-oldpos+1));
177
        oldpos = pos + 2;
308
        oldpos = pos + 2;
178
      }
309
      }
179
      else {
310
      else {
180
        cmd.append(cs.substr(oldpos, pos-oldpos));
311
        cmd.append(cs.substr(oldpos, pos-oldpos));
181
        if (cs[px] == '@') {          // base path
312
        if (cs[px] == '@') {          // base path
182
          cmd.append(pW->GetPath());
313
          cmd.append(pW->GetPath());
183
          oldpos = pos + 2;
314
          oldpos = pos + 2;
184
        }
315
        }
185
        else if (cs[px] == '#') {     // file name
316
        else if (cs[px] == '#') {     // file name
186
          cmd.append(rEvt.GetName());
317
          cmd.append(rEvt.GetName());
187
          oldpos = pos + 2;
318
          oldpos = pos + 2;
188
        }
319
        }
189
        else if (cs[px] == '%') {     // mask symbols
320
        else if (cs[px] == '%') {     // mask symbols
190
          std::string s;
321
          std::string s;
191
          rEvt.DumpTypes(s);
322
          rEvt.DumpTypes(s);
192
          cmd.append(s);
323
          cmd.append(s);
193
          oldpos = pos + 2;
324
          oldpos = pos + 2;
194
        }
325
        }
195
        else if (cs[px] == '&') {     // numeric mask
326
        else if (cs[px] == '&') {     // numeric mask
196
          char* s;
327
          char* s;
197
          asprintf(&s, "%u", (unsigned) rEvt.GetMask());
328
          asprintf(&s, "%u", (unsigned) rEvt.GetMask());
198
          cmd.append(s);
329
          cmd.append(s);
199
          free(s);
330
          free(s);
200
          oldpos = pos + 2;
331
          oldpos = pos + 2;
201
        }
332
        }
202
        else {
333
        else {
203
          oldpos = pos + 1;
334
          oldpos = pos + 1;
204
        }
335
        }
205
      }
336
      }
206
    }
337
    }
207
    else {
338
    else {
208
      cmd.append(cs.substr(oldpos, pos-oldpos));
339
      cmd.append(cs.substr(oldpos, pos-oldpos));
209
      oldpos = pos + 1;
340
      oldpos = pos + 1;
210
    }
341
    }
211
  }    
342
  }    
212
  cmd.append(cs.substr(oldpos));
343
  cmd.append(cs.substr(oldpos));
213
 
344
 
214
  int argc;
345
  int argc;
215
  char** argv;
346
  char** argv;
216
  if (!PrepareArgs(cmd, argc, argv)) {
347
  if (!PrepareArgs(cmd, argc, argv)) {
217
    syslog(LOG_ERR, "cannot prepare command arguments");
348
    syslog(LOG_ERR, "cannot prepare command arguments");
218
    return;
349
    return;
219
  }
350
  }
220
 
351
 
-
 
352
  if (m_fSysTable)
-
 
353
    syslog(LOG_INFO, "(system::%s) CMD (%s)", m_user.c_str(), cmd.c_str());
-
 
354
  else
221
  syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());
355
    syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());
222
 
356
 
223
  if (pE->IsNoLoop())
357
  if (pE->IsNoLoop())
224
    pW->SetEnabled(false);
358
    pW->SetEnabled(false);
225
 
359
 
226
  ProcData_t pd;
360
  ProcData_t pd;
227
  pd.pid = fork();
361
  pd.pid = fork();
228
  if (pd.pid == 0) {
362
  if (pd.pid == 0) {
229
   
363
   
-
 
364
    // for system table
-
 
365
    if (m_fSysTable) {
-
 
366
      if (execvp(argv[0], argv) != 0) // exec failed
-
 
367
      {
-
 
368
        syslog(LOG_ERR, "cannot exec process: %s", strerror(errno));
-
 
369
        _exit(1);
-
 
370
      }
-
 
371
    }
-
 
372
    else {
-
 
373
      // for user table
230
    struct passwd* pwd = getpwnam(m_user.c_str());
374
      struct passwd* pwd = getpwnam(m_user.c_str());
231
    if (    pwd == NULL                 // user not found
375
      if (    pwd == NULL                 // user not found
232
        ||  setgid(pwd->pw_gid) != 0    // setting GID failed
376
          ||  setgid(pwd->pw_gid) != 0    // setting GID failed
233
        ||  setuid(pwd->pw_uid) != 0    // setting UID failed
377
          ||  setuid(pwd->pw_uid) != 0    // setting UID failed
234
        ||  execvp(argv[0], argv) != 0) // exec failed
378
          ||  execvp(argv[0], argv) != 0) // exec failed
235
    {
379
      {
236
      syslog(LOG_ERR, "cannot exec process: %s", strerror(errno));
380
        syslog(LOG_ERR, "cannot exec process: %s", strerror(errno));
237
      _exit(1);
381
        _exit(1);
238
    }
382
      }
239
  }
383
    }
-
 
384
  }
240
  else if (pd.pid > 0) {
385
  else if (pd.pid > 0) {
241
    if (pE->IsNoLoop()) {
386
    if (pE->IsNoLoop()) {
242
      pd.onDone = on_proc_done;
387
      pd.onDone = on_proc_done;
243
      pd.pWatch = pW;
388
      pd.pWatch = pW;
244
    }
389
    }
245
    else {
390
    else {
246
      pd.onDone = NULL;
391
      pd.onDone = NULL;
247
      pd.pWatch = NULL;
392
      pd.pWatch = NULL;
248
    }
393
    }
249
   
394
   
250
    s_procList.push_back(pd);
395
    s_procList.push_back(pd);
251
  }
396
  }
252
  else {
397
  else {
253
    if (pE->IsNoLoop())
398
    if (pE->IsNoLoop())
254
      pW->SetEnabled(true);
399
      pW->SetEnabled(true);
255
     
400
     
256
    syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
401
    syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
257
  }
402
  }
258
 
403
 
259
  CleanupArgs(argc, argv);
404
  CleanupArgs(argc, argv);
260
}
405
}
261
406
262
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch)
407
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch)
263
{
408
{
264
  IWCE_MAP::iterator it = m_map.find(pWatch);
409
  IWCE_MAP::iterator it = m_map.find(pWatch);
265
  if (it == m_map.end())
410
  if (it == m_map.end())
266
    return NULL;
411
    return NULL;
267
   
412
   
268
  return (*it).second;
413
  return (*it).second;
269
}
414
}
270
415
271
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv)
416
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv)
272
{
417
{
273
  if (rCmd.empty())
418
  if (rCmd.empty())
274
    return false;
419
    return false;
275
   
420
   
276
  StringTokenizer tok(rCmd, ' ', '\\');
421
  StringTokenizer tok(rCmd, ' ', '\\');
277
  std::deque<std::string> args;
422
  std::deque<std::string> args;
278
  while (tok.HasMoreTokens()) {
423
  while (tok.HasMoreTokens()) {
279
    args.push_back(tok.GetNextToken());
424
    args.push_back(tok.GetNextToken());
280
  }
425
  }
281
 
426
 
282
  if (args.empty())
427
  if (args.empty())
283
    return false;
428
    return false;
284
 
429
 
285
  argc = (int) args.size();
430
  argc = (int) args.size();
286
  argv = new char*[argc+1];
431
  argv = new char*[argc+1];
287
  argv[argc] = NULL;
432
  argv[argc] = NULL;
288
 
433
 
289
  for (int i=0; i<argc; i++) {
434
  for (int i=0; i<argc; i++) {
290
    const std::string& s = args[i];
435
    const std::string& s = args[i];
291
    size_t len = s.length();
436
    size_t len = s.length();
292
    argv[i] = new char[len+1];
437
    argv[i] = new char[len+1];
293
    strcpy(argv[i], s.c_str());
438
    strcpy(argv[i], s.c_str());
294
  }
439
  }
295
 
440
 
296
  return true;
441
  return true;
297
}
442
}
298
443
299
void UserTable::CleanupArgs(int argc, char** argv)
444
void UserTable::CleanupArgs(int argc, char** argv)
300
{
445
{
301
  for (int i=0; i<argc; i++) {
446
  for (int i=0; i<argc; i++) {
302
    delete[] argv[i];
447
    delete[] argv[i];
303
  }
448
  }
304
 
449
 
305
  delete[] argv;
450
  delete[] argv;
306
}
451
}
307
452
308
void UserTable::FinishDone()
453
void UserTable::FinishDone()
309
{
454
{
310
  PROC_LIST::iterator it = s_procList.begin();
455
  PROC_LIST::iterator it = s_procList.begin();
311
  while (it != s_procList.end()) {
456
  while (it != s_procList.end()) {
312
    ProcData_t& pd = *it;
457
    ProcData_t& pd = *it;
313
    int status = 0;
458
    int status = 0;
314
    int res = waitpid(pd.pid, &status, WNOHANG);
459
    int res = waitpid(pd.pid, &status, WNOHANG);
315
    if (res == pd.pid && (WIFEXITED(status) || WIFSIGNALED(status))) {
460
    if (res == pd.pid && (WIFEXITED(status) || WIFSIGNALED(status))) {
316
      if (pd.onDone != NULL)
461
      if (pd.onDone != NULL)
317
        (*pd.onDone)(pd.pWatch);
462
        (*pd.onDone)(pd.pWatch);
318
      it = s_procList.erase(it);
463
      it = s_procList.erase(it);
319
    }
464
    }
320
    else {
465
    else {
321
      it++;
466
      it++;
322
    }
467
    }
323
  }  
468
  }  
324
}
469
}
325
470
326
bool UserTable::MayAccess(const std::string& rPath, bool fNoFollow) const
471
bool UserTable::MayAccess(const std::string& rPath, bool fNoFollow) const
327
{
472
{
328
  // first, retrieve file permissions
473
  // first, retrieve file permissions
329
  struct stat st;
474
  struct stat st;
330
  int res = fNoFollow
475
  int res = fNoFollow
331
      ? lstat(rPath.c_str(), &st) // don't follow symlink
476
      ? lstat(rPath.c_str(), &st) // don't follow symlink
332
      : stat(rPath.c_str(), &st);
477
      : stat(rPath.c_str(), &st);
333
  if (res != 0)
478
  if (res != 0)
334
    return false; // retrieving permissions failed
479
    return false; // retrieving permissions failed
335
 
480
 
336
  // file accessible to everyone
481
  // file accessible to everyone
337
  if (st.st_mode & S_IRWXO)
482
  if (st.st_mode & S_IRWXO)
338
    return true;
483
    return true;
339
 
484
 
340
  // retrieve user data
485
  // retrieve user data
341
  struct passwd* pwd = getpwnam(m_user.c_str());
486
  struct passwd* pwd = getpwnam(m_user.c_str());
342
 
487
 
-
 
488
  // root may always access
-
 
489
  if (pwd->pw_uid == 0)
-
 
490
    return true;
-
 
491
 
343
  // file accesible to group
492
  // file accesible to group
344
  if (st.st_mode & S_IRWXG) {
493
  if (st.st_mode & S_IRWXG) {
345
   
494
   
346
    // user's primary group
495
    // user's primary group
347
    if (pwd != NULL && pwd->pw_gid == st.st_gid)
496
    if (pwd != NULL && pwd->pw_gid == st.st_gid)
348
        return true;
497
        return true;
349
   
498
   
350
    // now check group database
499
    // now check group database
351
    struct group *gr = getgrgid(st.st_gid);
500
    struct group *gr = getgrgid(st.st_gid);
352
    if (gr != NULL) {
501
    if (gr != NULL) {
353
      int pos = 0;
502
      int pos = 0;
354
      const char* un;
503
      const char* un;
355
      while ((un = gr->gr_mem[pos]) != NULL) {
504
      while ((un = gr->gr_mem[pos]) != NULL) {
356
        if (strcmp(un, m_user.c_str()) == 0)
505
        if (strcmp(un, m_user.c_str()) == 0)
357
          return true;
506
          return true;
358
        pos++;
507
        pos++;
359
      }
508
      }
360
    }
509
    }
361
  }
510
  }
362
 
511
 
363
  // file accessible to owner
512
  // file accessible to owner
364
  if (st.st_mode & S_IRWXU) {  
513
  if (st.st_mode & S_IRWXU) {  
365
    if (pwd != NULL && pwd->pw_uid == st.st_uid)
514
    if (pwd != NULL && pwd->pw_uid == st.st_uid)
366
      return true;
515
      return true;
367
  }
516
  }
368
 
517
 
369
  return false; // no access right found
518
  return false; // no access right found
370
}
519
}
371
520
372
521
373
522
374
 
523