2 * Unix SMB/Netbios implementation.
3 * Version 1.9. SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Modified by Jeremy Allison 1995.
6 * Modified by Gerald (Jerry) Carter 2000-2001
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 675
20 * Mass Ave, Cambridge, MA 02139, USA.
25 #ifdef WITH_SMBPASSWD_SAM
29 smb_passwd is analogous to sam_passwd used everywhere
30 else. However, smb_passwd is limited to the information
31 stored by an smbpasswd entry
36 uid_t smb_userid; /* this is actually the unix uid_t */
37 char *smb_name; /* username string */
39 unsigned char *smb_passwd; /* Null if no password */
40 unsigned char *smb_nt_passwd; /* Null if no password */
42 uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
43 time_t pass_last_set_time; /* password last set time */
47 extern int DEBUGLEVEL;
48 extern pstring samlogon_user;
49 extern BOOL sam_logon_in_ssb;
50 extern struct passdb_ops pdb_ops;
53 /* used for maintain locks on the smbpasswd file */
54 static int pw_file_lock_depth;
55 static void *global_vp;
58 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
60 /***************************************************************
61 Lock an fd. Abandon after waitsecs seconds.
62 ****************************************************************/
64 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
69 if(*plock_depth == 0) {
70 if (!do_file_lock(fd, secs, type)) {
71 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
82 /***************************************************************
83 Unlock an fd. Abandon after waitsecs seconds.
84 ****************************************************************/
86 static BOOL pw_file_unlock(int fd, int *plock_depth)
91 ret = do_file_lock(fd, 5, F_UNLCK);
97 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
103 /**************************************************************
104 Intialize a smb_passwd struct
105 *************************************************************/
106 static void pdb_init_smb(struct smb_passwd *user)
112 user->pass_last_set_time = (time_t)-1;
117 /***************************************************************
118 Internal fn to enumerate the smbpasswd list. Returns a void pointer
119 to ensure no modification outside this module. Checks for atomic
120 rename of smbpasswd file on update or create once the lock has
121 been granted to prevent race conditions. JRA.
122 ****************************************************************/
124 static void *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
127 const char *open_mode = NULL;
129 int lock_type = F_RDLCK;
132 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
147 * Ensure atomic file creation.
152 for(i = 0; i < 5; i++) {
153 if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
155 sys_usleep(200); /* Spin, spin... */
158 DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
168 for(race_loop = 0; race_loop < 5; race_loop++) {
169 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
171 if((fp = sys_fopen(pfile, open_mode)) == NULL) {
172 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
176 if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
177 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
183 * Only check for replacement races on update or create.
184 * For read we don't mind if the data is one record out of date.
187 if(type == PWF_READ) {
190 SMB_STRUCT_STAT sbuf1, sbuf2;
193 * Avoid the potential race condition between the open and the lock
194 * by doing a stat on the filename and an fstat on the fd. If the
195 * two inodes differ then someone did a rename between the open and
196 * the lock. Back off and try the open again. Only do this 5 times to
197 * prevent infinate loops. JRA.
200 if (sys_stat(pfile,&sbuf1) != 0) {
201 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
202 pw_file_unlock(fileno(fp), lock_depth);
207 if (sys_fstat(fileno(fp),&sbuf2) != 0) {
208 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
209 pw_file_unlock(fileno(fp), lock_depth);
214 if( sbuf1.st_ino == sbuf2.st_ino) {
220 * Race occurred - back off and try again...
223 pw_file_unlock(fileno(fp), lock_depth);
229 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
233 /* Set a buffer to do more efficient reads */
234 setvbuf(fp, (char *)NULL, _IOFBF, 1024);
236 /* Make sure it is only rw by the owner */
237 if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
238 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
239 Error was %s\n.", pfile, strerror(errno) ));
240 pw_file_unlock(fileno(fp), lock_depth);
245 /* We have a lock on the file. */
249 /***************************************************************
250 End enumeration of the smbpasswd list.
251 ****************************************************************/
252 static void endsmbfilepwent(void *vp, int *lock_depth)
254 FILE *fp = (FILE *)vp;
256 pw_file_unlock(fileno(fp), lock_depth);
258 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
261 /*************************************************************************
262 Routine to return the next entry in the smbpasswd list.
263 *************************************************************************/
265 static struct smb_passwd *getsmbfilepwent(void *vp)
267 /* Static buffers we will return. */
268 static struct smb_passwd pw_buf;
269 static pstring user_name;
270 static unsigned char smbpwd[16];
271 static unsigned char smbntpwd[16];
272 FILE *fp = (FILE *)vp;
280 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
284 pdb_init_smb(&pw_buf);
286 pw_buf.acct_ctrl = ACB_NORMAL;
289 * Scan the file, a line at a time and check if the name matches.
294 fgets(linebuf, 256, fp);
300 * Check if the string is terminated with a newline - if not
301 * then we must keep reading and discard until we get one.
303 if ((linebuf_len = strlen(linebuf)) == 0)
306 if (linebuf[linebuf_len - 1] != '\n') {
308 while (!ferror(fp) && !feof(fp)) {
314 linebuf[linebuf_len - 1] = '\0';
316 #ifdef DEBUG_PASSWORD
317 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
319 if ((linebuf[0] == 0) && feof(fp)) {
320 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
324 * The line we have should be of the form :-
326 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
331 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
333 * if Windows NT compatible passwords are also present.
334 * [Account type] is an ascii encoding of the type of account.
335 * LCT-(8 hex digits) is the time_t value of the last change time.
338 if (linebuf[0] == '#' || linebuf[0] == '\0') {
339 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
342 p = (unsigned char *) strchr_m(linebuf, ':');
344 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
348 * As 256 is shorter than a pstring we don't need to check
349 * length here - if this ever changes....
351 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
352 user_name[PTR_DIFF(p, linebuf)] = '\0';
356 p++; /* Go past ':' */
359 DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
364 DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
368 uidval = atoi((char *) p);
370 while (*p && isdigit(*p))
374 DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
378 pw_buf.smb_name = user_name;
379 pw_buf.smb_userid = uidval;
382 * Now get the password value - this should be 32 hex digits
383 * which are the ascii representations of a 16 byte string.
384 * Get two at a time and put them into the password.
390 if (*p == '*' || *p == 'X') {
391 /* Password deliberately invalid - end here. */
392 DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
393 pw_buf.smb_nt_passwd = NULL;
394 pw_buf.smb_passwd = NULL;
395 pw_buf.acct_ctrl |= ACB_DISABLED;
399 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
400 DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
405 DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
409 if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
410 pw_buf.smb_passwd = NULL;
411 pw_buf.acct_ctrl |= ACB_PWNOTREQ;
413 if (!pdb_gethexpwd((char *)p, smbpwd)) {
414 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
417 pw_buf.smb_passwd = smbpwd;
421 * Now check if the NT compatible password is
424 pw_buf.smb_nt_passwd = NULL;
426 p += 33; /* Move to the first character of the line after
427 the lanman password. */
428 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
429 if (*p != '*' && *p != 'X') {
430 if(pdb_gethexpwd((char *)p,smbntpwd))
431 pw_buf.smb_nt_passwd = smbntpwd;
433 p += 33; /* Move to the first character of the line after
437 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
442 unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
443 pw_buf.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
445 /* Must have some account type set. */
446 if(pw_buf.acct_ctrl == 0)
447 pw_buf.acct_ctrl = ACB_NORMAL;
449 /* Now try and get the last change time. */
454 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
457 for(i = 0; i < 8; i++) {
458 if(p[i] == '\0' || !isxdigit(p[i]))
463 * p points at 8 characters of hex digits -
464 * read into a time_t as the seconds since
465 * 1970 that the password was last changed.
467 pw_buf.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
472 /* 'Old' style file. Fake up based on user name. */
474 * Currently trust accounts are kept in the same
475 * password file as 'normal accounts'. If this changes
476 * we will have to fix this code. JRA.
478 if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
479 pw_buf.acct_ctrl &= ~ACB_NORMAL;
480 pw_buf.acct_ctrl |= ACB_WSTRUST;
487 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
491 /************************************************************************
492 Create a new smbpasswd entry - malloced space returned.
493 *************************************************************************/
495 static char *format_new_smbpasswd_entry(struct smb_passwd *newpwd)
497 int new_entry_length;
502 new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
504 if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
505 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
509 slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
510 p = &new_entry[strlen(new_entry)];
512 if(newpwd->smb_passwd != NULL) {
513 for( i = 0; i < 16; i++) {
514 slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
518 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
519 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
521 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
528 if(newpwd->smb_nt_passwd != NULL) {
529 for( i = 0; i < 16; i++) {
530 slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
533 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
534 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
536 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
543 /* Add the account encoding and the last change time. */
544 slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
545 pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
546 (uint32)newpwd->pass_last_set_time);
551 /************************************************************************
552 Routine to add an entry to the smbpasswd file.
553 *************************************************************************/
555 static BOOL add_smbfilepwd_entry(struct smb_passwd *newpwd)
557 char *pfile = lp_smb_passwd_file();
558 struct smb_passwd *pwd = NULL;
562 size_t new_entry_length;
566 /* Open the smbpassword file - for update. */
567 fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
569 if (fp == NULL && errno == ENOENT) {
570 /* Try again - create. */
571 fp = startsmbfilepwent(pfile, PWF_CREATE, &pw_file_lock_depth);
575 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
580 * Scan the file, a line at a time and check if the name matches.
583 while ((pwd = getsmbfilepwent(fp)) != NULL)
585 if (strequal(newpwd->smb_name, pwd->smb_name))
587 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
588 endsmbfilepwent(fp, &pw_file_lock_depth);
593 /* Ok - entry doesn't exist. We can add it */
595 /* Create a new smb passwd entry and set it to the given password. */
597 * The add user write needs to be atomic - so get the fd from
598 * the fp and do a raw write() call.
602 if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
604 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
605 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
606 endsmbfilepwent(fp, &pw_file_lock_depth);
610 if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
612 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
613 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
614 endsmbfilepwent(fp, &pw_file_lock_depth);
618 new_entry_length = strlen(new_entry);
620 #ifdef DEBUG_PASSWORD
621 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
622 fd, new_entry_length, new_entry));
625 if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
627 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
628 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
630 /* Remove the entry we just wrote. */
631 if(sys_ftruncate(fd, offpos) == -1)
633 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
634 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
635 newpwd->smb_name, strerror(errno)));
638 endsmbfilepwent(fp, &pw_file_lock_depth);
644 endsmbfilepwent(fp, &pw_file_lock_depth);
648 /************************************************************************
649 Routine to search the smbpasswd file for an entry matching the username.
650 and then modify its password entry. We can't use the startsmbpwent()/
651 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
652 in the actual file to decide how much room we have to write data.
653 override = False, normal
654 override = True, override XXXXXXXX'd out password or NO PASS
655 ************************************************************************/
657 static BOOL mod_smbfilepwd_entry(struct smb_passwd* pwd, BOOL override)
659 /* Static buffers we will return. */
660 static pstring user_name;
667 unsigned char *p = NULL;
668 size_t linebuf_len = 0;
671 char *pfile = lp_smb_passwd_file();
672 BOOL found_entry = False;
673 BOOL got_pass_last_set_time = False;
675 SMB_OFF_T pwd_seekpos = 0;
682 DEBUG(0, ("No SMB password file set\n"));
685 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
687 fp = sys_fopen(pfile, "r+");
690 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
693 /* Set a buffer to do more efficient reads */
694 setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
698 if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
699 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
704 /* Make sure it is only rw by the owner */
707 /* We have a write lock on the file. */
709 * Scan the file, a line at a time and check if the name matches.
712 pwd_seekpos = sys_ftell(fp);
716 fgets(linebuf, sizeof(linebuf), fp);
718 pw_file_unlock(lockfd, &pw_file_lock_depth);
724 * Check if the string is terminated with a newline - if not
725 * then we must keep reading and discard until we get one.
727 linebuf_len = strlen(linebuf);
728 if (linebuf[linebuf_len - 1] != '\n') {
730 while (!ferror(fp) && !feof(fp)) {
737 linebuf[linebuf_len - 1] = '\0';
740 #ifdef DEBUG_PASSWORD
741 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
744 if ((linebuf[0] == 0) && feof(fp)) {
745 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
750 * The line we have should be of the form :-
752 * username:uid:[32hex bytes]:....other flags presently
757 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
759 * if Windows NT compatible passwords are also present.
762 if (linebuf[0] == '#' || linebuf[0] == '\0') {
763 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
767 p = (unsigned char *) strchr_m(linebuf, ':');
770 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
775 * As 256 is shorter than a pstring we don't need to check
776 * length here - if this ever changes....
778 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
779 user_name[PTR_DIFF(p, linebuf)] = '\0';
780 if (strequal(user_name, pwd->smb_name)) {
787 pw_file_unlock(lockfd, &pw_file_lock_depth);
792 DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
794 /* User name matches - get uid and password */
795 p++; /* Go past ':' */
798 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
799 pw_file_unlock(lockfd, &pw_file_lock_depth);
804 while (*p && isdigit(*p))
807 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
808 pw_file_unlock(lockfd, &pw_file_lock_depth);
814 * Now get the password value - this should be 32 hex digits
815 * which are the ascii representations of a 16 byte string.
816 * Get two at a time and put them into the password.
820 /* Record exact password position */
821 pwd_seekpos += PTR_DIFF(p, linebuf);
823 if (!override && (*p == '*' || *p == 'X')) {
824 /* Password deliberately invalid - end here. */
825 DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
826 pw_file_unlock(lockfd, &pw_file_lock_depth);
831 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
832 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
833 pw_file_unlock(lockfd,&pw_file_lock_depth);
839 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
840 pw_file_unlock(lockfd,&pw_file_lock_depth);
845 if (!override && (*p == '*' || *p == 'X')) {
846 pw_file_unlock(lockfd,&pw_file_lock_depth);
851 /* Now check if the NT compatible password is
853 p += 33; /* Move to the first character of the line after
854 the lanman password. */
855 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
856 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
857 pw_file_unlock(lockfd,&pw_file_lock_depth);
863 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
864 pw_file_unlock(lockfd,&pw_file_lock_depth);
870 * Now check if the account info and the password last
871 * change time is available.
873 p += 33; /* Move to the first character of the line after
877 * If both NT and lanman passwords are provided - reset password
881 if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
882 /* Reqiure password in the future (should ACB_DISABLED also be reset?) */
883 pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
889 encode_bits[i++] = *p++;
890 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
891 encode_bits[i++] = *p++;
893 encode_bits[i++] = ']';
894 encode_bits[i++] = '\0';
896 if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
898 * We are using a new format, space padded
899 * acct ctrl field. Encode the given acct ctrl
902 fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
905 * If using the old format and the ACB_DISABLED or
906 * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
907 * here as we have no space to encode the change.
909 if(pwd->acct_ctrl & (ACB_DISABLED|ACB_PWNOTREQ)) {
910 pwd->smb_passwd = NULL;
911 pwd->smb_nt_passwd = NULL;
915 /* Go past the ']' */
916 if(linebuf_len > PTR_DIFF(p, linebuf))
919 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
922 /* We should be pointing at the LCT entry. */
923 if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
926 for(i = 0; i < 8; i++) {
927 if(p[i] == '\0' || !isxdigit(p[i]))
932 * p points at 8 characters of hex digits -
933 * read into a time_t as the seconds since
934 * 1970 that the password was last changed.
936 got_pass_last_set_time = True;
938 } /* *p && StrnCaseCmp() */
942 /* Entry is correctly formed. */
944 /* Create the 32 byte representation of the new p16 */
945 if(pwd->smb_passwd != NULL) {
946 for (i = 0; i < 16; i++) {
947 slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
950 if(pwd->acct_ctrl & ACB_PWNOTREQ)
951 fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
953 fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
956 /* Add on the NT md4 hash */
959 if (pwd->smb_nt_passwd != NULL) {
960 for (i = 0; i < 16; i++) {
961 slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
964 if(pwd->acct_ctrl & ACB_PWNOTREQ)
965 fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
967 fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
970 ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
972 /* Add on the account info bits and the time of last
975 pwd->pass_last_set_time = time(NULL);
977 if(got_pass_last_set_time) {
978 slprintf(&ascii_p16[strlen(ascii_p16)],
979 sizeof(ascii_p16)-(strlen(ascii_p16)+1),
981 encode_bits, (uint32)pwd->pass_last_set_time );
982 wr_len = strlen(ascii_p16);
985 #ifdef DEBUG_PASSWORD
986 DEBUG(100,("mod_smbfilepwd_entry: "));
987 dump_data(100, ascii_p16, wr_len);
990 if(wr_len > sizeof(linebuf)) {
991 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
992 pw_file_unlock(lockfd,&pw_file_lock_depth);
998 * Do an atomic write into the file at the position defined by
1002 /* The mod user write needs to be atomic - so get the fd from
1003 the fp and do a raw write() call.
1008 if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
1009 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1010 pw_file_unlock(lockfd,&pw_file_lock_depth);
1015 /* Sanity check - ensure the areas we are writing are framed by ':' */
1016 if (read(fd, linebuf, wr_len+1) != wr_len+1) {
1017 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
1018 pw_file_unlock(lockfd,&pw_file_lock_depth);
1023 if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
1024 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
1025 pw_file_unlock(lockfd,&pw_file_lock_depth);
1030 if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
1031 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1032 pw_file_unlock(lockfd,&pw_file_lock_depth);
1037 if (write(fd, ascii_p16, wr_len) != wr_len) {
1038 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
1039 pw_file_unlock(lockfd,&pw_file_lock_depth);
1044 pw_file_unlock(lockfd,&pw_file_lock_depth);
1049 /************************************************************************
1050 Routine to delete an entry in the smbpasswd file by name.
1051 *************************************************************************/
1053 static BOOL del_smbfilepwd_entry(const char *name)
1055 char *pfile = lp_smb_passwd_file();
1057 struct smb_passwd *pwd = NULL;
1059 FILE *fp_write = NULL;
1060 int pfile2_lockdepth = 0;
1062 slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
1065 * Open the smbpassword file - for update. It needs to be update
1066 * as we need any other processes to wait until we have replaced
1070 if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth)) == NULL) {
1071 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1076 * Create the replacement password file.
1078 if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
1079 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1080 endsmbfilepwent(fp, &pw_file_lock_depth);
1085 * Scan the file, a line at a time and check if the name matches.
1088 while ((pwd = getsmbfilepwent(fp)) != NULL) {
1090 size_t new_entry_length;
1092 if (strequal(name, pwd->smb_name)) {
1093 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
1098 * We need to copy the entry out into the second file.
1101 if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
1103 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1104 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1106 endsmbfilepwent(fp, &pw_file_lock_depth);
1107 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1111 new_entry_length = strlen(new_entry);
1113 if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
1115 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1116 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1118 endsmbfilepwent(fp, &pw_file_lock_depth);
1119 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1128 * Ensure pfile2 is flushed before rename.
1131 if(fflush(fp_write) != 0)
1133 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
1134 endsmbfilepwent(fp, &pw_file_lock_depth);
1135 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1140 * Do an atomic rename - then release the locks.
1143 if(rename(pfile2,pfile) != 0) {
1147 endsmbfilepwent(fp, &pw_file_lock_depth);
1148 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1152 /*********************************************************************
1153 Create a smb_passwd struct from a SAM_ACCOUNT.
1154 We will not allocate any new memory. The smb_passwd struct
1155 should only stay around as long as the SAM_ACCOUNT does.
1156 ********************************************************************/
1157 static BOOL build_smb_pass (struct smb_passwd *smb_pw, SAM_ACCOUNT *sampass)
1159 if (sampass == NULL)
1162 ZERO_STRUCTP(smb_pw);
1164 smb_pw->smb_userid=pdb_get_uid(sampass);
1165 smb_pw->smb_name=pdb_get_username(sampass);
1167 smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1168 smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1170 smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1171 smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1177 /*********************************************************************
1178 Create a SAM_ACCOUNT from a smb_passwd struct
1179 ********************************************************************/
1180 static BOOL build_sam_account(SAM_ACCOUNT *sam_pass, struct smb_passwd *pw_buf)
1182 struct passwd *pwfile;
1184 if (sam_pass==NULL) {
1185 DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
1189 /* Verify in system password file...
1190 FIXME!!! This is where we should look up an internal
1191 mapping of allocated uid for machine accounts as well
1193 pwfile = sys_getpwnam(pw_buf->smb_name);
1194 if (pwfile == NULL) {
1195 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s not in unix passwd database!\n", pw_buf->smb_name));
1199 /* FIXME!! This doesn't belong here. Should be set in net_sam_logon()
1201 pstrcpy(samlogon_user, pw_buf->smb_name);
1203 pdb_set_uid (sam_pass, pwfile->pw_uid);
1204 pdb_set_gid (sam_pass, pwfile->pw_gid);
1205 pdb_set_fullname(sam_pass, pwfile->pw_gecos);
1207 pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
1209 /* should check the group mapping here instead of static mappig. JFM */
1210 pdb_set_group_rid(sam_pass, pdb_gid_to_group_rid(pwfile->pw_gid));
1212 pdb_set_username (sam_pass, pw_buf->smb_name);
1213 pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
1214 pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
1215 pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
1216 pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
1217 pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time);
1218 pdb_set_domain (sam_pass, lp_workgroup());
1220 pdb_set_dir_drive (sam_pass, lp_logon_drive());
1222 /* the smbpasswd format doesn't have a must change time field, so
1223 we can't get this right. The best we can do is to set this to
1224 some time in the future. 21 days seems as reasonable as any other value :)
1226 pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
1228 /* check if this is a user account or a machine account */
1229 if (samlogon_user[strlen(samlogon_user)-1] != '$')
1232 gid_t gid = getegid();
1234 sam_logon_in_ssb = True;
1236 pstrcpy(str, lp_logon_script());
1237 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1238 pdb_set_logon_script(sam_pass, str);
1240 pstrcpy(str, lp_logon_path());
1241 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1242 pdb_set_profile_path(sam_pass, str);
1244 pstrcpy(str, lp_logon_home());
1245 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1246 pdb_set_homedir(sam_pass, str);
1248 sam_logon_in_ssb = False;
1250 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
1251 pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS);
1256 /*****************************************************************
1257 Functions to be implemented by the new passdb API
1258 ****************************************************************/
1259 BOOL pdb_setsampwent (BOOL update)
1261 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1262 update ? PWF_UPDATE : PWF_READ,
1263 &pw_file_lock_depth);
1265 /* did we fail? Should we try to create it? */
1266 if (!global_vp && update && errno == ENOENT)
1269 /* slprintf(msg_str,msg_str_len-1,
1270 "smbpasswd file did not exist - attempting to create it.\n"); */
1271 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
1272 fp = sys_fopen(lp_smb_passwd_file(), "w");
1275 fprintf(fp, "# Samba SMB password file\n");
1279 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1280 update ? PWF_UPDATE : PWF_READ,
1281 &pw_file_lock_depth);
1284 return (global_vp != NULL);
1287 void pdb_endsampwent (void)
1289 endsmbfilepwent(global_vp, &pw_file_lock_depth);
1292 /*****************************************************************
1293 ****************************************************************/
1294 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
1296 struct smb_passwd *pw_buf=NULL;
1298 DEBUG(5,("pdb_getsampwent\n"));
1301 DEBUG(5,("pdb_getsampwent: user is NULL\n"));
1303 smb_panic("NULL pointer passed to pdb_getsampwent\n");
1310 /* do we have an entry? */
1311 pw_buf = getsmbfilepwent(global_vp);
1315 /* build the SAM_ACCOUNT entry from the smb_passwd struct.
1316 We loop in case the user in the pdb does not exist in
1317 the local system password file */
1318 if (build_sam_account(user, pw_buf))
1322 DEBUG(5,("pdb_getsampwent:done\n"));
1329 /****************************************************************
1330 Search smbpasswd file by iterating over the entries. Do not
1331 call getpwnam() for unix account information until we have found
1333 ***************************************************************/
1334 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, char *username)
1336 struct smb_passwd *smb_pw;
1338 char *domain = NULL;
1342 DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
1345 /* break the username from the domain if we have
1346 been given a string in the form 'DOMAIN\user' */
1347 fstrcpy (name, username);
1348 if ((user=strchr_m(name, '\\')) != NULL) {
1354 /* if a domain was specified and it wasn't ours
1355 then there is no chance of matching */
1356 if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
1359 /* startsmbfilepwent() is used here as we don't want to lookup
1360 the UNIX account in the local system password file until
1362 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1365 DEBUG(0, ("unable to open passdb database.\n"));
1369 /* if we have a domain name, then we should map it to a UNIX
1374 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1375 /* do nothing....another loop */ ;
1377 endsmbfilepwent(fp, &pw_file_lock_depth);
1380 /* did we locate the username in smbpasswd */
1384 DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
1387 DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
1389 smb_panic("NULL pointer passed to pdb_getsampwnam\n");
1394 /* now build the SAM_ACCOUNT */
1395 if (!build_sam_account(sam_acct, smb_pw))
1403 BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
1405 struct smb_passwd *smb_pw;
1408 DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", uid));
1410 /* Open the sam password file - not for update. */
1411 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1414 DEBUG(0, ("unable to open passdb database.\n"));
1418 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
1421 endsmbfilepwent(fp, &pw_file_lock_depth);
1423 /* did we locate the username in smbpasswd */
1427 DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
1430 DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
1432 smb_panic("NULL pointer passed to pdb_getsampwuid\n");
1437 /* now build the SAM_ACCOUNT */
1438 if (!build_sam_account(sam_acct, smb_pw))
1445 BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
1447 struct smb_passwd *smb_pw;
1450 DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
1452 /* Open the sam password file - not for update. */
1453 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1456 DEBUG(0, ("unable to open passdb database.\n"));
1460 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1463 endsmbfilepwent(fp, &pw_file_lock_depth);
1466 /* did we locate the username in smbpasswd */
1470 DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
1473 DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
1475 smb_panic("NULL pointer passed to pdb_getsampwrid\n");
1480 /* now build the SAM_ACCOUNT */
1481 if (!build_sam_account (sam_acct, smb_pw))
1488 BOOL pdb_add_sam_account(SAM_ACCOUNT *sampass)
1490 struct smb_passwd smb_pw;
1492 /* convert the SAM_ACCOUNT */
1493 build_smb_pass(&smb_pw, sampass);
1496 if(!add_smbfilepwd_entry(&smb_pw))
1502 BOOL pdb_update_sam_account(SAM_ACCOUNT *sampass, BOOL override)
1504 struct smb_passwd smb_pw;
1506 /* convert the SAM_ACCOUNT */
1507 build_smb_pass(&smb_pw, sampass);
1509 /* update the entry */
1510 if(!mod_smbfilepwd_entry(&smb_pw, override))
1516 BOOL pdb_delete_sam_account (char* username)
1518 return del_smbfilepwd_entry(username);
1522 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1523 void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1524 #endif /* WTH_SMBPASSWD_SAM*/