Subversion Repositories public

Rev

Rev 67 | Rev 77 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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