r24712: No longer expose the 'BOOL' data type in any interfaces.
[metze/samba/wip.git] / source4 / lib / samba3 / smbpasswd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    smbpasswd file format routines
4
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
11    
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 3 of the License, or
15    (at your option) any later version.
16    
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.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 /*! \file lib/smbpasswd.c
27
28    The smbpasswd file is used to store encrypted passwords in a similar
29    fashion to the /etc/passwd file.  The format is colon separated fields
30    with one user per line like so:
31
32    <username>:<uid>:<lanman hash>:<nt hash>:<acb info>:<last change time>
33
34    The username and uid must correspond to an entry in the /etc/passwd
35    file.  The lanman and nt password hashes are 32 hex digits corresponding
36    to the 16-byte lanman and nt hashes respectively.  
37
38    The password last change time is stored as a string of the format
39    LCD-<change time> where the change time is expressed as an 
40
41    'N'    No password
42    'D'    Disabled
43    'H'    Homedir required
44    'T'    Temp account.
45    'U'    User account (normal) 
46    'M'    MNS logon user account - what is this ? 
47    'W'    Workstation account
48    'S'    Server account 
49    'L'    Locked account
50    'X'    No Xpiry on password 
51    'I'    Interdomain trust account
52
53 */
54
55 #include "includes.h"
56 #include "system/locale.h"
57 #include "lib/samba3/samba3.h"
58
59 /*! Convert 32 hex characters into a 16 byte array. */
60
61 struct samr_Password *smbpasswd_gethexpwd(TALLOC_CTX *mem_ctx, const char *p)
62 {
63         int i;
64         unsigned char   lonybble, hinybble;
65         const char     *hexchars = "0123456789ABCDEF";
66         const char     *p1, *p2;
67         struct samr_Password *pwd = talloc(mem_ctx, struct samr_Password);
68
69         if (!p) return NULL;
70         
71         for (i = 0; i < (sizeof(pwd->hash) * 2); i += 2)
72         {
73                 hinybble = toupper(p[i]);
74                 lonybble = toupper(p[i + 1]);
75                 
76                 p1 = strchr_m(hexchars, hinybble);
77                 p2 = strchr_m(hexchars, lonybble);
78                 
79                 if (!p1 || !p2) {
80                         return NULL;
81                 }
82                 
83                 hinybble = PTR_DIFF(p1, hexchars);
84                 lonybble = PTR_DIFF(p2, hexchars);
85                 
86                 pwd->hash[i / 2] = (hinybble << 4) | lonybble;
87         }
88         return pwd;
89 }
90
91 /*! Convert a 16-byte array into 32 hex characters. */
92         struct samr_Password *lm_hash_p = NULL;
93         struct samr_Password *nt_hash_p = NULL;
94
95 char *smbpasswd_sethexpwd(TALLOC_CTX *mem_ctx, struct samr_Password *pwd, uint16_t acb_info)
96 {
97         char *p;
98         if (pwd != NULL) {
99                 int i;
100                 p = talloc_array(mem_ctx, char, 33);
101                 if (!p) {
102                         return NULL;
103                 }
104
105                 for (i = 0; i < sizeof(pwd->hash); i++)
106                         slprintf(&p[i*2], 3, "%02X", pwd->hash[i]);
107         } else {
108                 if (acb_info & ACB_PWNOTREQ)
109                         p = talloc_strdup(mem_ctx, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
110                 else
111                         p = talloc_strdup(mem_ctx, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
112         }
113         return p;
114 }
115
116 /*! Decode the account control bits (ACB) info from a string. */
117
118 uint16_t smbpasswd_decode_acb_info(const char *p)
119 {
120         uint16_t acb_info = 0;
121         bool finished = false;
122
123         /*
124          * Check if the account type bits have been encoded after the
125          * NT password (in the form [NDHTUWSLXI]).
126          */
127
128         if (*p != '[') return 0;
129
130         for (p++; *p && !finished; p++)
131         {
132                 switch (*p) {
133                 case 'N': /* 'N'o password. */
134                         acb_info |= ACB_PWNOTREQ; 
135                         break;
136                 case 'D': /* 'D'isabled. */
137                         acb_info |= ACB_DISABLED; 
138                         break; 
139                 case 'H': /* 'H'omedir required. */
140                         acb_info |= ACB_HOMDIRREQ; 
141                         break;
142                 case 'T': /* 'T'emp account. */
143                         acb_info |= ACB_TEMPDUP; 
144                         break;
145                 case 'U': /* 'U'ser account (normal). */
146                         acb_info |= ACB_NORMAL;
147                         break;
148                 case 'M': /* 'M'NS logon user account. What is this ? */
149                         acb_info |= ACB_MNS; 
150                         break; 
151                 case 'W': /* 'W'orkstation account. */
152                         acb_info |= ACB_WSTRUST; 
153                         break; 
154                 case 'S': /* 'S'erver account. */ 
155                         acb_info |= ACB_SVRTRUST; 
156                         break; 
157                 case 'L': /* 'L'ocked account. */
158                         acb_info |= ACB_AUTOLOCK; 
159                         break; 
160                 case 'X': /* No 'X'piry on password */
161                         acb_info |= ACB_PWNOEXP; 
162                         break; 
163                 case 'I': /* 'I'nterdomain trust account. */
164                         acb_info |= ACB_DOMTRUST; 
165                         break; 
166
167                 case ' ': 
168                         break;
169                 case ':':
170                 case '\n':
171                 case ']':
172                 default:  
173                         finished = true;
174                         break;
175                 }
176         }
177
178         return acb_info;
179 }
180
181 /*! Encode account control bits (ACBs) into a string. */
182
183 char *smbpasswd_encode_acb_info(TALLOC_CTX *mem_ctx, uint16_t acb_info)
184 {
185         char *acct_str = talloc_array(mem_ctx, char, 35);
186         size_t i = 0;
187
188         acct_str[i++] = '[';
189
190         if (acb_info & ACB_PWNOTREQ ) acct_str[i++] = 'N';
191         if (acb_info & ACB_DISABLED ) acct_str[i++] = 'D';
192         if (acb_info & ACB_HOMDIRREQ) acct_str[i++] = 'H';
193         if (acb_info & ACB_TEMPDUP  ) acct_str[i++] = 'T'; 
194         if (acb_info & ACB_NORMAL   ) acct_str[i++] = 'U';
195         if (acb_info & ACB_MNS      ) acct_str[i++] = 'M';
196         if (acb_info & ACB_WSTRUST  ) acct_str[i++] = 'W';
197         if (acb_info & ACB_SVRTRUST ) acct_str[i++] = 'S';
198         if (acb_info & ACB_AUTOLOCK ) acct_str[i++] = 'L';
199         if (acb_info & ACB_PWNOEXP  ) acct_str[i++] = 'X';
200         if (acb_info & ACB_DOMTRUST ) acct_str[i++] = 'I';
201
202         acct_str[i++] = ']';
203         acct_str[i++] = '\0';
204
205         return acct_str;
206 }     
207
208 NTSTATUS samba3_read_smbpasswd(const char *filename, TALLOC_CTX *ctx, struct samba3_samaccount **accounts, uint32_t *count)
209 {
210         int numlines;
211         char **lines;
212         int i;
213
214         *count = 0;
215         *accounts = NULL;
216
217         lines = file_lines_load(filename, &numlines, ctx);
218
219         if (lines == NULL) {
220                 DEBUG(0, ("Unable to load lines from %s\n", filename));
221                 return NT_STATUS_UNSUCCESSFUL;
222         }
223
224         *accounts = talloc_array(ctx, struct samba3_samaccount, numlines);
225
226         for (i = 0; i < numlines; i++) {
227                 char *p = lines[i], *q;
228                 uid_t uid;
229                 struct samba3_samaccount *acc = &((*accounts)[*count]);
230
231                 if (p[0] == '\0' || p[0] == '#')
232                         continue;
233
234                 ZERO_STRUCTP(acc);
235
236                 q = strchr(p, ':');
237                 if (!q) {
238                         DEBUG(0, ("%s:%d: expected ':'\n", filename, i));
239                         continue;
240                 }
241
242                 acc->username = talloc_strndup(ctx, p, PTR_DIFF(q, p));
243                 p = q+1;
244
245                 uid = atoi(p);
246                 
247                 /* uid is ignored here.. */
248
249                 q = strchr(p, ':');
250                 if (!q) {
251                         DEBUG(0, ("%s:%d: expected ':'\n", filename, i));
252                         continue;
253                 }
254                 p = q+1;
255
256                 if (strlen(p) < 33) {
257                         DEBUG(0, ("%s:%d: expected 32 byte password blob\n", filename, i));
258                         continue;
259                 }
260
261                 if (!strncmp(p, "NO PASSWORD", strlen("NO PASSWORD"))) {
262                         acc->acct_ctrl |= ACB_PWNOTREQ;
263                 } else if (p[0] == '*' || p[0] == 'X') {
264                         /* No password set */
265                 } else {
266                         struct samr_Password *pw = smbpasswd_gethexpwd(*accounts, p);
267                         
268                         if (!pw) {
269                                 DEBUG(0, ("%s:%d: Malformed LM pw entry\n", filename, i));
270                                 continue;
271                         }
272
273                         memcpy(acc->lm_pw.hash, pw, sizeof(*pw));
274                 }
275
276                 if (p[32] != ':') {
277                         DEBUG(0, ("%s:%d: expected ':' after 32 byte password blob\n", filename, i));
278                         continue;
279                 }
280
281                 p += 33;
282                 
283                 if (p[0] == '*' || p[0] == 'X') {
284                         /* No password set */
285                 } else {
286                         struct samr_Password *pw = smbpasswd_gethexpwd(*accounts, p);
287                         
288                         if (!pw) {
289                                 DEBUG(0, ("%s:%d: Malformed LM pw entry\n", filename, i));
290                                 continue;
291                         }
292
293                         memcpy(acc->nt_pw.hash, pw, sizeof(*pw));
294                 }
295                 
296                 if (p[32] != ':') {
297                         DEBUG(0, ("%s:%d: expected ':' after 32 byte password blob\n", filename, i));
298                         continue;
299                 }
300
301                 p += 33;
302
303                 if (p[0] == '[') {
304                         q = strchr(p, ']');
305                         if (!q) {
306                                 DEBUG(0, ("%s:%d: expected ']'\n", filename, i));
307                                 continue;
308                         }
309                         
310                         acc->acct_ctrl |= smbpasswd_decode_acb_info(p);
311
312                         p = q+1;
313                         if (p[0] == ':' && strncmp(p, "LCT-", 4) == 0) {
314                                 int j;
315                                 p += 4;
316
317                                 for(j = 0; j < 8; j++) {
318                                         if(p[j] == '\0' || !isxdigit(p[j])) {
319                                                 break;
320                                         }
321                                 }
322                                 if(i == 8) {
323                                         acc->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
324                                 }
325                         }
326                 } else {
327                         /* 'Old' style file. Fake up based on user name. */
328                         /*
329                          * Currently trust accounts are kept in the same
330                          * password file as 'normal accounts'. If this changes
331                          * we will have to fix this code. JRA.
332                          */
333                         if(acc->username[strlen(acc->username) - 1] == '$') {
334                                 acc->acct_ctrl &= ~ACB_NORMAL;
335                                 acc->acct_ctrl |= ACB_WSTRUST;
336                         }
337                 }
338
339                 (*count)++;
340         }
341
342         talloc_free(lines);
343
344         return NT_STATUS_OK;
345 }