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 const char *smb_name; /* username string */
39 const unsigned char *smb_passwd; /* Null if no password */
40 const 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 struct passdb_ops pdb_ops;
49 /* used for maintain locks on the smbpasswd file */
50 static int pw_file_lock_depth;
51 static void *global_vp;
54 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
56 /***************************************************************
57 Lock an fd. Abandon after waitsecs seconds.
58 ****************************************************************/
60 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
65 if(*plock_depth == 0) {
66 if (!do_file_lock(fd, secs, type)) {
67 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
78 /***************************************************************
79 Unlock an fd. Abandon after waitsecs seconds.
80 ****************************************************************/
82 static BOOL pw_file_unlock(int fd, int *plock_depth)
87 ret = do_file_lock(fd, 5, F_UNLCK);
93 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
99 /**************************************************************
100 Intialize a smb_passwd struct
101 *************************************************************/
103 static void pdb_init_smb(struct smb_passwd *user)
109 user->pass_last_set_time = (time_t)0;
112 /***************************************************************
113 Internal fn to enumerate the smbpasswd list. Returns a void pointer
114 to ensure no modification outside this module. Checks for atomic
115 rename of smbpasswd file on update or create once the lock has
116 been granted to prevent race conditions. JRA.
117 ****************************************************************/
119 static void *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
122 const char *open_mode = NULL;
124 int lock_type = F_RDLCK;
127 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
142 * Ensure atomic file creation.
147 for(i = 0; i < 5; i++) {
148 if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
150 sys_usleep(200); /* Spin, spin... */
153 DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
163 for(race_loop = 0; race_loop < 5; race_loop++) {
164 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
166 if((fp = sys_fopen(pfile, open_mode)) == NULL) {
167 DEBUG(2, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
171 if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
172 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
178 * Only check for replacement races on update or create.
179 * For read we don't mind if the data is one record out of date.
182 if(type == PWF_READ) {
185 SMB_STRUCT_STAT sbuf1, sbuf2;
188 * Avoid the potential race condition between the open and the lock
189 * by doing a stat on the filename and an fstat on the fd. If the
190 * two inodes differ then someone did a rename between the open and
191 * the lock. Back off and try the open again. Only do this 5 times to
192 * prevent infinate loops. JRA.
195 if (sys_stat(pfile,&sbuf1) != 0) {
196 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
197 pw_file_unlock(fileno(fp), lock_depth);
202 if (sys_fstat(fileno(fp),&sbuf2) != 0) {
203 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
204 pw_file_unlock(fileno(fp), lock_depth);
209 if( sbuf1.st_ino == sbuf2.st_ino) {
215 * Race occurred - back off and try again...
218 pw_file_unlock(fileno(fp), lock_depth);
224 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
228 /* Set a buffer to do more efficient reads */
229 setvbuf(fp, (char *)NULL, _IOFBF, 1024);
231 /* Make sure it is only rw by the owner */
232 if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
233 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
234 Error was %s\n.", pfile, strerror(errno) ));
235 pw_file_unlock(fileno(fp), lock_depth);
240 /* We have a lock on the file. */
244 /***************************************************************
245 End enumeration of the smbpasswd list.
246 ****************************************************************/
247 static void endsmbfilepwent(void *vp, int *lock_depth)
249 FILE *fp = (FILE *)vp;
251 pw_file_unlock(fileno(fp), lock_depth);
253 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
256 /*************************************************************************
257 Routine to return the next entry in the smbpasswd list.
258 *************************************************************************/
260 static struct smb_passwd *getsmbfilepwent(void *vp)
262 /* Static buffers we will return. */
263 static struct smb_passwd pw_buf;
264 static pstring user_name;
265 static unsigned char smbpwd[16];
266 static unsigned char smbntpwd[16];
267 FILE *fp = (FILE *)vp;
275 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
279 pdb_init_smb(&pw_buf);
281 pw_buf.acct_ctrl = ACB_NORMAL;
284 * Scan the file, a line at a time and check if the name matches.
289 fgets(linebuf, 256, fp);
295 * Check if the string is terminated with a newline - if not
296 * then we must keep reading and discard until we get one.
298 if ((linebuf_len = strlen(linebuf)) == 0)
301 if (linebuf[linebuf_len - 1] != '\n') {
303 while (!ferror(fp) && !feof(fp)) {
309 linebuf[linebuf_len - 1] = '\0';
311 #ifdef DEBUG_PASSWORD
312 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
314 if ((linebuf[0] == 0) && feof(fp)) {
315 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
319 * The line we have should be of the form :-
321 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
326 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
328 * if Windows NT compatible passwords are also present.
329 * [Account type] is an ascii encoding of the type of account.
330 * LCT-(8 hex digits) is the time_t value of the last change time.
333 if (linebuf[0] == '#' || linebuf[0] == '\0') {
334 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
337 p = (unsigned char *) strchr_m(linebuf, ':');
339 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
343 * As 256 is shorter than a pstring we don't need to check
344 * length here - if this ever changes....
346 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
347 user_name[PTR_DIFF(p, linebuf)] = '\0';
351 p++; /* Go past ':' */
354 DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
359 DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
363 uidval = atoi((char *) p);
365 while (*p && isdigit(*p))
369 DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
373 pw_buf.smb_name = user_name;
374 pw_buf.smb_userid = uidval;
377 * Now get the password value - this should be 32 hex digits
378 * which are the ascii representations of a 16 byte string.
379 * Get two at a time and put them into the password.
385 if (*p == '*' || *p == 'X') {
386 /* Password deliberately invalid - end here. */
387 DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
388 pw_buf.smb_nt_passwd = NULL;
389 pw_buf.smb_passwd = NULL;
390 pw_buf.acct_ctrl |= ACB_DISABLED;
394 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
395 DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
400 DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
404 if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
405 pw_buf.smb_passwd = NULL;
406 pw_buf.acct_ctrl |= ACB_PWNOTREQ;
408 if (!pdb_gethexpwd((char *)p, smbpwd)) {
409 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
412 pw_buf.smb_passwd = smbpwd;
416 * Now check if the NT compatible password is
419 pw_buf.smb_nt_passwd = NULL;
421 p += 33; /* Move to the first character of the line after
422 the lanman password. */
423 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
424 if (*p != '*' && *p != 'X') {
425 if(pdb_gethexpwd((char *)p,smbntpwd))
426 pw_buf.smb_nt_passwd = smbntpwd;
428 p += 33; /* Move to the first character of the line after
432 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
437 unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
438 pw_buf.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
440 /* Must have some account type set. */
441 if(pw_buf.acct_ctrl == 0)
442 pw_buf.acct_ctrl = ACB_NORMAL;
444 /* Now try and get the last change time. */
449 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
452 for(i = 0; i < 8; i++) {
453 if(p[i] == '\0' || !isxdigit(p[i]))
458 * p points at 8 characters of hex digits -
459 * read into a time_t as the seconds since
460 * 1970 that the password was last changed.
462 pw_buf.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
467 /* 'Old' style file. Fake up based on user name. */
469 * Currently trust accounts are kept in the same
470 * password file as 'normal accounts'. If this changes
471 * we will have to fix this code. JRA.
473 if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
474 pw_buf.acct_ctrl &= ~ACB_NORMAL;
475 pw_buf.acct_ctrl |= ACB_WSTRUST;
482 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
486 /************************************************************************
487 Create a new smbpasswd entry - malloced space returned.
488 *************************************************************************/
490 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
492 int new_entry_length;
497 new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
499 if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
500 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
504 slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
505 p = &new_entry[strlen(new_entry)];
507 if(newpwd->smb_passwd != NULL) {
508 for( i = 0; i < 16; i++) {
509 slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
513 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
514 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
516 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
523 if(newpwd->smb_nt_passwd != NULL) {
524 for( i = 0; i < 16; i++) {
525 slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
528 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
529 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
531 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
538 /* Add the account encoding and the last change time. */
539 slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
540 pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
541 (uint32)newpwd->pass_last_set_time);
546 /************************************************************************
547 Routine to add an entry to the smbpasswd file.
548 *************************************************************************/
550 static BOOL add_smbfilepwd_entry(const struct smb_passwd *newpwd)
552 char *pfile = lp_smb_passwd_file();
553 struct smb_passwd *pwd = NULL;
557 size_t new_entry_length;
561 /* Open the smbpassword file - for update. */
562 fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth);
564 if (fp == NULL && errno == ENOENT) {
565 /* Try again - create. */
566 fp = startsmbfilepwent(pfile, PWF_CREATE, &pw_file_lock_depth);
570 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
575 * Scan the file, a line at a time and check if the name matches.
578 while ((pwd = getsmbfilepwent(fp)) != NULL)
580 if (strequal(newpwd->smb_name, pwd->smb_name))
582 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
583 endsmbfilepwent(fp, &pw_file_lock_depth);
588 /* Ok - entry doesn't exist. We can add it */
590 /* Create a new smb passwd entry and set it to the given password. */
592 * The add user write needs to be atomic - so get the fd from
593 * the fp and do a raw write() call.
597 if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
599 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
600 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
601 endsmbfilepwent(fp, &pw_file_lock_depth);
605 if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
607 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
608 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
609 endsmbfilepwent(fp, &pw_file_lock_depth);
613 new_entry_length = strlen(new_entry);
615 #ifdef DEBUG_PASSWORD
616 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
617 fd, new_entry_length, new_entry));
620 if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
622 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
623 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
625 /* Remove the entry we just wrote. */
626 if(sys_ftruncate(fd, offpos) == -1)
628 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
629 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
630 newpwd->smb_name, strerror(errno)));
633 endsmbfilepwent(fp, &pw_file_lock_depth);
639 endsmbfilepwent(fp, &pw_file_lock_depth);
643 /************************************************************************
644 Routine to search the smbpasswd file for an entry matching the username.
645 and then modify its password entry. We can't use the startsmbpwent()/
646 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
647 in the actual file to decide how much room we have to write data.
648 override = False, normal
649 override = True, override XXXXXXXX'd out password or NO PASS
650 ************************************************************************/
652 static BOOL mod_smbfilepwd_entry(const struct smb_passwd* pwd, BOOL override)
654 /* Static buffers we will return. */
655 static pstring user_name;
662 unsigned char *p = NULL;
663 size_t linebuf_len = 0;
666 char *pfile = lp_smb_passwd_file();
667 BOOL found_entry = False;
668 BOOL got_pass_last_set_time = False;
670 SMB_OFF_T pwd_seekpos = 0;
677 DEBUG(0, ("No SMB password file set\n"));
680 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
682 fp = sys_fopen(pfile, "r+");
685 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
688 /* Set a buffer to do more efficient reads */
689 setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
693 if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
694 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
699 /* Make sure it is only rw by the owner */
702 /* We have a write lock on the file. */
704 * Scan the file, a line at a time and check if the name matches.
707 pwd_seekpos = sys_ftell(fp);
711 fgets(linebuf, sizeof(linebuf), fp);
713 pw_file_unlock(lockfd, &pw_file_lock_depth);
719 * Check if the string is terminated with a newline - if not
720 * then we must keep reading and discard until we get one.
722 linebuf_len = strlen(linebuf);
723 if (linebuf[linebuf_len - 1] != '\n') {
725 while (!ferror(fp) && !feof(fp)) {
732 linebuf[linebuf_len - 1] = '\0';
735 #ifdef DEBUG_PASSWORD
736 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
739 if ((linebuf[0] == 0) && feof(fp)) {
740 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
745 * The line we have should be of the form :-
747 * username:uid:[32hex bytes]:....other flags presently
752 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
754 * if Windows NT compatible passwords are also present.
757 if (linebuf[0] == '#' || linebuf[0] == '\0') {
758 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
762 p = (unsigned char *) strchr_m(linebuf, ':');
765 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
770 * As 256 is shorter than a pstring we don't need to check
771 * length here - if this ever changes....
773 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
774 user_name[PTR_DIFF(p, linebuf)] = '\0';
775 if (strequal(user_name, pwd->smb_name)) {
782 pw_file_unlock(lockfd, &pw_file_lock_depth);
787 DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
789 /* User name matches - get uid and password */
790 p++; /* Go past ':' */
793 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
794 pw_file_unlock(lockfd, &pw_file_lock_depth);
799 while (*p && isdigit(*p))
802 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
803 pw_file_unlock(lockfd, &pw_file_lock_depth);
809 * Now get the password value - this should be 32 hex digits
810 * which are the ascii representations of a 16 byte string.
811 * Get two at a time and put them into the password.
815 /* Record exact password position */
816 pwd_seekpos += PTR_DIFF(p, linebuf);
818 if (!override && (*p == '*' || *p == 'X')) {
819 /* Password deliberately invalid - end here. */
820 DEBUG(10, ("mod_smbfilepwd_entry: entry invalidated for user %s\n", user_name));
821 pw_file_unlock(lockfd, &pw_file_lock_depth);
826 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
827 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
828 pw_file_unlock(lockfd,&pw_file_lock_depth);
834 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
835 pw_file_unlock(lockfd,&pw_file_lock_depth);
840 if (!override && (*p == '*' || *p == 'X')) {
841 pw_file_unlock(lockfd,&pw_file_lock_depth);
846 /* Now check if the NT compatible password is
848 p += 33; /* Move to the first character of the line after
849 the lanman password. */
850 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
851 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
852 pw_file_unlock(lockfd,&pw_file_lock_depth);
858 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
859 pw_file_unlock(lockfd,&pw_file_lock_depth);
865 * Now check if the account info and the password last
866 * change time is available.
868 p += 33; /* Move to the first character of the line after
874 encode_bits[i++] = *p++;
875 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
876 encode_bits[i++] = *p++;
878 encode_bits[i++] = ']';
879 encode_bits[i++] = '\0';
881 if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
883 * We are using a new format, space padded
884 * acct ctrl field. Encode the given acct ctrl
887 fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
889 DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format. This is no longer supported.!\n"));
890 DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
894 /* Go past the ']' */
895 if(linebuf_len > PTR_DIFF(p, linebuf))
898 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
901 /* We should be pointing at the LCT entry. */
902 if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
905 for(i = 0; i < 8; i++) {
906 if(p[i] == '\0' || !isxdigit(p[i]))
911 * p points at 8 characters of hex digits -
912 * read into a time_t as the seconds since
913 * 1970 that the password was last changed.
915 got_pass_last_set_time = True;
917 } /* *p && StrnCaseCmp() */
921 /* Entry is correctly formed. */
923 /* Create the 32 byte representation of the new p16 */
924 if(pwd->smb_passwd != NULL) {
925 for (i = 0; i < 16; i++) {
926 slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
929 if(pwd->acct_ctrl & ACB_PWNOTREQ)
930 fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
932 fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
935 /* Add on the NT md4 hash */
938 if (pwd->smb_nt_passwd != NULL) {
939 for (i = 0; i < 16; i++) {
940 slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
943 if(pwd->acct_ctrl & ACB_PWNOTREQ)
944 fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
946 fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
949 ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
951 /* Add on the account info bits and the time of last
954 if(got_pass_last_set_time) {
955 slprintf(&ascii_p16[strlen(ascii_p16)],
956 sizeof(ascii_p16)-(strlen(ascii_p16)+1),
958 encode_bits, (uint32)pwd->pass_last_set_time );
959 wr_len = strlen(ascii_p16);
962 #ifdef DEBUG_PASSWORD
963 DEBUG(100,("mod_smbfilepwd_entry: "));
964 dump_data(100, ascii_p16, wr_len);
967 if(wr_len > sizeof(linebuf)) {
968 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
969 pw_file_unlock(lockfd,&pw_file_lock_depth);
975 * Do an atomic write into the file at the position defined by
979 /* The mod user write needs to be atomic - so get the fd from
980 the fp and do a raw write() call.
985 if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
986 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
987 pw_file_unlock(lockfd,&pw_file_lock_depth);
992 /* Sanity check - ensure the areas we are writing are framed by ':' */
993 if (read(fd, linebuf, wr_len+1) != wr_len+1) {
994 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
995 pw_file_unlock(lockfd,&pw_file_lock_depth);
1000 if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
1001 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
1002 pw_file_unlock(lockfd,&pw_file_lock_depth);
1007 if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
1008 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1009 pw_file_unlock(lockfd,&pw_file_lock_depth);
1014 if (write(fd, ascii_p16, wr_len) != wr_len) {
1015 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
1016 pw_file_unlock(lockfd,&pw_file_lock_depth);
1021 pw_file_unlock(lockfd,&pw_file_lock_depth);
1026 /************************************************************************
1027 Routine to delete an entry in the smbpasswd file by name.
1028 *************************************************************************/
1030 static BOOL del_smbfilepwd_entry(const char *name)
1032 char *pfile = lp_smb_passwd_file();
1034 struct smb_passwd *pwd = NULL;
1036 FILE *fp_write = NULL;
1037 int pfile2_lockdepth = 0;
1039 slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
1042 * Open the smbpassword file - for update. It needs to be update
1043 * as we need any other processes to wait until we have replaced
1047 if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &pw_file_lock_depth)) == NULL) {
1048 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1053 * Create the replacement password file.
1055 if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
1056 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1057 endsmbfilepwent(fp, &pw_file_lock_depth);
1062 * Scan the file, a line at a time and check if the name matches.
1065 while ((pwd = getsmbfilepwent(fp)) != NULL) {
1067 size_t new_entry_length;
1069 if (strequal(name, pwd->smb_name)) {
1070 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
1075 * We need to copy the entry out into the second file.
1078 if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
1080 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1081 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1083 endsmbfilepwent(fp, &pw_file_lock_depth);
1084 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1088 new_entry_length = strlen(new_entry);
1090 if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
1092 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1093 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1095 endsmbfilepwent(fp, &pw_file_lock_depth);
1096 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1105 * Ensure pfile2 is flushed before rename.
1108 if(fflush(fp_write) != 0)
1110 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
1111 endsmbfilepwent(fp, &pw_file_lock_depth);
1112 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1117 * Do an atomic rename - then release the locks.
1120 if(rename(pfile2,pfile) != 0) {
1124 endsmbfilepwent(fp, &pw_file_lock_depth);
1125 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1129 /*********************************************************************
1130 Create a smb_passwd struct from a SAM_ACCOUNT.
1131 We will not allocate any new memory. The smb_passwd struct
1132 should only stay around as long as the SAM_ACCOUNT does.
1133 ********************************************************************/
1134 static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
1139 if (sampass == NULL)
1141 uid = pdb_get_uid(sampass);
1142 gid = pdb_get_gid(sampass);
1145 DEBUG(0,("build_sam_pass: Failing attempt to store user without a UNIX uid or gid. \n"));
1149 ZERO_STRUCTP(smb_pw);
1151 smb_pw->smb_userid=*uid;
1152 smb_pw->smb_name=pdb_get_username(sampass);
1154 smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1155 smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1157 smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1158 smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1160 if (*uid != pdb_user_rid_to_uid(pdb_get_user_rid(sampass))) {
1161 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1167 * ifdef'out by JFM on 11/29/2001.
1168 * this assertion is no longer valid
1169 * and I don't understand the goal
1170 * and doing the same thing with the group mapping code
1173 * We just have the RID, in which SID is it valid ?
1174 * our domain SID ? well known SID ? local SID ?
1177 if (*gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
1178 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
1179 DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
1187 /*********************************************************************
1188 Create a SAM_ACCOUNT from a smb_passwd struct
1189 ********************************************************************/
1190 static BOOL build_sam_account(SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
1192 struct passwd *pwfile;
1194 if (sam_pass==NULL) {
1195 DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
1199 /* Verify in system password file...
1200 FIXME!!! This is where we should look up an internal
1201 mapping of allocated uid for machine accounts as well
1203 pwfile = sys_getpwnam(pw_buf->smb_name);
1204 if (pwfile == NULL) {
1205 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s not in unix passwd database!\n", pw_buf->smb_name));
1209 pdb_set_uid (sam_pass, &pwfile->pw_uid);
1210 pdb_set_gid (sam_pass, &pwfile->pw_gid);
1212 pdb_set_fullname(sam_pass, pwfile->pw_gecos);
1214 pdb_set_user_rid(sam_pass, pdb_uid_to_user_rid (pwfile->pw_uid));
1220 if (get_group_map_from_gid(pwfile->pw_gid, &map, MAPPING_WITHOUT_PRIV)) {
1221 sid_peek_rid(&map.sid, &rid);
1224 rid=pdb_gid_to_group_rid(pwfile->pw_gid);
1226 pdb_set_group_rid(sam_pass, rid);
1229 pdb_set_username (sam_pass, pw_buf->smb_name);
1230 pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
1231 pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
1232 pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
1233 pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
1234 pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time);
1235 pdb_set_domain (sam_pass, lp_workgroup());
1237 pdb_set_dir_drive (sam_pass, lp_logon_drive());
1239 /* the smbpasswd format doesn't have a must change time field, so
1240 we can't get this right. The best we can do is to set this to
1241 some time in the future. 21 days seems as reasonable as any other value :)
1243 pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
1245 /* check if this is a user account or a machine account */
1246 if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$')
1250 pstrcpy(str, lp_logon_path());
1251 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
1252 pdb_set_profile_path(sam_pass, str);
1254 pstrcpy(str, lp_logon_home());
1255 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
1256 pdb_set_homedir(sam_pass, str);
1258 pstrcpy(str, lp_logon_drive());
1259 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
1260 pdb_set_dir_drive(sam_pass, str);
1262 pstrcpy(str, lp_logon_script());
1263 standard_sub_advanced(-1, pwfile->pw_name, "", pwfile->pw_gid, pw_buf->smb_name, str);
1264 pdb_set_logon_script(sam_pass, str);
1267 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
1268 /*pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS); */
1273 /*****************************************************************
1274 Functions to be implemented by the new passdb API
1275 ****************************************************************/
1276 BOOL pdb_setsampwent (BOOL update)
1278 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1279 update ? PWF_UPDATE : PWF_READ,
1280 &pw_file_lock_depth);
1282 /* did we fail? Should we try to create it? */
1283 if (!global_vp && update && errno == ENOENT)
1286 /* slprintf(msg_str,msg_str_len-1,
1287 "smbpasswd file did not exist - attempting to create it.\n"); */
1288 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
1289 fp = sys_fopen(lp_smb_passwd_file(), "w");
1292 fprintf(fp, "# Samba SMB password file\n");
1296 global_vp = startsmbfilepwent(lp_smb_passwd_file(),
1297 update ? PWF_UPDATE : PWF_READ,
1298 &pw_file_lock_depth);
1301 return (global_vp != NULL);
1304 void pdb_endsampwent (void)
1306 endsmbfilepwent(global_vp, &pw_file_lock_depth);
1309 /*****************************************************************
1310 ****************************************************************/
1311 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
1313 struct smb_passwd *pw_buf=NULL;
1315 DEBUG(5,("pdb_getsampwent\n"));
1318 DEBUG(5,("pdb_getsampwent: user is NULL\n"));
1320 smb_panic("NULL pointer passed to pdb_getsampwent\n");
1327 /* do we have an entry? */
1328 pw_buf = getsmbfilepwent(global_vp);
1332 /* build the SAM_ACCOUNT entry from the smb_passwd struct.
1333 We loop in case the user in the pdb does not exist in
1334 the local system password file */
1335 if (build_sam_account(user, pw_buf))
1339 DEBUG(5,("pdb_getsampwent:done\n"));
1346 /****************************************************************
1347 Search smbpasswd file by iterating over the entries. Do not
1348 call getpwnam() for unix account information until we have found
1350 ***************************************************************/
1351 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
1353 struct smb_passwd *smb_pw;
1355 char *domain = NULL;
1359 DEBUG(10, ("pdb_getsampwnam: search by name: %s\n", username));
1362 /* break the username from the domain if we have
1363 been given a string in the form 'DOMAIN\user' */
1364 fstrcpy (name, username);
1365 if ((user=strchr_m(name, '\\')) != NULL) {
1371 /* if a domain was specified and it wasn't ours
1372 then there is no chance of matching */
1373 if ( domain && !StrCaseCmp(domain, lp_workgroup()) )
1376 /* startsmbfilepwent() is used here as we don't want to lookup
1377 the UNIX account in the local system password file until
1379 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1382 DEBUG(0, ("unable to open passdb database.\n"));
1386 /* if we have a domain name, then we should map it to a UNIX
1391 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1392 /* do nothing....another loop */ ;
1394 endsmbfilepwent(fp, &pw_file_lock_depth);
1397 /* did we locate the username in smbpasswd */
1401 DEBUG(10, ("pdb_getsampwnam: found by name: %s\n", smb_pw->smb_name));
1404 DEBUG(10,("pdb_getsampwnam:SAM_ACCOUNT is NULL\n"));
1406 smb_panic("NULL pointer passed to pdb_getsampwnam\n");
1411 /* now build the SAM_ACCOUNT */
1412 if (!build_sam_account(sam_acct, smb_pw))
1420 BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid)
1422 struct smb_passwd *smb_pw;
1425 DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", (int)uid));
1427 /* Open the sam password file - not for update. */
1428 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1431 DEBUG(0, ("unable to open passdb database.\n"));
1435 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (smb_pw->smb_userid != uid) )
1438 endsmbfilepwent(fp, &pw_file_lock_depth);
1440 /* did we locate the username in smbpasswd */
1444 DEBUG(10, ("pdb_getsampwuid: found by name: %s\n", smb_pw->smb_name));
1447 DEBUG(10,("pdb_getsampwuid:SAM_ACCOUNT is NULL\n"));
1449 smb_panic("NULL pointer passed to pdb_getsampwuid\n");
1454 /* now build the SAM_ACCOUNT */
1455 if (!build_sam_account(sam_acct, smb_pw))
1462 BOOL pdb_getsampwrid(SAM_ACCOUNT *sam_acct,uint32 rid)
1464 struct smb_passwd *smb_pw;
1467 DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
1469 /* Open the sam password file - not for update. */
1470 fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth);
1473 DEBUG(0, ("unable to open passdb database.\n"));
1477 while ( ((smb_pw=getsmbfilepwent(fp)) != NULL) && (pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1480 endsmbfilepwent(fp, &pw_file_lock_depth);
1483 /* did we locate the username in smbpasswd */
1487 DEBUG(10, ("pdb_getsampwrid: found by name: %s\n", smb_pw->smb_name));
1490 DEBUG(10,("pdb_getsampwrid:SAM_ACCOUNT is NULL\n"));
1492 smb_panic("NULL pointer passed to pdb_getsampwrid\n");
1497 /* now build the SAM_ACCOUNT */
1498 if (!build_sam_account (sam_acct, smb_pw))
1505 BOOL pdb_add_sam_account(const SAM_ACCOUNT *sampass)
1507 struct smb_passwd smb_pw;
1509 /* convert the SAM_ACCOUNT */
1510 if (!build_smb_pass(&smb_pw, sampass)) {
1515 if(!add_smbfilepwd_entry(&smb_pw)) {
1522 BOOL pdb_update_sam_account(const SAM_ACCOUNT *sampass, BOOL override)
1524 struct smb_passwd smb_pw;
1526 /* convert the SAM_ACCOUNT */
1527 build_smb_pass(&smb_pw, sampass);
1529 /* update the entry */
1530 if(!mod_smbfilepwd_entry(&smb_pw, override))
1536 BOOL pdb_delete_sam_account (const char* username)
1538 return del_smbfilepwd_entry(username);
1542 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
1543 void smbpass_dummy_function(void) { } /* stop some compilers complaining */
1544 #endif /* WTH_SMBPASSWD_SAM*/