2 Unix SMB/Netbios implementation.
4 LDAP protocol helper functions for SAMBA
5 Copyright (C) Jean François Micouleau 1998
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.
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.
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.
29 extern int DEBUGLEVEL;
31 /*******************************************************************
32 open a connection to the ldap serve.
33 ******************************************************************/
34 BOOL ldap_open_connection(LDAP **ldap_struct)
36 if ( (*ldap_struct = ldap_open(lp_ldap_server(),lp_ldap_port()) )== NULL)
38 DEBUG(0,("%s: The LDAP server is not responding !\n",timestring()));
41 DEBUG(2,("ldap_open_connection: connection opened\n"));
46 /*******************************************************************
47 connect anonymously to the ldap server.
49 ******************************************************************/
50 static BOOL ldap_connect_anonymous(LDAP *ldap_struct)
52 if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
54 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
61 /*******************************************************************
62 connect to the ldap server under system privileg.
63 ******************************************************************/
64 BOOL ldap_connect_system(LDAP *ldap_struct)
66 if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
68 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
71 DEBUG(2,("ldap_connect_system: succesfull connection to the LDAP server\n"));
75 /*******************************************************************
76 connect to the ldap server under a particular user.
77 ******************************************************************/
78 static BOOL ldap_connect_user(LDAP *ldap_struct, char *user, char *password)
80 if ( ldap_simple_bind_s(ldap_struct,lp_ldap_root(),lp_ldap_rootpasswd()) != LDAP_SUCCESS)
82 DEBUG(0,("%s: Couldn't bind to the LDAP server !\n", timestring() ));
85 DEBUG(2,("ldap_connect_user: succesfull connection to the LDAP server\n"));
89 /*******************************************************************
90 run the search by name.
91 ******************************************************************/
92 static BOOL ldap_search_one_user(LDAP *ldap_struct, char *filter, LDAPMessage **result)
94 int scope = LDAP_SCOPE_ONELEVEL;
97 DEBUG(2,("ldap_search_one_user: searching for:[%s]\n", filter));
99 rc=ldap_search_s(ldap_struct, lp_ldap_suffix(), scope, filter, NULL, 0, result);
101 if (rc != LDAP_SUCCESS )
103 DEBUG(0,("%s: Problem during the LDAP search\n",timestring()));
109 /*******************************************************************
110 run the search by name.
111 ******************************************************************/
112 BOOL ldap_search_one_user_by_name(LDAP *ldap_struct, char *user, LDAPMessage **result)
116 in the filter expression, replace %u with the real name
117 so in ldap filter, %u MUST exist :-)
119 strcpy(filter,lp_ldap_filter());
120 string_sub(filter,"%u",user);
122 if ( !ldap_search_one_user(ldap_struct, filter, result) )
129 /*******************************************************************
130 run the search by uid.
131 ******************************************************************/
132 BOOL ldap_search_one_user_by_uid(LDAP *ldap_struct, int uid, LDAPMessage **result)
136 in the filter expression, replace %u with the real name
137 so in ldap filter, %u MUST exist :-)
139 snprintf(filter, sizeof(pstring), "uidAccount=%d", uid);
141 if ( !ldap_search_one_user(ldap_struct, filter, result) )
148 /*******************************************************************
149 search an attribute and return the first value found.
150 ******************************************************************/
151 void get_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, char *attribute, char *value)
155 if ( (valeurs=ldap_get_values(ldap_struct, entry, attribute)) != NULL)
157 strcpy(value, valeurs[0]);
158 ldap_value_free(valeurs);
159 DEBUG(3,("get_single_attribute: [%s]=[%s]\n", attribute, value));
167 /*******************************************************************
168 find a user or a machine return a smbpass struct.
169 ******************************************************************/
170 struct passwd *Get_ldap_Pwnam(char *user)
177 BOOL sambaAccount=False;
180 static struct passwd ldap_passwd;
181 static char pw_name[256];
182 static char pw_passwd[256];
183 static char pw_gecos[256];
184 static char pw_dir[256];
185 static char pw_shell[256];
186 ldap_passwd.pw_name=pw_name;
187 ldap_passwd.pw_passwd=pw_passwd;
188 ldap_passwd.pw_gecos=pw_gecos;
189 ldap_passwd.pw_dir=pw_dir;
190 ldap_passwd.pw_shell=pw_shell;
192 DEBUG(0,("XXXX XXXX XXXX, ca merde serieux!\n"));
194 /* first clear the struct */
195 bzero(pw_name,sizeof(pw_name));
196 bzero(pw_passwd,sizeof(pw_passwd));
197 bzero(pw_gecos,sizeof(pw_gecos));
198 bzero(pw_dir,sizeof(pw_dir));
199 bzero(pw_shell,sizeof(pw_shell));
200 ldap_passwd.pw_uid=-1;
201 ldap_passwd.pw_gid=-1;
204 ldap_open_connection(&ldap_struct);
207 to get all the attributes (specially the userPassword )
208 we have to connect under the system administrator account
210 ldap_connect_system(ldap_struct);
212 ldap_search_one_user(ldap_struct, user, &result);
214 if (ldap_count_entries(ldap_struct, result) != 1)
216 DEBUG(0,("%s: Strange %d user in the base!\n",
217 timestring(), ldap_count_entries(ldap_struct, result) ));
220 /* take the first and unique entry */
221 entry=ldap_first_entry(ldap_struct, result);
223 /* check what kind of account it is */
224 /* as jeremy doesn't want to split getpwnam in 2 functions :-( */
226 if (user[strlen(user)-1]=='$')
233 valeur=ldap_get_values(ldap_struct,entry, "objectclass");
235 /* check if the entry is a person objectclass*/
237 for (i=0;valeur[i]!=NULL;i++)
239 if (!strcmp(valeur[i],"sambaAccount")) sambaAccount=True;
241 ldap_value_free(valeur);
245 /* we should have enough info to fill the struct */
246 strncpy(ldap_passwd.pw_name,user,strlen(user));
248 valeur=ldap_get_values(ldap_struct,entry, "uidAccount");
251 ldap_passwd.pw_uid=atoi(valeur[0]);
253 ldap_value_free(valeur);
255 valeur=ldap_get_values(ldap_struct,entry, "gidAccount");
258 ldap_passwd.pw_gid=atoi(valeur[0]);
260 ldap_value_free(valeur);
262 valeur=ldap_get_values(ldap_struct,entry, "userPassword");
266 as we have the clear-text password, we have to crypt it !
267 hum hum hum currently pass the clear text password to wait
269 strncpy(ldap_passwd.pw_passwd,valeur[0],strlen(valeur[0]));
271 ldap_value_free(valeur);
273 valeur=ldap_get_values(ldap_struct,entry, "gecos");
276 strncpy(ldap_passwd.pw_gecos,valeur[0],strlen(valeur[0]));
278 ldap_value_free(valeur);
280 valeur=ldap_get_values(ldap_struct,entry, "homeDirectory");
283 strncpy(ldap_passwd.pw_dir,valeur[0],strlen(valeur[0]));
285 ldap_value_free(valeur);
287 valeur=ldap_get_values(ldap_struct,entry, "loginShell");
290 strncpy(ldap_passwd.pw_shell,valeur[0],strlen(valeur[0]));
292 ldap_value_free(valeur);
299 ldap_unbind(ldap_struct);
302 /*******************************************************************
303 check if the returned entry is a sambaAccount objectclass.
304 ******************************************************************/
305 BOOL ldap_check_user(LDAP *ldap_struct, LDAPMessage *entry)
307 BOOL sambaAccount=False;
311 DEBUG(2,("ldap_check_user: "));
312 valeur=ldap_get_values(ldap_struct, entry, "objectclass");
315 for (i=0;valeur[i]!=NULL;i++)
317 if (!strcmp(valeur[i],"sambaAccount")) sambaAccount=True;
320 DEBUG(2,("%s\n",sambaAccount?"yes":"no"));
321 ldap_value_free(valeur);
322 return (sambaAccount);
325 /*******************************************************************
326 check if the returned entry is a sambaMachine objectclass.
327 ******************************************************************/
328 BOOL ldap_check_machine(LDAP *ldap_struct, LDAPMessage *entry)
330 BOOL sambaMachine=False;
334 DEBUG(2,("ldap_check_machine: "));
335 valeur=ldap_get_values(ldap_struct, entry, "objectclass");
338 for (i=0;valeur[i]!=NULL;i++)
340 if (!strcmp(valeur[i],"sambaMachine")) sambaMachine=True;
343 DEBUG(2,("%s\n",sambaMachine?"yes":"no"));
344 ldap_value_free(valeur);
345 return (sambaMachine);
348 /*******************************************************************
349 retrieve the user's info and contruct a smb_passwd structure.
350 ******************************************************************/
351 static void ldap_get_user(LDAP *ldap_struct,LDAPMessage *entry,
352 struct smb_passwd *ldap_passwd)
354 static pstring user_name;
355 static unsigned char smbpwd[16];
356 static unsigned char smbntpwd[16];
359 get_single_attribute(ldap_struct, entry, "cn", user_name);
361 DEBUG(2,("ldap_get_user: user: %s\n",user_name));
363 if ( (valeur=ldap_get_values(ldap_struct, entry, "uidAccount")) != NULL)
365 ldap_passwd->smb_userid=atoi(valeur[0]);
366 ldap_value_free(valeur);
369 if ( (valeur=ldap_get_values(ldap_struct, entry, "userPassword")) != NULL)
371 memset(smbntpwd, '\0', 16);
372 E_md4hash((uchar *) valeur[0], smbntpwd);
373 valeur[0][14] = '\0';
375 memset(smbpwd, '\0', 16);
376 E_P16((uchar *) valeur[0], smbpwd);
377 ldap_value_free(valeur);
380 if ( (valeur=ldap_get_values(ldap_struct,entry, "userAccountControl") ) != NULL)
382 ldap_passwd->acct_ctrl=atoi(valeur[0]);
383 if (ldap_passwd->acct_ctrl & (ACB_DOMTRUST|ACB_WSTRUST|ACB_SVRTRUST) )
385 DEBUG(0,("Inconsistency in the LDAP database\n"));
388 if (ldap_passwd->acct_ctrl & ACB_NORMAL)
390 ldap_passwd->smb_name=user_name;
391 ldap_passwd->smb_passwd=smbpwd;
392 ldap_passwd->smb_nt_passwd=smbntpwd;
394 ldap_value_free(valeur);
397 if ( (valeur=ldap_get_values(ldap_struct,entry, "pwdLastSet")) != NULL)
399 ldap_passwd->last_change_time=(time_t)strtol(valeur[0], NULL, 16);
400 ldap_value_free(valeur);
404 /*************************************************************
405 Routine to get the next 32 hex characters and turn them
406 into a 16 byte array.
407 **************************************************************/
409 static int gethexpwd(char *p, char *pwd)
412 unsigned char lonybble, hinybble;
413 char *hexchars = "0123456789ABCDEF";
416 for (i = 0; i < 32; i += 2) {
417 hinybble = toupper(p[i]);
418 lonybble = toupper(p[i + 1]);
420 p1 = strchr(hexchars, hinybble);
421 p2 = strchr(hexchars, lonybble);
424 hinybble = PTR_DIFF(p1, hexchars);
425 lonybble = PTR_DIFF(p2, hexchars);
427 pwd[i / 2] = (hinybble << 4) | lonybble;
432 /*******************************************************************
433 retrieve the machine's info and contruct a smb_passwd structure.
434 ******************************************************************/
435 static void ldap_get_machine(LDAP *ldap_struct,LDAPMessage *entry,
436 struct smb_passwd *ldap_passwd)
438 static pstring user_name;
439 static unsigned char smbntpwd[16];
442 /* by default it's a station */
443 ldap_passwd->acct_ctrl = ACB_WSTRUST;
445 get_single_attribute(ldap_struct, entry, "cn", user_name);
446 DEBUG(2,("ldap_get_machine: machine: %s\n", user_name));
448 if ( (valeur=ldap_get_values(ldap_struct, entry, "uidAccount")) != NULL)
450 ldap_passwd->smb_userid=atoi(valeur[0]);
451 ldap_value_free(valeur);
454 if ( (valeur=ldap_get_values(ldap_struct, entry, "machinePassword")) != NULL)
456 gethexpwd(valeur[0],smbntpwd);
457 ldap_value_free(valeur);
460 if ( (valeur=ldap_get_values(ldap_struct,entry, "machineRole") ) != NULL)
462 if ( !strcmp(valeur[0],"workstation") )
463 ldap_passwd->acct_ctrl=ACB_WSTRUST;
465 if ( !strcmp(valeur[0],"server") )
466 ldap_passwd->acct_ctrl=ACB_SVRTRUST;
467 ldap_value_free(valeur);
470 ldap_passwd->smb_name=user_name;
471 ldap_passwd->smb_passwd=smbntpwd;
472 ldap_passwd->smb_nt_passwd=smbntpwd;
475 /*******************************************************************
476 find a user or a machine return a smbpass struct.
477 ******************************************************************/
478 struct smb_passwd *ldap_get_smbpwd_entry(char *name, int smb_userid)
485 static struct smb_passwd ldap_passwd;
487 ldap_passwd.smb_name = NULL;
488 ldap_passwd.smb_passwd = NULL;
489 ldap_passwd.smb_nt_passwd = NULL;
491 ldap_passwd.smb_userid = -1;
492 ldap_passwd.acct_ctrl = ACB_DISABLED;
493 ldap_passwd.last_change_time = 0;
499 DEBUG(10, ("ldap_get_smbpwd_entry: search by name: %s\n", name));
503 DEBUG(10, ("ldap_get_smbpwd_entry: search by smb_userid: %x\n", smb_userid));
506 if (!ldap_open_connection(&ldap_struct))
508 if (!ldap_connect_system(ldap_struct))
513 if (!ldap_search_one_user_by_name(ldap_struct, name, &result))
518 if (!ldap_search_one_user_by_uid(ldap_struct, smb_userid, &result))
522 if (ldap_count_entries(ldap_struct, result) == 0)
524 DEBUG(2,("%s: Non existant user!\n", timestring() ));
528 if (ldap_count_entries(ldap_struct, result) > 1)
530 DEBUG(2,("%s: Strange %d users in the base!\n",
531 timestring(), ldap_count_entries(ldap_struct, result) ));
533 /* take the first and unique entry */
534 entry=ldap_first_entry(ldap_struct, result);
538 DEBUG(0,("ldap_get_smbpwd_entry: Found user: %s\n",name));
540 if (name[strlen(name)-1]=='$')
548 if (ldap_check_user(ldap_struct, entry)==True)
549 ldap_get_user(ldap_struct, entry, &ldap_passwd);
553 if (ldap_check_machine(ldap_struct, entry)==True)
554 ldap_get_machine(ldap_struct, entry, &ldap_passwd);
557 ldap_msgfree(result);
559 ldap_unbind(ldap_struct);
561 return(&ldap_passwd);