passdb.c
[samba.git] / source / passdb / passdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Andrew Tridgell 1992-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "nterr.h"
25
26 extern int DEBUGLEVEL;
27
28 /*
29  * This is set on startup - it defines the SID for this
30  * machine.
31  */
32 DOM_SID global_machine_sid;
33
34 /**********************************************************
35  **********************************************************
36
37  low-level redirection routines:
38
39         startsampwent()
40         endsampwent()
41         getsampwent()
42         getsam21pwent()
43         getsampwpos()
44         setsampwpos()
45
46         add_sampwd_entry()
47         mod_sampwd_entry()
48         add_sam21pwd_entry()
49         mod_sam21pwd_entry()
50
51  **********************************************************
52  **********************************************************/
53
54 /***************************************************************
55  Start to enumerate the sam passwd list. Returns a void pointer
56  to ensure no modification outside this module.
57 ****************************************************************/
58 void *startsampwent(BOOL update)
59 {
60 #ifdef USE_LDAP
61   return startldappwent(update);
62 #else
63   return startsmbpwent(update);
64 #endif /* USE_LDAP */
65 }
66
67 /***************************************************************
68  End enumeration of the sam passwd list.
69 ****************************************************************/
70 void endsampwent(void *vp)
71 {
72 #ifdef USE_LDAP
73   endldappwent(vp);
74 #else
75   endsmbpwent(vp);
76 #endif /* USE_LDAP */
77 }
78
79 /*************************************************************************
80  Routine to return the next entry in the sam passwd list.
81  *************************************************************************/
82 struct smb_passwd *getsampwent(void *vp)
83 {
84 #ifdef USE_LDAP
85   return getldappwent(vp);
86 #else
87   return getsmbpwent(vp);
88 #endif /* USE_LDAP */
89 }
90
91 /*************************************************************************
92  Routine to return the next entry in the sam passwd list.
93  *************************************************************************/
94 struct sam_passwd *getsam21pwent(void *vp)
95 {
96 #ifdef USE_LDAP
97   return getldap21pwent(vp);
98 #else
99   return getsmb21pwent(vp);
100 #endif /* USE_LDAP */
101 }
102
103 /*************************************************************************
104  Return the current position in the sam passwd list as an unsigned long.
105  This must be treated as an opaque token.
106  *************************************************************************/
107 unsigned long getsampwpos(void *vp)
108 {
109 #ifdef USE_LDAP
110   return getldappwpos(vp);
111 #else
112   return getsmbpwpos(vp);
113 #endif /* USE_LDAP */
114 }
115
116 /*************************************************************************
117  Set the current position in the sam passwd list from unsigned long.
118  This must be treated as an opaque token.
119  *************************************************************************/
120 BOOL setsampwpos(void *vp, unsigned long tok)
121 {
122 #ifdef USE_LDAP
123   return setldappwpos(vp, tok);
124 #else
125   return setsmbpwpos(vp, tok);
126 #endif /* USE_LDAP */
127 }
128
129 /************************************************************************
130  Routine to add an entry to the sam passwd file.
131 *************************************************************************/
132 BOOL add_sampwd_entry(struct smb_passwd *newpwd)
133 {
134 #ifdef USE_LDAP
135   return add_ldappwd_entry(newpwd);
136 #else
137   return add_smbpwd_entry(newpwd);
138 #endif /* USE_LDAP */
139 }
140
141 /************************************************************************
142  Routine to add an entry to the sam passwd file.
143 *************************************************************************/
144 BOOL add_sam21pwd_entry(struct sam_passwd *newpwd)
145 {
146 #if 0
147 #ifdef USE_LDAP
148   return add_ldap21pwd_entry(newpwd);
149 #else
150   return add_smb21pwd_entry(newpwd);
151 #endif /* USE_LDAP */
152 #else
153         DEBUG(0,("add_sam21pwd_entry() - under development\n"));
154         return False;
155 #endif
156 }
157
158 /************************************************************************
159  Routine to search the sam passwd file for an entry matching the username.
160  and then modify its password entry. We can't use the startsampwent()/
161  getsampwent()/endsampwent() interfaces here as we depend on looking
162  in the actual file to decide how much room we have to write data.
163  override = False, normal
164  override = True, override XXXXXXXX'd out password or NO PASS
165 ************************************************************************/
166 BOOL mod_sampwd_entry(struct smb_passwd* pwd, BOOL override)
167 {
168 #ifdef USE_LDAP
169   return mod_ldappwd_entry(pwd, override);
170 #else
171   return mod_smbpwd_entry(pwd, override);
172 #endif /* USE_LDAP */
173 }
174
175 /************************************************************************
176  Routine to search the sam passwd file for an entry matching the username.
177  and then modify its password entry. We can't use the startsampwent()/
178  getsampwent()/endsampwent() interfaces here as we depend on looking
179  in the actual file to decide how much room we have to write data.
180  override = False, normal
181  override = True, override XXXXXXXX'd out password or NO PASS
182 ************************************************************************/
183 BOOL mod_sam21pwd_entry(struct sam_passwd* pwd, BOOL override)
184 {
185 #if 0
186 #ifdef USE_LDAP
187   return mod_ldap21pwd_entry(pwd, override);
188 #else
189   return mod_smb21pwd_entry(pwd, override);
190 #endif /* USE_LDAP */
191 #else
192         DEBUG(0,("mod_sam21pwd_entry() - under development\n"));
193         return False;
194 #endif
195 }
196
197 /**********************************************************
198  **********************************************************
199
200  high-level database routines:
201         getsampwnam()
202         getsampwuid()
203         getsam21pwnam()
204         getsam21pwuid()
205
206  **********************************************************
207  **********************************************************/
208
209 /************************************************************************
210  Routine to search sam passwd by name.
211 *************************************************************************/
212 struct smb_passwd *getsampwnam(char *name)
213 {
214         struct smb_passwd *pwd = NULL;
215         void *fp = NULL;
216
217         DEBUG(10, ("getsampwnam: search by name: %s\n", name));
218
219         /* Open the sam password file - not for update. */
220         fp = startsampwent(False);
221
222         if (fp == NULL)
223         {
224                 DEBUG(0, ("getsampwnam: unable to open sam password database.\n"));
225                 return NULL;
226         }
227
228         while ((pwd = getsampwent(fp)) != NULL && !strequal(pwd->smb_name, name));
229
230         if (pwd != NULL)
231         {
232                 DEBUG(10, ("getsampwnam: found by name: %s\n", name));
233         }
234
235         endsampwent(fp);
236         return pwd;
237 }
238
239 /************************************************************************
240  Routine to search sam passwd by name.
241 *************************************************************************/
242 struct sam_passwd *getsam21pwnam(char *name)
243 {
244         struct sam_passwd *pwd = NULL;
245         void *fp = NULL;
246
247         DEBUG(10, ("getsam21pwnam: search by name: %s\n", name));
248
249         /* Open the sam password file - not for update. */
250         fp = startsampwent(False);
251
252         if (fp == NULL)
253         {
254                 DEBUG(0, ("getsam21pwnam: unable to open sam password database.\n"));
255                 return NULL;
256         }
257
258         while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->smb_name, name));
259
260         if (pwd != NULL)
261         {
262                 DEBUG(10, ("getsam21pwnam: found by name: %s\n", name));
263         }
264
265         endsampwent(fp);
266         return pwd;
267 }
268
269 /************************************************************************
270  Routine to search sam passwd by uid.
271 *************************************************************************/
272 struct smb_passwd *getsampwuid(uid_t smb_userid)
273 {
274         struct smb_passwd *pwd = NULL;
275         void *fp = NULL;
276
277         DEBUG(10, ("getsampwuid: search by smb_userid: %x\n", smb_userid));
278
279         /* Open the sam password file - not for update. */
280         fp = startsampwent(False);
281
282         if (fp == NULL)
283         {
284                 DEBUG(0, ("getsampwuid: unable to open sam password database.\n"));
285                 return NULL;
286         }
287
288         while ((pwd = getsampwent(fp)) != NULL && pwd->smb_userid != smb_userid);
289
290         if (pwd != NULL)
291         {
292                 DEBUG(10, ("getsampwuid: found by smb_userid: %x\n", smb_userid));
293         }
294
295         endsmbpwent(fp);
296         return pwd;
297 }
298
299 /************************************************************************
300  Routine to search sam passwd by rid.
301 *************************************************************************/
302 struct sam_passwd *getsam21pwrid(uint32 rid)
303 {
304         struct sam_passwd *pwd = NULL;
305         void *fp = NULL;
306
307         DEBUG(10, ("getsam21pwrid: search by rid: %x\n", rid));
308
309         /* Open the sam password file - not for update. */
310         fp = startsampwent(False);
311
312         if (fp == NULL)
313         {
314                 DEBUG(0, ("getsam21pwrid: unable to open sam password database.\n"));
315                 return NULL;
316         }
317
318         while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid);
319
320         if (pwd != NULL)
321         {
322                 DEBUG(10, ("getsam21pwrid: found by smb_userid: %x\n", rid));
323         }
324
325         endsmbpwent(fp);
326         return pwd;
327 }
328
329
330 /**********************************************************
331  **********************************************************
332
333  utility routines which are likely to be useful to all password
334  databases
335
336  **********************************************************
337  **********************************************************/
338
339 /**********************************************************
340  Encode the account control bits into a string.
341  **********************************************************/
342 char *encode_acct_ctrl(uint16 acct_ctrl)
343 {
344   static fstring acct_str;
345   char *p = acct_str;
346  
347   *p++ = '[';
348
349   if (acct_ctrl & ACB_HOMDIRREQ) *p++ = 'H';
350   if (acct_ctrl & ACB_TEMPDUP  ) *p++ = 'T'; 
351   if (acct_ctrl & ACB_NORMAL   ) *p++ = 'U';
352   if (acct_ctrl & ACB_MNS      ) *p++ = 'M';
353   if (acct_ctrl & ACB_WSTRUST  ) *p++ = 'W';
354   if (acct_ctrl & ACB_SVRTRUST ) *p++ = 'S';
355   if (acct_ctrl & ACB_AUTOLOCK ) *p++ = 'L';
356   if (acct_ctrl & ACB_PWNOEXP  ) *p++ = 'X';
357   if (acct_ctrl & ACB_DOMTRUST ) *p++ = 'I';
358       
359   *p++ = ']';
360   *p = '\0';
361   return acct_str;
362 }     
363
364 /**********************************************************
365  Decode the account control bits from a string.
366
367  this function breaks coding standards minimum line width of 80 chars.
368  reason: vertical line-up code clarity - all case statements fit into
369  15 lines, which is more important.
370  **********************************************************/
371 uint16 decode_acct_ctrl(char *p)
372 {
373         uint16 acct_ctrl = 0;
374         BOOL finished = False;
375
376         /*
377          * Check if the account type bits have been encoded after the
378          * NT password (in the form [NDHTUWSLXI]).
379          */
380
381         if (*p != '[') return 0;
382
383         for (p++; *p && !finished; p++)
384         {
385                 switch (*p)
386                 {
387 #if 0
388                         /*
389                          * Hmmm. Don't allow these to be set/read independently
390                          * of the actual password fields. We don't want a mismatch.
391                          * JRA.
392                          */
393                         case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
394                         case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
395 #endif 
396                         case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
397                         case 'T': { acct_ctrl |= ACB_TEMPDUP  ; break; /* 'T'emp account. */ } 
398                         case 'U': { acct_ctrl |= ACB_NORMAL   ; break; /* 'U'ser account (normal). */ } 
399                         case 'M': { acct_ctrl |= ACB_MNS      ; break; /* 'M'NS logon user account. What is this ? */ } 
400                         case 'W': { acct_ctrl |= ACB_WSTRUST  ; break; /* 'W'orkstation account. */ } 
401                         case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } 
402                         case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } 
403                         case 'X': { acct_ctrl |= ACB_PWNOEXP  ; break; /* No 'X'piry on password */ } 
404                         case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
405
406                         case ':':
407                         case '\n':
408                         case '\0': 
409                         case ']':
410                         default:  { finished = True; }
411                 }
412         }
413
414         return acct_ctrl;
415 }
416
417 /*************************************************************
418  Routine to get the next 32 hex characters and turn them
419  into a 16 byte array.
420 **************************************************************/
421 int gethexpwd(char *p, char *pwd)
422 {
423   int i;
424   unsigned char   lonybble, hinybble;
425   char           *hexchars = "0123456789ABCDEF";
426   char           *p1, *p2;
427
428   for (i = 0; i < 32; i += 2) {
429     hinybble = toupper(p[i]);
430     lonybble = toupper(p[i + 1]);
431  
432     p1 = strchr(hexchars, hinybble);
433     p2 = strchr(hexchars, lonybble);
434     if (!p1 || !p2)
435       return (False);
436     hinybble = PTR_DIFF(p1, hexchars);
437     lonybble = PTR_DIFF(p2, hexchars);
438  
439     pwd[i / 2] = (hinybble << 4) | lonybble;
440   }
441   return (True);
442 }
443
444 /*******************************************************************
445  Group and User RID username mapping function
446  ********************************************************************/
447 BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
448 {
449     struct passwd *pw = Get_Pwnam(user_name, False);
450
451         if (u_rid == NULL || g_rid == NULL || user_name == NULL)
452         {
453                 return False;
454         }
455
456     if (!pw)
457         {
458       DEBUG(1,("Username %s is invalid on this system\n", user_name));
459       return False;
460     }
461
462         if (user_in_list(user_name, lp_domain_guest_users()))
463         {
464                 *u_rid = DOMAIN_USER_RID_GUEST;
465         }
466         else if (user_in_list(user_name, lp_domain_admin_users()))
467         {
468                 *u_rid = DOMAIN_USER_RID_ADMIN;
469         }
470         else
471         {
472                 /* turn the unix UID into a Domain RID.  this is what the posix
473                    sub-system does (adds 1000 to the uid) */
474                 *u_rid = uid_to_user_rid(pw->pw_uid);
475         }
476
477         /* absolutely no idea what to do about the unix GID to Domain RID mapping */
478         *g_rid = gid_to_group_rid(pw->pw_gid);
479
480         return True;
481 }
482
483 /****************************************************************************
484  Read the machine SID from a file.
485 ****************************************************************************/
486     
487 static BOOL read_sid_from_file(int fd, char *sid_file)
488 {   
489   fstring fline;
490     
491   if(read(fd, &fline, sizeof(fline) -1 ) < 0) {
492     DEBUG(0,("read_sid_from_file: unable to read file %s. Error was %s\n",
493            sid_file, strerror(errno) ));
494     return False;
495   }
496
497   /*
498    * Convert to the machine SID.
499    */
500
501   fline[sizeof(fline)-1] = '\0';
502   if(!string_to_sid( &global_machine_sid, fline)) {
503     DEBUG(0,("read_sid_from_file: unable to generate machine SID.\n"));
504     return False;
505   }
506
507   return True;
508 }
509
510 /****************************************************************************
511  Generate the global machine sid. Look for the MACHINE.SID file first, if
512  not found then look in smb.conf and use it to create the MACHINE.SID file.
513 ****************************************************************************/
514
515 BOOL generate_machine_sid(void)
516 {
517   int fd;
518   char *p;
519   pstring sid_file;
520   fstring sid_string;
521   struct stat st;
522   uchar raw_sid_data[12];
523
524   pstrcpy(sid_file, lp_smb_passwd_file());
525   p = strrchr(sid_file, '/');
526   if(p != NULL)
527     *++p = '\0';
528     
529   pstrcat(sid_file, "MACHINE.SID");
530     
531   if((fd = open( sid_file, O_RDWR | O_CREAT, 0644)) < 0 ) {
532     DEBUG(0,("generate_machine_sid: unable to open or create file %s. Error was %s\n",
533              sid_file, strerror(errno) ));
534     return False;
535   } 
536   
537   /*
538    * Check if the file contains data.
539    */
540     
541   if(fstat( fd, &st) < 0) {
542     DEBUG(0,("generate_machine_sid: unable to stat file %s. Error was %s\n",
543              sid_file, strerror(errno) ));
544     close(fd);
545     return False;
546   } 
547   
548   if(st.st_size > 0) {
549     /*
550      * We have a valid SID - read it.
551      */
552     if(!read_sid_from_file( fd, sid_file)) {
553       DEBUG(0,("generate_machine_sid: unable to read file %s. Error was %s\n",
554              sid_file, strerror(errno) ));
555       close(fd);
556       return False;
557     }
558     close(fd);
559     return True;
560   } 
561   
562   /*
563    * The file contains no data - we may need to generate our
564    * own sid. Try the lp_domain_sid() first.
565    */
566     
567   if(*lp_domain_sid())
568     fstrcpy( sid_string, lp_domain_sid());
569   else {
570     /*
571      * Generate the new sid data & turn it into a string.
572      */
573     int i;
574     generate_random_buffer( raw_sid_data, 12, True);
575     
576     fstrcpy( sid_string, "S-1-5-21");
577     for( i = 0; i < 3; i++) {
578       fstring tmp_string;
579       slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
580       fstrcat( sid_string, tmp_string);
581     }
582   } 
583   
584   fstrcat(sid_string, "\n");
585     
586   /*
587    * Ensure our new SID is valid.
588    */
589     
590   if(!string_to_sid( &global_machine_sid, sid_string)) {
591     DEBUG(0,("generate_machine_sid: unable to generate machine SID.\n"));
592     return False;
593   } 
594   
595   /*
596    * Do an exclusive blocking lock on the file.
597    */
598     
599   if(!do_file_lock( fd, 60, F_WRLCK)) {
600     DEBUG(0,("generate_machine_sid: unable to lock file %s. Error was %s\n",
601              sid_file, strerror(errno) ));
602     close(fd);
603     return False;
604   } 
605   
606   /*
607    * At this point we have a blocking lock on the SID
608    * file - check if in the meantime someone else wrote
609    * SID data into the file. If so - they were here first,
610    * use their data.
611    */
612     
613   if(fstat( fd, &st) < 0) {
614     DEBUG(0,("generate_machine_sid: unable to stat file %s. Error was %s\n",
615              sid_file, strerror(errno) ));
616     close(fd);
617     return False;
618   } 
619   
620   if(st.st_size > 0) {
621     /*
622      * Unlock as soon as possible to reduce
623      * contention on the exclusive lock.
624      */ 
625     do_file_lock( fd, 60, F_UNLCK);
626     
627     /*
628      * We have a valid SID - read it.
629      */
630     
631     if(!read_sid_from_file( fd, sid_file)) {
632       DEBUG(0,("generate_machine_sid: unable to read file %s. Error was %s\n",
633              sid_file, strerror(errno) ));
634       close(fd);
635       return False;
636     }
637     close(fd);
638     return True;
639   } 
640     
641   /*
642    * The file is still empty and we have an exlusive lock on it.
643    * Write out out SID data into the file.
644    */
645     
646   if(fchmod(fd, 0644) < 0) {
647     DEBUG(0,("generate_machine_sid: unable to set correct permissions on file %s. \
648 Error was %s\n", sid_file, strerror(errno) ));
649     close(fd);
650     return False;
651   } 
652   
653   if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) {
654     DEBUG(0,("generate_machine_sid: unable to write file %s. Error was %s\n",
655           sid_file, strerror(errno) ));
656     close(fd);
657     return False;
658   } 
659   
660   /*
661    * Unlock & exit.
662    */
663     
664   do_file_lock( fd, 60, F_UNLCK);
665   close(fd);
666   return True;
667 }   
668
669 /*******************************************************************
670  XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
671  INSIDE smbpass.c
672
673  converts NT User RID to a UNIX uid.
674  ********************************************************************/
675 uid_t user_rid_to_uid(uint32 u_rid)
676 {
677         return (uid_t)(u_rid - 1000);
678 }
679
680 /*******************************************************************
681  XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
682  INSIDE smbpass.c
683
684  converts NT Group RID to a UNIX uid.
685  ********************************************************************/
686 uid_t group_rid_to_uid(uint32 u_gid)
687 {
688         return (uid_t)(u_gid - 1000);
689 }
690
691 /*******************************************************************
692  XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
693  INSIDE smbpass.c
694
695  converts UNIX uid to an NT User RID.
696  ********************************************************************/
697 uint32 uid_to_user_rid(uint32 uid)
698 {
699         return (uint32)(uid + 1000);
700 }
701
702 /*******************************************************************
703  XXXX THIS FUNCTION SHOULD NOT BE HERE: IT SHOULD BE A STATIC FUNCTION
704  INSIDE smbpass.c
705
706  converts NT Group RID to a UNIX uid.
707  ********************************************************************/
708 uint32 gid_to_group_rid(uint32 gid)
709 {
710         return (uint32)(gid + 1000);
711 }
712