1/* 2 * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup 3 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. 4 * 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) 8 * any later version. 9 * 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 13 * more details. 14 * 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. 18 */ 19 20#include "includes.h" 21 22extern int DEBUGLEVEL; 23 24BOOL global_machine_password_needs_changing = False; 25 26/*************************************************************** 27 Lock an fd. Abandon after waitsecs seconds. 28****************************************************************/ 29 30BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) 31{ 32 if (fd < 0) 33 return False; 34 35 if(*plock_depth == 0) { 36 if (!do_file_lock(fd, secs, type)) { 37 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", 38 strerror(errno))); 39 return False; 40 } 41 } 42 43 (*plock_depth)++; 44 45 return True; 46} 47 48/*************************************************************** 49 Unlock an fd. Abandon after waitsecs seconds. 50****************************************************************/ 51 52BOOL pw_file_unlock(int fd, int *plock_depth) 53{ 54 BOOL ret=True; 55 56 if(*plock_depth == 1) 57 ret = do_file_lock(fd, 5, F_UNLCK); 58 59 if (*plock_depth > 0) 60 (*plock_depth)--; 61 62 if(!ret) 63 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n", 64 strerror(errno))); 65 return ret; 66} 67 68static int mach_passwd_lock_depth; 69static FILE *mach_passwd_fp; 70 71/************************************************************************ 72 Routine to get the name for a trust account file. 73************************************************************************/ 74 75static void get_trust_account_file_name( char *domain, char *name, char *mac_file) 76{ 77 unsigned int mac_file_len; 78 char *p; 79 80 pstrcpy(mac_file, lp_smb_passwd_file()); 81 p = strrchr(mac_file, '/'); 82 if(p != NULL) 83 *++p = '\0'; 84 85 mac_file_len = strlen(mac_file); 86 87 if ((int)(sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6) < 0) 88 { 89 DEBUG(0,("trust_password_lock: path %s too long to add trust details.\n", 90 mac_file)); 91 return; 92 } 93 94 pstrcat(mac_file, domain); 95 pstrcat(mac_file, "."); 96 pstrcat(mac_file, name); 97 pstrcat(mac_file, ".mac"); 98} 99 100/************************************************************************ 101 Routine to lock the trust account password file for a domain. 102************************************************************************/ 103 104BOOL trust_password_lock( char *domain, char *name, BOOL update) 105{ 106 pstring mac_file; 107 108 if(mach_passwd_lock_depth == 0) { 109 110 get_trust_account_file_name( domain, name, mac_file); 111 112 if((mach_passwd_fp = sys_fopen(mac_file, "r+b")) == NULL) { 113 if(errno == ENOENT && update) { 114 mach_passwd_fp = sys_fopen(mac_file, "w+b"); 115 } 116 117 if(mach_passwd_fp == NULL) { 118 DEBUG(0,("trust_password_lock: cannot open file %s - Error was %s.\n", 119 mac_file, strerror(errno) )); 120 return False; 121 } 122 } 123 124 chmod(mac_file, 0600); 125 126 if(!pw_file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK), 127 60, &mach_passwd_lock_depth)) 128 { 129 DEBUG(0,("trust_password_lock: cannot lock file %s\n", mac_file)); 130 fclose(mach_passwd_fp); 131 return False; 132 } 133 134 } 135 136 return True; 137} 138 139/************************************************************************ 140 Routine to unlock the trust account password file for a domain. 141************************************************************************/ 142 143BOOL trust_password_unlock(void) 144{ 145 BOOL ret = pw_file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth); 146 if(mach_passwd_lock_depth == 0) 147 fclose(mach_passwd_fp); 148 return ret; 149} 150 151/************************************************************************ 152 Routine to delete the trust account password file for a domain. 153************************************************************************/ 154 155BOOL trust_password_delete( char *domain, char *name ) 156{ 157 pstring mac_file; 158 159 get_trust_account_file_name( domain, name, mac_file); 160 return (unlink( mac_file ) == 0); 161} 162 163/************************************************************************ 164 Routine to get the trust account password for a domain. 165 The user of this function must have locked the trust password file. 166************************************************************************/ 167 168BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time) 169{ 170 char linebuf[256]; 171 char *p; 172 int i; 173 174 linebuf[0] = '\0'; 175 176 *pass_last_set_time = (time_t)0; 177 memset(ret_pwd, '\0', 16); 178 179 if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) { 180 DEBUG(0,("get_trust_account_password: Failed to seek to start of file. Error was %s.\n", 181 strerror(errno) )); 182 return False; 183 } 184 185 fgets(linebuf, sizeof(linebuf), mach_passwd_fp); 186 if(ferror(mach_passwd_fp)) { 187 DEBUG(0,("get_trust_account_password: Failed to read password. Error was %s.\n", 188 strerror(errno) )); 189 return False; 190 } 191 192 if(linebuf[strlen(linebuf)-1] == '\n') 193 linebuf[strlen(linebuf)-1] = '\0'; 194 195 /* 196 * The length of the line read 197 * must be 45 bytes ( <---XXXX 32 bytes-->:TLC-12345678 198 */ 199 200 if(strlen(linebuf) != 45) { 201 DEBUG(0,("get_trust_account_password: Malformed trust password file (wrong length \ 202- was %d, should be 45).\n", (int)strlen(linebuf))); 203#ifdef DEBUG_PASSWORD 204 DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); 205#endif 206 return False; 207 } 208 209 /* 210 * Get the hex password. 211 */ 212 213 if (!pdb_gethexpwd((char *)linebuf, ret_pwd) || linebuf[32] != ':' || 214 strncmp(&linebuf[33], "TLC-", 4)) { 215 DEBUG(0,("get_trust_account_password: Malformed trust password file (incorrect format).\n")); 216#ifdef DEBUG_PASSWORD 217 DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); 218#endif 219 return False; 220 } 221 222 /* 223 * Get the last changed time. 224 */ 225 p = &linebuf[37]; 226 227 for(i = 0; i < 8; i++) { 228 if(p[i] == '\0' || !isxdigit((int)p[i])) { 229 DEBUG(0,("get_trust_account_password: Malformed trust password file (no timestamp).\n")); 230#ifdef DEBUG_PASSWORD 231 DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); 232#endif 233 return False; 234 } 235 } 236 237 /* 238 * p points at 8 characters of hex digits - 239 * read into a time_t as the seconds since 240 * 1970 that the password was last changed. 241 */ 242 243 *pass_last_set_time = (time_t)strtol(p, NULL, 16); 244 245 return True; 246} 247 248/************************************************************************ 249 Routine to get the trust account password for a domain. 250 The user of this function must have locked the trust password file. 251************************************************************************/ 252 253BOOL set_trust_account_password( unsigned char *md4_new_pwd) 254{ 255 char linebuf[64]; 256 int i; 257 258 if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) { 259 DEBUG(0,("set_trust_account_password: Failed to seek to start of file. Error was %s.\n", 260 strerror(errno) )); 261 return False; 262 } 263 264 for (i = 0; i < 16; i++) 265 slprintf(&linebuf[(i*2)], sizeof(linebuf) - (i*2) - 1, "%02X", md4_new_pwd[i]); 266 267 slprintf(&linebuf[32], 32, ":TLC-%08X\n", (unsigned)time(NULL)); 268 269 if(fwrite( linebuf, 1, 46, mach_passwd_fp)!= 46) { 270 DEBUG(0,("set_trust_account_password: Failed to write file. Warning - the trust \ 271account is now invalid. Please recreate. Error was %s.\n", strerror(errno) )); 272 return False; 273 } 274 275 fflush(mach_passwd_fp); 276 return True; 277} 278 279BOOL trust_get_passwd( unsigned char trust_passwd[16], char *domain, char *myname) 280{ 281 time_t lct; 282 283 /* 284 * Get the machine account password. 285 */ 286 if(!trust_password_lock( domain, myname, False)) { 287 DEBUG(0,("domain_client_validate: unable to open the machine account password file for \ 288machine %s in domain %s.\n", myname, domain )); 289 return False; 290 } 291 292 if(get_trust_account_password( trust_passwd, &lct) == False) { 293 DEBUG(0,("domain_client_validate: unable to read the machine account password for \ 294machine %s in domain %s.\n", myname, domain )); 295 trust_password_unlock(); 296 return False; 297 } 298 299 trust_password_unlock(); 300 301 /* 302 * Here we check the last change time to see if the machine 303 * password needs changing. JRA. 304 */ 305 306 if(time(NULL) > lct + lp_machine_password_timeout()) 307 { 308 global_machine_password_needs_changing = True; 309 } 310 return True; 311} 312