2 * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 675
17 * Mass Ave, Cambridge, MA 02139, USA.
22 extern int DEBUGLEVEL;
25 static char s_readbuf[16 * 1024];
27 /***************************************************************
28 Signal function to tell us we timed out.
29 ****************************************************************/
31 static void gotalarm_sig(void)
36 /***************************************************************
37 Lock or unlock a fd for a known lock type. Abandon after waitsecs
39 ****************************************************************/
41 static BOOL do_pw_lock(int fd, int waitsecs, int type)
47 signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
50 lock.l_whence = SEEK_SET;
56 ret = fcntl(fd, F_SETLKW, &lock);
58 signal(SIGALRM, SIGNAL_CAST SIG_DFL);
61 DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n",
62 type == F_UNLCK ? "unlock" : "lock"));
69 static int pw_file_lock_depth;
71 /***************************************************************
72 Lock an fd. Abandon after waitsecs seconds.
73 ****************************************************************/
75 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
82 if(pw_file_lock_depth == 0) {
83 if (!do_pw_lock(fd, secs, type)) {
84 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
93 /***************************************************************
94 Unlock an fd. Abandon after waitsecs seconds.
95 ****************************************************************/
97 static BOOL pw_file_unlock(int fd, int *plock_depth)
101 if(*plock_depth == 1)
102 ret = do_pw_lock(fd, 5, F_UNLCK);
107 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
112 /***************************************************************
113 Start to enumerate the smbpasswd list. Returns a void pointer
114 to ensure no modification outside this module.
116 do not call this function directly. use passdb.c instead.
118 ****************************************************************/
119 void *startsmbpwent(BOOL update)
122 char *pfile = lp_smb_passwd_file();
125 DEBUG(0, ("startsmbpwent: No SMB password file set\n"));
128 DEBUG(10, ("startsmbpwent: opening file %s\n", pfile));
130 fp = fopen(pfile, update ? "r+b" : "rb");
133 DEBUG(0, ("startsmbpwent: unable to open file %s\n", pfile));
137 /* Set a 16k buffer to do more efficient reads */
138 setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf));
140 if (!pw_file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, &pw_file_lock_depth))
142 DEBUG(0, ("startsmbpwent: unable to lock file %s\n", pfile));
147 /* Make sure it is only rw by the owner */
150 /* We have a lock on the file. */
154 /***************************************************************
155 End enumeration of the smbpasswd list.
156 ****************************************************************/
158 void endsmbpwent(void *vp)
160 FILE *fp = (FILE *)vp;
162 pw_file_unlock(fileno(fp), &pw_file_lock_depth);
164 DEBUG(7, ("endsmbpwent: closed password file.\n"));
167 /*************************************************************************
168 Routine to return the next entry in the smbpasswd list.
170 do not call this function directly. use passdb.c instead.
172 *************************************************************************/
173 struct smb_passwd *getsmbpwent(void *vp)
175 /* Static buffers we will return. */
176 static struct smb_passwd pw_buf;
177 static pstring user_name;
178 static unsigned char smbpwd[16];
179 static unsigned char smbntpwd[16];
180 FILE *fp = (FILE *)vp;
188 DEBUG(0,("getsmbpwent: Bad password file pointer.\n"));
192 pw_buf.acct_ctrl = ACB_NORMAL;
193 pw_buf.pass_last_set_time = (time_t)-1;
196 * Scan the file, a line at a time and check if the name matches.
201 fgets(linebuf, 256, fp);
207 * Check if the string is terminated with a newline - if not
208 * then we must keep reading and discard until we get one.
210 linebuf_len = strlen(linebuf);
211 if (linebuf[linebuf_len - 1] != '\n') {
213 while (!ferror(fp) && !feof(fp)) {
219 linebuf[linebuf_len - 1] = '\0';
221 #ifdef DEBUG_PASSWORD
222 DEBUG(100, ("getsmbpwent: got line |%s|\n", linebuf));
224 if ((linebuf[0] == 0) && feof(fp)) {
225 DEBUG(4, ("getsmbpwent: end of file reached\n"));
229 * The line we have should be of the form :-
231 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
236 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
238 * if Windows NT compatible passwords are also present.
239 * [Account type] is an ascii encoding of the type of account.
240 * LCT-(8 hex digits) is the time_t value of the last change time.
243 if (linebuf[0] == '#' || linebuf[0] == '\0') {
244 DEBUG(6, ("getsmbpwent: skipping comment or blank line\n"));
247 p = (unsigned char *) strchr(linebuf, ':');
249 DEBUG(0, ("getsmbpwent: malformed password entry (no :)\n"));
253 * As 256 is shorter than a pstring we don't need to check
254 * length here - if this ever changes....
256 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
257 user_name[PTR_DIFF(p, linebuf)] = '\0';
261 p++; /* Go past ':' */
263 DEBUG(0, ("getsmbpwent: malformed password entry (uid not number)\n"));
267 uidval = atoi((char *) p);
269 while (*p && isdigit(*p))
273 DEBUG(0, ("getsmbpwent: malformed password entry (no : after uid)\n"));
277 pw_buf.smb_name = user_name;
278 pw_buf.smb_userid = uidval;
281 * Now get the password value - this should be 32 hex digits
282 * which are the ascii representations of a 16 byte string.
283 * Get two at a time and put them into the password.
289 if (*p == '*' || *p == 'X') {
290 /* Password deliberately invalid - end here. */
291 DEBUG(10, ("getsmbpwent: entry invalidated for user %s\n", user_name));
292 pw_buf.smb_nt_passwd = NULL;
293 pw_buf.smb_passwd = NULL;
294 pw_buf.acct_ctrl |= ACB_DISABLED;
298 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
299 DEBUG(0, ("getsmbpwent: malformed password entry (passwd too short)\n"));
304 DEBUG(0, ("getsmbpwent: malformed password entry (no terminating :)\n"));
308 if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
309 pw_buf.smb_passwd = NULL;
310 pw_buf.acct_ctrl |= ACB_PWNOTREQ;
312 if (!gethexpwd((char *)p, (char *)smbpwd)) {
313 DEBUG(0, ("getsmbpwent: Malformed Lanman password entry (non hex chars)\n"));
316 pw_buf.smb_passwd = smbpwd;
320 * Now check if the NT compatible password is
323 pw_buf.smb_nt_passwd = NULL;
325 p += 33; /* Move to the first character of the line after
326 the lanman password. */
327 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
328 if (*p != '*' && *p != 'X') {
329 if(gethexpwd((char *)p,(char *)smbntpwd))
330 pw_buf.smb_nt_passwd = smbntpwd;
332 p += 33; /* Move to the first character of the line after
336 DEBUG(5, ("getsmbpwent: returning passwd entry for user %s, uid %d\n",
340 * Check if the account type bits have been encoded after the
341 * NT password (in the form [NDHTUWSLXI]).
345 BOOL finished = False;
347 pw_buf.acct_ctrl = 0;
349 for(p++;*p && !finished; p++) {
353 * Hmmm. Don't allow these to be set/read independently
354 * of the actual password fields. We don't want a mismatch.
359 pw_buf.acct_ctrl |= ACB_PWNOTREQ;
363 pw_buf.acct_ctrl |= ACB_DISABLED;
367 /* 'H'omedir required. */
368 pw_buf.acct_ctrl |= ACB_HOMDIRREQ;
371 /* 'T'emp account. */
372 pw_buf.acct_ctrl |= ACB_TEMPDUP;
375 /* 'U'ser account (normal). */
376 pw_buf.acct_ctrl |= ACB_NORMAL;
379 /* 'M'NS logon user account. What is this ? */
380 pw_buf.acct_ctrl |= ACB_MNS;
383 /* 'W'orkstation account. */
384 pw_buf.acct_ctrl |= ACB_WSTRUST;
387 /* 'S'erver account. */
388 pw_buf.acct_ctrl |= ACB_SVRTRUST;
391 /* 'L'ocked account. */
392 pw_buf.acct_ctrl |= ACB_AUTOLOCK;
396 pw_buf.acct_ctrl |= ACB_PWNOEXP;
399 /* 'I'nterdomain trust account. */
400 pw_buf.acct_ctrl |= ACB_DOMTRUST;
412 /* Must have some account type set. */
413 if(pw_buf.acct_ctrl == 0)
414 pw_buf.acct_ctrl = ACB_NORMAL;
416 /* Now try and get the last change time. */
421 if(*p && StrnCaseCmp( p, "LCT-", 4)) {
424 for(i = 0; i < 8; i++) {
425 if(p[i] == '\0' || !isxdigit(p[i]))
430 * p points at 8 characters of hex digits -
431 * read into a time_t as the seconds since
432 * 1970 that the password was last changed.
434 pw_buf.pass_last_set_time = (time_t)strtol(p, NULL, 16);
439 /* 'Old' style file. Fake up based on user name. */
441 * Currently machine accounts are kept in the same
442 * password file as 'normal accounts'. If this changes
443 * we will have to fix this code. JRA.
445 if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') {
446 pw_buf.acct_ctrl &= ~ACB_NORMAL;
447 pw_buf.acct_ctrl |= ACB_WSTRUST;
454 DEBUG(5,("getsmbpwent: end of file reached.\n"));
458 /*************************************************************************
459 Return the current position in the smbpasswd list as an unsigned long.
460 This must be treated as an opaque token.
462 do not call this function directly. use passdb.c instead.
464 *************************************************************************/
465 unsigned long getsmbpwpos(void *vp)
467 return (unsigned long)ftell((FILE *)vp);
470 /*************************************************************************
471 Set the current position in the smbpasswd list from unsigned long.
472 This must be treated as an opaque token.
474 do not call this function directly. use passdb.c instead.
476 *************************************************************************/
477 BOOL setsmbpwpos(void *vp, unsigned long tok)
479 return !fseek((FILE *)vp, tok, SEEK_SET);
482 /*************************************************************************
483 Routine to search the smbpasswd file for an entry matching the username
484 or user id. if the name is NULL, then the smb_uid is used instead.
485 *************************************************************************/
486 static struct smb_passwd *get_smbpwd_entry(char *name, int smb_userid)
488 struct smb_passwd *pwd = NULL;
492 DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name));
494 DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid));
497 /* Open the smbpassword file - not for update. */
498 fp = startsmbpwent(False);
501 DEBUG(0, ("get_smbpwd_entry: unable to open password file.\n"));
506 * Scan the file, a line at a time and check if the name
510 while ((pwd = getsmbpwent(fp)) != NULL) {
512 /* Search is by user name */
513 if (!strequal(pwd->smb_name, name))
515 DEBUG(10, ("get_smbpwd_entry: found by name: %s\n", name));
518 /* Search is by user id */
519 if (pwd->smb_userid != smb_userid)
521 DEBUG(10, ("get_smbpwd_entry: found by smb_userid: %x\n", smb_userid));
530 /************************************************************************
531 Routine to search smb passwd by name.
532 *************************************************************************/
534 struct smb_passwd *getsmbpwnam(char *name)
536 return get_smbpwd_entry(name, 0);
540 /************************************************************************
541 Routine to search smb passwd by uid.
542 *************************************************************************/
544 struct smb_passwd *getsmbpwuid(unsigned int uid)
546 return get_smbpwd_entry(NULL, uid);
550 /**********************************************************
551 Encode the account control bits into a string.
552 **********************************************************/
554 char *encode_acct_ctrl(uint16 acct_ctrl)
556 static fstring acct_str;
561 if (acct_ctrl & ACB_HOMDIRREQ) *p++ = 'H';
562 if (acct_ctrl & ACB_TEMPDUP ) *p++ = 'T';
563 if (acct_ctrl & ACB_NORMAL ) *p++ = 'U';
564 if (acct_ctrl & ACB_MNS ) *p++ = 'M';
565 if (acct_ctrl & ACB_WSTRUST ) *p++ = 'W';
566 if (acct_ctrl & ACB_SVRTRUST ) *p++ = 'S';
567 if (acct_ctrl & ACB_AUTOLOCK ) *p++ = 'L';
568 if (acct_ctrl & ACB_PWNOEXP ) *p++ = 'X';
569 if (acct_ctrl & ACB_DOMTRUST ) *p++ = 'I';
576 /************************************************************************
577 Routine to add an entry to the smbpasswd file.
579 do not call this function directly. use passdb.c instead.
581 *************************************************************************/
583 BOOL add_smbpwd_entry(struct smb_passwd *newpwd)
585 char *pfile = lp_smb_passwd_file();
586 struct smb_passwd *pwd = NULL;
593 int new_entry_length;
598 /* Open the smbpassword file - for update. */
599 fp = startsmbpwent(True);
602 DEBUG(0, ("add_smbpwd_entry: unable to open file.\n"));
607 * Scan the file, a line at a time and check if the name matches.
610 while ((pwd = getsmbpwent(fp)) != NULL) {
611 if (strequal(newpwd->smb_name, pwd->smb_name)) {
612 DEBUG(0, ("add_smbpwd_entry: entry with name %s already exists\n", pwd->smb_name));
618 /* Ok - entry doesn't exist. We can add it */
620 /* Create a new smb passwd entry and set it to the given password. */
622 * The add user write needs to be atomic - so get the fd from
623 * the fp and do a raw write() call.
627 if((offpos = lseek(fd, 0, SEEK_END)) == -1) {
628 DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \
629 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
634 new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 5 + 1 + 13 + 2;
636 if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
637 DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \
638 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
643 sprintf(new_entry, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
644 p = (unsigned char *)&new_entry[strlen(new_entry)];
646 if(newpwd->smb_passwd != NULL) {
647 for( i = 0; i < 16; i++) {
648 sprintf((char *)&p[i*2], "%02X", newpwd->smb_passwd[i]);
652 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
653 sprintf(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
655 sprintf(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
662 if(newpwd->smb_nt_passwd != NULL) {
663 for( i = 0; i < 16; i++) {
664 sprintf((char *)&p[i*2], "%02X", newpwd->smb_nt_passwd[i]);
667 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
668 sprintf(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
670 sprintf(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
677 /* Add the account encoding and the last change time. */
678 sprintf((char *)p, "%s:LCT-%08X:\n", encode_acct_ctrl(newpwd->acct_ctrl),
681 #ifdef DEBUG_PASSWORD
682 DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|",
683 fd, new_entry_length, strlen(new_entry), new_entry));
686 if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry)) {
687 DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \
688 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
690 /* Remove the entry we just wrote. */
691 if(ftruncate(fd, offpos) == -1) {
692 DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \
693 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
694 newpwd->smb_name, strerror(errno)));
705 /************************************************************************
706 Routine to search the smbpasswd file for an entry matching the username.
707 and then modify its password entry. We can't use the startsmbpwent()/
708 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
709 in the actual file to decide how much room we have to write data.
710 override = False, normal
711 override = True, override XXXXXXXX'd out password or NO PASS
713 do not call this function directly. use passdb.c instead.
715 ************************************************************************/
717 BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override)
719 /* Static buffers we will return. */
720 static pstring user_name;
723 char readbuf[16 * 1024];
727 unsigned char *p = NULL;
728 long linebuf_len = 0;
731 char *pfile = lp_smb_passwd_file();
732 BOOL found_entry = False;
733 BOOL got_pass_last_set_time = False;
735 long pwd_seekpos = 0;
742 DEBUG(0, ("No SMB password file set\n"));
745 DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile));
747 fp = fopen(pfile, "r+");
750 DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile));
753 /* Set a 16k buffer to do more efficient reads */
754 setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
758 if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) {
759 DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile));
764 /* Make sure it is only rw by the owner */
767 /* We have a write lock on the file. */
769 * Scan the file, a line at a time and check if the name matches.
772 pwd_seekpos = ftell(fp);
776 fgets(linebuf, sizeof(linebuf), fp);
778 pw_file_unlock(lockfd, &pw_file_lock_depth);
784 * Check if the string is terminated with a newline - if not
785 * then we must keep reading and discard until we get one.
787 linebuf_len = strlen(linebuf);
788 if (linebuf[linebuf_len - 1] != '\n') {
790 while (!ferror(fp) && !feof(fp)) {
797 linebuf[linebuf_len - 1] = '\0';
800 #ifdef DEBUG_PASSWORD
801 DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf));
804 if ((linebuf[0] == 0) && feof(fp)) {
805 DEBUG(4, ("mod_smbpwd_entry: end of file reached\n"));
810 * The line we have should be of the form :-
812 * username:uid:[32hex bytes]:....other flags presently
817 * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
819 * if Windows NT compatible passwords are also present.
822 if (linebuf[0] == '#' || linebuf[0] == '\0') {
823 DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n"));
827 p = (unsigned char *) strchr(linebuf, ':');
830 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n"));
835 * As 256 is shorter than a pstring we don't need to check
836 * length here - if this ever changes....
838 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
839 user_name[PTR_DIFF(p, linebuf)] = '\0';
840 if (strequal(user_name, pwd->smb_name)) {
846 if (!found_entry) return False;
848 DEBUG(6, ("mod_smbpwd_entry: entry exists\n"));
850 /* User name matches - get uid and password */
851 p++; /* Go past ':' */
854 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n"));
855 pw_file_unlock(lockfd, &pw_file_lock_depth);
860 while (*p && isdigit(*p))
863 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n"));
864 pw_file_unlock(lockfd, &pw_file_lock_depth);
870 * Now get the password value - this should be 32 hex digits
871 * which are the ascii representations of a 16 byte string.
872 * Get two at a time and put them into the password.
876 /* Record exact password position */
877 pwd_seekpos += PTR_DIFF(p, linebuf);
879 if (!override && (*p == '*' || *p == 'X')) {
880 /* Password deliberately invalid - end here. */
881 DEBUG(10, ("mod_smbpwd_entry: entry invalidated for user %s\n", user_name));
882 pw_file_unlock(lockfd, &pw_file_lock_depth);
887 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
888 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
889 pw_file_unlock(lockfd,&pw_file_lock_depth);
895 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
896 pw_file_unlock(lockfd,&pw_file_lock_depth);
901 if (!override && (*p == '*' || *p == 'X')) {
902 pw_file_unlock(lockfd,&pw_file_lock_depth);
907 /* Now check if the NT compatible password is
909 p += 33; /* Move to the first character of the line after
910 the lanman password. */
911 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
912 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
913 pw_file_unlock(lockfd,&pw_file_lock_depth);
919 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
920 pw_file_unlock(lockfd,&pw_file_lock_depth);
926 * Now check if the account info and the password last
927 * change time is available.
929 p += 33; /* Move to the first character of the line after
936 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
937 encode_bits[i++] = *p++;
939 encode_bits[i] = '\0';
941 /* Go past the ']' */
942 if(linebuf_len > PTR_DIFF(p, linebuf))
945 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
948 /* We should be pointing at the TLC entry. */
949 if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && StrnCaseCmp( p, "LCT-", 4)) {
952 for(i = 0; i < 8; i++) {
953 if(p[i] == '\0' || !isxdigit(p[i]))
958 * p points at 8 characters of hex digits -
959 * read into a time_t as the seconds since
960 * 1970 that the password was last changed.
962 got_pass_last_set_time = True;
964 } /* *p && StrnCaseCmp() */
968 /* Entry is correctly formed. */
971 * Do an atomic write into the file at the position defined by
975 /* The mod user write needs to be atomic - so get the fd from
976 the fp and do a raw write() call.
981 if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
982 DEBUG(0, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile));
983 pw_file_unlock(lockfd,&pw_file_lock_depth);
988 /* Sanity check - ensure the character is a ':' */
989 if (read(fd, &c, 1) != 1) {
990 DEBUG(0, ("mod_smbpwd_entry: read fail on file %s.\n", pfile));
991 pw_file_unlock(lockfd,&pw_file_lock_depth);
997 DEBUG(0, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile));
998 pw_file_unlock(lockfd,&pw_file_lock_depth);
1003 /* Create the 32 byte representation of the new p16 */
1004 if(pwd->smb_passwd != NULL) {
1005 for (i = 0; i < 16; i++) {
1006 sprintf(&ascii_p16[i*2], "%02X", (uchar) pwd->smb_passwd[i]);
1009 if(pwd->acct_ctrl & ACB_PWNOTREQ)
1010 sprintf(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1012 sprintf(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1015 /* Add on the NT md4 hash */
1016 ascii_p16[32] = ':';
1018 if (pwd->smb_nt_passwd != NULL) {
1019 for (i = 0; i < 16; i++) {
1020 sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]);
1023 if(pwd->acct_ctrl & ACB_PWNOTREQ)
1024 sprintf(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
1026 sprintf(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
1029 /* Add on the account info bits and the time of last
1032 pwd->pass_last_set_time = time(NULL);
1034 if(got_pass_last_set_time) {
1035 sprintf(&ascii_p16[strlen(ascii_p16)], ":[%s]:TLC-%08X:",
1036 encode_bits, (uint32)pwd->pass_last_set_time );
1037 wr_len = strlen(ascii_p16);
1040 #ifdef DEBUG_PASSWORD
1041 DEBUG(100,("mod_smbpwd_entry: "));
1042 dump_data(100, ascii_p16, wr_len);
1045 if (write(fd, ascii_p16, wr_len) != wr_len) {
1046 DEBUG(0, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile));
1047 pw_file_unlock(lockfd,&pw_file_lock_depth);
1052 pw_file_unlock(lockfd,&pw_file_lock_depth);
1057 static int mach_passwd_lock_depth;
1058 static FILE *mach_passwd_fp;
1060 /************************************************************************
1061 Routine to get the name for a machine account file.
1062 ************************************************************************/
1064 static void get_machine_account_file_name( char *domain, char *name, char *mac_file)
1066 unsigned int mac_file_len;
1069 pstrcpy(mac_file, lp_smb_passwd_file());
1070 p = strrchr(mac_file, '/');
1074 mac_file_len = strlen(mac_file);
1076 if (sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6 < 0)
1078 DEBUG(0,("machine_password_lock: path %s too long to add machine details.\n",
1083 strcat(mac_file, domain);
1084 strcat(mac_file, ".");
1085 strcat(mac_file, name);
1086 strcat(mac_file, ".mac");
1089 /************************************************************************
1090 Routine to lock the machine account password file for a domain.
1091 ************************************************************************/
1093 BOOL machine_password_lock( char *domain, char *name, BOOL update)
1097 if(mach_passwd_lock_depth == 0) {
1099 get_machine_account_file_name( domain, name, mac_file);
1101 if((mach_passwd_fp = fopen(mac_file, "r+b")) == NULL) {
1102 if(errno == ENOENT && update) {
1103 mach_passwd_fp = fopen(mac_file, "w+b");
1106 if(mach_passwd_fp == NULL) {
1107 DEBUG(0,("machine_password_lock: cannot open file %s - Error was %s.\n",
1108 mac_file, strerror(errno) ));
1113 chmod(mac_file, 0600);
1115 if(!pw_file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK),
1116 60, &mach_passwd_lock_depth))
1118 DEBUG(0,("machine_password_lock: cannot lock file %s\n", mac_file));
1119 fclose(mach_passwd_fp);
1128 /************************************************************************
1129 Routine to unlock the machine account password file for a domain.
1130 ************************************************************************/
1132 BOOL machine_password_unlock(void)
1134 BOOL ret = pw_file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth);
1135 if(mach_passwd_lock_depth == 0)
1136 fclose(mach_passwd_fp);
1140 /************************************************************************
1141 Routine to delete the machine account password file for a domain.
1142 ************************************************************************/
1144 BOOL machine_password_delete( char *domain, char *name )
1148 get_machine_account_file_name( domain, name, mac_file);
1149 return (unlink( mac_file ) == 0);
1152 /************************************************************************
1153 Routine to get the machine account password for a domain.
1154 The user of this function must have locked the machine password file.
1155 ************************************************************************/
1157 BOOL get_machine_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time)
1165 *pass_last_set_time = (time_t)0;
1166 memset(ret_pwd, '\0', 16);
1168 if(fseek( mach_passwd_fp, 0L, SEEK_SET) == -1) {
1169 DEBUG(0,("get_machine_account_password: Failed to seek to start of file. Error was %s.\n",
1174 fgets(linebuf, sizeof(linebuf), mach_passwd_fp);
1175 if(ferror(mach_passwd_fp)) {
1176 DEBUG(0,("get_machine_account_password: Failed to read password. Error was %s.\n",
1182 * The length of the line read
1183 * must be 45 bytes ( <---XXXX 32 bytes-->:TLC-12345678
1186 if(strlen(linebuf) != 45) {
1187 DEBUG(0,("get_machine_account_password: Malformed machine password file (wrong length).\n"));
1188 #ifdef DEBUG_PASSWORD
1189 DEBUG(100,("get_machine_account_password: line = |%s|\n", linebuf));
1195 * Get the hex password.
1198 if (!gethexpwd((char *)linebuf, (char *)ret_pwd) || linebuf[32] != ':' ||
1199 strncmp(&linebuf[33], "TLC-", 4)) {
1200 DEBUG(0,("get_machine_account_password: Malformed machine password file (incorrect format).\n"));
1201 #ifdef DEBUG_PASSWORD
1202 DEBUG(100,("get_machine_account_password: line = |%s|\n", linebuf));
1208 * Get the last changed time.
1212 for(i = 0; i < 8; i++) {
1213 if(p[i] == '\0' || !isxdigit(p[i])) {
1214 DEBUG(0,("get_machine_account_password: Malformed machine password file (no timestamp).\n"));
1215 #ifdef DEBUG_PASSWORD
1216 DEBUG(100,("get_machine_account_password: line = |%s|\n", linebuf));
1223 * p points at 8 characters of hex digits -
1224 * read into a time_t as the seconds since
1225 * 1970 that the password was last changed.
1228 *pass_last_set_time = (time_t)strtol(p, NULL, 16);
1233 /************************************************************************
1234 Routine to get the machine account password for a domain.
1235 The user of this function must have locked the machine password file.
1236 ************************************************************************/
1238 BOOL set_machine_account_password( unsigned char *md4_new_pwd)
1243 if(fseek( mach_passwd_fp, 0L, SEEK_SET) == -1) {
1244 DEBUG(0,("set_machine_account_password: Failed to seek to start of file. Error was %s.\n",
1249 for (i = 0; i < 16; i++)
1250 sprintf(&linebuf[(i*2)], "%02X", md4_new_pwd[i]);
1252 sprintf(&linebuf[32], ":TLC-%08X\n", (unsigned)time(NULL));
1254 if(fwrite( linebuf, 1, 45, mach_passwd_fp)!= 45) {
1255 DEBUG(0,("set_machine_account_password: Failed to write file. Warning - the machine \
1256 machine account is now invalid. Please recreate. Error was %s.\n", strerror(errno) ));
1260 fflush(mach_passwd_fp);