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