fixing smbpasswd to link to smbd to obtain domain sid
[samba.git] / source3 / lib / util_pwdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Jeremy Allison 1996-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
7       
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "nterr.h"
25
26 extern int DEBUGLEVEL;
27 extern DOM_SID global_sam_sid;
28 extern fstring global_sam_name;
29
30 extern DOM_SID global_member_sid;
31 extern fstring global_myworkgroup;
32
33 extern DOM_SID global_sid_S_1_5_20;
34
35 extern pstring global_myname;
36
37 /*
38  * A list of the rids of well known BUILTIN and Domain users
39  * and groups.
40  */
41
42 rid_name builtin_alias_rids[] =
43 {  
44     { BUILTIN_ALIAS_RID_ADMINS       , "Administrators" },
45     { BUILTIN_ALIAS_RID_USERS        , "Users" },
46     { BUILTIN_ALIAS_RID_GUESTS       , "Guests" },
47     { BUILTIN_ALIAS_RID_POWER_USERS  , "Power Users" },
48    
49     { BUILTIN_ALIAS_RID_ACCOUNT_OPS  , "Account Operators" },
50     { BUILTIN_ALIAS_RID_SYSTEM_OPS   , "System Operators" },
51     { BUILTIN_ALIAS_RID_PRINT_OPS    , "Print Operators" },
52     { BUILTIN_ALIAS_RID_BACKUP_OPS   , "Backup Operators" },
53     { BUILTIN_ALIAS_RID_REPLICATOR   , "Replicator" },
54     { 0                             , NULL }
55 };
56
57 /* array lookup of well-known Domain RID users. */
58 rid_name domain_user_rids[] =
59 {  
60     { DOMAIN_USER_RID_ADMIN         , "Administrator" },
61     { DOMAIN_USER_RID_GUEST         , "Guest" },
62     { 0                             , NULL }
63 };
64
65 /* array lookup of well-known Domain RID groups. */
66 rid_name domain_group_rids[] =
67 {  
68     { DOMAIN_GROUP_RID_ADMINS       , "Domain Admins" },
69     { DOMAIN_GROUP_RID_USERS        , "Domain Users" },
70     { DOMAIN_GROUP_RID_GUESTS       , "Domain Guests" },
71     { 0                             , NULL }
72 };
73
74
75 /*******************************************************************
76  lookup_wk_group_name
77  ********************************************************************/
78 uint32 lookup_wk_group_name(const char *group_name, const char *domain,
79                                 DOM_SID *sid, uint8 *type)
80 {
81         char *grp_name;
82         int i = -1; /* start do loop at -1 */
83         uint32 rid;
84         (*type) = SID_NAME_WKN_GRP;
85
86         if (strequal(domain, global_sam_name))
87         {
88                 sid_copy(sid, &global_sam_sid);
89         }
90         else if (strequal(domain, "BUILTIN"))
91         {
92                 sid_copy(sid, &global_sid_S_1_5_20);
93         }
94         else
95         {
96                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
97         }
98
99         do /* find, if it exists, a group rid for the group name */
100         {
101                 i++;
102                 rid      = domain_group_rids[i].rid;
103                 grp_name = domain_group_rids[i].name;
104
105                 if (strequal(grp_name, group_name))
106                 {
107                         sid_append_rid(sid, rid);
108
109                         return 0x0;
110                 }
111                         
112         } while (grp_name != NULL);
113
114         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
115 }
116
117 /*******************************************************************
118  lookup_wk_user_name
119  ********************************************************************/
120 uint32 lookup_wk_user_name(const char *user_name, const char *domain,
121                                 DOM_SID *sid, uint8 *type)
122 {
123         char *usr_name;
124         int i = -1; /* start do loop at -1 */
125         (*type) = SID_NAME_USER;
126
127         if (strequal(domain, global_sam_name))
128         {
129                 sid_copy(sid, &global_sam_sid);
130         }
131         else if (strequal(domain, "BUILTIN"))
132         {
133                 sid_copy(sid, &global_sid_S_1_5_20);
134         }
135         else
136         {
137                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
138         }
139
140         do /* find, if it exists, a alias rid for the alias name */
141         {
142                 i++;
143                 usr_name = domain_user_rids[i].name;
144
145         } while (usr_name != NULL && !strequal(usr_name, user_name));
146
147         if (usr_name != NULL)
148         {
149                 sid_append_rid(sid, domain_user_rids[i].rid);
150                 return 0;
151         }
152
153         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
154 }
155
156 /*******************************************************************
157  lookup_builtin_alias_name
158  ********************************************************************/
159 uint32 lookup_builtin_alias_name(const char *alias_name, const char *domain,
160                                 DOM_SID *sid, uint8 *type)
161 {
162         char *als_name;
163         int i = 0;
164         uint32 rid;
165
166         if (strequal(domain, "BUILTIN"))
167         {
168                 if (sid != NULL)
169                 {
170                         sid_copy(sid, &global_sid_S_1_5_20);
171                 }
172         }
173         else
174         {
175                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
176         }
177
178         do /* find, if it exists, a alias rid for the alias name*/
179         {
180                 rid      = builtin_alias_rids[i].rid;
181                 als_name = builtin_alias_rids[i].name;
182
183                 if (strequal(als_name, alias_name))
184                 {
185                         if (sid != NULL)
186                         {
187                                 sid_append_rid(sid, rid);
188                         }
189
190                         if (type != NULL)
191                         {
192                                 (*type) = SID_NAME_ALIAS;
193                         }
194
195                         return 0x0;
196                 }
197                         
198                 i++;
199
200         } while (als_name != NULL);
201
202         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
203 }
204 /**********************************************************
205  Encode the account control bits into a string.
206  length = length of string to encode into (including terminating
207  null). length *MUST BE MORE THAN 2* !
208  **********************************************************/
209
210 char *pwdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
211 {
212         static fstring acct_str;
213         size_t i = 0;
214
215         acct_str[i++] = '[';
216
217         if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
218         if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
219         if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
220         if (acct_ctrl & ACB_TEMPDUP  ) acct_str[i++] = 'T'; 
221         if (acct_ctrl & ACB_NORMAL   ) acct_str[i++] = 'U';
222         if (acct_ctrl & ACB_MNS      ) acct_str[i++] = 'M';
223         if (acct_ctrl & ACB_WSTRUST  ) acct_str[i++] = 'W';
224         if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
225         if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
226         if (acct_ctrl & ACB_PWNOEXP  ) acct_str[i++] = 'X';
227         if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
228
229         for ( ; i < length - 2 ; i++ )
230         {
231                 acct_str[i] = ' ';
232         }
233
234         i = length - 2;
235         acct_str[i++] = ']';
236         acct_str[i++] = '\0';
237
238         return acct_str;
239 }     
240
241 /**********************************************************
242  Decode the account control bits from a string.
243
244  this function breaks coding standards minimum line width of 80 chars.
245  reason: vertical line-up code clarity - all case statements fit into
246  15 lines, which is more important.
247  **********************************************************/
248
249 uint16 pwdb_decode_acct_ctrl(const char *p)
250 {
251         uint16 acct_ctrl = 0;
252         BOOL finished = False;
253
254         /*
255          * Check if the account type bits have been encoded after the
256          * NT password (in the form [NDHTUWSLXI]).
257          */
258
259         if (*p != '[') return 0;
260
261         for (p++; *p && !finished; p++)
262         {
263                 switch (*p)
264                 {
265                         case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
266                         case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
267                         case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
268                         case 'T': { acct_ctrl |= ACB_TEMPDUP  ; break; /* 'T'emp account. */ } 
269                         case 'U': { acct_ctrl |= ACB_NORMAL   ; break; /* 'U'ser account (normal). */ } 
270                         case 'M': { acct_ctrl |= ACB_MNS      ; break; /* 'M'NS logon user account. What is this ? */ } 
271                         case 'W': { acct_ctrl |= ACB_WSTRUST  ; break; /* 'W'orkstation account. */ } 
272                         case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } 
273                         case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } 
274                         case 'X': { acct_ctrl |= ACB_PWNOEXP  ; break; /* No 'X'piry on password */ } 
275                         case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
276                         case ' ': { break; }
277                         case ':':
278                         case '\n':
279                         case '\0': 
280                         case ']':
281                         default:  { finished = True; }
282                 }
283         }
284
285         return acct_ctrl;
286 }
287
288 /*******************************************************************
289  gets password-database-format time from a string.
290  ********************************************************************/
291
292 static time_t get_time_from_string(const char *p)
293 {
294         int i;
295
296         for (i = 0; i < 8; i++)
297         {
298                 if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF)))
299                 {
300                         break;
301                 }
302         }
303         if (i == 8)
304         {
305                 /*
306                  * p points at 8 characters of hex digits - 
307                  * read into a time_t as the seconds since
308                  * 1970 that the password was last changed.
309                  */
310                 return (time_t)strtol(p, NULL, 16);
311         }
312         return (time_t)-1;
313 }
314
315 /*******************************************************************
316  gets password last set time
317  ********************************************************************/
318
319 time_t pwdb_get_last_set_time(const char *p)
320 {
321         if (*p && StrnCaseCmp(p, "LCT-", 4))
322         {
323                 return get_time_from_string(p + 4);
324         }
325         return (time_t)-1;
326 }
327
328
329 /*******************************************************************
330  sets password-database-format time in a string.
331  ********************************************************************/
332 static void set_time_in_string(char *p, int max_len, char *type, time_t t)
333 {
334         slprintf(p, max_len, ":%s-%08X:", type, (uint32)t);
335 }
336
337 /*******************************************************************
338  sets logon time
339  ********************************************************************/
340 void pwdb_set_logon_time(char *p, int max_len, time_t t)
341 {
342         set_time_in_string(p, max_len, "LNT", t);
343 }
344
345 /*******************************************************************
346  sets logoff time
347  ********************************************************************/
348 void pwdb_set_logoff_time(char *p, int max_len, time_t t)
349 {
350         set_time_in_string(p, max_len, "LOT", t);
351 }
352
353 /*******************************************************************
354  sets kickoff time
355  ********************************************************************/
356 void pwdb_set_kickoff_time(char *p, int max_len, time_t t)
357 {
358         set_time_in_string(p, max_len, "KOT", t);
359 }
360
361 /*******************************************************************
362  sets password can change time
363  ********************************************************************/
364 void pwdb_set_can_change_time(char *p, int max_len, time_t t)
365 {
366         set_time_in_string(p, max_len, "CCT", t);
367 }
368
369 /*******************************************************************
370  sets password last set time
371  ********************************************************************/
372 void pwdb_set_must_change_time(char *p, int max_len, time_t t)
373 {
374         set_time_in_string(p, max_len, "MCT", t);
375 }
376
377 /*******************************************************************
378  sets password last set time
379  ********************************************************************/
380 void pwdb_set_last_set_time(char *p, int max_len, time_t t)
381 {
382         set_time_in_string(p, max_len, "LCT", t);
383 }
384
385
386 /*************************************************************
387  Routine to set 32 hex password characters from a 16 byte array.
388 **************************************************************/
389 void pwdb_sethexpwd(char *p, const char *pwd, uint16 acct_ctrl)
390 {
391         if (pwd != NULL)
392         {
393                 int i;
394                 for (i = 0; i < 16; i++)
395                 {
396                         slprintf(&p[i*2], 33, "%02X", pwd[i]);
397                 }
398         }
399         else
400         {
401                 if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ))
402                 {
403                         safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
404                 }
405                 else
406                 {
407                         safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
408                 }
409         }
410 }
411
412 /*************************************************************
413  Routine to get the 32 hex characters and turn them
414  into a 16 byte array.
415 **************************************************************/
416 BOOL pwdb_gethexpwd(const char *p, char *pwd)
417 {
418         return strhex_to_str(pwd, 32, p) == 16;
419 }
420
421 /*************************************************************
422  initialise password databases, domain names, domain sid.
423 **************************************************************/
424 BOOL pwdb_initialise(BOOL is_server)
425 {
426         fstrcpy(global_myworkgroup, lp_workgroup());
427
428         if (strequal(global_myworkgroup,"*"))
429         {
430                 DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
431                 return False;
432         }
433
434         get_sam_domain_name();
435
436         generate_wellknown_sids();
437
438         if (is_server)
439         {
440                 if (!generate_sam_sid(global_sam_name))
441                 {
442                         DEBUG(0,("ERROR: Samba cannot create a SAM SID for its domain (%s).\n",
443                                   global_sam_name));
444                         return False;
445                 }
446         }
447         else
448         {
449                 if (!get_domain_sids(&global_member_sid, &global_sam_sid, global_myname))
450                 {
451                         return False;
452                 }
453         }
454
455         return initialise_password_db();
456 }