Code

Updated macro class. Added check -> Empty macros can't be saved.
[gosa.git] / plugins / personal / generic / class_user.inc
1 <?php
2 /*!
3   \brief   user plugin
4   \author  Cajus Pollmeier <pollmeier@gonicus.de>
5   \version 2.00
6   \date    24.07.2003
8   This class provides the functionality to read and write all attributes
9   relevant for person, organizationalPerson, inetOrgPerson and gosaAccount
10   from/to the LDAP. It does syntax checking and displays the formulars required.
11  */
13 class user extends plugin
14 {
15   /* Definitions */
16   var $plHeadline= "Generic";
17   var $plDescription= "This does something";
19   /* CLI vars */
20   var $cli_summary= "Handling of GOsa's user base object";
21   var $cli_description= "Some longer text\nfor help";
22   var $cli_parameters= array("eins" => "Eins ist toll", "zwei" => "Zwei ist noch besser");
24   /* Plugin specific values */
25   var $base= "";
26   var $orig_base= "";
27   var $cn= "";
28   var $new_dn= "";
29   var $personalTitle= "";
30   var $academicTitle= "";
31   var $homePostalAddress= "";
32   var $homePhone= "";
33   var $labeledURI= "";
34   var $o= "";
35   var $ou= "";
36   var $departmentNumber= "";
37   var $employeeNumber= "";
38   var $employeeType= "";
39   var $roomNumber= "";
40   var $telephoneNumber= "";
41   var $facsimileTelephoneNumber= "";
42   var $mobile= "";
43   var $pager= "";
44   var $l= "";
45   var $st= "";
46   var $postalAddress= "";
47   var $dateOfBirth;
48   var $use_dob= "0";
49   var $gender="0";
50   var $preferredLanguage="0";
52   var $jpegPhoto= "*removed*";
53   var $photoData= "";
54   var $old_jpegPhoto= "";
55   var $old_photoData= "";
56   var $cert_dialog= FALSE;
57   var $picture_dialog= FALSE;
59   var $userPKCS12= "";
60   var $userSMIMECertificate= "";
61   var $userCertificate= "";
62   var $certificateSerialNumber= "";
63   var $old_certificateSerialNumber= "";
64   var $old_userPKCS12= "";
65   var $old_userSMIMECertificate= "";
66   var $old_userCertificate= "";
68   var $gouvernmentOrganizationalUnit= "";
69   var $houseIdentifier= "";
70   var $street= "";
71   var $postalCode= "";
72   var $vocation= "";
73   var $ivbbLastDeliveryCollective= "";
74   var $gouvernmentOrganizationalPersonLocality= "";
75   var $gouvernmentOrganizationalUnitDescription= "";
76   var $gouvernmentOrganizationalUnitSubjectArea= "";
77   var $functionalTitle= "";
78   var $role= "";
79   var $publicVisible= "";
81   var $dialog;
83   /* variables to trigger password changes */
84   var $pw_storage= "crypt";
85   var $last_pw_storage= "unset";
86   var $had_userCertificate= FALSE;
88   /* attribute list for save action */
89   var $attributes= array("sn", "givenName", "uid", "personalTitle", "academicTitle",
90       "homePostalAddress", "homePhone", "labeledURI", "ou", "o", "dateOfBirth", "gender","preferredLanguage",
91       "departmentNumber", "employeeNumber", "employeeType", "l", "st","jpegPhoto",
92       "roomNumber", "telephoneNumber", "mobile", "pager", "cn", "userPKCS12",
93       "postalAddress", "facsimileTelephoneNumber", "userSMIMECertificate");
95   var $objectclasses= array("top", "person", "organizationalPerson", "inetOrgPerson",
96       "gosaAccount");
98   /* attributes that are part of the government mode */
99   var $govattrs= array("gouvernmentOrganizationalUnit", "houseIdentifier", "vocation",
100       "ivbbLastDeliveryCollective", "gouvernmentOrganizationalPersonLocality",
101       "gouvernmentOrganizationalUnitDescription","gouvernmentOrganizationalUnitSubjectArea",
102       "functionalTitle", "certificateSerialNumber", "publicVisible", "street", "role",
103       "postalCode");
106   /* constructor, if 'dn' is set, the node loads the given
107      'dn' from LDAP */
108   function user ($config, $dn= NULL)
109   {
110     $this->config= $config;
111     /* Configuration is fine, allways */
112     if ($this->config->current['GOVERNMENTMODE']){
113       $this->attributes=array_merge($this->attributes,$this->govattrs);
114     }
116     /* Load base attributes */
117     plugin::plugin ($config, $dn);
119     if ($this->config->current['GOVERNMENTMODE']){
120       /* Fix public visible attribute if unset */
121       if (!isset($this->attrs['publicVisible'])){
122         $this->publicVisible == "nein";
123       }
124     }
126     /* Load government mode attributes */
127     if ($this->config->current['GOVERNMENTMODE']){
128       /* Copy all attributs */
129       foreach ($this->govattrs as $val){
130         if (isset($this->attrs["$val"][0])){
131           $this->$val= $this->attrs["$val"][0];
132         }
133       }
134     }
136     /* Create me for new accounts */
137     if ($dn == "new"){
138       $this->is_account= TRUE;
139     }
141     /* Make hash default to md5 if not set in config */
142     if (!isset($this->config->current['HASH'])){
143       $hash= "md5";
144     } else {
145       $hash= $this->config->current['HASH'];
146     }
148     /* Load data from LDAP? */
149     if ($dn != NULL){
151       /* Do base conversation */
152       if ($this->dn == "new"){
153         $ui= get_userinfo();
154         $this->base= dn2base($ui->dn);
155       } else {
156         $this->base= dn2base($dn);
157       }
159       /* get password storage type */
160       if (isset ($this->attrs['userPassword'][0])){
161         /* Initialize local array */
162         $matches= array();
163         if (preg_match ("/^{([^}]+)}(.+)/", $this->attrs['userPassword'][0], $matches)){
164           $this->pw_storage= strtolower($matches[1]);
165         } else {
166           if ($this->attrs['userPassword'][0] != ""){
167             $this->pw_storage= "clear";
168           } else {
169             $this->pw_storage= $hash;
170           }
171         }
172       } else {
173         /* Preset with vaule from configuration */
174         $this->pw_storage= $hash;
175       }
177       /* Load extra attributes: certificate and picture */
178       $this->load_cert();
179       $this->load_picture();
180       if ($this->userCertificate != ""){
181         $this->had_userCertificate= TRUE;
182       }
183     }
185     /* Reset password storage indicator, used by password_change_needed() */
186     if ($dn == "new"){
187       $this->last_pw_storage= "unset";
188     } else {
189       $this->last_pw_storage= $this->pw_storage;
190     }
192     /* Generate dateOfBirth entry */
193     if (isset ($this->attrs['dateOfBirth'])){
194       /* This entry is ISO 8601 conform */
195       list($year, $month, $day)= split("-", $this->attrs['dateOfBirth'][0], 3);
196     
197       $this->dateOfBirth=array( 'mon'=> $month,"mday"=> $day,"year"=> $year);
198       $this->use_dob= "1";
199     } else {
200       $this->use_dob= "0";
201     }
203     /* Put gender attribute to upper case */
204     if (isset ($this->attrs['gender'])){
205       $this->gender= strtoupper($this->attrs['gender'][0]);
206     }
207   
208     $this->orig_base = $this->base;
209   }
212   /* execute generates the html output for this node */
213   function execute()
214   {
215     /* Call parent execute */
216     plugin::execute();
218     $smarty= get_smarty();
220     /* Fill calendar */
221     if ($this->dateOfBirth == "0"){
222       $date= getdate();
223     } else {
224       if(is_array($this->dateOfBirth)){
225         $date = $this->dateOfBirth;
226   
227         // Trigger on dates like 1985-04-01, getdate only understands timestamps
228       } else if (!empty($this->dateOfBirth) && !is_numeric($this->dateOfBirth)){
229         $date= getdate(strtotime($this->dateOfBirth));
231       } else {
232         $date = getdate($this->dateOfBirth);
233       }
234     }
236     $days= array();
237     for($d= 1; $d<32; $d++){
238       $days[$d]= $d;
239     }
240     $years= array();
242     if(($date['year']-100)<1901){
243       $start = 1901;
244     }else{
245       $start = $date['year']-100;
246     }
248     $end = $start +100;
249     
250     for($y= $start; $y<=$end; $y++){
251       $years[]= $y;
252     }
253     $years['-']= "-&nbsp;";
254     $months= array(_("January"), _("February"), _("March"), _("April"),
255         _("May"), _("June"), _("July"), _("August"), _("September"),
256         _("October"), _("November"), _("December"), '-' => '-&nbsp;');
257     $smarty->assign("day", $date["mday"]);
258     $smarty->assign("days", $days);
259     $smarty->assign("months", $months);
260     $smarty->assign("month", $date["mon"]-1);
261     $smarty->assign("years", $years);
262     $smarty->assign("year", $date["year"]);
264     /* Assign sex */
265     $sex= array(0 => "&nbsp;", "F" => _("female"), "M" => _("male"));
266     $smarty->assign("gender_list", $sex);
268     /* Assign prefered langage */
269     $language= array(0 => "&nbsp;", "fr_FR" => ("fr_FR"), "en_EN" => ("en_EN"), 
270                                     "de_DE" => ("de_DE"), "it_IT" => ("it_IT"), 
271                                     "nl_NL" => ("nl_NL"), "ru_RU" => ("ru_RU"));
272     $smarty->assign("preferredLanguage_list", $language);
274     /* Get random number for pictures */
275     srand((double)microtime()*1000000); 
276     $smarty->assign("rand", rand(0, 10000));
279     /* Do we represent a valid gosaAccount? */
280     if (!$this->is_account){
281       echo "<img alt=\"\" src=\"images/stop.png\" align=\"middle\">&nbsp;<b>".
282         _("This account has no valid GOsa extensions.")."</b>";
283       return;
284     }
286     /* Base select dialog */
287     $once = true;
288     foreach($_POST as $name => $value){
289       if(preg_match("/^chooseBase/",$name) && $once){
290         $once = false;
291         $this->dialog = new baseSelectDialog($this->config,$this,$this->allowedBasesToMoveTo());
292         $this->dialog->setCurrentBase($this->base);
293       }
294     }
296     /* Dialog handling */
297     if(is_object($this->dialog)){
298       /* Must be called before save_object */
299       $this->dialog->save_object();
300    
301       if($this->dialog->isClosed()){
302         $this->dialog = false;
303       }elseif($this->dialog->isSelected()){
305         /* check if selected base is allowed to move to / create a new object */
306         $tmp = $this->get_allowed_bases();
307         if(isset($tmp[$this->dialog->isSelected()])){
308           $this->base = $this->dialog->isSelected();
309         }
310         $this->dialog= false;
311       }else{
312         return($this->dialog->execute());
313       }
314     }
316     /* Want picture edit dialog? */
317     if($this->acl_is_writeable("userPicture")) {
318       if (isset($_POST['edit_picture'])){
319         /* Save values for later recovery, in case some presses
320            the cancel button. */
321         $this->old_jpegPhoto= $this->jpegPhoto;
322         $this->old_photoData= $this->photoData;
323         $this->picture_dialog= TRUE;
324         $this->dialog= TRUE;
325       }
326     }
328     /* Remove picture? */
329     if($this->acl_is_writeable("userPicture",(!is_object($this->parent) && !isset($_SESSION['edit']))) ){
330       if (isset($_POST['picture_remove'])){
331         $this->set_picture ();
332         $this->jpegPhoto= "*removed*";
333         $this->is_modified= TRUE;
334         return($smarty->fetch (get_template_path('generic_picture.tpl', TRUE, dirname(__FILE__))));
335       }
336     }
338     /* Save picture */
339     if (isset($_POST['picture_edit_finish'])){
341       /* Check for clean upload */
342       if ($_FILES['picture_file']['name'] != ""){
343         if (!is_uploaded_file($_FILES['picture_file']['tmp_name'])) {
344           print_red(_("The specified file has not been uploaded via HTTP POST! Aborted."));
345         }else{
346           /* Activate new picture */
347           $this->set_picture($_FILES['picture_file']['tmp_name']);
348         }
349       }
350       $this->picture_dialog= FALSE;
351       $this->dialog= FALSE;
352       $this->is_modified= TRUE;
353     }
356     /* Cancel picture */
357     if (isset($_POST['picture_edit_cancel'])){
359       /* Restore values */
360       $this->jpegPhoto= $this->old_jpegPhoto;
361       $this->photoData= $this->old_photoData;
363       /* Update picture */
364       $_SESSION['binary']= $this->photoData;
365       $_SESSION['binarytype']= "image/jpeg";
366       $this->picture_dialog= FALSE;
367       $this->dialog= FALSE;
368     }
370     /* Toggle dateOfBirth information */
371     if (isset($_POST['set_dob'])){
372       $this->use_dob= ($this->use_dob == "0")?"1":"0";
373     }
376     /* Want certificate= */
377     if ((isset($_POST['edit_cert'])) && $this->acl_is_readable("Certificate")){
379       /* Save original values for later reconstruction */
380       foreach (array("certificateSerialNumber", "userCertificate",
381             "userSMIMECertificate", "userPKCS12") as $val){
383         $oval= "old_$val";
384         $this->$oval= $this->$val;
385       }
387       $this->cert_dialog= TRUE;
388       $this->dialog= TRUE;
389     }
392     /* Cancel certificate dialog */
393     if (isset($_POST['cert_edit_cancel'])){
395       /* Restore original values in case of 'cancel' */
396       foreach (array("certificateSerialNumber", "userCertificate",
397             "userSMIMECertificate", "userPKCS12") as $val){
399         $oval= "old_$val";
400         $this->$val= $this->$oval;
401       }
402       $this->cert_dialog= FALSE;
403       $this->dialog= FALSE;
404     }
407     /* Remove certificate? */
408     if($this->acl_is_writeable("Certificate",(!is_object($this->parent) && !isset($_SESSION['edit'])))){ 
409       foreach (array ("userCertificate", "userSMIMECertificate", "userPKCS12") as $val){
410         if (isset($_POST["remove_$val"])){
412           /* Reset specified cert*/
413           $this->$val= "";
414           $this->is_modified= TRUE;
415         }
416       }
417     }
419     /* Upload new cert and close dialog? */     
420     if($this->acl_is_writeable("Certificate",(!is_object($this->parent) && !isset($_SESSION['edit'])))){ 
421       if (isset($_POST['cert_edit_finish'])){
423         /* for all certificates do */
424         foreach (array ("userCertificate", "userSMIMECertificate", "userPKCS12")
425             as $val){
427           /* Check for clean upload */
428           if (array_key_exists($val."_file", $_FILES) &&
429               array_key_exists('name', $_FILES[$val."_file"]) &&
430               $_FILES[$val."_file"]['name'] != "" &&
431               is_uploaded_file($_FILES[$val."_file"]['tmp_name'])) {
432             $this->set_cert("$val", $_FILES[$val."_file"]['tmp_name']);
433           }
434         }
436         /* Save serial number */
437         if (isset($_POST["certificateSerialNumber"]) &&
438             $_POST["certificateSerialNumber"] != ""){
440           if (!is_id($_POST["certificateSerialNumber"])){
441             print_red (_("Please enter a valid serial number"));
443             foreach(array("userCertificate", "userSMIMECertificate", "userPKCS12") as $cert){
444               if ($this->$cert != ""){
445                 $smarty->assign("$cert"."_state", "true");
446               } else {
447                 $smarty->assign("$cert"."_state", "");
448               }
449             }
450             return ($smarty->fetch (get_template_path('generic_certs.tpl', TRUE, dirname(__FILE__))));
451           }
453           $this->certificateSerialNumber= $_POST["certificateSerialNumber"];
454           $this->is_modified= TRUE;
455         }
457         $this->cert_dialog= FALSE;
458         $this->dialog= FALSE;
459       }
460     }
461     /* Display picture dialog */
462     if ($this->picture_dialog){
463       return($smarty->fetch (get_template_path('generic_picture.tpl', TRUE, dirname(__FILE__))));
464     }
466     /* Display cert dialog */
467     if ($this->cert_dialog){
468       $smarty->assign("CertificateACL",$this->getacl("Certificate",(!is_object($this->parent) && !isset($_SESSION['edit']))));
469       $smarty->assign("Certificate_readable",$this->acl_is_readable("Certificate"));
471       foreach(array("userCertificate", "userSMIMECertificate", "userPKCS12") as $cert){
472         if ($this->$cert != ""){
473           /* import certificate */
474           $certificate = new certificate;
475           $certificate->import($this->$cert);
476       
477           /* Read out data*/
478           $timeto   = $certificate->getvalidto_date();
479           $timefrom = $certificate->getvalidfrom_date();
480          
481           
482           /* Additional info if start end time is '0' */
483           $add_str_info = "";
484           if($timeto == 0 && $timefrom == 0){
485             $add_str_info = "<br><i>"._("(Some types of certificates are currently not supported and may be displayed as 'invalid'.)")."</i>";
486           }
488           $str = "<table summary=\"\" border=0>
489                     <tr>
490                       <td style='vertical-align:top'>CN</td>
491                       <td>".preg_replace("/ /", "&nbsp;", $certificate->getname())."</td>
492                     </tr>
493                   </table><br>".
495                   sprintf(_("Certificate is valid from %s to %s and is currently %s."),
496                         "<b>".date('d M Y',$timefrom)."</b>",
497                         "<b>".date('d M Y',$timeto)."</b>",
498                         $certificate->isvalid()?"<b><font style='color:green'>"._("valid")."</font></b>":
499                                                 "<b><font style='color:red'>"._("invalid")."</font></b>").$add_str_info;
501           $smarty->assign($cert."info",$str);
502           $smarty->assign($cert."_state","true");
503         } else {
504           $smarty->assign($cert."info", "<i>"._("No certificate installed")."</i>");
505           $smarty->assign($cert."_state","");
506         }
507       }
508       $smarty->assign("governmentmode", "false");
509       return($smarty->fetch (get_template_path('generic_certs.tpl', TRUE, dirname(__FILE__))));
510     }
512     /* Prepare password hashes */
513     if ($this->pw_storage == ""){
514       $this->pw_storage= $this->config->current['HASH'];
515     }
517     $temp   = @passwordMethod::get_available_methods();
518     $hashes = $temp['name'];
519     
520     /* Load attributes and acl's */
521     $ui =get_userinfo();
522     foreach($this->attributes as $val){
523       $smarty->assign("$val", $this->$val);
524     }
526     /* Set acls */
527     $tmp = $this->plinfo();
528     foreach($tmp['plProvidedAcls'] as $val => $translation){
529       $smarty->assign("$val"."ACL", $this->getacl($val,(!is_object($this->parent) && !isset($_SESSION['edit']))));
530     }
532     $smarty->assign("pwmode", $hashes);
533     $smarty->assign("pwmode_select", $this->pw_storage);
534     $smarty->assign("passwordStorageACL", $this->getacl("userPassword",(!is_object($this->parent) && !isset($_SESSION['edit']))));
535     $smarty->assign("base_select",      $this->base);
536     $smarty->assign("CertificatesACL",  $this->getacl("Certificate",(!is_object($this->parent) && !isset($_SESSION['edit']))));
537     $smarty->assign("userPictureACL",   $this->getacl("userPicture",(!is_object($this->parent) && !isset($_SESSION['edit']))));
538     $smarty->assign("userPicture_is_readable",   $this->acl_is_readable("userPicture",(!is_object($this->parent) && !isset($_SESSION['edit']))));
540     /* Create base acls */
541     @$smarty->assign("bases", $this->allowedBasesToMoveTo());
543     /* Save government mode attributes */
544     if (isset($this->config->current['GOVERNMENTMODE']) &&
545         preg_match('/true/i', $this->config->current['GOVERNMENTMODE'])){
546       $smarty->assign("governmentmode", "true");
547       $ivbbmodes= array("nein", "ivbv", "testa", "ivbv,testa", "internet",
548           "internet,ivbv", "internet,testa", "internet,ivbv,testa");
549       $smarty->assign("ivbbmodes", $ivbbmodes);
550       foreach ($this->govattrs as $val){
551         $smarty->assign("$val", $this->$val);
552         $smarty->assign("$val"."ACL", $this->getacl($val,(!is_object($this->parent) && !isset($_SESSION['edit']))));
553       }
554     } else {
555       $smarty->assign("governmentmode", "false");
556     }
558     /* Special mode for uid */
559     $uidACL= $this->getacl("uid",(!is_object($this->parent) && !isset($_SESSION['edit'])));
560     if (isset ($this->dn)){
561       if ($this->dn != "new"){
562         $uidACL= preg_replace("/w/","",$uidACL);
563       }
564     }  else {
565       $uidACL= preg_replace("/w/","",$uidACL);
566     }
567     
568     $smarty->assign("uidACL", $uidACL);
569     $smarty->assign("is_template", $this->is_template);
570     $smarty->assign("use_dob", $this->use_dob);
572     if (isset($this->parent)){
573       if (isset($this->parent->by_object['phoneAccount']) &&
574           $this->parent->by_object['phoneAccount']->is_account){
575         $smarty->assign("has_phoneaccount", "true");
576       } else {
577         $smarty->assign("has_phoneaccount", "false");
578       }
579     } else {
580       $smarty->assign("has_phoneaccount", "false");
581     }
582     return($smarty->fetch (get_template_path('generic.tpl', TRUE, dirname(__FILE__))));
583   }
586   /* remove object from parent */
587   function remove_from_parent()
588   {
589     $ldap= $this->config->get_ldap_link();
590     $ldap->rmdir ($this->dn);
591     show_ldap_error($ldap->get_error(), sprintf(_("Removing of user/generic account with dn '%s' failed."),$this->dn));
593     /* Delete references to groups */
594     $ldap->cd ($this->config->current['BASE']);
595     $ldap->search ("(&(objectClass=posixGroup)(memberUid=".$this->uid."))", array("uid"));
596     while ($ldap->fetch()){
597       $g= new group($this->config, $ldap->getDN());
598       $g->removeUser($this->uid);
599       $g->save ();
600     }
602     /* Delete references to object groups */
603     $ldap->cd ($this->config->current['BASE']);
604     $ldap->search ("(&(objectClass=gosaGroupOfNames)(member=".$this->dn."))", array("cn"));
605     while ($ldap->fetch()){
606       $og= new ogroup($this->config, $ldap->getDN());
607       unset($og->member[$this->dn]);
608       $og->save ();
609     }
611     /* Kerberos server defined? */
612     if (isset($this->config->data['SERVERS']['KERBEROS'])){
613       $cfg= $this->config->data['SERVERS']['KERBEROS'];
614     }
615     if (isset($cfg['SERVER']) && function_exists('kadm5_init_with_password')){
617       /* Connect to the admin interface */
618       $handle = kadm5_init_with_password($cfg['SERVER'], $cfg['REALM'],
619           $cfg['ADMIN'], $cfg['PASSWORD']);
621       /* Errors? */             
622       if ($handle === FALSE){
623         print_red (_("Kerberos database communication failed"));
624         return (2);
625       }
627       /* Build user principal, get list of existsing principals */
628       $principal= $this->uid."@".$cfg['REALM'];
629       $principals = kadm5_get_principals($handle);
631       /* User exists in database? */
632       if (in_array($principal, $principals)){
634         /* Ok. User exists. Remove him/her */
635           $ret= kadm5_delete_principal ( $handle, $principal);
636           if ($ret === FALSE){
637             print_red (_("Can't remove user from kerberos database."));
638           }
639       }
641       /* Free kerberos admin handle */
642       kadm5_destroy($handle);
643     }
646     /* Optionally execute a command after we're done */
647     $this->handle_post_events("remove",array("uid" => $this->uid));
648   }
651   /* Save data to object */
652   function save_object()
653   {
654     if (isset($_POST['generic'])){
656       /* Make a backup of the current selected base */
657       $base_tmp = $this->base;
659       /* Parents save function */
660       plugin::save_object ();
662       /* Save government mode attributes */
663       if ($this->config->current['GOVERNMENTMODE']){
664         foreach ($this->govattrs as $val){
665           if ($this->acl_is_writeable($val,(!is_object($this->parent) && !isset($_SESSION['edit']))) && isset($_POST["$val"])){
666             $data= stripcslashes($_POST["$val"]);
667             if ($data != $this->$val){
668               $this->is_modified= TRUE;
669             }
670             $this->$val= $data;
671           }
672         }
673       }
675       /* In template mode, the uid is autogenerated... */
676       if ($this->is_template){
677         $this->uid= strtolower($this->sn);
678         $this->givenName= $this->sn;
679       }
681       /* Save base and pw_storage, since these are no LDAP attributes */
682       if (isset($_POST['base'])){
684         $tmp = $this->get_allowed_bases();
685         if(isset($tmp[$_POST['base']])){
686           $base= validate($_POST['base']);
687           if ($base != $this->base){
688             $this->is_modified= TRUE;
689           }
690           $this->base= $base;
691         }else{
692           $this->base = $base_tmp;
693           print_red(sprintf(_("You are not allowed to move this object to '%s'."),LDAP::fix($_POST['base'])));
694           $this->set_acl_base('dummy,'.$this->base);
695         }
696       }
698       /* Get pw_storage mode */
699       if (isset($_POST['pw_storage'])){
700         foreach(array("pw_storage") as $val){
701           if(isset($_POST[$val])){
702             $data= validate($_POST[$val]);
703             if ($data != $this->$val){
704               $this->is_modified= TRUE;
705             }
706             $this->$val= $data;
707           }
708         }
709       }
711       $this->set_acl_base('dummy,'.$this->base);
712     }
713   }
715   function rebind($ldap, $referral)
716   {
717     $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
718     if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
719       $this->error = "Success";
720       $this->hascon=true;
721       $this->reconnect= true;
722       return (0);
723     } else {
724       $this->error = "Could not bind to " . $credentials['ADMIN'];
725       return NULL;
726     }
727   }
729   /* Save data to LDAP, depending on is_account we save or delete */
730   function save()
731   {
732     /* Only force save of changes .... 
733        If this attributes aren't changed, avoid saving.
734      */
735     if($this->gender=="0") $this->gender ="";
736     if($this->preferredLanguage=="0") $this->preferredLanguage ="";
737     
738  
739     /* First use parents methods to do some basic fillup in $this->attrs */
740     plugin::save ();
742     if ($this->use_dob == "1"){
743       /* If it is an array, the generic page has never been loaded - so there's no difference. Using an array would cause an error btw. */
744       if(!is_array($this->attrs['dateOfBirth'])) {
745         $this->attrs['dateOfBirth'] = date("Y-m-d", $this->dateOfBirth);
746       }
747     }
749     /* Remove additional objectClasses */
750     $tmp= array();
751     foreach ($this->attrs['objectClass'] as $key => $set){
752       $found= false;
753       foreach (array("ivbbentry", "gosaUserTemplate") as $val){
754         if (preg_match ("/^$set$/i", $val)){
755           $found= true;
756           break;
757         }
758       }
759       if (!$found){
760         $tmp[]= $set;
761       }
762     }
764     /* Replace the objectClass array. This is done because of the
765        separation into government and normal mode. */
766     $this->attrs['objectClass']= $tmp;
768     /* Add objectClasss for template mode? */
769     if ($this->is_template){
770       $this->attrs['objectClass'][]= "gosaUserTemplate";
771     }
773     /* Hard coded government mode? */
774     if ($this->config->current['GOVERNMENTMODE'] != 'false'){
775       $this->attrs['objectClass'][]= "ivbbentry";
777       /* Copy standard attributes */
778       foreach ($this->govattrs as $val){
779         if ($this->$val != ""){
780           $this->attrs["$val"]= $this->$val;
781         } elseif (!$this->is_new) {
782           $this->attrs["$val"]= array();
783         }
784       }
786       /* Remove attribute if set to "nein" */
787       if ($this->publicVisible == "nein"){
788         $this->attrs['publicVisible']= array();
789         if($this->is_new){
790           unset($this->attrs['publicVisible']);
791         }else{
792           $this->attrs['publicVisible']=array();
793         }
795       }
797     }
799     /* Special handling for attribute userCertificate needed */
800     if ($this->userCertificate != ""){
801       $this->attrs["userCertificate;binary"]= $this->userCertificate;
802       $remove_userCertificate= false;
803     } else {
804       $remove_userCertificate= true;
805     }
807     /* Special handling for dateOfBirth value */
808     if ($this->use_dob != "1"){
809       if ($this->is_new) {
810         unset($this->attrs["dateOfBirth"]);
811       } else {
812         $this->attrs["dateOfBirth"]= array();
813       }
814     }
815     if (!$this->gender){
816       if ($this->is_new) {
817         unset($this->attrs["gender"]);
818       } else {
819         $this->attrs["gender"]= array();
820       }
821     }
822     if (!$this->preferredLanguage){
823       if ($this->is_new) {
824         unset($this->attrs["preferredLanguage"]);
825       } else {
826         $this->attrs["preferredLanguage"]= array();
827       }
828     }
830     /* Special handling for attribute jpegPhote needed, scale image via
831        image magick to 147x200 pixels and inject resulting data. */
832     if ($this->jpegPhoto == "*removed*"){
833     
834       /* Reset attribute to avoid writing *removed* as value */    
835       $this->attrs["jpegPhoto"] = array();
837     } else {
839       /* Fallback if there's no image magick inside PHP */
840       if (!function_exists("imagick_blob2image")){
841         /* Get temporary file name for conversation */
842         $fname = tempnam ("/tmp", "GOsa");
844         /* Open file and write out photoData */
845         $fp = fopen ($fname, "w");
846         fwrite ($fp, $this->photoData);
847         fclose ($fp);
849         /* Build conversation query. Filename is generated automatically, so
850            we do not need any special security checks. Exec command and save
851            output. For PHP safe mode, you'll need a configuration which respects
852            image magick as executable... */
853         $query= "convert -size 147x200 $fname -resize 147x200 +profile \"*\" -";
854         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
855             $query, "Execute");
857         /* Read data written by convert */
858         $output= "";
859         $sh= popen($query, 'r');
860         while (!feof($sh)){
861           $output.= fread($sh, 4096);
862         }
863         pclose($sh);
865         unlink($fname);
867         /* Save attribute */
868         $this->attrs["jpegPhoto"] = $output;
870       } else {
872         /* Load the new uploaded Photo */
873         if(!$handle  =  imagick_blob2image($this->photoData))  {
874           gosa_log("Can't Load image");
875         }
877         /* Resizing image to 147x200 and blur */
878         if(!imagick_resize($handle,147,200,IMAGICK_FILTER_GAUSSIAN,0)){
879           gosa_log("imagick_resize failed");
880         }
882         /* Converting image to JPEG */
883         if(!imagick_convert($handle,"JPEG")) {
884           gosa_log("Can't Convert to JPEG");
885         }
887         /* Creating binary Code for the Image */
888         if(!$dump = imagick_image2blob($handle)){
889           gosa_log("Can't create blob for image");
890         }
892         /* Sending Image */
893         $output=  $dump;
895         /* Save attribute */
896         $this->attrs["jpegPhoto"] = $output;
897       }
899     }
901     /* This only gets called when user is renaming himself */
902     $ldap= $this->config->get_ldap_link();
903     if ($this->dn != $this->new_dn){
905       /* Write entry on new 'dn' */
906       $this->update_acls($this->dn,$this->new_dn);
907       $this->move($this->dn, $this->new_dn);
909       /* Happen to use the new one */
910       change_ui_dn($this->dn, $this->new_dn);
911       $this->dn= $this->new_dn;
912     }
915     /* Save data. Using 'modify' implies that the entry is already present, use 'add' for
916        new entries. So do a check first... */
917     $ldap->cat ($this->dn, array('dn'));
918     if ($ldap->fetch()){
919       $mode= "modify";
920     } else {
921       $mode= "add";
922       $ldap->cd($this->config->current['BASE']);
923       $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
924     }
926     /* Set password to some junk stuff in case of templates */
927     if ($this->is_template){
928       $this->attrs['userPassword']= '{crypt}N0T$3T4N0W';
929     }
931     @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
932         $this->attributes, "Save via $mode");
934     /* Finally write data with selected 'mode' */
935     $this->cleanup();
936     $ldap->cd ($this->dn);
937     $ldap->$mode ($this->attrs);
938     if (show_ldap_error($ldap->get_error(), sprintf(_("Saving of user/generic account with dn '%s' failed."),$this->dn))){
939       return (1);
940     }
942     /* Remove cert? 
943        For some reason, the 'ldap' class doesn't want to remove binary entries, so I need
944        to work around myself. */
945     if ($remove_userCertificate == true && !$this->is_new && $this->had_userCertificate){
947       /* Reset array, assemble new, this should be reworked */
948       $this->attrs= array();
949       $this->attrs['userCertificate;binary']= array();
951       /* Prepare connection */
952       if (!($ds = ldap_connect($this->config->current['SERVER']))) {
953         die ("Could not connect to LDAP server");
954       }
955       ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
956       if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['RECURSIVE']) && $this->config->current['RECURSIVE'] == "true") {
957         ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
958         ldap_set_rebind_proc($ds, array(&$this, "rebind"));
959       }
960       if(isset($config->current['TLS']) && $config->current['TLS'] == "true"){
961         ldap_start_tls($ds);
962       }
963       if (!($res = @ldap_bind($ds, $this->config->current['ADMIN'],
964               $this->config->current['PASSWORD']))) {
965         die ("Could not bind to LDAP");
966       }
968       /* Modify using attrs */
969       ldap_mod_del($ds,$this->dn,$this->attrs);
970       ldap_close($ds);
971     }
973     /* Kerberos server defined? */
974     if (isset($this->config->data['SERVERS']['KERBEROS'])){
975       $cfg= $this->config->data['SERVERS']['KERBEROS'];
976     }
977     if (isset($cfg['SERVER']) && function_exists('kadm5_init_with_password')){
979       /* Connect to the admin interface */
980       $handle = kadm5_init_with_password($cfg['SERVER'], $cfg['REALM'],
981           $cfg['ADMIN'], $cfg['PASSWORD']);
983       /* Errors? */             
984       if ($handle === FALSE){
985         print_red (_("Kerberos database communication failed"));
986         return (2);
987       }
989       /* Build user principal, get list of existsing principals */
990       $principal= $this->uid."@".$cfg['REALM'];
991       $principals = kadm5_get_principals($handle);
993       /* User exists in database? */
994       if (in_array($principal, $principals)){
996         /* Ok. User exists. Remove him/her when pw_storage has
997            changed to be NOT kerberos. */
998         if ($this->pw_storage != $this->config->current['KRBSASL']){
999           $ret= kadm5_delete_principal ( $handle, $principal);
1001           if ($ret === FALSE){
1002             print_red (_("Can't remove user from kerberos database."));
1003           }
1004         }
1006       } else {
1008         /* User doesn't exists, create it when pw_storage is kerberos. */
1009         if ($this->pw_storage == "kerberos" || $this->pw_storage == "sasl" ){
1010           $ret= kadm5_create_principal ( $handle, $principal);
1012           if ($ret === FALSE){
1013             print_red (_("Can't add user to kerberos database."));
1014           }
1015         }
1017       }
1019       /* Free kerberos admin handle */
1020       kadm5_destroy($handle);
1021     }
1023     /* Optionally execute a command after we're done */
1024     if ($mode == "add"){
1025       $this->handle_post_events("add", array("uid" => $this->uid));
1026     } elseif ($this->is_modified){
1027       $this->handle_post_events("modify", array("uid" => $this->uid));
1028     }
1030     /* Fix tagging if needed */
1031     $this->handle_object_tagging();
1033     return (0);
1034   }
1037   /* Check formular input */
1038   function check()
1039   {
1040     /* Call common method to give check the hook */
1041     $message= plugin::check();
1043     $pt= "";
1044     if(isset($this->config->current['INCLUDE_PERSONAL_TITLE']) && preg_match("/true/i",$this->config->current['INCLUDE_PERSONAL_TITLE'])){
1045       if(!empty($this->personalTitle)){
1046         $pt = $this->personalTitle." ";
1047       }
1048      }
1049     $this->cn= $pt.$this->givenName." ".$this->sn;
1051     /* Permissions for that base? */
1052     if (isset($this->config->current['DNMODE']) && $this->config->current['DNMODE'] == "uid"){
1053       $this->new_dn= 'uid='.$this->uid.','.get_people_ou().$this->base;
1054     } else {
1055       /* Don't touch dn, if cn hasn't changed */
1056       if (isset($this->saved_attributes['cn']) && $this->saved_attributes['cn'] == $this->cn &&
1057           $this->orig_base == $this->base ){
1058         $this->new_dn= $this->dn;
1059       } else {
1060         $this->new_dn= $this->create_unique_dn('cn', get_people_ou().$this->base);
1061       }
1062     }
1064     /* Set the new acl base */
1065     if($this->dn == "new") {
1066       $this->set_acl_base($this->base);
1067     }
1069     /* must: sn, givenName, uid */
1070     if ($this->sn == "" && ($this->acl_is_writeable("sn",(!is_object($this->parent) && !isset($_SESSION['edit'])) || ($this->is_new)))){
1071       $message[]= _("The required field 'Name' is not set.");
1072     }
1074     /* UID already used? */
1075     $ldap= $this->config->get_ldap_link();
1076     $ldap->cd($this->config->current['BASE']);
1077     $ldap->search("(uid=$this->uid)", array("uid"));
1078     $ldap->fetch();
1079     if ($ldap->count() != 0 && $this->dn == 'new'){
1080       $message[]= _("There's already a person with this 'Login' in the database.");
1081     }
1083     /* In template mode, the uid and givenName are autogenerated... */
1084     if (!$this->is_template){
1085       if ($this->givenName == "" && $this->acl_is_writeable("givenName",(!is_object($this->parent) && !isset($_SESSION['edit'])))){
1086         $message[]= _("The required field 'Given name' is not set.");
1087       }
1088       if ($this->uid == "" && $this->acl_is_writeable("uid",(!is_object($this->parent) && !isset($_SESSION['edit'])))){
1089         $message[]= _("The required field 'Login' is not set.");
1090       }
1091       if (!(isset($this->config->current['DNMODE']) && $this->config->current['DNMODE'] == "uid")){
1092         $ldap->cat($this->new_dn);
1093         if ($ldap->count() != 0 && $this->dn != $this->new_dn && $this->dn == 'new'){
1094           $message[]= _("There's already a person with this 'Name'/'Given name' combination in the database.");
1095         }
1096       }
1097     }
1099     /* Check for valid input */
1100     if ($this->is_modified && !is_uid($this->uid)){
1101       $message[]= _("The field 'Login' contains invalid characters. Lowercase, numbers and dashes are allowed.");
1102     }
1103     if (!is_url($this->labeledURI)){
1104       $message[]= _("The field 'Homepage' contains an invalid URL definition.");
1105     }
1106     if (preg_match ("/[\\\\]/", $this->sn)){
1107       $message[]= _("The field 'Name' contains invalid characters.");
1108     }
1109     if (preg_match ("/[\\\\]/", $this->givenName)){
1110       $message[]= _("The field 'Given name' contains invalid characters.");
1111     }
1113     /* Check phone numbers */
1114     if (!is_phone_nr($this->telephoneNumber)){
1115       $message[]= _("The field 'Phone' contains an invalid phone number.");
1116     }
1117     if (!is_phone_nr($this->facsimileTelephoneNumber)){
1118       $message[]= _("The field 'Fax' contains an invalid phone number.");
1119     }
1120     if (!is_phone_nr($this->mobile)){
1121       $message[]= _("The field 'Mobile' contains an invalid phone number.");
1122     }
1123     if (!is_phone_nr($this->pager)){
1124       $message[]= _("The field 'Pager' contains an invalid phone number.");
1125     }
1127     /* Check for reserved characers */
1128     if (preg_match ('/[,+"?\'()=<>;]/', $this->givenName)){
1129       $message[]= _("The field 'Given name' contains invalid characters.");
1130     }
1131     if (preg_match ('/[,+"?\'()=<>;]/', $this->sn)){
1132       $message[]= _("The field 'Name' contains invalid characters.");
1133     }
1135   return $message;
1136   }
1139   /* Indicate whether a password change is needed or not */
1140   function password_change_needed()
1141   {
1142     return ($this->pw_storage != $this->last_pw_storage);
1143   }
1146   /* Load a jpegPhoto from LDAP, this is going to be simplified later on */
1147   function load_picture()
1148   {
1149     $ldap = $this->config->get_ldap_link();
1150     $ldap->cd ($this->dn);
1151     $data = $ldap->get_attribute($this->dn,"jpegPhoto");
1152       
1153     if((!$data) || ($data == "*removed*")){ 
1155       /* In case we don't get an entry, load a default picture */
1156       $this->set_picture ();//"./images/default.jpg");
1157       $this->jpegPhoto= "*removed*";
1158     }else{
1160       /* Set picture */
1161       $this->photoData= $data;
1162       $_SESSION['binary']= $this->photoData;
1163       $_SESSION['binarytype']= "image/jpeg";
1164       $this->jpegPhoto= "";
1165     }
1166   }
1169   /* Load a certificate from LDAP, this is going to be simplified later on */
1170   function load_cert()
1171   {
1172     $ds= ldap_connect($this->config->current['SERVER']);
1173     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1174     if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['RECURSIVE']) && $this->config->current['RECURSIVE'] == "true") {
1175       ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
1176       ldap_set_rebind_proc($ds, array(&$this, "rebind"));
1177     }
1178     if(isset($this->config->current['TLS']) &&
1179         $this->config->current['TLS'] == "true"){
1181       ldap_start_tls($ds);
1182     }
1184     $r= ldap_bind($ds);
1185     $sr= @ldap_read($ds, $this->dn, "userCertificate=*", array("userCertificate"));
1187     if ($sr) {
1188       $ei= @ldap_first_entry($ds, $sr);
1189       
1190       if ($ei) {
1191         if (!$info = @ldap_get_values_len($ds, $ei, "userCertificate;binary")){
1192           $this->userCertificate= "";
1193         } else {
1194           $this->userCertificate= $info[0];
1195         }
1196       }
1197     } else {
1198       $this->userCertificate= "";
1199     }
1201     ldap_unbind($ds);
1202   }
1205   /* Load picture from file to object */
1206   function set_picture($filename ="")
1207   {
1208     if (!is_file($filename) || $filename =="" ){
1209       $filename= "./images/default.jpg";
1210       $this->jpegPhoto= "*removed*";
1211     }
1213     $fd = fopen ($filename, "rb");
1214     $this->photoData= fread ($fd, filesize ($filename));
1215     $_SESSION['binary']= $this->photoData;
1216     $_SESSION['binarytype']= "image/jpeg";
1217     $this->jpegPhoto= "";
1219     fclose ($fd);
1220   }
1223   /* Load certificate from file to object */
1224   function set_cert($cert, $filename)
1225   {
1226     if(!$thsi->acl_is_writeable("Certificate",(!is_object($this->parent) && !isset($_SESSION['edit'])))) return;
1227     $fd = fopen ($filename, "rb");
1228     if (filesize($filename)>0) {
1229       $this->$cert= fread ($fd, filesize ($filename));
1230       fclose ($fd);
1231       $this->is_modified= TRUE;
1232     } else {
1233       print_red(_("Could not open specified certificate!"));
1234     }
1235   }
1237   /* Adapt from given 'dn' */
1238   function adapt_from_template($dn)
1239   {
1240     plugin::adapt_from_template($dn);
1242     /* Get base */
1243     $this->base= preg_replace('/^[^,]+,'.get_people_ou().'/i', '', $dn);
1245     if ($this->config->current['GOVERNMENTMODE']){
1247       /* Walk through govattrs */
1248       foreach ($this->govattrs as $val){
1250         if (isset($this->attrs["$val"][0])){
1252           /* If attribute is set, replace dynamic parts: 
1253              %sn, %givenName and %uid. Fill these in our local variables. */
1254           $value= $this->attrs["$val"][0];
1256           foreach (array("sn", "givenName", "uid") as $repl){
1257             if (preg_match("/%$repl/i", $value)){
1258               $value= preg_replace ("/%$repl/i",
1259                   $this->parent->$repl, $value);
1260             }
1261           }
1262           $this->$val= $value;
1263         }
1264       }
1265     }
1267     /* Get back uid/sn/givenName */
1268     if ($this->parent != NULL){
1269       $this->uid= $this->parent->uid;
1270       $this->sn= $this->parent->sn;
1271       $this->givenName= $this->parent->givenName;
1272     }
1273   }
1275  
1276   /* This avoids that users move themselves out of their rights. 
1277    */
1278   function allowedBasesToMoveTo()
1279   {
1280     /* Get bases */
1281     $bases  = $this->get_allowed_bases();
1282     return($bases);
1283   } 
1286   function getCopyDialog()
1287   {
1288     $str = "";
1290     $_SESSION['binary'] = $this->photoData; 
1291     $_SESSION['binarytype']= "image/jpeg";
1293     /* Get random number for pictures */
1294     srand((double)microtime()*1000000); 
1295     $rand = rand(0, 10000);
1297     $smarty = get_smarty();
1299     $smarty->assign("passwordTodo","clear");
1301     if(isset($_POST['passwordTodo'])){
1302       $smarty->assign("passwordTodo",$_POST['passwordTodo']);
1303     }
1305     $smarty->assign("sn",       $this->sn);
1306     $smarty->assign("givenName",$this->givenName);
1307     $smarty->assign("uid",      $this->uid);
1308     $smarty->assign("rand",     $rand);
1309     $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE,dirname(__FILE__)));
1312     $ret = array();
1313     $ret['string'] = $str;
1314     $ret['status'] = "";  
1315     return($ret);
1316   }
1318   function saveCopyDialog()
1319   {
1320     /* Set_acl_base */
1321     $this->set_acl_base("cn=dummy,".get_people_ou().$this->base);
1323     if((isset($_FILES['picture_file']['tmp_name'])) && ($_FILES['picture_file']['size'] > 0)){
1324       $this->set_picture($_FILES['picture_file']['tmp_name']);
1325     }
1327     /* Remove picture? */
1328     if (isset($_POST['picture_remove'])){
1329       $this->jpegPhoto= "*removed*";
1330       $this->set_picture ("./images/default.jpg");
1331       $this->is_modified= TRUE;
1332     }
1334     $attrs = array("uid","givenName","sn");
1335     foreach($attrs as $attr){
1336       if(isset($_POST[$attr])){
1337         $this->$attr = $_POST[$attr];
1338       }
1339     } 
1340   }
1343   function PrepareForCopyPaste($source)
1344   {
1345     plugin::PrepareForCopyPaste($source);
1347     /* Reset certificate information addepted from source user
1348        to avoid setting the same user certificate for the destination user. */
1349     $this->userPKCS12= "";
1350     $this->userSMIMECertificate= "";
1351     $this->userCertificate= "";
1352     $this->certificateSerialNumber= "";
1353     $this->old_certificateSerialNumber= "";
1354     $this->old_userPKCS12= "";
1355     $this->old_userSMIMECertificate= "";
1356     $this->old_userCertificate= "";
1357   }
1360   function plInfo()
1361   {
1362   
1363     $govattrs= array(
1364         "gouvernmentOrganizationalUnit"             =>  _("Unit"), 
1365         "houseIdentifier"                           =>  _("House identifier"), 
1366         "vocation"                                  =>  _("Vocation"),
1367         "ivbbLastDeliveryCollective"                =>  _("Last delivery"), 
1368         "gouvernmentOrganizationalPersonLocality"   =>  _("Person locality"),
1369         "gouvernmentOrganizationalUnitDescription"  =>  _("Unit description"),
1370         "gouvernmentOrganizationalUnitSubjectArea"  =>  _("Subject area"),
1371         "functionalTitle"                           =>  _("Functional title"),
1372         "certificateSerialNumber"                   =>  _(""),
1373         "publicVisible"                             =>  _("Public visible"),
1374         "street"                                    =>  _("Street"),
1375         "role"                                      =>  _("Role"),
1376         "postalCode"                                =>  _("Postal code"));
1378     $ret = array(
1379         "plShortName" => _("Generic"),
1380         "plDescription" => _("Generic user settings"),
1381         "plSelfModify"  => TRUE,
1382         "plDepends"     => array(),
1383         "plPriority"    => 1,
1384         "plSection"     => array("personal" => _("My account")),
1385         "plCategory"    => array("users" => array("description" => _("Users"),
1386                                                   "objectClass" => "gosaAccount")),
1388         "plProvidedAcls" => array(
1389           "base"              => _("Base"), 
1390           "userPassword"      => _("User password"), 
1391           "sn"                => _("Surename"),
1392           "givenName"         => _("Given name"),
1393           "uid"               => _("User identification"),
1394           "personalTitle"     => _("Personal title"),
1395           "academicTitle"     => _("Academic title"),
1396           "homePostalAddress" => _("Home postal address"),
1397           "homePhone"         => _("Home phone number"),
1398           "labeledURI"        => _("Homepage"),
1399           "o"                 => _("Organization"),
1400           "ou"                => _("Department"),
1401           "dateOfBirth"       => _("Date of birth"),
1402           "gender"            => _("Gender"),
1403           "preferredLanguage" => _("Preferred language"),
1404           "departmentNumber"  => _("Department number"),
1405           "employeeNumber"    => _("Employee number"),
1406           "employeeType"      => _("Employee type"),
1407           "l"                 => _("Location"),
1408           "st"                => _("State"),
1409           "userPicture"       => _("User picture"),
1410           "roomNumber"        => _("Room number"),
1411           "telephoneNumber"   => _("Telefon number"),
1412           "mobile"            => _("Mobile number"),
1413           "pager"             => _("Pager number"),
1414           "Certificate"        => _("User certificates"),
1416           "postalAddress"                => _("Postal address"),
1417           "facsimileTelephoneNumber"     => _("Fax number"))
1418         );
1420     /* Append government attributes if required */
1421       global $config;
1422     if (isset($config->current['GOVERNMENTMODE']) &&  preg_match('/true/i', $config->current['GOVERNMENTMODE'])){
1423       foreach($govattrs as $attr => $desc){
1424         $ret["plProvidedAcls"][$attr] = $desc;
1425       }
1426     }
1428     return($ret);
1429   }
1432 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1433 ?>