Skip to content

Instantly share code, notes, and snippets.

@jirutka
Created July 31, 2011 15:52
Show Gist options
  • Save jirutka/1116902 to your computer and use it in GitHub Desktop.
Save jirutka/1116902 to your computer and use it in GitHub Desktop.
Script for creating user accounts (including LDAP)
#!/usr/bin/python
# -*- coding: utf-8 -*-
# encoding: utf-8
###############################################################################
# Copyright 2011 Jakub Jirutka. All rights reserved.
#
# "THE KOFOLA-WARE LICENSE" (Revision 1):
# Jakub Jirutka originally wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a Kofola in return. <jakub@jirutka.cz>
#
###############################################################################
#
# Script for creating user accounts
#
# This scipt will ask you for some information about new user and then creates
# user entry in LDAP, home directory structure with proper ownership,
# permissions and ACL, copy skeleton and finally sets quota.
#
#
# @author Jakub Jirutka <jakub@jirutka.cz>
# @version 1.2
# @date 2011-07-31
#
import pwd
import grp
import os
import sys
import subprocess
import shutil
import ldap
import getpass
import math
import string
from random import choice
from time import time
################################ Constants ################################
HOME_BASE = "/home"
HOME_BASE_LOC = "/mnt/home"
HOME_CHMOD = 0o751
HOME_DEF_ACL = "u::rwx,g::-,o::-"
HOME_DEV = "/dev/lvm5/home"
WWW_DIR = "www"
WWW_GROUP = "www"
WWW_CHMOD = 0o2755
WWW_DEF_ACL = "u::rwx,g::rx,o::rx"
PUBL_DIR = "public"
PUBL_GROUP = "users"
PUBL_CHMOD = 0o2750
PUBL_DEF_ACL = "u::rwx,g::rx,o::-"
PRIV_DIR = "private"
PRIV_CHMOD = 0o2700
PRIV_DEF_ACL = "u::rwx,g::-,o::-"
FIRST_UID = 601
LAST_UID = 700
DEFAULT_SHELL = "/bin/false"
SKEL_PATH = "/etc/skel"
LDAP_HOST = "ldap://localhost"
LDAP_BASE_DN = "ou=People,dc=jirutka,dc=cz"
LDAP_ADMIN_DN = "cn=root,dc=jirutka,dc=cz"
################################ Functions ################################
# Asks for LDAP admin password
def input_ldap_pass():
return getpass.getpass("Enter LDAP manager password: ")
# Asks for information about user to create
def input_data():
user = {}
print("Enter some information about new user.")
# Name and email
user['firstname'] = raw_input("Firstname: ")
user['lastname'] = raw_input("Lastname: ")
user['email'] = raw_input("E-mail: ")
# Username
user['username'] = raw_input("Username: ")
if (check_username(user["username"])):
print("This username is already used!")
sys.exit(2)
# UID
uid = raw_input("UID (or empty for generate): ")
if (uid == ""):
user['uid'] = generate_uid()
else:
uid = int(uid)
if (check_uid(uid)):
print("This UID is already used!")
sys.exit(2)
else:
user['uid'] = uid
# Group
user['group'] = raw_input("Group name: ")
if (not(check_group(user['group']))):
print("No such group found!")
sys.exit(2)
# Login shell
shell = raw_input("Login shell [default is /bin/false]: ")
if (shell == ""):
user['shell'] = DEFAULT_SHELL
else:
user['shell'] = shell;
# Allowed hosts - where can user login?
hosts = raw_input("Allowed hosts (space-sep hostnames or * for all): ")
user['hosts'] = hosts.split()
# Create www?
www = raw_input("Create www dir? [default is y]: ")
if (www == 'n'):
user['www'] = False
elif (www == 'y' or www == ''):
user['www'] = True
else:
print("You must type 'y' or 'n' or nothing for default!")
sys.exit(1)
# FS quota for home directory
quota = raw_input("Quota for home dir in GB [default is none]: ")
user['quota'] = int(quota)
print("")
return user
# Checks if given username already exists
def check_username(username):
try:
pwd.getpwnam(username)
except KeyError:
return False
else:
return True
# Checks if given UID already exists
def check_uid(uid):
try:
pwd.getpwuid(uid)
except KeyError:
return False
else:
return True
# Finds first free UID (in range FIRST_UID : LAST_UID)
def generate_uid():
for uid in range(FIRST_UID, LAST_UID):
try:
pwd.getpwuid(uid)
except KeyError:
return uid
else:
pass
raise Exception("No free UID!")
# Finds UID of given user
def find_uid(username):
return pwd.getpwnam(username)[2]
# Checks if given group already exists
def check_group(name):
try:
grp.getgrnam(name)
except KeyError:
return False
else:
return True
# Finds GID of given group
def find_gid(name):
return grp.getgrnam(name)[2]
# Returns path of users home directory on THIS filesystem (where you're running
# this script, not what is in LDAP)
def home_path(username):
return HOME_BASE_LOC + '/' + username
# Generates random initial password
def generate_password():
chars = string.letters + string.digits
newpasswd = ""
for i in range(8):
newpasswd = newpasswd + choice(chars)
return newpasswd
# This will try to bind to LDAP with admin DN and givem password and exit
# the script with error message if it fails.
def try_ldap_bind(admin_pass):
try:
ldap_conn = ldap.initialize(LDAP_HOST)
except ldap.SERVER_DOWN:
print("Can't contact LDAP server")
exit(4)
try:
ldap_conn.simple_bind_s(LDAP_ADMIN_DN, admin_pass)
except ldap.INVALID_CREDENTIALS:
print("This password is incorrect!")
sys.exit(3)
print("Authentization successful")
print("")
# Creates new entry in LDAP for given user
def create_user(user, admin_pass):
dn = 'uid=' + user['username'] + ',' + LDAP_BASE_DN
fullname = user['firstname'] + ' ' + user['lastname']
home_dir = HOME_BASE + '/' + user['username']
gid = find_gid(user['group'])
lastchange = int(math.floor(time() / 86400))
entry = []
entry.extend([
('objectClass', ["person", "organizationalPerson", "inetOrgPerson", "posixAccount", "top", "shadowAccount", "hostObject"]),
('uid', user['username']),
('cn', fullname),
('givenname', user['firstname']),
('sn', user['lastname']),
('mail', user['email']),
('uidNumber', str(user['uid'])),
('gidNumber', str(gid)),
('loginShell', user['shell']),
('homeDirectory', home_dir),
('shadowMax', "99999"),
('shadowWarning', "7"),
('shadowLastChange', str(lastchange)),
('userPassword', user['password'])
])
if (len(user['hosts'])):
entry.append( ('host', user['hosts']) )
ldap_conn = ldap.initialize(LDAP_HOST)
ldap_conn.simple_bind_s(LDAP_ADMIN_DN, admin_pass)
try:
ldap_conn.add_s(dn, entry)
finally:
ldap_conn.unbind_s()
# Creates new directory with given permsissions and ACL
def create_dir(path, username, group, chmod, def_acl = None):
os.mkdir(path)
os.chown(path, find_uid(username), find_gid(group))
os.chmod(path, chmod)
if (def_acl): subprocess.Popen(["setfacl", "-dm", def_acl, path])
# Creates home directory structure for given user
def create_home(username, group):
home_path = home_path(username)
create_dir(home_path, username, group, HOME_CHMOD)
copy_skel(home_path, username, group)
subprocess.Popen(["setfacl", "-dm", HOME_DEF_ACL, home_path])
publ_path = home_path + '/' + PUBL_DIR
create_dir(publ_path, username, PUBL_GROUP, PUBL_CHMOD, PUBL_DEF_ACL)
priv_path = home_path + '/' + PRIV_DIR
create_dir(priv_path, username, group, PRIV_CHMOD, PRIV_DEF_ACL)
# Creates www directory for given user
def create_www(username):
www_path = home_path(username) + '/' + WWW_DIR
create_dir(www_path, username, WWW_GROUP, WWW_CHMOD, WWW_DEF_ACL)
# Copy skeleton to home directory
def copy_skel(home_path, username, group):
names = os.listdir(SKEL_PATH)
for name in names:
src_path = SKEL_PATH + '/' + name
dst_path = home_path + '/' + name
if os.path.isdir(src_path):
shutil.copytree(src_path, dst_path)
else:
shutil.copy(src_path, dst_path)
# TODO ošetřit nastavení práv při použití copytree
os.chown(dst_path, find_uid(username), find_gid(group))
# This will set hard quota limit (size in GB) for device
def set_quota(username, size, dev):
size_kb = size * 1048576
subprocess.Popen(["setquota", "-u", "-F", "vfsv0", username, "0", str(size_kb), "0", "0", dev])
################################## Main ###################################
admin_pass = input_ldap_pass()
try_ldap_bind(admin_pass)
user = input_data()
user['password'] = generate_password()
print("Creating LDAP entry")
create_user(user, admin_pass)
print("Creating home directory")
create_home(user['username'], user['group'])
if (user['www']):
print("Creating www directory")
create_www(user['username'])
if (user['quota']):
print("Setting fs quota on " + HOME_DEV + " to " + str(user['quota']) + " GB")
set_quota(user['username'], user['quota'], HOME_DEV)
print("")
print("Account for user " + user['username'] + " (" + str(user['uid']) + ") successfuly created")
print("Initial password is: " + user['password'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment