Subversion Repositories public

Rev

Rev 65 | Rev 69 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 65 Rev 67
Line 23... Line 23...
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();
Line 159... Line 290...
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;
Line 216... Line 347...
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
    }
Line 338... Line 483...
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)