-
-
Save plugandplay/1401980 to your computer and use it in GitHub Desktop.
Script for creating user accounts (including LDAP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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. <[email protected]> | |
# | |
############################################################################### | |
# | |
# 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 <[email protected]> | |
# @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
Hola, este script no me funcionó hasta que reemplace todos los "raw_input()" por "input()".
Hello, this script did't work for me until I replaced all the "raw_input()" for "input()".