bcbb5e56d89e331687cf072321503ff3f01e9988
[sfrench/samba-autobuild/.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    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 "librpc/gen_ndr/ndr_samr.h"
57 #include "system/iconv.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                 {
81                         return (False);
82                 }
83                 
84                 hinybble = PTR_DIFF(p1, hexchars);
85                 lonybble = PTR_DIFF(p2, hexchars);
86                 
87                 pwd->hash[i / 2] = (hinybble << 4) | lonybble;
88         }
89         return pwd;
90 }
91
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;
95
96 char *smbpasswd_sethexpwd(TALLOC_CTX *mem_ctx, struct samr_Password *pwd, uint16_t acb_info)
97 {
98         char *p;
99         if (pwd != NULL) {
100                 int i;
101                 p = talloc_array(mem_ctx, char, 33);
102                 if (!p) {
103                         return NULL;
104                 }
105
106                 for (i = 0; i < sizeof(pwd->hash); i++)
107                         slprintf(&p[i*2], 3, "%02X", pwd->hash[i]);
108         } else {
109                 if (acb_info & ACB_PWNOTREQ)
110                         p = talloc_strdup(mem_ctx, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
111                 else
112                         p = talloc_strdup(mem_ctx, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
113         }
114         return p;
115 }
116
117 /*! Decode the account control bits (ACB) info from a string. */
118
119 uint16_t smbpasswd_decode_acb_info(const char *p)
120 {
121         uint16_t acb_info = 0;
122         BOOL finished = False;
123
124         /*
125          * Check if the account type bits have been encoded after the
126          * NT password (in the form [NDHTUWSLXI]).
127          */
128
129         if (*p != '[') return 0;
130
131         for (p++; *p && !finished; p++)
132         {
133                 switch (*p) {
134                 case 'N': /* 'N'o password. */
135                         acb_info |= ACB_PWNOTREQ; 
136                         break;
137                 case 'D': /* 'D'isabled. */
138                         acb_info |= ACB_DISABLED; 
139                         break; 
140                 case 'H': /* 'H'omedir required. */
141                         acb_info |= ACB_HOMDIRREQ; 
142                         break;
143                 case 'T': /* 'T'emp account. */
144                         acb_info |= ACB_TEMPDUP; 
145                         break;
146                 case 'U': /* 'U'ser account (normal). */
147                         acb_info |= ACB_NORMAL;
148                         break;
149                 case 'M': /* 'M'NS logon user account. What is this ? */
150                         acb_info |= ACB_MNS; 
151                         break; 
152                 case 'W': /* 'W'orkstation account. */
153                         acb_info |= ACB_WSTRUST; 
154                         break; 
155                 case 'S': /* 'S'erver account. */ 
156                         acb_info |= ACB_SVRTRUST; 
157                         break; 
158                 case 'L': /* 'L'ocked account. */
159                         acb_info |= ACB_AUTOLOCK; 
160                         break; 
161                 case 'X': /* No 'X'piry on password */
162                         acb_info |= ACB_PWNOEXP; 
163                         break; 
164                 case 'I': /* 'I'nterdomain trust account. */
165                         acb_info |= ACB_DOMTRUST; 
166                         break; 
167
168                 case ' ': 
169                         break;
170                 case ':':
171                 case '\n':
172                 case '\0': 
173                 case ']':
174                 default:  
175                         finished = True;
176                         break;
177                 }
178         }
179
180         return acb_info;
181 }
182
183 /*! Encode account control bits (ACBs) into a string. */
184
185 char *smbpasswd_encode_acb_info(TALLOC_CTX *mem_ctx, uint16_t acb_info)
186 {
187         char *acct_str = talloc_array(mem_ctx, char, 35);
188         size_t i = 0;
189
190         acct_str[i++] = '[';
191
192         if (acb_info & ACB_PWNOTREQ ) acct_str[i++] = 'N';
193         if (acb_info & ACB_DISABLED ) acct_str[i++] = 'D';
194         if (acb_info & ACB_HOMDIRREQ) acct_str[i++] = 'H';
195         if (acb_info & ACB_TEMPDUP  ) acct_str[i++] = 'T'; 
196         if (acb_info & ACB_NORMAL   ) acct_str[i++] = 'U';
197         if (acb_info & ACB_MNS      ) acct_str[i++] = 'M';
198         if (acb_info & ACB_WSTRUST  ) acct_str[i++] = 'W';
199         if (acb_info & ACB_SVRTRUST ) acct_str[i++] = 'S';
200         if (acb_info & ACB_AUTOLOCK ) acct_str[i++] = 'L';
201         if (acb_info & ACB_PWNOEXP  ) acct_str[i++] = 'X';
202         if (acb_info & ACB_DOMTRUST ) acct_str[i++] = 'I';
203
204         acct_str[i++] = ']';
205         acct_str[i++] = '\0';
206
207         return acct_str;
208 }