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