2 * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 675
17 * Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL
;
25 extern pstring samlogon_user
;
26 extern BOOL sam_logon_in_ssb
;
28 static int pw_file_lock_depth
;
30 enum pwf_access_type
{ PWF_READ
, PWF_UPDATE
, PWF_CREATE
};
32 /***************************************************************
33 Internal fn to enumerate the smbpasswd list. Returns a void pointer
34 to ensure no modification outside this module. Checks for atomic
35 rename of smbpasswd file on update or create once the lock has
36 been granted to prevent race conditions. JRA.
37 ****************************************************************/
39 static void *startsmbfilepwent_internal(const char *pfile
, enum pwf_access_type type
, int *lock_depth
)
42 const char *open_mode
= NULL
;
44 int lock_type
= F_RDLCK
;
47 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
62 * Ensure atomic file creation.
67 for(i
= 0; i
< 5; i
++) {
68 if((fd
= sys_open(pfile
, O_CREAT
|O_TRUNC
|O_EXCL
|O_RDWR
, 0600))!=-1)
70 sys_usleep(200); /* Spin, spin... */
73 DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile
));
83 for(race_loop
= 0; race_loop
< 5; race_loop
++) {
84 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile
));
86 if((fp
= sys_fopen(pfile
, open_mode
)) == NULL
) {
87 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile
, strerror(errno
) ));
91 if (!pw_file_lock(fileno(fp
), lock_type
, 5, lock_depth
)) {
92 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile
, strerror(errno
) ));
98 * Only check for replacement races on update or create.
99 * For read we don't mind if the data is one record out of date.
102 if(type
== PWF_READ
) {
105 SMB_STRUCT_STAT sbuf1
, sbuf2
;
108 * Avoid the potential race condition between the open and the lock
109 * by doing a stat on the filename and an fstat on the fd. If the
110 * two inodes differ then someone did a rename between the open and
111 * the lock. Back off and try the open again. Only do this 5 times to
112 * prevent infinate loops. JRA.
115 if (sys_stat(pfile
,&sbuf1
) != 0) {
116 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile
, strerror(errno
)));
117 pw_file_unlock(fileno(fp
), lock_depth
);
122 if (sys_fstat(fileno(fp
),&sbuf2
) != 0) {
123 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile
, strerror(errno
)));
124 pw_file_unlock(fileno(fp
), lock_depth
);
129 if( sbuf1
.st_ino
== sbuf2
.st_ino
) {
135 * Race occurred - back off and try again...
138 pw_file_unlock(fileno(fp
), lock_depth
);
144 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile
));
148 /* Set a buffer to do more efficient reads */
149 setvbuf(fp
, (char *)NULL
, _IOFBF
, 1024);
151 /* Make sure it is only rw by the owner */
152 if(fchmod(fileno(fp
), S_IRUSR
|S_IWUSR
) == -1) {
153 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
154 Error was %s\n.", pfile
, strerror(errno
) ));
155 pw_file_unlock(fileno(fp
), lock_depth
);
160 /* We have a lock on the file. */
164 /***************************************************************
165 Start to enumerate the smbpasswd list. Returns a void pointer
166 to ensure no modification outside this module.
167 ****************************************************************/
169 static void *startsmbfilepwent(BOOL update
)
171 return startsmbfilepwent_internal(lp_smb_passwd_file(), update
? PWF_UPDATE
: PWF_READ
, &pw_file_lock_depth
);
174 /***************************************************************
175 End enumeration of the smbpasswd list.
176 ****************************************************************/
178 static void endsmbfilepwent_internal(void *vp
, int *lock_depth
)
180 FILE *fp
= (FILE *)vp
;
182 pw_file_unlock(fileno(fp
), lock_depth
);
184 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
187 /***************************************************************
188 End enumeration of the smbpasswd list - operate on the default
190 ****************************************************************/
192 static void endsmbfilepwent(void *vp
)
194 endsmbfilepwent_internal(vp
, &pw_file_lock_depth
);
197 /*************************************************************************
198 Routine to return the next entry in the smbpasswd list.
199 *************************************************************************/
201 static struct smb_passwd
*getsmbfilepwent(void *vp
)
203 /* Static buffers we will return. */
204 static struct smb_passwd pw_buf
;
205 static pstring user_name
;
206 static unsigned char smbpwd
[16];
207 static unsigned char smbntpwd
[16];
208 FILE *fp
= (FILE *)vp
;
216 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
220 pdb_init_smb(&pw_buf
);
222 pw_buf
.acct_ctrl
= ACB_NORMAL
;
225 * Scan the file, a line at a time and check if the name matches.
230 fgets(linebuf
, 256, fp
);
236 * Check if the string is terminated with a newline - if not
237 * then we must keep reading and discard until we get one.
239 if ((linebuf_len
= strlen(linebuf
)) == 0)
242 if (linebuf
[linebuf_len
- 1] != '\n') {
244 while (!ferror(fp
) && !feof(fp
)) {
250 linebuf
[linebuf_len
- 1] = '\0';
252 #ifdef DEBUG_PASSWORD
253 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf
));
255 if ((linebuf
[0] == 0) && feof(fp
)) {
256 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
260 * The line we have should be of the form :-
262 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
267 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
269 * if Windows NT compatible passwords are also present.
270 * [Account type] is an ascii encoding of the type of account.
271 * LCT-(8 hex digits) is the time_t value of the last change time.
274 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
275 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
278 p
= (unsigned char *) strchr(linebuf
, ':');
280 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
284 * As 256 is shorter than a pstring we don't need to check
285 * length here - if this ever changes....
287 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
288 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
292 p
++; /* Go past ':' */
295 DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
300 DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
304 uidval
= atoi((char *) p
);
306 while (*p
&& isdigit(*p
))
310 DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
314 pw_buf
.smb_name
= user_name
;
315 pw_buf
.smb_userid
= uidval
;
318 * Now get the password value - this should be 32 hex digits
319 * which are the ascii representations of a 16 byte string.
320 * Get two at a time and put them into the password.
326 if (*p
== '*' || *p
== 'X') {
327 /* Password deliberately invalid - end here. */
328 DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name
));
329 pw_buf
.smb_nt_passwd
= NULL
;
330 pw_buf
.smb_passwd
= NULL
;
331 pw_buf
.acct_ctrl
|= ACB_DISABLED
;
335 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
336 DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
341 DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
345 if (!strncasecmp((char *) p
, "NO PASSWORD", 11)) {
346 pw_buf
.smb_passwd
= NULL
;
347 pw_buf
.acct_ctrl
|= ACB_PWNOTREQ
;
349 if (!pdb_gethexpwd((char *)p
, smbpwd
)) {
350 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
353 pw_buf
.smb_passwd
= smbpwd
;
357 * Now check if the NT compatible password is
360 pw_buf
.smb_nt_passwd
= NULL
;
362 p
+= 33; /* Move to the first character of the line after
363 the lanman password. */
364 if ((linebuf_len
>= (PTR_DIFF(p
, linebuf
) + 33)) && (p
[32] == ':')) {
365 if (*p
!= '*' && *p
!= 'X') {
366 if(pdb_gethexpwd((char *)p
,smbntpwd
))
367 pw_buf
.smb_nt_passwd
= smbntpwd
;
369 p
+= 33; /* Move to the first character of the line after
373 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
378 unsigned char *end_p
= (unsigned char *)strchr((char *)p
, ']');
379 pw_buf
.acct_ctrl
= pdb_decode_acct_ctrl((char*)p
);
381 /* Must have some account type set. */
382 if(pw_buf
.acct_ctrl
== 0)
383 pw_buf
.acct_ctrl
= ACB_NORMAL
;
385 /* Now try and get the last change time. */
390 if(*p
&& (StrnCaseCmp((char *)p
, "LCT-", 4)==0)) {
393 for(i
= 0; i
< 8; i
++) {
394 if(p
[i
] == '\0' || !isxdigit(p
[i
]))
399 * p points at 8 characters of hex digits -
400 * read into a time_t as the seconds since
401 * 1970 that the password was last changed.
403 pw_buf
.pass_last_set_time
= (time_t)strtol((char *)p
, NULL
, 16);
408 /* 'Old' style file. Fake up based on user name. */
410 * Currently trust accounts are kept in the same
411 * password file as 'normal accounts'. If this changes
412 * we will have to fix this code. JRA.
414 if(pw_buf
.smb_name
[strlen(pw_buf
.smb_name
) - 1] == '$') {
415 pw_buf
.acct_ctrl
&= ~ACB_NORMAL
;
416 pw_buf
.acct_ctrl
|= ACB_WSTRUST
;
423 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
427 /*************************************************************************
428 Routine to return the next entry in the smbpasswd list.
429 this function is a nice, messy combination of reading:
431 - the unix password database
432 - smb.conf options (not done at present).
433 *************************************************************************/
435 static struct sam_passwd
*getsmbfile21pwent(void *vp
)
437 struct smb_passwd
*pw_buf
= getsmbfilepwent(vp
);
438 static struct sam_passwd user
;
439 struct passwd
*pwfile
;
441 static pstring full_name
;
442 static pstring home_dir
;
443 static pstring home_drive
;
444 static pstring logon_script
;
445 static pstring profile_path
;
446 static pstring acct_desc
;
447 static pstring workstations
;
449 DEBUG(5,("getsmbfile21pwent\n"));
451 if (pw_buf
== NULL
) return NULL
;
453 pwfile
= sys_getpwnam(pw_buf
->smb_name
);
456 DEBUG(0,("getsmbfile21pwent: smbpasswd database is corrupt!\n"));
457 DEBUG(0,("getsmbfile21pwent: username %s not in unix passwd database!\n", pw_buf
->smb_name
));
463 pstrcpy(samlogon_user
, pw_buf
->smb_name
);
465 if (samlogon_user
[strlen(samlogon_user
)-1] != '$')
467 /* XXXX hack to get standard_sub_basic() to use sam logon username */
468 /* possibly a better way would be to do a become_user() call */
469 sam_logon_in_ssb
= True
;
471 user
.smb_userid
= pw_buf
->smb_userid
;
472 user
.smb_grpid
= pwfile
->pw_gid
;
474 user
.user_rid
= pdb_uid_to_user_rid (user
.smb_userid
);
475 user
.group_rid
= pdb_gid_to_group_rid(user
.smb_grpid
);
477 pstrcpy(full_name
, pwfile
->pw_gecos
);
478 pstrcpy(logon_script
, lp_logon_script ());
479 pstrcpy(profile_path
, lp_logon_path ());
480 pstrcpy(home_drive
, lp_logon_drive ());
481 pstrcpy(home_dir
, lp_logon_home ());
482 pstrcpy(acct_desc
, "");
483 pstrcpy(workstations
, "");
485 sam_logon_in_ssb
= False
;
489 user
.smb_userid
= pw_buf
->smb_userid
;
490 user
.smb_grpid
= pwfile
->pw_gid
;
492 user
.user_rid
= pdb_uid_to_user_rid (user
.smb_userid
);
493 user
.group_rid
= DOMAIN_GROUP_RID_USERS
; /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
495 pstrcpy(full_name
, "");
496 pstrcpy(logon_script
, "");
497 pstrcpy(profile_path
, "");
498 pstrcpy(home_drive
, "");
499 pstrcpy(home_dir
, "");
500 pstrcpy(acct_desc
, "");
501 pstrcpy(workstations
, "");
504 user
.smb_name
= pw_buf
->smb_name
;
505 user
.full_name
= full_name
;
506 user
.home_dir
= home_dir
;
507 user
.dir_drive
= home_drive
;
508 user
.logon_script
= logon_script
;
509 user
.profile_path
= profile_path
;
510 user
.acct_desc
= acct_desc
;
511 user
.workstations
= workstations
;
513 user
.unknown_str
= NULL
; /* don't know, yet! */
514 user
.munged_dial
= NULL
; /* "munged" dial-back telephone number */
516 user
.smb_nt_passwd
= pw_buf
->smb_nt_passwd
;
517 user
.smb_passwd
= pw_buf
->smb_passwd
;
519 user
.acct_ctrl
= pw_buf
->acct_ctrl
;
521 user
.unknown_3
= 0xffffff; /* don't know */
522 user
.logon_divs
= 168; /* hours per week */
523 user
.hours_len
= 21; /* 21 times 8 bits = 168 */
524 memset(user
.hours
, 0xff, user
.hours_len
); /* available at all hours */
525 user
.unknown_5
= 0x00020000; /* don't know */
526 user
.unknown_5
= 0x000004ec; /* don't know */
531 /*************************************************************************
532 Return the current position in the smbpasswd list as an SMB_BIG_UINT.
533 This must be treated as an opaque token.
534 *************************************************************************/
536 static SMB_BIG_UINT
getsmbfilepwpos(void *vp
)
538 return (SMB_BIG_UINT
)sys_ftell((FILE *)vp
);
541 /*************************************************************************
542 Set the current position in the smbpasswd list from an SMB_BIG_UINT.
543 This must be treated as an opaque token.
544 *************************************************************************/
546 static BOOL
setsmbfilepwpos(void *vp
, SMB_BIG_UINT tok
)
548 return !sys_fseek((FILE *)vp
, (SMB_OFF_T
)tok
, SEEK_SET
);
551 /************************************************************************
552 Create a new smbpasswd entry - malloced space returned.
553 *************************************************************************/
555 char *format_new_smbpasswd_entry(struct smb_passwd
*newpwd
)
557 int new_entry_length
;
562 new_entry_length
= strlen(newpwd
->smb_name
) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN
+ 1 + 13 + 2;
564 if((new_entry
= (char *)malloc( new_entry_length
)) == NULL
) {
565 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd
->smb_name
));
569 slprintf(new_entry
, new_entry_length
- 1, "%s:%u:", newpwd
->smb_name
, (unsigned)newpwd
->smb_userid
);
570 p
= &new_entry
[strlen(new_entry
)];
572 if(newpwd
->smb_passwd
!= NULL
) {
573 for( i
= 0; i
< 16; i
++) {
574 slprintf((char *)&p
[i
*2], new_entry_length
- (p
- new_entry
) - 1, "%02X", newpwd
->smb_passwd
[i
]);
578 if(newpwd
->acct_ctrl
& ACB_PWNOTREQ
)
579 safe_strcpy((char *)p
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
581 safe_strcpy((char *)p
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
588 if(newpwd
->smb_nt_passwd
!= NULL
) {
589 for( i
= 0; i
< 16; i
++) {
590 slprintf((char *)&p
[i
*2], new_entry_length
- 1 - (p
- new_entry
), "%02X", newpwd
->smb_nt_passwd
[i
]);
593 if(newpwd
->acct_ctrl
& ACB_PWNOTREQ
)
594 safe_strcpy((char *)p
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
596 safe_strcpy((char *)p
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
603 /* Add the account encoding and the last change time. */
604 slprintf((char *)p
, new_entry_length
- 1 - (p
- new_entry
), "%s:LCT-%08X:\n",
605 pdb_encode_acct_ctrl(newpwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
),
606 (uint32
)newpwd
->pass_last_set_time
);
611 /************************************************************************
612 Routine to add an entry to the smbpasswd file.
613 *************************************************************************/
615 static BOOL
add_smbfilepwd_entry(struct smb_passwd
*newpwd
)
617 char *pfile
= lp_smb_passwd_file();
618 struct smb_passwd
*pwd
= NULL
;
622 size_t new_entry_length
;
626 /* Open the smbpassword file - for update. */
627 fp
= startsmbfilepwent(True
);
630 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
635 * Scan the file, a line at a time and check if the name matches.
638 while ((pwd
= getsmbfilepwent(fp
)) != NULL
) {
639 if (strequal(newpwd
->smb_name
, pwd
->smb_name
)) {
640 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd
->smb_name
));
646 /* Ok - entry doesn't exist. We can add it */
648 /* Create a new smb passwd entry and set it to the given password. */
650 * The add user write needs to be atomic - so get the fd from
651 * the fp and do a raw write() call.
655 if((offpos
= sys_lseek(fd
, 0, SEEK_END
)) == -1) {
656 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
657 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
662 if((new_entry
= format_new_smbpasswd_entry(newpwd
)) == NULL
) {
663 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
664 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
669 new_entry_length
= strlen(new_entry
);
671 #ifdef DEBUG_PASSWORD
672 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
673 fd
, new_entry_length
, new_entry
));
676 if ((wr_len
= write(fd
, new_entry
, new_entry_length
)) != new_entry_length
) {
677 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
678 Error was %s\n", wr_len
, newpwd
->smb_name
, pfile
, strerror(errno
)));
680 /* Remove the entry we just wrote. */
681 if(sys_ftruncate(fd
, offpos
) == -1) {
682 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
683 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
684 newpwd
->smb_name
, strerror(errno
)));
697 /************************************************************************
698 Routine to search the smbpasswd file for an entry matching the username.
699 and then modify its password entry. We can't use the startsmbpwent()/
700 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
701 in the actual file to decide how much room we have to write data.
702 override = False, normal
703 override = True, override XXXXXXXX'd out password or NO PASS
704 ************************************************************************/
706 static BOOL
mod_smbfilepwd_entry(struct smb_passwd
* pwd
, BOOL override
)
708 /* Static buffers we will return. */
709 static pstring user_name
;
716 unsigned char *p
= NULL
;
717 size_t linebuf_len
= 0;
720 char *pfile
= lp_smb_passwd_file();
721 BOOL found_entry
= False
;
722 BOOL got_pass_last_set_time
= False
;
724 SMB_OFF_T pwd_seekpos
= 0;
731 DEBUG(0, ("No SMB password file set\n"));
734 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile
));
736 fp
= sys_fopen(pfile
, "r+");
739 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile
));
742 /* Set a buffer to do more efficient reads */
743 setvbuf(fp
, readbuf
, _IOFBF
, sizeof(readbuf
));
747 if (!pw_file_lock(lockfd
, F_WRLCK
, 5, &pw_file_lock_depth
)) {
748 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile
));
753 /* Make sure it is only rw by the owner */
756 /* We have a write lock on the file. */
758 * Scan the file, a line at a time and check if the name matches.
761 pwd_seekpos
= sys_ftell(fp
);
765 fgets(linebuf
, sizeof(linebuf
), fp
);
767 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
773 * Check if the string is terminated with a newline - if not
774 * then we must keep reading and discard until we get one.
776 linebuf_len
= strlen(linebuf
);
777 if (linebuf
[linebuf_len
- 1] != '\n') {
779 while (!ferror(fp
) && !feof(fp
)) {
786 linebuf
[linebuf_len
- 1] = '\0';
789 #ifdef DEBUG_PASSWORD
790 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf
));
793 if ((linebuf
[0] == 0) && feof(fp
)) {
794 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
799 * The line we have should be of the form :-
801 * username:uid:[32hex bytes]:....other flags presently
806 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
808 * if Windows NT compatible passwords are also present.
811 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
812 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
816 p
= (unsigned char *) strchr(linebuf
, ':');
819 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
824 * As 256 is shorter than a pstring we don't need to check
825 * length here - if this ever changes....
827 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
828 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
829 if (strequal(user_name
, pwd
->smb_name
)) {
836 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
841 DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
843 /* User name matches - get uid and password */
844 p
++; /* Go past ':' */
847 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
848 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
853 while (*p
&& isdigit(*p
))
856 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
857 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
863 * Now get the password value - this should be 32 hex digits
864 * which are the ascii representations of a 16 byte string.
865 * Get two at a time and put them into the password.
869 /* Record exact password position */
870 pwd_seekpos
+= PTR_DIFF(p
, linebuf
);
872 if (!override
&& (*p
== '*' || *p
== 'X')) {
873 /* Password deliberately invalid - end here. */
874 DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name
));
875 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
880 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
881 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
882 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
888 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
889 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
894 if (!override
&& (*p
== '*' || *p
== 'X')) {
895 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
900 /* Now check if the NT compatible password is
902 p
+= 33; /* Move to the first character of the line after
903 the lanman password. */
904 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
905 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
906 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
912 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
913 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
919 * Now check if the account info and the password last
920 * change time is available.
922 p
+= 33; /* Move to the first character of the line after
926 * If both NT and lanman passwords are provided - reset password
930 if(pwd
->smb_passwd
!= NULL
|| pwd
->smb_nt_passwd
!= NULL
) {
931 /* Reqiure password in the future (should ACB_DISABLED also be reset?) */
932 pwd
->acct_ctrl
&= ~(ACB_PWNOTREQ
);
938 encode_bits
[i
++] = *p
++;
939 while((linebuf_len
> PTR_DIFF(p
, linebuf
)) && (*p
!= ']'))
940 encode_bits
[i
++] = *p
++;
942 encode_bits
[i
++] = ']';
943 encode_bits
[i
++] = '\0';
945 if(i
== NEW_PW_FORMAT_SPACE_PADDED_LEN
) {
947 * We are using a new format, space padded
948 * acct ctrl field. Encode the given acct ctrl
951 fstrcpy(encode_bits
, pdb_encode_acct_ctrl(pwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
));
954 * If using the old format and the ACB_DISABLED or
955 * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
956 * here as we have no space to encode the change.
958 if(pwd
->acct_ctrl
& (ACB_DISABLED
|ACB_PWNOTREQ
)) {
959 pwd
->smb_passwd
= NULL
;
960 pwd
->smb_nt_passwd
= NULL
;
964 /* Go past the ']' */
965 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)) {
975 for(i
= 0; i
< 8; i
++) {
976 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 if(pwd
->smb_passwd
!= NULL
) {
995 for (i
= 0; i
< 16; i
++) {
996 slprintf(&ascii_p16
[i
*2], sizeof(fstring
) - 1, "%02X", (uchar
) pwd
->smb_passwd
[i
]);
999 if(pwd
->acct_ctrl
& ACB_PWNOTREQ
)
1000 fstrcpy(ascii_p16
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1002 fstrcpy(ascii_p16
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1005 /* Add on the NT md4 hash */
1006 ascii_p16
[32] = ':';
1008 if (pwd
->smb_nt_passwd
!= NULL
) {
1009 for (i
= 0; i
< 16; i
++) {
1010 slprintf(&ascii_p16
[(i
*2)+33], sizeof(fstring
) - 1, "%02X", (uchar
) pwd
->smb_nt_passwd
[i
]);
1013 if(pwd
->acct_ctrl
& ACB_PWNOTREQ
)
1014 fstrcpy(&ascii_p16
[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1016 fstrcpy(&ascii_p16
[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1018 ascii_p16
[65] = ':';
1019 ascii_p16
[66] = '\0'; /* null-terminate the string so that strlen works */
1021 /* Add on the account info bits and the time of last
1024 pwd
->pass_last_set_time
= time(NULL
);
1026 if(got_pass_last_set_time
) {
1027 slprintf(&ascii_p16
[strlen(ascii_p16
)],
1028 sizeof(ascii_p16
)-(strlen(ascii_p16
)+1),
1030 encode_bits
, (uint32
)pwd
->pass_last_set_time
);
1031 wr_len
= strlen(ascii_p16
);
1034 #ifdef DEBUG_PASSWORD
1035 DEBUG(100,("mod_smbfilepwd_entry: "));
1036 dump_data(100, ascii_p16
, wr_len
);
1039 if(wr_len
> sizeof(linebuf
)) {
1040 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len
+1));
1041 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1047 * Do an atomic write into the file at the position defined by
1051 /* The mod user write needs to be atomic - so get the fd from
1052 the fp and do a raw write() call.
1057 if (sys_lseek(fd
, pwd_seekpos
- 1, SEEK_SET
) != pwd_seekpos
- 1) {
1058 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1059 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1064 /* Sanity check - ensure the areas we are writing are framed by ':' */
1065 if (read(fd
, linebuf
, wr_len
+1) != wr_len
+1) {
1066 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile
));
1067 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1072 if ((linebuf
[0] != ':') || (linebuf
[wr_len
] != ':')) {
1073 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile
));
1074 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1079 if (sys_lseek(fd
, pwd_seekpos
, SEEK_SET
) != pwd_seekpos
) {
1080 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1081 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1086 if (write(fd
, ascii_p16
, wr_len
) != wr_len
) {
1087 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile
));
1088 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1093 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1098 /************************************************************************
1099 Routine to delete an entry in the smbpasswd file by name.
1100 *************************************************************************/
1102 static BOOL
del_smbfilepwd_entry(const char *name
)
1104 char *pfile
= lp_smb_passwd_file();
1106 struct smb_passwd
*pwd
= NULL
;
1108 FILE *fp_write
= NULL
;
1109 int pfile2_lockdepth
= 0;
1111 slprintf(pfile2
, sizeof(pfile2
)-1, "%s.%u", pfile
, (unsigned)sys_getpid() );
1114 * Open the smbpassword file - for update. It needs to be update
1115 * as we need any other processes to wait until we have replaced
1119 if((fp
= startsmbfilepwent(True
)) == NULL
) {
1120 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1125 * Create the replacement password file.
1127 if((fp_write
= startsmbfilepwent_internal(pfile2
, PWF_CREATE
, &pfile2_lockdepth
)) == NULL
) {
1128 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1129 endsmbfilepwent(fp
);
1134 * Scan the file, a line at a time and check if the name matches.
1137 while ((pwd
= getsmbfilepwent(fp
)) != NULL
) {
1139 size_t new_entry_length
;
1141 if (strequal(name
, pwd
->smb_name
)) {
1142 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name
));
1147 * We need to copy the entry out into the second file.
1150 if((new_entry
= format_new_smbpasswd_entry(pwd
)) == NULL
) {
1151 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1152 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1154 endsmbfilepwent(fp
);
1155 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1159 new_entry_length
= strlen(new_entry
);
1161 if(fwrite(new_entry
, 1, new_entry_length
, fp_write
) != new_entry_length
) {
1162 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1163 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1165 endsmbfilepwent(fp
);
1166 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1175 * Ensure pfile2 is flushed before rename.
1178 if(fflush(fp_write
) != 0) {
1179 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2
, strerror(errno
)));
1180 endsmbfilepwent(fp
);
1181 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1186 * Do an atomic rename - then release the locks.
1189 if(rename(pfile2
,pfile
) != 0) {
1192 endsmbfilepwent(fp
);
1193 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1198 * Stub functions - implemented in terms of others.
1201 static BOOL
mod_smbfile21pwd_entry(struct sam_passwd
* pwd
, BOOL override
)
1203 return mod_smbfilepwd_entry(pdb_sam_to_smb(pwd
), override
);
1206 static BOOL
add_smbfile21pwd_entry(struct sam_passwd
*newpwd
)
1208 return add_smbfilepwd_entry(pdb_sam_to_smb(newpwd
));
1211 static struct sam_disp_info
*getsmbfiledispnam(char *name
)
1213 return pdb_sam_to_dispinfo(getsam21pwnam(name
));
1216 static struct sam_disp_info
*getsmbfiledisprid(uint32 rid
)
1218 return pdb_sam_to_dispinfo(getsam21pwrid(rid
));
1221 static struct sam_disp_info
*getsmbfiledispent(void *vp
)
1223 return pdb_sam_to_dispinfo(getsam21pwent(vp
));
1226 static struct passdb_ops file_ops
= {
1231 iterate_getsmbpwnam
, /* In passdb.c */
1232 iterate_getsmbpwuid
, /* In passdb.c */
1233 iterate_getsmbpwrid
, /* In passdb.c */
1235 add_smbfilepwd_entry
,
1236 mod_smbfilepwd_entry
,
1237 del_smbfilepwd_entry
,
1239 iterate_getsam21pwnam
,
1240 iterate_getsam21pwuid
,
1241 iterate_getsam21pwrid
,
1242 add_smbfile21pwd_entry
,
1243 mod_smbfile21pwd_entry
,
1249 struct passdb_ops
*file_initialize_password_db(void)
1255 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1256 void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1257 #endif /* USE_SMBPASS_DB */