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