e190be99a56ef15fc093c5f372a253b65709e38b
[samba.git] / source3 / passdb / pdb_smbpasswd.c
1 /*
2  * Unix SMB/Netbios implementation. 
3  * Version 1.9. SMB parameters and setup
4  * Copyright (C) Andrew Tridgell 1992-1998 
5  * Modified by Jeremy Allison 1995.
6  * Modified by Gerald (Jerry) Carter 2000-2001
7  * 
8  * This program is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  * 
18  * You should have received a copy of the GNU General Public License along with
19  * this program; if not, write to the Free Software Foundation, Inc., 675
20  * Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include "includes.h"
24
25 #ifdef WITH_SMBPASSWD_SAM
26
27
28 /* 
29    smb_passwd is analogous to sam_passwd used everywhere
30    else.  However, smb_passwd is limited to the information
31    stored by an smbpasswd entry 
32  */
33  
34 struct smb_passwd
35 {
36         uid_t smb_userid;     /* this is actually the unix uid_t */
37         const char *smb_name;     /* username string */
38
39         const unsigned char *smb_passwd; /* Null if no password */
40         const unsigned char *smb_nt_passwd; /* Null if no password */
41
42         uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
43         time_t pass_last_set_time;    /* password last set time */
44 };
45
46
47 extern pstring samlogon_user;
48 extern BOOL sam_logon_in_ssb;
49 extern struct passdb_ops pdb_ops;
50
51 /* used for maintain locks on the smbpasswd file */
52 static int      pw_file_lock_depth;
53 static void     *global_vp;
54
55
56 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
57
58 /***************************************************************
59  Lock an fd. Abandon after waitsecs seconds.
60 ****************************************************************/
61
62 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
63 {
64   if (fd < 0)
65     return False;
66
67   if(*plock_depth == 0) {
68     if (!do_file_lock(fd, secs, type)) {
69       DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
70                  strerror(errno)));
71       return False;
72     }
73   }
74
75   (*plock_depth)++;
76
77   return True;
78 }
79
80 /***************************************************************
81  Unlock an fd. Abandon after waitsecs seconds.
82 ****************************************************************/
83
84 static BOOL pw_file_unlock(int fd, int *plock_depth)
85 {
86   BOOL ret=True;
87
88   if(*plock_depth == 1)
89     ret = do_file_lock(fd, 5, F_UNLCK);
90
91   if (*plock_depth > 0)
92     (*plock_depth)--;
93
94   if(!ret)
95     DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
96                  strerror(errno)));
97   return ret;
98 }
99
100
101 /**************************************************************
102  Intialize a smb_passwd struct
103  *************************************************************/
104
105 static void pdb_init_smb(struct smb_passwd *user)
106 {
107         if (user == NULL) 
108                 return;
109         ZERO_STRUCTP (user);
110         
111         user->pass_last_set_time = (time_t)0;
112 }
113
114 /***************************************************************
115  Internal fn to enumerate the smbpasswd list. Returns a void pointer
116  to ensure no modification outside this module. Checks for atomic
117  rename of smbpasswd file on update or create once the lock has
118  been granted to prevent race conditions. JRA.
119 ****************************************************************/
120
121 static void *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
122 {
123   FILE *fp = NULL;
124   const char *open_mode = NULL;
125   int race_loop = 0;
126   int lock_type = F_RDLCK;
127
128   if (!*pfile) {
129     DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
130     return (NULL);
131   }
132
133   switch(type) {
134   case PWF_READ:
135     open_mode = "rb";
136     lock_type = F_RDLCK;
137     break;
138   case PWF_UPDATE:
139     open_mode = "r+b";
140     lock_type = F_WRLCK;
141     break;
142   case PWF_CREATE:
143     /*
144      * Ensure atomic file creation.
145      */
146     {
147       int i, fd = -1;
148
149       for(i = 0; i < 5; i++) {
150         if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
151           break;
152         sys_usleep(200); /* Spin, spin... */
153       }
154       if(fd == -1) {
155         DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
156         return NULL;
157       }
158       close(fd);
159       open_mode = "r+b";
160       lock_type = F_WRLCK;
161       break;
162     }
163   }
164                        
165   for(race_loop = 0; race_loop < 5; race_loop++) {
166     DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
167
168     if((fp = sys_fopen(pfile, open_mode)) == NULL) {
169       DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
170       return NULL;
171     }
172
173     if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
174       DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
175       fclose(fp);
176       return NULL;
177     }
178
179     /*
180      * Only check for replacement races on update or create.
181      * For read we don't mind if the data is one record out of date.
182      */
183
184     if(type == PWF_READ) {
185       break;
186     } else {
187       SMB_STRUCT_STAT sbuf1, sbuf2;
188
189       /*
190        * Avoid the potential race condition between the open and the lock
191        * by doing a stat on the filename and an fstat on the fd. If the
192        * two inodes differ then someone did a rename between the open and
193        * the lock. Back off and try the open again. Only do this 5 times to
194        * prevent infinate loops. JRA.
195        */
196
197       if (sys_stat(pfile,&sbuf1) != 0) {
198         DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
199         pw_file_unlock(fileno(fp), lock_depth);
200         fclose(fp);
201         return NULL;
202       }
203
204       if (sys_fstat(fileno(fp),&sbuf2) != 0) {
205         DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
206         pw_file_unlock(fileno(fp), lock_depth);
207         fclose(fp);
208         return NULL;
209       }
210
211       if( sbuf1.st_ino == sbuf2.st_ino) {
212         /* No race. */
213         break;
214       }
215
216       /*
217        * Race occurred - back off and try again...
218        */
219
220       pw_file_unlock(fileno(fp), lock_depth);
221       fclose(fp);
222     }
223   }
224
225   if(race_loop == 5) {
226     DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
227     return NULL;
228   }
229
230   /* Set a buffer to do more efficient reads */
231   setvbuf(fp, (char *)NULL, _IOFBF, 1024);
232
233   /* Make sure it is only rw by the owner */
234   if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
235     DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
236 Error was %s\n.", pfile, strerror(errno) ));
237     pw_file_unlock(fileno(fp), lock_depth);
238     fclose(fp);
239     return NULL;
240   }
241
242   /* We have a lock on the file. */
243   return (void *)fp;
244 }
245
246 /***************************************************************
247  End enumeration of the smbpasswd list.
248 ****************************************************************/
249 static void endsmbfilepwent(void *vp, int *lock_depth)
250 {
251   FILE *fp = (FILE *)vp;
252
253   pw_file_unlock(fileno(fp), lock_depth);
254   fclose(fp);
255   DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
256 }
257
258 /*************************************************************************
259  Routine to return the next entry in the smbpasswd list.
260  *************************************************************************/
261
262 static struct smb_passwd *getsmbfilepwent(void *vp)
263 {
264   /* Static buffers we will return. */
265   static struct smb_passwd pw_buf;
266   static pstring  user_name;
267   static unsigned char smbpwd[16];
268   static unsigned char smbntpwd[16];
269   FILE *fp = (FILE *)vp;
270   char            linebuf[256];
271   unsigned char   c;
272   unsigned char  *p;
273   long            uidval;
274   size_t            linebuf_len;
275
276   if(fp == NULL) {
277     DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
278     return NULL;
279   }
280
281   pdb_init_smb(&pw_buf);
282
283   pw_buf.acct_ctrl = ACB_NORMAL;  
284
285   /*
286    * Scan the file, a line at a time and check if the name matches.
287    */
288   while (!feof(fp)) {
289     linebuf[0] = '\0';
290
291     fgets(linebuf, 256, fp);
292     if (ferror(fp)) {
293       return NULL;
294     }
295
296     /*
297      * Check if the string is terminated with a newline - if not
298      * then we must keep reading and discard until we get one.
299      */
300     if ((linebuf_len = strlen(linebuf)) == 0)
301                 continue;
302
303     if (linebuf[linebuf_len - 1] != '\n') {
304       c = '\0';
305       while (!ferror(fp) && !feof(fp)) {
306         c = fgetc(fp);
307         if (c == '\n')
308           break;
309       }
310     } else
311       linebuf[linebuf_len - 1] = '\0';
312
313 #ifdef DEBUG_PASSWORD
314     DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
315 #endif
316     if ((linebuf[0] == 0) && feof(fp)) {
317       DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
318       break;
319     }
320     /*
321      * The line we have should be of the form :-
322      * 
323      * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
324      * ignored....
325      * 
326      * or,
327      *
328      * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
329      *
330      * if Windows NT compatible passwords are also present.
331      * [Account type] is an ascii encoding of the type of account.
332      * LCT-(8 hex digits) is the time_t value of the last change time.
333      */
334
335     if (linebuf[0] == '#' || linebuf[0] == '\0') {
336       DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
337       continue;
338     }
339     p = (unsigned char *) strchr_m(linebuf, ':');
340     if (p == NULL) {
341       DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
342       continue;
343     }
344     /*
345      * As 256 is shorter than a pstring we don't need to check
346      * length here - if this ever changes....
347      */
348     strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
349     user_name[PTR_DIFF(p, linebuf)] = '\0';
350
351     /* Get smb uid. */
352
353     p++;                /* Go past ':' */
354
355     if(*p == '-') {
356       DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
357       continue;
358     }
359
360     if (!isdigit(*p)) {
361       DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
362       continue;
363     }
364
365     uidval = atoi((char *) p);
366
367     while (*p && isdigit(*p))
368       p++;
369
370     if (*p != ':') {
371       DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
372       continue;
373     }
374
375     pw_buf.smb_name = user_name;
376     pw_buf.smb_userid = uidval;
377
378     /*
379      * Now get the password value - this should be 32 hex digits
380      * which are the ascii representations of a 16 byte string.
381      * Get two at a time and put them into the password.
382      */
383
384     /* Skip the ':' */
385     p++;
386
387     if (*p == '*' || *p == 'X') {
388       /* Password deliberately invalid - end here. */
389       DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
390       pw_buf.smb_nt_passwd = NULL;
391       pw_buf.smb_passwd = NULL;
392       pw_buf.acct_ctrl |= ACB_DISABLED;
393       return &pw_buf;
394     }
395
396     if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
397       DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
398       continue;
399     }
400
401     if (p[32] != ':') {
402       DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
403       continue;
404     }
405
406     if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
407       pw_buf.smb_passwd = NULL;
408       pw_buf.acct_ctrl |= ACB_PWNOTREQ;
409     } else {
410       if (!pdb_gethexpwd((char *)p, smbpwd)) {
411         DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
412         continue;
413       }
414       pw_buf.smb_passwd = smbpwd;
415     }
416
417     /* 
418      * Now check if the NT compatible password is
419      * available.
420      */
421     pw_buf.smb_nt_passwd = NULL;
422
423     p += 33; /* Move to the first character of the line after
424                 the lanman password. */
425     if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
426       if (*p != '*' && *p != 'X') {
427         if(pdb_gethexpwd((char *)p,smbntpwd))
428           pw_buf.smb_nt_passwd = smbntpwd;
429       }
430       p += 33; /* Move to the first character of the line after
431                   the NT password. */
432     }
433
434     DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
435              user_name, uidval));
436
437     if (*p == '[')
438         {
439       unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
440       pw_buf.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
441
442       /* Must have some account type set. */
443       if(pw_buf.acct_ctrl == 0)
444         pw_buf.acct_ctrl = ACB_NORMAL;
445
446       /* Now try and get the last change time. */
447       if(end_p)
448         p = end_p + 1;
449       if(*p == ':') {
450         p++;
451         if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
452           int i;
453           p += 4;
454           for(i = 0; i < 8; i++) {
455             if(p[i] == '\0' || !isxdigit(p[i]))
456               break;
457           }
458           if(i == 8) {
459             /*
460              * p points at 8 characters of hex digits - 
461              * read into a time_t as the seconds since
462              * 1970 that the password was last changed.
463              */
464             pw_buf.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
465           }
466         }
467       }
468     } else {
469       /* 'Old' style file. Fake up based on user name. */
470       /*
471        * Currently trust accounts are kept in the same
472        * password file as 'normal accounts'. If this changes
473        * we will have to fix this code. JRA.
474        */
475       if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
476         pw_buf.acct_ctrl &= ~ACB_NORMAL;
477         pw_buf.acct_ctrl |= ACB_WSTRUST;
478       }
479     }
480
481     return &pw_buf;
482   }
483
484   DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
485   return NULL;
486 }
487
488 /************************************************************************
489  Create a new smbpasswd entry - malloced space returned.
490 *************************************************************************/
491
492 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
493 {
494   int new_entry_length;
495   char *new_entry;
496   char *p;
497   int i;
498
499   new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
500
501   if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
502     DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
503     return NULL;
504   }
505
506   slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
507   p = &new_entry[strlen(new_entry)];
508
509   if(newpwd->smb_passwd != NULL) {
510     for( i = 0; i < 16; i++) {
511       slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
512     }
513   } else {
514     i=0;
515     if(newpwd->acct_ctrl & ACB_PWNOTREQ)
516       safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
517     else
518       safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
519   }
520   
521   p += 32;
522
523   *p++ = ':';
524
525   if(newpwd->smb_nt_passwd != NULL) {
526     for( i = 0; i < 16; i++) {
527       slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
528     }
529   } else {
530     if(newpwd->acct_ctrl & ACB_PWNOTREQ)
531       safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
532     else
533       safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
534   }
535
536   p += 32;
537
538   *p++ = ':';
539
540   /* Add the account encoding and the last change time. */
541   slprintf((char *)p, new_entry_length - 1 - (p - new_entry),  "%s:LCT-%08X:\n",
542            pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
543            (uint32)newpwd->pass_last_set_time);
544
545   return new_entry;
546 }
547
548 /************************************************************************
549  Routine to add an entry to the smbpasswd file.
550 *************************************************************************/
551
552 static BOOL add_smbfilepwd_entry(const struct smb_passwd *newpwd)
553 {
554   char *pfile = lp_smb_passwd_file();
555   struct smb_passwd *pwd = NULL;
556   FILE *fp = NULL;
557   int wr_len;
558   int fd;
559   size_t new_entry_length;
560   char *new_entry;
561   SMB_OFF_T offpos;
562
563   /* Open the smbpassword file - for update. */
564   fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
565
566   if (fp == NULL && errno == ENOENT) {
567         /* Try again - create. */
568         fp = startsmbfilepwent(pfile, PWF_CREATE, &pw_file_lock_depth);
569   }
570
571   if (fp == NULL) {
572     DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
573     return False;
574   }
575
576   /*
577    * Scan the file, a line at a time and check if the name matches.
578    */
579
580   while ((pwd = getsmbfilepwent(fp)) != NULL) 
581   {
582     if (strequal(newpwd->smb_name, pwd->smb_name)) 
583     {
584         DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
585         endsmbfilepwent(fp, &pw_file_lock_depth);
586         return False;
587     }
588   }
589
590   /* Ok - entry doesn't exist. We can add it */
591
592   /* Create a new smb passwd entry and set it to the given password. */
593   /* 
594    * The add user write needs to be atomic - so get the fd from 
595    * the fp and do a raw write() call.
596    */
597   fd = fileno(fp);
598
599   if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) 
600   {
601         DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
602 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
603         endsmbfilepwent(fp, &pw_file_lock_depth);
604         return False;
605   }
606
607   if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) 
608   {
609         DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
610 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
611         endsmbfilepwent(fp, &pw_file_lock_depth);
612         return False;
613   }
614
615   new_entry_length = strlen(new_entry);
616
617 #ifdef DEBUG_PASSWORD
618   DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", 
619                              fd, new_entry_length, new_entry));
620 #endif
621
622   if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) 
623   {
624         DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
625 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
626
627         /* Remove the entry we just wrote. */
628         if(sys_ftruncate(fd, offpos) == -1) 
629         {
630                 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
631 Error was %s. Password file may be corrupt ! Please examine by hand !\n", 
632                 newpwd->smb_name, strerror(errno)));
633         }
634
635         endsmbfilepwent(fp, &pw_file_lock_depth);
636         free(new_entry);
637         return False;
638   }
639
640   free(new_entry);
641   endsmbfilepwent(fp, &pw_file_lock_depth);
642   return True;
643 }
644
645 /************************************************************************
646  Routine to search the smbpasswd file for an entry matching the username.
647  and then modify its password entry. We can't use the startsmbpwent()/
648  getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
649  in the actual file to decide how much room we have to write data.
650  override = False, normal
651  override = True, override XXXXXXXX'd out password or NO PASS
652 ************************************************************************/
653
654 static BOOL mod_smbfilepwd_entry(const struct smb_passwd* pwd, BOOL override)
655 {
656   /* Static buffers we will return. */
657   static pstring  user_name;
658
659   char            linebuf[256];
660   char            readbuf[1024];
661   unsigned char   c;
662   fstring         ascii_p16;
663   fstring         encode_bits;
664   unsigned char  *p = NULL;
665   size_t            linebuf_len = 0;
666   FILE           *fp;
667   int             lockfd;
668   char           *pfile = lp_smb_passwd_file();
669   BOOL found_entry = False;
670   BOOL got_pass_last_set_time = False;
671
672   SMB_OFF_T pwd_seekpos = 0;
673
674   int i;
675   int wr_len;
676   int fd;
677
678   if (!*pfile) {
679     DEBUG(0, ("No SMB password file set\n"));
680     return False;
681   }
682   DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
683
684   fp = sys_fopen(pfile, "r+");
685
686   if (fp == NULL) {
687     DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
688     return False;
689   }
690   /* Set a buffer to do more efficient reads */
691   setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
692
693   lockfd = fileno(fp);
694
695   if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
696     DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
697     fclose(fp);
698     return False;
699   }
700
701   /* Make sure it is only rw by the owner */
702   chmod(pfile, 0600);
703
704   /* We have a write lock on the file. */
705   /*
706    * Scan the file, a line at a time and check if the name matches.
707    */
708   while (!feof(fp)) {
709     pwd_seekpos = sys_ftell(fp);
710
711     linebuf[0] = '\0';
712
713     fgets(linebuf, sizeof(linebuf), fp);
714     if (ferror(fp)) {
715       pw_file_unlock(lockfd, &pw_file_lock_depth);
716       fclose(fp);
717       return False;
718     }
719
720     /*
721      * Check if the string is terminated with a newline - if not
722      * then we must keep reading and discard until we get one.
723      */
724     linebuf_len = strlen(linebuf);
725     if (linebuf[linebuf_len - 1] != '\n') {
726       c = '\0';
727       while (!ferror(fp) && !feof(fp)) {
728         c = fgetc(fp);
729         if (c == '\n') {
730           break;
731         }
732       }
733     } else {
734       linebuf[linebuf_len - 1] = '\0';
735     }
736
737 #ifdef DEBUG_PASSWORD
738     DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
739 #endif
740
741     if ((linebuf[0] == 0) && feof(fp)) {
742       DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
743       break;
744     }
745
746     /*
747      * The line we have should be of the form :-
748      * 
749      * username:uid:[32hex bytes]:....other flags presently
750      * ignored....
751      * 
752      * or,
753      *
754      * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
755      *
756      * if Windows NT compatible passwords are also present.
757      */
758
759     if (linebuf[0] == '#' || linebuf[0] == '\0') {
760       DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
761       continue;
762     }
763
764     p = (unsigned char *) strchr_m(linebuf, ':');
765
766     if (p == NULL) {
767       DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
768       continue;
769     }
770
771     /*
772      * As 256 is shorter than a pstring we don't need to check
773      * length here - if this ever changes....
774      */
775     strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
776     user_name[PTR_DIFF(p, linebuf)] = '\0';
777     if (strequal(user_name, pwd->smb_name)) {
778       found_entry = True;
779       break;
780     }
781   }
782
783   if (!found_entry) {
784     pw_file_unlock(lockfd, &pw_file_lock_depth);
785     fclose(fp);
786     return False;
787   }
788
789   DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
790
791   /* User name matches - get uid and password */
792   p++;          /* Go past ':' */
793
794   if (!isdigit(*p)) {
795     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
796     pw_file_unlock(lockfd, &pw_file_lock_depth);
797     fclose(fp);
798     return False;
799   }
800
801   while (*p && isdigit(*p))
802     p++;
803   if (*p != ':') {
804     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
805     pw_file_unlock(lockfd, &pw_file_lock_depth);
806     fclose(fp);
807     return False;
808   }
809
810   /*
811    * Now get the password value - this should be 32 hex digits
812    * which are the ascii representations of a 16 byte string.
813    * Get two at a time and put them into the password.
814    */
815   p++;
816
817   /* Record exact password position */
818   pwd_seekpos += PTR_DIFF(p, linebuf);
819
820   if (!override && (*p == '*' || *p == 'X')) {
821     /* Password deliberately invalid - end here. */
822     DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
823     pw_file_unlock(lockfd, &pw_file_lock_depth);
824     fclose(fp);
825     return False;
826   }
827
828   if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
829     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
830     pw_file_unlock(lockfd,&pw_file_lock_depth);
831     fclose(fp);
832     return (False);
833   }
834
835   if (p[32] != ':') {
836     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
837     pw_file_unlock(lockfd,&pw_file_lock_depth);
838     fclose(fp);
839     return False;
840   }
841
842   if (!override && (*p == '*' || *p == 'X')) {
843     pw_file_unlock(lockfd,&pw_file_lock_depth);
844     fclose(fp);
845     return False;
846   }
847
848   /* Now check if the NT compatible password is
849      available. */
850   p += 33; /* Move to the first character of the line after
851               the lanman password. */
852   if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
853     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
854     pw_file_unlock(lockfd,&pw_file_lock_depth);
855     fclose(fp);
856     return (False);
857   }
858
859   if (p[32] != ':') {
860     DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
861     pw_file_unlock(lockfd,&pw_file_lock_depth);
862     fclose(fp);
863     return False;
864   }
865
866   /* 
867    * Now check if the account info and the password last
868    * change time is available.
869    */
870   p += 33; /* Move to the first character of the line after
871               the NT password. */
872
873   if (*p == '[') {
874
875     i = 0;
876     encode_bits[i++] = *p++;
877     while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
878       encode_bits[i++] = *p++;
879
880     encode_bits[i++] = ']';
881     encode_bits[i++] = '\0';
882
883     if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
884       /*
885        * We are using a new format, space padded
886        * acct ctrl field. Encode the given acct ctrl
887        * bits into it.
888        */
889       fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
890     } else {
891             DEBUG(0,("mod_smbfilepwd_entry:  Using old smbpasswd format.  This is no longer supported.!\n"));
892             DEBUG(0,("mod_smbfilepwd_entry:  No changes made, failing.!\n"));
893             return False;
894     }
895
896     /* Go past the ']' */
897     if(linebuf_len > PTR_DIFF(p, linebuf))
898       p++;
899
900     if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
901       p++;
902
903       /* We should be pointing at the LCT entry. */
904       if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
905
906         p += 4;
907         for(i = 0; i < 8; i++) {
908           if(p[i] == '\0' || !isxdigit(p[i]))
909             break;
910         }
911         if(i == 8) {
912           /*
913            * p points at 8 characters of hex digits -
914            * read into a time_t as the seconds since
915            * 1970 that the password was last changed.
916            */
917           got_pass_last_set_time = True;
918         } /* i == 8 */
919       } /* *p && StrnCaseCmp() */
920     } /* p == ':' */
921   } /* p == '[' */
922
923   /* Entry is correctly formed. */
924
925   /* Create the 32 byte representation of the new p16 */
926   if(pwd->smb_passwd != NULL) {
927     for (i = 0; i < 16; i++) {
928       slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
929     }
930   } else {
931     if(pwd->acct_ctrl & ACB_PWNOTREQ)
932       fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
933     else
934       fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
935   }
936
937   /* Add on the NT md4 hash */
938   ascii_p16[32] = ':';
939   wr_len = 66;
940   if (pwd->smb_nt_passwd != NULL) {
941     for (i = 0; i < 16; i++) {
942       slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
943     }
944   } else {
945     if(pwd->acct_ctrl & ACB_PWNOTREQ)
946       fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
947     else
948       fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
949   }
950   ascii_p16[65] = ':';
951   ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
952
953   /* Add on the account info bits and the time of last
954      password change. */
955
956   if(got_pass_last_set_time) {
957     slprintf(&ascii_p16[strlen(ascii_p16)], 
958              sizeof(ascii_p16)-(strlen(ascii_p16)+1),
959              "%s:LCT-%08X:", 
960                      encode_bits, (uint32)pwd->pass_last_set_time );
961     wr_len = strlen(ascii_p16);
962   }
963
964 #ifdef DEBUG_PASSWORD
965   DEBUG(100,("mod_smbfilepwd_entry: "));
966   dump_data(100, ascii_p16, wr_len);
967 #endif
968
969   if(wr_len > sizeof(linebuf)) {
970     DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
971     pw_file_unlock(lockfd,&pw_file_lock_depth);
972     fclose(fp);
973     return (False);
974   }
975
976   /*
977    * Do an atomic write into the file at the position defined by
978    * seekpos.
979    */
980
981   /* The mod user write needs to be atomic - so get the fd from 
982      the fp and do a raw write() call.
983    */
984
985   fd = fileno(fp);
986
987   if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
988     DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
989     pw_file_unlock(lockfd,&pw_file_lock_depth);
990     fclose(fp);
991     return False;
992   }
993
994   /* Sanity check - ensure the areas we are writing are framed by ':' */
995   if (read(fd, linebuf, wr_len+1) != wr_len+1) {
996     DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
997     pw_file_unlock(lockfd,&pw_file_lock_depth);
998     fclose(fp);
999     return False;
1000   }
1001
1002   if ((linebuf[0] != ':') || (linebuf[wr_len] != ':'))  {
1003     DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
1004     pw_file_unlock(lockfd,&pw_file_lock_depth);
1005     fclose(fp);
1006     return False;
1007   }
1008  
1009   if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
1010     DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1011     pw_file_unlock(lockfd,&pw_file_lock_depth);
1012     fclose(fp);
1013     return False;
1014   }
1015
1016   if (write(fd, ascii_p16, wr_len) != wr_len) {
1017     DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
1018     pw_file_unlock(lockfd,&pw_file_lock_depth);
1019     fclose(fp);
1020     return False;
1021   }
1022
1023   pw_file_unlock(lockfd,&pw_file_lock_depth);
1024   fclose(fp);
1025   return True;
1026 }
1027
1028 /************************************************************************
1029  Routine to delete an entry in the smbpasswd file by name.
1030 *************************************************************************/
1031
1032 static BOOL del_smbfilepwd_entry(const char *name)
1033 {
1034   char *pfile = lp_smb_passwd_file();
1035   pstring pfile2;
1036   struct smb_passwd *pwd = NULL;
1037   FILE *fp = NULL;
1038   FILE *fp_write = NULL;
1039   int pfile2_lockdepth = 0;
1040
1041   slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
1042
1043   /*
1044    * Open the smbpassword file - for update. It needs to be update
1045    * as we need any other processes to wait until we have replaced
1046    * it.
1047    */
1048
1049   if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth)) == NULL) {
1050     DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1051     return False;
1052   }
1053
1054   /*
1055    * Create the replacement password file.
1056    */
1057   if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
1058     DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1059     endsmbfilepwent(fp, &pw_file_lock_depth);
1060     return False;
1061   }
1062
1063   /*
1064    * Scan the file, a line at a time and check if the name matches.
1065    */
1066
1067   while ((pwd = getsmbfilepwent(fp)) != NULL) {
1068     char *new_entry;
1069     size_t new_entry_length;
1070
1071     if (strequal(name, pwd->smb_name)) {
1072       DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
1073       continue;
1074     }
1075
1076     /*
1077      * We need to copy the entry out into the second file.
1078      */
1079
1080     if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) 
1081     {
1082         DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1083 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1084         unlink(pfile2);
1085         endsmbfilepwent(fp, &pw_file_lock_depth);
1086         endsmbfilepwent(fp_write, &pfile2_lockdepth);
1087         return False;
1088     }
1089
1090     new_entry_length = strlen(new_entry);
1091
1092     if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) 
1093     {
1094         DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1095 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1096         unlink(pfile2);
1097         endsmbfilepwent(fp, &pw_file_lock_depth);
1098         endsmbfilepwent(fp_write, &pfile2_lockdepth);
1099         free(new_entry);
1100         return False;
1101     }
1102
1103     free(new_entry);
1104   }
1105
1106   /*
1107    * Ensure pfile2 is flushed before rename.
1108    */
1109
1110   if(fflush(fp_write) != 0) 
1111   {
1112         DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
1113         endsmbfilepwent(fp, &pw_file_lock_depth);
1114         endsmbfilepwent(fp_write,&pfile2_lockdepth);
1115         return False;
1116   }
1117
1118   /*
1119    * Do an atomic rename - then release the locks.
1120    */
1121
1122   if(rename(pfile2,pfile) != 0) {
1123     unlink(pfile2);
1124   }
1125   
1126   endsmbfilepwent(fp, &pw_file_lock_depth);
1127   endsmbfilepwent(fp_write,&pfile2_lockdepth);
1128   return True;
1129 }
1130
1131 /*********************************************************************
1132  Create a smb_passwd struct from a SAM_ACCOUNT.
1133  We will not allocate any new memory.  The smb_passwd struct
1134  should only stay around as long as the SAM_ACCOUNT does.
1135  ********************************************************************/
1136 static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
1137 {
1138         uid_t *uid;
1139         gid_t *gid;
1140
1141         if (sampass == NULL) 
1142                 return False;
1143         uid = pdb_get_uid(sampass);
1144         gid = pdb_get_gid(sampass);
1145
1146         if (!uid || !gid) {
1147                 DEBUG(0,("build_sam_pass: Failing attempt to store user without a UNIX uid or gid. \n"));
1148                 return False;
1149         }
1150
1151         ZERO_STRUCTP(smb_pw);
1152
1153         smb_pw->smb_userid=*uid;
1154         smb_pw->smb_name=pdb_get_username(sampass);
1155
1156         smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1157         smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1158
1159         smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1160         smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1161
1162         if (*uid != pdb_user_rid_to_uid(pdb_get_user_rid(sampass))) {
1163                 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1164                 return False;
1165         }
1166
1167         if (*gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
1168                 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
1169                 return False;
1170         }
1171
1172         return True;
1173 }       
1174
1175 /*********************************************************************
1176  Create a SAM_ACCOUNT from a smb_passwd struct
1177  ********************************************************************/
1178 static BOOL build_sam_account(SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
1179 {
1180         struct passwd *pwfile;
1181         
1182         if (sam_pass==NULL) {
1183                 DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
1184                 return False;
1185         }
1186                 
1187         /* Verify in system password file...
1188            FIXME!!!  This is where we should look up an internal
1189            mapping of allocated uid for machine accounts as well 
1190            --jerry */ 
1191         pwfile = sys_getpwnam(pw_buf->smb_name);
1192         if (pwfile == NULL) {
1193                 DEBUG(0,("build_sam_account: smbpasswd database is corrupt!  username %s not in unix passwd database!\n", pw_buf->smb_name));
1194                 return False;
1195         }
1196
1197         pdb_set_uid (sam_pass, &pwfile->pw_uid);
1198         pdb_set_gid (sam_pass, &pwfile->pw_gid);
1199
1200         /* FIXME!!  This doesn't belong here.  Should be set in net_sam_logon() 
1201            --jerry */
1202
1203         pstrcpy(samlogon_user, pw_buf->smb_name);
1204         sam_logon_in_ssb = True;
1205                 
1206         pdb_set_fullname(sam_pass, pwfile->pw_gecos);           
1207         
1208         pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
1209
1210         /* should check the group mapping here instead of static mappig. JFM */
1211         pdb_set_group_rid(sam_pass, pdb_gid_to_group_rid(pwfile->pw_gid)); 
1212         
1213         pdb_set_username (sam_pass, pw_buf->smb_name);
1214         pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
1215         pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);                   
1216         pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
1217         pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
1218         pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time);
1219         pdb_set_domain (sam_pass, lp_workgroup());
1220         
1221         pdb_set_dir_drive     (sam_pass, lp_logon_drive());
1222
1223         /* the smbpasswd format doesn't have a must change time field, so
1224            we can't get this right. The best we can do is to set this to 
1225            some time in the future. 21 days seems as reasonable as any other value :) 
1226         */
1227         pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
1228
1229         /* check if this is a user account or a machine account */
1230         if (samlogon_user[strlen(samlogon_user)-1] != '$')
1231         {
1232                 pstring         str;
1233                 
1234                 pstrcpy(str, lp_logon_path());
1235                 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, str);
1236                 pdb_set_profile_path(sam_pass, str);
1237                 
1238                 pstrcpy(str, lp_logon_home());
1239                 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, str);
1240                 pdb_set_homedir(sam_pass, str);
1241                 
1242                 pstrcpy(str, lp_logon_drive());
1243                 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, str);
1244                 pdb_set_dir_drive(sam_pass, str);
1245                 
1246                 pstrcpy(str, lp_logon_script());
1247                 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, str);
1248                 pdb_set_logon_script(sam_pass, str);
1249                 
1250         } else {
1251                 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
1252                 pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS); 
1253         }
1254
1255         sam_logon_in_ssb = False;
1256         
1257         return True;
1258 }
1259 /*****************************************************************
1260  Functions to be implemented by the new passdb API 
1261  ****************************************************************/
1262 BOOL pdb_setsampwent (BOOL update)
1263 {
1264         global_vp = startsmbfilepwent(lp_smb_passwd_file(), 
1265                                 update ? PWF_UPDATE : PWF_READ, 
1266                                 &pw_file_lock_depth);
1267                                    
1268         /* did we fail?  Should we try to create it? */
1269         if (!global_vp && update && errno == ENOENT) 
1270         {
1271                 FILE *fp;
1272                 /* slprintf(msg_str,msg_str_len-1,
1273                         "smbpasswd file did not exist - attempting to create it.\n"); */
1274                 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
1275                 fp = sys_fopen(lp_smb_passwd_file(), "w");
1276                 if (fp) 
1277                 {
1278                         fprintf(fp, "# Samba SMB password file\n");
1279                         fclose(fp);
1280                 }
1281                 
1282                 global_vp = startsmbfilepwent(lp_smb_passwd_file(), 
1283                                         update ? PWF_UPDATE : PWF_READ, 
1284                                         &pw_file_lock_depth);
1285         }
1286         
1287         return (global_vp != NULL);                
1288 }
1289
1290 void pdb_endsampwent (void)
1291 {
1292         endsmbfilepwent(global_vp, &pw_file_lock_depth);
1293 }
1294  
1295 /*****************************************************************
1296  ****************************************************************/
1297 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
1298 {
1299         struct smb_passwd *pw_buf=NULL;
1300         BOOL done = False;
1301         DEBUG(5,("pdb_getsampwent\n"));
1302
1303         if (user==NULL) {
1304                 DEBUG(5,("pdb_getsampwent: user is NULL\n"));
1305 #if 0
1306                 smb_panic("NULL pointer passed to pdb_getsampwent\n");
1307 #endif
1308                 return False;
1309         }
1310
1311         while (!done)
1312         {
1313                 /* do we have an entry? */
1314                 pw_buf = getsmbfilepwent(global_vp);
1315                 if (pw_buf == NULL) 
1316                         return False;
1317
1318                 /* build the SAM_ACCOUNT entry from the smb_passwd struct. 
1319                    We loop in case the user in the pdb does not exist in 
1320                    the local system password file */
1321                 if (build_sam_account(user, pw_buf))
1322                         done = True;
1323         }
1324
1325         DEBUG(5,("pdb_getsampwent:done\n"));
1326
1327         /* success */
1328         return True;
1329 }
1330
1331
1332 /****************************************************************
1333  Search smbpasswd file by iterating over the entries.  Do not
1334  call getpwnam() for unix account information until we have found
1335  the correct entry
1336  ***************************************************************/
1337 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
1338 {
1339         struct smb_passwd *smb_pw;
1340         void *fp = NULL;
1341         char *domain = NULL;
1342         char *user = NULL;
1343         fstring name;
1344
1345         DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
1346
1347         
1348         /* break the username from the domain if we have 
1349            been given a string in the form 'DOMAIN\user' */
1350         fstrcpy (name, username);
1351         if ((user=strchr_m(name, '\\')) != NULL) {
1352                 domain = name;
1353                 *user = '\0';
1354                 user++;
1355         }
1356         
1357         /* if a domain was specified and it wasn't ours
1358            then there is no chance of matching */
1359         if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
1360                 return False;
1361
1362         /* startsmbfilepwent() is used here as we don't want to lookup
1363            the UNIX account in the local system password file until
1364            we have a match.  */
1365         fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1366
1367         if (fp == NULL) {
1368                 DEBUG(0, ("unable to open passdb database.\n"));
1369                 return False;
1370         }
1371
1372         /* if we have a domain name, then we should map it to a UNIX 
1373            username first */
1374         if ( domain )
1375                 map_username(user);
1376
1377         while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1378                 /* do nothing....another loop */ ;
1379         
1380         endsmbfilepwent(fp, &pw_file_lock_depth);
1381
1382
1383         /* did we locate the username in smbpasswd  */
1384         if (smb_pw == NULL)
1385                 return False;
1386         
1387         DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
1388
1389         if (!sam_acct) {
1390                 DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
1391 #if 0
1392                 smb_panic("NULL pointer passed to pdb_getsampwnam\n");
1393 #endif
1394                 return False;
1395         }
1396                 
1397         /* now build the SAM_ACCOUNT */
1398         if (!build_sam_account(sam_acct, smb_pw))
1399                 return False;
1400
1401         /* success */
1402         return True;
1403 }
1404
1405
1406 BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
1407 {
1408         struct smb_passwd *smb_pw;
1409         void *fp = NULL;
1410
1411         DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", uid));
1412
1413         /* Open the sam password file - not for update. */
1414         fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1415
1416         if (fp == NULL) {
1417                 DEBUG(0, ("unable to open passdb database.\n"));
1418                 return False;
1419         }
1420
1421         while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
1422                 /* do nothing */ ;
1423
1424         endsmbfilepwent(fp, &pw_file_lock_depth);
1425
1426         /* did we locate the username in smbpasswd  */
1427         if (smb_pw == NULL)
1428                 return False;
1429         
1430         DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
1431                 
1432         if (!sam_acct) {
1433                 DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
1434 #if 0
1435                 smb_panic("NULL pointer passed to pdb_getsampwuid\n");
1436 #endif
1437                 return False;
1438         }
1439
1440         /* now build the SAM_ACCOUNT */
1441         if (!build_sam_account(sam_acct, smb_pw))
1442                 return False;
1443
1444         /* success */
1445         return True;
1446 }
1447
1448 BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
1449 {
1450         struct smb_passwd *smb_pw;
1451         void *fp = NULL;
1452
1453         DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
1454
1455         /* Open the sam password file - not for update. */
1456         fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1457
1458         if (fp == NULL) {
1459                 DEBUG(0, ("unable to open passdb database.\n"));
1460                 return False;
1461         }
1462
1463         while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1464                 /* do nothing */ ;
1465
1466         endsmbfilepwent(fp, &pw_file_lock_depth);
1467
1468
1469         /* did we locate the username in smbpasswd  */
1470         if (smb_pw == NULL)
1471                 return False;
1472         
1473         DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
1474                 
1475         if (!sam_acct) {
1476                 DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
1477 #if 0
1478                 smb_panic("NULL pointer passed to pdb_getsampwrid\n");
1479 #endif
1480                 return False;
1481         }
1482
1483         /* now build the SAM_ACCOUNT */
1484         if (!build_sam_account (sam_acct, smb_pw))
1485                 return False;
1486
1487         /* success */
1488         return True;
1489 }
1490
1491 BOOL pdb_add_sam_account(const SAM_ACCOUNT *sampass)
1492 {
1493         struct smb_passwd smb_pw;
1494         
1495         /* convert the SAM_ACCOUNT */
1496         if (!build_smb_pass(&smb_pw, sampass)) {
1497                 return False;
1498         }
1499         
1500         /* add the entry */
1501         if(!add_smbfilepwd_entry(&smb_pw)) {
1502                 return False;
1503         }
1504
1505         return True;
1506 }
1507
1508 BOOL pdb_update_sam_account(const SAM_ACCOUNT *sampass, BOOL override)
1509 {
1510         struct smb_passwd smb_pw;
1511         
1512         /* convert the SAM_ACCOUNT */
1513         build_smb_pass(&smb_pw, sampass);
1514         
1515         /* update the entry */
1516         if(!mod_smbfilepwd_entry(&smb_pw, override))
1517                 return False;
1518                 
1519         return True;
1520 }
1521
1522 BOOL pdb_delete_sam_account (const char* username)
1523 {
1524         return del_smbfilepwd_entry(username);
1525 }
1526
1527 #else
1528  /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1529  void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1530 #endif /* WTH_SMBPASSWD_SAM*/
1531