#!/usr/bin/env python # Copyright (c) 2002 by Zoran Pucar # zoran@lysator.liu.se # All Rights Reserved # License: This is free software. You may use this software for any # purpose including modification/redistribution, so long as # this header remains intact and that you do not claim any # rights of ownership or authorship of this software. This # software has been tested, but no warranty is expressed or # implied. # import string, sys, os, time # # Configuration # # Place where your files from which you create yp maps are. Don't forget trailing slash ypdir = "/export/zorans/maps/" passwdfile = ypdir+"passwd" autohomefile = ypdir+"auto_home" groupfile = ypdir+"group" shadowfile = ypdir+"shadow" # Where to create fysical home directories, usually /export/home/. Don't forget trailing slash fys_dir = "/export2/home/" # Where to mount home directories. Often /home/. Don't forget trailing slash home_dir = "/home/" # Fileserver, this is sometimes localhost. If not, specify fileserver. # home directories via /net/ other then /export/... # This code below finds out the hostname server = os.uname()[1].split(".")[0] #server = "milan" # Directory where skel directories are placed # remember to name your skel directories skel. # Here you need to specify path including ".../skel." skeldir = "/export/zorans/skel." # If recom_uid is set to 1, script parses your passwd file and tries to find highest available # UID between lowest_uid and 59999. If you set this to 0 it doesn't recomend an UID. recom_uid = 1 # Some UID-s are "reserved" for special users. Usually "normal" users start at UID 1000. This # is up to you to decide by setting lowest_uid to value you want lowest_uid = 2000 #highest_uid is the highest uid that script will recomend. highest_uid = 59999 # This script asks you if you want to create user manually or "automatically" by pasting in output # from ypcat passwd| grep username from another system. If you know that you ALWAYS create users # manually or if you know that you ALWAYS create users by pasting in row from another system you # can set this switch to eather 0 = ask, 1 = manual, 2 = paste create = 1 # If you want this script to create home directories (by copyng skel dir) set # createhome variable to 1 else to 0 createhome = 1 # If you use shadow passwords set use_shadow to 1. If you don't, set it to 2. If # it is set to 0 you will be prompted for it use_shadow = 0 # Usually home directories have 755 as permissions. However, sometimes one don't want users # to be able to read or enter other users home directories. In that case 700 is good. Here you set it. homedir_perms = 755 # If you want to backup all files that are modified in some directory set backup to 1 else to 0 backup_files = 1 # Where to save all backup files. Don't forget trailing slash backup_dir = "/root/backup/" # If you want make to be run after updating files and creating directories set runmake to 1 else 0 runmake = 1 # Path to make if runmake is set to 1 make_bin = "/usr/ccs/bin/make" # Comment this out to make the script work sys.exit("Edit configuration before running this script") # # End of configuration # #Do not edit below! os.system("clear") print "* * * * A D D I N G U S E R T O N I S * * * *\n\ ---------------------------------------------------\n\ * *\n\ * Copyright (c) 2002 Zoran Pucar *\n\ * zoran@lysator.liu.se *\n\ * *\n\ ___________________________________________________\n\ ---------------------------------------------------\n\n\n\ Default values, if any available, will be inside brackets []\n\n" #Look if the group is in the group file, if it is return GID or else -1 def chk_grp(gruppen): grpfile = open(groupfile,"r") notfound = 1 while notfound: grupp = string.split(grpfile.readline(),":") if grupp[0] == gruppen: grpfile.close() return grupp[2] elif grupp[0] == "": grpfile.close() notfound = 0 return "-1" #Actual function that creates group in group file def create_gr(grname): gid = raw_input("What gid do you want this group to have? ") grpfile = open(groupfile,"a") grpfile.write(grname + "::" + gid + ":\n") grpfile.flush() grpfile.close() return gid #Get groupname and check for existence in group file, create if missing def ask_gr(): groupn = raw_input("Enter group name [other]: ") if groupn == "": groupn = "other" grnr = chk_grp(groupn) if grnr == "-1": print "Group " + groupn + " not found in " + groupfile + "!\n" create = raw_input("Do you want to create group " + groupn + " (y/n) [y]? ") if create == "y" or create == "": grnr = create_gr(groupn) else: print "That doesn't make sense, exiting!\n" sys.exit() else: print "Group \"" + groupn + "\" found in " + groupfile + " as GID " + grnr + "!\n" return [groupn,grnr] #This checks if uid already exists in passwd and if it does it returns 1. This is used to generate warning #if you attempt to create duplicate uid-s def check_uid(uid_to_check): pass_f = open(passwdfile,"r") for line in pass_f.xreadlines(): rad = line.split(":") if int(uid_to_check) == int(rad[2]): return 1 return 0 #What is the biggest uid in passwd file under 60000 #The reason why i don't "find" an available uid is that I #whould have to count in sequence up to 60000 and check every #time in passwd file. That would be extremely slow. def get_biggest_uid(startuid): pass_f = open(passwdfile,"r") uid = int(startuid) for line in pass_f.xreadlines(): rad = line.split(":") prevuid = uid uid = int(rad[2]) if uid >= highest_uid: uid = prevuid if check_uid(uid): print "Warning, the script tried to find highest\n\ available uid. However the highest possible uid\n\ (configured by highest_uid = " + str(highest_uid) + ") already\n\ exists in passwd file. You should check your uid manually." if prevuid >= uid: uid = prevuid pass_f.close() return uid #Get input from user about password and create one if desired def pass_supply(): import crypt, getpass, pwd, random salt = random.choice("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")+random.choice("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ") while 1: answ = raw_input("Do you want to lock account \"l\",\nsupply encrypted password \"e\",\nsupply cleartext password \"c\"\nor create it with blank password \"b\"? [l]: ") if answ == "e" or answ == "E": password = raw_input("Enter encrypted password: ") return password elif answ == "l" or answ == "L" or answ == "": print "Not supplying password, account will be locked.\n\ Unlock the account by running \"passwd\" command for that user\n" password = "*LK*" return password elif answ == "b" or answ == "B": print "Warning! You have chosen not to use password for this user, this is a bad idea" password = "" return password elif answ == "c" or answ == "C": while 1: cleartext = getpass.getpass() cleartext2 = getpass.getpass("Password again: ") if cleartext == cleartext2: break else: print "Passwords don't match, try again\n" password = crypt.crypt(cleartext,salt) return password else: print "Invalid input, please answer with \"l\",\"e\",\"c\" or \"b\"\n" #Create row to put in shadow file def shadow_row(username,password): date = str(int(time.time())/86400) row_s = username + ":" + password + ":" + date + "::::::" return row_s #Check if user is already in passwd file def check_user(username): file = open(passwdfile,"r") for lines in file.xreadlines(): if lines.split(":")[0] == username: return 1 return 0 #This function checks if server variable points to localhost def this_server(): import socket if socket.gethostbyname(os.uname()[1].split(".")[0]) == socket.gethostbyname(server): return 1 else: return 0 def ask_shad(way): global row_s global row_p global password if use_shadow == 1 and way == "manual": shadow = password password = "x" row_s = shadow_row(username,shadow) elif use_shadow == 1 and way == "automatic": shadow = row_p[1] row_p[1] = "x" row_s = shadow_row(username,shadow) elif use_shadow == 2: row_s = "" elif use_shadow == 0: row_s = "" while 1: shadow_answ = raw_input("Are you using shadow for creating databases? (y/n) [n]: ") if shadow_answ == "n" or shadow_answ == "N" or shadow_answ == "": break elif (shadow_answ == "y" or shadow_answ == "Y") and way == "manual": shadow = password password = "x" row_s = shadow_row(username,shadow) break elif (shadow_answ == "y" or shadow_answ == "Y") and way == "automatic": shadow = row_p[1] row_p[1] = "x" row_s = shadow_row(username,shadow) break else: print "Invalid input, please answer \"y\" or \"n\"" else: print "Error in configuration! Invalid setting in use_shadow" sys.exit(1) def get_fyshome(): global fyshome global createhome while 1: fyshome = raw_input("Enter physical home [" + fys_dir + username + "]: ") if fyshome == "": fyshome = fys_dir + username if not this_server() and createhome: print "Home dir is not on this server, attempting to create through /net" fyshome_net = "/net/" + server + fyshome print fyshome_net fysdir_net = fyshome_net.split("/") fysdir_net = fysdir_net[1:len(fysdir_net)-1] path = "" index = 0 cont = 1 length = len(fysdir_net)-1 while cont: if index == length: cont = 0 path = path + "/" + fysdir_net[index] index = index + 1 fysdir_net = path print "Fysdir_net is " + fysdir_net if os.access(fysdir_net,2): print "Writing ok" else: while 1: abort = raw_input("Warning! Cannot create directory!\n Do you want to abort? If you continue you have to create home directory " + fyshome + " manually.\nAbort (y/n) [y]?: ") if abort == "" or abort == "y" or abort == "Y": sys.exit() elif abort == "n" or abort == "N": createhome = 0 break else: print "Invalid input, please answer \"y\" or \"n\"" if os.path.exists(fyshome) and createhome: print "Path you specified exists! Enter new one!" elif fyshome[:1] != "/": print "Beginning slash missing on the path. This will be wrong! Try again!" else: break #This is the main function for manual creation of users def manual(): global username notready = 1 while notready: while 1: username = raw_input("Enter username: ") if username == "": print "You have to supply username!\n" elif check_user(username): print "This username is already in passwd file, please choose another!\n" else: break global password password = pass_supply() ask_shad("manual") anotheruid = 1 while anotheruid: if recom_uid: maxuid = str(get_biggest_uid(lowest_uid) + 1) else: maxuid = "" not_int = 1 while not_int: uid = raw_input("Enter uid for the user [" + maxuid + "]: ") if not uid == "": try: int(uid) not_int = 0 break except ValueError: print "You have to enter a numerical value" else: not_int = 0 if uid == "" and maxuid != "": uid = maxuid break elif uid == "" and maxuid == "": print "You need to enter valid uid!" elif int(uid) < 0 or int(uid) > 65536: print "You need uid between 0 and 65536!" elif not check_uid(uid): break else: while 1: cont = raw_input("You have chosen an uid that already exits in the passwd file, do you want to continue anyway? (y/n) [n]?: ") if cont == "" or cont == "n" or cont == "N": print "Choose another uid" break elif cont == "y" or cont == "Y": break else: print "Invalid input, please answer \"y\" or \"n\"" if cont == "y" or cont == "Y": anotheruid = 0 else: anotheruid = 1 realname = raw_input("Enter real name: ") global groupname groupname = ask_gr() global fyshome get_fyshome() home = raw_input("Enter home directory [" + home_dir + username + "]: ") if home == "": home = home_dir + username shell = raw_input("Enter users shell [/bin/tcsh]: ") if shell == "": shell = "/bin/tcsh" if row_s: shadprint = "using shadow: yes\n" else: shadprint = "using shadow: no\n" os.system("clear") home_fysical = fyshome if not this_server(): home_fysical = server + ":" + fyshome print "You entered following data: \n\n\ username: " + username + "\n\ uid: " + uid + "\n\ realname: " + realname + "\n\ group: " + groupname[0] + "\n\ gid: " + groupname[1] + "\n\ phisycal home directory: " + home_fysical + "\n\ home directory: " + home + "\n\ shell:" + shell + "\n\ "+shadprint while 1: correct = raw_input("Is this correct? (y/n) [y]?: ") if correct == "" or correct == "y" or correct == "Y": notready = 0 break elif correct == "n" or correct == "N": notready = 1 os.system("clear") break else: print "Invalid input, please answer \"y\" or \"n\"" row_p = username + ":" + password + ":" + uid + ":" + groupname[1] + ":" + realname + ":" + home + ":" + shell return row_p #Here we paste in line from another passwd file and modify it and output new row def row(): global password global username global fyshome global groupname global row_p row_p = string.split(raw_input("Paste in the line from ypcat passwd: "),":") password = row_p[1] username = row_p[0] ask_shad("automatic") groupname = ask_gr() row_p[3] = groupname[1] get_fyshome() row_p = row_p[0] + ":" + row_p[1] + ":" + row_p[2] + ":" + row_p[3] + ":" + row_p[4] + ":" + row_p[5] + ":" + row_p[6] return row_p #Function for saving rows into files def save(row_var,file): if backup_files == 1: date = time.localtime(time.time()) date = str(date[0]) + str(date[1]) + str(date[2]) + "_" + str(date[3]) + str(date[4]) if os.path.isfile(backup_dir): print "Error in configuration! Backup path is file\nRemove file or change backup_dir in configuration" sys.exit(1) if not os.path.isdir(backup_dir): os.system("mkdir -p " + backup_dir) os.system("chmod 700 " + backup_dir) backup_file = backup_dir + file.split("/")[-1] + "." + date os.system("cp " + file + " " + backup_file) os.system("chmod 600 " + backup_file) print "Old " + file + " saved as " + backup_file elif not backup_files == 0: print "Error in configuration! Invalid setting in backup_files" sys.exit(1) pass_f = open(file,"a") pass_f.write(row_var+"\n") pass_f.flush() pass_f.close() #Create row that will be inserted into auto_home map def auto_home(username): row_a = username + " " + server + ":" + fyshome return row_a #Check if skel directory exists and if not create one def check_skel(skel): if not os.path.exists(skel): print "Skel directory does not exist" createit = raw_input("Do you want to create it? (y/n) [y]: ") if createit == "" or createit == "y" or createit == "Y": while 1: whatgr = raw_input("Which group's skel directory do you want to copy? None for empty skel [None]: ") if whatgr == "None" or whatgr == "none" or whatgr == "": print "Creating empty skel directory, make sure to create login files in it" os.system("mkdir -p " + skel) break elif os.path.exists(skeldir + whatgr): print "Copying " + skeldir + whatgr + " to " + skel os.system("cp -r " + skeldir + whatgr + " " + skel) print "Done creating skel directory!" break else: print "This group does not have skel dir. Choose another!" #Create home directory by copyng skel directory and setting correct owner def make_homedir(userid,groupid,skel): global fyshome if not this_server(): fyshome = "/net/" + server + fyshome check_skel(skel) directory = os.path.dirname(fyshome) if not os.path.isdir(directory) and not os.path.isfile(directory): print "Creating root home drectory " + directory os.system("mkdir -p " + directory) elif os.path.isfile(directory): print "File " + directory + " exists but it is a file\nAborting..." sys.exit() os.system("cp -r " + skel + " " + fyshome) os.system("chown -R " + userid + ":" + groupid + " " + fyshome) os.system("chmod " + str(homedir_perms) + " " + fyshome) #Main part of the program # There are two methods of adding the user to the system. One is manually # by supplying username, groupname, realname etc. and the other is by # pasting in output from ypcat passwd | grep username for that user # from another system. This is good since it keeps passwords def start_manual(): global createhome result = manual() username = result.split(":")[0] userid = result.split(":")[2] groupn = result.split(":")[3] if row_s: save(row_s,shadowfile) save(result,passwdfile) save(auto_home(username),autohomefile) if createhome == 1: print "Wait... attempting to create home directory\n" make_homedir(userid,groupn,skeldir + groupname[0]) print "Home directory created!\n" def start_automatic(): global createhome result = row() userid = result.split(":")[2] groupn = result.split(":")[3] if row_s: save(row_s,shadowfile) save(result,passwdfile) save(auto_home(result.split(":")[0]),autohomefile) if createhome == 1: print "Wait... attempting to create home directory\n" make_homedir(userid,groupn,skeldir + groupname[0]) print "Home directory created!\n" if create == 0: while 1: answer = raw_input("Do you want to create user manually (y/n) [y]?: ") if answer == "y" or answer == "" or answer == "Y": start_manual() break elif answer == "n" or answer == "N": start_automatic() break else: print "Invalid input, please answer \"y\" or \"n\"" elif create == 1: start_manual() elif create == 2: start_automatic() else: sys.exit("Error in configuration. Invalid value for \"create\"...") if runmake: print "Wait while rebuilding NIS maps..." os.system("cd /var/yp;" + make_bin) print "Rebuilding done!" ############################################################################## ### This script is submitted to BigAdmin by a user of the BigAdmin community. ### Sun Microsystems, Inc. is not responsible for the ### contents or the code enclosed. ### ### ### Copyright 2006 Sun Microsystems, Inc. ALL RIGHTS RESERVED ### Use of this software is authorized pursuant to the ### terms of the license found at ### http://www.sun.com/bigadmin/common/berkeley_license.html ##############################################################################