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