PHP Classes

File: shadow.class.php

Recommend this page to a friend!
  Classes of Oliver Schlag   shadow.class   shadow.class.php   Download  
File: shadow.class.php
Role: ???
Content type: text/plain
Description: The main library
Class: shadow.class
Manage user accounts on shadow based Unix systems
Author: By
Last change:
Date: 22 years ago
Size: 21,569 bytes
 

Contents

Class file image Download
<?php class shadow { // Class to manage User and Group Accounts on Shadow based Linux/Unix Systems // Date : 01/23/2002 // Author : Oliver Schlag <oliver.schlag@blue-online.de> // You can use this class without any warranty. Please report every // bug to the Author. If you make changes to this class please report // them to the Author, too. // To easily manage all accounts we first read them into some arrays. // And after making all changes, we write them back to the file. I // think thats the fastest way to do the job. Yes it consumes much // memory but I think thats not so much important. // This is the structure of the files, which we use : // /etc/passwd -> Username:x:UID:GID:GCOS:Home:Shell // /etc/shadow -> Username:Password:DOC:MindD:MaxD:Warn:Exp:Dis:Res // /etc/group -> Groupname:Password:GID:Member // /etc/gshadow-> Groupname:Password:Groupmanager:Member // To prevent, that two jobs are using the user and Group Files we // create a simple lock file, and if it the file exists at startup // we do nothing. // All functions in this class return TRUE on success and FALSE on error, // so you can easily catch all errors. All errors of this function are // stored in the variable $ERROR_MSG. You can then read it and provide // a custom error message. // You can use the following functions in your applications : // int user_add (username,userid,primary_group,name,shell,homedir,password); // int user_del (username); // int user_mod (username,new_name,new_shell,new_password); // int group_add (groupname,member,password,manager); // int group_del (groupname); // int group_mod(groupname,new_name); // int add_to_group(groupname,username); // int del_from_group(groupname,username); // int del_from_all_groups(username); // There are 2 more functions, which provide some simple constructor and // destructor functions for the class. So you had to call the constructor // first, then use the functions and then call the destructor to write all // data back into the files and remove the lock file. // int shadow(passwd_path,shadow_path,group_path,gshadow_path,enable_logging); -> The pseudo constructor // int stop_shadow(); -> The pseudo destructor // If you like, you can activate the logging into your syslog, so all actions // somebody makes, will be reported to it. To do this call the pseudo constructor // with a 1 as first parameter. // We use the following arrays to manage the user and group Accounts in memory // $user["username"] = Username; // $user["password"] = Password; // $user["uid"] = UserID; // $user["gid"] = GroupID; // $user["gcos"] = Real Name; // $user["home"] = Homedir; // $user["shell"] = Shell; // $user["doc"] = Date of last password change in days from the 1.1.1970 // $user["mind"] = Minimal days the password is valid // $user["maxd"] = Maximum days the password is valid // $user["warn"] = Number of days before the user recives a message that he should change his password // $user["exp"] = After maxd, how many days is the password still valid // $user["dis"] = Up to this day (counted from 1.1.1970) the account is locked // $group["groupname"] = Groupname; // $group["password"] = Password; // $group["gid"] = GroupID; // $group["member"] = Comma seperated list of members; // $group["manager"] = Comma seperated list of group managers; // $homed["dir"] = Homedirectory; // $homed["user"] = User which this directory belongs to; // $homed["group"] = The group which this directory belongs to; // All homedirectorys are chmoded 755; VAR $ERROR_MSG; VAR $LOGGING; // Tells us if syslog logging is enabled or not VAR $STARTED; // Keeps track if the constructor was called VAR $USERDATA; // Here are all arrays of the type $user are stored in VAR $GROUPDATA; // Here are all arrays of the type $group are stored in VAR $FASTSEEK; // Little Array which contains number to name assignments for usernames VAR $GFASTSEEK; // Little Array which contains number to name assignments for groupnames VAR $HOMEDIRS; // The homedirectorys which have to be created; VAR $STARTUID; // The first UserID a user can have VAR $STARTGID; // The first GroupID a group can have VAR $SHADOWFILE; // The location of the shadow file VAR $PASSWDFILE; // The location of the passwd file VAR $GROUPFILE; // The location of the group file VAR $GSHADOWFILE; // The location of the gshadow file VAR $LOCKFILE; // The name of the lock file function shadow($passwd = "/etc/passwd", $shadow = "/etc/shadow", $groupf = "/etc/group", $gshadow = "/etc/gshadow", $enable_logging = 0) { // Set logging state $this->LOGGING = $enable_logging; // Set the minimum UserID $this->STARTUID = 100; // Set the minimum GroupID $this->STARTGID = 100; // Set the passwd file $this->PASSWDFILE = $passwd; // Set the shadow file $this->SHADOWFILE = $shadow; // Set the group file $this->GROUPFILE = $groupf; // Set the gshadow file $this->GSHADOWFILE = $gshadow; // Set the lockfile name $this->LOCKFILE = "C:\\temp\\shadow.lock"; // Initalize an array $this->HOMEDIRS = array(); // Check if a log file exists, if not create one if (file_exists($this->LOCKFILE)) { $this->ERROR_MSG = "Lockfile exists"; $this->STARTED = 0; if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"Could not start shadow class. Lockfile exists."); } return FALSE; } else { $fp = fopen($this->LOCKFILE,"w"); fputs($fp," "); fclose($fp); } // Read the shadow user file into the array $sp = fopen($this->SHADOWFILE,"r"); $i = 0; while(!feof($sp)) { $temp = fgets($sp,8069); $temp = rtrim(ereg_replace("\n"," ",$temp)); $temp = explode(":",$temp); $user["username"] = $temp[0]; $user["password"] = $temp[1]; $user["doc"] = $temp[2]; $user["mind"] = $temp[3]; $user["maxd"] = $temp[4]; $user["warn"] = $temp[5]; $user["exp"] = $temp[6]; $user["dis"] = $temp[7]; $temp = $user["username"]; $this->USERDATA[$i] = $user; $this->FASTSEEK[$temp] = $i; $i++; } fclose($sp); $pp = fopen($this->PASSWDFILE,"r"); while(!feof($pp)) { $temp = fgets($pp,8096); $temp = rtrim(ereg_replace("\n"," ",$temp)); $temp = explode(":",$temp); $username = $temp[0]; $i = -1; $i = $this->FASTSEEK[$username]; if ( $i != -1 ) { $this->USERDATA[$i]["uid"] = $temp[2]; $this->USERDATA[$i]["gid"] = $temp[3]; $this->USERDATA[$i]["gcos"] = $temp[4]; $this->USERDATA[$i]["home"] = $temp[5]; $this->USERDATA[$i]["shell"] = $temp[6]; } } fclose($pp); // Now we read all groups into another array $gp = fopen($this->GROUPFILE,"r"); $i = 0; while(!feof($gp)) { $temp = fgets($gp,8096); $temp = rtrim(ereg_replace("\n"," ",$temp)); $temp = explode(":",$temp); $group["groupname"] = $temp[0]; $group["gid"] = $temp[2]; $group["member"] = $temp[3]; $temp = $temp[0]; $this->GROUPDATA[$i] = $group; $this->GFASTSEEK[$temp] = $i; $i++; } fclose($gp); $gs = fopen($this->GSHADOWFILE,"r"); $i = -1; while(!feof($gs)) { $temp = fgets($gs,8096); $temp = rtrim(ereg_replace("\n"," ",$temp)); $temp = explode(":",$temp); $groupname = $temp[0]; $i = $this->GFASTSEEK[$groupname]; if ( $i != -1 ) { $this->GROUPDATA[$i]["password"] = $temp[1]; $this->GROUPDATA[$i]["manager"] = $temp[2]; } } fclose($gs); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"Shadow Class initalized."); } return TRUE; // End of pseudo constructor } function stop_shadow() { // To avoide damages to production files, we make backup copies // of the original files. We delete them at the next run. if(file_exists($this->PASSWDFILE."-backup")) { unlink($this->PASSWDFILE."-backup"); } copy($this->PASSWDFILE,$this->PASSWDFILE."-backup"); if(file_exists($this->SHADOWFILE."-backup")) { unlink($this->SHADOWFILE."-backup"); } copy($this->SHADOWFILE,$this->SHADOWFILE."-backup"); if(file_exists($this->GROUPFILE."-backup")) { unlink($this->GROUPFILE."-backup"); } copy($this->GROUPFILE,$this->GROUPFILE."-backup"); if(file_exists($this->GSHADOWFILE."-backup")) { unlink($this->GSHADOWFILE."-backup"); } copy($this->GSHADOWFILE,$this->GSHADOWFILE."-backup"); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"Backup files created"); } // Write back all user informations into the correct files; $pf = fopen($this->PASSWDFILE,"w"); $sf = fopen($this->SHADOWFILE,"w"); for ( $i = 0 ; $i < count($this->USERDATA) ; $i++ ) { if ($this->USERDATA[$i]["username"] != "") { if ($i == count($this->USERDATA)-1 ) { $passwd = $this->USERDATA[$i]["username"].":x:".$this->USERDATA[$i]["uid"].":".$this->USERDATA[$i]["gid"].":".$this->USERDATA[$i]["gcos"].":".$this->USERDATA[$i]["home"].":".$this->USERDATA[$i]["shell"]; $shadow = $this->USERDATA[$i]["username"].":".$this->USERDATA[$i]["password"].":".$this->USERDATA[$i]["doc"].":".$this->USERDATA[$i]["mind"].":".$this->USERDATA[$i]["maxd"].":".$this->USERDATA[$i]["warn"].":".$this->USERDATA[$i]["exp"].":".$this->USERDATA[$i]["dis"].":"; } else { $passwd = $this->USERDATA[$i]["username"].":x:".$this->USERDATA[$i]["uid"].":".$this->USERDATA[$i]["gid"].":".$this->USERDATA[$i]["gcos"].":".$this->USERDATA[$i]["home"].":".$this->USERDATA[$i]["shell"]."\n"; $shadow = $this->USERDATA[$i]["username"].":".$this->USERDATA[$i]["password"].":".$this->USERDATA[$i]["doc"].":".$this->USERDATA[$i]["mind"].":".$this->USERDATA[$i]["maxd"].":".$this->USERDATA[$i]["warn"].":".$this->USERDATA[$i]["exp"].":".$this->USERDATA[$i]["dis"].":\n"; } fputs($pf,$passwd); fputs($sf,$shadow); } } fclose($pf); fclose($sf); // Write all group informations into the correct files; $gf = fopen($this->GROUPFILE,"w"); $sg = fopen($this->GSHADOWFILE,"w"); for ( $i = 0 ; $i < count ($this->GROUPDATA) ; $i++ ) { if ($this->GROUPDATA[$i]["groupname"] != "") { if ($i == count($this->GROUPDATA)-1 ) { $group = $this->GROUPDATA[$i]["groupname"].":x:".$this->GROUPDATA[$i]["gid"].":".$this->GROUPDATA[$i]["member"]; $gshadow = $this->GROUPDATA[$i]["groupname"].":".$this->GROUPDATA[$i]["password"].":".$this->GROUPDATA[$i]["manager"].":".$this->GROUPDATA[$i]["member"]; } else { $group = $this->GROUPDATA[$i]["groupname"].":x:".$this->GROUPDATA[$i]["gid"].":".$this->GROUPDATA[$i]["member"]."\n"; $gshadow = $this->GROUPDATA[$i]["groupname"].":".$this->GROUPDATA[$i]["password"].":".$this->GROUPDATA[$i]["manager"].":".$this->GROUPDATA[$i]["member"]."\n"; } fputs($gf,$group); fputs($sg,$gshadow); } } fclose($gf); fclose($sg); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"User and Group Database generated"); } // Create or delete homedirectorys and set permissions; for ( $i = 0 ; $i < count($this->HOMEDIRS) ; $i++ ) { if ($this->HOMEDIRS[$i]["action"] == "create") { mkdir($this->HOMEDIRS[$i]["dir"],0755); chown($this->HOMEDIRS[$i]["dir"],$this->HOMEDIRS[$i]["user"]); chgrp($this->HOMEDIRS[$i]["dir"],$this->HOMEDIRS[$i]["group"]); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"User : ".$this->HOMEDIRS[$i]["user"]." created"); } } else { $cmd = "/bin/rm -R ".$this->HOMEDIRS[$i]["dir"]; $res = exec($cmd); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"User : ".$this->HOMEDIRS[$i]["user"]." deleted"); } } } if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"Homedirectorys created and deleted"); } unlink($this->LOCKFILE); if ($this->LOGGING == 1) { syslog(LOG_NOTICE,"Shadow class ended"); } RETURN TRUE; // End of pseudo destructor } function user_add($username,$uid,$group,$gcos,$shell,$home,$password) { if ($username == "") { $this->ERROR_MSG = "NO Username specified"; RETURN FALSE; } if ($uid < 0 || $uid > 64999) { $this->ERROR_MSG = "Incorrect UserID"; RETURN FALSE; } if ($home == "") { $this->ERROR_MSG = "Please provide a home directory !"; RETURN FALSE; } for ( $i = 0 ; $i < count($this->USERDATA) ; $i++ ) { if ( $this->USERDATA[$i]["uid"] == $uid ) { $this->ERROR_MSG = "Userid already exists"; RETURN FALSE; } } for ( $i = 0 ; $i < count($this->USERDATA) ; $i++ ) { if ( $this->USERDATA[$i]["username"] == $username ) { $this->ERROR_MSG = "Username already exists"; RETURN FALSE; } } $i = count($this->USERDATA); $this->USERDATA[$i]["username"] = $username; $this->USERDATA[$i]["password"] = crypt($password); $this->USERDATA[$i]["uid"] = $uid; $this->USERDATA[$i]["gid"] = $this->group_to_gid($group); $this->USERDATA[$i]["gcos"] = $gcos; $this->USERDATA[$i]["home"] = $home; $this->USERDATA[$i]["shell"] = $shell; $doc = time() / 86400; $doc = explode(".",$doc); $this->USERDATA[$i]["doc"] = $doc[0]; $this->USERDATA[$i]["mind"] = ""; $this->USERDATA[$i]["maxd"] = ""; $this->USERDATA[$i]["warn"] = ""; $this->USERDATA[$i]["exp"] = ""; $this->USERDATA[$i]["dis"] = ""; $i = count($this->HOMEDIRS); $this->HOMEDIRS[$i]["action"] = "create"; $this->HOMEDIRS[$i]["dir"] = $home; $this->HOMEDIRS[$i]["user"] = $username; $this->HOMEDIRS[$i]["group"] = $group; $this->FASTSEEK[$username] = $i; if (!$this->add_to_group($group,$username)) { $this->ERROR_MSG = "Could not add user ".$username." to group ".$group; unset($this->USERDATA[count($this->USERDATA)]); RETURN FALSE; } RETURN TRUE; // End of user_add } function user_del($username) { if ( $username == "" ) { $this->ERROR_MSG = "No Username specified !"; RETURN FALSE; } for ( $i = 0 ; $i < count($this->USERDATA) ; $i++ ) { if ( $this->USERDATA[$i]["username"] == $username ) break; } $this->del_from_all_groups($username); $j = count($this->HOMEDIRS); $this->HOMEDIRS[$j]["action"] = "delete"; $this->HOMEDIRS[$j]["dir"] = $this->USERDATA[$i]["home"]; $this->HOMEDIRS[$j]["user"] = $username; unset($this->USERDATA[$i]); RETURN TRUE; // End of user_del unset($this->FASTSEEK[$username]); } function user_mod($username,$new_gcos,$new_shell,$new_password) { if ( $username == "" ) { $this->ERROR_MSG = "No Username specified !"; RETURN FALSE; } else { for ( $i = 0 ; $i < count($this->USERDATA) ; $i++ ) { if ( $this->USERDATA[$i]["username"] == $username ) break; } if ( $new_gcos != "" ) { $this->USERDATA[$i]["gcos"] = $new_gcos; } if ( $new_shell != "" ) { $this->USERDATA[$i]["shell"] = $new_shell; } if ( $new_password != "" ) { $this->USERDATA[$i]["password"] = crypt($new_password); } } RETURN TRUE; // End of user_mod } function group_add($groupname,$member = "",$password = "",$manager = "") { if ($groupname == "") { $this->ERROR_MSG = "No groupname specified"; RETURN FALSE; } $i = count($this->GROUPDATA); $this->GROUPDATA[$i]["groupname"] = $groupname; if ($password != "") { $this->GROUPDATA[$i]["password"] = crypt($password); } else { $this->GROUPDATA[$i]["password"] = ""; } $this->GROUPDATA[$i]["gid"] = $this->get_next_gid(); $this->GROUPDATA[$i]["member"] = $member; $this->GROUPDATA[$i]["manager"] = $manager; $this->GFASTSEEK[$groupname] = $i; RETURN TRUE; } function group_del($groupname) { $i = $this->GFASTSEEK[$groupname]; unset($this->GROUPDATA[$i]); unset($this->GFASTSEEK[$groupname]); RETURN TRUE; } function group_mod($groupname,$new_name) { if ($groupname == "") { $this->ERROR_MSG = "No Groupname specified"; RETURN FALSE; } if ($new_name == "") { $this->ERROR_MSG = "No new Groupname specified"; RETURN FALSE; } $i = $this->GFASTSEEK[$groupname]; if (!isset($i)) { $this->ERROR_MSG = "Group does not exist"; return FALSE; } $this->GROUPDATA[$i]["groupname"] = $new_name; RETURN TRUE; } function add_to_group($groupname,$user) { $new_member = ""; $i = $this->GFASTSEEK[$groupname]; if (!isset($i)) { $this->ERROR_MSG = "Group does not exist"; return FALSE; } $member = $this->GROUPDATA[$i]["member"]; $member = explode(",",$member); $memcount = count($member); $member[$memcount] = $user; for ( $j = 0; $j <= $memcount; $j++ ) { if ( $j == 0 || $new_member == "") { $new_member = $member[$j]; } else { $new_member = $new_member.",".$member[$j]; } echo $j."=>".$new_member."<br>\n"; } $this->GROUPDATA[$i]["member"] = $new_member; RETURN TRUE; } function del_from_group($groupname,$user) { $i = $this->GFASTSEEK[$groupname]; if (!isset($i)) { $this->ERROR_MSG = "Group does not exist"; return FALSE; } $member = $this->GROUPDATA[$i]["member"]; $member = explode(",",$member); $memcount = count($member); for ( $j = 0; $j < $memcount; $j++) { if ($member[$j] != $user) { if ( $j == 0 ) { $new_member = $member[$j]; } else { $new_member = $new_member.",".$member[$j]; } } } $this->GROUPDATA[$i]["member"] = $new_member; RETURN TRUE; } function del_from_all_groups($user) { for ($i = 0; $i < count($this->GROUPDATA); $i++) { $this->del_from_group($this->GROUPDATA[$i]["groupname"],$user); } RETURN TRUE; } function get_next_uid() { $uid = $this->STARTUID; do { $used = 0; for ( $i = 0; $i < count($this->USERDATA); $i++ ) { if ( $uid == $this->USERDATA[$i]["uid"] ) { $used = 1; $uid++; break; } } } while($used == 1 && $uid <= 64999); if ( $uid <= 64999 ) { return $uid; } else { $this->ERROR_MSG = "UserID greater than 65000"; return FALSE; } } function get_next_gid() { $gid = $this->STARTGID; do { $used = 0; for ( $i = 0; $i < count($this->GROUPDATA); $i++ ) { if ( $gid == $this->GROUPDATA[$i]["gid"] && $gid <= 64999) { $used = 1; $gid++; break; } } } while($used == 1 && $gid <= 64999); if ( $gid <= 64999 ) { return $gid; } else { $this->ERROR_MSG = "GroupID greater than 65000"; return FALSE; } } function uid_to_user($uid) { for ( $i = 0; $i < count($this->USERDATA); $i++ ) { if ( $uid == $this->USERDATA[$i]["uid"] ) { return $this->USERDATA[$i]["username"]; } } } function gid_to_group($gid) { for ( $i = 0; $i < count($this->GROUPDATA); $i++ ) { if ( $gid == $this->GROUPDATA[$i]["gid"] ) { return $this->GROUPDATA[$i]["groupname"]; } } } function group_to_gid($group) { for ( $i = 0; $i < count($this->GROUPDATA); $i++ ) { if ( $group == $this->GROUPDATA[$i]["groupname"] ) { return $this->GROUPDATA[$i]["gid"]; } } } function user_to_uid($user) { for ( $i = 0; $i < count($this->USERDATA); $i++ ) { if ( $user == $this->USERDATA[$i]["username"] ) { return $this->USERDATA[$i]["uid"]; } } } function show_all() { for ( $i = 0; $i < count($this->USERDATA); $i++) { while (list($key, $val) = each($this->USERDATA[$i])) { echo "$key => $val\n"; } } for ( $i = 0; $i < count($this->GROUPDATA); $i++) { while (list($key, $val) = each($this->GROUPDATA[$i])) { echo "$key => $val\n"; } } } // End of class } ?>