<?php
global $ldapconn,$ldapdn;

//pull in required settings, connect to the ldap server, and then bind to it, leaving $ldapconn ready for use
function ldap_mcms_init() {
    file_exists("/etc/mcms/settings") or die('Missing /etc/mcms/settings file');
    global $ldapconn,$ldapdn;
    $nullreturn=array(NULL,NULL);
    list($rcode,$result) = microwayPerformCommand("grep LDAPHOST= /etc/mcms/settings");
    if($rcode!=0 || $result=="") return $nullreturn;
    $ldaphost=trim(str_replace("LDAPHOST=","",$result));

    list($rcode,$result) = microwayPerformCommand("grep LDAPPORT= /etc/mcms/settings");
    if($rcode!=0 || $result=="") return $nullreturn;
    $ldapport=(int)str_replace("LDAPPORT=","",$result);

    list($rcode,$result) = microwayPerformCommand("grep LDAPCN= /etc/mcms/settings");
    if($rcode!=0 || $result=="") return $nullreturn;
    $ldapcn=trim(str_replace("LDAPCN=","",$result));

    list($rcode,$result) = microwayPerformCommand("grep LDAPDN= /etc/mcms/settings");
    if($rcode!=0 || $result=="") return $nullreturn;
    $ldapdn=trim(str_replace("LDAPDN=","",$result));

    list($rcode,$result) = microwayPerformCommand("grep LDAPPASS= /etc/mcms/settings");
    if($rcode!=0 || $result=="") return $nullreturn;
    $ldappass=trim(str_replace("LDAPPASS=","",$result));

    $ldapconn = ldap_connect($ldaphost, $ldapport)
          or die("Could not connect to LDAP server $ldaphost");
    ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
 
    $ldapbind = ldap_bind($ldapconn, $ldapcn.",".$ldapdn, $ldappass)
          or die("Could not bind to LDAP server");
    return array($ldapconn,$ldapdn);
}

function ldap_change_password($username,$password) {
  global $ldapconn,$ldapdn;
  $userpassword = "{SHA}" . base64_encode( pack( "H*", sha1( $password ) ) );
  $ldapmod["userpassword"]=$userpassword;
  $result=ldap_mod_replace($ldapconn,"cn=" . $username . ",ou=users,".$ldapdn,$ldapmod);
  return $result;
}

function ldap_change_fullname($username,$fullname) {
  global $ldapconn,$ldapdn;
  $ldapmod["gecos"]=$fullname;
  $result=ldap_mod_replace($ldapconn,"cn=" . $username . ",ou=users,".$ldapdn,$ldapmod);
  return $result;
}

function ldap_change_shell($username,$shell) {
  global $ldapconn,$ldapdn;
  $ldapmod["loginshell"]=$shell;
  $result=ldap_mod_replace($ldapconn,"cn=" . $username . ",ou=users,".$ldapdn,$ldapmod);
  return $result;
}

function ldap_add_user($username,$password,$uid,$gid,$fullname="settousername",$shell="/bin/bash",$forcepwchange="off") {
  global $ldapconn,$ldapdn;

  if ($uid != "auto") {
      if(uid_in_use($uid)) {
          global $returntoadduid;
          echo $returntoadduid;
          exit ();
      }
  } else {
      $uid=next_free_uid(); 
      if($uid==0) {
          global $returntoaddnouids;
          echo $returntoaddnouids;
          exit ();
      }
  }
  if ($gid=="auto") $gid=microwayGetDefaultGroup();

  //$userpassword = "{SHA}" . base64_encode( pack( "H*", sha1( $password ) ) );
  $salt = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',4)),0,4);
  $userpassword = "{SSHA}" . base64_encode(sha1( $password.$salt,TRUE).$salt);
  if($fullname=="settousername") $fullname=$username;
  $add["uid"]=$username;
  $add["gecos"]=$fullname;
  $add["objectClass"][0]="top";
  $add["objectClass"][1]="account";
  $add["objectClass"][2]="posixAccount";
  $add["objectClass"][3]="shadowAccount";
  $add["userPassword"]=$userpassword;
  if($forcepwchange=="on") {
      $add["shadowLastChange"]=0;
  } else {
      $add["shadowLastChange"]=(int)(time()/86400);
  }
  $add["shadowMin"]=0;
  $add["shadowMax"]=99999;
  $add["shadowWarning"]=7;
  $add["loginShell"]=$shell;
  $add["uidNumber"]=(int)$uid;
  $add["gidNumber"]=(int)$gid;
  $add["homeDirectory"]="/home/" . $username;
  $result=ldap_add($ldapconn,"cn=" . $username . ",ou=users,".$ldapdn,$add);
  if(!$result) { echo "ldap_add failed<br>"; echo ldap_error($ldapconn); }
  return $result;
}

function ldap_del_user($username) {
  global $ldapconn,$ldapdn;
  $result=ldap_delete($ldapconn,"cn=".$username.",ou=users,".$ldapdn);
  return $result;
}

function ldap_get_groups($mingid=1001) {
  global $ldapconn,$ldapdn;
  $filter="(objectClass=posixGroup)";

  $sr=ldap_search($ldapconn, $ldapdn, $filter,["cn","gidnumber"]);

  $info = ldap_get_entries($ldapconn, $sr);
  $count=0;
  foreach ($info as $grouparray) {
      if($grouparray['cn'][0]!="" && ((int)$grouparray['gidnumber'][0])>=(int)$mingid) {
        $allgroups[$count]['name']=$grouparray['cn'][0];
        $allgroups[$count]['id']=$grouparray['gidnumber'][0];
        $count++;
      }
  }
  return $allgroups;
}

function ldap_user_set_groups($username,$groups) {
  $allgroups=ldap_get_groups();
  $grouparray=explode(" ", preg_replace("/ *$/","",str_replace(array(",","\n","\r"),array(" "," ",""),$groups)));
  foreach($allgroups as $group) {
      if(in_array($group['name'],$grouparray)) {
          ldap_group_add_member($group['name'],$username);
      } else {
          ldap_group_del_member($group['name'],$username);
      }
  }
}

function ldap_user_exists($username) {
  global $ldapconn,$ldapdn;

  $filter="(&(objectClass=posixAccount)(cn=".$username."))";
  $sr=ldap_search($ldapconn, $ldapdn, $filter,["cn","uid"]);
  $info = ldap_get_entries($ldapconn, $sr);
  if ($info == FALSE) return FALSE;
  if ($info["count"]!=1) return FALSE;
  return TRUE;
}

function ldap_update_user($username,$password,$fullname,$shell,$forcepwchange) {
  global $ldapconn,$ldapdn;
  
  if($password!="") ldap_change_password($username,$password);
  if($fullname!="") ldap_change_fullname($username,$fullname);
  if($shell!="") ldap_change_shell($username,$shell);
  if($forcepwchange="yes") ldap_change_age($username);
}

function ldap_add_group($group,$gid) {
  global $ldapconn,$ldapdn;
  if ($gid != "auto") {
      if(gid_in_use($gid)) {
          global $returntoaddgid;
          echo $returntoaddgid;
          exit ();
      }
  } else {
      $gid=next_free_gid(); 
      if($gid==0) {
          global $returntoaddnogids;
          echo $returntoaddnogids;
          exit ();
      }
  }
  
  $add["cn"]=$group;
  $add["objectClass"][0]="top";
  $add["objectClass"][1]="posixGroup";
  $add["gidNumber"]=$gid;
  $add["description"]="MCMS generated group";
  $result=ldap_add($ldapconn,"cn=" . $group . ",ou=groups,".$ldapdn,$add);
  if(!$result) echo ldap_error($ldapconn);
  return $result;
}

function ldap_del_group($group) {
  global $ldapconn,$ldapdn;
//FIXME - check for users with this as their primary gid and warn before deleting
  $result=ldap_delete($ldapconn,"cn=".$group.",ou=groups,".$ldapdn);
  if(!$result) echo ldap_error($ldapconn);
  return $result;
}

function ldap_group_add_member($group,$username) {
  global $ldapconn,$ldapdn;
  $filter="(&(objectClass=posixGroup)(cn=".$group."))";

  $sr=ldap_search($ldapconn, $ldapdn, $filter,["memberuid"]);

  $ldapgroup = ldap_get_entries($ldapconn, $sr);
  //if the group doesn't have any members, memberuid doesn't exist so you need an empty array instead
  if(is_array($ldapgroup[0]['memberuid'])) {
      $modify['memberuid']=$ldapgroup[0]['memberuid'];
      //eliminate count entry
      array_splice($modify['memberuid'],0,1);
  } else $modify['memberuid']=[];

  if(!in_array($username,$modify['memberuid'])) {
      array_push($modify['memberuid'],$username);
      $result=ldap_modify($ldapconn,"cn=".$group.",ou=groups,".$ldapdn,$modify);
      if(!$result) echo ldap_error($ldapconn)."<br>\n";
      return $result;
  } else return FALSE;
}

function ldap_group_del_member($group,$username) {
  global $ldapconn,$ldapdn;
  $filter="(&(objectClass=posixGroup)(cn=".$group."))";

  $sr=ldap_search($ldapconn, $ldapdn, $filter,["memberuid"]);

  $ldapgroup = ldap_get_entries($ldapconn, $sr);
  //if the group doesn't have any members, memberuid doesn't exist so you need an empty array instead
  if(is_array($ldapgroup[0]['memberuid'])) {
      $modify['memberuid']=$ldapgroup[0]['memberuid'];
      //eliminate count entry
      array_splice($modify['memberuid'],0,1);
  } else {
      $modify['memberuid']=[];
  }
  
  if(in_array($username,$modify['memberuid'])) {
      $uidkey=array_search($username,$modify['memberuid']);
      array_splice($modify['memberuid'],$uidkey,1);
      $result=ldap_modify($ldapconn,"cn=".$group.",ou=groups,".$ldapdn,$modify);
      if(!$result) echo ldap_error($ldapconn);
      return $result;
  } else return FALSE;
}

//determines if a uid is in use - checks all uids with getent passwd, not just ldap ones
function uid_in_use($uidcheck) {
  static $uidsloaded=FALSE;
  static $uidlist=[];
  if (!$uidsloaded) {
      $uids = popen ("getent passwd | sort -u |awk 'BEGIN{FS=\":\"}{print $3}'", "r")
            or die("Could not read passwd list\n");
      if($uids==FALSE) return -1;

      $count=0;
      while (!feof ($uids)) {
          $uidlist[$count] = (int) fgets ($uids, 4096);
          $count++;
      }
      $uidsloaded=TRUE;
  }
  foreach($uidlist as $uid) {
    if($uid==$uidcheck) return TRUE;
  }
  pclose($uids);
  return FALSE;
} 

//gets next uid for uid=auto
function next_free_uid($start=1001,$maxuid=5000){
  for($uidcheck=(int)$start ; $uidcheck<$maxuid ; $uidcheck++) {
    if(!uid_in_use($uidcheck)) return $uidcheck;
  } 
  return 0;
}

//checks if gid is in use for group creation
function gid_in_use($gidcheck) {
  $gids = popen ("getent group | sort -u |awk 'BEGIN{FS=\":\"}{print $3}'", "r")
        or die("Could not read group list\n");
  if($gids==FALSE) return -1;

  $count=0;
  while (!feof ($gids)) {
    $gidlist[$count] = (int) fgets ($gids, 4096);
    $count++;
  }
  foreach($gidlist as $gid) {
    if($gid==$gidcheck) return TRUE;
  }
  pclose($gids);
  return FALSE;
} 

//gets next gid for gid=auto creating groups
function next_free_gid($start=1001,$maxgid=5000){
  for($gidcheck=(int)$start ; $gidcheck<$maxgid ; $gidcheck++) {
    if(!gid_in_use($gidcheck)) return $gidcheck;
  } 
  return 0;
}

//run with no params sets age to 0 to force pw reset
function ldap_change_age($username,$age=0) {
  global $ldapconn;
  $ldapmod["shadowLastChange"]=$age;
  $result=ldap_mod_replace($ldapconn,"cn=" . $username . ",ou=users,".$ldapdn,$ldapmod);
  return $result;
}

?>

