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