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