- mail related tables in database schema
- gpg encryption for mails - domain creation and deletion completed - logging - use pwd and grp git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/gnuviech.info/gnuviechadmin/trunk@230 a67ec6bc-e5d5-0310-a910-815c51eb3124
This commit is contained in:
		
							parent
							
								
									3f4457bdca
								
							
						
					
					
						commit
						fdea3217c8
					
				
					 28 changed files with 877 additions and 323 deletions
				
			
		
							
								
								
									
										7
									
								
								bin/gva
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								bin/gva
									
										
									
									
									
								
							|  | @ -24,7 +24,12 @@ import gnuviechadmin.cli.client | |||
| import gnuviechadmin.cli.sysuser | ||||
| import gnuviechadmin.cli.domain | ||||
| import gnuviechadmin.cli.record | ||||
| import sys | ||||
| import sys, os, logging.config | ||||
| 
 | ||||
| logcfgs = ('gnuviechadmin/logging.cfg', '/etc/gnuviechadmin/logging.cfg', | ||||
|            os.path.expanduser('~/.gva-logging.cfg')) | ||||
| for cfg in [x for x in logcfgs if os.path.exists(x)]: | ||||
|     logging.config.fileConfig(cfg) | ||||
| 
 | ||||
| commands = [gnuviechadmin.cli.client.ClientCli, | ||||
|             gnuviechadmin.cli.sysuser.SysuserCli, | ||||
|  |  | |||
							
								
								
									
										49
									
								
								data/dbrepo/versions/3/3.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								data/dbrepo/versions/3/3.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| from sqlalchemy import * | ||||
| from migrate import * | ||||
| from gnuviechadmin.backend.settings import dbschema | ||||
| 
 | ||||
| meta = BoundMetaData(migrate_engine) | ||||
| domain = Table('domain', meta, schema = dbschema, autoload = True) | ||||
| mailaccount = Table( | ||||
|     'mailaccount', meta, | ||||
|     Column('mailaccountid', Integer, primary_key = True), | ||||
|     Column('domainid', Integer, ForeignKey('domain.domainid'), | ||||
|            nullable = False), | ||||
|     Column('mailaccount', String(12), nullable = False, unique = True), | ||||
|     Column('clearpass', String(64)), | ||||
|     Column('cryptpass', String(34)), | ||||
|     Column('uid', Integer, nullable = False), | ||||
|     Column('gid', Integer, nullable = False), | ||||
|     Column('home', String(128), nullable = False), | ||||
|     Column('spamcheck', Boolean, nullable = False, default = False), | ||||
|     Column('sajunkscore', Integer), | ||||
|     schema = dbschema | ||||
|     ) | ||||
| mailaddress = Table( | ||||
|     'mailaddress', meta, | ||||
|     Column('mailaddressid', Integer, primary_key = True), | ||||
|     Column('domainid', Integer, ForeignKey('domain.domainid'), | ||||
|            nullable = False), | ||||
|     Column('email', String(255), nullable = False), | ||||
|     UniqueConstraint('email', 'domainid'), | ||||
|     schema = dbschema | ||||
|     ) | ||||
| mailtarget = Table( | ||||
|     'mailtarget', meta, | ||||
|     Column('mailtargetid', Integer, primary_key = True), | ||||
|     Column('mailaddressid', Integer, ForeignKey('mailaddress.mailaddressid'), | ||||
|            nullable = False), | ||||
|     Column('target', String(128), nullable = False), | ||||
|     UniqueConstraint('target', 'mailaddressid'), | ||||
|     schema = dbschema | ||||
|     ) | ||||
| 
 | ||||
| def upgrade(): | ||||
|     mailaccount.create() | ||||
|     mailaddress.create() | ||||
|     mailtarget.create() | ||||
| 
 | ||||
| def downgrade(): | ||||
|     mailtarget.drop() | ||||
|     mailaddress.drop() | ||||
|     mailaccount.drop() | ||||
							
								
								
									
										6
									
								
								data/templates/domain/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								data/templates/domain/index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| <html> | ||||
| <head><title>Hier entsteht ein neuer Internetauftritt</title></head> | ||||
| <body> | ||||
| <p>Hier entsteht der Internetauftritt für www.${domain}.</p> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										4
									
								
								data/templates/domainconf/htaccess-stats
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								data/templates/domainconf/htaccess-stats
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| AuthType Basic | ||||
| AuthName "Statistics for ${domain}" | ||||
| AuthUserFile "${userfile}" | ||||
| require valid-user | ||||
							
								
								
									
										42
									
								
								data/templates/domainconf/modlogan.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								data/templates/domainconf/modlogan.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| [global] | ||||
| includepath		= /etc/modlogan | ||||
| include  			= modlogan.def.conf,global | ||||
| 
 | ||||
| loadplugin		= input_clf | ||||
| loadplugin		= processor_web | ||||
| loadplugin		= output_modlogan | ||||
| 
 | ||||
| statedir	= ${statsdir} | ||||
| 
 | ||||
| incremental	= 1 | ||||
| enable_resolver = 1 | ||||
| 
 | ||||
| read_ahead_limit	= 100 | ||||
| 
 | ||||
| [processor_web] | ||||
| # to group known bot attacks like Nimda and CodeRed | ||||
| include			= group.url.conf,group_exploits | ||||
| # to use the german file extension descriptions uncomment the following | ||||
| #include		= group.extension.conf,groupext_german | ||||
| # include the default config | ||||
| include			= modlogan.def.conf,processor_web | ||||
| 
 | ||||
| # to only have pages listed, not files | ||||
| #hideurl="\.(?i:gif|png|jpe?g|css|js|class|mid|swf|mp3|mpg)$$" | ||||
| # to not show people they're reading the stats more often than people their page...  | ||||
| hideurl="^/stats" | ||||
| 
 | ||||
| debug_searchengines = 1 | ||||
| hidereferrer	= "^http://([^.]+\.)*${domainesc}/" | ||||
| 
 | ||||
| ## configure the output generator | ||||
| [output_modlogan] | ||||
| include			= modlogan.def.conf,output_modlogan | ||||
| hostname		= ${domain} | ||||
| 
 | ||||
| outputdir		= ${statsdir} | ||||
| 
 | ||||
| ## configure the parser | ||||
| [input_clf] | ||||
| include			= modlogan.def.conf,input_clf | ||||
| inputfile		= - | ||||
							
								
								
									
										10
									
								
								data/templates/domainconf/vhost.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								data/templates/domainconf/vhost.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| <VirtualHost ${ipaddr}:80> | ||||
|   ServerName www.${domain} | ||||
|   ServerAlias ${domain} | ||||
| 
 | ||||
|   Alias /stats ${statsdir} | ||||
|   DocumentRoot ${docroot} | ||||
| 
 | ||||
|   ErrorLog ${logdir}/error.log | ||||
|   CustomLog ${logdir}/access.log combined | ||||
| </VirtualHost> | ||||
							
								
								
									
										8
									
								
								data/templates/mails/create_client.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								data/templates/mails/create_client.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| A new client with the following data has been created: | ||||
| 
 | ||||
|  Firstname : ${firstname} | ||||
|  Lastname  : ${lastname} | ||||
|  Email     : ${email} | ||||
|  Address   : ${address1} | ||||
|            : ${zipcode} ${city} | ||||
|  Phone     : ${phone} | ||||
							
								
								
									
										14
									
								
								data/templates/mails/create_domain.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								data/templates/mails/create_domain.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| A new domain with the following data has been created: | ||||
| 
 | ||||
|  System user         : ${sysuser} | ||||
|  Domain name         : ${domain} | ||||
|  Document root       : ${docroot} | ||||
|  Statistics password : ${statspass} | ||||
| 
 | ||||
| To enable the domain in apache use | ||||
| 
 | ||||
|  sudo a2ensite ${domain} | ||||
| 
 | ||||
| You can access statistics for the domain at | ||||
| 
 | ||||
|  http://www.${domain}/stats/ | ||||
							
								
								
									
										8
									
								
								data/templates/mails/create_sysuser.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								data/templates/mails/create_sysuser.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| A new system user has been created | ||||
| 
 | ||||
| UID      : ${uid} | ||||
| Client   : ${firstname} ${lastname} <${email}> | ||||
| Username : ${username} | ||||
| Password : ${password} | ||||
| Home     : ${home} | ||||
| Shell    : ${shell} | ||||
|  | @ -19,41 +19,35 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| import ConfigParser, os | ||||
| from subprocess import * | ||||
| from sqlalchemy import * | ||||
| import smtplib, os, logging, tempfile | ||||
| from email.MIMEText import MIMEText | ||||
| from pyme import core | ||||
| from pyme.constants.sig import mode | ||||
| 
 | ||||
| from settings import config | ||||
| from gnuviechadmin.exceptions import * | ||||
| from subprocess import * | ||||
| import sqlalchemy | ||||
| 
 | ||||
| class BackendEntity(object): | ||||
|     """This is the abstract base class for all backend entity classes.""" | ||||
| 
 | ||||
|     def __init__(self, verbose = False): | ||||
|     def __init__(self, delegateto, verbose = False): | ||||
|         self.logger = logging.getLogger("%s.%s" % ( | ||||
|             self.__class__.__module__, self.__class__.__name__)) | ||||
|         self.delegateto = delegateto | ||||
|         self.verbose = verbose | ||||
|         self.config = ConfigParser.ConfigParser() | ||||
|         self.config.readfp(open('gnuviechadmin/defaults.cfg')) | ||||
|         self.config.read(['gnuviechadmin/gva.cfg', | ||||
|                           os.path.expanduser('~/.gva.cfg')]) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         if self.verbose: | ||||
|             cols = [col for col in \ | ||||
|                     object_mapper(self).local_table.columns.keys()] | ||||
|             format = "%(class)s:" | ||||
|             format = format + ", ".join([col + "=%(" + col + ")s" for col in \ | ||||
|                                          cols]) | ||||
|             data = {'class' : self.__class__.__name__} | ||||
|         else: | ||||
|             cols = self._shortkeys | ||||
|             format = ",".join("%(" + col + ")s" for col in cols) | ||||
|             data = {} | ||||
|         data.update(dict([(col, self.__getattribute__(col)) for col in cols])) | ||||
|         return format % data | ||||
|         return self.delegateto.__repr__(verbose = self.verbose) | ||||
| 
 | ||||
|     def sucommand(self, cmdline, pipedata = None): | ||||
|         """Executes a command as root using the configured suwrapper | ||||
|         command. If a pipe is specified it is used as stdin of the | ||||
|         subprocess.""" | ||||
|         suwrapper = self.config.get('common', 'suwrapper') | ||||
|         self.logger.debug("sucommand called: %s (pipedata=%s)", cmdline, | ||||
|                           str(pipedata)) | ||||
|         suwrapper = config.get('common', 'suwrapper') | ||||
|         toexec = "%s %s" % (suwrapper, cmdline) | ||||
|         if pipedata: | ||||
|             p = Popen(toexec, shell = True, stdin=PIPE) | ||||
|  | @ -63,21 +57,80 @@ class BackendEntity(object): | |||
|             sts = os.waitpid(p.pid, 0) | ||||
|             if self.verbose: | ||||
|                 print "%s|%s: %d" % (pipedata, toexec, sts[1]) | ||||
|             self.logger.info("%s|%s: %d", pipedata, toexec, sts[1]) | ||||
|         else: | ||||
|             p = Popen(toexec, shell = True) | ||||
|             sts = os.waitpid(p.pid, 0) | ||||
|             if self.verbose: | ||||
|                 print "%s: %s" % (toexec, sts[1]) | ||||
|             self.logger.info("%s: %s", toexec, sts[1]) | ||||
|         return sts[1] | ||||
| 
 | ||||
|     def send_mail(self, subject, text): | ||||
|         """This method sends a mail with the given text and subject | ||||
|         and signs it usign GnuPG. If a public key of the recipient is | ||||
|         available the mail is encrypted.""" | ||||
|         plain = core.Data(text) | ||||
|         sig = core.Data() | ||||
|         c = core.Context() | ||||
|         signer = config.get('common', 'mailfrom') | ||||
|         rcpt = config.get('common', 'mailto') | ||||
|         c.signers_clear() | ||||
|         for sigkey in [x for x in c.op_keylist_all(signer, 1)]: | ||||
|             if sigkey.can_sign: | ||||
|                 c.signers_add(sigkey) | ||||
|         if not c.signers_enum(0): | ||||
|             raise Exception("No secret keys for signing available for %s." % ( | ||||
|                 signer)) | ||||
|         keylist = [] | ||||
|         for key in [x for x in c.op_keylist_all(rcpt, 1)]: | ||||
|             valid = 0 | ||||
|             subkey = key.subkeys | ||||
|             while subkey: | ||||
|                 keyid = subkey.keyid | ||||
|                 if keyid == None: | ||||
|                     break | ||||
|                 can_encrypt = subkey.can_encrypt | ||||
|                 valid += can_encrypt | ||||
|                 subkey = subkey.next | ||||
|             if valid: | ||||
|                 keylist.append(key) | ||||
|         if keylist: | ||||
|             c.set_armor(1) | ||||
|             c.op_encrypt_sign(keylist, 1, plain, sig) | ||||
|         else: | ||||
|             c.op_sign(plain, sig, mode.CLEAR) | ||||
|         sig.seek(0,0) | ||||
| 
 | ||||
|         msg = MIMEText(sig.read()) | ||||
|         msg['Subject'] = subject | ||||
|         msg['From'] = signer | ||||
|         msg['To'] = rcpt | ||||
| 
 | ||||
|         s = smtplib.SMTP() | ||||
|         s.connect() | ||||
|         s.sendmail(signer, [rcpt], msg.as_string()) | ||||
|         s.close()   | ||||
| 
 | ||||
|     def validate(self): | ||||
|         """Validates whether all mandatory fields of the entity have | ||||
|         values.""" | ||||
|         missingfields = [] | ||||
|         for key in [col.name for col in \ | ||||
|                     object_mapper(self).local_table.columns \ | ||||
|                     sqlalchemy.object_mapper( | ||||
|             self.delegateto).local_table.columns \ | ||||
|                     if not col.primary_key and not col.nullable]: | ||||
|             if self.__getattribute__(key) is None: | ||||
|             if self.delegateto.__getattribute__(key) is None: | ||||
|                 missingfields.append(key) | ||||
|         if missingfields: | ||||
|             raise MissingFieldsError(missingfields) | ||||
| 
 | ||||
|     def write_to_file(self, filename, template): | ||||
|         """Write the data from template to the specified file.""" | ||||
|         tmp = tempfile.NamedTemporaryFile() | ||||
|         tmp.write(template) | ||||
|         tmp.flush() | ||||
|         cmd = 'cp "%s" "%s"' % (tmp.name, filename) | ||||
|         self.sucommand(cmd) | ||||
|         tmp.close() | ||||
|          | ||||
|  |  | |||
|  | @ -19,51 +19,68 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| from sqlalchemy import * | ||||
| import sqlalchemy, logging | ||||
| from gnuviechadmin.exceptions import * | ||||
| from BackendEntity import * | ||||
| 
 | ||||
| class BackendEntityHandler(object): | ||||
|     def __init__(self, entityclass, verbose = False): | ||||
|     def __init__(self, entityclass, toclass, verbose = False): | ||||
|         self.logger = logging.getLogger("%s.%s" % ( | ||||
|             self.__class__.__module__, self.__class__.__name__)) | ||||
|         self.entityclass = entityclass | ||||
|         self.toclass = toclass | ||||
|         self.verbose = verbose | ||||
| 
 | ||||
|     def create(self, **kwargs): | ||||
| #        try: | ||||
|             sess = create_session() | ||||
|             entity = self.entityclass(self.verbose, **kwargs) | ||||
|             try: | ||||
|                 entity.create_hook() | ||||
|                 sess.save(entity) | ||||
|                 sess.flush() | ||||
|             except: | ||||
|                 sess.delete(entity) | ||||
|                 sess.flush() | ||||
|                 raise | ||||
| #        except Exception, e: | ||||
| #            raise CreationFailedError(self.entityclass.__name__, e) | ||||
|         """Create a new entity of the managed type with the fields set | ||||
|         to the values in kwargs.""" | ||||
|         self.logger.debug("create with params %s", str(kwargs)) | ||||
|         sess = sqlalchemy.create_session() | ||||
|         transaction = sess.create_transaction() | ||||
|         delegate = self.toclass(**kwargs) | ||||
|         entity = self.entityclass(delegate, self.verbose)             | ||||
|         try: | ||||
|             sess.save(delegate) | ||||
|             sess.flush() | ||||
|             sess.refresh(delegate) | ||||
|             entity.create_hook(sess) | ||||
|             sess.flush() | ||||
|             transaction.commit() | ||||
|         except: | ||||
|             transaction.rollback() | ||||
|             self.logger.exception("Exception in create.") | ||||
|             raise | ||||
| 
 | ||||
|     def fetchall(self): | ||||
|     def fetchall(self, **kwargs): | ||||
|         """Fetches all entities of the managed entity type.""" | ||||
|         session = create_session() | ||||
|         query = session.query(self.entityclass) | ||||
|         allentities = query.select() | ||||
|         for entity in allentities: | ||||
|             BackendEntity.__init__(entity, self.verbose) | ||||
|         return allentities | ||||
|         self.logger.debug("fetchall with params %s", str(kwargs)) | ||||
|         session = sqlalchemy.create_session() | ||||
|         query = session.query(self.toclass) | ||||
|         if kwargs: | ||||
|             allentities = query.select_by(**kwargs) | ||||
|         else: | ||||
|             allentities = query.select() | ||||
|         return [self.entityclass(entity, self.verbose) \ | ||||
|                 for entity in allentities] | ||||
| 
 | ||||
|     def delete(self, pkvalue): | ||||
|         """Deletes the entity of the managed entity type that has the | ||||
|         specified primary key value.""" | ||||
|         self.logger.debug("delete with primary key %s", str(pkvalue)) | ||||
|         sess = sqlalchemy.create_session() | ||||
|         transaction = sess.create_transaction() | ||||
|         try: | ||||
|             sess = create_session() | ||||
|             entity = sess.query(self.entityclass).get(pkvalue) | ||||
|             if entity: | ||||
|                 BackendEntity.__init__(entity, self.verbose) | ||||
|             to = sess.query(self.toclass).get(pkvalue) | ||||
|             if to: | ||||
|                 entity = self.entityclass(to, self.verbose) | ||||
|                 self.logger.info("delete %s", str(entity)) | ||||
|                 if self.verbose: | ||||
|                     print "delete %s" % (str(entity)) | ||||
|                 entity.delete_hook() | ||||
|                 sess.delete(entity) | ||||
|                 entity.delete_hook(sess) | ||||
|                 sess.delete(to) | ||||
|             sess.flush() | ||||
|             transaction.commit() | ||||
|         except Exception, e: | ||||
|             raise DeleteFailedError(self.entityclass.__name__, e) | ||||
|             transaction.rollback() | ||||
|             self.logger.exception("Exception in delete.") | ||||
|             raise | ||||
|  |  | |||
							
								
								
									
										73
									
								
								gnuviechadmin/backend/BackendTo.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								gnuviechadmin/backend/BackendTo.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| # -*- coding: UTF-8 -*- | ||||
| # | ||||
| # Copyright (C) 2007 by Jan Dittberner. | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation; either version 2 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, but | ||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
| # General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||||
| # USA. | ||||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| from sqlalchemy import object_mapper | ||||
| 
 | ||||
| from tables import * | ||||
| 
 | ||||
| class BackendTo(object): | ||||
|     """Backend transfer object class.""" | ||||
|     def __init__(self, **kwargs): | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, value) | ||||
| 
 | ||||
|     def __repr__(self, **kwargs): | ||||
|         if 'verbose' in kwargs and kwargs['verbose']: | ||||
|             cols = [col for col in \ | ||||
|                     object_mapper(self).local_table.columns.keys()] | ||||
|             format = "%(class)s:" | ||||
|             format = format + ", ".join([col + "=%(" + col + ")s" for col in \ | ||||
|                                          cols]) | ||||
|             data = {'class' : self.__class__.__name__} | ||||
|         else: | ||||
|             cols = self._shortkeys | ||||
|             format = ",".join("%(" + col + ")s" for col in cols) | ||||
|             data = {} | ||||
|         data.update(dict([(col, self.__getattribute__(col)) for col in cols])) | ||||
|         return format % data | ||||
| 
 | ||||
| class Client(BackendTo): | ||||
|     """Transfer object class for clients.""" | ||||
|     _shortkeys = ('clientid', 'firstname', 'lastname', 'email') | ||||
| 
 | ||||
| class Sysuser(BackendTo): | ||||
|     """Transfer object class for system users.""" | ||||
|     _shortkeys = ("sysuserid", "clientid", "username", "home", "shell") | ||||
| 
 | ||||
| class Domain(BackendTo): | ||||
|     """Transfer object class for DNS domains.""" | ||||
|     _shortkeys = ("domainid", "sysuserid", "name", "type") | ||||
| 
 | ||||
| class Record(BackendTo): | ||||
|     """Transfer object class for DNS domain records.""" | ||||
|     _shortkeys = ("recordid", "domainid", "name", "type", "content") | ||||
| 
 | ||||
| client_mapper = mapper(Client, client_table) | ||||
| sysuser_mapper = mapper(Sysuser, sysuser_table) | ||||
| domain_mapper = mapper(Domain, domain_table) | ||||
| record_mapper = mapper(Record, record_table) | ||||
| 
 | ||||
| client_mapper.add_property("sysusers", relation(Sysuser, backref = 'client')) | ||||
| 
 | ||||
| sysuser_mapper.add_property("domains", relation(Domain, backref = 'sysuser')) | ||||
| 
 | ||||
| domain_mapper.add_property("records", relation(Record, cascade = 'all', | ||||
|                                                backref = 'domain')) | ||||
|  | @ -19,42 +19,58 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| from sqlalchemy import * | ||||
| from tables import client_table | ||||
| from gnuviechadmin.exceptions import * | ||||
| 
 | ||||
| import sysuser | ||||
| from settings import config | ||||
| from BackendTo import * | ||||
| from BackendEntity import * | ||||
| from BackendEntityHandler import * | ||||
| 
 | ||||
| class Client(BackendEntity): | ||||
| class ClientEntity(BackendEntity): | ||||
|     """Entity class for clients.""" | ||||
| 
 | ||||
|     _shortkeys = ('clientid', 'firstname', 'lastname', 'email') | ||||
| 
 | ||||
|     def __init__(self, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, verbose) | ||||
|         self.clientid = None | ||||
|         self.country = 'de' | ||||
|         self.title = None | ||||
|         self.address2 = None | ||||
|         self.mobile = None | ||||
|         self.fax = None | ||||
|     def __init__(self, delegate, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, delegate, verbose) | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, value) | ||||
|         if not self.delegateto.country: | ||||
|             self.delegateto.country = self._get_default_country() | ||||
|         self.validate() | ||||
| 
 | ||||
|     def create_hook(self): | ||||
|         pass | ||||
|     def _client_mail(self): | ||||
|         text = get_template(config.get('common', 'mailtemplates'), | ||||
|                             config.get('client', 'create.mail')).substitute({ | ||||
|             'firstname' : self.delegateto.firstname, | ||||
|             'lastname'  : self.delegateto.lastname, | ||||
|             'email'     : self.delegateto.email, | ||||
|             'address1'  : self.delegateto.address1, | ||||
|             'zipcode'   : self.delegateto.zip, | ||||
|             'city'      : self.delegateto.city, | ||||
|             'phone'     : self.delegateto.phone}) | ||||
|         subject = get_template_string( | ||||
|             config.get('client', 'create_subject')).substitute({ | ||||
|             'firstname' : self.delegateto.firstname, | ||||
|             'lastname'  : self.delegateto.lastname}) | ||||
|         self.send_mail(subject, text)         | ||||
| 
 | ||||
|     def delete_hook(self): | ||||
|         pass | ||||
|     def create_hook(self, session): | ||||
|         """Actions to perform when a client is created.""" | ||||
|         self._client_mail() | ||||
| 
 | ||||
| client_mapper = mapper(Client, client_table) | ||||
| client_mapper.add_property("sysusers", relation(sysuser.Sysuser)) | ||||
|     def delete_hook(self, session): | ||||
|         """Actions to perform when a client is deleted.""" | ||||
|         if self.delegateto.sysusers: | ||||
|             raise CannotDeleteError( | ||||
|                 self.delegateto, | ||||
|                 "it still has the following system users assigned: %s" % ( | ||||
|                 ", ".join([sysuser.username for sysuser in \ | ||||
|                            self.delegateto.sysusers]))) | ||||
| 
 | ||||
|     def _get_default_country(self): | ||||
|         """Gets the default country.""" | ||||
|         return config.get('common', 'defaultcountry') | ||||
| 
 | ||||
| class ClientHandler(BackendEntityHandler): | ||||
|     """BackendEntityHandler for Client entities.""" | ||||
| 
 | ||||
|     def __init__(self, verbose = False): | ||||
|         BackendEntityHandler.__init__(self, Client, verbose) | ||||
|         BackendEntityHandler.__init__(self, ClientEntity, Client, verbose) | ||||
|  |  | |||
|  | @ -19,37 +19,29 @@ | |||
| # | ||||
| # Version: $Id: client.py 1101 2007-02-28 21:15:20Z jan $ | ||||
| 
 | ||||
| from sqlalchemy import * | ||||
| from tables import domain_table | ||||
| import datetime, os | ||||
| 
 | ||||
| from gnuviechadmin.exceptions import * | ||||
| from settings import * | ||||
| from BackendTo import Record, Domain | ||||
| from BackendEntity import BackendEntity | ||||
| from BackendEntityHandler import BackendEntityHandler | ||||
| 
 | ||||
| from record import Record | ||||
| import datetime | ||||
| from BackendEntity import * | ||||
| from BackendEntityHandler import * | ||||
| from settings import config | ||||
| 
 | ||||
| class Domain(BackendEntity): | ||||
| class DomainEntity(BackendEntity): | ||||
|     """Entity class for DNS domains.""" | ||||
| 
 | ||||
|     _shortkeys = ("domainid", "sysuserid", "name", "type") | ||||
|     _valid_domain_types = ("MASTER", "SLAVE") | ||||
| 
 | ||||
|     def __init__(self, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, verbose) | ||||
|         self.domainid = None | ||||
|         self.sysuserid = None | ||||
|         self.name = None | ||||
|         self.type = None | ||||
|         self.master = None | ||||
|     def __init__(self, delegate, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, delegate, verbose) | ||||
|         self.ns1 = None | ||||
|         self.ns2 = None | ||||
|         self.mx = None | ||||
|         self.ipaddr = None | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, value) | ||||
|         if not self.type: | ||||
|             self.type = self.getdefaultdomaintype() | ||||
|         if not self.delegateto.type: | ||||
|             self.delegateto.type = self.getdefaultdomaintype() | ||||
|         if not self.ns1: | ||||
|             self.ns1 = config.get('domain', 'defaultns1') | ||||
|         if not self.ns2: | ||||
|  | @ -58,7 +50,7 @@ class Domain(BackendEntity): | |||
|             self.mx = config.get('domain', 'defaultmx') | ||||
|         if not self.ipaddr: | ||||
|             self.ipaddr = config.get('domain', 'defaultip') | ||||
|         self.type = self.type.upper() | ||||
|         self.delegateto.type = self.delegateto.type.upper() | ||||
|         self.validate() | ||||
| 
 | ||||
|     def getdefaultdomaintype(self): | ||||
|  | @ -66,13 +58,13 @@ class Domain(BackendEntity): | |||
| 
 | ||||
|     def validate(self): | ||||
|         BackendEntity.validate(self) | ||||
|         if not self.type in self._valid_domain_types: | ||||
|         if not self.delegateto.type in self._valid_domain_types: | ||||
|             raise ValidationFailedError( | ||||
|                 self, "invalid domain type %s" % (self.type)) | ||||
|         if self.type == 'SLAVE' and not self.master: | ||||
|                 self, "invalid domain type %s" % (self.delegateto.type)) | ||||
|         if self.delegateto.type == 'SLAVE' and not self.delegateto.master: | ||||
|             raise ValidationFailedError( | ||||
|                 self, "you have to specify a master for slave domains.") | ||||
|         if self.type == 'MASTER': | ||||
|         if self.delegateto.type == 'MASTER': | ||||
|             if not self.ns1 or not self.ns2: | ||||
|                 raise ValidationFailedError( | ||||
|                     self, "two nameservers must be specified.") | ||||
|  | @ -80,10 +72,17 @@ class Domain(BackendEntity): | |||
|                 raise ValidationFailedError( | ||||
|                     self, "a primary mx host must be specified.") | ||||
| 
 | ||||
|     def _getnewserial(self): | ||||
|     def _getnewserial(self, oldserial = None): | ||||
|         current = datetime.datetime.now() | ||||
|         return int("%04d%02d%02d01" % \ | ||||
|                    (current.year, current.month, current.day)) | ||||
|         datepart = "%04d%02d%02d" % \ | ||||
|                    (current.year, current.month, current.day) | ||||
|         retval = None | ||||
|         if oldserial: | ||||
|             if str(oldserial)[:len(datepart)] == datepart: | ||||
|                 retval = oldserial + 1 | ||||
|         if not retval: | ||||
|             retval = int("%s01" % (datepart)) | ||||
|         return retval | ||||
| 
 | ||||
|     def _getnewsoa(self): | ||||
|         return '%s %s %d %d %d %d %d' % \ | ||||
|  | @ -95,36 +94,228 @@ class Domain(BackendEntity): | |||
|                 config.getint('domain', 'defaultexpire'), | ||||
|                 config.getint('domain', 'defaultminimumttl')) | ||||
| 
 | ||||
|     def create_hook(self): | ||||
|         self.records.append(Record( | ||||
|             name = self.name, type = 'SOA', | ||||
|     def update_serial(self, session): | ||||
|         query = session.query(Record) | ||||
|         soarecord = query.get_by(Record.c.type == 'SOA', | ||||
|                                  Record.c.domainid == self.delegateto.domainid) | ||||
|         parts = soarecord.content.split(" ") | ||||
|         parts[2] = str(self._getnewserial(int(parts[2]))) | ||||
|         soarecord.content = " ".join(parts) | ||||
|         session.save(soarecord) | ||||
|         session.flush() | ||||
| 
 | ||||
|     def _get_vhost_dir(self): | ||||
|         return os.path.join(self.delegateto.sysuser.home, | ||||
|                             self.delegateto.name, | ||||
|                             config.get('domain', 'htdir')) | ||||
| 
 | ||||
|     def _get_log_dir(self): | ||||
|         return os.path.join(config.get('domain', 'logpath'), | ||||
|                             self.delegateto.name) | ||||
| 
 | ||||
|     def _get_stats_dir(self): | ||||
|         return os.path.join(config.get('domain', 'statspath'), | ||||
|                             self.delegateto.name) | ||||
| 
 | ||||
|     def _create_vhost_dir(self): | ||||
|         vhostdir = self._get_vhost_dir() | ||||
|         cmd = 'mkdir -p "%s"' % (vhostdir) | ||||
|         self.sucommand(cmd) | ||||
|         for tpl in [tpl for tpl in os.listdir( | ||||
|             get_template_dir(config.get('domain', 'htdocstemplate'))) \ | ||||
|                     if not tpl.startswith('.')]: | ||||
|             template = get_template(config.get('domain', 'htdocstemplate'), | ||||
|                                     tpl) | ||||
|             template = template.substitute({ | ||||
|                 'domain' : self.delegateto.name}) | ||||
|             self.write_to_file(os.path.join(vhostdir, tpl), template) | ||||
|         cmd = 'chown -R %(username)s:%(group)s "%(dir)s"' % { | ||||
|             'username' : self.delegateto.sysuser.username, | ||||
|             'group'    : config.get('sysuser', 'defaultgroup'), | ||||
|             'dir'      : vhostdir} | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def _create_log_dir(self): | ||||
|         cmd = 'mkdir -p "%s"' % (self._get_log_dir()) | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def _get_auth_userfile(self): | ||||
|         authdir = config.get('domain', 'authdir') | ||||
|         if not os.path.isdir(authdir): | ||||
|             cmd = 'mkdir -p "%s"' % (authdir) | ||||
|             self.sucommand(cmd) | ||||
|         return os.path.join(authdir, '%s.passwd' % (self.delegateto.name)) | ||||
| 
 | ||||
|     def _create_stats_dir(self): | ||||
|         """Creates the statistics directory for the domain and sets | ||||
|         Apache .htaccess password protection.""" | ||||
|         statsdir = self._get_stats_dir() | ||||
|         authfile = self._get_auth_userfile() | ||||
|         cmd = 'htpasswd -m -c -b "%s" "%s" "%s"' % ( | ||||
|             authfile, | ||||
|             self.delegateto.sysuser.username, | ||||
|             self.delegateto.sysuser.clearpass) | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'mkdir -p "%s"' % (statsdir) | ||||
|         self.sucommand(cmd) | ||||
|         template = get_template(config.get('domain', 'conftemplates'), | ||||
|                                 config.get('domain', 'statshtaccesstemplate')) | ||||
|         template = template.substitute({ | ||||
|             'domain'   : self.delegateto.name, | ||||
|             'userfile' : authfile}) | ||||
|         self.write_to_file(os.path.join(self._get_stats_dir(), | ||||
|                                         '.htaccess'), template) | ||||
| 
 | ||||
|     def _create_stats_conf(self): | ||||
|         modlogandir = os.path.join(config.get('domain', | ||||
|                                               'modlogandir'), | ||||
|                                    self.delegateto.sysuser.username) | ||||
|         cmd = 'mkdir -p "%s"' % (modlogandir) | ||||
|         self.sucommand(cmd) | ||||
|         template = get_template(config.get('domain', 'conftemplates'), | ||||
|                                 config.get('domain', 'modlogantemplate')) | ||||
|         template = template.substitute({ | ||||
|             'statsdir'  : self._get_stats_dir(), | ||||
|             'logdir'    : self._get_log_dir(), | ||||
|             'domain'    : self.delegateto.name, | ||||
|             'domainesc' : self.delegateto.name.replace('.', '\.')}) | ||||
|         self.write_to_file(os.path.join(modlogandir, | ||||
|                                         self.delegateto.name + '.conf'), | ||||
|                            template) | ||||
| 
 | ||||
|     def _create_apache_conf(self): | ||||
|         template = get_template(config.get('domain', 'conftemplates'), | ||||
|                                 config.get('domain', 'apachetemplate')) | ||||
|         template = template.substitute({ | ||||
|             'ipaddr'    : self.ipaddr, | ||||
|             'statsdir'  : self._get_stats_dir(), | ||||
|             'logdir'    : self._get_log_dir(), | ||||
|             'domain'    : self.delegateto.name, | ||||
|             'docroot'   : self._get_vhost_dir()}) | ||||
|         self.write_to_file(os.path.join(config.get('domain', 'sitesdir'), | ||||
|                                         self.delegateto.name), template) | ||||
| 
 | ||||
|     def _mail_domain(self): | ||||
|         template = get_template(config.get('common', 'mailtemplates'), | ||||
|                                 config.get('domain', 'create.mail')) | ||||
|         text = template.substitute({ | ||||
|             'sysuser'   : self.delegateto.sysuser.username, | ||||
|             'domain'    : self.delegateto.name, | ||||
|             'docroot'   : self._get_vhost_dir(), | ||||
|             'statspass' : self.delegateto.sysuser.clearpass}) | ||||
|         template = get_template_string(config.get('domain', 'create_subject')) | ||||
|         subject = template.substitute({ | ||||
|             'domain'    : self.delegateto.name}) | ||||
|         self.send_mail(subject, text)         | ||||
| 
 | ||||
|     def create_hook(self, session): | ||||
|         self.delegateto.records.append(Record( | ||||
|             name = self.delegateto.name, type = 'SOA', | ||||
|             content = self._getnewsoa(), | ||||
|             ttl = config.getint('domain', 'defaultttl'))) | ||||
|         self.records.append(Record( | ||||
|             name = self.name, type = 'NS', content = self.ns1, | ||||
|         self.delegateto.records.append(Record( | ||||
|             name = self.delegateto.name, type = 'NS', content = self.ns1, | ||||
|             ttl = config.getint('domain', 'defaultttl'))) | ||||
|         self.records.append(Record( | ||||
|             name = self.name, type = 'NS', content = self.ns2, | ||||
|         self.delegateto.records.append(Record( | ||||
|             name = self.delegateto.name, type = 'NS', content = self.ns2, | ||||
|             ttl = config.getint('domain', 'defaultttl'))) | ||||
|         self.records.append(Record( | ||||
|             name  = self.name, type = 'MX', content = self.mx, | ||||
|         self.delegateto.records.append(Record( | ||||
|             name  = self.delegateto.name, type = 'MX', content = self.mx, | ||||
|             ttl = config.getint('domain', 'defaultttl'), | ||||
|             prio = config.getint('domain', 'defaultmxprio'))) | ||||
|         self.records.append(Record( | ||||
|             name = self.name, type = 'A', content = self.ipaddr, | ||||
|         self.delegateto.records.append(Record( | ||||
|             name = self.delegateto.name, type = 'A', content = self.ipaddr, | ||||
|             ttl = config.getint('domain', 'defaultttl'))) | ||||
|         self.records.append(Record( | ||||
|             name = "www.%s" % (self.name), type = 'A', content = self.ipaddr, | ||||
|         self.delegateto.records.append(Record( | ||||
|             name = "www.%s" % (self.delegateto.name), type = 'A', | ||||
|             content = self.ipaddr, | ||||
|             ttl = config.getint('domain', 'defaultttl'))) | ||||
|         session.save(self.delegateto) | ||||
|         session.flush() | ||||
|         self._create_vhost_dir() | ||||
|         self._create_log_dir() | ||||
|         self._create_stats_dir() | ||||
|         self._create_stats_conf() | ||||
|         self._create_apache_conf() | ||||
|         self._mail_domain() | ||||
| 
 | ||||
|     def delete_hook(self): | ||||
|         pass | ||||
|     def _delete_apache_conf(self): | ||||
|         cmd = 'a2dissite %s' % (self.delegateto.name) | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'rm "%s"' % (os.path.join(config.get('domain', 'sitesdir'), | ||||
|                                         self.delegateto.name)) | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
| domain_mapper = mapper(Domain, domain_table) | ||||
| domain_mapper.add_property("records", relation(Record)) | ||||
|     def _delete_stats_conf(self): | ||||
|         cmd = 'rm "%s"' % (os.path.join(config.get('domain', 'modlogandir'), | ||||
|                                         self.delegateto.sysuser.username, | ||||
|                                         self.delegateto.name + '.conf')) | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def _archive_stats_dir(self): | ||||
|         archive = os.path.join(self.delegateto.sysuser.home, | ||||
|                                '%(domain)s-stats.tar.gz' % { | ||||
|             'domain' : self.delegateto.name}) | ||||
|         cmd = 'tar czf "%(archive)s" --directory="%(statsbase)s" "%(statsdir)s"' % { | ||||
|             'archive'   : archive, | ||||
|             'statsbase' : config.get('domain', 'statspath'), | ||||
|             'statsdir'  : self.delegateto.name} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'rm -r "%(statsdir)s"' % { | ||||
|             'statsdir' : self._get_stats_dir()} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { | ||||
|             'username' : self.delegateto.sysuser.username, | ||||
|             'group'    : config.get('sysuser', 'defaultgroup'), | ||||
|             'archive'  : archive} | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def _archive_log_dir(self): | ||||
|         archive = os.path.join(self.delegateto.sysuser.home, | ||||
|                                '%(domain)s-logs.tar.gz' % { | ||||
|             'domain' : self.delegateto.name}) | ||||
|         cmd = 'tar czf "%(archive)s" --directory="%(logbase)s" "%(logdir)s"' % { | ||||
|             'archive' : archive, | ||||
|             'logbase' : config.get('domain', 'logpath'), | ||||
|             'logdir'  : self.delegateto.name} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'rm -r "%(logdir)s"' % { | ||||
|             'logdir' : self._get_log_dir()} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { | ||||
|             'username' : self.delegateto.sysuser.username, | ||||
|             'group'    : config.get('sysuser', 'defaultgroup'), | ||||
|             'archive'  : archive} | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def _archive_vhost_dir(self): | ||||
|         archive = os.path.join(self.delegateto.sysuser.home, | ||||
|                                '%(domain)s-vhost.tar.gz' % { | ||||
|             'domain' : self.delegateto.name}) | ||||
|         cmd = 'tar czf "%(archive)s" --directory="%(vhostbase)s" "%(vhostdir)s"' % {             | ||||
|             'archive'   : archive, | ||||
|             'vhostbase' : self.delegateto.sysuser.home, | ||||
|             'vhostdir'  : self.delegateto.name} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'rm -r "%(vhostdir)s"' % { | ||||
|             'vhostdir' : os.path.join(self.delegateto.sysuser.home, | ||||
|                                       self.delegateto.name)} | ||||
|         self.sucommand(cmd) | ||||
|         cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { | ||||
|             'username' : self.delegateto.sysuser.username, | ||||
|             'group'    : config.get('sysuser', 'defaultgroup'), | ||||
|             'archive'  : archive} | ||||
|         self.sucommand(cmd) | ||||
| 
 | ||||
|     def delete_hook(self, session):         | ||||
|         self._delete_apache_conf() | ||||
|         self._delete_stats_conf() | ||||
|         self._archive_stats_dir() | ||||
|         self._archive_log_dir() | ||||
|         self._archive_vhost_dir() | ||||
| 
 | ||||
| class DomainHandler(BackendEntityHandler): | ||||
|     """BackendEntityHandler for Domain entities.""" | ||||
| 
 | ||||
|     def __init__(self, verbose = False): | ||||
|         BackendEntityHandler.__init__(self, Domain, verbose) | ||||
|         BackendEntityHandler.__init__(self, DomainEntity, Domain, verbose) | ||||
|  |  | |||
|  | @ -19,37 +19,24 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| from sqlalchemy import * | ||||
| from tables import record_table | ||||
| from gnuviechadmin.exceptions import * | ||||
| 
 | ||||
| from BackendTo import Record, Domain | ||||
| from domain import DomainEntity | ||||
| from BackendEntity import * | ||||
| from BackendEntityHandler import * | ||||
| 
 | ||||
| class Record(object): | ||||
| class RecordEntity(BackendEntity): | ||||
|     """Entity class for DNS domain records.""" | ||||
|     def __init__(self, **kwargs): | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, value) | ||||
| 
 | ||||
|     #_shortkeys = ("recordid", "domainid", "name", "type", "content") | ||||
| 
 | ||||
|     #def __init__(self, verbose = False, **kwargs): | ||||
|     #    BackendEntity.__init__(self, verbose) | ||||
|     #    self.recordid = None | ||||
|     #    self.domainid = None | ||||
|     #    self.name = None | ||||
|     #    self.type = None | ||||
|     #    self.content = None | ||||
|     #    self.ttl = None | ||||
|     #    self.prio = None | ||||
|     #    self.change_date = None | ||||
|     #    self.validate() | ||||
| 
 | ||||
| record_mapper = mapper(Record, record_table) | ||||
|     def create_hook(self, session): | ||||
|         domain = session.load(Domain, self.delegateto.domainid) | ||||
|         DomainEntity(domain).update_serial(session) | ||||
|      | ||||
|     def delete_hook(self, session): | ||||
|         domain = session.load(Domain, self.delegateto.domainid) | ||||
|         DomainEntity(domain).update_serial(session) | ||||
| 
 | ||||
| class RecordHandler(BackendEntityHandler): | ||||
|     """BackendEntityHandler for Record entities.""" | ||||
| 
 | ||||
|     def __init__(self, verbose = False): | ||||
|         BackendEntityHandler.__init__(self, Record, verbose) | ||||
|         BackendEntityHandler.__init__(self, RecordEntity, Record, verbose) | ||||
|  |  | |||
|  | @ -19,13 +19,28 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| import ConfigParser, os | ||||
| import ConfigParser, os, string, logging.config | ||||
| 
 | ||||
| # global settings which must not be user configurable | ||||
| required_version = 2 | ||||
| required_version = 3 | ||||
| dbschema = 'gva' | ||||
| 
 | ||||
| # load user configuration | ||||
| config = ConfigParser.ConfigParser() | ||||
| config.readfp(open('gnuviechadmin/defaults.cfg')) | ||||
| config.read(['gnuviechadmin/gva.cfg', os.path.expanduser('~/.gva.cfg')]) | ||||
| 
 | ||||
| def get_template_dir(dirname): | ||||
|     """Returns the template directory for the given directory.""" | ||||
|     templatepath = config.get('common', 'templatedir') | ||||
|     return os.path.join(templatepath, dirname) | ||||
| 
 | ||||
| def get_template(dirname, filename): | ||||
|     """Returns the template data from the given template file.""" | ||||
|     templatefile = file(os.path.join(get_template_dir(dirname), | ||||
|                                      filename)) | ||||
|     return string.Template(templatefile.read()) | ||||
| 
 | ||||
| def get_template_string(templatestring): | ||||
|     """Returns a template object for the given template string.""" | ||||
|     return string.Template(templatestring) | ||||
|  |  | |||
|  | @ -19,120 +19,123 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| from sqlalchemy import * | ||||
| from tables import sysuser_table | ||||
| from gnuviechadmin.exceptions import * | ||||
| from gnuviechadmin.util import passwordutils, getenttools | ||||
| 
 | ||||
| from settings import config | ||||
| from BackendTo import * | ||||
| from BackendEntity import * | ||||
| from BackendEntityHandler import * | ||||
| 
 | ||||
| class Sysuser(BackendEntity): | ||||
| class SysuserEntity(BackendEntity): | ||||
|     """Entity class for system users.""" | ||||
| 
 | ||||
|     _shortkeys = ("sysuserid", "clientid", "username", "home", "shell") | ||||
| 
 | ||||
|     def __init__(self, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, verbose) | ||||
|         self.sysuserid = None | ||||
|         self.username = None | ||||
|         self.usertype = None | ||||
|         self.home = None | ||||
|         self.shell = None | ||||
|         self.clearpass = None | ||||
|         self.md5pass = None | ||||
|         self.clientid = None | ||||
|         self.sysuid = None | ||||
|     def __init__(self, delegate, verbose = False, **kwargs): | ||||
|         BackendEntity.__init__(self, delegate, verbose) | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, value) | ||||
|         if not self.username: | ||||
|             self.username = self.getnextsysusername() | ||||
|         if not self.usertype: | ||||
|             self.usertype = self.getdefaultsysusertype() | ||||
|         if not self.home: | ||||
|             self.home = self.gethome(self.username) | ||||
|         if not self.shell: | ||||
|             self.shell = self.getdefaultshell() | ||||
|         (self.clearpass, self.md5pass) = \ | ||||
|                          passwordutils.get_pw_tuple(self.clearpass) | ||||
|         if not self.sysuid: | ||||
|             self.sysuid = self.getnextsysuid() | ||||
|         if not self.delegateto.username: | ||||
|             self.delegateto.username = self._get_next_sysusername() | ||||
|         if not self.delegateto.usertype: | ||||
|             self.delegateto.usertype = self._get_default_sysusertype() | ||||
|         if not self.delegateto.home: | ||||
|             self.delegateto.home = self._get_home(self.delegateto.username) | ||||
|         if not self.delegateto.shell: | ||||
|             self.delegateto.shell = self._get_default_shell() | ||||
|         (self.delegateto.clearpass, self.delegateto.md5pass) = \ | ||||
|                          passwordutils.get_pw_tuple(self.delegateto.clearpass) | ||||
|         if not self.delegateto.sysuid: | ||||
|             self.delegateto.sysuid = self._get_next_sysuid() | ||||
|         self.validate() | ||||
| 
 | ||||
|     def getnextsysusername(self): | ||||
|         prefix = self.config.get('sysuser', 'nameprefix') | ||||
|     def _get_next_sysusername(self): | ||||
|         prefix = config.get('sysuser', 'nameprefix') | ||||
|         usernames = [user.username for user in \ | ||||
|                      getenttools.finduserbyprefix(prefix)] | ||||
|                      getenttools.find_user_by_prefix(prefix)] | ||||
|         maxid = max([int(username[len(prefix):]) for username in usernames]) | ||||
|         for num in range(1, maxid + 1): | ||||
|             username = "%s%02d" % (prefix, num) | ||||
|             if not username in usernames: | ||||
|                 return username | ||||
| 
 | ||||
|     def getdefaultsysusertype(self): | ||||
|     def _get_default_sysusertype(self): | ||||
|         return 1 | ||||
| 
 | ||||
|     def gethome(self, sysusername): | ||||
|     def _get_home(self, sysusername): | ||||
|         """Gets a valid home directory for the given user name.""" | ||||
|         return os.path.join(self.config.get('sysuser', 'homedirbase'), | ||||
|         return os.path.join(config.get('sysuser', 'homedirbase'), | ||||
|                             sysusername) | ||||
| 
 | ||||
|     def getdefaultshell(self): | ||||
|     def _get_default_shell(self): | ||||
|         return False | ||||
| 
 | ||||
|     def getshellbinary(self): | ||||
|         if self.shell: | ||||
|             return self.config.get('sysuser', 'shellyes') | ||||
|         return self.config.get('sysuser', 'shellno') | ||||
|     def _get_shell_binary(self): | ||||
|         if self.delegateto.shell: | ||||
|             return config.get('sysuser', 'shellyes') | ||||
|         return config.get('sysuser', 'shellno') | ||||
| 
 | ||||
|     def getnextsysuid(self): | ||||
|         uid = int(self.config.get('sysuser', 'minuid')) | ||||
|         muid = getenttools.getmaxuid(int(self.config.get('sysuser', | ||||
|                                                          'maxuid'))) | ||||
|     def _get_next_sysuid(self): | ||||
|         uid = int(config.get('sysuser', 'minuid')) | ||||
|         muid = getenttools.get_max_uid(int(config.get('sysuser', 'maxuid'))) | ||||
|         if muid >= uid: | ||||
|             uid = muid + 1 | ||||
|         return uid | ||||
| 
 | ||||
|     def populate_home(self): | ||||
|         templatedir = self.config.get('sysuser', 'hometemplate') | ||||
|         cmdline = 'install -d --owner="%(username)s" --group="%(group)s" "%(home)s"' % { | ||||
|             'username' : self.username, | ||||
|             'group'    : self.config.get('sysuser', 'defaultgroup'), | ||||
|             'home'     : self.home } | ||||
|         self.sucommand(cmdline) | ||||
|     def _populate_home(self): | ||||
|         templatedir = get_template_dir(config.get('sysuser', 'hometemplate')) | ||||
|         cmdline = 'cp -R "%(template)s" "%(home)s"' % { | ||||
|             'template' : templatedir, | ||||
|             'home'     : self.home } | ||||
|             'home'     : self.delegateto.home } | ||||
|         self.sucommand(cmdline) | ||||
|         cmdline = 'chown -R "%(username)s":"%(group)s" %(home)s' % { | ||||
|             'username' : self.username, | ||||
|             'group'    : self.config.get('sysuser', 'defaultgroup'), | ||||
|             'home'     : self.home } | ||||
|             'username' : self.delegateto.username, | ||||
|             'group'    : config.get('sysuser', 'defaultgroup'), | ||||
|             'home'     : self.delegateto.home } | ||||
|         self.sucommand(cmdline) | ||||
| 
 | ||||
|     def create_hook(self): | ||||
|         gecos = self.config.get('sysuser', 'gecos') | ||||
|         gecos = gecos % (self.username) | ||||
|     def _mail_sysuser(self): | ||||
|         template = get_template(config.get('common', 'mailtemplates'), | ||||
|                                 config.get('sysuser', 'create.mail')) | ||||
|         text = template.substitute({ | ||||
|             'uid'       : self.delegateto.sysuid, | ||||
|             'firstname' : self.delegateto.client.firstname, | ||||
|             'lastname'  : self.delegateto.client.lastname, | ||||
|             'email'     : self.delegateto.client.email, | ||||
|             'username'  : self.delegateto.username, | ||||
|             'password'  : self.delegateto.clearpass, | ||||
|             'home'      : self.delegateto.home, | ||||
|             'shell'     : self._get_shell_binary()}) | ||||
|         template = get_template_string(config.get('sysuser', 'create_subject')) | ||||
|         subject = template.substitute({ | ||||
|             'username' : self.delegateto.username}) | ||||
|         self.send_mail(subject, text) | ||||
| 
 | ||||
|     def create_hook(self, session): | ||||
|         gecos = config.get('sysuser', 'gecos') % (self.delegateto.username) | ||||
|         cmdline = 'adduser --home "%(home)s" --shell "%(shell)s" --no-create-home --uid %(sysuid)d --ingroup "%(group)s" --disabled-password --gecos "%(gecos)s" %(username)s' % { | ||||
|             'home'      : self.home, | ||||
|             'shell'     : self.getshellbinary(), | ||||
|             'sysuid'    : self.sysuid, | ||||
|             'group'     : self.config.get('sysuser', 'defaultgroup'), | ||||
|             'home'      : self.delegateto.home, | ||||
|             'shell'     : self._get_shell_binary(), | ||||
|             'sysuid'    : self.delegateto.sysuid, | ||||
|             'group'     : config.get('sysuser', 'defaultgroup'), | ||||
|             'gecos'     : gecos, | ||||
|             'username'  : self.username} | ||||
|             'username'  : self.delegateto.username} | ||||
|         self.sucommand(cmdline) | ||||
|         cmdline = 'chpasswd --encrypted' | ||||
|         inline = '%(username)s:%(md5pass)s' % { | ||||
|             'username' : self.username, | ||||
|             'md5pass'  : self.md5pass} | ||||
|             'username' : self.delegateto.username, | ||||
|             'md5pass'  : self.delegateto.md5pass} | ||||
|         self.sucommand(cmdline, inline) | ||||
|         self.populate_home() | ||||
|         self._populate_home() | ||||
|         self._mail_sysuser() | ||||
| 
 | ||||
|     def delete_hook(self): | ||||
|         backupdir = os.path.join(self.config.get('common', | ||||
|                                                  'backupdir'), | ||||
|                                  self.config.get('sysuser', | ||||
|                                                  'homebackupdir')) | ||||
|     def delete_hook(self, session): | ||||
|         if self.delegateto.domains: | ||||
|             raise CannotDeleteError( | ||||
|                 self.delegateto, | ||||
|                 "it still has the following domains assigned: %s" % ( | ||||
|                 ", ".join([domain.name for domain in \ | ||||
|                            self.delegateto.domains]))) | ||||
|         backupdir = os.path.join(config.get('common', 'backupdir'), | ||||
|                                  config.get('sysuser', 'homebackupdir')) | ||||
|         if not os.path.isdir(backupdir): | ||||
|             cmdline = 'mkdir -p "%(backupdir)s"' % { | ||||
|                 'backupdir' : backupdir} | ||||
|  | @ -141,13 +144,11 @@ class Sysuser(BackendEntity): | |||
|                 raise Exception("could not create backup directory") | ||||
|         cmdline = 'deluser --remove-home --backup --backup-to "%(backupdir)s" %(username)s' % { | ||||
|             'backupdir' : backupdir, | ||||
|             'username'  : self.username} | ||||
|             'username'  : self.delegateto.username} | ||||
|         self.sucommand(cmdline) | ||||
| 
 | ||||
| sysusermapper = mapper(Sysuser, sysuser_table) | ||||
| 
 | ||||
| class SysuserHandler(BackendEntityHandler): | ||||
|     """BackendEntityHandler for Sysuser entities.""" | ||||
| 
 | ||||
|     def __init__(self, verbose = False): | ||||
|         BackendEntityHandler.__init__(self, Sysuser, verbose) | ||||
|         BackendEntityHandler.__init__(self, SysuserEntity, Sysuser, verbose) | ||||
|  |  | |||
|  | @ -24,82 +24,49 @@ import sys | |||
| import migrate.versioning.api | ||||
| from settings import * | ||||
| 
 | ||||
| dbversion = migrate.versioning.api.db_version( | ||||
|     config.get('database', 'uri'), | ||||
|     config.get('database', 'repository')) | ||||
| if dbversion < required_version: | ||||
|     print("""Database version is %d but required version is %d, run | ||||
| try: | ||||
|     dbversion = migrate.versioning.api.db_version( | ||||
|         config.get('database', 'uri'), | ||||
|         config.get('database', 'repository')) | ||||
|     if dbversion < required_version: | ||||
|         print("""Database version is %d but required version is %d, run | ||||
| 
 | ||||
|  migrate upgrade %s %s | ||||
| 
 | ||||
| to fix this.""" % | ||||
|           (dbversion, required_version, config.get('database', 'uri'), | ||||
|            config.get('database', 'repository'))) | ||||
|               (dbversion, required_version, config.get('database', 'uri'), | ||||
|                config.get('database', 'repository'))) | ||||
|         sys.exit(1) | ||||
| except exceptions.NoSuchTableError, nste:     | ||||
|     print nste | ||||
|     sys.exit(1) | ||||
| 
 | ||||
| meta = BoundMetaData(config.get('database', 'uri')) | ||||
| #meta.engine.echo = True | ||||
| client_table = Table( | ||||
|     'client', meta, | ||||
|     Column('clientid', Integer, primary_key=True), | ||||
|     Column('title', String(10)), | ||||
|     Column('firstname', String(64), nullable=False), | ||||
|     Column('lastname', String(64), nullable=False), | ||||
|     Column('address1', String(64), nullable=False), | ||||
|     Column('address2', String(64)), | ||||
|     Column('zip', String(7), nullable=False), | ||||
|     Column('city', String(64), nullable=False), | ||||
|     Column('country', String(5), nullable=False), | ||||
|     Column('phone', String(32), nullable=False), | ||||
|     Column('mobile', String(32)), | ||||
|     Column('fax', String(32)), | ||||
|     Column('email', String(64), unique=True, nullable=False), | ||||
|     schema = dbschema | ||||
|     ) | ||||
|     'client', meta, schema = dbschema, autoload = True) | ||||
| sysuser_table = Table( | ||||
|     'sysuser', meta, | ||||
|     Column('sysuserid', Integer, primary_key=True), | ||||
|     Column('username', String(12), nullable=False, unique=True), | ||||
|     Column('usertype', Integer, nullable=False, default=0, index=True), | ||||
|     Column('home', String(128)), | ||||
|     Column('shell', Boolean, nullable=False, default=False), | ||||
|     Column('clearpass', String(64)), | ||||
|     Column('md5pass', String(34)), | ||||
|     Column('clientid', Integer, ForeignKey("client.clientid"), | ||||
|            nullable=False), | ||||
|     Column('sysuid', Integer, nullable=False, unique=True), | ||||
|     Column('lastchange', DateTime, default=func.now()), | ||||
|     schema = dbschema | ||||
|     ) | ||||
|     'sysuser', meta, ForeignKeyConstraint(['clientid'], ['client.clientid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| domain_table = Table( | ||||
|     'domain', meta, | ||||
|     Column('domainid', Integer, primary_key=True), | ||||
|     Column('name', String(255), nullable=False, unique=True), | ||||
|     Column('master', String(20)), | ||||
|     Column('last_check', Integer), | ||||
|     Column('type', String(6), nullable=False), | ||||
|     Column('notified_serial', Integer), | ||||
|     Column('sysuserid', Integer, ForeignKey("sysuser.sysuserid"), | ||||
|            nullable=False), | ||||
|     schema = dbschema | ||||
|     ) | ||||
|     'domain', meta, ForeignKeyConstraint(['sysuserid'], ['sysuser.sysuserid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| record_table = Table( | ||||
|     'record', meta, | ||||
|     Column('recordid', Integer, primary_key=True), | ||||
|     Column('domainid', Integer, ForeignKey("domain.domainid"), | ||||
|            nullable=False), | ||||
|     Column('name', String(255)), | ||||
|     Column('type', String(6)), | ||||
|     Column('content', String(255)), | ||||
|     Column('ttl', Integer), | ||||
|     Column('prio', Integer), | ||||
|     Column('change_date', Integer), | ||||
|     schema = dbschema | ||||
|     ) | ||||
|     'record', meta, ForeignKeyConstraint(['domainid'], ['domain.domainid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| supermaster_table = Table( | ||||
|     'supermaster', meta, | ||||
|     Column('ip', String(25), nullable=False), | ||||
|     Column('nameserver', String(255), nullable=False), | ||||
|     Column('account', Integer, ForeignKey("sysuser.sysuserid"), | ||||
|            nullable=False), | ||||
|     schema = dbschema | ||||
|     ) | ||||
|     ForeignKeyConstraint(['account'], ['sysuser.sysuserid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| mailaccount_table = Table( | ||||
|     'mailaccount', meta, | ||||
|     ForeignKeyConstraint(['domainid'], ['domain.domainid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| mailaddress_table = Table( | ||||
|     'mailaddress', meta, | ||||
|     ForeignKeyConstraint(['domainid'], ['domain.domainid']), | ||||
|     schema = dbschema, autoload = True) | ||||
| mailtarget_table = Table( | ||||
|     'mailtarget', meta, | ||||
|     ForeignKeyConstraint(['mailaddressid'], ['mailaddress.mailaddressid']), | ||||
|     schema = dbschema, autoload = True) | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| import getopt, sys | ||||
| import getopt, sys, logging | ||||
| from gnuviechadmin.exceptions import GnuviechadminError | ||||
| 
 | ||||
| class CliCommand: | ||||
|  | @ -198,6 +198,8 @@ Common options: | |||
|     def __init__(self, args): | ||||
|         """This initializes the command with the given command line | ||||
|         arguments and executes it.""" | ||||
|         self.logger = logging.getLogger("%s.%s" % ( | ||||
|             self.__class__.__module__, self.__class__.__name__)) | ||||
|         self._data = {} | ||||
|         if len(args) > 0: | ||||
|             if args[0] in self._subcommands(): | ||||
|  |  | |||
|  | @ -59,6 +59,8 @@ class ClientCli(CliCommand.CliCommand): | |||
|                       "the client id", True)])} | ||||
|                       | ||||
|     def _execute(self, subcommand): | ||||
|         self.logger.debug("execute %s with data %s", subcommand, | ||||
|                           str(self._data)) | ||||
|         from gnuviechadmin.backend import client | ||||
|         from gnuviechadmin import exceptions | ||||
|         if subcommand == "create": | ||||
|  |  | |||
|  | @ -43,6 +43,8 @@ class DomainCli(CliCommand.CliCommand): | |||
|                       "the domain id", True)])} | ||||
| 
 | ||||
|     def _execute(self, subcommand): | ||||
|         self.logger.debug("execute %s with data %s", subcommand, | ||||
|                           str(self._data)) | ||||
|         from gnuviechadmin.backend.domain import DomainHandler | ||||
|         from gnuviechadmin import exceptions | ||||
|         if subcommand == "create": | ||||
|  |  | |||
|  | @ -37,16 +37,19 @@ class RecordCli(CliCommand.CliCommand): | |||
|                      (["-p", "--prio"], "prio", | ||||
|                       "MX record priority", False), | ||||
|                      (["--ttl"], "ttl", | ||||
|                       "Time to live", False), | ||||
|                       "time to live", False), | ||||
|                      (["-d", "--domainid"], "domainid", | ||||
|                       "Domain id", True)]), | ||||
|                       "domain id", True)]), | ||||
|         'list'   : ("lists existing records", | ||||
|                     []), | ||||
|                     [(["-d", "--domainid"], "domainid", | ||||
|                       "domain id", False)]), | ||||
|         'delete' : ("delete a record", | ||||
|                     [(["-r", "--recordid"], "recordid", | ||||
|                       "the record id", True)])} | ||||
| 
 | ||||
|     def _execute(self, subcommand): | ||||
|         self.logger.debug("execute %s with data %s", subcommand, | ||||
|                           str(self._data)) | ||||
|         from gnuviechadmin.backend.record import RecordHandler | ||||
|         from gnuviechadmin import exceptions | ||||
|         if subcommand == "create": | ||||
|  | @ -60,7 +63,7 @@ class RecordCli(CliCommand.CliCommand): | |||
|                 print cfe | ||||
|                 sys.exit(2) | ||||
|         elif subcommand == "list": | ||||
|             records = RecordHandler(self._verbose).fetchall() | ||||
|             records = RecordHandler(self._verbose).fetchall(**self._data) | ||||
|             for record in records: | ||||
|                 print record | ||||
|         elif subcommand == "delete": | ||||
|  |  | |||
|  | @ -47,6 +47,8 @@ class SysuserCli(CliCommand.CliCommand): | |||
|                       "the system user id", True)])} | ||||
| 
 | ||||
|     def _execute(self, subcommand): | ||||
|         self.logger.debug("execute %s with data %s", subcommand, | ||||
|                           str(self._data)) | ||||
|         from gnuviechadmin.backend import sysuser | ||||
|         from gnuviechadmin import exceptions | ||||
|         if subcommand == "create": | ||||
|  |  | |||
|  | @ -35,6 +35,13 @@ repository = /etc/gnuviechadmin/dbrepo | |||
| [common] | ||||
| suwrapper = sudo | ||||
| backupdir = /var/backups/gnuviechadmin | ||||
| templatedir = /etc/gnuviechadmin/templates | ||||
| mailtemplates = mails | ||||
| log.cfg = /etc/gnuviechadmin/logging.cfg | ||||
| 
 | ||||
| [client] | ||||
| create.mail = create_client.txt | ||||
| create_subject = A new client ${firstname} ${lastname} has been created. | ||||
| 
 | ||||
| [sysuser] | ||||
| nameprefix = usr | ||||
|  | @ -46,4 +53,27 @@ shellno = /usr/bin/scponly | |||
| defaultgroup = wwwusers | ||||
| gecos = Webuser %s | ||||
| homebackupdir = homes | ||||
| hometemplate = /etc/gnuviechadmin/templates/home | ||||
| hometemplate = home | ||||
| create.mail = create_sysuser.txt | ||||
| create_subject = A new system user ${username} has been created. | ||||
| 
 | ||||
| [domain] | ||||
| defaultmxprio = 5 | ||||
| defaultrefresh = 86400 | ||||
| defaultretry = 7200 | ||||
| defaultexpire = 1209600 | ||||
| defaultminimumttl = 86400 | ||||
| defaultttl = 86400 | ||||
| htdir = html | ||||
| logpath = /var/log/apache2 | ||||
| statspath = /home/stats | ||||
| htdocstemplate = domain | ||||
| conftemplates = domainconf | ||||
| apachetemplate = vhost.conf | ||||
| statshtaccesstemplate = htaccess-stats | ||||
| modlogantemplate = modlogan.conf | ||||
| modlogandir = /var/lib/gnuviechadmin/stats | ||||
| sitesdir = /etc/apache2/sites-available | ||||
| authdir = /etc/apache2/authdata | ||||
| create.mail = create_domain.txt | ||||
| create_subject = A new domain ${domain} has been created. | ||||
|  |  | |||
|  | @ -73,3 +73,16 @@ class ValidationFailedError(GnuviechadminError): | |||
|         if self.cause: | ||||
|             msg += " The reason is %s." % (str(self.cause)) | ||||
|         return msg | ||||
| 
 | ||||
| class CannotDeleteError(GnuviechadminError): | ||||
|     """This exception should be raised if an entity cannot be deleted | ||||
|     because of some unmatched precondition.""" | ||||
|     def __init__(self, instance, cause = None): | ||||
|         self.instance = instance | ||||
|         self.cause = cause | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         msg = "Cannot delete %s." % (str(self.instance)) | ||||
|         if self.cause: | ||||
|             msg += " The reason is %s." % (str(self.cause)) | ||||
|         return msg | ||||
|  |  | |||
							
								
								
									
										34
									
								
								gnuviechadmin/logging.cfg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								gnuviechadmin/logging.cfg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| [formatters] | ||||
| keys=simple | ||||
| 
 | ||||
| [formatter_simple] | ||||
| format=%(asctime)s %(levelname)s %(name)s: %(message)s | ||||
| datefmt= | ||||
| 
 | ||||
| [handlers] | ||||
| keys=handler01,handler02 | ||||
| 
 | ||||
| [handler_handler01] | ||||
| class=handlers.RotatingFileHandler | ||||
| level=DEBUG | ||||
| formatter=simple | ||||
| args=('gnuviechadmin.log', 'a', 10485760, 5) | ||||
| 
 | ||||
| [handler_handler02] | ||||
| class=StreamHandler | ||||
| level=NOTSET | ||||
| formatter=simple | ||||
| args=(sys.stdout,) | ||||
| 
 | ||||
| [loggers] | ||||
| keys=root,gnuviechadmin | ||||
| 
 | ||||
| [logger_root] | ||||
| level=NOTSET | ||||
| handlers=handler02 | ||||
| 
 | ||||
| [logger_gnuviechadmin] | ||||
| level=DEBUG | ||||
| handlers=handler01 | ||||
| propagate=0 | ||||
| qualname=gnuviechadmin | ||||
|  | @ -19,7 +19,7 @@ | |||
| # | ||||
| # Version: $Id$ | ||||
| 
 | ||||
| import os, popen2 | ||||
| import pwd, grp | ||||
| 
 | ||||
| class PasswdUser(object): | ||||
|     """This class represents users in the user database.""" | ||||
|  | @ -45,7 +45,7 @@ class PasswdGroup(object): | |||
|     def __init__(self, groupname, pw, gid, members): | ||||
|         self.groupname = groupname | ||||
|         self.gid = int(gid) | ||||
|         self.members = members.split(",") | ||||
|         self.members = members | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "%s(%s:%d:%s)" % (self.__class__.__name__, | ||||
|  | @ -53,42 +53,41 @@ class PasswdGroup(object): | |||
|                                  self.gid, | ||||
|                                  ",".join(self.members)) | ||||
| 
 | ||||
| def parsegroups(): | ||||
|     (stdout, stdin) = popen2.popen2("getent group") | ||||
|     return [PasswdGroup(*arr) for arr in [line.strip().split(":") for line in stdout]] | ||||
| def parse_groups(): | ||||
|     return [PasswdGroup(*arr) for arr in grp.getgrall()] | ||||
| 
 | ||||
| def parseusers(): | ||||
|     (stdout, stdin) = popen2.popen2("getent passwd") | ||||
|     return [PasswdUser(*arr) for arr in [line.strip().split(":") for line in stdout]] | ||||
| def parse_users(): | ||||
|     return [PasswdUser(*arr) for arr in pwd.getpwall()] | ||||
| 
 | ||||
| def finduserbyprefix(prefix): | ||||
| def find_user_by_prefix(prefix): | ||||
|     """Finds all user entries with the given prefix."""     | ||||
|     return [user for user in parseusers() if user.username.startswith(prefix)] | ||||
|     return [user for user in parse_users() if user.username.startswith(prefix)] | ||||
| 
 | ||||
| def getuserbyid(uid): | ||||
| def get_user_by_id(uid): | ||||
|     """Gets the user with the given user id.""" | ||||
|     users = [user for user in parseusers() if user.uid == uid] | ||||
|     users = [user for user in parse_users() if user.uid == uid] | ||||
|     if users: | ||||
|         return users[0] | ||||
|     return None | ||||
| 
 | ||||
| def getgroupbyid(gid): | ||||
| def get_group_by_id(gid): | ||||
|     """Gets the group with the given group id.""" | ||||
|     groups = [group for group in parsegroups() if group.gid == gid] | ||||
|     groups = [group for group in parse_groups() if group.gid == gid] | ||||
|     if groups: | ||||
|         return groups[0] | ||||
|     return None | ||||
| 
 | ||||
| def getmaxuid(boundary = 65536): | ||||
| def get_max_uid(boundary = 65536): | ||||
|     """Gets the highest uid value.""" | ||||
|     return max([user.uid for user in parseusers() if user.uid <= boundary]) | ||||
|     return max([user.uid for user in parse_users() if user.uid <= boundary]) | ||||
| 
 | ||||
| def getmaxgid(boundary = 65536): | ||||
| def get_max_gid(boundary = 65536): | ||||
|     """Gets the highest gid value.""" | ||||
|     return max([group.gid for group in parsegroups() if group.gid <= boundary]) | ||||
|     return max([group.gid for group in parse_groups() \ | ||||
|                 if group.gid <= boundary]) | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     print "Max UID is %d" % (getmaxuid(40000)) | ||||
|     print "Max GID is %d" % (getmaxgid(40000)) | ||||
|     print "User with max UID is %s" % (getuserbyid(getmaxuid(40000))) | ||||
|     print "Group with max GID is %s" % (getgroupbyid(getmaxgid(40000))) | ||||
|     print "Max UID is %d" % (get_max_uid(40000)) | ||||
|     print "Max GID is %d" % (get_max_gid(40000)) | ||||
|     print "User with max UID is %s" % (get_user_by_id(get_max_uid(40000))) | ||||
|     print "Group with max GID is %s" % (get_group_by_id(get_max_gid(40000))) | ||||
|  |  | |||
|  | @ -21,16 +21,17 @@ | |||
| 
 | ||||
| import crypt, crack, random | ||||
| 
 | ||||
| _pwchars = [] | ||||
| for pair in (('0', '9'), ('A', 'Z'), ('a', 'z')): | ||||
|     _pwchars.extend(range(ord(pair[0]), ord(pair[1]))) | ||||
| for char in "-+/*_@": | ||||
|     _pwchars.append(ord(char)) | ||||
| 
 | ||||
| def generatepassword(minlength = 8, maxlength = 12): | ||||
|     """Generates a random password with a length between the given | ||||
|     minlength and maxlength values.""" | ||||
|     pwchars = [] | ||||
|     for pair in (('0', '9'), ('A', 'Z'), ('a', 'z')): | ||||
|         pwchars.extend(range(ord(pair[0]), ord(pair[1]))) | ||||
|     for char in "-+/*_@": | ||||
|         pwchars.append(ord(char)) | ||||
|     return "".join([chr(letter) for letter in \ | ||||
|                     random.sample(pwchars, | ||||
|                     random.sample(_pwchars, | ||||
|                                   random.randint(minlength, maxlength))]) | ||||
| 
 | ||||
| def checkpassword(password): | ||||
|  | @ -45,7 +46,7 @@ def checkpassword(password): | |||
| def md5_crypt_password(password): | ||||
|     """Hashes the given password with MD5 and a random salt value.""" | ||||
|     salt = "".join([chr(letter) for letter in \ | ||||
|                     random.sample(range(ord('a'), ord('z')), 8)]) | ||||
|                     random.sample(_pwchars, 8)]) | ||||
|     return crypt.crypt(password, '$1$' + salt) | ||||
| 
 | ||||
| def get_pw_tuple(password = None): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue