b8336146cda23d2b5a74fe5086ca695abfc254c6
[ira/wip.git] / source / sam / account.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Jeremy Allison                 1996-2001
5    Copyright (C) Luke Kenneth Casson Leighton   1996-1998
6    Copyright (C) Gerald (Jerry) Carter          2000-2001
7    Copyright (C) Andrew Bartlett                2001-2002
8       
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_SAM
28
29 /************************************************************
30  Fill the SAM_ACCOUNT_HANDLE with default values.
31  ***********************************************************/
32
33 static void sam_fill_default_account(SAM_ACCOUNT_HANDLE *account)
34 {
35         ZERO_STRUCT(account->private); /* Don't touch the talloc context */
36
37         /* Don't change these timestamp settings without a good reason.
38            They are important for NT member server compatibility. */
39
40         /* FIXME: We should actually call get_nt_time_max() or sthng 
41          * here */
42         unix_to_nt_time(&(account->private.logoff_time),get_time_t_max());
43         unix_to_nt_time(&(account->private.kickoff_time),get_time_t_max());
44         unix_to_nt_time(&(account->private.pass_must_change_time),get_time_t_max());
45         account->private.unknown_1 = 0x00ffffff;        /* don't know */
46         account->private.logon_divs = 168;      /* hours per week */
47         account->private.hours_len = 21;                /* 21 times 8 bits = 168 */
48         memset(account->private.hours, 0xff, account->private.hours_len); /* available at all hours */
49         account->private.unknown_2 = 0x00000000; /* don't know */
50         account->private.unknown_3 = 0x000004ec; /* don't know */
51 }       
52
53 static void destroy_sam_talloc(SAM_ACCOUNT_HANDLE **account) 
54 {
55         if (*account) {
56                 data_blob_clear_free(&((*account)->private.lm_pw));
57                 data_blob_clear_free(&((*account)->private.nt_pw));
58                 if((*account)->private.plaintext_pw!=NULL)
59                         memset((*account)->private.plaintext_pw,'\0',strlen((*account)->private.plaintext_pw));
60
61                 talloc_destroy((*account)->mem_ctx);
62                 *account = NULL;
63         }
64 }
65
66
67 /**********************************************************************
68  Alloc memory and initialises a SAM_ACCOUNT_HANDLE on supplied mem_ctx.
69 ***********************************************************************/
70
71 NTSTATUS sam_init_account_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT_HANDLE **account)
72 {
73         SMB_ASSERT(*account != NULL);
74
75         if (!mem_ctx) {
76                 DEBUG(0,("sam_init_account_talloc: mem_ctx was NULL!\n"));
77                 return NT_STATUS_UNSUCCESSFUL;
78         }
79
80         *account=(SAM_ACCOUNT_HANDLE *)talloc(mem_ctx, sizeof(SAM_ACCOUNT_HANDLE));
81
82         if (*account==NULL) {
83                 DEBUG(0,("sam_init_account_talloc: error while allocating memory\n"));
84                 return NT_STATUS_NO_MEMORY;
85         }
86
87         (*account)->mem_ctx = mem_ctx;
88
89         (*account)->free_fn = NULL;
90
91         sam_fill_default_account(*account);
92         
93         return NT_STATUS_OK;
94 }
95
96
97 /*************************************************************
98  Alloc memory and initialises a struct sam_passwd.
99  ************************************************************/
100
101 NTSTATUS sam_init_account(SAM_ACCOUNT_HANDLE **account)
102 {
103         TALLOC_CTX *mem_ctx;
104         NTSTATUS nt_status;
105         
106         mem_ctx = talloc_init("sam internal SAM_ACCOUNT_HANDLE allocation");
107
108         if (!mem_ctx) {
109                 DEBUG(0,("sam_init_account: error while doing talloc_init()\n"));
110                 return NT_STATUS_NO_MEMORY;
111         }
112
113         if (!NT_STATUS_IS_OK(nt_status = sam_init_account_talloc(mem_ctx, account))) {
114                 talloc_destroy(mem_ctx);
115                 return nt_status;
116         }
117         
118         (*account)->free_fn = destroy_sam_talloc;
119
120         return NT_STATUS_OK;
121 }
122
123 /**
124  * Free the contents of the SAM_ACCOUNT_HANDLE, but not the structure.
125  *
126  * Also wipes the LM and NT hashes and plaintext password from 
127  * memory.
128  *
129  * @param account SAM_ACCOUNT_HANDLE to free members of.
130  **/
131
132 static void sam_free_account_contents(SAM_ACCOUNT_HANDLE *account)
133 {
134
135         /* Kill off sensitive data.  Free()ed by the
136            talloc mechinism */
137
138         data_blob_clear_free(&(account->private.lm_pw));
139         data_blob_clear_free(&(account->private.nt_pw));
140         if (account->private.plaintext_pw)
141                 memset(account->private.plaintext_pw,'\0',strlen(account->private.plaintext_pw));
142 }
143
144
145 /************************************************************
146  Reset the SAM_ACCOUNT_HANDLE and free the NT/LM hashes.
147  ***********************************************************/
148
149 NTSTATUS sam_reset_sam(SAM_ACCOUNT_HANDLE *account)
150 {
151         SMB_ASSERT(account != NULL);
152         
153         sam_free_account_contents(account);
154
155         sam_fill_default_account(account);
156
157         return NT_STATUS_OK;
158 }
159
160
161 /************************************************************
162  Free the SAM_ACCOUNT_HANDLE and the member pointers.
163  ***********************************************************/
164
165 NTSTATUS sam_free_account(SAM_ACCOUNT_HANDLE **account)
166 {
167         SMB_ASSERT(*account != NULL);
168
169         sam_free_account_contents(*account);
170         
171         if ((*account)->free_fn) {
172                 (*account)->free_fn(account);
173         }
174
175         return NT_STATUS_OK;    
176 }
177
178
179 /**********************************************************
180  Encode the account control bits into a string.
181  length = length of string to encode into (including terminating
182  null). length *MUST BE MORE THAN 2* !
183  **********************************************************/
184
185 char *sam_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
186 {
187         static fstring acct_str;
188         size_t i = 0;
189
190         acct_str[i++] = '[';
191
192         if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
193         if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
194         if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
195         if (acct_ctrl & ACB_TEMPDUP  ) acct_str[i++] = 'T'; 
196         if (acct_ctrl & ACB_NORMAL   ) acct_str[i++] = 'U';
197         if (acct_ctrl & ACB_MNS      ) acct_str[i++] = 'M';
198         if (acct_ctrl & ACB_WSTRUST  ) acct_str[i++] = 'W';
199         if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
200         if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
201         if (acct_ctrl & ACB_PWNOEXP  ) acct_str[i++] = 'X';
202         if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
203
204         for ( ; i < length - 2 ; i++ )
205                 acct_str[i] = ' ';
206
207         i = length - 2;
208         acct_str[i++] = ']';
209         acct_str[i++] = '\0';
210
211         return acct_str;
212 }     
213
214 /**********************************************************
215  Decode the account control bits from a string.
216  **********************************************************/
217
218 uint16 sam_decode_acct_ctrl(const char *p)
219 {
220         uint16 acct_ctrl = 0;
221         BOOL finished = False;
222
223         /*
224          * Check if the account type bits have been encoded after the
225          * NT password (in the form [NDHTUWSLXI]).
226          */
227
228         if (*p != '[')
229                 return 0;
230
231         for (p++; *p && !finished; p++) {
232                 switch (*p) {
233                         case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
234                         case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
235                         case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
236                         case 'T': { acct_ctrl |= ACB_TEMPDUP  ; break; /* 'T'emp account. */ } 
237                         case 'U': { acct_ctrl |= ACB_NORMAL   ; break; /* 'U'ser account (normal). */ } 
238                         case 'M': { acct_ctrl |= ACB_MNS      ; break; /* 'M'NS logon user account. What is this ? */ } 
239                         case 'W': { acct_ctrl |= ACB_WSTRUST  ; break; /* 'W'orkstation account. */ } 
240                         case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } 
241                         case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } 
242                         case 'X': { acct_ctrl |= ACB_PWNOEXP  ; break; /* No 'X'piry on password */ } 
243                         case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
244             case ' ': { break; }
245                         case ':':
246                         case '\n':
247                         case '\0': 
248                         case ']':
249                         default:  { finished = True; }
250                 }
251         }
252
253         return acct_ctrl;
254 }
255
256 /*************************************************************
257  Routine to set 32 hex password characters from a 16 byte array.
258 **************************************************************/
259
260 void sam_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl)
261 {
262         if (pwd != NULL) {
263                 int i;
264                 for (i = 0; i < 16; i++)
265                         slprintf(&p[i*2], 3, "%02X", pwd[i]);
266         } else {
267                 if (acct_ctrl & ACB_PWNOTREQ)
268                         safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
269                 else
270                         safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
271         }
272 }
273
274 /*************************************************************
275  Routine to get the 32 hex characters and turn them
276  into a 16 byte array.
277 **************************************************************/
278
279 BOOL sam_gethexpwd(const char *p, unsigned char *pwd)
280 {
281         int i;
282         unsigned char   lonybble, hinybble;
283         char           *hexchars = "0123456789ABCDEF";
284         char           *p1, *p2;
285         
286         if (!p)
287                 return (False);
288         
289         for (i = 0; i < 32; i += 2) {
290                 hinybble = toupper(p[i]);
291                 lonybble = toupper(p[i + 1]);
292
293                 p1 = strchr(hexchars, hinybble);
294                 p2 = strchr(hexchars, lonybble);
295
296                 if (!p1 || !p2)
297                         return (False);
298
299                 hinybble = PTR_DIFF(p1, hexchars);
300                 lonybble = PTR_DIFF(p2, hexchars);
301
302                 pwd[i / 2] = (hinybble << 4) | lonybble;
303         }
304         return (True);
305 }