2 Unix SMB/CIFS implementation.
3 smbpasswd file format routines
5 Copyright (C) Andrew Tridgell 1992-1998
6 Modified by Jeremy Allison 1995.
7 Modified by Gerald (Jerry) Carter 2000-2001
8 Copyright (C) Tim Potter 2001
9 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
10 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2005
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 /*! \file lib/smbpasswd.c
29 The smbpasswd file is used to store encrypted passwords in a similar
30 fashion to the /etc/passwd file. The format is colon separated fields
31 with one user per line like so:
33 <username>:<uid>:<lanman hash>:<nt hash>:<acb info>:<last change time>
35 The username and uid must correspond to an entry in the /etc/passwd
36 file. The lanman and nt password hashes are 32 hex digits corresponding
37 to the 16-byte lanman and nt hashes respectively.
39 The password last change time is stored as a string of the format
40 LCD-<change time> where the change time is expressed as an
46 'U' User account (normal)
47 'M' MNS logon user account - what is this ?
48 'W' Workstation account
51 'X' No Xpiry on password
52 'I' Interdomain trust account
57 #include "system/locale.h"
58 #include "lib/samba3/samba3.h"
60 /*! Convert 32 hex characters into a 16 byte array. */
62 struct samr_Password
*smbpasswd_gethexpwd(TALLOC_CTX
*mem_ctx
, const char *p
)
65 unsigned char lonybble
, hinybble
;
66 const char *hexchars
= "0123456789ABCDEF";
68 struct samr_Password
*pwd
= talloc(mem_ctx
, struct samr_Password
);
72 for (i
= 0; i
< (sizeof(pwd
->hash
) * 2); i
+= 2)
74 hinybble
= toupper(p
[i
]);
75 lonybble
= toupper(p
[i
+ 1]);
77 p1
= strchr_m(hexchars
, hinybble
);
78 p2
= strchr_m(hexchars
, lonybble
);
84 hinybble
= PTR_DIFF(p1
, hexchars
);
85 lonybble
= PTR_DIFF(p2
, hexchars
);
87 pwd
->hash
[i
/ 2] = (hinybble
<< 4) | lonybble
;
92 /*! Convert a 16-byte array into 32 hex characters. */
93 struct samr_Password
*lm_hash_p
= NULL
;
94 struct samr_Password
*nt_hash_p
= NULL
;
96 char *smbpasswd_sethexpwd(TALLOC_CTX
*mem_ctx
, struct samr_Password
*pwd
, uint16_t acb_info
)
101 p
= talloc_array(mem_ctx
, char, 33);
106 for (i
= 0; i
< sizeof(pwd
->hash
); i
++)
107 slprintf(&p
[i
*2], 3, "%02X", pwd
->hash
[i
]);
109 if (acb_info
& ACB_PWNOTREQ
)
110 p
= talloc_strdup(mem_ctx
, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
112 p
= talloc_strdup(mem_ctx
, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
117 /*! Decode the account control bits (ACB) info from a string. */
119 uint16_t smbpasswd_decode_acb_info(const char *p
)
121 uint16_t acb_info
= 0;
122 BOOL finished
= False
;
125 * Check if the account type bits have been encoded after the
126 * NT password (in the form [NDHTUWSLXI]).
129 if (*p
!= '[') return 0;
131 for (p
++; *p
&& !finished
; p
++)
134 case 'N': /* 'N'o password. */
135 acb_info
|= ACB_PWNOTREQ
;
137 case 'D': /* 'D'isabled. */
138 acb_info
|= ACB_DISABLED
;
140 case 'H': /* 'H'omedir required. */
141 acb_info
|= ACB_HOMDIRREQ
;
143 case 'T': /* 'T'emp account. */
144 acb_info
|= ACB_TEMPDUP
;
146 case 'U': /* 'U'ser account (normal). */
147 acb_info
|= ACB_NORMAL
;
149 case 'M': /* 'M'NS logon user account. What is this ? */
152 case 'W': /* 'W'orkstation account. */
153 acb_info
|= ACB_WSTRUST
;
155 case 'S': /* 'S'erver account. */
156 acb_info
|= ACB_SVRTRUST
;
158 case 'L': /* 'L'ocked account. */
159 acb_info
|= ACB_AUTOLOCK
;
161 case 'X': /* No 'X'piry on password */
162 acb_info
|= ACB_PWNOEXP
;
164 case 'I': /* 'I'nterdomain trust account. */
165 acb_info
|= ACB_DOMTRUST
;
182 /*! Encode account control bits (ACBs) into a string. */
184 char *smbpasswd_encode_acb_info(TALLOC_CTX
*mem_ctx
, uint16_t acb_info
)
186 char *acct_str
= talloc_array(mem_ctx
, char, 35);
191 if (acb_info
& ACB_PWNOTREQ
) acct_str
[i
++] = 'N';
192 if (acb_info
& ACB_DISABLED
) acct_str
[i
++] = 'D';
193 if (acb_info
& ACB_HOMDIRREQ
) acct_str
[i
++] = 'H';
194 if (acb_info
& ACB_TEMPDUP
) acct_str
[i
++] = 'T';
195 if (acb_info
& ACB_NORMAL
) acct_str
[i
++] = 'U';
196 if (acb_info
& ACB_MNS
) acct_str
[i
++] = 'M';
197 if (acb_info
& ACB_WSTRUST
) acct_str
[i
++] = 'W';
198 if (acb_info
& ACB_SVRTRUST
) acct_str
[i
++] = 'S';
199 if (acb_info
& ACB_AUTOLOCK
) acct_str
[i
++] = 'L';
200 if (acb_info
& ACB_PWNOEXP
) acct_str
[i
++] = 'X';
201 if (acb_info
& ACB_DOMTRUST
) acct_str
[i
++] = 'I';
204 acct_str
[i
++] = '\0';
209 NTSTATUS
samba3_read_smbpasswd(const char *filename
, TALLOC_CTX
*ctx
, struct samba3_samaccount
**accounts
, uint32_t *count
)
218 lines
= file_lines_load(filename
, &numlines
, ctx
);
221 DEBUG(0, ("Unable to load lines from %s\n", filename
));
222 return NT_STATUS_UNSUCCESSFUL
;
225 *accounts
= talloc_array(ctx
, struct samba3_samaccount
, numlines
);
227 for (i
= 0; i
< numlines
; i
++) {
228 char *p
= lines
[i
], *q
;
230 struct samba3_samaccount
*acc
= &((*accounts
)[*count
]);
232 if (p
[0] == '\0' || p
[0] == '#')
239 DEBUG(0, ("%s:%d: expected ':'\n", filename
, i
));
243 acc
->username
= talloc_strndup(ctx
, p
, PTR_DIFF(q
, p
));
248 /* uid is ignored here.. */
252 DEBUG(0, ("%s:%d: expected ':'\n", filename
, i
));
257 if (strlen(p
) < 33) {
258 DEBUG(0, ("%s:%d: expected 32 byte password blob\n", filename
, i
));
262 if (!strncmp(p
, "NO PASSWORD", strlen("NO PASSWORD"))) {
263 acc
->acct_ctrl
|= ACB_PWNOTREQ
;
264 } else if (p
[0] == '*' || p
[0] == 'X') {
265 /* No password set */
267 struct samr_Password
*pw
= smbpasswd_gethexpwd(*accounts
, p
);
270 DEBUG(0, ("%s:%d: Malformed LM pw entry\n", filename
, i
));
274 memcpy(acc
->lm_pw
.hash
, pw
, sizeof(*pw
));
278 DEBUG(0, ("%s:%d: expected ':' after 32 byte password blob\n", filename
, i
));
284 if (p
[0] == '*' || p
[0] == 'X') {
285 /* No password set */
287 struct samr_Password
*pw
= smbpasswd_gethexpwd(*accounts
, p
);
290 DEBUG(0, ("%s:%d: Malformed LM pw entry\n", filename
, i
));
294 memcpy(acc
->nt_pw
.hash
, pw
, sizeof(*pw
));
298 DEBUG(0, ("%s:%d: expected ':' after 32 byte password blob\n", filename
, i
));
307 DEBUG(0, ("%s:%d: expected ']'\n", filename
, i
));
311 acc
->acct_ctrl
|= smbpasswd_decode_acb_info(p
);
314 if (p
[0] == ':' && strncmp(p
, "LCT-", 4) == 0) {
318 for(j
= 0; j
< 8; j
++) {
319 if(p
[j
] == '\0' || !isxdigit(p
[j
])) {
324 acc
->pass_last_set_time
= (time_t)strtol((char *)p
, NULL
, 16);
328 /* 'Old' style file. Fake up based on user name. */
330 * Currently trust accounts are kept in the same
331 * password file as 'normal accounts'. If this changes
332 * we will have to fix this code. JRA.
334 if(acc
->username
[strlen(acc
->username
) - 1] == '$') {
335 acc
->acct_ctrl
&= ~ACB_NORMAL
;
336 acc
->acct_ctrl
|= ACB_WSTRUST
;