SAM database "set user info".
[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_DOM_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         if (acct_ctrl & ACB_PWLOCK   ) acct_str[i++] = 'P';
229
230         for ( ; i < length - 2 ; i++ )
231         {
232                 acct_str[i] = ' ';
233         }
234
235         i = length - 2;
236         acct_str[i++] = ']';
237         acct_str[i++] = '\0';
238
239         return acct_str;
240 }     
241
242 /**********************************************************
243  Decode the account control bits from a string.
244
245  this function breaks coding standards minimum line width of 80 chars.
246  reason: vertical line-up code clarity - all case statements fit into
247  15 lines, which is more important.
248  **********************************************************/
249
250 uint16 pwdb_decode_acct_ctrl(const char *p)
251 {
252         uint16 acct_ctrl = 0;
253         BOOL finished = False;
254
255         /*
256          * Check if the account type bits have been encoded after the
257          * NT password (in the form [NDHTUWSLXI]).
258          */
259
260         if (*p != '[') return 0;
261
262         for (p++; *p && !finished; p++)
263         {
264                 switch (*p)
265                 {
266                         case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
267                         case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
268                         case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
269                         case 'T': { acct_ctrl |= ACB_TEMPDUP  ; break; /* 'T'emp account. */ } 
270                         case 'U': { acct_ctrl |= ACB_NORMAL   ; break; /* 'U'ser account (normal). */ } 
271                         case 'M': { acct_ctrl |= ACB_MNS      ; break; /* 'M'NS logon user account. What is this ? */ } 
272                         case 'W': { acct_ctrl |= ACB_WSTRUST  ; break; /* 'W'orkstation account. */ } 
273                         case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } 
274                         case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } 
275                         case 'X': { acct_ctrl |= ACB_PWNOEXP  ; break; /* No 'X'piry on password */ } 
276                         case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
277                         case 'P': { acct_ctrl |= ACB_PWLOCK   ; break; /* 'P'assword cannot be changed remotely */ } 
278                         case ' ': { break; }
279                         case ':':
280                         case '\n':
281                         case '\0': 
282                         case ']':
283                         default:  { finished = True; }
284                 }
285         }
286
287         return acct_ctrl;
288 }
289
290 /*******************************************************************
291  gets password-database-format time from a string.
292  ********************************************************************/
293
294 static time_t get_time_from_string(const char *p)
295 {
296         int i;
297
298         for (i = 0; i < 8; i++)
299         {
300                 if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF)))
301                 {
302                         break;
303                 }
304         }
305         if (i == 8)
306         {
307                 /*
308                  * p points at 8 characters of hex digits - 
309                  * read into a time_t as the seconds since
310                  * 1970 that the password was last changed.
311                  */
312                 return (time_t)strtol(p, NULL, 16);
313         }
314         return (time_t)-1;
315 }
316
317 /*******************************************************************
318  gets password last set time
319  ********************************************************************/
320
321 time_t pwdb_get_last_set_time(const char *p)
322 {
323         if (*p && !StrnCaseCmp(p, "LCT-", 4))
324         {
325                 return get_time_from_string(p + 4);
326         }
327         return (time_t)-1;
328 }
329
330
331 /*******************************************************************
332  sets password-database-format time in a string.
333  ********************************************************************/
334 static void set_time_in_string(char *p, int max_len, char *type, time_t t)
335 {
336         slprintf(p, max_len, ":%s-%08X:", type, (uint32)t);
337 }
338
339 /*******************************************************************
340  sets logon time
341  ********************************************************************/
342 void pwdb_set_logon_time(char *p, int max_len, time_t t)
343 {
344         set_time_in_string(p, max_len, "LNT", t);
345 }
346
347 /*******************************************************************
348  sets logoff time
349  ********************************************************************/
350 void pwdb_set_logoff_time(char *p, int max_len, time_t t)
351 {
352         set_time_in_string(p, max_len, "LOT", t);
353 }
354
355 /*******************************************************************
356  sets kickoff time
357  ********************************************************************/
358 void pwdb_set_kickoff_time(char *p, int max_len, time_t t)
359 {
360         set_time_in_string(p, max_len, "KOT", t);
361 }
362
363 /*******************************************************************
364  sets password can change time
365  ********************************************************************/
366 void pwdb_set_can_change_time(char *p, int max_len, time_t t)
367 {
368         set_time_in_string(p, max_len, "CCT", t);
369 }
370
371 /*******************************************************************
372  sets password last set time
373  ********************************************************************/
374 void pwdb_set_must_change_time(char *p, int max_len, time_t t)
375 {
376         set_time_in_string(p, max_len, "MCT", t);
377 }
378
379 /*******************************************************************
380  sets password last set time
381  ********************************************************************/
382 void pwdb_set_last_set_time(char *p, int max_len, time_t t)
383 {
384         set_time_in_string(p, max_len, "LCT", t);
385 }
386
387
388 /*************************************************************
389  Routine to set 32 hex password characters from a 16 byte array.
390 **************************************************************/
391 void pwdb_sethexpwd(char *p, const char *pwd, uint16 acct_ctrl)
392 {
393         if (pwd != NULL)
394         {
395                 int i;
396                 for (i = 0; i < 16; i++)
397                 {
398                         slprintf(&p[i*2], 33, "%02X", pwd[i]);
399                 }
400         }
401         else
402         {
403                 if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ))
404                 {
405                         safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
406                 }
407                 else
408                 {
409                         safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
410                 }
411         }
412 }
413
414 /*************************************************************
415  Routine to get the 32 hex characters and turn them
416  into a 16 byte array.
417 **************************************************************/
418 BOOL pwdb_gethexpwd(const char *p, char *pwd, uint32 *acct_ctrl)
419 {
420         if (strnequal(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32))
421         {
422                 if (acct_ctrl != NULL)
423                 {
424                         *acct_ctrl |= ACB_PWNOTREQ;
425                 }
426                 pwd[0] = 0;
427                 return True;
428         }
429         else if (strnequal(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32))
430         {
431                 pwd[0] = 0;
432                 return True;
433         }
434         else
435         {
436                 return strhex_to_str(pwd, 32, p) == 16;
437         }
438 }
439
440
441 /*************************************************************
442  initialise password databases, domain names, domain sid.
443 **************************************************************/
444 BOOL pwdb_initialise(BOOL is_server)
445 {
446         get_sam_domain_name();
447
448         if (!init_myworkgroup())
449         {
450                 return False;
451         }
452
453         generate_wellknown_sids();
454
455         if (is_server)
456         {
457                 if (!generate_sam_sid(global_sam_name))
458                 {
459                         DEBUG(0,("ERROR: Samba cannot create a SAM SID for its domain (%s).\n",
460                                   global_sam_name));
461                         return False;
462                 }
463         }
464         else
465         {
466                 if (!get_domain_sids(&global_member_sid, &global_sam_sid, global_myname))
467                 {
468                         return False;
469                 }
470         }
471
472         return initialise_password_db();
473 }