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