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 /* FIXME!! What should this be set to? New smb.conf parameter maybe?
1223 max password age? For now, we'll use the current time + 21 days.
1225 pdb_set_pass_must_change_time (sam_pass, time(NULL)+1814400);
1227 /* check if this is a user account or a machine account */
1228 if (samlogon_user[strlen(samlogon_user)-1] != '$')
1231 gid_t gid = getegid();
1233 sam_logon_in_ssb = True;
1235 pstrcpy(str, lp_logon_script());
1236 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1237 pdb_set_logon_script(sam_pass, str);
1239 pstrcpy(str, lp_logon_path());
1240 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1241 pdb_set_profile_path(sam_pass, str);
1243 pstrcpy(str, lp_logon_home());
1244 standard_sub_advanced(-1, pw_buf->smb_name, "", gid, str);
1245 pdb_set_homedir(sam_pass, str);
1247 sam_logon_in_ssb = False;
1249 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
1250 pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS);
1255 /*****************************************************************
1256 Functions to be implemented by the new passdb API
1257 ****************************************************************/
1258 BOOL pdb_setsampwent (BOOL update)
1260 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1261 update ? PWF_UPDATE : PWF_READ,
1262 &pw_file_lock_depth);
1264 /* did we fail? Should we try to create it? */
1265 if (!global_vp && update && errno == ENOENT)
1268 /* slprintf(msg_str,msg_str_len-1,
1269 "smbpasswd file did not exist - attempting to create it.\n"); */
1270 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
1271 fp = sys_fopen(lp_smb_passwd_file(), "w");
1274 fprintf(fp, "# Samba SMB password file\n");
1278 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1279 update ? PWF_UPDATE : PWF_READ,
1280 &pw_file_lock_depth);
1283 return (global_vp != NULL);
1286 void pdb_endsampwent (void)
1288 endsmbfilepwent(global_vp, &pw_file_lock_depth);
1291 /*****************************************************************
1292 ****************************************************************/
1293 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
1295 struct smb_passwd *pw_buf=NULL;
1297 DEBUG(5,("pdb_getsampwent\n"));
1300 DEBUG(5,("pdb_getsampwent: user is NULL\n"));
1302 smb_panic("NULL pointer passed to pdb_getsampwent\n");
1309 /* do we have an entry? */
1310 pw_buf = getsmbfilepwent(global_vp);
1314 /* build the SAM_ACCOUNT entry from the smb_passwd struct.
1315 We loop in case the user in the pdb does not exist in
1316 the local system password file */
1317 if (build_sam_account(user, pw_buf))
1321 DEBUG(5,("pdb_getsampwent:done\n"));
1328 /****************************************************************
1329 Search smbpasswd file by iterating over the entries. Do not
1330 call getpwnam() for unix account information until we have found
1332 ***************************************************************/
1333 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, char *username)
1335 struct smb_passwd *smb_pw;
1337 char *domain = NULL;
1341 DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
1344 /* break the username from the domain if we have
1345 been given a string in the form 'DOMAIN\user' */
1346 fstrcpy (name, username);
1347 if ((user=strchr_m(name, '\\')) != NULL) {
1353 /* if a domain was specified and it wasn't ours
1354 then there is no chance of matching */
1355 if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
1358 /* startsmbfilepwent() is used here as we don't want to lookup
1359 the UNIX account in the local system password file until
1361 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1364 DEBUG(0, ("unable to open passdb database.\n"));
1368 /* if we have a domain name, then we should map it to a UNIX
1373 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1374 /* do nothing....another loop */ ;
1376 endsmbfilepwent(fp, &pw_file_lock_depth);
1379 /* did we locate the username in smbpasswd */
1383 DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
1386 DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
1388 smb_panic("NULL pointer passed to pdb_getsampwnam\n");
1393 /* now build the SAM_ACCOUNT */
1394 if (!build_sam_account(sam_acct, smb_pw))
1402 BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
1404 struct smb_passwd *smb_pw;
1407 DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", uid));
1409 /* Open the sam password file - not for update. */
1410 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1413 DEBUG(0, ("unable to open passdb database.\n"));
1417 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
1420 endsmbfilepwent(fp, &pw_file_lock_depth);
1422 /* did we locate the username in smbpasswd */
1426 DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
1429 DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
1431 smb_panic("NULL pointer passed to pdb_getsampwuid\n");
1436 /* now build the SAM_ACCOUNT */
1437 if (!build_sam_account(sam_acct, smb_pw))
1444 BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
1446 struct smb_passwd *smb_pw;
1449 DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
1451 /* Open the sam password file - not for update. */
1452 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1455 DEBUG(0, ("unable to open passdb database.\n"));
1459 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1462 endsmbfilepwent(fp, &pw_file_lock_depth);
1465 /* did we locate the username in smbpasswd */
1469 DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
1472 DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
1474 smb_panic("NULL pointer passed to pdb_getsampwrid\n");
1479 /* now build the SAM_ACCOUNT */
1480 if (!build_sam_account (sam_acct, smb_pw))
1487 BOOL pdb_add_sam_account(SAM_ACCOUNT *sampass)
1489 struct smb_passwd smb_pw;
1491 /* convert the SAM_ACCOUNT */
1492 build_smb_pass(&smb_pw, sampass);
1495 if(!add_smbfilepwd_entry(&smb_pw))
1501 BOOL pdb_update_sam_account(SAM_ACCOUNT *sampass, BOOL override)
1503 struct smb_passwd smb_pw;
1505 /* convert the SAM_ACCOUNT */
1506 build_smb_pass(&smb_pw, sampass);
1508 /* update the entry */
1509 if(!mod_smbfilepwd_entry(&smb_pw, override))
1515 BOOL pdb_delete_sam_account (char* username)
1517 return del_smbfilepwd_entry(username);
1521 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1522 void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1523 #endif /* WTH_SMBPASSWD_SAM*/