7a73bf59324e9c0244d4da8b221e0fd1d052bdd2
[kai/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 = 0;
26 static FILE *mach_passwd_fp = NULL;
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,("get_trust_account_file_name: 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   DEBUG(5,("trust_account_file_name: %s\n", mac_file));
57 }
58  
59 /************************************************************************
60  Routine to lock the trust account password file for a domain.
61 ************************************************************************/
62
63 BOOL trust_password_lock( char *domain, char *name, BOOL update)
64 {
65   pstring mac_file;
66
67   if(mach_passwd_lock_depth == 0) {
68
69     get_trust_account_file_name( domain, name, mac_file);
70
71     if((mach_passwd_fp = sys_fopen(mac_file, "r+b")) == NULL) {
72       if(errno == ENOENT && update) {
73         mach_passwd_fp = sys_fopen(mac_file, "w+b");
74       }
75
76       if(mach_passwd_fp == NULL) {
77         DEBUG(0,("trust_password_lock: cannot open file %s - Error was %s.\n",
78               mac_file, strerror(errno) ));
79         return False;
80       }
81     }
82
83     chmod(mac_file, 0600);
84
85     if(!file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK), 
86                                       60, &mach_passwd_lock_depth))
87     {
88       DEBUG(0,("trust_password_lock: cannot lock file %s\n", mac_file));
89       fclose(mach_passwd_fp);
90       return False;
91     }
92
93   }
94
95   return True;
96 }
97
98 /************************************************************************
99  Routine to unlock the trust account password file for a domain.
100 ************************************************************************/
101
102 BOOL trust_password_unlock(void)
103 {
104   BOOL ret = file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth);
105   if(mach_passwd_lock_depth == 0)
106     fclose(mach_passwd_fp);
107   return ret;
108 }
109
110 /************************************************************************
111  Routine to delete the trust account password file for a domain.
112 ************************************************************************/
113
114 BOOL trust_password_delete( char *domain, char *name )
115 {
116   pstring mac_file;
117
118   get_trust_account_file_name( domain, name, mac_file);
119   return (unlink( mac_file ) == 0);
120 }
121
122 /************************************************************************
123  Routine to get the trust account password for a domain.
124  The user of this function must have locked the trust password file.
125 ************************************************************************/
126
127 BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time)
128 {
129   char linebuf[256];
130   char *p;
131   int i;
132
133   linebuf[0] = '\0';
134
135   *pass_last_set_time = (time_t)0;
136   memset(ret_pwd, '\0', 16);
137
138   if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
139     DEBUG(0,("get_trust_account_password: Failed to seek to start of file. Error was %s.\n",
140               strerror(errno) ));
141     return False;
142   } 
143
144   fgets(linebuf, sizeof(linebuf), mach_passwd_fp);
145   if(ferror(mach_passwd_fp)) {
146     DEBUG(0,("get_trust_account_password: Failed to read password. Error was %s.\n",
147               strerror(errno) ));
148     return False;
149   }
150
151   if(linebuf[strlen(linebuf)-1] == '\n')
152     linebuf[strlen(linebuf)-1] = '\0';
153
154   /*
155    * The length of the line read
156    * must be 45 bytes ( <---XXXX 32 bytes-->:TLC-12345678
157    */
158
159   if(strlen(linebuf) != 45) {
160     DEBUG(0,("get_trust_account_password: Malformed trust password file (wrong length \
161 - was %d, should be 45).\n", strlen(linebuf)));
162 #ifdef DEBUG_PASSWORD
163     DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
164 #endif
165     return False;
166   }
167
168   /*
169    * Get the hex password.
170    */
171
172   if (!pwdb_gethexpwd((char *)linebuf, (char *)ret_pwd, NULL) || linebuf[32] != ':' || 
173          strncmp(&linebuf[33], "TLC-", 4)) {
174     DEBUG(0,("get_trust_account_password: Malformed trust password file (incorrect format).\n"));
175 #ifdef DEBUG_PASSWORD
176     DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
177 #endif
178     return False;
179   }
180
181   /*
182    * Get the last changed time.
183    */
184   p = &linebuf[37];
185
186   for(i = 0; i < 8; i++) {
187     if(p[i] == '\0' || !isxdigit((int)p[i])) {
188       DEBUG(0,("get_trust_account_password: Malformed trust password file (no timestamp).\n"));
189 #ifdef DEBUG_PASSWORD
190       DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
191 #endif
192       return False;
193     }
194   }
195
196   /*
197    * p points at 8 characters of hex digits -
198    * read into a time_t as the seconds since
199    * 1970 that the password was last changed.
200    */
201
202   *pass_last_set_time = (time_t)strtol(p, NULL, 16);
203
204   return True;
205 }
206
207 /************************************************************************
208  Routine to get the trust account password for a domain.
209  The user of this function must have locked the trust password file.
210 ************************************************************************/
211
212 BOOL set_trust_account_password( unsigned char *md4_new_pwd)
213 {
214   char linebuf[64];
215   int i;
216
217   if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
218     DEBUG(0,("set_trust_account_password: Failed to seek to start of file. Error was %s.\n",
219               strerror(errno) ));
220     return False;
221   } 
222
223   for (i = 0; i < 16; i++)
224     slprintf(&linebuf[(i*2)], sizeof(linebuf) -  (i*2) - 1, "%02X", md4_new_pwd[i]);
225
226   slprintf(&linebuf[32], 32, ":TLC-%08X\n", (unsigned)time(NULL));
227
228   if(fwrite( linebuf, 1, 46, mach_passwd_fp)!= 46) {
229     DEBUG(0,("set_trust_account_password: Failed to write file. Warning - the trust \
230 account is now invalid. Please recreate. Error was %s.\n", strerror(errno) ));
231     return False;
232   }
233
234   fflush(mach_passwd_fp);
235   return True;
236 }
237
238 BOOL trust_get_passwd( unsigned char trust_passwd[16], char *domain, char *myname)
239 {
240   time_t lct;
241
242   /*
243    * Get the trust account password.
244    */
245   if(!trust_password_lock( domain, myname, False)) {
246     DEBUG(0,("trust_get_passwd: unable to open the trust account password file for \
247 trust %s in domain %s.\n", myname, domain ));
248     return False;
249   }
250
251   if(get_trust_account_password( trust_passwd, &lct) == False) {
252     DEBUG(0,("trust_get_passwd: unable to read the trust account password for \
253 trust %s in domain %s.\n", myname, domain ));
254     trust_password_unlock();
255     return False;
256   }
257
258   trust_password_unlock();
259
260   /* 
261    * Here we check the last change time to see if the trust
262    * password needs changing. JRA. 
263    */
264
265   if(time(NULL) > lct + lp_machine_password_timeout())
266   {
267     global_machine_password_needs_changing = True;
268   }
269   return True;
270 }
271
272 /*********************************************************
273 record Trust Account password.
274 **********************************************************/
275 BOOL create_trust_account_file(char *domain, char *name, uchar pass[16])
276 {
277         /*
278          * Create the machine account password file.
279          */
280
281         if (!trust_password_lock( domain, name, True))
282         {
283                 DEBUG(0,("unable to open the trust account password file for \
284 account %s in domain %s.\n", name, domain)); 
285                 return False;
286         }
287
288         /*
289          * Write the old machine account password.
290          */
291         
292         if (!set_trust_account_password( pass))
293         {              
294                 DEBUG(0,("unable to write the trust account password for \
295 %s in domain %s.\n", name, domain));
296                 trust_password_unlock();
297                 return False;
298         }
299         
300         trust_password_unlock();
301         
302         return True;
303 }