password back-end database support
[ira/wip.git] / source3 / passdb / ldap.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    LDAP protocol helper functions for SAMBA
5    Copyright (C) Jean François Micouleau 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #ifdef USE_LDAP
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 /*******************************************************************
30  open a connection to the ldap serve.
31 ******************************************************************/     
32 BOOL ldap_open_connection(LDAP **ldap_struct)
33 {
34         if ( (*ldap_struct = ldap_open(lp_ldap_server(),lp_ldap_port()) )== NULL)
35         {
36                 DEBUG(0,("%s: The LDAP server is not responding !\n",timestring()));
37                 return(False);
38         }
39         DEBUG(2,("ldap_open_connection: connection opened\n"));
40         return (True);
41 }
42
43
44 /*******************************************************************
45  connect anonymously to the ldap server.
46  FIXME: later (jfm)
47 ******************************************************************/     
48 static BOOL ldap_connect_anonymous(LDAP *ldap_struct)
49 {
50         if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
51         {
52                 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
53                 return(False);
54         }
55         return (True);
56 }
57
58
59 /*******************************************************************
60  connect to the ldap server under system privileg.
61 ******************************************************************/     
62 BOOL ldap_connect_system(LDAP *ldap_struct)
63 {
64         if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
65         {
66                 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
67                 return(False);
68         }
69         DEBUG(2,("ldap_connect_system: succesfull connection to the LDAP server\n"));
70         return (True);
71 }
72
73 /*******************************************************************
74  connect to the ldap server under a particular user.
75 ******************************************************************/     
76 static BOOL ldap_connect_user(LDAP *ldap_struct, char *user, char *password)
77 {
78         if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
79         {
80                 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
81                 return(False);
82         }
83         DEBUG(2,("ldap_connect_user: succesfull connection to the LDAP server\n"));
84         return (True);
85 }
86
87 /*******************************************************************
88  run the search by name.
89 ******************************************************************/     
90 static BOOL ldap_search_one_user(LDAP *ldap_struct, char *filter, LDAPMessage **result)
91 {       
92         int scope = LDAP_SCOPE_ONELEVEL;
93         int rc;
94                 
95         DEBUG(2,("ldap_search_one_user: searching for:[%s]\n", filter));
96                 
97         rc=ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, result);
98
99         if (rc != LDAP_SUCCESS )
100         {
101                 DEBUG(0,("%s: Problem during the LDAP search\n",timestring()));
102                 return(False);
103         }
104         return (True);
105 }
106
107 /*******************************************************************
108  run the search by name.
109 ******************************************************************/     
110 BOOL ldap_search_one_user_by_name(LDAP *ldap_struct, char *user, LDAPMessage **result)
111 {       
112         pstring filter;
113         /*
114            in the filter expression, replace %u with the real name
115            so in ldap filter, %u MUST exist :-)
116         */      
117         strcpy(filter,lp_ldap_filter());
118         string_sub(filter,"%u",user);
119         
120         if ( !ldap_search_one_user(ldap_struct, filter, result) )
121         {
122                 return(False);
123         }
124         return (True);
125 }
126
127 /*******************************************************************
128  run the search by uid.
129 ******************************************************************/     
130 BOOL ldap_search_one_user_by_uid(LDAP *ldap_struct, int uid, LDAPMessage **result)
131 {       
132         pstring filter;
133         /*
134            in the filter expression, replace %u with the real name
135            so in ldap filter, %u MUST exist :-)
136         */
137         snprintf(filter, sizeof(pstring), "uidAccount=%d", uid);
138         
139         if ( !ldap_search_one_user(ldap_struct, filter, result) )
140         {       
141                 return(False);
142         }
143         return (True);
144 }
145
146 /*******************************************************************
147  search an attribute and return the first value found.
148 ******************************************************************/
149 void get_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, char *attribute, char *value)
150 {
151         char **valeurs;
152         
153         if ( (valeurs=ldap_get_values(ldap_struct, entry, attribute)) != NULL) 
154         {
155                 strcpy(value, valeurs[0]);
156                 ldap_value_free(valeurs);
157                 DEBUG(3,("get_single_attribute: [%s]=[%s]\n", attribute, value));       
158         }
159         else
160         {
161                 value=NULL;
162         }
163 }
164
165 /*******************************************************************
166  check if the returned entry is a sambaAccount objectclass.
167 ******************************************************************/     
168 BOOL ldap_check_user(LDAP *ldap_struct, LDAPMessage *entry)
169 {
170         BOOL sambaAccount=False;
171         char **valeur;
172         int i;
173
174         DEBUG(2,("ldap_check_user: "));
175         valeur=ldap_get_values(ldap_struct, entry, "objectclass");
176         if (valeur!=NULL)
177         {
178                 for (i=0;valeur[i]!=NULL;i++)
179                 {
180                         if (!strcmp(valeur[i],"sambaAccount")) sambaAccount=True;
181                 }
182         }
183         DEBUG(2,("%s\n",sambaAccount?"yes":"no"));
184         ldap_value_free(valeur);
185         return (sambaAccount);
186 }
187
188 /*******************************************************************
189  check if the returned entry is a sambaMachine objectclass.
190 ******************************************************************/     
191 BOOL ldap_check_trust(LDAP *ldap_struct, LDAPMessage *entry)
192 {
193         BOOL sambaMachine=False;
194         char **valeur;
195         int i;
196         
197         DEBUG(2,("ldap_check_trust: "));
198         valeur=ldap_get_values(ldap_struct, entry, "objectclass");
199         if (valeur!=NULL)
200         {
201                 for (i=0;valeur[i]!=NULL;i++)
202                 {
203                         if (!strcmp(valeur[i],"sambaMachine")) sambaMachine=True;
204                 }
205         }       
206         DEBUG(2,("%s\n",sambaMachine?"yes":"no"));
207         ldap_value_free(valeur);        
208         return (sambaMachine);
209 }
210
211 /*******************************************************************
212  retrieve the user's info and contruct a smb_passwd structure.
213 ******************************************************************/
214 static void ldap_get_sam_passwd(LDAP *ldap_struct, LDAPMessage *entry, 
215                           struct sam_passwd *user)
216 {       
217         static pstring user_name;
218         static pstring fullname;
219         static pstring home_dir;
220         static pstring dir_drive;
221         static pstring logon_script;
222         static pstring profile_path;
223         static pstring acct_desc;
224         static pstring workstations;
225         static pstring temp;
226         
227         bzero(user, sizeof(*user));
228
229         user->logon_time            = (time_t)-1;
230         user->logoff_time           = (time_t)-1;
231         user->kickoff_time          = (time_t)-1;
232         user->pass_last_set_time    = (time_t)-1;
233         user->pass_can_change_time  = (time_t)-1;
234         user->pass_must_change_time = (time_t)-1;
235
236         get_single_attribute(ldap_struct, entry, "logonTime", temp);
237         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
238
239         get_single_attribute(ldap_struct, entry, "logoffTime", temp);
240         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
241
242         get_single_attribute(ldap_struct, entry, "kickoffTime", temp);
243         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
244
245         get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
246         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
247
248         get_single_attribute(ldap_struct, entry, "pwdCanChange", temp);
249         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
250
251         get_single_attribute(ldap_struct, entry, "pwdMustChange", temp);
252         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
253
254         get_single_attribute(ldap_struct, entry, "cn", user_name);
255         user->smb_name = user_name;
256
257         DEBUG(2,("ldap_get_sam_passwd: user: %s\n", user_name));
258                 
259         get_single_attribute(ldap_struct, entry, "userFullName", fullname);
260         user->full_name = fullname;
261
262         get_single_attribute(ldap_struct, entry, "homeDirectory", home_dir);
263         user->home_dir = home_dir;
264
265         get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive);
266         user->dir_drive = dir_drive;
267
268         get_single_attribute(ldap_struct, entry, "scriptPath", logon_script);
269         user->logon_script = logon_script;
270
271         get_single_attribute(ldap_struct, entry, "profilePath", profile_path);
272         user->profile_path = profile_path;
273
274         get_single_attribute(ldap_struct, entry, "comment", acct_desc);
275         user->acct_desc = acct_desc;
276
277         get_single_attribute(ldap_struct, entry, "userWorkstations", workstations);
278         user->workstations = workstations;
279
280         
281         user->unknown_str = NULL; /* don't know, yet! */
282         user->munged_dial = NULL; /* "munged" dial-back telephone number */
283
284         get_single_attribute(ldap_struct, entry, "userPassword", temp);
285         nt_lm_owf_gen(temp, user->smb_nt_passwd, user->smb_passwd);
286         bzero(temp, sizeof(temp)); /* destroy local copy of the password */
287                         
288         get_single_attribute(ldap_struct, entry, "rid", temp);
289         user->user_rid=atoi(temp);
290
291         get_single_attribute(ldap_struct, entry, "primaryGroupID", temp);
292         user->group_rid=atoi(temp);
293
294         /* the smb (unix) ids are not stored: they are created */
295         user->smb_userid = user_rid_to_uid (user->user_rid);
296         user->smb_grpid  = group_rid_to_uid(user->group_rid);
297
298         get_single_attribute(ldap_struct, entry, "userAccountControl", temp);
299         user->acct_ctrl=atoi(temp);
300
301         user->unknown_3 = 0xffffff; /* don't know */
302         user->logon_divs = 168; /* hours per week */
303         user->hours_len = 21; /* 21 times 8 bits = 168 */
304         memset(user->hours, 0xff, user->hours_len); /* available at all hours */
305         user->unknown_5 = 0x00020000; /* don't know */
306         user->unknown_5 = 0x000004ec; /* don't know */
307
308         if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
309         {
310                 DEBUG(0,("Inconsistency in the LDAP database\n"));
311         }
312
313         if (!(user->acct_ctrl & ACB_NORMAL))
314         {
315                 DEBUG(0,("User's acct_ctrl bits not set to ACT_NORMAL in LDAP database\n"));
316                 return;
317         }
318
319 }
320
321 /*******************************************************************
322  retrieve the user's info and contruct a smb_passwd structure.
323 ******************************************************************/
324 static void ldap_get_smb_passwd(LDAP *ldap_struct,LDAPMessage *entry, 
325                           struct smb_passwd *user)
326 {       
327         static pstring user_name;
328         static pstring user_pass;
329         static pstring temp;
330         static unsigned char smblmpwd[16];
331         static unsigned char smbntpwd[16];
332
333         user->smb_name = NULL;
334         user->smb_passwd = NULL;
335         user->smb_nt_passwd = NULL;
336         user->smb_userid = 0;
337         user->pass_last_set_time    = (time_t)-1;
338
339         get_single_attribute(ldap_struct, entry, "cn", user_name);
340         DEBUG(2,("ldap_get_smb_passwd: user: %s\n",user_name));
341                 
342         get_single_attribute(ldap_struct, entry, "userPassword", user_pass);
343         nt_lm_owf_gen(user_pass, smbntpwd, smblmpwd);
344         bzero(user_pass, sizeof(user_pass)); /* destroy local copy of the password */
345                         
346         get_single_attribute(ldap_struct, entry, "userAccountControl", temp);
347         user->acct_ctrl=decode_acct_ctrl(temp);
348
349         get_single_attribute(ldap_struct, entry, "pwdLastSet", temp);
350         user->pass_last_set_time = (time_t)strtol(temp, NULL, 16);
351
352         get_single_attribute(ldap_struct, entry, "rid", temp);
353
354         /* the smb (unix) ids are not stored: they are created */
355         user->smb_userid = user_rid_to_uid (atoi(temp));
356
357         if (user->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
358         {
359                 DEBUG(0,("Inconsistency in the LDAP database\n"));
360                          
361         }
362         if (user->acct_ctrl & ACB_NORMAL)
363         {
364                 user->smb_name      = user_name;
365                 user->smb_passwd    = smblmpwd;
366                 user->smb_nt_passwd = smbntpwd;
367         }
368 }
369
370 /*******************************************************************
371  retrieve the trust's info and contruct a smb_passwd structure.
372 ******************************************************************/
373 static void ldap_get_trust(LDAP *ldap_struct,LDAPMessage *entry, 
374                              struct smb_passwd *trust)
375 {       
376         static pstring  user_name;
377         static unsigned char smbntpwd[16];
378         static pstring temp;
379         
380         get_single_attribute(ldap_struct, entry, "cn", user_name);
381         DEBUG(2,("ldap_get_trust: trust: %s\n", user_name));
382                 
383         get_single_attribute(ldap_struct, entry, "trustPassword", temp);
384         gethexpwd(temp,smbntpwd);               
385                         
386         get_single_attribute(ldap_struct, entry, "rid", temp);
387
388         /* the smb (unix) ids are not stored: they are created */
389         trust->smb_userid = user_rid_to_uid(atoi(temp));
390
391         get_single_attribute(ldap_struct, entry, "trustAccountControl", temp);
392         trust->acct_ctrl=decode_acct_ctrl(temp);
393
394         if (trust->acct_ctrl == 0)
395         {
396                 /* by default it's a workstation (or stand-alone server) */
397                 trust->acct_ctrl = ACB_WSTRUST;
398         }
399
400         trust->smb_name      = user_name;
401         trust->smb_passwd    = NULL;
402         trust->smb_nt_passwd = smbntpwd;
403 }
404
405 /************************************************************************
406  Routine to add an entry to the ldap passwd file.
407
408  do not call this function directly.  use passdb.c instead.
409
410 *************************************************************************/
411 BOOL add_ldappwd_entry(struct smb_passwd *newpwd)
412 {
413   return True;
414 }
415
416 /************************************************************************
417  Routine to search the ldap passwd file for an entry matching the username.
418  and then modify its password entry. We can't use the startldappwent()/
419  getldappwent()/endldappwent() interfaces here as we depend on looking
420  in the actual file to decide how much room we have to write data.
421  override = False, normal
422  override = True, override XXXXXXXX'd out password or NO PASS
423
424  do not call this function directly.  use passdb.c instead.
425
426 ************************************************************************/
427 BOOL mod_ldappwd_entry(struct smb_passwd* pwd, BOOL override)
428 {
429     return False;
430 }
431
432 /***************************************************************
433  Start to enumerate the ldap passwd list. Returns a void pointer
434  to ensure no modification outside this module.
435
436  do not call this function directly.  use passdb.c instead.
437
438  ****************************************************************/
439
440 struct ldap_enum_info
441 {
442         LDAP *ldap_struct;
443         LDAPMessage *result;
444         LDAPMessage *entry;
445 };
446
447 static struct ldap_enum_info ldap_ent;
448
449 void *startldappwent(BOOL update)
450 {
451         int scope = LDAP_SCOPE_ONELEVEL;
452         int rc;
453
454         char filter[256];
455
456         if (!ldap_open_connection(&ldap_ent.ldap_struct)) /* open a connection to the server */
457                 return NULL;
458
459         if (!ldap_connect_system(ldap_ent.ldap_struct)) /* connect as system account */
460                 return NULL;
461
462         /* when the class is known the search is much faster */
463         switch (0)
464         {
465                 case 1:
466                 {
467                         strcpy(filter, "objectclass=sambaAccount");
468                         break;
469                 }
470                 case 2:
471                 {
472                         strcpy(filter, "objectclass=sambaMachine");
473                         break;
474                 }
475                 default:
476                 {
477                         strcpy(filter, "(|(objectclass=sambaMachine)(objectclass=sambaAccount))");
478                         break;
479                 }
480         }
481
482         rc=ldap_search_s(ldap_ent.ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, &ldap_ent.result);
483
484         DEBUG(2,("%d entries in the base!\n", ldap_count_entries(ldap_ent.ldap_struct, ldap_ent.result) ));
485
486         ldap_ent.entry = ldap_first_entry(ldap_ent.ldap_struct, ldap_ent.result);
487
488         return &ldap_ent;
489 }
490
491 /*************************************************************************
492  Routine to return the next entry in the ldap passwd list.
493
494  do not call this function directly.  use passdb.c instead.
495
496  *************************************************************************/
497 struct smb_passwd *getldappwent(void *vp)
498 {
499         static struct smb_passwd user;
500         struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
501
502         ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
503
504         if (ldap_vp->entry != NULL)
505         {
506                 ldap_get_smb_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
507                 return &user;
508         }
509         return NULL;
510 }
511
512 /*************************************************************************
513  Routine to return the next entry in the ldap passwd list.
514
515  do not call this function directly.  use passdb.c instead.
516
517  *************************************************************************/
518 struct sam_passwd *getldap21pwent(void *vp)
519 {
520         static struct sam_passwd user;
521         struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
522
523         ldap_vp->entry = ldap_next_entry(ldap_vp->ldap_struct, ldap_vp->entry);
524
525         if (ldap_vp->entry != NULL)
526         {
527                 ldap_get_sam_passwd(ldap_vp->ldap_struct, ldap_vp->entry, &user);
528                 return &user;
529         }
530         return NULL;
531 }
532
533 /***************************************************************
534  End enumeration of the ldap passwd list.
535
536  do not call this function directly.  use passdb.c instead.
537
538 ****************************************************************/
539 void endldappwent(void *vp)
540 {
541         struct ldap_enum_info *ldap_vp = (struct ldap_enum_info *)vp;
542         ldap_msgfree(ldap_vp->result);
543         ldap_unbind(ldap_vp->ldap_struct);
544 }
545
546 /*************************************************************************
547  Return the current position in the ldap passwd list as an unsigned long.
548  This must be treated as an opaque token.
549
550  do not call this function directly.  use passdb.c instead.
551
552 *************************************************************************/
553 unsigned long getldappwpos(void *vp)
554 {
555         return 0;
556 }
557
558 /*************************************************************************
559  Set the current position in the ldap passwd list from unsigned long.
560  This must be treated as an opaque token.
561
562  do not call this function directly.  use passdb.c instead.
563
564 *************************************************************************/
565 BOOL setldappwpos(void *vp, unsigned long tok)
566 {
567         return False;
568 }
569
570 #endif