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
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.
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.
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.
27 #define DBGC_CLASS DBGC_SAM
29 /************************************************************
30 Fill the SAM_ACCOUNT_HANDLE with default values.
31 ***********************************************************/
33 static void sam_fill_default_account(SAM_ACCOUNT_HANDLE
*account
)
35 ZERO_STRUCT(account
->private); /* Don't touch the talloc context */
37 /* Don't change these timestamp settings without a good reason.
38 They are important for NT member server compatibility. */
40 /* FIXME: We should actually call get_nt_time_max() or sthng
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 */
53 static void destroy_sam_talloc(SAM_ACCOUNT_HANDLE
**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
));
61 talloc_destroy((*account
)->mem_ctx
);
67 /**********************************************************************
68 Alloc memory and initialises a SAM_ACCOUNT_HANDLE on supplied mem_ctx.
69 ***********************************************************************/
71 NTSTATUS
sam_init_account_talloc(TALLOC_CTX
*mem_ctx
, SAM_ACCOUNT_HANDLE
**account
)
73 SMB_ASSERT(*account
!= NULL
);
76 DEBUG(0,("sam_init_account_talloc: mem_ctx was NULL!\n"));
77 return NT_STATUS_UNSUCCESSFUL
;
80 *account
=(SAM_ACCOUNT_HANDLE
*)talloc(mem_ctx
, sizeof(SAM_ACCOUNT_HANDLE
));
83 DEBUG(0,("sam_init_account_talloc: error while allocating memory\n"));
84 return NT_STATUS_NO_MEMORY
;
87 (*account
)->mem_ctx
= mem_ctx
;
89 (*account
)->free_fn
= NULL
;
91 sam_fill_default_account(*account
);
97 /*************************************************************
98 Alloc memory and initialises a struct sam_passwd.
99 ************************************************************/
101 NTSTATUS
sam_init_account(SAM_ACCOUNT_HANDLE
**account
)
106 mem_ctx
= talloc_init("sam internal SAM_ACCOUNT_HANDLE allocation");
109 DEBUG(0,("sam_init_account: error while doing talloc_init()\n"));
110 return NT_STATUS_NO_MEMORY
;
113 if (!NT_STATUS_IS_OK(nt_status
= sam_init_account_talloc(mem_ctx
, account
))) {
114 talloc_destroy(mem_ctx
);
118 (*account
)->free_fn
= destroy_sam_talloc
;
124 * Free the contents of the SAM_ACCOUNT_HANDLE, but not the structure.
126 * Also wipes the LM and NT hashes and plaintext password from
129 * @param account SAM_ACCOUNT_HANDLE to free members of.
132 static void sam_free_account_contents(SAM_ACCOUNT_HANDLE
*account
)
135 /* Kill off sensitive data. Free()ed by the
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
));
145 /************************************************************
146 Reset the SAM_ACCOUNT_HANDLE and free the NT/LM hashes.
147 ***********************************************************/
149 NTSTATUS
sam_reset_sam(SAM_ACCOUNT_HANDLE
*account
)
151 SMB_ASSERT(account
!= NULL
);
153 sam_free_account_contents(account
);
155 sam_fill_default_account(account
);
161 /************************************************************
162 Free the SAM_ACCOUNT_HANDLE and the member pointers.
163 ***********************************************************/
165 NTSTATUS
sam_free_account(SAM_ACCOUNT_HANDLE
**account
)
167 SMB_ASSERT(*account
!= NULL
);
169 sam_free_account_contents(*account
);
171 if ((*account
)->free_fn
) {
172 (*account
)->free_fn(account
);
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 **********************************************************/
185 char *sam_encode_acct_ctrl(uint16 acct_ctrl
, size_t length
)
187 static fstring acct_str
;
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';
204 for ( ; i
< length
- 2 ; i
++ )
209 acct_str
[i
++] = '\0';
214 /**********************************************************
215 Decode the account control bits from a string.
216 **********************************************************/
218 uint16
sam_decode_acct_ctrl(const char *p
)
220 uint16 acct_ctrl
= 0;
221 BOOL finished
= False
;
224 * Check if the account type bits have been encoded after the
225 * NT password (in the form [NDHTUWSLXI]).
231 for (p
++; *p
&& !finished
; 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. */ }
249 default: { finished
= True
; }
256 /*************************************************************
257 Routine to set 32 hex password characters from a 16 byte array.
258 **************************************************************/
260 void sam_sethexpwd(char *p
, const unsigned char *pwd
, uint16 acct_ctrl
)
264 for (i
= 0; i
< 16; i
++)
265 slprintf(&p
[i
*2], 3, "%02X", pwd
[i
]);
267 if (acct_ctrl
& ACB_PWNOTREQ
)
268 safe_strcpy(p
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
270 safe_strcpy(p
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
274 /*************************************************************
275 Routine to get the 32 hex characters and turn them
276 into a 16 byte array.
277 **************************************************************/
279 BOOL
sam_gethexpwd(const char *p
, unsigned char *pwd
)
282 unsigned char lonybble
, hinybble
;
283 char *hexchars
= "0123456789ABCDEF";
289 for (i
= 0; i
< 32; i
+= 2) {
290 hinybble
= toupper(p
[i
]);
291 lonybble
= toupper(p
[i
+ 1]);
293 p1
= strchr(hexchars
, hinybble
);
294 p2
= strchr(hexchars
, lonybble
);
299 hinybble
= PTR_DIFF(p1
, hexchars
);
300 lonybble
= PTR_DIFF(p2
, hexchars
);
302 pwd
[i
/ 2] = (hinybble
<< 4) | lonybble
;