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
;
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 linebuf_len
= strlen(linebuf
);
240 if (linebuf
[linebuf_len
- 1] != '\n') {
242 while (!ferror(fp
) && !feof(fp
)) {
248 linebuf
[linebuf_len
- 1] = '\0';
250 #ifdef DEBUG_PASSWORD
251 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf
));
253 if ((linebuf
[0] == 0) && feof(fp
)) {
254 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
258 * The line we have should be of the form :-
260 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
265 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
267 * if Windows NT compatible passwords are also present.
268 * [Account type] is an ascii encoding of the type of account.
269 * LCT-(8 hex digits) is the time_t value of the last change time.
272 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
273 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
276 p
= (unsigned char *) strchr(linebuf
, ':');
278 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
282 * As 256 is shorter than a pstring we don't need to check
283 * length here - if this ever changes....
285 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
286 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
290 p
++; /* Go past ':' */
293 DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
298 DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
302 uidval
= atoi((char *) p
);
304 while (*p
&& isdigit(*p
))
308 DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
312 pw_buf
.smb_name
= user_name
;
313 pw_buf
.smb_userid
= uidval
;
316 * Now get the password value - this should be 32 hex digits
317 * which are the ascii representations of a 16 byte string.
318 * Get two at a time and put them into the password.
324 if (*p
== '*' || *p
== 'X') {
325 /* Password deliberately invalid - end here. */
326 DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name
));
327 pw_buf
.smb_nt_passwd
= NULL
;
328 pw_buf
.smb_passwd
= NULL
;
329 pw_buf
.acct_ctrl
|= ACB_DISABLED
;
333 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
334 DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
339 DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
343 if (!strncasecmp((char *) p
, "NO PASSWORD", 11)) {
344 pw_buf
.smb_passwd
= NULL
;
345 pw_buf
.acct_ctrl
|= ACB_PWNOTREQ
;
347 if (!pdb_gethexpwd((char *)p
, smbpwd
)) {
348 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
351 pw_buf
.smb_passwd
= smbpwd
;
355 * Now check if the NT compatible password is
358 pw_buf
.smb_nt_passwd
= NULL
;
360 p
+= 33; /* Move to the first character of the line after
361 the lanman password. */
362 if ((linebuf_len
>= (PTR_DIFF(p
, linebuf
) + 33)) && (p
[32] == ':')) {
363 if (*p
!= '*' && *p
!= 'X') {
364 if(pdb_gethexpwd((char *)p
,smbntpwd
))
365 pw_buf
.smb_nt_passwd
= smbntpwd
;
367 p
+= 33; /* Move to the first character of the line after
371 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
376 unsigned char *end_p
= (unsigned char *)strchr((char *)p
, ']');
377 pw_buf
.acct_ctrl
= pdb_decode_acct_ctrl((char*)p
);
379 /* Must have some account type set. */
380 if(pw_buf
.acct_ctrl
== 0)
381 pw_buf
.acct_ctrl
= ACB_NORMAL
;
383 /* Now try and get the last change time. */
388 if(*p
&& (StrnCaseCmp((char *)p
, "LCT-", 4)==0)) {
391 for(i
= 0; i
< 8; i
++) {
392 if(p
[i
] == '\0' || !isxdigit(p
[i
]))
397 * p points at 8 characters of hex digits -
398 * read into a time_t as the seconds since
399 * 1970 that the password was last changed.
401 pw_buf
.pass_last_set_time
= (time_t)strtol((char *)p
, NULL
, 16);
406 /* 'Old' style file. Fake up based on user name. */
408 * Currently trust accounts are kept in the same
409 * password file as 'normal accounts'. If this changes
410 * we will have to fix this code. JRA.
412 if(pw_buf
.smb_name
[strlen(pw_buf
.smb_name
) - 1] == '$') {
413 pw_buf
.acct_ctrl
&= ~ACB_NORMAL
;
414 pw_buf
.acct_ctrl
|= ACB_WSTRUST
;
421 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
425 /*************************************************************************
426 Routine to return the next entry in the smbpasswd list.
427 this function is a nice, messy combination of reading:
429 - the unix password database
430 - smb.conf options (not done at present).
431 *************************************************************************/
433 static struct sam_passwd
*getsmbfile21pwent(void *vp
)
435 struct smb_passwd
*pw_buf
= getsmbfilepwent(vp
);
436 static struct sam_passwd user
;
437 struct passwd
*pwfile
;
439 static pstring full_name
;
440 static pstring home_dir
;
441 static pstring home_drive
;
442 static pstring logon_script
;
443 static pstring profile_path
;
444 static pstring acct_desc
;
445 static pstring workstations
;
447 DEBUG(5,("getsmbfile21pwent\n"));
449 if (pw_buf
== NULL
) return NULL
;
451 pwfile
= sys_getpwnam(pw_buf
->smb_name
);
454 DEBUG(0,("getsmbfile21pwent: smbpasswd database is corrupt!\n"));
455 DEBUG(0,("getsmbfile21pwent: username %s not in unix passwd database!\n", pw_buf
->smb_name
));
461 pstrcpy(samlogon_user
, pw_buf
->smb_name
);
463 if (samlogon_user
[strlen(samlogon_user
)-1] != '$')
465 /* XXXX hack to get standard_sub_basic() to use sam logon username */
466 /* possibly a better way would be to do a become_user() call */
467 sam_logon_in_ssb
= True
;
469 user
.smb_userid
= pw_buf
->smb_userid
;
470 user
.smb_grpid
= pwfile
->pw_gid
;
472 user
.user_rid
= pdb_uid_to_user_rid (user
.smb_userid
);
473 user
.group_rid
= pdb_gid_to_group_rid(user
.smb_grpid
);
475 pstrcpy(full_name
, pwfile
->pw_gecos
);
476 pstrcpy(logon_script
, lp_logon_script ());
477 pstrcpy(profile_path
, lp_logon_path ());
478 pstrcpy(home_drive
, lp_logon_drive ());
479 pstrcpy(home_dir
, lp_logon_home ());
480 pstrcpy(acct_desc
, "");
481 pstrcpy(workstations
, "");
483 sam_logon_in_ssb
= False
;
487 user
.smb_userid
= pw_buf
->smb_userid
;
488 user
.smb_grpid
= pwfile
->pw_gid
;
490 user
.user_rid
= pdb_uid_to_user_rid (user
.smb_userid
);
491 user
.group_rid
= DOMAIN_GROUP_RID_USERS
; /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
493 pstrcpy(full_name
, "");
494 pstrcpy(logon_script
, "");
495 pstrcpy(profile_path
, "");
496 pstrcpy(home_drive
, "");
497 pstrcpy(home_dir
, "");
498 pstrcpy(acct_desc
, "");
499 pstrcpy(workstations
, "");
502 user
.smb_name
= pw_buf
->smb_name
;
503 user
.full_name
= full_name
;
504 user
.home_dir
= home_dir
;
505 user
.dir_drive
= home_drive
;
506 user
.logon_script
= logon_script
;
507 user
.profile_path
= profile_path
;
508 user
.acct_desc
= acct_desc
;
509 user
.workstations
= workstations
;
511 user
.unknown_str
= NULL
; /* don't know, yet! */
512 user
.munged_dial
= NULL
; /* "munged" dial-back telephone number */
514 user
.smb_nt_passwd
= pw_buf
->smb_nt_passwd
;
515 user
.smb_passwd
= pw_buf
->smb_passwd
;
517 user
.acct_ctrl
= pw_buf
->acct_ctrl
;
519 user
.unknown_3
= 0xffffff; /* don't know */
520 user
.logon_divs
= 168; /* hours per week */
521 user
.hours_len
= 21; /* 21 times 8 bits = 168 */
522 memset(user
.hours
, 0xff, user
.hours_len
); /* available at all hours */
523 user
.unknown_5
= 0x00020000; /* don't know */
524 user
.unknown_5
= 0x000004ec; /* don't know */
529 /*************************************************************************
530 Return the current position in the smbpasswd list as an SMB_BIG_UINT.
531 This must be treated as an opaque token.
532 *************************************************************************/
534 static SMB_BIG_UINT
getsmbfilepwpos(void *vp
)
536 return (SMB_BIG_UINT
)sys_ftell((FILE *)vp
);
539 /*************************************************************************
540 Set the current position in the smbpasswd list from an SMB_BIG_UINT.
541 This must be treated as an opaque token.
542 *************************************************************************/
544 static BOOL
setsmbfilepwpos(void *vp
, SMB_BIG_UINT tok
)
546 return !sys_fseek((FILE *)vp
, (SMB_OFF_T
)tok
, SEEK_SET
);
549 /************************************************************************
550 Create a new smbpasswd entry - malloced space returned.
551 *************************************************************************/
553 char *format_new_smbpasswd_entry(struct smb_passwd
*newpwd
)
555 int new_entry_length
;
560 new_entry_length
= strlen(newpwd
->smb_name
) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN
+ 1 + 13 + 2;
562 if((new_entry
= (char *)malloc( new_entry_length
)) == NULL
) {
563 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd
->smb_name
));
567 slprintf(new_entry
, new_entry_length
- 1, "%s:%u:", newpwd
->smb_name
, (unsigned)newpwd
->smb_userid
);
568 p
= &new_entry
[strlen(new_entry
)];
570 if(newpwd
->smb_passwd
!= NULL
) {
571 for( i
= 0; i
< 16; i
++) {
572 slprintf((char *)&p
[i
*2], new_entry_length
- (p
- new_entry
) - 1, "%02X", newpwd
->smb_passwd
[i
]);
576 if(newpwd
->acct_ctrl
& ACB_PWNOTREQ
)
577 safe_strcpy((char *)p
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
579 safe_strcpy((char *)p
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
586 if(newpwd
->smb_nt_passwd
!= NULL
) {
587 for( i
= 0; i
< 16; i
++) {
588 slprintf((char *)&p
[i
*2], new_entry_length
- 1 - (p
- new_entry
), "%02X", newpwd
->smb_nt_passwd
[i
]);
591 if(newpwd
->acct_ctrl
& ACB_PWNOTREQ
)
592 safe_strcpy((char *)p
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
594 safe_strcpy((char *)p
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length
- 1 - (p
- new_entry
));
601 /* Add the account encoding and the last change time. */
602 slprintf((char *)p
, new_entry_length
- 1 - (p
- new_entry
), "%s:LCT-%08X:\n",
603 pdb_encode_acct_ctrl(newpwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
),
604 (uint32
)newpwd
->pass_last_set_time
);
609 /************************************************************************
610 Routine to add an entry to the smbpasswd file.
611 *************************************************************************/
613 static BOOL
add_smbfilepwd_entry(struct smb_passwd
*newpwd
)
615 char *pfile
= lp_smb_passwd_file();
616 struct smb_passwd
*pwd
= NULL
;
620 size_t new_entry_length
;
624 /* Open the smbpassword file - for update. */
625 fp
= startsmbfilepwent(True
);
628 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
633 * Scan the file, a line at a time and check if the name matches.
636 while ((pwd
= getsmbfilepwent(fp
)) != NULL
) {
637 if (strequal(newpwd
->smb_name
, pwd
->smb_name
)) {
638 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd
->smb_name
));
644 /* Ok - entry doesn't exist. We can add it */
646 /* Create a new smb passwd entry and set it to the given password. */
648 * The add user write needs to be atomic - so get the fd from
649 * the fp and do a raw write() call.
653 if((offpos
= sys_lseek(fd
, 0, SEEK_END
)) == -1) {
654 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
655 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
660 if((new_entry
= format_new_smbpasswd_entry(newpwd
)) == NULL
) {
661 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
662 Error was %s\n", newpwd
->smb_name
, pfile
, strerror(errno
)));
667 new_entry_length
= strlen(new_entry
);
669 #ifdef DEBUG_PASSWORD
670 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
671 fd
, new_entry_length
, new_entry
));
674 if ((wr_len
= write(fd
, new_entry
, new_entry_length
)) != new_entry_length
) {
675 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
676 Error was %s\n", wr_len
, newpwd
->smb_name
, pfile
, strerror(errno
)));
678 /* Remove the entry we just wrote. */
679 if(sys_ftruncate(fd
, offpos
) == -1) {
680 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
681 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
682 newpwd
->smb_name
, strerror(errno
)));
695 /************************************************************************
696 Routine to search the smbpasswd file for an entry matching the username.
697 and then modify its password entry. We can't use the startsmbpwent()/
698 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
699 in the actual file to decide how much room we have to write data.
700 override = False, normal
701 override = True, override XXXXXXXX'd out password or NO PASS
702 ************************************************************************/
704 static BOOL
mod_smbfilepwd_entry(struct smb_passwd
* pwd
, BOOL override
)
706 /* Static buffers we will return. */
707 static pstring user_name
;
714 unsigned char *p
= NULL
;
715 size_t linebuf_len
= 0;
718 char *pfile
= lp_smb_passwd_file();
719 BOOL found_entry
= False
;
720 BOOL got_pass_last_set_time
= False
;
722 SMB_OFF_T pwd_seekpos
= 0;
729 DEBUG(0, ("No SMB password file set\n"));
732 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile
));
734 fp
= sys_fopen(pfile
, "r+");
737 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile
));
740 /* Set a buffer to do more efficient reads */
741 setvbuf(fp
, readbuf
, _IOFBF
, sizeof(readbuf
));
745 if (!pw_file_lock(lockfd
, F_WRLCK
, 5, &pw_file_lock_depth
)) {
746 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile
));
751 /* Make sure it is only rw by the owner */
754 /* We have a write lock on the file. */
756 * Scan the file, a line at a time and check if the name matches.
759 pwd_seekpos
= sys_ftell(fp
);
763 fgets(linebuf
, sizeof(linebuf
), fp
);
765 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
771 * Check if the string is terminated with a newline - if not
772 * then we must keep reading and discard until we get one.
774 linebuf_len
= strlen(linebuf
);
775 if (linebuf
[linebuf_len
- 1] != '\n') {
777 while (!ferror(fp
) && !feof(fp
)) {
784 linebuf
[linebuf_len
- 1] = '\0';
787 #ifdef DEBUG_PASSWORD
788 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf
));
791 if ((linebuf
[0] == 0) && feof(fp
)) {
792 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
797 * The line we have should be of the form :-
799 * username:uid:[32hex bytes]:....other flags presently
804 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
806 * if Windows NT compatible passwords are also present.
809 if (linebuf
[0] == '#' || linebuf
[0] == '\0') {
810 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
814 p
= (unsigned char *) strchr(linebuf
, ':');
817 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
822 * As 256 is shorter than a pstring we don't need to check
823 * length here - if this ever changes....
825 strncpy(user_name
, linebuf
, PTR_DIFF(p
, linebuf
));
826 user_name
[PTR_DIFF(p
, linebuf
)] = '\0';
827 if (strequal(user_name
, pwd
->smb_name
)) {
834 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
839 DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
841 /* User name matches - get uid and password */
842 p
++; /* Go past ':' */
845 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
846 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
851 while (*p
&& isdigit(*p
))
854 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
855 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
861 * Now get the password value - this should be 32 hex digits
862 * which are the ascii representations of a 16 byte string.
863 * Get two at a time and put them into the password.
867 /* Record exact password position */
868 pwd_seekpos
+= PTR_DIFF(p
, linebuf
);
870 if (!override
&& (*p
== '*' || *p
== 'X')) {
871 /* Password deliberately invalid - end here. */
872 DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name
));
873 pw_file_unlock(lockfd
, &pw_file_lock_depth
);
878 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
879 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
880 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
886 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
887 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
892 if (!override
&& (*p
== '*' || *p
== 'X')) {
893 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
898 /* Now check if the NT compatible password is
900 p
+= 33; /* Move to the first character of the line after
901 the lanman password. */
902 if (linebuf_len
< (PTR_DIFF(p
, linebuf
) + 33)) {
903 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
904 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
910 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
911 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
917 * Now check if the account info and the password last
918 * change time is available.
920 p
+= 33; /* Move to the first character of the line after
924 * If both NT and lanman passwords are provided - reset password
928 if(pwd
->smb_passwd
!= NULL
|| pwd
->smb_nt_passwd
!= NULL
) {
929 /* Reqiure password in the future (should ACB_DISABLED also be reset?) */
930 pwd
->acct_ctrl
&= ~(ACB_PWNOTREQ
);
936 encode_bits
[i
++] = *p
++;
937 while((linebuf_len
> PTR_DIFF(p
, linebuf
)) && (*p
!= ']'))
938 encode_bits
[i
++] = *p
++;
940 encode_bits
[i
++] = ']';
941 encode_bits
[i
++] = '\0';
943 if(i
== NEW_PW_FORMAT_SPACE_PADDED_LEN
) {
945 * We are using a new format, space padded
946 * acct ctrl field. Encode the given acct ctrl
949 fstrcpy(encode_bits
, pdb_encode_acct_ctrl(pwd
->acct_ctrl
, NEW_PW_FORMAT_SPACE_PADDED_LEN
));
952 * If using the old format and the ACB_DISABLED or
953 * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
954 * here as we have no space to encode the change.
956 if(pwd
->acct_ctrl
& (ACB_DISABLED
|ACB_PWNOTREQ
)) {
957 pwd
->smb_passwd
= NULL
;
958 pwd
->smb_nt_passwd
= NULL
;
962 /* Go past the ']' */
963 if(linebuf_len
> PTR_DIFF(p
, linebuf
))
966 if((linebuf_len
> PTR_DIFF(p
, linebuf
)) && (*p
== ':')) {
969 /* We should be pointing at the LCT entry. */
970 if((linebuf_len
> (PTR_DIFF(p
, linebuf
) + 13)) && (StrnCaseCmp((char *)p
, "LCT-", 4) == 0)) {
973 for(i
= 0; i
< 8; i
++) {
974 if(p
[i
] == '\0' || !isxdigit(p
[i
]))
979 * p points at 8 characters of hex digits -
980 * read into a time_t as the seconds since
981 * 1970 that the password was last changed.
983 got_pass_last_set_time
= True
;
985 } /* *p && StrnCaseCmp() */
989 /* Entry is correctly formed. */
991 /* Create the 32 byte representation of the new p16 */
992 if(pwd
->smb_passwd
!= NULL
) {
993 for (i
= 0; i
< 16; i
++) {
994 slprintf(&ascii_p16
[i
*2], sizeof(fstring
) - 1, "%02X", (uchar
) pwd
->smb_passwd
[i
]);
997 if(pwd
->acct_ctrl
& ACB_PWNOTREQ
)
998 fstrcpy(ascii_p16
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1000 fstrcpy(ascii_p16
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1003 /* Add on the NT md4 hash */
1004 ascii_p16
[32] = ':';
1006 if (pwd
->smb_nt_passwd
!= NULL
) {
1007 for (i
= 0; i
< 16; i
++) {
1008 slprintf(&ascii_p16
[(i
*2)+33], sizeof(fstring
) - 1, "%02X", (uchar
) pwd
->smb_nt_passwd
[i
]);
1011 if(pwd
->acct_ctrl
& ACB_PWNOTREQ
)
1012 fstrcpy(&ascii_p16
[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1014 fstrcpy(&ascii_p16
[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1016 ascii_p16
[65] = ':';
1017 ascii_p16
[66] = '\0'; /* null-terminate the string so that strlen works */
1019 /* Add on the account info bits and the time of last
1022 pwd
->pass_last_set_time
= time(NULL
);
1024 if(got_pass_last_set_time
) {
1025 slprintf(&ascii_p16
[strlen(ascii_p16
)],
1026 sizeof(ascii_p16
)-(strlen(ascii_p16
)+1),
1028 encode_bits
, (uint32
)pwd
->pass_last_set_time
);
1029 wr_len
= strlen(ascii_p16
);
1032 #ifdef DEBUG_PASSWORD
1033 DEBUG(100,("mod_smbfilepwd_entry: "));
1034 dump_data(100, ascii_p16
, wr_len
);
1037 if(wr_len
> sizeof(linebuf
)) {
1038 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len
+1));
1039 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1045 * Do an atomic write into the file at the position defined by
1049 /* The mod user write needs to be atomic - so get the fd from
1050 the fp and do a raw write() call.
1055 if (sys_lseek(fd
, pwd_seekpos
- 1, SEEK_SET
) != pwd_seekpos
- 1) {
1056 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1057 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1062 /* Sanity check - ensure the areas we are writing are framed by ':' */
1063 if (read(fd
, linebuf
, wr_len
+1) != wr_len
+1) {
1064 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile
));
1065 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1070 if ((linebuf
[0] != ':') || (linebuf
[wr_len
] != ':')) {
1071 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile
));
1072 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1077 if (sys_lseek(fd
, pwd_seekpos
, SEEK_SET
) != pwd_seekpos
) {
1078 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile
));
1079 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1084 if (write(fd
, ascii_p16
, wr_len
) != wr_len
) {
1085 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile
));
1086 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1091 pw_file_unlock(lockfd
,&pw_file_lock_depth
);
1096 /************************************************************************
1097 Routine to delete an entry in the smbpasswd file by name.
1098 *************************************************************************/
1100 static BOOL
del_smbfilepwd_entry(const char *name
)
1102 char *pfile
= lp_smb_passwd_file();
1104 struct smb_passwd
*pwd
= NULL
;
1106 FILE *fp_write
= NULL
;
1107 int pfile2_lockdepth
= 0;
1109 slprintf(pfile2
, sizeof(pfile2
)-1, "%s.%u", pfile
, (unsigned)getpid() );
1112 * Open the smbpassword file - for update. It needs to be update
1113 * as we need any other processes to wait until we have replaced
1117 if((fp
= startsmbfilepwent(True
)) == NULL
) {
1118 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1123 * Create the replacement password file.
1125 if((fp_write
= startsmbfilepwent_internal(pfile2
, PWF_CREATE
, &pfile2_lockdepth
)) == NULL
) {
1126 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile
));
1127 endsmbfilepwent(fp
);
1132 * Scan the file, a line at a time and check if the name matches.
1135 while ((pwd
= getsmbfilepwent(fp
)) != NULL
) {
1137 size_t new_entry_length
;
1139 if (strequal(name
, pwd
->smb_name
)) {
1140 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name
));
1145 * We need to copy the entry out into the second file.
1148 if((new_entry
= format_new_smbpasswd_entry(pwd
)) == NULL
) {
1149 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1150 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1152 endsmbfilepwent(fp
);
1153 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1157 new_entry_length
= strlen(new_entry
);
1159 if(fwrite(new_entry
, 1, new_entry_length
, fp_write
) != new_entry_length
) {
1160 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1161 Error was %s\n", pwd
->smb_name
, pfile2
, strerror(errno
)));
1163 endsmbfilepwent(fp
);
1164 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1173 * Ensure pfile2 is flushed before rename.
1176 if(fflush(fp_write
) != 0) {
1177 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2
, strerror(errno
)));
1178 endsmbfilepwent(fp
);
1179 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1184 * Do an atomic rename - then release the locks.
1187 if(rename(pfile2
,pfile
) != 0) {
1190 endsmbfilepwent(fp
);
1191 endsmbfilepwent_internal(fp_write
,&pfile2_lockdepth
);
1196 * Stub functions - implemented in terms of others.
1199 static BOOL
mod_smbfile21pwd_entry(struct sam_passwd
* pwd
, BOOL override
)
1201 return mod_smbfilepwd_entry(pdb_sam_to_smb(pwd
), override
);
1204 static BOOL
add_smbfile21pwd_entry(struct sam_passwd
*newpwd
)
1206 return add_smbfilepwd_entry(pdb_sam_to_smb(newpwd
));
1209 static struct sam_disp_info
*getsmbfiledispnam(char *name
)
1211 return pdb_sam_to_dispinfo(getsam21pwnam(name
));
1214 static struct sam_disp_info
*getsmbfiledisprid(uint32 rid
)
1216 return pdb_sam_to_dispinfo(getsam21pwrid(rid
));
1219 static struct sam_disp_info
*getsmbfiledispent(void *vp
)
1221 return pdb_sam_to_dispinfo(getsam21pwent(vp
));
1224 static struct passdb_ops file_ops
= {
1229 iterate_getsmbpwnam
, /* In passdb.c */
1230 iterate_getsmbpwuid
, /* In passdb.c */
1231 iterate_getsmbpwrid
, /* In passdb.c */
1233 add_smbfilepwd_entry
,
1234 mod_smbfilepwd_entry
,
1235 del_smbfilepwd_entry
,
1237 iterate_getsam21pwnam
,
1238 iterate_getsam21pwuid
,
1239 iterate_getsam21pwrid
,
1240 add_smbfile21pwd_entry
,
1241 mod_smbfile21pwd_entry
,
1247 struct passdb_ops
*file_initialize_password_db(void)
1253 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1254 void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1255 #endif /* USE_SMBPASS_DB */