Login   Register  
PHP Classes
elePHPant
Icontem

File: shadow.class.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  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: 12 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
}
?>