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