66b8128be2fb5ba9db92cb5ac31b736cd079adcd
[gosa.git] / gosa-plugins / mit-krb5 / admin / systems / services / kerberos / class_password-methods-MIT.inc
1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2008 Fabian Hickert
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 class passwordMethodMIT extends passwordMethod
22 {
24 var $dn = "new"; // DN of the current object
25 var $parent_dn = "new"; // parents DN
26 var $is_account = FALSE; // This is TRUE if this object already has a krb extension
27 var $server_list = array(); // A list with all configured servers
28 var $map = array(); // Mapping array, maps SERVER-REALM, REALM-SERVER ...
30 var $goKrbRealm = ""; // The realm name this principal belongs to
31 var $principal = ""; // The principals name (e.g. user@MY-DOMAIN.SYS)
32 var $is_new = TRUE; // Is TRUE if principal is new
34 var $si_error = FALSE; // TRUE is daemon communication failed
35 var $si_error_msg = ""; // The last error message if above attribute is TRUE.
37 var $values = array(
38 "PRINC_EXPIRE_TIME", // Expiry date of this principal
39 "PW_EXPIRATION", // Password expiration
40 "MAX_LIFE", // Ticket lifetime
41 "MASK", // I'dont know
42 "MAX_RENEWABLE_LIFE", // Max ticket lifetime when renewed
43 "POLICY"); // The policy used by this principal
45 var $PRINC_EXPIRE_TIME = 0;
46 var $PW_EXPIRATION = 0;
47 var $PRINC_EXPIRE_TIME_clear = TRUE;
48 var $PW_EXPIRATION_clear = TRUE;
49 var $MAX_LIFE = 36000;
50 var $MAX_RENEWABLE_LIFE = 604800;
51 var $MASK = 0;
53 var $flags = array(
54 "DISALLOW_POSTDATED" =>0x00000001 , // Pohibit postdated tickets
55 "DISALLOW_FORWARDABLE" =>0x00000002 , // Prohibit forwardable tickets
56 "DISALLOW_TGT_BASED" =>0x00000004 , // Disallow Ticket-Granting Service
57 "DISALLOW_RENEWABLE" =>0x00000008 , // Prohibit renewable tickets
58 "DISALLOW_PROXIABLE" =>0x00000010 , // Disallow proxiable tickets
59 "DISALLOW_DUP_SKEY" =>0x00000020 , // Disallow user to user authentification
60 "DISALLOW_ALL_TIX" =>0x00000040 , // Forbid ticket issuance
61 "REQUIRES_PRE_AUTH" =>0x00000080 , // Preauthentication required
62 "REQUIRES_HW_AUTH" =>0x00000100 , // Hardware preauthentication
63 "REQUIRES_PWCHANGE" =>0x00000200 , // Force a password change
64 "UNKNOWN_0x00000400" =>0x00000400 , // ?
65 "UNKNOWN_0x00000800" =>0x00000800 , // ?
66 "DISALLOW_SVR" =>0x00001000 , // Prohibit issuance of service tickets
67 "PWCHANGE_SERVICE" =>0x00002000 , // Password change service
68 "SUPPORT_DESMD5" =>0x00004000 , // ?
69 "NEW_PRINC" =>0x00008000 ); // ?
71 var $used_flags = 128; // Flags, see below
73 var $readonly = array(
74 "FAIL_AUTH_COUNT", // The number of failed logins
75 "KVNO", // Key version number
76 "LAST_FAILED", // Last failed login time
77 "LAST_PWD_CHANGE", // Password last change time
78 "LAST_SUCCESS", // Last successful login
79 "MOD_DATE"); // Last modification time
81 var $FAIL_AUTH_COUNT = 0;
82 var $KVNO = "";
83 var $LAST_FAILED = 0;
84 var $LAST_PWD_CHANGE = 0;
85 var $LAST_SUCCESS = 0;
86 var $MOD_DATE = 0;
88 var $POLICY = "_none_";
89 var $POLICIES = array(); // Policies provided by the corrently selected realm/server
91 public function is_locked($config,$dn = "")
92 {
93 return(FALSE);
94 }
96 public function lock_account($config,$dn = "")
97 {
98 return(FALSE);
99 }
101 public function unlock_account($config,$dn = "")
102 {
103 return(FALSE);
104 }
106 public function __construct(&$config,$dn = "new")
107 {
108 $this->config= $config;
109 $this->parent_dn = $dn;
111 /* No config object given, this may be the case
112 if there is only a is_available() request triggered.
113 */
114 if(!is_object($this->config)){
115 return;
116 }
118 /* Keep the cached valued and skip loading principals
119 from si until this method gets configured.
120 */
121 $skip_si_access = TRUE;
122 if($dn != "new" && $dn != ""){
123 session::un_set("MIT_CACHE");
124 session::un_set("MIT_PRINCIPAL_CACHE");
125 session::un_set("MIT_POLICY_CACHE");
126 $this->clear_cache();
127 $skip_si_access = FALSE;
128 }
130 /* Get a list of all kerberos servers, defined in ldap
131 and get a list of principals they are providing.
132 */
133 $ldap = $this->config->get_ldap_link();
134 $ldap->cd($this->config->current['BASE']);
135 $ldap->search("(&(objectClass=goServer)(objectClass=goKrbServer))",array("goKrbRealm","cn","description","macAddress"));
136 $this->server_list = array();
137 while($attrs = $ldap->fetch()){
138 if(!isset($attrs['macAddress'][0])) continue;
139 if(!isset($attrs['description'][0])) $attrs['description'][0] ="";
141 if($skip_si_access){
142 $principals = array();
143 }else{
144 $principals = $this->load_principals_for_server($attrs['macAddress'][0]);
145 }
147 /* Create Realm/Server/Principal mapping.
148 */
149 foreach($principals as $principal){
150 $this->map["PRINCIPAL_SERVER"][$principal] = $attrs['cn'][0];
151 $this->map["PRINCIPAL_REALM"] [$principal] = $attrs['goKrbRealm'][0];
152 }
153 $this->map["SERVER_REALM"][$attrs['cn'][0]] = $attrs['goKrbRealm'][0];
154 $this->map["REALM_SERVER"][$attrs['goKrbRealm'][0]] = $attrs['cn'][0];
156 /* Set first realm as selected.
157 */
158 if($this->goKrbRealm == ""){
159 $this->goKrbRealm = $attrs['goKrbRealm'][0];
160 }
162 /* Create Server list
163 */
164 $this->server_list[$attrs['cn'][0]] = array("macAddress" => $attrs['macAddress'][0],
165 "description"=> $attrs['description'][0],
166 "dn" => $attrs['dn'],
167 "principals" => $principals,
168 "goKrbRealm" => $attrs['goKrbRealm'][0],
169 "cn" => $attrs['cn'][0]);
170 }
172 /* If this methods is initialized with a valid object dn then
173 load the object data from ldap and the SI daemon && initialize this class.
174 */
175 $this->is_new = TRUE;
176 if(!$skip_si_access){
177 $ldap = $this->config->get_ldap_link();
178 $ldap->cd($dn);
179 $ldap->cat($dn);
180 $this->attrs = $ldap->fetch();
182 /* Set initial pwd hash which take effect if no password method was set yet.
183 Will be overwritten by the following lines, if the user has already a valid principal.
184 */
185 $this->principal = $this->attrs['uid'][0]."@".$this->goKrbRealm;
187 if(isset($this->attrs['userPassword']) && preg_match("/^\{".$this->get_hash_name()."\}/",$this->attrs['userPassword'][0])){
189 /* Extract principal name out of userPassword attribute
190 */
191 $p_name = preg_replace("/^\{".$this->get_hash_name()."\}/","",$this->attrs['userPassword'][0]);
193 /* Try to detect server our principal is configured on
194 */
195 if(isset($this->map['PRINCIPAL_SERVER'][$p_name])){
196 $server= $this->map['PRINCIPAL_SERVER'][$p_name];
197 $this->goKrbRealm = $this->map['SERVER_REALM'][$server];
198 $this->principal = $p_name;
200 /* Load policies */
201 $server_name = $this->map['REALM_SERVER'][$this->goKrbRealm];
202 $server_mac = $this->server_list[$server_name]['macAddress'];
203 $this->POLICIES = $this->load_policies_for_server($server_mac);
205 /* Load principal */
206 $this->load_principal($this->server_list[$server]['macAddress'],$p_name);
207 $this->is_new = FALSE;
208 }
209 }
210 }
211 }
214 public static function clear_cache()
215 {
216 session::un_set("MIT_CACHE");
217 session::un_set("MIT_PRINCIPAL_CACHE");
218 session::un_set("MIT_POLICY_CACHE");
219 }
222 /*! \brief Load a specific principal from the si daemon
223 and initialize this plugin with it.
224 @param String The macAddress of the kerberos server.
225 @param String The name of the principal to load.
226 */
227 public function load_principal($server,$name)
228 {
229 $o = new gosaSupportDaemon();
230 $tmp = array();
231 $tmp = $o->krb5_get_principal($server,$name);
233 if($o->is_error()){
234 $this->si_error = TRUE;
235 $this->si_error_msg = sprintf(_("Cannot load principal '%s', from server '%s'!"),$name,$server).": <br>".$o->get_error();
236 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
237 }else{
239 /* Load flags
240 */
241 if(isset($tmp['ATTRIBUTES'])){
242 $this->used_flags = $tmp['ATTRIBUTES'];
243 }
245 /* Load readonly attributes
246 */
247 foreach($this->readonly as $attr){
248 if(isset($tmp[$attr])){
249 $this->$attr = $tmp[$attr];
250 }
251 }
253 /* Load modifyable attributes
254 */
255 foreach($this->values as $attr){
256 if(isset($tmp[$attr])){
257 $this->$attr = $tmp[$attr];
258 }
259 }
261 /* Update time checkboxes
262 */
263 $date_values = array("PW_EXPIRATION","PRINC_EXPIRE_TIME");
264 foreach($date_values as $value){
265 if(!empty($this->$value)){
266 $clear = $value."_clear";
267 $this->$clear = FALSE;
268 }
269 }
270 }
271 }
274 /*! \brief Get the list of all configured principals for a given server.
275 @param String The servers mac address.
276 @return Array A list with all principals
277 The results will cached.
278 */
279 public function load_principals_for_server($server)
280 {
281 if(!session::is_set("MIT_PRINCIPAL_CACHE")){
282 session::set("MIT_PRINCIPAL_CACHE",array());
283 }
284 $cache = session::get("MIT_PRINCIPAL_CACHE");
285 if(!isset($cache[$server])){
286 $o = new gosaSupportDaemon();
287 if($o->is_configured()){
288 $tmp = $o->krb5_list_principals($server);
289 if($o->is_error()){
290 $this->si_error = TRUE;
291 $this->si_error_msg = sprintf(_("Cannot load principals from server '%s'!"),$server).": <br>".$o->get_error();
292 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
293 return(array());
294 }else{
295 $cache[$server] = $tmp;
296 }
297 }
298 session::set("MIT_PRINCIPAL_CACHE",$cache);
299 }
300 return($cache[$server]);
301 }
304 /*! \brief get list of all configured policies
305 for a given server.
306 The results will cached.
307 */
308 public function load_policies_for_server($server)
309 {
310 if(!session::is_set("MIT_POLICY_CACHE")){
311 session::set("MIT_POLICY_CACHE",array());
312 }
313 $cache = session::get("MIT_POLICY_CACHE");
314 if(!isset($cache[$server])){
315 $o = new gosaSupportDaemon();
316 $tmp = $o->krb5_list_policies($server);
317 if($o->is_error()){
318 $this->si_error = TRUE;
319 $this->si_error_msg = sprintf(_("Cannot load policies from server '%s'!"),$server).": <br>".$o->get_error();
320 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
321 return(array());
322 }else{
323 $cache[$server] = array();
324 $cache[$server]["_none_"] = _("none");
325 foreach($tmp as $policy){
326 $cache[$server][$policy] = $policy;
327 }
328 ksort($cache[$server]);
329 }
330 session::set("MIT_POLICY_CACHE",$cache);
331 }
332 return($cache[$server]);
333 }
336 /*! \brief Check if this password method is useable.
337 This is the case if there is a si server running and at least one server configured.
338 kerberos support.
339 */
340 public function is_available()
341 {
342 global $config;
344 /* No config object given, this may be the case
345 if there is only a is_available() request triggered.
346 */
347 if(!is_object($config)){
348 return;
349 }
352 $o = new gosaSupportDaemon(FALSE);
354 if(count($this->server_list) && $o->connect() && $o->is_configured()){
355 return TRUE;
356 }
357 return(FALSE);
358 }
361 /*! \brief Create the password hash. In this case: {kerberos/sasl}name@RELAM
362 @param String The password -in this case unusued.
363 @return String The generated hash
364 */
365 public function generate_hash($pwd = "")
366 {
367 $mode= "kerberos";
369 /* No config object given, this may be the case
370 if there is only a is_available() request triggered.
371 */
372 if (is_object($this->config) && $this->config->get_cfg_value("useSaslForKerberos") == "true"){
373 $mode= "sasl";
374 }
375 return "{".$mode."}".$this->attrs['uid'][0]."@".$this->goKrbRealm;
376 }
379 public function create_template_hash($attrs)
380 {
381 return($this->generate_hash());
382 }
385 /*! \brief Removes this principal.
386 */
387 public function remove_from_parent()
388 {
389 if(!empty($this->principal) && $this->goKrbRealm){
390 $server = $this->map['REALM_SERVER'][$this->goKrbRealm];
391 $o = new gosaSupportDaemon();
392 if(!$o->krb5_del_principal($this->server_list[$server]['macAddress'],$this->principal)){
393 $this->si_error = TRUE;
394 $this->si_error_msg = $o->get_error();
395 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
396 }
397 }
398 }
401 /*! \brief Set a new password for this principal
402 @param String The new password.
403 */
404 public function set_password($password)
405 {
406 if(!empty($this->principal) && $this->goKrbRealm){
407 $server = $this->map['REALM_SERVER'][$this->goKrbRealm];
408 $o = new gosaSupportDaemon();
409 if(!$o->krb5_set_password($this->server_list[$server]['macAddress'],$this->principal,$password)){
410 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
411 return(FALSE);
412 }
413 }
414 return(TRUE);
415 }
418 /*! \brief Return the hash name of this mehtod, e.g. to identify methods.
419 @return String The hash used by this method.
420 */
421 public function get_hash_name()
422 {
423 $mode= "kerberos";
425 /* No config object given, this may be the case
426 if there is only a is_available() request triggered.
427 */
428 if (is_object($this->config) && $this->config->get_cfg_value("useSaslForKerberos") == "true"){
429 $mode= "sasl";
430 }
431 return "$mode";
432 }
435 /*! \brief Returns TRUE if this method is configurable else FALSE
436 @retrun Boolena TRUE if configurable, else FALSE.
437 */
438 public function is_configurable()
439 {
440 return TRUE;
441 }
444 /*! \brief Additional info displayed in the users password method drop down.
445 @retunr String Additional password method info.
446 */
447 public function get_description()
448 {
449 return(_("Daemon based"));
450 }
453 /*! \brief Display a HTML based configuration dialog for this plugin
454 @return String HTML.
455 */
456 public function configure()
457 {
458 $this->save_object();
460 $years = array();
461 $start = date("Y")-1;
462 for($i = $start; $i < ($start +20) ; $i++){
463 $years[$i] = $i;
464 }
465 $month= array();
466 for($i = 1; $i <= 12 ; $i++){
467 $month[str_pad($i,2,"0",STR_PAD_LEFT)] = $i;
468 }
469 $days= array();
470 for($i = 1; $i <= 31 ; $i++){
471 $days[str_pad($i,2,"0",STR_PAD_LEFT)] = $i;
472 }
473 $hours= array();
474 for($i = 0; $i <= 23 ; $i++){
475 $hours[str_pad($i,2,"0",STR_PAD_LEFT)] = $i;
476 }
477 $minutes= array();
478 for($i = 0; $i <= 59 ; $i++){
479 $minutes[str_pad($i,2,"0",STR_PAD_LEFT)] = $i;
480 }
483 /* Cancel heimdal options */
484 if (isset($_POST['pw_abort']) || $this->display == FALSE){
485 $this->display = FALSE;
486 return("");
487 }
489 /* Cancel heimdal options */
490 if (isset($_POST['pw_save'])){
491 $msgs = $this->check();
492 if(count($msgs)){
493 foreach($msgs as $msg){
494 msg_dialog::display(_("Kerberos"),$msg,WARNING_DIALOG);
495 }
496 }else{
497 $this->display = FALSE;
498 return "";
499 }
500 }
502 $smarty = get_smarty();
503 $smarty->assign("si_error",$this->si_error);
504 $smarty->assign("si_error_msg",$this->si_error_msg);
505 $smarty->assign("years",$years);
506 $smarty->assign("month",$month);
507 $smarty->assign("days",$days);
508 $smarty->assign("hours",$hours);
509 $smarty->assign("minutes",$minutes);
510 $smarty->assign("server_list",$this->server_list);
511 $smarty->assign("POLICY" ,$this->POLICY);
512 $smarty->assign("goKrbRealm" , $this->goKrbRealm);
513 $server_name = $this->map['REALM_SERVER'][$this->goKrbRealm];
514 $server_mac = $this->server_list[$server_name]['macAddress'];
515 $this->POLICIES = $this->load_policies_for_server($server_mac);
516 $smarty->assign("POLICIES" ,$this->POLICIES);
518 foreach($this->values as $attr){
519 $smarty->assign($attr ,$this->$attr);
520 }
521 foreach($this->readonly as $attr){
522 $smarty->assign($attr ,$this->$attr);
523 }
524 foreach($this->flags as $attr => $hex){
525 $smarty->assign($attr, ($this->used_flags & $hex ));
526 }
528 $date_values = array("PRINC_EXPIRE_TIME","PW_EXPIRATION");
529 foreach($date_values as $date_val){
530 $clear = $date_val."_clear";
531 $smarty->assign($date_val."_clear",$this->$clear);
532 $smarty->assign($date_val."_y",date("Y",$this->$date_val));
533 $smarty->assign($date_val."_m",date("m",$this->$date_val));
534 $smarty->assign($date_val."_d",date("d",$this->$date_val));
535 $smarty->assign($date_val."_h",date("h",$this->$date_val));
536 $smarty->assign($date_val."_i",date("i",$this->$date_val));
537 }
539 return($smarty->fetch(get_template_path("pwd_kerberos_mit.tpl",TRUE,dirname(__FILE__))));
540 }
543 /*! \brief Saves all relevant HTML posts for this plugin
544 */
545 public function save_object()
546 {
547 /* If the communication with the si server failed,
548 you are able to retry to connect to the server.
549 Here we hanlde those requests.
550 */
551 if(isset($_POST['retry_si'])){
552 $this->si_error= FALSE;
553 $this->si_error_msg= "";
554 session::un_set("MIT_PRINCIPAL_CACHE");
555 session::un_set("MIT_POLICY_CACHE");
556 $this->__construct($this->config,$this->parent_dn);
557 }
559 /* Only handle posts for this plugin, it its content was posted
560 */
561 if(isset($_POST['pwd_heimdal_posted'])){
563 if(isset($_POST['goKrbRealm'])){
564 $this->goKrbRealm = get_post("goKrbRealm");
565 }
567 $this->used_flags = 0;
568 foreach($this->flags as $attr => $hex){
569 if(isset($_POST[$attr])){
570 $this->used_flags |= $hex;
571 }
572 }
574 foreach(array("MAX_LIFE","MAX_RENEWABLE_LIFE","POLICY") as $attr){
575 if(isset($_POST[$attr])){
576 $this->$attr = get_post($attr);
577 }
578 }
580 $date_values = array("PW_EXPIRATION","PRINC_EXPIRE_TIME");
581 foreach($date_values as $date_value){
582 $clear = $date_value."_clear";
583 if(isset($_POST[$date_value."_clear"])){
584 $this->$clear = TRUE;
585 }else{
586 $this->$clear = FALSE;
587 $this->$date_value = gmmktime(
588 $_POST[$date_value."_h"],
589 $_POST[$date_value."_i"],
590 0,
591 $_POST[$date_value."_m"],
592 $_POST[$date_value."_d"],
593 $_POST[$date_value."_y"]);
594 }
595 }
596 }
597 }
600 /*! \brief Checks the values specified in the configuration dialog.
601 @return Array Containing all error messages.
602 */
603 public function check()
604 {
605 $message = array();
607 if(!preg_match("/^[0-9]*$/",$this->MAX_LIFE)){
608 $message[] = msgPool::invalid(_("Ticket max life"),$this->MAX_LIFE,"/[0-9]/");
609 }
610 if(!preg_match("/^[0-9]*$/",$this->MAX_RENEWABLE_LIFE)){
611 $message[] = msgPool::invalid(_("Ticket max renew"),$this->MAX_RENEWABLE_LIFE,"/[0-9]/");
612 }
613 return($message);
614 }
617 /*! \brief Adapt account settings from given dn
618 */
619 public function adapt_from_template ($dn)
620 {
621 $source = new passwordMethodMIT($this->config,$dn);
622 $attrs = array("PRINC_EXPIRE_TIME","PW_EXPIRATION","POLICY","MAX_LIFE","MAX_RENEWABLE_LIFE","MASK","used_flags");
623 foreach($attrs as $attr){
624 $this->$attr = $source->$attr;
625 }
626 }
629 /*! \brief Saves changes back to the SI daemon.
630 */
631 public function save($dn)
632 {
633 $ldap = $this->config->get_ldap_link();
634 $ldap->cd($dn);
635 $ldap->cat($dn,array('uid'));
636 $attrs = $ldap->fetch();
638 if(isset($attrs['uid'][0])){
640 /* Get servers mac */
641 $server_name = $this->map['REALM_SERVER'][$this->goKrbRealm];
642 $server_mac = $this->server_list[$server_name]['macAddress'];
644 $uid = $attrs['uid'][0];
645 $principal = $uid."@".strtoupper($this->goKrbRealm);
646 $policy = $this->POLICY;
648 /* Collect flags */
649 $flags = array();
650 $entry = array();
652 $entry['ATTRIBUTES'] = $this->used_flags;
654 /* Append other values */
655 foreach($this->values as $attr){
656 if($attr == "POLICY") continue;
657 $entry[$attr] = $this->$attr;
658 }
660 /* Prepare entry to be saved */
661 if($policy != "_none_"){
662 $entry['POLICY'] = $policy;
663 }
665 /* Set date values
666 */
667 $date_values = array("PW_EXPIRATION","PRINC_EXPIRE_TIME");
668 foreach($date_values as $value){
669 $clear = $value."_clear";
670 if($this->$clear){
671 $entry[$value] = 0;
672 }
673 }
676 /* Save principal changes */
677 $o = new gosaSupportDaemon();
678 if(in_array($principal,$this->server_list[$server_name]['principals'])){
679 $this->is_new = FALSE;
680 }
682 if($this->is_new){
683 $o->krb5_add_principal($server_mac,$principal,$entry);
684 }else{
685 $o->krb5_set_principal($server_mac,$principal,$entry);
686 }
687 if($o->is_error()){
688 $this->si_error = TRUE;
689 $this->si_error_msg = $o->get_error();
690 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o->get_error()),ERROR_DIALOG);
691 }
692 }
693 }
697 }
698 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
699 ?>