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,2003
7 * Modified by Andrew Bartlett 2002.
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 3 of the License, or (at your option)
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
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "../librpc/gen_ndr/samr.h"
25 #include "../libcli/security/security.h"
28 #define DBGC_CLASS DBGC_PASSDB
31 smb_passwd is analogous to sam_passwd used everywhere
32 else. However, smb_passwd is limited to the information
33 stored by an smbpasswd entry
38 uint32 smb_userid
; /* this is actually the unix uid_t */
39 const char *smb_name
; /* username string */
41 const unsigned char *smb_passwd
; /* Null if no password */
42 const unsigned char *smb_nt_passwd
; /* Null if no password */
44 uint16_t acct_ctrl
; /* account info (ACB_xxxx bit-mask) */
45 time_t pass_last_set_time
; /* password last set time */
48 struct smbpasswd_privates
50 /* used for maintain locks on the smbpasswd file */
51 int pw_file_lock_depth
;
53 /* Global File pointer */
56 /* formerly static variables */
57 struct smb_passwd pw_buf
;
59 unsigned char smbpwd
[16];
60 unsigned char smbntpwd
[16];
62 /* retrive-once info */
63 const char *smbpasswd_file
;
66 enum pwf_access_type
{ PWF_READ
, PWF_UPDATE
, PWF_CREATE
};
68 static SIG_ATOMIC_T gotalarm
;
70 /***************************************************************
71 Signal function to tell us we timed out.
72 ****************************************************************/
74 static void gotalarm_sig(int signum
)
79 /***************************************************************
80 Lock or unlock a fd for a known lock type. Abandon after waitsecs
82 ****************************************************************/
84 static bool do_file_lock(int fd
, int waitsecs
, int type
)
86 SMB_STRUCT_FLOCK lock
;
88 void (*oldsig_handler
)(int);
91 oldsig_handler
= CatchSignal(SIGALRM
, gotalarm_sig
);
94 lock
.l_whence
= SEEK_SET
;
100 /* Note we must *NOT* use sys_fcntl here ! JRA */
101 ret
= fcntl(fd
, SMB_F_SETLKW
, &lock
);
103 CatchSignal(SIGALRM
, oldsig_handler
);
105 if (gotalarm
&& ret
== -1) {
106 DEBUG(0, ("do_file_lock: failed to %s file.\n",
107 type
== F_UNLCK
? "unlock" : "lock"));
114 /***************************************************************
115 Lock an fd. Abandon after waitsecs seconds.
116 ****************************************************************/
118 static bool pw_file_lock(int fd
, int type
, int secs
, int *plock_depth
)
124 if(*plock_depth
== 0) {
125 if (!do_file_lock(fd
, secs
, type
)) {
126 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
137 /***************************************************************
138 Unlock an fd. Abandon after waitsecs seconds.
139 ****************************************************************/
141 static bool pw_file_unlock(int fd
, int *plock_depth
)
145 if (fd
== 0 || *plock_depth
== 0) {
149 if(*plock_depth
== 1) {
150 ret
= do_file_lock(fd
, 5, F_UNLCK
);
153 if (*plock_depth
> 0) {
158 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
164 /**************************************************************
165 Intialize a smb_passwd struct
166 *************************************************************/
168 static void pdb_init_smb(struct smb_passwd
*user
)
174 user
->pass_last_set_time
= (time_t)0;
177 /***************************************************************
178 Internal fn to enumerate the smbpasswd list. Returns a void pointer
179 to ensure no modification outside this module. Checks for atomic
180 rename of smbpasswd file on update or create once the lock has
181 been granted to prevent race conditions. JRA.
182 ****************************************************************/
184 static FILE *startsmbfilepwent(const char *pfile
, enum pwf_access_type type
, int *lock_depth
)
187 const char *open_mode
= NULL
;
189 int lock_type
= F_RDLCK
;
192 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
207 * Ensure atomic file creation.
212 for(i
= 0; i
< 5; i
++) {
213 if((fd
= sys_open(pfile
, O_CREAT
|O_TRUNC
|O_EXCL
|O_RDWR
, 0600))!=-1) {
216 sys_usleep(200); /* Spin, spin... */
219 DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
220 creating file %s\n", pfile
));
230 for(race_loop
= 0; race_loop
< 5; race_loop
++) {
231 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile
));
233 if((fp
= sys_fopen(pfile
, open_mode
)) == NULL
) {
236 * If smbpasswd file doesn't exist, then create new one. This helps to avoid
237 * confusing error msg when adding user account first time.
239 if (errno
== ENOENT
) {
240 if ((fp
= sys_fopen(pfile
, "a+")) != NULL
) {
241 DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
242 exist. File successfully created.\n", pfile
));
244 DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
245 exist. Couldn't create new one. Error was: %s",
246 pfile
, strerror(errno
)));
250 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
251 Error was: %s\n", pfile
, strerror(errno
)));
256 if (!pw_file_lock(fileno(fp
), lock_type
, 5, lock_depth
)) {
257 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
258 Error was %s\n", pfile
, strerror(errno
) ));
264 * Only check for replacement races on update or create.
265 * For read we don't mind if the data is one record out of date.
268 if(type
== PWF_READ
) {
271 SMB_STRUCT_STAT sbuf1
, sbuf2
;
274 * Avoid the potential race condition between the open and the lock
275 * by doing a stat on the filename and an fstat on the fd. If the
276 * two inodes differ then someone did a rename between the open and
277 * the lock. Back off and try the open again. Only do this 5 times to
278 * prevent infinate loops. JRA.
281 if (sys_stat(pfile
, &sbuf1
, false) != 0) {
282 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
283 Error was %s\n", pfile
, strerror(errno
)));
284 pw_file_unlock(fileno(fp
), lock_depth
);
289 if (sys_fstat(fileno(fp
), &sbuf2
, false) != 0) {
290 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
291 Error was %s\n", pfile
, strerror(errno
)));
292 pw_file_unlock(fileno(fp
), lock_depth
);
297 if( sbuf1
.st_ex_ino
== sbuf2
.st_ex_ino
) {
303 * Race occurred - back off and try again...
306 pw_file_unlock(fileno(fp
), lock_depth
);
312 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile
));
316 /* Set a buffer to do more efficient reads */
317 setvbuf(fp
, (char *)NULL
, _IOFBF
, 1024);
319 /* Make sure it is only rw by the owner */
321 if(fchmod(fileno(fp
), S_IRUSR
|S_IWUSR
) == -1) {
323 if(chmod(pfile
, S_IRUSR
|S_IWUSR
) == -1) {
325 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
326 Error was %s\n.", pfile
, strerror(errno
) ));
327 pw_file_unlock(fileno(fp
), lock_depth
);
332 /* We have a lock on the file. */
336 /***************************************************************
337 End enumeration of the smbpasswd list.
338 ****************************************************************/
340 static void endsmbfilepwent(FILE *fp
, int *lock_depth
)
346 pw_file_unlock(fileno(fp
), lock_depth
);
348 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
351 /*************************************************************************
352 Routine to return the next entry in the smbpasswd list.
353 *************************************************************************/
355 static struct smb_passwd
*getsmbfilepwent(struct smbpasswd_privates
*smbpasswd_state
, FILE *fp
)
357 /* Static buffers we will return. */
358 struct smb_passwd
*pw_buf
= &smbpasswd_state
->pw_buf
;
359 char *user_name
= smbpasswd_state
->user_name
;
360 unsigned char *smbpwd
= smbpasswd_state
->smbpwd
;
361 unsigned char *smbntpwd
= smbpasswd_state
->smbntpwd
;
370 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
374 pdb_init_smb(pw_buf
);
375 pw_buf
->acct_ctrl
= ACB_NORMAL
;
378 * Scan the file, a line at a time and check if the name matches.
381 while (status
&& !feof(fp
)) {
384 status
= fgets(linebuf
, 256, fp
);
385 if (status
== NULL
&& ferror(fp
)) {
390 * Check if the string is terminated with a newline - if not
391 * then we must keep reading and discard until we get one.
393 if ((linebuf_len
= strlen(linebuf
)) == 0) {
397 if (linebuf
[linebuf_len
- 1] != '\n') {
399 while (!ferror(fp
) && !feof(fp
)) {
406 linebuf
[linebuf_len
- 1] = '\0';
409 #ifdef DEBUG_PASSWORD
410 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf
));
412 if ((linebuf
[0] == 0) && feof(fp
)) {
413 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
418 * The line we have should be of the form :-
420 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
425 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
427 * if Windows NT compatible passwords are also present.
428 * [Account type] is an ascii encoding of the type of account.
429 * LCT-(8 hex digits) is the time_t value of the last change time.
432 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
433 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
436 p
= (unsigned char *) strchr_m(linebuf
, ':');
438 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
442 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
443 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
447 p
++; /* Go past ':' */
450 DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name
));
455 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
460 uidval
= atoi((char *) p
);
462 while (*p
&& isdigit(*p
)) {
467 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
472 pw_buf
->smb_name
= user_name
;
473 pw_buf
->smb_userid
= uidval
;
476 * Now get the password value - this should be 32 hex digits
477 * which are the ascii representations of a 16 byte string.
478 * Get two at a time and put them into the password.
484 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
485 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
491 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
496 if (strnequal((char *) p
, "NO PASSWORD", 11)) {
497 pw_buf
->smb_passwd
= NULL
;
498 pw_buf
->acct_ctrl
|= ACB_PWNOTREQ
;
500 if (*p
== '*' || *p
== 'X') {
501 /* NULL LM password */
502 pw_buf
->smb_passwd
= NULL
;
503 DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name
));
504 } else if (pdb_gethexpwd((char *)p
, smbpwd
)) {
505 pw_buf
->smb_passwd
= smbpwd
;
507 pw_buf
->smb_passwd
= NULL
;
508 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
509 (non hex chars)\n", user_name
));
514 * Now check if the NT compatible password is
517 pw_buf
->smb_nt_passwd
= NULL
;
518 p
+= 33; /* Move to the first character of the line after the lanman password. */
519 if ((linebuf_len
>= (PTR_DIFF(p
, linebuf
) + 33)) && (p
[32] == ':')) {
520 if (*p
!= '*' && *p
!= 'X') {
521 if(pdb_gethexpwd((char *)p
,smbntpwd
)) {
522 pw_buf
->smb_nt_passwd
= smbntpwd
;
525 p
+= 33; /* Move to the first character of the line after the NT password. */
528 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
532 unsigned char *end_p
= (unsigned char *)strchr_m((char *)p
, ']');
533 pw_buf
->acct_ctrl
= pdb_decode_acct_ctrl((char*)p
);
535 /* Must have some account type set. */
536 if(pw_buf
->acct_ctrl
== 0) {
537 pw_buf
->acct_ctrl
= ACB_NORMAL
;
540 /* Now try and get the last change time. */
546 if(*p
&& (StrnCaseCmp((char *)p
, "LCT-", 4)==0)) {
549 for(i
= 0; i
< 8; i
++) {
550 if(p
[i
] == '\0' || !isxdigit(p
[i
])) {
556 * p points at 8 characters of hex digits -
557 * read into a time_t as the seconds since
558 * 1970 that the password was last changed.
560 pw_buf
->pass_last_set_time
= (time_t)strtol((char *)p
, NULL
, 16);
565 /* 'Old' style file. Fake up based on user name. */
567 * Currently trust accounts are kept in the same
568 * password file as 'normal accounts'. If this changes
569 * we will have to fix this code. JRA.
571 if(pw_buf
->smb_name
[strlen(pw_buf
->smb_name
) - 1] == '$') {
572 pw_buf
->acct_ctrl
&= ~ACB_NORMAL
;
573 pw_buf
->acct_ctrl
|= ACB_WSTRUST
;
580 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
584 /************************************************************************
585 Create a new smbpasswd entry - malloced space returned.
586 *************************************************************************/
588 static char *format_new_smbpasswd_entry(const struct smb_passwd
*newpwd
)
590 int new_entry_length
;
594 new_entry_length
= strlen(newpwd
->smb_name
) + 1 + 15 + 1 + 32 + 1 + 32 + 1 +
595 NEW_PW_FORMAT_SPACE_PADDED_LEN
+ 1 + 13 + 2;
597 if((new_entry
= (char *)SMB_MALLOC( new_entry_length
)) == NULL
) {
598 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
603 slprintf(new_entry
, new_entry_length
- 1, "%s:%u:", newpwd
->smb_name
, (unsigned)newpwd
->smb_userid
);
605 p
= new_entry
+strlen(new_entry
);
606 pdb_sethexpwd(p
, newpwd
->smb_passwd
, newpwd
->acct_ctrl
);
611 pdb_sethexpwd(p
, newpwd
->smb_nt_passwd
, newpwd
->acct_ctrl
);
616 /* Add the account encoding and the last change time. */
617 slprintf((char *)p
, new_entry_length
- 1 - (p
- new_entry
), "%s:LCT-%08X:\n",
618 pdb_encode_acct_ctrl(newpwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
),
619 (uint32_t)newpwd
->pass_last_set_time
);
624 /************************************************************************
625 Routine to add an entry to the smbpasswd file.
626 *************************************************************************/
628 static NTSTATUS
add_smbfilepwd_entry(struct smbpasswd_privates
*smbpasswd_state
,
629 struct smb_passwd
*newpwd
)
631 const char *pfile
= smbpasswd_state
->smbpasswd_file
;
632 struct smb_passwd
*pwd
= NULL
;
636 size_t new_entry_length
;
640 /* Open the smbpassword file - for update. */
641 fp
= startsmbfilepwent(pfile
, PWF_UPDATE
, &smbpasswd_state
->pw_file_lock_depth
);
643 if (fp
== NULL
&& errno
== ENOENT
) {
644 /* Try again - create. */
645 fp
= startsmbfilepwent(pfile
, PWF_CREATE
, &smbpasswd_state
->pw_file_lock_depth
);
649 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
650 return map_nt_error_from_unix(errno
);
654 * Scan the file, a line at a time and check if the name matches.
657 while ((pwd
= getsmbfilepwent(smbpasswd_state
, fp
)) != NULL
) {
658 if (strequal(newpwd
->smb_name
, pwd
->smb_name
)) {
659 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd
->smb_name
));
660 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
661 return NT_STATUS_USER_EXISTS
;
665 /* Ok - entry doesn't exist. We can add it */
667 /* Create a new smb passwd entry and set it to the given password. */
669 * The add user write needs to be atomic - so get the fd from
670 * the fp and do a raw write() call.
674 if((offpos
= sys_lseek(fd
, 0, SEEK_END
)) == -1) {
675 NTSTATUS result
= map_nt_error_from_unix(errno
);
676 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
677 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
678 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
682 if((new_entry
= format_new_smbpasswd_entry(newpwd
)) == NULL
) {
683 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
684 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
685 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
686 return NT_STATUS_NO_MEMORY
;
689 new_entry_length
= strlen(new_entry
);
691 #ifdef DEBUG_PASSWORD
692 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
693 fd
, (int)new_entry_length
, new_entry
));
696 if ((wr_len
= write(fd
, new_entry
, new_entry_length
)) != new_entry_length
) {
697 NTSTATUS result
= map_nt_error_from_unix(errno
);
698 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
699 Error was %s\n", wr_len
, newpwd
->smb_name
, pfile
, strerror(errno
)));
701 /* Remove the entry we just wrote. */
702 if(sys_ftruncate(fd
, offpos
) == -1) {
703 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
704 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
705 newpwd
->smb_name
, strerror(errno
)));
708 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
714 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
718 /************************************************************************
719 Routine to search the smbpasswd file for an entry matching the username.
720 and then modify its password entry. We can't use the startsmbpwent()/
721 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
722 in the actual file to decide how much room we have to write data.
723 override = False, normal
724 override = True, override XXXXXXXX'd out password or NO PASS
725 ************************************************************************/
727 static bool mod_smbfilepwd_entry(struct smbpasswd_privates
*smbpasswd_state
, const struct smb_passwd
* pwd
)
729 /* Static buffers we will return. */
738 unsigned char *p
= NULL
;
739 size_t linebuf_len
= 0;
742 const char *pfile
= smbpasswd_state
->smbpasswd_file
;
743 bool found_entry
= False
;
744 bool got_pass_last_set_time
= False
;
746 SMB_OFF_T pwd_seekpos
= 0;
753 DEBUG(0, ("No SMB password file set\n"));
756 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile
));
758 fp
= sys_fopen(pfile
, "r+");
761 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile
));
764 /* Set a buffer to do more efficient reads */
765 setvbuf(fp
, readbuf
, _IOFBF
, sizeof(readbuf
));
769 if (!pw_file_lock(lockfd
, F_WRLCK
, 5, &smbpasswd_state
->pw_file_lock_depth
)) {
770 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile
));
775 /* Make sure it is only rw by the owner */
778 /* We have a write lock on the file. */
780 * Scan the file, a line at a time and check if the name matches.
783 while (status
&& !feof(fp
)) {
784 pwd_seekpos
= sys_ftell(fp
);
788 status
= fgets(linebuf
, sizeof(linebuf
), fp
);
789 if (status
== NULL
&& ferror(fp
)) {
790 pw_file_unlock(lockfd
, &smbpasswd_state
->pw_file_lock_depth
);
796 * Check if the string is terminated with a newline - if not
797 * then we must keep reading and discard until we get one.
799 linebuf_len
= strlen(linebuf
);
800 if (linebuf
[linebuf_len
- 1] != '\n') {
802 while (!ferror(fp
) && !feof(fp
)) {
809 linebuf
[linebuf_len
- 1] = '\0';
812 #ifdef DEBUG_PASSWORD
813 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf
));
816 if ((linebuf
[0] == 0) && feof(fp
)) {
817 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
822 * The line we have should be of the form :-
824 * username:uid:[32hex bytes]:....other flags presently
829 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
831 * if Windows NT compatible passwords are also present.
834 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
835 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
839 p
= (unsigned char *) strchr_m(linebuf
, ':');
842 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
846 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
847 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
848 if (strequal(user_name
, pwd
->smb_name
)) {
855 pw_file_unlock(lockfd
, &smbpasswd_state
->pw_file_lock_depth
);
858 DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
863 DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd
->smb_name
));
865 /* User name matches - get uid and password */
866 p
++; /* Go past ':' */
869 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
871 pw_file_unlock(lockfd
, &smbpasswd_state
->pw_file_lock_depth
);
876 while (*p
&& isdigit(*p
)) {
880 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
882 pw_file_unlock(lockfd
, &smbpasswd_state
->pw_file_lock_depth
);
888 * Now get the password value - this should be 32 hex digits
889 * which are the ascii representations of a 16 byte string.
890 * Get two at a time and put them into the password.
894 /* Record exact password position */
895 pwd_seekpos
+= PTR_DIFF(p
, linebuf
);
897 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
898 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
900 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
906 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
908 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
913 /* Now check if the NT compatible password is available. */
914 p
+= 33; /* Move to the first character of the line after the lanman password. */
915 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
916 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
918 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
924 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
926 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
932 * Now check if the account info and the password last
933 * change time is available.
935 p
+= 33; /* Move to the first character of the line after the NT password. */
939 encode_bits
[i
++] = *p
++;
940 while((linebuf_len
> PTR_DIFF(p
, linebuf
)) && (*p
!= ']')) {
941 encode_bits
[i
++] = *p
++;
944 encode_bits
[i
++] = ']';
945 encode_bits
[i
++] = '\0';
947 if(i
== NEW_PW_FORMAT_SPACE_PADDED_LEN
) {
949 * We are using a new format, space padded
950 * acct ctrl field. Encode the given acct ctrl
953 fstrcpy(encode_bits
, pdb_encode_acct_ctrl(pwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
));
955 DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format for user %s. \
956 This is no longer supported.!\n", pwd
->smb_name
));
957 DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
958 pw_file_unlock(lockfd
, &smbpasswd_state
->pw_file_lock_depth
);
963 /* Go past the ']' */
964 if(linebuf_len
> PTR_DIFF(p
, linebuf
)) {
968 if((linebuf_len
> PTR_DIFF(p
, linebuf
)) && (*p
== ':')) {
971 /* We should be pointing at the LCT entry. */
972 if((linebuf_len
> (PTR_DIFF(p
, linebuf
) + 13)) && (StrnCaseCmp((char *)p
, "LCT-", 4) == 0)) {
974 for(i
= 0; i
< 8; i
++) {
975 if(p
[i
] == '\0' || !isxdigit(p
[i
])) {
981 * p points at 8 characters of hex digits -
982 * read into a time_t as the seconds since
983 * 1970 that the password was last changed.
985 got_pass_last_set_time
= True
;
987 } /* *p && StrnCaseCmp() */
991 /* Entry is correctly formed. */
993 /* Create the 32 byte representation of the new p16 */
994 pdb_sethexpwd(ascii_p16
, pwd
->smb_passwd
, pwd
->acct_ctrl
);
996 /* Add on the NT md4 hash */
999 pdb_sethexpwd(ascii_p16
+33, pwd
->smb_nt_passwd
, pwd
->acct_ctrl
);
1000 ascii_p16
[65] = ':';
1001 ascii_p16
[66] = '\0'; /* null-terminate the string so that strlen works */
1003 /* Add on the account info bits and the time of last password change. */
1004 if(got_pass_last_set_time
) {
1005 slprintf(&ascii_p16
[strlen(ascii_p16
)],
1006 sizeof(ascii_p16
)-(strlen(ascii_p16
)+1),
1008 encode_bits
, (uint32_t)pwd
->pass_last_set_time
);
1009 wr_len
= strlen(ascii_p16
);
1012 #ifdef DEBUG_PASSWORD
1013 DEBUG(100,("mod_smbfilepwd_entry: "));
1014 dump_data(100, (uint8
*)ascii_p16
, wr_len
);
1017 if(wr_len
> sizeof(linebuf
)) {
1018 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len
+1));
1019 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1025 * Do an atomic write into the file at the position defined by
1029 /* The mod user write needs to be atomic - so get the fd from
1030 the fp and do a raw write() call.
1035 if (sys_lseek(fd
, pwd_seekpos
- 1, SEEK_SET
) != pwd_seekpos
- 1) {
1036 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1037 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1042 /* Sanity check - ensure the areas we are writing are framed by ':' */
1043 if (read(fd
, linebuf
, wr_len
+1) != wr_len
+1) {
1044 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile
));
1045 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1050 if ((linebuf
[0] != ':') || (linebuf
[wr_len
] != ':')) {
1051 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile
));
1052 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1057 if (sys_lseek(fd
, pwd_seekpos
, SEEK_SET
) != pwd_seekpos
) {
1058 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1059 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1064 if (write(fd
, ascii_p16
, wr_len
) != wr_len
) {
1065 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile
));
1066 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1071 pw_file_unlock(lockfd
,&smbpasswd_state
->pw_file_lock_depth
);
1076 /************************************************************************
1077 Routine to delete an entry in the smbpasswd file by name.
1078 *************************************************************************/
1080 static bool del_smbfilepwd_entry(struct smbpasswd_privates
*smbpasswd_state
, const char *name
)
1082 const char *pfile
= smbpasswd_state
->smbpasswd_file
;
1083 char *pfile2
= NULL
;
1084 struct smb_passwd
*pwd
= NULL
;
1086 FILE *fp_write
= NULL
;
1087 int pfile2_lockdepth
= 0;
1089 pfile2
= talloc_asprintf(talloc_tos(),
1091 pfile
, (unsigned)sys_getpid());
1097 * Open the smbpassword file - for update. It needs to be update
1098 * as we need any other processes to wait until we have replaced
1102 if((fp
= startsmbfilepwent(pfile
, PWF_UPDATE
, &smbpasswd_state
->pw_file_lock_depth
)) == NULL
) {
1103 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1108 * Create the replacement password file.
1110 if((fp_write
= startsmbfilepwent(pfile2
, PWF_CREATE
, &pfile2_lockdepth
)) == NULL
) {
1111 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1112 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
1117 * Scan the file, a line at a time and check if the name matches.
1120 while ((pwd
= getsmbfilepwent(smbpasswd_state
, fp
)) != NULL
) {
1122 size_t new_entry_length
;
1124 if (strequal(name
, pwd
->smb_name
)) {
1125 DEBUG(10, ("del_smbfilepwd_entry: found entry with "
1126 "name %s - deleting it.\n", name
));
1131 * We need to copy the entry out into the second file.
1134 if((new_entry
= format_new_smbpasswd_entry(pwd
)) == NULL
) {
1135 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1136 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1138 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
1139 endsmbfilepwent(fp_write
, &pfile2_lockdepth
);
1143 new_entry_length
= strlen(new_entry
);
1145 if(fwrite(new_entry
, 1, new_entry_length
, fp_write
) != new_entry_length
) {
1146 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1147 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1149 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
1150 endsmbfilepwent(fp_write
, &pfile2_lockdepth
);
1159 * Ensure pfile2 is flushed before rename.
1162 if(fflush(fp_write
) != 0) {
1163 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2
, strerror(errno
)));
1164 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
1165 endsmbfilepwent(fp_write
,&pfile2_lockdepth
);
1170 * Do an atomic rename - then release the locks.
1173 if(rename(pfile2
,pfile
) != 0) {
1177 endsmbfilepwent(fp
, &smbpasswd_state
->pw_file_lock_depth
);
1178 endsmbfilepwent(fp_write
,&pfile2_lockdepth
);
1182 /*********************************************************************
1183 Create a smb_passwd struct from a struct samu.
1184 We will not allocate any new memory. The smb_passwd struct
1185 should only stay around as long as the struct samu does.
1186 ********************************************************************/
1188 static bool build_smb_pass (struct smb_passwd
*smb_pw
, const struct samu
*sampass
)
1192 if (sampass
== NULL
)
1194 ZERO_STRUCTP(smb_pw
);
1196 if (!IS_SAM_DEFAULT(sampass
, PDB_USERSID
)) {
1197 rid
= pdb_get_user_rid(sampass
);
1199 /* If the user specified a RID, make sure its able to be both stored and retreived */
1200 if (rid
== DOMAIN_RID_GUEST
) {
1201 struct passwd
*passwd
= Get_Pwnam_alloc(NULL
, lp_guestaccount());
1203 DEBUG(0, ("Could not find guest account via Get_Pwnam_alloc()! (%s)\n", lp_guestaccount()));
1206 smb_pw
->smb_userid
=passwd
->pw_uid
;
1207 TALLOC_FREE(passwd
);
1208 } else if (algorithmic_pdb_rid_is_user(rid
)) {
1209 smb_pw
->smb_userid
=algorithmic_pdb_user_rid_to_uid(rid
);
1211 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1216 smb_pw
->smb_name
=(const char*)pdb_get_username(sampass
);
1218 smb_pw
->smb_passwd
=pdb_get_lanman_passwd(sampass
);
1219 smb_pw
->smb_nt_passwd
=pdb_get_nt_passwd(sampass
);
1221 smb_pw
->acct_ctrl
=pdb_get_acct_ctrl(sampass
);
1222 smb_pw
->pass_last_set_time
=pdb_get_pass_last_set_time(sampass
);
1227 /*********************************************************************
1228 Create a struct samu from a smb_passwd struct
1229 ********************************************************************/
1231 static bool build_sam_account(struct smbpasswd_privates
*smbpasswd_state
,
1232 struct samu
*sam_pass
, const struct smb_passwd
*pw_buf
)
1234 struct passwd
*pwfile
;
1237 DEBUG(5,("build_sam_account: struct samu is NULL\n"));
1241 /* verify the user account exists */
1243 if ( !(pwfile
= Get_Pwnam_alloc(NULL
, pw_buf
->smb_name
)) ) {
1244 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid "
1245 "%u is not in unix passwd database!\n", pw_buf
->smb_name
, pw_buf
->smb_userid
));
1249 if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass
, pwfile
)) )
1252 TALLOC_FREE(pwfile
);
1254 /* set remaining fields */
1256 if (!pdb_set_nt_passwd (sam_pass
, pw_buf
->smb_nt_passwd
, PDB_SET
))
1258 if (!pdb_set_lanman_passwd (sam_pass
, pw_buf
->smb_passwd
, PDB_SET
))
1260 pdb_set_acct_ctrl (sam_pass
, pw_buf
->acct_ctrl
, PDB_SET
);
1261 pdb_set_pass_last_set_time (sam_pass
, pw_buf
->pass_last_set_time
, PDB_SET
);
1262 pdb_set_pass_can_change_time (sam_pass
, pw_buf
->pass_last_set_time
, PDB_SET
);
1267 /*****************************************************************
1268 Functions to be implemented by the new passdb API
1269 ****************************************************************/
1271 /****************************************************************
1272 Search smbpasswd file by iterating over the entries. Do not
1273 call getpwnam() for unix account information until we have found
1275 ***************************************************************/
1277 static NTSTATUS
smbpasswd_getsampwnam(struct pdb_methods
*my_methods
,
1278 struct samu
*sam_acct
, const char *username
)
1280 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1281 struct smbpasswd_privates
*smbpasswd_state
= (struct smbpasswd_privates
*)my_methods
->private_data
;
1282 struct smb_passwd
*smb_pw
;
1285 DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username
));
1287 /* startsmbfilepwent() is used here as we don't want to lookup
1288 the UNIX account in the local system password file until
1290 fp
= startsmbfilepwent(smbpasswd_state
->smbpasswd_file
, PWF_READ
, &(smbpasswd_state
->pw_file_lock_depth
));
1293 DEBUG(0, ("Unable to open passdb database.\n"));
1297 while ( ((smb_pw
=getsmbfilepwent(smbpasswd_state
, fp
)) != NULL
)&& (!strequal(smb_pw
->smb_name
, username
)) )
1298 /* do nothing....another loop */ ;
1300 endsmbfilepwent(fp
, &(smbpasswd_state
->pw_file_lock_depth
));
1303 /* did we locate the username in smbpasswd */
1307 DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw
->smb_name
));
1310 DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
1314 /* now build the struct samu */
1315 if (!build_sam_account(smbpasswd_state
, sam_acct
, smb_pw
))
1319 return NT_STATUS_OK
;
1322 static NTSTATUS
smbpasswd_getsampwsid(struct pdb_methods
*my_methods
, struct samu
*sam_acct
, const struct dom_sid
*sid
)
1324 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1325 struct smbpasswd_privates
*smbpasswd_state
= (struct smbpasswd_privates
*)my_methods
->private_data
;
1326 struct smb_passwd
*smb_pw
;
1330 DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
1331 sid_string_dbg(sid
)));
1333 if (!sid_peek_check_rid(get_global_sam_sid(), sid
, &rid
))
1334 return NT_STATUS_UNSUCCESSFUL
;
1336 /* More special case 'guest account' hacks... */
1337 if (rid
== DOMAIN_RID_GUEST
) {
1338 const char *guest_account
= lp_guestaccount();
1339 if (!(guest_account
&& *guest_account
)) {
1340 DEBUG(1, ("Guest account not specfied!\n"));
1343 return smbpasswd_getsampwnam(my_methods
, sam_acct
, guest_account
);
1346 /* Open the sam password file - not for update. */
1347 fp
= startsmbfilepwent(smbpasswd_state
->smbpasswd_file
, PWF_READ
, &(smbpasswd_state
->pw_file_lock_depth
));
1350 DEBUG(0, ("Unable to open passdb database.\n"));
1354 while ( ((smb_pw
=getsmbfilepwent(smbpasswd_state
, fp
)) != NULL
) && (algorithmic_pdb_uid_to_user_rid(smb_pw
->smb_userid
) != rid
) )
1357 endsmbfilepwent(fp
, &(smbpasswd_state
->pw_file_lock_depth
));
1360 /* did we locate the username in smbpasswd */
1364 DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw
->smb_name
));
1367 DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
1371 /* now build the struct samu */
1372 if (!build_sam_account (smbpasswd_state
, sam_acct
, smb_pw
))
1375 /* build_sam_account might change the SID on us, if the name was for the guest account */
1376 if (NT_STATUS_IS_OK(nt_status
) && !dom_sid_equal(pdb_get_user_sid(sam_acct
), sid
)) {
1377 DEBUG(1, ("looking for user with sid %s instead returned %s "
1378 "for account %s!?!\n", sid_string_dbg(sid
),
1379 sid_string_dbg(pdb_get_user_sid(sam_acct
)),
1380 pdb_get_username(sam_acct
)));
1381 return NT_STATUS_NO_SUCH_USER
;
1385 return NT_STATUS_OK
;
1388 static NTSTATUS
smbpasswd_add_sam_account(struct pdb_methods
*my_methods
, struct samu
*sampass
)
1390 struct smbpasswd_privates
*smbpasswd_state
= (struct smbpasswd_privates
*)my_methods
->private_data
;
1391 struct smb_passwd smb_pw
;
1393 /* convert the struct samu */
1394 if (!build_smb_pass(&smb_pw
, sampass
)) {
1395 return NT_STATUS_UNSUCCESSFUL
;
1399 return add_smbfilepwd_entry(smbpasswd_state
, &smb_pw
);
1402 static NTSTATUS
smbpasswd_update_sam_account(struct pdb_methods
*my_methods
, struct samu
*sampass
)
1404 struct smbpasswd_privates
*smbpasswd_state
= (struct smbpasswd_privates
*)my_methods
->private_data
;
1405 struct smb_passwd smb_pw
;
1407 /* convert the struct samu */
1408 if (!build_smb_pass(&smb_pw
, sampass
)) {
1409 DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
1410 return NT_STATUS_UNSUCCESSFUL
;
1413 /* update the entry */
1414 if(!mod_smbfilepwd_entry(smbpasswd_state
, &smb_pw
)) {
1415 DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
1416 return NT_STATUS_UNSUCCESSFUL
;
1419 return NT_STATUS_OK
;
1422 static NTSTATUS
smbpasswd_delete_sam_account (struct pdb_methods
*my_methods
, struct samu
*sampass
)
1424 struct smbpasswd_privates
*smbpasswd_state
= (struct smbpasswd_privates
*)my_methods
->private_data
;
1426 const char *username
= pdb_get_username(sampass
);
1428 if (del_smbfilepwd_entry(smbpasswd_state
, username
))
1429 return NT_STATUS_OK
;
1431 return NT_STATUS_UNSUCCESSFUL
;
1434 static NTSTATUS
smbpasswd_rename_sam_account (struct pdb_methods
*my_methods
,
1435 struct samu
*old_acct
,
1436 const char *newname
)
1438 char *rename_script
= NULL
;
1439 struct samu
*new_acct
= NULL
;
1440 bool interim_account
= False
;
1441 TALLOC_CTX
*ctx
= talloc_tos();
1442 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
1444 if (!*(lp_renameuser_script()))
1447 if ( !(new_acct
= samu_new( NULL
)) ) {
1448 return NT_STATUS_NO_MEMORY
;
1451 if ( !pdb_copy_sam_account( new_acct
, old_acct
)
1452 || !pdb_set_username(new_acct
, newname
, PDB_CHANGED
))
1457 ret
= smbpasswd_add_sam_account(my_methods
, new_acct
);
1458 if (!NT_STATUS_IS_OK(ret
))
1461 interim_account
= True
;
1463 /* rename the posix user */
1464 rename_script
= talloc_strdup(ctx
,
1465 lp_renameuser_script());
1466 if (!rename_script
) {
1467 ret
= NT_STATUS_NO_MEMORY
;
1471 if (*rename_script
) {
1474 rename_script
= talloc_string_sub2(ctx
,
1481 if (!rename_script
) {
1482 ret
= NT_STATUS_NO_MEMORY
;
1485 rename_script
= talloc_string_sub2(ctx
,
1488 pdb_get_username(old_acct
),
1492 if (!rename_script
) {
1493 ret
= NT_STATUS_NO_MEMORY
;
1497 rename_ret
= smbrun(rename_script
, NULL
);
1499 DEBUG(rename_ret
? 0 : 3,("Running the command `%s' gave %d\n", rename_script
, rename_ret
));
1501 if (rename_ret
== 0) {
1502 smb_nscd_flush_user_cache();
1511 smbpasswd_delete_sam_account(my_methods
, old_acct
);
1512 interim_account
= False
;
1516 if (interim_account
)
1517 smbpasswd_delete_sam_account(my_methods
, new_acct
);
1520 TALLOC_FREE(new_acct
);
1525 static uint32_t smbpasswd_capabilities(struct pdb_methods
*methods
)
1530 static void free_private_data(void **vp
)
1532 struct smbpasswd_privates
**privates
= (struct smbpasswd_privates
**)vp
;
1534 endsmbfilepwent((*privates
)->pw_file
, &((*privates
)->pw_file_lock_depth
));
1537 /* No need to free any further, as it is talloc()ed */
1540 struct smbpasswd_search_state
{
1541 uint32_t acct_flags
;
1543 struct samr_displayentry
*entries
;
1544 uint32_t num_entries
;
1549 static void smbpasswd_search_end(struct pdb_search
*search
)
1551 struct smbpasswd_search_state
*state
= talloc_get_type_abort(
1552 search
->private_data
, struct smbpasswd_search_state
);
1556 static bool smbpasswd_search_next_entry(struct pdb_search
*search
,
1557 struct samr_displayentry
*entry
)
1559 struct smbpasswd_search_state
*state
= talloc_get_type_abort(
1560 search
->private_data
, struct smbpasswd_search_state
);
1562 if (state
->current
== state
->num_entries
) {
1566 entry
->idx
= state
->entries
[state
->current
].idx
;
1567 entry
->rid
= state
->entries
[state
->current
].rid
;
1568 entry
->acct_flags
= state
->entries
[state
->current
].acct_flags
;
1570 entry
->account_name
= talloc_strdup(
1571 search
, state
->entries
[state
->current
].account_name
);
1572 entry
->fullname
= talloc_strdup(
1573 search
, state
->entries
[state
->current
].fullname
);
1574 entry
->description
= talloc_strdup(
1575 search
, state
->entries
[state
->current
].description
);
1577 if ((entry
->account_name
== NULL
) || (entry
->fullname
== NULL
)
1578 || (entry
->description
== NULL
)) {
1579 DEBUG(0, ("talloc_strdup failed\n"));
1583 state
->current
+= 1;
1587 static bool smbpasswd_search_users(struct pdb_methods
*methods
,
1588 struct pdb_search
*search
,
1589 uint32_t acct_flags
)
1591 struct smbpasswd_privates
*smbpasswd_state
=
1592 (struct smbpasswd_privates
*)methods
->private_data
;
1594 struct smbpasswd_search_state
*search_state
;
1595 struct smb_passwd
*pwd
;
1598 search_state
= talloc_zero(search
, struct smbpasswd_search_state
);
1599 if (search_state
== NULL
) {
1600 DEBUG(0, ("talloc failed\n"));
1603 search_state
->acct_flags
= acct_flags
;
1605 fp
= startsmbfilepwent(smbpasswd_state
->smbpasswd_file
, PWF_READ
,
1606 &smbpasswd_state
->pw_file_lock_depth
);
1609 DEBUG(10, ("Unable to open smbpasswd file.\n"));
1610 TALLOC_FREE(search_state
);
1614 while ((pwd
= getsmbfilepwent(smbpasswd_state
, fp
)) != NULL
) {
1615 struct samr_displayentry entry
;
1618 if ((acct_flags
!= 0)
1619 && ((acct_flags
& pwd
->acct_ctrl
) == 0)) {
1623 user
= samu_new(talloc_tos());
1625 DEBUG(0, ("samu_new failed\n"));
1629 if (!build_sam_account(smbpasswd_state
, user
, pwd
)) {
1630 /* Already got debug msgs... */
1636 entry
.acct_flags
= pdb_get_acct_ctrl(user
);
1637 sid_peek_rid(pdb_get_user_sid(user
), &entry
.rid
);
1638 entry
.account_name
= talloc_strdup(
1639 search_state
, pdb_get_username(user
));
1640 entry
.fullname
= talloc_strdup(
1641 search_state
, pdb_get_fullname(user
));
1642 entry
.description
= talloc_strdup(
1643 search_state
, pdb_get_acct_desc(user
));
1647 if ((entry
.account_name
== NULL
) || (entry
.fullname
== NULL
)
1648 || (entry
.description
== NULL
)) {
1649 DEBUG(0, ("talloc_strdup failed\n"));
1653 ADD_TO_LARGE_ARRAY(search_state
, struct samr_displayentry
,
1654 entry
, &search_state
->entries
,
1655 &search_state
->num_entries
,
1656 &search_state
->array_size
);
1659 endsmbfilepwent(fp
, &(smbpasswd_state
->pw_file_lock_depth
));
1661 search
->private_data
= search_state
;
1662 search
->next_entry
= smbpasswd_search_next_entry
;
1663 search
->search_end
= smbpasswd_search_end
;
1668 static NTSTATUS
pdb_init_smbpasswd( struct pdb_methods
**pdb_method
, const char *location
)
1671 struct smbpasswd_privates
*privates
;
1673 if ( !NT_STATUS_IS_OK(nt_status
= make_pdb_method( pdb_method
)) ) {
1677 (*pdb_method
)->name
= "smbpasswd";
1679 (*pdb_method
)->getsampwnam
= smbpasswd_getsampwnam
;
1680 (*pdb_method
)->getsampwsid
= smbpasswd_getsampwsid
;
1681 (*pdb_method
)->add_sam_account
= smbpasswd_add_sam_account
;
1682 (*pdb_method
)->update_sam_account
= smbpasswd_update_sam_account
;
1683 (*pdb_method
)->delete_sam_account
= smbpasswd_delete_sam_account
;
1684 (*pdb_method
)->rename_sam_account
= smbpasswd_rename_sam_account
;
1685 (*pdb_method
)->search_users
= smbpasswd_search_users
;
1687 (*pdb_method
)->capabilities
= smbpasswd_capabilities
;
1689 /* Setup private data and free function */
1691 if ( !(privates
= TALLOC_ZERO_P( *pdb_method
, struct smbpasswd_privates
)) ) {
1692 DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
1693 return NT_STATUS_NO_MEMORY
;
1696 /* Store some config details */
1699 privates
->smbpasswd_file
= talloc_strdup(*pdb_method
, location
);
1701 privates
->smbpasswd_file
= talloc_strdup(*pdb_method
, lp_smb_passwd_file());
1704 if (!privates
->smbpasswd_file
) {
1705 DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
1706 return NT_STATUS_NO_MEMORY
;
1709 (*pdb_method
)->private_data
= privates
;
1711 (*pdb_method
)->free_private_data
= free_private_data
;
1713 return NT_STATUS_OK
;
1716 NTSTATUS
pdb_smbpasswd_init(void)
1718 return smb_register_passdb(PASSDB_INTERFACE_VERSION
, "smbpasswd", pdb_init_smbpasswd
);