/* * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" extern int DEBUGLEVEL; static int gotalarm; int pw_file_lock_depth = 0; /*************************************************************** Signal function to tell us we timed out. ****************************************************************/ static void gotalarm_sig(void) { gotalarm = 1; } /*************************************************************** Lock or unlock a fd for a known lock type. Abandon after waitsecs seconds. ****************************************************************/ BOOL do_file_lock(int fd, int waitsecs, int type) { SMB_STRUCT_FLOCK lock; int ret; gotalarm = 0; CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); lock.l_type = type; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; lock.l_pid = 0; alarm(5); ret = fcntl(fd, SMB_F_SETLKW, &lock); alarm(0); CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL); if (gotalarm) { DEBUG(0, ("do_file_lock: failed to %s file.\n", type == F_UNLCK ? "unlock" : "lock")); return False; } return (ret == 0); } /*************************************************************** Lock an fd. Abandon after waitsecs seconds. ****************************************************************/ BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) { if (fd < 0) return False; (*plock_depth)++; if(pw_file_lock_depth == 0) { if (!do_file_lock(fd, secs, type)) { DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", strerror(errno))); return False; } } return True; } /*************************************************************** Unlock an fd. Abandon after waitsecs seconds. ****************************************************************/ BOOL pw_file_unlock(int fd, int *plock_depth) { BOOL ret=True; if(*plock_depth == 1) ret = do_file_lock(fd, 5, F_UNLCK); (*plock_depth)--; if(!ret) DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n", strerror(errno))); return ret; } static int mach_passwd_lock_depth; static FILE *mach_passwd_fp; /************************************************************************ Routine to get the name for a trust account file. ************************************************************************/ static void get_trust_account_file_name( char *domain, char *name, char *mac_file) { unsigned int mac_file_len; char *p; pstrcpy(mac_file, lp_smb_passwd_file()); p = strrchr(mac_file, '/'); if(p != NULL) *++p = '\0'; mac_file_len = strlen(mac_file); if ((int)(sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6) < 0) { DEBUG(0,("trust_password_lock: path %s too long to add trust details.\n", mac_file)); return; } pstrcat(mac_file, domain); pstrcat(mac_file, "."); pstrcat(mac_file, name); pstrcat(mac_file, ".mac"); } /************************************************************************ Routine to lock the trust account password file for a domain. ************************************************************************/ BOOL trust_password_lock( char *domain, char *name, BOOL update) { pstring mac_file; if(mach_passwd_lock_depth == 0) { get_trust_account_file_name( domain, name, mac_file); if((mach_passwd_fp = fopen(mac_file, "r+b")) == NULL) { if(errno == ENOENT && update) { mach_passwd_fp = fopen(mac_file, "w+b"); } if(mach_passwd_fp == NULL) { DEBUG(0,("trust_password_lock: cannot open file %s - Error was %s.\n", mac_file, strerror(errno) )); return False; } } chmod(mac_file, 0600); if(!pw_file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK), 60, &mach_passwd_lock_depth)) { DEBUG(0,("trust_password_lock: cannot lock file %s\n", mac_file)); fclose(mach_passwd_fp); return False; } } return True; } /************************************************************************ Routine to unlock the trust account password file for a domain. ************************************************************************/ BOOL trust_password_unlock(void) { BOOL ret = pw_file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth); if(mach_passwd_lock_depth == 0) fclose(mach_passwd_fp); return ret; } /************************************************************************ Routine to delete the trust account password file for a domain. ************************************************************************/ BOOL trust_password_delete( char *domain, char *name ) { pstring mac_file; get_trust_account_file_name( domain, name, mac_file); return (unlink( mac_file ) == 0); } /************************************************************************ Routine to get the trust account password for a domain. The user of this function must have locked the trust password file. ************************************************************************/ BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time) { char linebuf[256]; char *p; int i; linebuf[0] = '\0'; *pass_last_set_time = (time_t)0; memset(ret_pwd, '\0', 16); if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) { DEBUG(0,("get_trust_account_password: Failed to seek to start of file. Error was %s.\n", strerror(errno) )); return False; } fgets(linebuf, sizeof(linebuf), mach_passwd_fp); if(ferror(mach_passwd_fp)) { DEBUG(0,("get_trust_account_password: Failed to read password. Error was %s.\n", strerror(errno) )); return False; } if(linebuf[strlen(linebuf)-1] == '\n') linebuf[strlen(linebuf)-1] = '\0'; /* * The length of the line read * must be 45 bytes ( <---XXXX 32 bytes-->:TLC-12345678 */ if(strlen(linebuf) != 45) { DEBUG(0,("get_trust_account_password: Malformed trust password file (wrong length \ - was %d, should be 45).\n", strlen(linebuf))); #ifdef DEBUG_PASSWORD DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); #endif return False; } /* * Get the hex password. */ if (!pdb_gethexpwd((char *)linebuf, (char *)ret_pwd) || linebuf[32] != ':' || strncmp(&linebuf[33], "TLC-", 4)) { DEBUG(0,("get_trust_account_password: Malformed trust password file (incorrect format).\n")); #ifdef DEBUG_PASSWORD DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); #endif return False; } /* * Get the last changed time. */ p = &linebuf[37]; for(i = 0; i < 8; i++) { if(p[i] == '\0' || !isxdigit((int)p[i])) { DEBUG(0,("get_trust_account_password: Malformed trust password file (no timestamp).\n")); #ifdef DEBUG_PASSWORD DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf)); #endif return False; } } /* * p points at 8 characters of hex digits - * read into a time_t as the seconds since * 1970 that the password was last changed. */ *pass_last_set_time = (time_t)strtol(p, NULL, 16); return True; } /************************************************************************ Routine to get the trust account password for a domain. The user of this function must have locked the trust password file. ************************************************************************/ BOOL set_trust_account_password( unsigned char *md4_new_pwd) { char linebuf[64]; int i; if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) { DEBUG(0,("set_trust_account_password: Failed to seek to start of file. Error was %s.\n", strerror(errno) )); return False; } for (i = 0; i < 16; i++) slprintf(&linebuf[(i*2)], sizeof(linebuf) - (i*2) - 1, "%02X", md4_new_pwd[i]); slprintf(&linebuf[32], 32, ":TLC-%08X\n", (unsigned)time(NULL)); if(fwrite( linebuf, 1, 46, mach_passwd_fp)!= 46) { DEBUG(0,("set_trust_account_password: Failed to write file. Warning - the trust \ account is now invalid. Please recreate. Error was %s.\n", strerror(errno) )); return False; } fflush(mach_passwd_fp); return True; }