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