2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Jeremy Allison 1996-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1996-1998
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.
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.
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.
26 extern int DEBUGLEVEL;
27 extern DOM_SID global_sam_sid;
28 extern fstring global_sam_name;
30 extern DOM_SID global_member_sid;
31 extern fstring global_myworkgroup;
33 extern DOM_SID global_sid_S_1_5_20;
35 extern pstring global_myname;
45 * A list of the rids of well known BUILTIN and Domain users
49 static rid_name builtin_alias_rids[] =
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 },
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 },
64 /* array lookup of well-known Domain RID users. */
65 static rid_name domain_user_rids[] =
67 { DOMAIN_USER_RID_ADMIN , "Administrator" , NULL },
68 { DOMAIN_USER_RID_GUEST , "Guest" , NULL },
72 /* array lookup of well-known Domain RID groups. */
73 static rid_name domain_group_rids[] =
75 { DOMAIN_GROUP_RID_ADMINS , "Domain Admins" , NULL },
76 { DOMAIN_GROUP_RID_USERS , "Domain Users" , NULL },
77 { DOMAIN_GROUP_RID_GUESTS , "Domain Guests" , NULL },
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)
87 if(isdigit(*defaultname))
92 if(*defaultname == '0')
94 if(defaultname[1] == 'x')
109 sscanf(defaultname, s, &rid);
111 for( ; map->rid; map++)
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));
123 for( ; map->rid; map++)
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));
135 /*******************************************************************
136 reset wk map to default values
137 *******************************************************************/
138 static void reset_wk_map(rid_name *map)
140 for( ; map->rid; map++)
142 if(map->name != NULL && map->name != map->defaultname)
144 map->name = map->defaultname;
148 /*******************************************************************
150 *******************************************************************/
151 static void reset_wk_maps(void)
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);
159 /*******************************************************************
160 Load builtin alias map
161 *******************************************************************/
162 static BOOL load_wk_rid_map(void)
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();
172 if (!map_initialized)
178 if (!*builtin_rid_file)
183 fp = open_file_if_modified(builtin_rid_file, "r", &builtin_rid_file_last_modified);
186 DEBUG(0,("load_wk_rid_map: can't open name map %s. Error was %s\n",
187 builtin_rid_file, strerror(errno)));
192 DEBUG(4,("load_wk_rid_map: Scanning builtin rid map %s\n",builtin_rid_file));
194 while ((s = fgets_slash(buf, sizeof(buf), fp)) != NULL)
199 DEBUG(10,("Read line |%s|\n", s));
201 if (!*s || strchr("#;",*s))
204 if (!next_token(&s,name, "\t\n\r=", sizeof(defaultname)))
207 if (!next_token(&s,defaultname, "\t\n\r=", sizeof(name)))
210 trim_string(defaultname, " ", " ");
211 trim_string(name, " ", " ");
213 if (!*defaultname || !*name)
216 if(make_alias_entry(builtin_alias_rids, defaultname, name))
218 if(make_alias_entry(domain_user_rids, defaultname, name))
220 if(make_alias_entry(domain_group_rids, defaultname, name))
223 DEBUG(0,("load_wk_rid_map: Unknown alias %s in map %s\n",
224 defaultname, builtin_rid_file));
231 /*******************************************************************
233 ********************************************************************/
234 uint32 lookup_wk_group_name(const char *group_name, const char *domain,
235 DOM_SID *sid, uint8 *type)
238 int i = -1; /* start do loop at -1 */
240 (*type) = SID_NAME_DOM_GRP;
242 if (strequal(domain, global_sam_name))
244 sid_copy(sid, &global_sam_sid);
246 else if (strequal(domain, "BUILTIN"))
248 sid_copy(sid, &global_sid_S_1_5_20);
252 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
257 do /* find, if it exists, a group rid for the group name */
260 rid = domain_group_rids[i].rid;
261 grp_name = domain_group_rids[i].name;
263 if (strequal(grp_name, group_name))
265 sid_append_rid(sid, rid);
270 } while (grp_name != NULL);
272 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
275 /*******************************************************************
277 ********************************************************************/
278 uint32 lookup_wk_user_name(const char *user_name, const char *domain,
279 DOM_SID *sid, uint8 *type)
282 int i = -1; /* start do loop at -1 */
283 (*type) = SID_NAME_USER;
285 if (strequal(domain, global_sam_name))
287 sid_copy(sid, &global_sam_sid);
289 else if (strequal(domain, "BUILTIN"))
291 sid_copy(sid, &global_sid_S_1_5_20);
295 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
300 do /* find, if it exists, a alias rid for the alias name */
303 usr_name = domain_user_rids[i].name;
305 } while (usr_name != NULL && !strequal(usr_name, user_name));
307 if (usr_name != NULL)
309 sid_append_rid(sid, domain_user_rids[i].rid);
313 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
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)
326 if (strequal(domain, "BUILTIN"))
330 sid_copy(sid, &global_sid_S_1_5_20);
335 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
340 do /* find, if it exists, a alias rid for the alias name*/
342 rid = builtin_alias_rids[i].rid;
343 als_name = builtin_alias_rids[i].name;
345 if (strequal(als_name, alias_name))
349 sid_append_rid(sid, rid);
354 (*type) = SID_NAME_ALIAS;
362 } while (als_name != NULL);
364 return 0xC0000000 | NT_STATUS_NONE_MAPPED;
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 **********************************************************/
372 char *pwdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
374 static fstring acct_str;
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';
392 for ( ; i < length - 2 ; i++ )
399 acct_str[i++] = '\0';
404 /**********************************************************
405 Decode the account control bits from a string.
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 **********************************************************/
412 uint16 pwdb_decode_acct_ctrl(const char *p)
414 uint16 acct_ctrl = 0;
415 BOOL finished = False;
418 * Check if the account type bits have been encoded after the
419 * NT password (in the form [NDHTUWSLXI]).
422 if (*p != '[') return 0;
424 for (p++; *p && !finished; p++)
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 */ }
445 default: { finished = True; }
452 /*******************************************************************
453 gets password-database-format time from a string.
454 ********************************************************************/
456 static time_t get_time_from_string(const char *p)
460 for (i = 0; i < 8; i++)
462 if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF)))
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.
474 return (time_t)strtol(p, NULL, 16);
479 /*******************************************************************
480 gets password last set time
481 ********************************************************************/
483 time_t pwdb_get_last_set_time(const char *p)
485 if (*p && !StrnCaseCmp(p, "LCT-", 4))
487 return get_time_from_string(p + 4);
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)
498 slprintf(p, max_len, ":%s-%08X:", type, (uint32)t);
501 /*******************************************************************
503 ********************************************************************/
504 void pwdb_set_logon_time(char *p, int max_len, time_t t)
506 set_time_in_string(p, max_len, "LNT", t);
509 /*******************************************************************
511 ********************************************************************/
512 void pwdb_set_logoff_time(char *p, int max_len, time_t t)
514 set_time_in_string(p, max_len, "LOT", t);
517 /*******************************************************************
519 ********************************************************************/
520 void pwdb_set_kickoff_time(char *p, int max_len, time_t t)
522 set_time_in_string(p, max_len, "KOT", t);
525 /*******************************************************************
526 sets password can change time
527 ********************************************************************/
528 void pwdb_set_can_change_time(char *p, int max_len, time_t t)
530 set_time_in_string(p, max_len, "CCT", t);
533 /*******************************************************************
534 sets password last set time
535 ********************************************************************/
536 void pwdb_set_must_change_time(char *p, int max_len, time_t t)
538 set_time_in_string(p, max_len, "MCT", t);
541 /*******************************************************************
542 sets password last set time
543 ********************************************************************/
544 void pwdb_set_last_set_time(char *p, int max_len, time_t t)
546 set_time_in_string(p, max_len, "LCT", t);
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)
558 for (i = 0; i < 16; i++)
560 slprintf(&p[i*2], 33, "%02X", pwd[i]);
565 if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ))
567 safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
571 safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
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)
582 if (strnequal(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32))
584 if (acct_ctrl != NULL)
586 *acct_ctrl |= ACB_PWNOTREQ;
591 else if (strnequal(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32))
598 return strhex_to_str(pwd, 32, p) == 16;
603 /*************************************************************
604 initialise password databases, domain names, domain sid.
605 **************************************************************/
606 BOOL pwdb_initialise(BOOL is_server)
608 get_sam_domain_name();
610 if (!init_myworkgroup())
615 generate_wellknown_sids();
619 if (!generate_sam_sid(global_sam_name))
621 DEBUG(0,("ERROR: Samba cannot create a SAM SID for its domain (%s).\n",
629 if (lp_server_role() == ROLE_DOMAIN_PDC)
631 srvs = global_myname;
635 srvs = lp_passwordserver();
637 if (!get_domain_sids(&global_member_sid, &global_sam_sid, srvs))
643 return initialise_password_db();
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)
653 for( ; table->rid ; table++)
655 if(table->rid == rid)
663 char *lookup_wk_alias_rid(uint32 rid)
665 return lookup_wk_rid(rid, builtin_alias_rids);
668 char *lookup_wk_user_rid(uint32 rid)
670 return lookup_wk_rid(rid, domain_user_rids);
673 char *lookup_wk_group_rid(uint32 rid)
675 return lookup_wk_rid(rid, domain_group_rids);