23e68717c7d02cc2281ac294f426569c8ceb6a58
[sfrench/samba-autobuild/.git] / source4 / lib / samba3 / tdbsam.c
1 /* 
2    Unix SMB/CIFS implementation.
3    tdb passdb backend format routines
4
5         Copyright (C) Simo Sorce        2000-2003
6     Copyright (C) Jelmer Vernooij       2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "system/iconv.h"
25 #include "system/filesys.h"
26 #include "lib/tdb/include/tdbutil.h"
27 #include "lib/samba3/samba3.h"
28
29 #define TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
30 #define TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
31 #define TDB_FORMAT_STRING_V2       "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
32 #define TDBSAM_VERSION_STRING      "INFO/version"
33
34 static BOOL init_sam_from_buffer_v0(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
35 {
36         uint32_t        username_len, domain_len, nt_username_len,
37                 dir_drive_len, unknown_str_len, munged_dial_len,
38                 fullname_len, homedir_len, logon_script_len,
39                 profile_path_len, acct_desc_len, workstations_len;
40                 
41         uint32_t        remove_me;
42         uint32_t                len = 0;
43         uint32_t                lm_pw_len, nt_pw_len, hourslen;
44         
45         if(sampass == NULL || buf.dptr == NULL) {
46                 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
47                 return False;
48         }
49
50         /* unpack the buffer into variables */
51         len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V0,
52                 &sampass->logon_time,                                   /* d */
53                 &sampass->logoff_time,                                  /* d */
54                 &sampass->kickoff_time,                                 /* d */
55                 &sampass->pass_last_set_time,                           /* d */
56                 &sampass->pass_can_change_time,                         /* d */
57                 &sampass->pass_must_change_time,                        /* d */
58                 &username_len, &sampass->username,                      /* B */
59                 &domain_len, &sampass->domain,                          /* B */
60                 &nt_username_len, &sampass->nt_username,                /* B */
61                 &fullname_len, &sampass->fullname,                      /* B */
62                 &homedir_len, &sampass->homedir,                        /* B */
63                 &dir_drive_len, &sampass->dir_drive,                    /* B */
64                 &logon_script_len, &sampass->logon_script,              /* B */
65                 &profile_path_len, &sampass->profile_path,              /* B */
66                 &acct_desc_len, &sampass->acct_desc,                    /* B */
67                 &workstations_len, &sampass->workstations,              /* B */
68                 &unknown_str_len, &sampass->unknown_str,                /* B */
69                 &munged_dial_len, &sampass->munged_dial,                /* B */
70                 &sampass->user_rid,                                     /* d */
71                 &sampass->group_rid,                                    /* d */
72                 &lm_pw_len, &sampass->lm_pw_ptr,                        /* B */
73                 &nt_pw_len, &sampass->nt_pw_ptr,                        /* B */
74                 &sampass->acct_ctrl,                                    /* w */
75                 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
76                 &sampass->logon_divs,                                   /* w */
77                 &sampass->hours_len,                                    /* d */
78                 &hourslen, &sampass->hours,                             /* B */
79                 &sampass->bad_password_count,                           /* w */
80                 &sampass->logon_count,                                  /* w */
81                 &sampass->unknown_6);                                   /* d */
82                 
83         if (len == (uint32_t) -1)  {
84                 return False;
85         }
86
87         if (lm_pw_len != 16) {
88                 sampass->lm_pw_ptr = NULL;
89         }
90
91         if (nt_pw_len != 16) {
92                 sampass->nt_pw_ptr = NULL;
93         }
94
95         return True;
96 }
97
98 static BOOL init_sam_from_buffer_v1(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
99 {
100         uint32_t        username_len, domain_len, nt_username_len,
101                 dir_drive_len, unknown_str_len, munged_dial_len,
102                 fullname_len, homedir_len, logon_script_len,
103                 profile_path_len, acct_desc_len, workstations_len;
104                 
105         uint32_t        remove_me;
106         uint32_t                len = 0;
107         uint32_t                lm_pw_len, nt_pw_len, hourslen;
108         
109         if(sampass == NULL || buf.dptr == NULL) {
110                 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
111                 return False;
112         }
113
114         /* unpack the buffer into variables */
115         len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V1,
116                 &sampass->logon_time,                                   /* d */
117                 &sampass->logoff_time,                                  /* d */
118                 &sampass->kickoff_time,                         /* d */
119                 /* Change from V0 is addition of bad_password_time field. */
120                 &sampass->bad_password_time,                            /* d */
121                 &sampass->pass_last_set_time,                           /* d */
122                 &sampass->pass_can_change_time,                 /* d */
123                 &sampass->pass_must_change_time,                        /* d */
124                 &username_len, &sampass->username,                      /* B */
125                 &domain_len, &sampass->domain,          /* B */
126                 &nt_username_len, &sampass->nt_username,        /* B */
127                 &fullname_len, &sampass->fullname,                      /* B */
128                 &homedir_len, &sampass->homedir,                        /* B */
129                 &dir_drive_len, &sampass->dir_drive,                    /* B */
130                 &logon_script_len, &sampass->logon_script,              /* B */
131                 &profile_path_len, &sampass->profile_path,              /* B */
132                 &acct_desc_len, &sampass->acct_desc,                    /* B */
133                 &workstations_len, &sampass->workstations,              /* B */
134                 &unknown_str_len, &sampass->unknown_str,                /* B */
135                 &munged_dial_len, &sampass->munged_dial,                /* B */
136                 &sampass->user_rid,                                     /* d */
137                 &sampass->group_rid,                                    /* d */
138                 &lm_pw_len, &sampass->lm_pw_ptr,                        /* B */
139                 &nt_pw_len, &sampass->nt_pw_ptr,                        /* B */
140                 &sampass->acct_ctrl,                                    /* w */
141                 &remove_me,                                             /* d */
142                 &sampass->logon_divs,                                   /* w */
143                 &sampass->hours_len,                                    /* d */
144                 &hourslen, &sampass->hours,                             /* B */
145                 &sampass->bad_password_count,                           /* w */
146                 &sampass->logon_count,                                  /* w */
147                 &sampass->unknown_6);                                   /* d */
148                 
149         if (len == (uint32_t) -1)  {
150                 return False;
151         }
152
153         if (sampass->lm_pw_ptr && lm_pw_len != 16) {
154                 sampass->lm_pw_ptr = NULL;
155         }
156
157         if (sampass->nt_pw_ptr && nt_pw_len != 16) {
158                 sampass->nt_pw_ptr = NULL;
159         }
160
161         return True;
162 }
163
164 static BOOL init_sam_from_buffer_v2(TDB_CONTEXT *tdb, struct samba3_samaccount *sampass, TDB_DATA buf)
165 {
166         uint32_t        username_len, domain_len, nt_username_len,
167                 dir_drive_len, unknown_str_len, munged_dial_len,
168                 fullname_len, homedir_len, logon_script_len,
169                 profile_path_len, acct_desc_len, workstations_len;
170                 
171         uint32_t                len = 0;
172         uint32_t                lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
173         
174         if(sampass == NULL || buf.dptr == NULL) {
175                 DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
176                 return False;
177         }
178
179         /* unpack the buffer into variables */
180         len = tdb_unpack (tdb, (char *)buf.dptr, buf.dsize, TDB_FORMAT_STRING_V2,
181                 &sampass->logon_time,                                   /* d */
182                 &sampass->logoff_time,                                  /* d */
183                 &sampass->kickoff_time,                                 /* d */
184                 &sampass->bad_password_time,                            /* d */
185                 &sampass->pass_last_set_time,                           /* d */
186                 &sampass->pass_can_change_time,                         /* d */
187                 &sampass->pass_must_change_time,                        /* d */
188                 &username_len, &sampass->username,                      /* B */
189                 &domain_len, &sampass->domain,                          /* B */
190                 &nt_username_len, &sampass->nt_username,                /* B */
191                 &fullname_len, &sampass->fullname,                      /* B */
192                 &homedir_len, &sampass->homedir,                        /* B */
193                 &dir_drive_len, &sampass->dir_drive,                    /* B */
194                 &logon_script_len, &sampass->logon_script,              /* B */
195                 &profile_path_len, &sampass->profile_path,              /* B */
196                 &acct_desc_len, &sampass->acct_desc,                    /* B */
197                 &workstations_len, &sampass->workstations,              /* B */
198                 &unknown_str_len, &sampass->unknown_str,                /* B */
199                 &munged_dial_len, &sampass->munged_dial,                /* B */
200                 &sampass->user_rid,                                     /* d */
201                 &sampass->group_rid,                                    /* d */
202                 &lm_pw_len, &sampass->lm_pw_ptr,                        /* B */
203                 &nt_pw_len, &sampass->nt_pw_ptr,                        /* B */
204                 /* Change from V1 is addition of password history field. */
205                 &nt_pw_hist_len, &sampass->nt_pw_hist_ptr,              /* B */
206                 &sampass->acct_ctrl,                                    /* w */
207                 /* Also "remove_me" field was removed. */
208                 &sampass->logon_divs,                                   /* w */
209                 &sampass->hours_len,                                    /* d */
210                 &hourslen, &sampass->hours,                             /* B */
211                 &sampass->bad_password_count,                           /* w */
212                 &sampass->logon_count,                                  /* w */
213                 &sampass->unknown_6);                                   /* d */
214                 
215         if (len == (uint32_t) -1)  {
216                 return False;
217         }
218
219         if (sampass->lm_pw_ptr && lm_pw_len != 16) {
220                 sampass->lm_pw_ptr = NULL;
221         }
222
223         if (sampass->nt_pw_ptr && nt_pw_len != 16) {
224                 sampass->nt_pw_ptr = NULL;
225         }
226
227         return True;
228 }
229
230 NTSTATUS samba3_read_tdbsam(const char *filename, TALLOC_CTX *ctx, struct samba3_samaccount **accounts, uint32_t *count)
231 {
232         int32_t version;
233         TDB_CONTEXT *tdb;
234         TDB_DATA key, val;
235
236         /* Try to open tdb passwd */
237         if (!(tdb = tdb_open(filename, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
238                 DEBUG(0, ("Unable to open TDB passwd file '%s'\n", filename));
239                 return NT_STATUS_UNSUCCESSFUL;
240         }
241
242         /* Check the version */
243         version = tdb_fetch_int32(tdb, 
244                                                 TDBSAM_VERSION_STRING);
245         if (version == -1)
246                 version = 0;    /* Version not found, assume version 0 */
247         
248         /* Compare the version */
249         if (version > 2) {
250                 /* Version more recent than the latest known */ 
251                 DEBUG(0, ("TDBSAM version unknown: %d\n", version));
252                 tdb_close(tdb);
253                 return NT_STATUS_NOT_SUPPORTED;
254         } 
255         
256         *accounts = NULL;
257         *count = 0;
258
259         for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key))
260         {
261                 BOOL ret;
262                 if (strncmp(key.dptr, "USER_", 5) != 0) 
263                         continue;
264
265                 val = tdb_fetch(tdb, key);
266
267                 *accounts = talloc_realloc(ctx, *accounts, struct samba3_samaccount, (*count)+1);
268
269                 switch (version) 
270                 {
271                         case 0: ret = init_sam_from_buffer_v0(tdb, &(*accounts)[*count], val); break;
272                         case 1: ret = init_sam_from_buffer_v1(tdb, &(*accounts)[*count], val); break;
273                         case 2: ret = init_sam_from_buffer_v2(tdb, &(*accounts)[*count], val); break;
274
275                 }
276
277                 if (!ret) {
278                         DEBUG(0, ("Unable to parse SAM account %s\n", key.dptr));
279                 }
280
281                 (*count)++;
282         }
283         
284         tdb_close(tdb);
285         
286         return NT_STATUS_OK;
287 }