67 argument may be ``True``. By default it is ``False`` and |
69 argument may be ``True``. By default it is ``False`` and |
68 all checks will be performed. |
70 all checks will be performed. |
69 |
71 |
70 Throws a NotRootError if your uid is greater 0. |
72 Throws a NotRootError if your uid is greater 0. |
71 """ |
73 """ |
72 self._cfgFileName = '' |
74 self._cfg_fname = '' |
73 self.__warnings = [] |
75 self.__warnings = [] |
74 self._Cfg = None |
76 self._cfg = None |
75 self._dbh = None |
77 self._dbh = None |
76 |
78 |
77 if os.geteuid(): |
79 if os.geteuid(): |
78 raise NotRootError(_(u"You are not root.\n\tGood bye!\n"), |
80 raise NotRootError(_(u"You are not root.\n\tGood bye!\n"), |
79 CONF_NOPERM) |
81 CONF_NOPERM) |
80 if self.__chkCfgFile(): |
82 if self.__check_cfg_file(): |
81 self._Cfg = Cfg(self._cfgFileName) |
83 self._cfg = Cfg(self._cfg_fname) |
82 self._Cfg.load() |
84 self._cfg.load() |
83 if not skip_some_checks: |
85 if not skip_some_checks: |
84 self._Cfg.check() |
86 self._cfg.check() |
85 self._chkenv() |
87 self._chkenv() |
86 |
88 |
87 def __findCfgFile(self): |
89 def __find_cfg_file(self): |
88 for path in ['/root', '/usr/local/etc', '/etc']: |
90 """Search the CFG_FILE in CFG_PATH. |
89 tmp = os.path.join(path, 'vmm.cfg') |
91 Raise a VMMError when no vmm.cfg could be found. |
|
92 """ |
|
93 for path in CFG_PATH.split(':'): |
|
94 tmp = os.path.join(path, CFG_FILE) |
90 if os.path.isfile(tmp): |
95 if os.path.isfile(tmp): |
91 self._cfgFileName = tmp |
96 self._cfg_fname = tmp |
92 break |
97 break |
93 if not len(self._cfgFileName): |
98 if not self._cfg_fname: |
94 raise VMMError(_(u"No 'vmm.cfg' found in: " |
99 raise VMMError(_(u"Could not find '%(cfg_file)s' in: " |
95 u"/root:/usr/local/etc:/etc"), CONF_NOFILE) |
100 u"'%(cfg_path)s'") % {'cfg_file': CFG_FILE, |
96 |
101 'cfg_path' : CFG_PATH}, CONF_NOFILE) |
97 def __chkCfgFile(self): |
102 |
|
103 def __check_cfg_file(self): |
98 """Checks the configuration file, returns bool""" |
104 """Checks the configuration file, returns bool""" |
99 self.__findCfgFile() |
105 self.__find_cfg_file() |
100 fstat = os.stat(self._cfgFileName) |
106 fstat = os.stat(self._cfg_fname) |
101 fmode = int(oct(fstat.st_mode & 0777)) |
107 fmode = int(oct(fstat.st_mode & 0777)) |
102 if fmode % 100 and fstat.st_uid != fstat.st_gid or \ |
108 if fmode % 100 and fstat.st_uid != fstat.st_gid or \ |
103 fmode % 10 and fstat.st_uid == fstat.st_gid: |
109 fmode % 10 and fstat.st_uid == fstat.st_gid: |
104 raise PermissionError(_(u"wrong permissions for '%(file)s': " |
110 raise PermissionError(_(u"wrong permissions for '%(file)s': " |
105 u"%(perms)s\n`chmod 0600 %(file)s` would " |
111 u"%(perms)s\n`chmod 0600 %(file)s` would " |
106 u"be great.") % {'file': self._cfgFileName, |
112 u"be great.") % {'file': self._cfg_fname, |
107 'perms': fmode}, CONF_WRONGPERM) |
113 'perms': fmode}, CONF_WRONGPERM) |
108 else: |
114 else: |
109 return True |
115 return True |
110 |
116 |
111 def _chkenv(self): |
117 def _chkenv(self): |
112 """""" |
118 """Make sure our base_directory is a directory and that all |
113 basedir = self._Cfg.dget('misc.base_directory') |
119 required executables exists and are executable. |
|
120 If not, a VMMError will be raised""" |
|
121 basedir = self._cfg.dget('misc.base_directory') |
114 if not os.path.exists(basedir): |
122 if not os.path.exists(basedir): |
115 old_umask = os.umask(0006) |
123 old_umask = os.umask(0006) |
116 os.makedirs(basedir, 0771) |
124 os.makedirs(basedir, 0771) |
117 os.chown(basedir, 0, 0) |
125 os.chown(basedir, 0, 0) |
118 os.umask(old_umask) |
126 os.umask(old_umask) |
119 elif not os.path.isdir(basedir): |
127 elif not os.path.isdir(basedir): |
120 raise VMMError(_(u"'%s' is not a directory.\n(vmm.cfg: section " |
128 raise VMMError(_(u"'%(path)s' is not a directory.\n(%(cfg_file)s: " |
121 u"'misc', option 'base_directory')") % basedir, |
129 u"section 'misc', option 'base_directory')") % |
|
130 {'path': basedir, 'cfg_file': self._cfg_fname}, |
122 NO_SUCH_DIRECTORY) |
131 NO_SUCH_DIRECTORY) |
123 for opt, val in self._Cfg.items('bin'): |
132 for opt, val in self._cfg.items('bin'): |
124 try: |
133 try: |
125 exec_ok(val) |
134 exec_ok(val) |
126 except VMMError, err: |
135 except VMMError, err: |
127 if err.code is NO_SUCH_BINARY: |
136 if err.code is NO_SUCH_BINARY: |
128 raise VMMError(_(u"'%(binary)s' doesn't exist.\n(vmm.cfg: " |
137 raise VMMError(_(u"'%(binary)s' doesn't exist.\n" |
129 u"section 'bin', option '%(option)s')") % |
138 u"(%(cfg_file)s: section 'bin', option " |
130 {'binary': val, 'option': opt}, err.code) |
139 u"'%(option)s')") % {'binary': val, |
|
140 'cfg_file': self._cfg_fname, 'option': opt}, |
|
141 err.code) |
131 elif err.code is NOT_EXECUTABLE: |
142 elif err.code is NOT_EXECUTABLE: |
132 raise VMMError(_(u"'%(binary)s' is not executable.\n" |
143 raise VMMError(_(u"'%(binary)s' is not executable.\n" |
133 u"(vmm.cfg: section 'bin', option " |
144 u"(%(cfg_file)s: section 'bin', option " |
134 u"'%(option)s')") % {'binary': val, |
145 u"'%(option)s')") % {'binary': val, |
135 'option': opt}, err.code) |
146 'cfg_file': self._cfg_fname, 'option': opt}, |
|
147 err.code) |
136 else: |
148 else: |
137 raise |
149 raise |
138 |
150 |
139 def __dbConnect(self): |
151 def __dbConnect(self): |
140 """Creates a pyPgSQL.PgSQL.connection instance.""" |
152 """Creates a pyPgSQL.PgSQL.connection instance.""" |
141 if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and |
153 if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and |
142 not self._dbh._isOpen): |
154 not self._dbh._isOpen): |
143 try: |
155 try: |
144 self._dbh = PgSQL.connect( |
156 self._dbh = PgSQL.connect( |
145 database=self._Cfg.dget('database.name'), |
157 database=self._cfg.dget('database.name'), |
146 user=self._Cfg.pget('database.user'), |
158 user=self._cfg.pget('database.user'), |
147 host=self._Cfg.dget('database.host'), |
159 host=self._cfg.dget('database.host'), |
148 password=self._Cfg.pget('database.pass'), |
160 password=self._cfg.pget('database.pass'), |
149 client_encoding='utf8', unicode_results=True) |
161 client_encoding='utf8', unicode_results=True) |
150 dbc = self._dbh.cursor() |
162 dbc = self._dbh.cursor() |
151 dbc.execute("SET NAMES 'UTF8'") |
163 dbc.execute("SET NAMES 'UTF8'") |
152 dbc.close() |
164 dbc.close() |
153 except PgSQL.libpq.DatabaseError, e: |
165 except PgSQL.libpq.DatabaseError, e: |
228 return isdir |
240 return isdir |
229 |
241 |
230 def __make_domain_dir(self, domain): |
242 def __make_domain_dir(self, domain): |
231 cwd = os.getcwd() |
243 cwd = os.getcwd() |
232 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
244 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
233 os.chdir(self._Cfg.dget('misc.base_directory')) |
245 os.chdir(self._cfg.dget('misc.base_directory')) |
234 if not os.path.isdir(hashdir): |
246 if not os.path.isdir(hashdir): |
235 os.mkdir(hashdir, 0711) |
247 os.mkdir(hashdir, 0711) |
236 os.chown(hashdir, 0, 0) |
248 os.chown(hashdir, 0, 0) |
237 os.mkdir(os.path.join(hashdir, domdir), |
249 os.mkdir(os.path.join(hashdir, domdir), |
238 self._Cfg.dget('domain.directory_mode')) |
250 self._cfg.dget('domain.directory_mode')) |
239 os.chown(domain.directory, 0, domain.gid) |
251 os.chown(domain.directory, 0, domain.gid) |
240 os.chdir(cwd) |
252 os.chdir(cwd) |
241 |
253 |
242 def __make_home(self, account): |
254 def __make_home(self, account): |
243 """Create a home directory for the new Account *account*.""" |
255 """Create a home directory for the new Account *account*.""" |
244 os.umask(0007) |
256 os.umask(0007) |
245 os.chdir(account.domain_directory) |
257 os.chdir(account.domain_directory) |
246 os.mkdir('%s' % account.uid, self._Cfg.dget('account.directory_mode')) |
258 os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) |
247 os.chown('%s' % account.uid, account.uid, account.gid) |
259 os.chown('%s' % account.uid, account.uid, account.gid) |
248 |
260 |
249 def __userDirDelete(self, domdir, uid, gid): |
261 def __userDirDelete(self, domdir, uid, gid): |
250 if uid > 0 and gid > 0: |
262 if uid > 0 and gid > 0: |
251 userdir = '%s' % uid |
263 userdir = '%s' % uid |
298 |
310 |
299 def cfg_dget(self, option): |
311 def cfg_dget(self, option): |
300 """Get the configured value of the *option* (section.option). |
312 """Get the configured value of the *option* (section.option). |
301 When the option was not configured its default value will be |
313 When the option was not configured its default value will be |
302 returned.""" |
314 returned.""" |
303 return self._Cfg.dget(option) |
315 return self._cfg.dget(option) |
304 |
316 |
305 def cfg_pget(self, option): |
317 def cfg_pget(self, option): |
306 """Get the configured value of the *option* (section.option).""" |
318 """Get the configured value of the *option* (section.option).""" |
307 return self._Cfg.pget(option) |
319 return self._cfg.pget(option) |
308 |
320 |
309 def cfg_install(self): |
321 def cfg_install(self): |
310 """Installs the cfg_dget method as ``cfg_dget`` into the built-in |
322 """Installs the cfg_dget method as ``cfg_dget`` into the built-in |
311 namespace.""" |
323 namespace.""" |
312 import __builtin__ |
324 import __builtin__ |
313 assert 'cfg_dget' not in __builtin__.__dict__ |
325 assert 'cfg_dget' not in __builtin__.__dict__ |
314 __builtin__.__dict__['cfg_dget'] = self._Cfg.dget |
326 __builtin__.__dict__['cfg_dget'] = self._cfg.dget |
315 |
327 |
316 def domainAdd(self, domainname, transport=None): |
328 def domainAdd(self, domainname, transport=None): |
317 dom = self.__getDomain(domainname) |
329 dom = self.__getDomain(domainname) |
318 if transport is None: |
330 if transport is None: |
319 dom.set_transport(Transport(self._dbh, |
331 dom.set_transport(Transport(self._dbh, |
320 transport=self._Cfg.dget('misc.transport'))) |
332 transport=self._cfg.dget('misc.transport'))) |
321 else: |
333 else: |
322 dom.set_transport(Transport(self._dbh, transport=transport)) |
334 dom.set_transport(Transport(self._dbh, transport=transport)) |
323 dom.set_directory(self._Cfg.dget('misc.base_directory')) |
335 dom.set_directory(self._cfg.dget('misc.base_directory')) |
324 dom.save() |
336 dom.save() |
325 self.__make_domain_dir(dom) |
337 self.__make_domain_dir(dom) |
326 |
338 |
327 def domainTransport(self, domainname, transport, force=None): |
339 def domainTransport(self, domainname, transport, force=None): |
328 if force is not None and force != 'force': |
340 if force is not None and force != 'force': |
340 raise DomainError(_(u"Invalid argument: '%s'") % force, |
352 raise DomainError(_(u"Invalid argument: '%s'") % force, |
341 INVALID_ARGUMENT) |
353 INVALID_ARGUMENT) |
342 dom = self.__getDomain(domainname) |
354 dom = self.__getDomain(domainname) |
343 gid = dom.gid |
355 gid = dom.gid |
344 domdir = dom.directory |
356 domdir = dom.directory |
345 if self._Cfg.dget('domain.force_deletion') or force == 'delall': |
357 if self._cfg.dget('domain.force_deletion') or force == 'delall': |
346 dom.delete(True, True) |
358 dom.delete(True, True) |
347 elif force == 'deluser': |
359 elif force == 'deluser': |
348 dom.delete(deluser=True) |
360 dom.delete(deluser=True) |
349 elif force == 'delalias': |
361 elif force == 'delalias': |
350 dom.delete(delalias=True) |
362 dom.delete(delalias=True) |
351 else: |
363 else: |
352 dom.delete() |
364 dom.delete() |
353 if self._Cfg.dget('domain.delete_directory'): |
365 if self._cfg.dget('domain.delete_directory'): |
354 self.__domDirDelete(domdir, gid) |
366 self.__domDirDelete(domdir, gid) |
355 |
367 |
356 def domainInfo(self, domainname, details=None): |
368 def domainInfo(self, domainname, details=None): |
357 if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', |
369 if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', |
358 'relocated']: |
370 'relocated']: |