ActiveDirectory
[ class tree: ActiveDirectory ] [ index: ActiveDirectory ] [ all elements ]

Source for file ActiveDirectory.php

Documentation is available at ActiveDirectory.php

  1. <?php
  2. /**
  3.  * Project: ActiveDirectory :: Control Active Directory with ldap or ldaps
  4.  * File:    ActiveDirectory.php
  5.  *
  6.  * Copyright (c) 2018, JoungKyun.Kim <http://oops.org>
  7.  *
  8.  * LICENSE: BSD
  9.  *
  10.  * ActiveDirectory pear package support to control Microsoft Active Directory
  11.  * with ldap or ldaps protocol.
  12.  *
  13.  * @category   System
  14.  * @package    ActiveDirectory
  15.  * @author     JoungKyun.Kim <http://oops.org>
  16.  * @copyright  (c) 2018 JoungKyun.Kim
  17.  * @license    BSD License
  18.  * @link       http://pear.oops.org/package/ActiveDirectory
  19.  * @filesource
  20.  */
  21.  
  22. /**
  23.  * import KSC5601 class
  24.  * http://pear.oops.org/docs/li_KSC5601.html
  25.  * http://pear.oops.org/package/KSC5601
  26.  */
  27. require_once 'KSC5601.php';
  28.  
  29. /**
  30.  * import ActiveDirectory_API class
  31.  */
  32. require_once 'ActiveDirectory/API.php';
  33.  
  34. /**
  35.  * Main Class that control Active Directory
  36.  * @package ActiveDirectory
  37.  */
  38. {
  39.     // {{{ properties
  40.     /**
  41.      * KSC5601 object
  42.      * @access protected
  43.      * @var    object 
  44.      */
  45.     protected $ksc = null;
  46.  
  47.     /**
  48.      * Ldap bind resource
  49.      * @access protected
  50.      * @var    resource 
  51.      */
  52.     protected $link = null;
  53.  
  54.     /**
  55.      * Set default Active Directory Domain name
  56.      * @access  public
  57.      * @var     string 
  58.      */
  59.     public $domain = null;
  60.  
  61.     /**
  62.      * Set default distinguished name
  63.      * @access  public
  64.      * @var     string 
  65.      */
  66.     public $rdn = null;
  67.  
  68.     /**
  69.      * 출력 문자열. 이 값은 iconv 변경을 위해 지정한다.
  70.      * @access  public
  71.      * @var     stinrg 
  72.      */
  73.     public $charset = null;
  74.  
  75.     /**
  76.      * ActiveDirectory의 local character set 을 지정한다.
  77.      * @access  public
  78.      * @var     string 
  79.      *
  80.      */
  81.     public $adcharset = 'cp949';
  82.  
  83.     /**
  84.      * Set Ldap error messages
  85.      * @access  public
  86.      * @var     string 
  87.      */
  88.     static public $error;
  89.     // }}}
  90.  
  91.     // {{{ (boolean) ActiveDirectory::__construct (void)
  92.     /**
  93.      * @access  public
  94.      * @return  void 
  95.      */
  96.     
  97. public
  98.     function __construct ({
  99.         putenv ('LDAPTLS_REQCERT=never');
  100.  
  101.         if php_sapi_name (== 'cli' {
  102.             $char strtolower (getenv ('LANG'));
  103.  
  104.             if preg_match ('/euc-?kr/'$char) )
  105.                 $this->charset = 'cp949'// euc-kr
  106.             else
  107.                 $this->charset = 'utf-8';
  108.         else
  109.             $this->charset = 'utf-8';
  110.  
  111.  
  112.         $this->ksc = new KSC5601;
  113.     }
  114.     // }}}
  115.  
  116.     // {{{ (object) ActiveDirectory::connect ($account, $pass, $host, $port = null, $certi = null)
  117.     /**
  118.      * Active Directory 에 접속을 하고, 접속한 계정의 정보를 반환한다.
  119.      *
  120.      * @access  public
  121.      * @return  object|false  {status, error, info}
  122.      * @param   string   Active Directory account 이름
  123.      * @param   string   Account 암호
  124.      * @param   string   접속할 호스트
  125.      * @param   integer  Ldap 포트
  126.      * @param   string   Ldaps 연결에 필요한 서버 인증서
  127.      */
  128.     
  129. public
  130.     function connect ($account$pass$host$port null$certi null{
  131.         if $certi != null && file_exists ($certi) )
  132.             $certi null;
  133.  
  134.         if is_numeric ($port) )
  135.             $port null;
  136.  
  137.         if $port === null )
  138.             $port $certi 636 389;
  139.  
  140.         $proto $certi 'ldaps' 'ldap';
  141.         $host sprintf ('%s://%s'$proto$host);
  142.  
  143.         if $certi )
  144.             putenv ('LDAPTLS_CACERT=' $certi);
  145.  
  146.         $this->link = ldap_connect ($host$port);
  147.  
  148.         ldap_set_option($this->linkLDAP_OPT_PROTOCOL_VERSION3);
  149.         ldap_set_option($this->linkLDAP_OPT_REFERRALS0);
  150.  
  151.         if $this->domain )
  152.             $dn sprintf ('%s@%s'$account$this->domain);
  153.         else
  154.             $dn sprintf ('cn=%s,%s'$account$this->rdn);
  155.  
  156.         $r = (object) array (
  157.             'status' => false,
  158.             'error'  => null,
  159.             'info'   => null
  160.         );
  161.  
  162.         if ( ($r->status $this->auth ($dn$pass$this->link)) === false {
  163.             $r->error ldap_error ($this->link);
  164.         else {
  165.             $r->info $this->user ($account$this->rdn);
  166.  
  167.             if $r->info === false {
  168.                 $r->status false;
  169.                 $r->error self::$error;
  170.                 @ldap_unbind ($this->link);
  171.             }
  172.         }
  173.  
  174.         return $r;
  175.     }
  176.     // }}}
  177.  
  178.     // {{{ (object) ActiveDirectory::user ($user, $rdn = null, $full = false)
  179.     /**
  180.      * 지정한 계정의 속성을 반환.
  181.      *
  182.      * @return object|false
  183.      * @param  string   Account 이름
  184.      * @param  string   bind DN
  185.      * @param  bool     true로 지정을 하면 전체 속성을 반환 (기본값 false)
  186.      */
  187.     
  188. public
  189.     function user ($user$rdn null$full false{
  190.         $rdn $rdn $rdn $this->rdn;
  191.  
  192.         $r->error self::$error null;
  193.         $filter sprintf ('(samaccountname=%s)'$user);
  194.  
  195.         if $full )
  196.             return $this->search ($rdn$filter);
  197.  
  198.         return $this->search_ex ($rdn$filter);
  199.     }
  200.     // }}}
  201.  
  202.     // {{{ (array) ActiveDirectory::userlist ($rdn = null)
  203.     /**
  204.      * Active Directory에 있는 전체 사용자 계정 리스트를 반환
  205.      *
  206.      * @access  public
  207.      * @return  array|false
  208.      * @param   string   Bind dn
  209.      */
  210.     
  211. public
  212.     function userlist ($rdn null{
  213.         $rdn $rdn $rdn $this->rdn;
  214.  
  215.         $filter '(&(objectCategory=person)(objectClass=user))';
  216.         $entries $this->search ($rdn$filter);
  217.  
  218.         if $entries === false )
  219.             return false;
  220.  
  221.         $i 0;
  222.         foreach $entries as $v )
  223.             $r[$i++$v->cn;
  224.  
  225.         sort ($r);
  226.  
  227.         return $r;
  228.     }
  229.     // }}}
  230.  
  231.     // {{{ (array) ActiveDirectory::grouplist ($rdn = null)
  232.     /**
  233.      * Active Directory에 있는 전체 그룹 리스트를 반환
  234.      *
  235.      * @access  public
  236.      * @return  array|false
  237.      * @param   string   Bind DN
  238.      */
  239.     
  240. public
  241.     function grouplist ($rdn null{
  242.         $rdn $rdn $rdn $this->rdn;
  243.  
  244.         #$filter = '(grouptype=*)';
  245.         $filter '(objectCategory=group)';
  246.         $entries $this->search ($rdn$filter);
  247.  
  248.         if $entries === false )
  249.             return false;
  250.  
  251.         $i 0;
  252.         foreach $entries as $v )
  253.             $r[$i++$v->cn;
  254.  
  255.         sort ($r);
  256.  
  257.         return $r;
  258.     }
  259.     // }}}
  260.  
  261.     // {{{ (boolean) ActiveDirectory::is_account_lock ($obj)
  262.     /**
  263.      * 주어진 계정이 lock이 걸려있는지 여부를 확인
  264.      *
  265.      * lockout account (lockouttime>=1)
  266.      * disabled account (userAccountControl:1.2.840.113556.1.4.803:=2)
  267.      *   -> userAccountControl value is 512 or 66048 enabled account
  268.      *   -> userAccountControl value is 514 or 66050 disabled account
  269.      *
  270.      * @access  public
  271.      * @return  boolean 
  272.      * @param   object   ActiveDirectory::user mehtod의 결과값
  273.      */
  274.     function is_account_locked ($obj{
  275.         if is_object ($obj) )
  276.             return false;
  277.  
  278.         if $obj->lockouttime && $obj->lockouttime != )
  279.             return true;
  280.  
  281.         if $obj->useraccountcontrol == 514 || $obj->useraccountcontrol == 66050 )
  282.             return true;
  283.  
  284.         return false;
  285.     }
  286.     // }}}
  287.  
  288.     // {{{ (object) ActiveDirectory::maxid ($rdn = null)
  289.     /**
  290.      * 현재 Active Directory의 UID/GID 최대값을 가져온다.
  291.      *
  292.      * Unix Attribute가 활성화 되어 있지 않으면 0을 반환한다.
  293.      *
  294.      * @access public
  295.      * @return object 
  296.      * @param  string   bind DN
  297.      */
  298.     
  299. public
  300.     function maxid ($rdn null{
  301.         $rdn $rdn $rdn $this->rdn;
  302.         $ret new StdClass;
  303.  
  304.         $ret->uid 0;
  305.         $ret->gid 0;
  306.  
  307.         $r $this->search_api ($rdnnullarray ('uid''uidnumber''gidnumber'));
  308.  
  309.         foreach $r as $v {
  310.             $ret->uid isset ($v->uidnumber&& $v->uidnumber $ret->uid $v->uidnumber $ret->uid;
  311.             $ret->gid isset ($v->gidnumber&& $v->gidnumber $ret->gid $v->gidnumber $ret->gid;
  312.         }
  313.  
  314.         return $ret;
  315.     }
  316.     // }}}
  317.  
  318.     // {{{ (object) ActiveDirectory::search ($rdn, $filter = null)
  319.     /**
  320.      * Entry를 검색
  321.      *
  322.      * 결과 값이 1 entry일 경우에는 object로 반환을 하며, 1개 이상일 경우에는
  323.      * 모든 entry를 배열로 반환한다.
  324.      *
  325.      * @access  public
  326.      * @return  object|array|false
  327.      * @param   string   bind DN
  328.      * @param   filter   ldap 필터
  329.      */
  330.     
  331. public
  332.     function search ($rdn null$filter null{
  333.         $rdn $rdn $rdn $this->rdn;
  334.         return $this->search_api ($rdn$filter);
  335.     }
  336.     // }}}
  337.  
  338.     // {{{ (object) ActiveDirectory::search_ex ($rdn, $filter = null, $attr = null)
  339.     /**
  340.      * Entry를 검색
  341.      *
  342.      * ActiveDirectory::search 와의 차이점은 4번째 인자로 반환할 속성을
  343.      * 지정할 수 있다. 지정하지 않을 경우 다음의 속성을 반환한다.
  344.      *
  345.      * 'cn', 'sn', 'givenname', 'displayname', 'distinguishedname',
  346.      * 'department', 'title', 'description', 'company',
  347.      * 'mail', 'ipphone', 'mobile', 'memberof', 'member',
  348.      * 'mssfu30name', 'uidnumber', 'gidnumber', 'unixhomedirectory', 'loginshell',
  349.      * 'whencreated', 'whenchanged', 'lastlogontimestamp', 'lastlogon',
  350.      * 'pwdlastset', 'badpasswordtime', 'accountexpires', 'lockouttime',
  351.      * 'useraccountcontrol', 'samaccountname'
  352.      *
  353.      * @access  public
  354.      * @return  object|array|false
  355.      * @param   string   bind Dn
  356.      * @param   string   ldap 필터
  357.      * @param   array    반환할 속성
  358.      */
  359.     
  360. public
  361.     function search_ex ($rdn null$filter null$attr null{
  362.         $rdn   $rdn $rdn $this->rdn;
  363.         if $attr {
  364.             $attr array (
  365.                 'cn''sn''givenname''displayname''distinguishedname',
  366.                 'department''title''description''company',
  367.                 'mail''ipphone''mobile''memberof''member',
  368.                 'mssfu30name''uidnumber''gidnumber''unixhomedirectory''loginshell',
  369.                 'whencreated''whenchanged''lastlogontimestamp''lastlogon',
  370.                 'pwdlastset''badpasswordtime''accountexpires''lockouttime',
  371.                 'useraccountcontrol''samaccountname'
  372.             );
  373.         }
  374.  
  375.         return $this->search_api ($rdn$filter$attr);
  376.     }
  377.     // }}}
  378.  
  379.     // {{{ (boolean) ActiveDirectory::change_password ($account, $new_pass)
  380.     /**
  381.      * Active Directory 계정의 암호를 변경한다. 이 method는 ldaps 프로토콜로
  382.      * 연결해야 동작한다.
  383.      *
  384.      * @access  public
  385.      * @return  boolean 
  386.      * @param   string|object 계정  이름 또는 ActiveDirectory::user method의 결과
  387.      * @param   new_pass     변경할 암호
  388.      */
  389.     
  390. public
  391.     function change_password ($entry$new_pass{
  392.         if trim ($new_pass) ) {
  393.             self::$error sprintf (
  394.                 "The given password is '%s'. " .
  395.                 "The password is only ascii character.",
  396.                 $new_pass
  397.             );
  398.             return false;
  399.         }
  400.  
  401.         if is_array ($entry) ) {
  402.             if trim ($entry) ) {
  403.                 self::$error sprintf (
  404.                     "The given account name is '%s'. " .
  405.                     "The account name is only ascii character without white space.",
  406.                     $entry
  407.                 );
  408.                 return false;
  409.             }
  410.             $account $entry;
  411.  
  412.             $entry $this->user ($entry);
  413.             #$entry = $this->search_ex ($this->rdn, "samaccountname={$account}");
  414.             if $entry === false )
  415.                 return false;
  416.         }
  417.  
  418.         $data['unicodePwd'$this->make_nt_passwd ($new_pass);
  419.  
  420.         /*
  421.          * 패스워드 변경은.. UTF8 로 보내면.. 또 안된다..
  422.          * MS 왜이러는 거야..
  423.          * 2012 에서도 그런지는 확인 필요! (2008 R2 까지는 확인)
  424.          *
  425.          * LDAP protocol 3 에서는 어떤지 확인 안됨. protocol3은 무조건
  426.          * UTF-8을 사용하는 것이 표준인데..
  427.         if ( $this->ksc->is_utf8 ($entry->distinguishedname, true) )
  428.             $entry->distinguishedname = $this->ksc->utf8 ($entry->distinguishednamem, UHC);
  429.          */
  430.  
  431.         $r $this->exec ($entry->distinguishedname$data'replace');
  432.         #if ( ($r = @ldap_mod_replace ($this->link, $entry->distinguishedname, $data)) === false )
  433.         #    self::$error = ldap_error ($this->link);
  434.  
  435.         if $r === true {
  436.             if $this->is_unix_attribute )
  437.                 $this->change_unix_password ($entry$new_pass);
  438.         }
  439.  
  440.         return $r;
  441.     }
  442.     // }}}
  443.  
  444.     /*
  445.      * UNIX Attribute method
  446.      */
  447.  
  448.     // {{{ (boolean) ActiveDirectory::is_unix_attribute (&$r)
  449.     /**
  450.      * 해당 유저의 UNIX attribute가 활성화 되어 있는지 여부를 확인
  451.      *
  452.      * @access public
  453.      * @return bool 
  454.      * @param  string|object 계정  또는 계정 속성
  455.      */
  456.     
  457. public
  458.     function is_unix_attribute (&$r{
  459.         if is_object ($r) ) {
  460.             if is_string ($r) )
  461.                 return false;
  462.  
  463.             if ( ($res $this->user ($r$this->rdn)) === false )
  464.                 return false;
  465.  
  466.             if is_object ($res|| isset ($res->samaccountname) )
  467.                 return false;
  468.  
  469.             $r $res;
  470.             unset ($res);
  471.         }
  472.  
  473.         if $r->uid && $r->mssfu30name && $r->loginshell )
  474.             return true;
  475.  
  476.         return false;
  477.     }
  478.     // }}}
  479.  
  480.     // {{{ (boolean) ActiveDirectory::enable_unix_attribute ($account, $attr)
  481.     /**
  482.      * 계정의 unix attribyte를 활성화 한다.
  483.      *
  484.      * ActiveDirectory::user method의 결과값을 파라미터로 넘긴다.
  485.      *
  486.      * @access public
  487.      * @return boolean 
  488.      * @param  object  계정 속성
  489.      * @param  array   unix attribute 값<br>
  490.      *     설정 가능한 배열 멤버는 다음과 같다. (괄호안은 지정하지 않았을 경우의
  491.      *     기본값이다.)
  492.      *     <p>
  493.      *     <ul>
  494.      *         <li>mssfu30name (CN attribute)</li>
  495.      *         <li>mssfu30nisdomain (ActiveDirectory::$domain)</li>
  496.      *         <li>loginshell (/bin/bash)</li>
  497.      *         <li>unixhomedirectory (/home/AD/USERNAME)</li>
  498.      *         <li>unixuserpassword (Gabage data)</li>
  499.      *     </ul>
  500.      */
  501.     
  502. public
  503.     function enable_unix_attribute ($account$attr null{
  504.         return $this->set_unix_attribute ($account$attr'add');
  505.     }
  506.     // }}}
  507.  
  508.     // {{{ (boolean) ActiveDirectory::disable_unix_attribute ($account)
  509.     /**
  510.      * 계정의 unix attribyte를 비활성화 한다.
  511.      *
  512.      * @access public
  513.      * @return boolean 
  514.      * @param  object  계정 속성 또는 계정 이름
  515.      */
  516.     
  517. public
  518.     function disable_unix_attribute ($account{
  519.         return $this->set_unix_attribute ($accountnull'remove');
  520.     }
  521.     // }}}
  522.  
  523.     // {{{ (boolean) ActiveDirectory::change_unix_password ($account, $pass = null)
  524.     /**
  525.      * Unix Attribute 속성의 암호를 변경한다.
  526.      *
  527.      * @access public
  528.      * @return bool 
  529.      * @param  string 계정 이름
  530.      * @param  string 변경할 암호
  531.      */
  532.     
  533. public
  534.     function change_unix_password ($account$pass null{
  535.         if $pass )
  536.             return false;
  537.  
  538.         $attr['unixuserpassword'$pass;
  539.         return $this->set_unix_attribute ($account$attr'replace');
  540.     }
  541.     // }}}
  542.  
  543.     // {{{ (void) ActiveDirectory::close ($link = null) 
  544.     /**
  545.      * Disconnect Active Directory
  546.      * @access  public
  547.      * @return  void 
  548.      * @param   resource  (optional) ldap link
  549.      */
  550.     
  551. public
  552.     function close (&$r{
  553.         if is_resource ($r) )
  554.             ldap_unbind ($r);
  555.         else if is_object ($r) ) {
  556.             if is_resource ($r->link) )
  557.                 ldap_unbind ($r->link);
  558.  
  559.             $r->status false;
  560.             $r->link   false;
  561.             $r->error  null;
  562.             $r->info   null;
  563.         else {
  564.             if is_resource ($r) )
  565.                 ldap_unbind ($r);
  566.         }
  567.     }
  568.     // }}}
  569.  
  570.     /*
  571.      * Ldap Execute
  572.      */
  573.  
  574.     // {{{ (boolean) ActiveDirectory::exec ($link, $dn, $attrs, $mode='add')
  575.     /**
  576.      * LDAP 추가/수정/삭제 실행을 한다.
  577.      *
  578.      * @access public
  579.      * @return boolean 
  580.      * @param  resrouce 
  581.      * @param  string   Bind DN
  582.      * @param  array    실행할 키/값
  583.      */
  584.     
  585. public
  586.     function exec ($dn$attrs$mode 'add'$link null{
  587.         $link $link $link $this->link;
  588.  
  589.         if is_array ($attrs) ) {
  590.             ActiveDirectory::$error 'Entry is must set with Array';
  591.             return false;
  592.         }
  593.  
  594.         if count ($attrs) ) {
  595.             ActiveDirectory::$error 'Entry is empty';
  596.             return false;
  597.         }
  598.  
  599.         $mode strtolower ($mode);
  600.         if preg_match ('/^(add|del|replace)$/'$mode) ) {
  601.             ActiveDirectory::$error 'Invalid mode';
  602.             return false;
  603.         }
  604.  
  605.         $funcname 'ldap_mod_' $mode;
  606.  
  607.         if ( ($r @$funcname ($link$dn$attrs)) === false )
  608.             ActiveDirectory::$error ldap_error ($link);
  609.  
  610.         return $r;
  611.     }
  612.     // }}}
  613.  
  614.  
  615.     // {{{ (boolean) ActiveDirectory::__construct (void)
  616.     /**
  617.      * @access  public
  618.      * @return  void 
  619.      */
  620.     public function __destruct ({
  621.         if is_resource ($this->link) )
  622.             ldap_unbind ($this->link);
  623.     }
  624.     // }}}
  625. }
  626.  
  627. /*
  628.  * Local variables:
  629.  * tab-width: 4
  630.  * c-basic-offset: 4
  631.  * End:
  632.  * vim: set filetype=php noet sw=4 ts=4 fdm=marker:
  633.  * vim600: noet sw=4 ts=4 fdm=marker
  634.  * vim<600: noet sw=4 ts=4
  635.  */
  636. ?>

Documentation generated on Tue, 14 May 2019 01:59:38 +0900 by phpDocumentor 1.4.4