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