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