23 from VirtualMailManager.account import Account |
24 from VirtualMailManager.account import Account |
24 from VirtualMailManager.alias import Alias |
25 from VirtualMailManager.alias import Alias |
25 from VirtualMailManager.aliasdomain import AliasDomain |
26 from VirtualMailManager.aliasdomain import AliasDomain |
26 from VirtualMailManager.common import exec_ok |
27 from VirtualMailManager.common import exec_ok |
27 from VirtualMailManager.config import Config as Cfg |
28 from VirtualMailManager.config import Config as Cfg |
28 from VirtualMailManager.constants import \ |
29 from VirtualMailManager.constants import MIN_GID, MIN_UID, \ |
29 ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \ |
30 ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \ |
30 DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \ |
31 DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \ |
31 FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \ |
32 FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \ |
32 NOT_EXECUTABLE, NO_SUCH_ACCOUNT, NO_SUCH_ALIAS, NO_SUCH_BINARY, \ |
33 NOT_EXECUTABLE, NO_SUCH_ACCOUNT, NO_SUCH_ALIAS, NO_SUCH_BINARY, \ |
33 NO_SUCH_DIRECTORY, NO_SUCH_RELOCATED, RELOCATED_EXISTS |
34 NO_SUCH_DIRECTORY, NO_SUCH_RELOCATED, RELOCATED_EXISTS |
34 from VirtualMailManager.domain import Domain, get_gid |
35 from VirtualMailManager.domain import Domain, get_gid |
35 from VirtualMailManager.emailaddress import EmailAddress |
36 from VirtualMailManager.emailaddress import EmailAddress |
36 from VirtualMailManager.errors import \ |
37 from VirtualMailManager.errors import \ |
37 DomainError, NotRootError, PermissionError, VMMError |
38 DomainError, NotRootError, PermissionError, VMMError |
38 from VirtualMailManager.mailbox import new as new_mailbox |
39 from VirtualMailManager.mailbox import new as new_mailbox |
39 from VirtualMailManager.pycompat import any |
40 from VirtualMailManager.pycompat import all, any |
40 from VirtualMailManager.relocated import Relocated |
41 from VirtualMailManager.relocated import Relocated |
41 from VirtualMailManager.transport import Transport |
42 from VirtualMailManager.transport import Transport |
42 |
43 |
43 |
44 |
44 _ = lambda msg: msg |
45 _ = lambda msg: msg |
226 return Domain(self._dbh, domainname) |
227 return Domain(self._dbh, domainname) |
227 |
228 |
228 def _get_disk_usage(self, directory): |
229 def _get_disk_usage(self, directory): |
229 """Estimate file space usage for the given directory. |
230 """Estimate file space usage for the given directory. |
230 |
231 |
231 Keyword arguments: |
232 Arguments: |
232 directory -- the directory to summarize recursively disk usage for |
233 |
233 """ |
234 `directory` : basestring |
234 if self._isdir(directory): |
235 The directory to summarize recursively disk usage for |
|
236 """ |
|
237 if os.path.isdir(directory): |
235 return Popen([self._cfg.dget('bin.du'), "-hs", directory], |
238 return Popen([self._cfg.dget('bin.du'), "-hs", directory], |
236 stdout=PIPE).communicate()[0].split('\t')[0] |
239 stdout=PIPE).communicate()[0].split('\t')[0] |
237 else: |
240 else: |
|
241 self._warnings.append(_('No such directory: %s') % directory) |
238 return 0 |
242 return 0 |
239 |
|
240 def _isdir(self, directory): |
|
241 """Check if `directory` is a directory. Returns bool. |
|
242 When `directory` isn't a directory, a warning will be appended to |
|
243 _warnings.""" |
|
244 isdir = os.path.isdir(directory) |
|
245 if not isdir: |
|
246 self._warnings.append(_('No such directory: %s') % directory) |
|
247 return isdir |
|
248 |
243 |
249 def _make_domain_dir(self, domain): |
244 def _make_domain_dir(self, domain): |
250 """Create a directory for the `domain` and its accounts.""" |
245 """Create a directory for the `domain` and its accounts.""" |
251 cwd = os.getcwd() |
246 cwd = os.getcwd() |
252 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
247 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
265 os.chdir(account.domain_directory) |
260 os.chdir(account.domain_directory) |
266 os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) |
261 os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) |
267 os.chown('%s' % account.uid, account.uid, account.gid) |
262 os.chown('%s' % account.uid, account.uid, account.gid) |
268 |
263 |
269 def _delete_home(self, domdir, uid, gid): |
264 def _delete_home(self, domdir, uid, gid): |
270 """Delete a user's home directory.""" |
265 """Delete a user's home directory. |
271 if uid > 0 and gid > 0: |
266 |
272 userdir = '%s' % uid |
267 Arguments: |
273 if userdir.count('..') or domdir.count('..'): |
268 |
274 raise VMMError(_(u'Found ".." in home directory path.'), |
269 `domdir` : basestring |
275 FOUND_DOTS_IN_PATH) |
270 The directory of the domain the user belongs to |
276 if os.path.isdir(domdir): |
271 (commonly AccountObj.domain_directory) |
277 os.chdir(domdir) |
272 `uid` : int/long |
278 if os.path.isdir(userdir): |
273 The user's UID (commonly AccountObj.uid) |
279 mdstat = os.stat(userdir) |
274 `gid` : int/long |
280 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
275 The user's GID (commonly AccountObj.gid) |
281 raise VMMError(_(u'Detected owner/group mismatch in ' |
276 """ |
282 u'home directory.'), |
277 assert all(isinstance(xid, (long, int)) for xid in (uid, gid)) and \ |
283 MAILDIR_PERM_MISMATCH) |
278 isinstance(domdir, basestring) |
284 rmtree(userdir, ignore_errors=True) |
279 if uid < MIN_UID or gid < MIN_GID: |
285 else: |
280 raise VMMError(_(u"UID '%(uid)u' and/or GID '%(gid)u' are less " |
286 raise VMMError(_(u"No such directory: %s") % |
281 u"than %(min_uid)u/%(min_gid)u.") % {'uid': uid, |
287 os.path.join(domdir, userdir), |
282 'gid': gid, 'min_gid': MIN_GID, 'min_uid': MIN_UID}, |
288 NO_SUCH_DIRECTORY) |
283 MAILDIR_PERM_MISMATCH) |
|
284 if domdir.count('..'): |
|
285 raise VMMError(_(u'Found ".." in domain directory path: %s') % |
|
286 domdir, FOUND_DOTS_IN_PATH) |
|
287 if not os.path.isdir(domdir): |
|
288 raise VMMError(_(u"No such directory: %s") % domdir, |
|
289 NO_SUCH_DIRECTORY) |
|
290 os.chdir(domdir) |
|
291 userdir = '%s' % uid |
|
292 if not os.path.isdir(userdir): |
|
293 self._warnings.append(_(u"No such directory: %s") % |
|
294 os.path.join(domdir, userdir)) |
|
295 return |
|
296 mdstat = os.lstat(userdir) |
|
297 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
|
298 raise VMMError(_(u'Detected owner/group mismatch in home ' |
|
299 u'directory.'), MAILDIR_PERM_MISMATCH) |
|
300 rmtree(userdir, ignore_errors=True) |
289 |
301 |
290 def _delete_domain_dir(self, domdir, gid): |
302 def _delete_domain_dir(self, domdir, gid): |
291 """Delete a domain's directory.""" |
303 """Delete a domain's directory. |
292 if gid > 0: |
304 |
293 if not self._isdir(domdir): |
305 Arguments: |
294 return |
306 |
295 basedir = self._cfg.dget('misc.base_directory') |
307 `domdir` : basestring |
296 domdirdirs = domdir.replace(basedir + '/', '').split('/') |
308 The domain's directory (commonly DomainObj.directory) |
297 domdirparent = os.path.join(basedir, domdirdirs[0]) |
309 `gid` : int/long |
298 if basedir.count('..') or domdir.count('..'): |
310 The domain's GID (commonly DomainObj.gid) |
299 raise VMMError(_(u'Found ".." in domain directory path.'), |
311 """ |
300 FOUND_DOTS_IN_PATH) |
312 assert isinstance(domdir, basestring) and isinstance(gid, (long, int)) |
301 if os.path.isdir(domdirparent): |
313 if gid < MIN_GID: |
302 os.chdir(domdirparent) |
314 raise VMMError(_(u"GID '%(gid)u' is less than '%(min_gid)u'.") % |
303 if os.lstat(domdirdirs[1]).st_gid != gid: |
315 {'gid': gid, 'min_gid': MIN_GID}, |
304 raise VMMError(_(u'Detected group mismatch in domain ' |
316 DOMAINDIR_GROUP_MISMATCH) |
305 u'directory.'), DOMAINDIR_GROUP_MISMATCH) |
317 if domdir.count('..'): |
306 rmtree(domdirdirs[1], ignore_errors=True) |
318 raise VMMError(_(u'Found ".." in domain directory path: %s') % |
|
319 domdir, FOUND_DOTS_IN_PATH) |
|
320 try: |
|
321 dirst = os.lstat(domdir) |
|
322 except OSError: |
|
323 dirst = None |
|
324 if not dirst or not stat.S_ISDIR(dirst.st_mode): |
|
325 self._warnings.append(_('No such directory: %s') % domdir) |
|
326 return |
|
327 if dirst.st_gid != gid: |
|
328 raise VMMError(_(u'Detected group mismatch in domain directory: ' |
|
329 u'%s') % domdir, DOMAINDIR_GROUP_MISMATCH) |
|
330 rmtree(domdir, ignore_errors=True) |
307 |
331 |
308 def has_warnings(self): |
332 def has_warnings(self): |
309 """Checks if warnings are present, returns bool.""" |
333 """Checks if warnings are present, returns bool.""" |
310 return bool(len(self._warnings)) |
334 return bool(len(self._warnings)) |
311 |
335 |