BDC support.
[kai/samba.git] / source / 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 typedef struct
38 {
39         uint32 rid;
40         char *defaultname;
41         char *name;
42 } rid_name;
43
44 /*
45  * A list of the rids of well known BUILTIN and Domain users
46  * and groups.
47  */
48
49 static rid_name builtin_alias_rids[] =
50 {  
51     { BUILTIN_ALIAS_RID_ADMINS       , "Administrators"    , NULL },
52     { BUILTIN_ALIAS_RID_USERS        , "Users"             , NULL },
53     { BUILTIN_ALIAS_RID_GUESTS       , "Guests"            , NULL },
54     { BUILTIN_ALIAS_RID_POWER_USERS  , "Power Users"       , NULL },
55    
56     { BUILTIN_ALIAS_RID_ACCOUNT_OPS  , "Account Operators" , NULL },
57     { BUILTIN_ALIAS_RID_SYSTEM_OPS   , "System Operators"  , NULL },
58     { BUILTIN_ALIAS_RID_PRINT_OPS    , "Print Operators"   , NULL },
59     { BUILTIN_ALIAS_RID_BACKUP_OPS   , "Backup Operators"  , NULL },
60     { BUILTIN_ALIAS_RID_REPLICATOR   , "Replicator"        , NULL },
61     { 0                              , NULL                , NULL}
62 };
63
64 /* array lookup of well-known Domain RID users. */
65 static rid_name domain_user_rids[] =
66 {  
67     { DOMAIN_USER_RID_ADMIN         , "Administrator" , NULL },
68     { DOMAIN_USER_RID_GUEST         , "Guest"         , NULL },
69     { 0                             , NULL            , NULL}
70 };
71
72 /* array lookup of well-known Domain RID groups. */
73 static rid_name domain_group_rids[] =
74 {  
75     { DOMAIN_GROUP_RID_ADMINS       , "Domain Admins" , NULL },
76     { DOMAIN_GROUP_RID_USERS        , "Domain Users"  , NULL },
77     { DOMAIN_GROUP_RID_GUESTS       , "Domain Guests" , NULL },
78     { 0                             , NULL            , NULL}
79 };
80
81 /*******************************************************************
82   make an entry in wk name map
83   the name is strdup()ed!
84  *******************************************************************/
85 static BOOL make_alias_entry(rid_name *map, char *defaultname, char *name)
86 {
87         if(isdigit(*defaultname))
88         {
89                 long rid = -1;
90                 char *s;
91
92                 if(*defaultname == '0')
93                 {
94                         if(defaultname[1] == 'x')
95                         {
96                                 s = "%lx";
97                                 defaultname += 2;
98                         }
99                         else
100                         {
101                                 s = "%lo";
102                         }
103                 }
104                 else
105                 {
106                         s = "%ld";
107                 }
108
109                 sscanf(defaultname, s, &rid);
110
111                 for( ; map->rid; map++)
112                 {
113                         if(map->rid == rid) {
114                                 map->name = strdup(name);
115                                 DEBUG(5, ("make_alias_entry: mapping %s (rid 0x%x) to %s\n",
116                                       map->defaultname, map->rid, map->name));
117                                 return True;
118                         }
119                 }
120                 return False;
121         }
122
123         for( ; map->rid; map++)
124         {
125                 if(!StrCaseCmp(map->name, defaultname)) {
126                         map->name = strdup(name);
127                         DEBUG(5, ("make_alias_entry: mapping %s (rid 0x%x) to %s\n",
128                               map->defaultname, map->rid, map->name));
129                         return True;
130                 }
131         }
132         return False;
133 }
134
135 /*******************************************************************
136   reset wk map to default values
137  *******************************************************************/
138 static void reset_wk_map(rid_name *map)
139 {
140         for( ; map->rid; map++)
141         {
142                 if(map->name != NULL && map->name != map->defaultname)
143                         free(map->name);
144                 map->name = map->defaultname;
145         }
146 }
147
148 /*******************************************************************
149   reset all wk maps
150  *******************************************************************/
151 static void reset_wk_maps(void)
152 {
153         DEBUG(4, ("reset_wk_maps: Initializing maps\n"));
154         reset_wk_map(builtin_alias_rids);
155         reset_wk_map(domain_user_rids);
156         reset_wk_map(domain_group_rids);
157 }
158
159 /*******************************************************************
160   Load builtin alias map
161  *******************************************************************/
162 static BOOL load_wk_rid_map(void)
163 {
164         static int map_initialized = 0;
165         static time_t builtin_rid_file_last_modified = (time_t)0;
166         char *builtin_rid_file = lp_builtinrid_file();
167
168         FILE *fp;
169         char *s;
170         pstring buf;
171
172         if (!map_initialized)
173         {
174                 reset_wk_maps();
175                 map_initialized = 1;
176         }
177
178         if (!*builtin_rid_file)
179         {
180                 return False;
181         }
182
183         fp = open_file_if_modified(builtin_rid_file, "r", &builtin_rid_file_last_modified);
184         if(!fp)
185         {
186                 DEBUG(0,("load_wk_rid_map: can't open name map %s. Error was %s\n",
187                           builtin_rid_file, strerror(errno)));
188                  return False;
189         }
190
191         reset_wk_maps();
192         DEBUG(4,("load_wk_rid_map: Scanning builtin rid map %s\n",builtin_rid_file));
193
194         while ((s = fgets_slash(buf, sizeof(buf), fp)) != NULL)
195         {
196                 pstring defaultname;
197                 pstring name;
198
199                 DEBUG(10,("Read line |%s|\n", s));
200
201                 if (!*s || strchr("#;",*s))
202                         continue;
203
204                 if (!next_token(&s,name, "\t\n\r=", sizeof(defaultname)))
205                         continue;
206
207                 if (!next_token(&s,defaultname, "\t\n\r=", sizeof(name)))
208                         continue;
209
210                 trim_string(defaultname, " ", " ");
211                 trim_string(name, " ", " ");
212
213                 if (!*defaultname || !*name)
214                         continue;
215
216                 if(make_alias_entry(builtin_alias_rids, defaultname, name))
217                         continue;
218                 if(make_alias_entry(domain_user_rids, defaultname, name))
219                         continue;
220                 if(make_alias_entry(domain_group_rids, defaultname, name))
221                         continue;
222
223                 DEBUG(0,("load_wk_rid_map: Unknown alias %s in map %s\n",
224                          defaultname, builtin_rid_file));
225         }
226
227         fclose(fp);
228         return True;
229 }
230
231 /*******************************************************************
232  lookup_wk_group_name
233  ********************************************************************/
234 uint32 lookup_wk_group_name(const char *group_name, const char *domain,
235                                 DOM_SID *sid, uint8 *type)
236 {
237         char *grp_name;
238         int i = -1; /* start do loop at -1 */
239         uint32 rid;
240         (*type) = SID_NAME_DOM_GRP;
241
242         if (strequal(domain, global_sam_name))
243         {
244                 sid_copy(sid, &global_sam_sid);
245         }
246         else if (strequal(domain, "BUILTIN"))
247         {
248                 sid_copy(sid, &global_sid_S_1_5_20);
249         }
250         else
251         {
252                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
253         }
254
255         load_wk_rid_map();
256
257         do /* find, if it exists, a group rid for the group name */
258         {
259                 i++;
260                 rid      = domain_group_rids[i].rid;
261                 grp_name = domain_group_rids[i].name;
262
263                 if (strequal(grp_name, group_name))
264                 {
265                         sid_append_rid(sid, rid);
266
267                         return 0x0;
268                 }
269                         
270         } while (grp_name != NULL);
271
272         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
273 }
274
275 /*******************************************************************
276  lookup_wk_user_name
277  ********************************************************************/
278 uint32 lookup_wk_user_name(const char *user_name, const char *domain,
279                                 DOM_SID *sid, uint8 *type)
280 {
281         char *usr_name;
282         int i = -1; /* start do loop at -1 */
283         (*type) = SID_NAME_USER;
284
285         if (strequal(domain, global_sam_name))
286         {
287                 sid_copy(sid, &global_sam_sid);
288         }
289         else if (strequal(domain, "BUILTIN"))
290         {
291                 sid_copy(sid, &global_sid_S_1_5_20);
292         }
293         else
294         {
295                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
296         }
297
298         load_wk_rid_map();
299
300         do /* find, if it exists, a alias rid for the alias name */
301         {
302                 i++;
303                 usr_name = domain_user_rids[i].name;
304
305         } while (usr_name != NULL && !strequal(usr_name, user_name));
306
307         if (usr_name != NULL)
308         {
309                 sid_append_rid(sid, domain_user_rids[i].rid);
310                 return 0;
311         }
312
313         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
314 }
315
316 /*******************************************************************
317  lookup_builtin_alias_name
318  ********************************************************************/
319 uint32 lookup_builtin_alias_name(const char *alias_name, const char *domain,
320                                 DOM_SID *sid, uint8 *type)
321 {
322         char *als_name;
323         int i = 0;
324         uint32 rid;
325
326         if (strequal(domain, "BUILTIN"))
327         {
328                 if (sid != NULL)
329                 {
330                         sid_copy(sid, &global_sid_S_1_5_20);
331                 }
332         }
333         else
334         {
335                 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
336         }
337
338         load_wk_rid_map();
339
340         do /* find, if it exists, a alias rid for the alias name*/
341         {
342                 rid      = builtin_alias_rids[i].rid;
343                 als_name = builtin_alias_rids[i].name;
344
345                 if (strequal(als_name, alias_name))
346                 {
347                         if (sid != NULL)
348                         {
349                                 sid_append_rid(sid, rid);
350                         }
351
352                         if (type != NULL)
353                         {
354                                 (*type) = SID_NAME_ALIAS;
355                         }
356
357                         return 0x0;
358                 }
359                         
360                 i++;
361
362         } while (als_name != NULL);
363
364         return 0xC0000000 | NT_STATUS_NONE_MAPPED;
365 }
366 /**********************************************************
367  Encode the account control bits into a string.
368  length = length of string to encode into (including terminating
369  null). length *MUST BE MORE THAN 2* !
370  **********************************************************/
371
372 char *pwdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
373 {
374         static fstring acct_str;
375         size_t i = 0;
376
377         acct_str[i++] = '[';
378
379         if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
380         if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
381         if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
382         if (acct_ctrl & ACB_TEMPDUP  ) acct_str[i++] = 'T'; 
383         if (acct_ctrl & ACB_NORMAL   ) acct_str[i++] = 'U';
384         if (acct_ctrl & ACB_MNS      ) acct_str[i++] = 'M';
385         if (acct_ctrl & ACB_WSTRUST  ) acct_str[i++] = 'W';
386         if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
387         if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
388         if (acct_ctrl & ACB_PWNOEXP  ) acct_str[i++] = 'X';
389         if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
390         if (acct_ctrl & ACB_PWLOCK   ) acct_str[i++] = 'P';
391
392         for ( ; i < length - 2 ; i++ )
393         {
394                 acct_str[i] = ' ';
395         }
396
397         i = length - 2;
398         acct_str[i++] = ']';
399         acct_str[i++] = '\0';
400
401         return acct_str;
402 }     
403
404 /**********************************************************
405  Decode the account control bits from a string.
406
407  this function breaks coding standards minimum line width of 80 chars.
408  reason: vertical line-up code clarity - all case statements fit into
409  15 lines, which is more important.
410  **********************************************************/
411
412 uint16 pwdb_decode_acct_ctrl(const char *p)
413 {
414         uint16 acct_ctrl = 0;
415         BOOL finished = False;
416
417         /*
418          * Check if the account type bits have been encoded after the
419          * NT password (in the form [NDHTUWSLXI]).
420          */
421
422         if (*p != '[') return 0;
423
424         for (p++; *p && !finished; p++)
425         {
426                 switch (*p)
427                 {
428                         case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
429                         case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
430                         case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
431                         case 'T': { acct_ctrl |= ACB_TEMPDUP  ; break; /* 'T'emp account. */ } 
432                         case 'U': { acct_ctrl |= ACB_NORMAL   ; break; /* 'U'ser account (normal). */ } 
433                         case 'M': { acct_ctrl |= ACB_MNS      ; break; /* 'M'NS logon user account. What is this ? */ } 
434                         case 'W': { acct_ctrl |= ACB_WSTRUST  ; break; /* 'W'orkstation account. */ } 
435                         case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } 
436                         case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } 
437                         case 'X': { acct_ctrl |= ACB_PWNOEXP  ; break; /* No 'X'piry on password */ } 
438                         case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
439                         case 'P': { acct_ctrl |= ACB_PWLOCK   ; break; /* 'P'assword cannot be changed remotely */ } 
440                         case ' ': { break; }
441                         case ':':
442                         case '\n':
443                         case '\0': 
444                         case ']':
445                         default:  { finished = True; }
446                 }
447         }
448
449         return acct_ctrl;
450 }
451
452 /*******************************************************************
453  gets password-database-format time from a string.
454  ********************************************************************/
455
456 static time_t get_time_from_string(const char *p)
457 {
458         int i;
459
460         for (i = 0; i < 8; i++)
461         {
462                 if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF)))
463                 {
464                         break;
465                 }
466         }
467         if (i == 8)
468         {
469                 /*
470                  * p points at 8 characters of hex digits - 
471                  * read into a time_t as the seconds since
472                  * 1970 that the password was last changed.
473                  */
474                 return (time_t)strtol(p, NULL, 16);
475         }
476         return (time_t)-1;
477 }
478
479 /*******************************************************************
480  gets password last set time
481  ********************************************************************/
482
483 time_t pwdb_get_last_set_time(const char *p)
484 {
485         if (*p && !StrnCaseCmp(p, "LCT-", 4))
486         {
487                 return get_time_from_string(p + 4);
488         }
489         return (time_t)-1;
490 }
491
492
493 /*******************************************************************
494  sets password-database-format time in a string.
495  ********************************************************************/
496 static void set_time_in_string(char *p, int max_len, char *type, time_t t)
497 {
498         slprintf(p, max_len, ":%s-%08X:", type, (uint32)t);
499 }
500
501 /*******************************************************************
502  sets logon time
503  ********************************************************************/
504 void pwdb_set_logon_time(char *p, int max_len, time_t t)
505 {
506         set_time_in_string(p, max_len, "LNT", t);
507 }
508
509 /*******************************************************************
510  sets logoff time
511  ********************************************************************/
512 void pwdb_set_logoff_time(char *p, int max_len, time_t t)
513 {
514         set_time_in_string(p, max_len, "LOT", t);
515 }
516
517 /*******************************************************************
518  sets kickoff time
519  ********************************************************************/
520 void pwdb_set_kickoff_time(char *p, int max_len, time_t t)
521 {
522         set_time_in_string(p, max_len, "KOT", t);
523 }
524
525 /*******************************************************************
526  sets password can change time
527  ********************************************************************/
528 void pwdb_set_can_change_time(char *p, int max_len, time_t t)
529 {
530         set_time_in_string(p, max_len, "CCT", t);
531 }
532
533 /*******************************************************************
534  sets password last set time
535  ********************************************************************/
536 void pwdb_set_must_change_time(char *p, int max_len, time_t t)
537 {
538         set_time_in_string(p, max_len, "MCT", t);
539 }
540
541 /*******************************************************************
542  sets password last set time
543  ********************************************************************/
544 void pwdb_set_last_set_time(char *p, int max_len, time_t t)
545 {
546         set_time_in_string(p, max_len, "LCT", t);
547 }
548
549
550 /*************************************************************
551  Routine to set 32 hex password characters from a 16 byte array.
552 **************************************************************/
553 void pwdb_sethexpwd(char *p, const char *pwd, uint16 acct_ctrl)
554 {
555         if (pwd != NULL)
556         {
557                 int i;
558                 for (i = 0; i < 16; i++)
559                 {
560                         slprintf(&p[i*2], 33, "%02X", pwd[i]);
561                 }
562         }
563         else
564         {
565                 if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ))
566                 {
567                         safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
568                 }
569                 else
570                 {
571                         safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
572                 }
573         }
574 }
575
576 /*************************************************************
577  Routine to get the 32 hex characters and turn them
578  into a 16 byte array.
579 **************************************************************/
580 BOOL pwdb_gethexpwd(const char *p, char *pwd, uint32 *acct_ctrl)
581 {
582         if (strnequal(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32))
583         {
584                 if (acct_ctrl != NULL)
585                 {
586                         *acct_ctrl |= ACB_PWNOTREQ;
587                 }
588                 pwd[0] = 0;
589                 return True;
590         }
591         else if (strnequal(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32))
592         {
593                 pwd[0] = 0;
594                 return True;
595         }
596         else
597         {
598                 return strhex_to_str(pwd, 32, p) == 16;
599         }
600 }
601
602
603 /*************************************************************
604  initialise password databases, domain names, domain sid.
605 **************************************************************/
606 BOOL pwdb_initialise(BOOL is_server)
607 {
608         get_sam_domain_name();
609
610         if (!init_myworkgroup())
611         {
612                 return False;
613         }
614
615         generate_wellknown_sids();
616
617         if (is_server)
618         {
619                 if (!generate_sam_sid(global_sam_name))
620                 {
621                         DEBUG(0,("ERROR: Samba cannot create a SAM SID for its domain (%s).\n",
622                                   global_sam_name));
623                         return False;
624                 }
625         }
626         else
627         {
628                 char *srvs;
629                 if (lp_server_role() == ROLE_DOMAIN_PDC)
630                 {
631                         srvs = global_myname;
632                 }
633                 else
634                 {
635                         srvs = lp_passwordserver();
636                 }
637                 if (!get_domain_sids(&global_member_sid, &global_sam_sid, srvs))
638                 {
639                         return False;
640                 }
641         }
642
643         return initialise_password_db();
644 }
645
646 /*************************************************************
647  the following functions lookup wk rid's.
648  these may be unnecessary...
649 **************************************************************/
650 static char *lookup_wk_rid(uint32 rid, rid_name *table)
651 {
652         load_wk_rid_map();
653         for( ; table->rid ; table++)
654         {
655                 if(table->rid == rid)
656                 {
657                         return table->name;
658                 }
659         }
660         return NULL;
661 }
662
663 char *lookup_wk_alias_rid(uint32 rid)
664 {
665         return lookup_wk_rid(rid, builtin_alias_rids);
666 }
667
668 char *lookup_wk_user_rid(uint32 rid)
669 {
670         return lookup_wk_rid(rid, domain_user_rids);
671 }
672
673 char *lookup_wk_group_rid(uint32 rid)
674 {
675         return lookup_wk_rid(rid, domain_group_rids);
676 }
677