1
0
Fork 0

- remove domain specific code from mail tools

- make mail aliases and pop3 accounts domain properties
- add class for system users
- move GNVDomain class to gnuviech package
- add more logging
- add password hashing, passwd and shadow functions to gnuviech.tools


git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/gnuviech.info/gnuviechadmin/trunk@87 a67ec6bc-e5d5-0310-a910-815c51eb3124
This commit is contained in:
Jan Dittberner 2004-12-26 19:29:32 +00:00
parent b9ec217d1e
commit fa6961463e
6 changed files with 316 additions and 76 deletions

View file

@ -8,7 +8,7 @@ from log4py import Logger, FileAppender, LOGLEVEL_DEBUG
class GNVPrefs:
"""This class has static variables for the settings of the GNUViech
administration tool. These settings can be customized in the file
administration tool. These settings may be customized in the file
gvadm.preferences."""
# define standard values
PWDMINLENGTH = 6
@ -31,10 +31,33 @@ class GNVPrefs:
WEBSTATSDIR = WEBHOMEDIR+"stats/"
LOGDIR = BASEPREFIX+"/var/log"
LOGFILE = LOGDIR+"/gnvadm.log"
USERTYPES = {
"web" : {
"minuid" : 10000,
"maxuid" : 10999,
"group" : "wwwusers",
"fullname" : "Webuser %s",
"home" : WEBHOMEDIR + "%s",
"shell" : "/bin/true",
"nohome" : 1,
"disabledpass" : 1
},
"pop3" : {
"minuid" : 20000,
"maxuid" : 29999,
"group" : "poponly",
"fullname" : "Popuser %s",
"home" : POPHOMEDIR + "%s",
"shell" : "/bin/true",
"nohome" : 1,
"disabledpass" : 1
}
}
# load custom settings
execfile("gvadm.preferences")
def __init__(self):
self.logger = self.getLogger(self)
self.setupDirs()
def __repr__(self):
@ -76,6 +99,30 @@ class GNVPrefs:
logger.set_loglevel(LOGLEVEL_DEBUG)
return logger
def getNextSysId(self, type):
nextid = self.USERTYPES[type]["minuid"]
file = open(self.BASEPREFIX+"/etc/passwd", "r")
for line in file.readlines():
pwdline = tools.splitPasswdLine(line)
self.logger.debug(str(pwdline))
uid = int(pwdline["uid"])
if (uid in
range(int(self.USERTYPES[type]["minuid"]),
int(self.USERTYPES[type]["maxuid"]))
and nextid <= uid): nextid = uid+1
return nextid
def getGroupId(self, type): pass
def getFullName(self, type, username):
return self.USERTYPES[type]["fullname"] % username
def getHomeDir(self, type, username):
return self.USERTYPES[type]["home"] % username
def getShell(self, type):
return self.USERTYPES[type]["shell"]
class NoAdmDirError(Exception):
"""This exception is raised if the admin directory does'nt exist."""
pass

View file

@ -0,0 +1,152 @@
"""Package for GNUViech Admin main types and functions
(c) Copyright 2004 Jan Dittberner, IT-Consulting & Solutions
Germany
"""
import os, pwd
import gnuviech
from gnuviech import sysuser
class DomainNotExistentError(Exception): pass
class DomainFileNotExistentError(Exception): pass
class GNVDomain:
"""Represents a domain in the GNUViech admin tool"""
def __init__(self, domain, prefs):
"""Initializes the domain object"""
self.logger = prefs.getLogger(self)
self.prefs = prefs
self.name = domain
self.webaccount = None
self.zone = None
self.statsusers = {}
self.mailaliases = {}
self.pop3accounts = {}
try:
self.__findUser()
except gnuviech.NoAdmDirError:
prefs.setupDirs()
self.__init__(domain)
except DomainFileNotExistentError:
self.__createDomainFile()
self.__init__(domain, prefs)
except DomainNotExistentError:
self.__createUser()
self.createWebUser()
def __repr__(self):
retval = "Domain "+self.name
if not self.username is None:
retval += ", User "+self.username
else:
retval += ", new domain"
return retval
def __createDomainFile(self):
"""Create the domain user id map file."""
file = open(gnuviech.GNVPrefs.GVADMDIR+"domains", "w")
file.close()
def __createUser(self):
"""Create a user for the domain."""
file = open(self.prefs.GVADMDIR+"domains", "r")
id = 0
for line in file.readlines():
(key, value) = line.split(":")
if (int(value) > id): id = int(value)
file.close()
id += 1
file = open(self.prefs.GVADMDIR+"domains", "a")
file.write("%s:%d\n" % (self.name, id))
file.close()
self.__findUser()
def __findUser(self):
"""Finds the user for the domain."""
self.username = None
if (os.access(self.prefs.GVADMDIR, os.R_OK)):
try:
domainsfile = open(self.prefs.GVADMDIR+"domains", "r")
for line in domainsfile.readlines():
(key, value) = line.split(":")
if (key == self.name):
self.username = "%s%02d" % (
self.prefs.USERPREFIX,
int(value))
domainsfile.close()
if self.username is None:
raise DomainNotExistentError
except IOError:
raise DomainFileNotExistentError
else:
raise gnuviech.NoAdmDirError
def getMaxPop3Id(self):
maxid = 0
try:
passwdfile = open(gnuviech.GNVPrefs.BASEPREFIX+"/etc/passwd", "r")
for line in passwdfile.readlines():
(login, passwd, uid, gid, name, dir, shell) = line.split(":")
if login.startswith(self.username + "p"):
id = int(login[len(self.username):])
print id
if (id > maxid): maxid = id
except IOError:
pass
return maxid
def getNextUser(self, usertype):
"""Gets the next user for the given type."""
if (usertype == "web"):
return self.username
if (usertype == "pop3"):
return "%sp%d" % (self.username, self.getMaxPop3Id()+1)
def addPOP3Account(self, account):
self.pop3accounts[account.localpart] = account
def addMailAlias(self, alias):
self.mailaliases[alias.localpart] = alias
def createWebUser(self):
try:
self.webaccount = sysuser.SystemUser(self.prefs, self.username)
except sysuser.UserNotInPasswdError:
self.webaccount = sysuser.createUser(self.prefs, self.username,
"web")
self.logger.debug(str(self.webaccount))
# #!/bin/sh
# . /usr/local/etc/preferences
# if [ -n $USERPREFIX ]; then
# USERPREFIX="usr"
# fi
# if [ $1 == "" ]; then
# echo "usage: $0 <usernum>"
# exit
# fi
# NEWUSER="$USERPREFIX$1"
# NEWHOME="/home/www/$NEWUSER"
# LOGDIR="/home/www/logfiles/$NEWUSER"
# adduser --home "$NEWHOME" --shell /bin/true --no-create-home --firstuid 10000 --ingroup wwwusers --disabled-password --gecos "Webuser $NEWUSER" $NEWUSER
# echo "${NEWUSER}:${NEWPASS}" | chpasswd
# mkdir -p "$NEWHOME/"{html,cgi-bin}
# mkdir -p "$LOGDIR"
# chown -Rc www-data.www-data "$LOGDIR"
# chmod 0750 "$LOGDIR"
# chown -Rc $NEWUSER.wwwusers "$NEWHOME"
# mkdir -p "$NEWHOME/html/stats"
# chown modlogan.wwwusers "$NEWHOME/html/stats"
# htpasswd -bc "/home/www/${NEWUSER}stats" "${NEWUSER}" "${NEWPASS}"
# echo added new web user $NEWUSER with password $NEWPASS
if __name__ == "__main__":
dom = GNVDomain("dittberner.info")
print dom

View file

@ -0,0 +1,62 @@
from gnuviech import tools
class UserNotInPasswdError(Exception): pass
class NoPasswordInShadowError(Exception): pass
class SystemUser:
def __init__(self, prefs, username):
self.prefs = prefs
self.logger = prefs.getLogger(self)
self.getUser(username)
self.logger.debug(str(self))
def getUser(self, username):
pwdfile = open(self.prefs.BASEPREFIX+"/etc/passwd", "r")
for line in pwdfile.readlines():
pwdline = tools.splitPasswdLine(line)
self.logger.debug("PWDLINE: %s" % pwdline)
if pwdline["loginname"] == username:
self.username = pwdline["loginname"]
self.password = self.getPassword()
self.uid = pwdline["uid"]
self.gid = pwdline["gid"]
self.fullname = pwdline["fullname"]
self.homedir = pwdline["homedir"]
self.shell = pwdline["shell"]
return
pwdfile.close()
raise UserNotInPasswdError
def getPassword(self):
shadowfile = open(self.prefs.BASEPREFIX+"/etc/shadow", "r")
for line in shadowfile.readlines():
shadowline = tools.splitShadowLine(line)
self.logger.debug("SHADOWLINE: %s" % shadowline)
if shadowline["loginname"] == self.username:
shadowfile.close()
return shadowline["passwordhash"]
shadowfile.close()
raise NoPasswordInShadowError
def createUser(prefs, username, type):
line = ":".join((username, "x",
str(prefs.getNextSysId(type)),
str(prefs.getGroupId(type)),
prefs.getFullName(type, username),
prefs.getHomeDir(type, username),
prefs.getShell(type)))
passwdfile = open(prefs.BASEPREFIX+"/etc/passwd", "a")
passwdfile.write("%s\n" % line)
passwdfile.close()
createShadowItem(prefs, username, type, tools.generatePassword())
return SystemUser(prefs, username)
def createShadowItem(prefs, username, type, password):
line = ":".join((username,
tools.hashPassword(password, "md5"),
str(tools.daysSince1970()),
"0", "99999", "7", "", "", ""))
shadowfile = open(prefs.BASEPREFIX+"/etc/shadow", "a")
shadowfile.write("%s\n" % line)
shadowfile.close()

View file

@ -5,16 +5,62 @@
import random, re
from gnuviech import GNVPrefs
from crypt import crypt
from time import time
def generatePassword():
"""Generates a password from the chars in GNVPrefs.PWDCHARS with
a length between GNVPrefs.PWDMINLENGTH and GNVPrefs.PWDMAXLENGTH."""
return "".join([chr(char) for char in
random.sample(GNVPrefs.PWDCHARS,
random.randint(GNVPrefs.PWDMINLENGTH,
GNVPrefs.PWDMAXLENGTH))])
def generateSalt():
saltchars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
salt = []
for i in range(8):
salt.append(saltchars[random.randint(0, len(saltchars) - 1)])
return "".join(salt)
def checkEmail(email):
"""Returns a match object if the given email address is syntactically
correct otherwise it returns None"""
# regex for email check
p = re.compile(r'^([a-zA-Z0-9_\-.]+)@([a-zA-Z0-9\-]+(\.|[a-zA-Z0-9\-]+)*\.[a-z]{2,5})$')
return p.search(email)
def splitPasswdLine(line):
loginname, password, uid, gid, fullname, directory, shell = line.split(":")
return {
"loginname" : loginname,
"password" : password,
"uid" : uid,
"gid" : gid,
"fullname" : fullname,
"homedir" : directory,
"shell" : shell
}
def splitShadowLine(line):
(loginname, passwordhash, lastchange, maychange, mustchange, warnexpire,
disabled, disabledsince, reserved) = line.split(":")
return {
"loginname" : loginname,
"passwordhash" : passwordhash,
"lastchange" : lastchange,
"maychange" : maychange,
"mustchange" : mustchange,
"warnexpire" : warnexpire,
"disabled" : disabled,
"disabledsince" : disabledsince,
"reserved" : reserved
}
def hashPassword(password, method="md5"):
if (method == "md5"):
return crypt(password, "$1$%s" % generateSalt())
return crypt(password, generateSalt())
def daysSince1970():
return int(time()/(3600*24))