2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Jeremy Allison 1996-2001
5 Copyright (C) Luke Kenneth Casson Leighton 1996-1998
6 Copyright (C) Gerald (Jerry) Carter 2000-2006
7 Copyright (C) Andrew Bartlett 2001-2002
8 Copyright (C) Simo Sorce 2003
9 Copyright (C) Volker Lendecke 2006
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 3 of the License, or
14 (at your option) any later version.
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.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "../libcli/auth/libcli_auth.h"
29 #define DBGC_CLASS DBGC_PASSDB
31 /******************************************************************
32 Get the default domain/netbios name to be used when
33 testing authentication.
35 LEGACY: this function provides the legacy domain mapping used with
36 the lp_map_untrusted_to_domain() parameter
37 ******************************************************************/
39 const char *my_sam_name(void)
41 /* Standalone servers can only use the local netbios name */
42 if ( lp_server_role() == ROLE_STANDALONE )
43 return global_myname();
45 /* Default to the DOMAIN name when not specified */
46 return lp_workgroup();
49 /**********************************************************************
50 ***********************************************************************/
52 static int samu_destroy(struct samu *user)
54 data_blob_clear_free( &user->lm_pw );
55 data_blob_clear_free( &user->nt_pw );
57 if ( user->plaintext_pw )
58 memset( user->plaintext_pw, 0x0, strlen(user->plaintext_pw) );
63 /**********************************************************************
64 generate a new struct samuser
65 ***********************************************************************/
67 struct samu *samu_new( TALLOC_CTX *ctx )
71 if ( !(user = TALLOC_ZERO_P( ctx, struct samu )) ) {
72 DEBUG(0,("samuser_new: Talloc failed!\n"));
76 talloc_set_destructor( user, samu_destroy );
78 /* no initial methods */
82 /* Don't change these timestamp settings without a good reason.
83 They are important for NT member server compatibility. */
85 user->logon_time = (time_t)0;
86 user->pass_last_set_time = (time_t)0;
87 user->pass_can_change_time = (time_t)0;
88 user->logoff_time = get_time_t_max();
89 user->kickoff_time = get_time_t_max();
90 user->pass_must_change_time = get_time_t_max();
91 user->fields_present = 0x00ffffff;
92 user->logon_divs = 168; /* hours per week */
93 user->hours_len = 21; /* 21 times 8 bits = 168 */
94 memset(user->hours, 0xff, user->hours_len); /* available at all hours */
95 user->bad_password_count = 0;
96 user->logon_count = 0;
97 user->unknown_6 = 0x000004ec; /* don't know */
99 /* Some parts of samba strlen their pdb_get...() returns,
100 so this keeps the interface unchanged for now. */
104 user->nt_username = "";
105 user->full_name = "";
107 user->logon_script = "";
108 user->profile_path = "";
109 user->acct_desc = "";
110 user->workstations = "";
112 user->munged_dial = "";
114 user->plaintext_pw = NULL;
116 /* Unless we know otherwise have a Account Control Bit
117 value of 'normal user'. This helps User Manager, which
118 asks for a filtered list of users. */
120 user->acct_ctrl = ACB_NORMAL;
125 /*********************************************************************
126 Initialize a struct samu from a struct passwd including the user
127 and group SIDs. The *user structure is filled out with the Unix
128 attributes and a user SID.
129 *********************************************************************/
131 static NTSTATUS samu_set_unix_internal(struct samu *user, const struct passwd *pwd, bool create)
133 const char *guest_account = lp_guestaccount();
134 const char *domain = global_myname();
138 return NT_STATUS_NO_SUCH_USER;
141 /* Basic properties based upon the Unix account information */
143 pdb_set_username(user, pwd->pw_name, PDB_SET);
144 pdb_set_fullname(user, pwd->pw_gecos, PDB_SET);
145 pdb_set_domain (user, get_global_sam_name(), PDB_DEFAULT);
147 /* This can lead to a primary group of S-1-22-2-XX which
148 will be rejected by other parts of the Samba code.
149 Rely on pdb_get_group_sid() to "Do The Right Thing" (TM)
152 gid_to_sid(&group_sid, pwd->pw_gid);
153 pdb_set_group_sid(user, &group_sid, PDB_SET);
156 /* save the password structure for later use */
158 user->unix_pw = tcopy_passwd( user, pwd );
160 /* Special case for the guest account which must have a RID of 501 */
162 if ( strequal( pwd->pw_name, guest_account ) ) {
163 if ( !pdb_set_user_sid_from_rid(user, DOMAIN_USER_RID_GUEST, PDB_DEFAULT)) {
164 return NT_STATUS_NO_SUCH_USER;
169 /* Non-guest accounts...Check for a workstation or user account */
171 if (pwd->pw_name[strlen(pwd->pw_name)-1] == '$') {
174 if (!pdb_set_acct_ctrl(user, ACB_WSTRUST, PDB_DEFAULT)) {
175 DEBUG(1, ("Failed to set 'workstation account' flags for user %s.\n",
177 return NT_STATUS_INVALID_COMPUTER_NAME;
183 if (!pdb_set_acct_ctrl(user, ACB_NORMAL, PDB_DEFAULT)) {
184 DEBUG(1, ("Failed to set 'normal account' flags for user %s.\n",
186 return NT_STATUS_INVALID_ACCOUNT_NAME;
189 /* set some basic attributes */
191 pdb_set_profile_path(user, talloc_sub_specified(user,
192 lp_logon_path(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
194 pdb_set_homedir(user, talloc_sub_specified(user,
195 lp_logon_home(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
197 pdb_set_dir_drive(user, talloc_sub_specified(user,
198 lp_logon_drive(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
200 pdb_set_logon_script(user, talloc_sub_specified(user,
201 lp_logon_script(), pwd->pw_name, domain, pwd->pw_uid, pwd->pw_gid),
205 /* Now deal with the user SID. If we have a backend that can generate
206 RIDs, then do so. But sometimes the caller just wanted a structure
207 initialized and will fill in these fields later (such as from a
208 netr_SamInfo3 structure) */
210 if ( create && (pdb_capabilities() & PDB_CAP_STORE_RIDS)) {
214 if ( !pdb_new_rid( &user_rid ) ) {
215 DEBUG(3, ("Could not allocate a new RID\n"));
216 return NT_STATUS_ACCESS_DENIED;
219 sid_compose(&user_sid, get_global_sam_sid(), user_rid);
221 if ( !pdb_set_user_sid(user, &user_sid, PDB_SET) ) {
222 DEBUG(3, ("pdb_set_user_sid failed\n"));
223 return NT_STATUS_INTERNAL_ERROR;
229 /* generate a SID for the user with the RID algorithm */
231 urid = algorithmic_pdb_uid_to_user_rid( user->unix_pw->pw_uid );
233 if ( !pdb_set_user_sid_from_rid( user, urid, PDB_SET) ) {
234 return NT_STATUS_INTERNAL_ERROR;
240 /********************************************************************
241 Set the Unix user attributes
242 ********************************************************************/
244 NTSTATUS samu_set_unix(struct samu *user, const struct passwd *pwd)
246 return samu_set_unix_internal( user, pwd, False );
249 NTSTATUS samu_alloc_rid_unix(struct samu *user, const struct passwd *pwd)
251 return samu_set_unix_internal( user, pwd, True );
254 /**********************************************************
255 Encode the account control bits into a string.
256 length = length of string to encode into (including terminating
257 null). length *MUST BE MORE THAN 2* !
258 **********************************************************/
260 char *pdb_encode_acct_ctrl(uint32_t acct_ctrl, size_t length)
267 SMB_ASSERT(length <= sizeof(acct_str));
271 if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
272 if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
273 if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
274 if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
275 if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
276 if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
277 if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
278 if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
279 if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
280 if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
281 if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
283 for ( ; i < length - 2 ; i++ )
288 acct_str[i++] = '\0';
290 result = talloc_strdup(talloc_tos(), acct_str);
291 SMB_ASSERT(result != NULL);
295 /**********************************************************
296 Decode the account control bits from a string.
297 **********************************************************/
299 uint32_t pdb_decode_acct_ctrl(const char *p)
301 uint32_t acct_ctrl = 0;
302 bool finished = false;
305 * Check if the account type bits have been encoded after the
306 * NT password (in the form [NDHTUWSLXI]).
312 for (p++; *p && !finished; p++) {
314 case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
315 case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
316 case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
317 case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
318 case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
319 case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
320 case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
321 case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
322 case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
323 case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
324 case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
330 default: { finished = true; }
337 /*************************************************************
338 Routine to set 32 hex password characters from a 16 byte array.
339 **************************************************************/
341 void pdb_sethexpwd(char p[33], const unsigned char *pwd, uint32 acct_ctrl)
345 for (i = 0; i < 16; i++)
346 slprintf(&p[i*2], 3, "%02X", pwd[i]);
348 if (acct_ctrl & ACB_PWNOTREQ)
349 safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 32);
351 safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32);
355 /*************************************************************
356 Routine to get the 32 hex characters and turn them
357 into a 16 byte array.
358 **************************************************************/
360 bool pdb_gethexpwd(const char *p, unsigned char *pwd)
363 unsigned char lonybble, hinybble;
364 const char *hexchars = "0123456789ABCDEF";
370 for (i = 0; i < 32; i += 2) {
371 hinybble = toupper_ascii(p[i]);
372 lonybble = toupper_ascii(p[i + 1]);
374 p1 = strchr(hexchars, hinybble);
375 p2 = strchr(hexchars, lonybble);
380 hinybble = PTR_DIFF(p1, hexchars);
381 lonybble = PTR_DIFF(p2, hexchars);
383 pwd[i / 2] = (hinybble << 4) | lonybble;
388 /*************************************************************
389 Routine to set 42 hex hours characters from a 21 byte array.
390 **************************************************************/
392 void pdb_sethexhours(char *p, const unsigned char *hours)
396 for (i = 0; i < 21; i++) {
397 slprintf(&p[i*2], 3, "%02X", hours[i]);
400 safe_strcpy(p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 43);
404 /*************************************************************
405 Routine to get the 42 hex characters and turn them
406 into a 21 byte array.
407 **************************************************************/
409 bool pdb_gethexhours(const char *p, unsigned char *hours)
412 unsigned char lonybble, hinybble;
413 const char *hexchars = "0123456789ABCDEF";
420 for (i = 0; i < 42; i += 2) {
421 hinybble = toupper_ascii(p[i]);
422 lonybble = toupper_ascii(p[i + 1]);
424 p1 = strchr(hexchars, hinybble);
425 p2 = strchr(hexchars, lonybble);
431 hinybble = PTR_DIFF(p1, hexchars);
432 lonybble = PTR_DIFF(p2, hexchars);
434 hours[i / 2] = (hinybble << 4) | lonybble;
439 /********************************************************************
440 ********************************************************************/
442 int algorithmic_rid_base(void)
446 rid_offset = lp_algorithmic_rid_base();
448 if (rid_offset < BASE_RID) {
449 /* Try to prevent admin foot-shooting, we can't put algorithmic
450 rids below 1000, that's the 'well known RIDs' on NT */
451 DEBUG(0, ("'algorithmic rid base' must be equal to or above %ld\n", BASE_RID));
452 rid_offset = BASE_RID;
454 if (rid_offset & 1) {
455 DEBUG(0, ("algorithmic rid base must be even\n"));
461 /*******************************************************************
462 Converts NT user RID to a UNIX uid.
463 ********************************************************************/
465 uid_t algorithmic_pdb_user_rid_to_uid(uint32 user_rid)
467 int rid_offset = algorithmic_rid_base();
468 return (uid_t)(((user_rid & (~USER_RID_TYPE)) - rid_offset)/RID_MULTIPLIER);
471 uid_t max_algorithmic_uid(void)
473 return algorithmic_pdb_user_rid_to_uid(0xfffffffe);
476 /*******************************************************************
477 converts UNIX uid to an NT User RID.
478 ********************************************************************/
480 uint32 algorithmic_pdb_uid_to_user_rid(uid_t uid)
482 int rid_offset = algorithmic_rid_base();
483 return (((((uint32)uid)*RID_MULTIPLIER) + rid_offset) | USER_RID_TYPE);
486 /*******************************************************************
487 Converts NT group RID to a UNIX gid.
488 ********************************************************************/
490 gid_t pdb_group_rid_to_gid(uint32 group_rid)
492 int rid_offset = algorithmic_rid_base();
493 return (gid_t)(((group_rid & (~GROUP_RID_TYPE))- rid_offset)/RID_MULTIPLIER);
496 gid_t max_algorithmic_gid(void)
498 return pdb_group_rid_to_gid(0xffffffff);
501 /*******************************************************************
502 converts NT Group RID to a UNIX uid.
504 warning: you must not call that function only
505 you must do a call to the group mapping first.
506 there is not anymore a direct link between the gid and the rid.
507 ********************************************************************/
509 uint32 algorithmic_pdb_gid_to_group_rid(gid_t gid)
511 int rid_offset = algorithmic_rid_base();
512 return (((((uint32)gid)*RID_MULTIPLIER) + rid_offset) | GROUP_RID_TYPE);
515 /*******************************************************************
516 Decides if a RID is a well known RID.
517 ********************************************************************/
519 static bool rid_is_well_known(uint32 rid)
521 /* Not using rid_offset here, because this is the actual
522 NT fixed value (1000) */
524 return (rid < BASE_RID);
527 /*******************************************************************
528 Decides if a RID is a user or group RID.
529 ********************************************************************/
531 bool algorithmic_pdb_rid_is_user(uint32 rid)
533 if ( rid_is_well_known(rid) ) {
535 * The only well known user RIDs are DOMAIN_USER_RID_ADMIN
536 * and DOMAIN_USER_RID_GUEST.
538 if(rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST)
540 } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) {
546 /*******************************************************************
547 Convert a name into a SID. Used in the lookup name rpc.
548 ********************************************************************/
550 bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
551 enum lsa_SidType *type)
556 /* Windows treats "MACHINE\None" as a special name for
557 rid 513 on non-DCs. You cannot create a user or group
558 name "None" on Windows. You will get an error that
559 the group already exists. */
561 if ( strequal( name, "None" ) ) {
562 *rid = DOMAIN_GROUP_RID_USERS;
563 *type = SID_NAME_DOM_GRP;
568 /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work
569 * correctly in the case where foo also exists as a user. If the flag
570 * is set, don't look for users at all. */
572 if ((flags & LOOKUP_NAME_GROUP) == 0) {
573 struct samu *sam_account = NULL;
576 if ( !(sam_account = samu_new( NULL )) ) {
581 ret = pdb_getsampwnam(sam_account, name);
585 sid_copy(&user_sid, pdb_get_user_sid(sam_account));
588 TALLOC_FREE(sam_account);
591 if (!sid_check_is_in_our_domain(&user_sid)) {
592 DEBUG(0, ("User %s with invalid SID %s in passdb\n",
593 name, sid_string_dbg(&user_sid)));
597 sid_peek_rid(&user_sid, rid);
598 *type = SID_NAME_USER;
604 * Maybe it is a group ?
608 ret = pdb_getgrnam(&map, name);
615 /* BUILTIN groups are looked up elsewhere */
616 if (!sid_check_is_in_our_domain(&map.sid)) {
617 DEBUG(10, ("Found group %s (%s) not in our domain -- "
618 "ignoring.", name, sid_string_dbg(&map.sid)));
622 /* yes it's a mapped group */
623 sid_peek_rid(&map.sid, rid);
624 *type = map.sid_name_use;
628 /*************************************************************
629 Change a password entry in the local passdb backend.
632 - always called as root
633 - ignores the account type except when adding a new account
634 - will create/delete the unix account if the relative
635 add/delete user script is configured
637 *************************************************************/
639 NTSTATUS local_password_change(const char *user_name,
641 const char *new_passwd,
646 struct samu *sam_pass;
656 tosctx = talloc_tos();
658 sam_pass = samu_new(tosctx);
660 result = NT_STATUS_NO_MEMORY;
664 /* Get the smb passwd entry for this user */
665 user_exists = pdb_getsampwnam(sam_pass, user_name);
667 /* Check delete first, we don't need to do anything else if we
668 * are going to delete the acocunt */
669 if (user_exists && (local_flags & LOCAL_DELETE_USER)) {
671 result = pdb_delete_user(tosctx, sam_pass);
672 if (!NT_STATUS_IS_OK(result)) {
673 ret = asprintf(pp_err_str,
674 "Failed to delete entry for user %s.\n",
679 result = NT_STATUS_UNSUCCESSFUL;
681 ret = asprintf(pp_msg_str,
682 "Deleted user %s.\n",
691 if (user_exists && (local_flags & LOCAL_ADD_USER)) {
692 /* the entry already existed */
693 local_flags &= ~LOCAL_ADD_USER;
696 if (!user_exists && !(local_flags & LOCAL_ADD_USER)) {
697 ret = asprintf(pp_err_str,
698 "Failed to find entry for user %s.\n",
703 result = NT_STATUS_NO_SUCH_USER;
707 /* First thing add the new user if we are required to do so */
708 if (local_flags & LOCAL_ADD_USER) {
710 if (local_flags & LOCAL_TRUST_ACCOUNT) {
712 } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
718 result = pdb_create_user(tosctx, user_name, acb, &rid);
719 if (!NT_STATUS_IS_OK(result)) {
720 ret = asprintf(pp_err_str,
721 "Failed to add entry for user %s.\n",
726 result = NT_STATUS_UNSUCCESSFUL;
730 sam_pass = samu_new(tosctx);
732 result = NT_STATUS_NO_MEMORY;
736 /* Now get back the smb passwd entry for this new user */
737 user_exists = pdb_getsampwnam(sam_pass, user_name);
739 ret = asprintf(pp_err_str,
740 "Failed to add entry for user %s.\n",
745 result = NT_STATUS_UNSUCCESSFUL;
750 acb = pdb_get_acct_ctrl(sam_pass);
753 * We are root - just write the new password
754 * and the valid last change time.
756 if ((local_flags & LOCAL_SET_NO_PASSWORD) && !(acb & ACB_PWNOTREQ)) {
758 if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
759 ret = asprintf(pp_err_str,
760 "Failed to set 'no password required' "
761 "flag for user %s.\n", user_name);
765 result = NT_STATUS_UNSUCCESSFUL;
770 if (local_flags & LOCAL_SET_PASSWORD) {
772 * If we're dealing with setting a completely empty user account
773 * ie. One with a password of 'XXXX', but not set disabled (like
774 * an account created from scratch) then if the old password was
775 * 'XX's then getsmbpwent will have set the ACB_DISABLED flag.
776 * We remove that as we're giving this user their first password
777 * and the decision hasn't really been made to disable them (ie.
778 * don't create them disabled). JRA.
780 if ((pdb_get_lanman_passwd(sam_pass) == NULL) &&
781 (acb & ACB_DISABLED)) {
782 acb &= (~ACB_DISABLED);
783 if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
784 ret = asprintf(pp_err_str,
785 "Failed to unset 'disabled' "
786 "flag for user %s.\n",
791 result = NT_STATUS_UNSUCCESSFUL;
796 acb &= (~ACB_PWNOTREQ);
797 if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
798 ret = asprintf(pp_err_str,
799 "Failed to unset 'no password required'"
800 " flag for user %s.\n", user_name);
804 result = NT_STATUS_UNSUCCESSFUL;
808 if (!pdb_set_plaintext_passwd(sam_pass, new_passwd)) {
809 ret = asprintf(pp_err_str,
810 "Failed to set password for "
811 "user %s.\n", user_name);
815 result = NT_STATUS_UNSUCCESSFUL;
820 if ((local_flags & LOCAL_DISABLE_USER) && !(acb & ACB_DISABLED)) {
822 if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
823 ret = asprintf(pp_err_str,
824 "Failed to set 'disabled' flag for "
825 "user %s.\n", user_name);
829 result = NT_STATUS_UNSUCCESSFUL;
834 if ((local_flags & LOCAL_ENABLE_USER) && (acb & ACB_DISABLED)) {
835 acb &= (~ACB_DISABLED);
836 if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
837 ret = asprintf(pp_err_str,
838 "Failed to unset 'disabled' flag for "
839 "user %s.\n", user_name);
843 result = NT_STATUS_UNSUCCESSFUL;
848 /* now commit changes if any */
849 result = pdb_update_sam_account(sam_pass);
850 if (!NT_STATUS_IS_OK(result)) {
851 ret = asprintf(pp_err_str,
852 "Failed to modify entry for user %s.\n",
860 if (local_flags & LOCAL_ADD_USER) {
861 ret = asprintf(pp_msg_str, "Added user %s.\n", user_name);
862 } else if (local_flags & LOCAL_DISABLE_USER) {
863 ret = asprintf(pp_msg_str, "Disabled user %s.\n", user_name);
864 } else if (local_flags & LOCAL_ENABLE_USER) {
865 ret = asprintf(pp_msg_str, "Enabled user %s.\n", user_name);
866 } else if (local_flags & LOCAL_SET_NO_PASSWORD) {
867 ret = asprintf(pp_msg_str,
868 "User %s password set to none.\n", user_name);
875 result = NT_STATUS_OK;
878 TALLOC_FREE(sam_pass);
882 /**********************************************************************
883 Marshall/unmarshall struct samu structs.
884 *********************************************************************/
886 #define SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
887 #define SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
888 #define SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
889 #define SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd"
890 /* nothing changed between V3 and V4 */
892 /*********************************************************************
893 *********************************************************************/
895 static bool init_samu_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
898 /* times are stored as 32bit integer
899 take care on system with 64bit wide time_t
905 pass_can_change_time,
906 pass_must_change_time;
907 char *username = NULL;
909 char *nt_username = NULL;
910 char *dir_drive = NULL;
911 char *unknown_str = NULL;
912 char *munged_dial = NULL;
913 char *fullname = NULL;
914 char *homedir = NULL;
915 char *logon_script = NULL;
916 char *profile_path = NULL;
917 char *acct_desc = NULL;
918 char *workstations = NULL;
919 uint32 username_len, domain_len, nt_username_len,
920 dir_drive_len, unknown_str_len, munged_dial_len,
921 fullname_len, homedir_len, logon_script_len,
922 profile_path_len, acct_desc_len, workstations_len;
924 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
925 uint16 acct_ctrl, logon_divs;
926 uint16 bad_password_count, logon_count;
928 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
930 uint32 lm_pw_len, nt_pw_len, hourslen;
933 if(sampass == NULL || buf == NULL) {
934 DEBUG(0, ("init_samu_from_buffer_v0: NULL parameters found!\n"));
938 /* SAMU_BUFFER_FORMAT_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
940 /* unpack the buffer into variables */
941 len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V0,
943 &logoff_time, /* d */
944 &kickoff_time, /* d */
945 &pass_last_set_time, /* d */
946 &pass_can_change_time, /* d */
947 &pass_must_change_time, /* d */
948 &username_len, &username, /* B */
949 &domain_len, &domain, /* B */
950 &nt_username_len, &nt_username, /* B */
951 &fullname_len, &fullname, /* B */
952 &homedir_len, &homedir, /* B */
953 &dir_drive_len, &dir_drive, /* B */
954 &logon_script_len, &logon_script, /* B */
955 &profile_path_len, &profile_path, /* B */
956 &acct_desc_len, &acct_desc, /* B */
957 &workstations_len, &workstations, /* B */
958 &unknown_str_len, &unknown_str, /* B */
959 &munged_dial_len, &munged_dial, /* B */
962 &lm_pw_len, &lm_pw_ptr, /* B */
963 &nt_pw_len, &nt_pw_ptr, /* B */
965 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
968 &hourslen, &hours, /* B */
969 &bad_password_count, /* w */
970 &logon_count, /* w */
973 if (len == (uint32) -1) {
978 pdb_set_logon_time(sampass, logon_time, PDB_SET);
979 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
980 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
981 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
982 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
983 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
985 pdb_set_username(sampass, username, PDB_SET);
986 pdb_set_domain(sampass, domain, PDB_SET);
987 pdb_set_nt_username(sampass, nt_username, PDB_SET);
988 pdb_set_fullname(sampass, fullname, PDB_SET);
991 pdb_set_homedir(sampass, homedir, PDB_SET);
994 pdb_set_homedir(sampass,
995 talloc_sub_basic(sampass, username, domain,
1001 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
1003 pdb_set_dir_drive(sampass,
1004 talloc_sub_basic(sampass, username, domain,
1010 pdb_set_logon_script(sampass, logon_script, PDB_SET);
1012 pdb_set_logon_script(sampass,
1013 talloc_sub_basic(sampass, username, domain,
1019 pdb_set_profile_path(sampass, profile_path, PDB_SET);
1021 pdb_set_profile_path(sampass,
1022 talloc_sub_basic(sampass, username, domain,
1027 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
1028 pdb_set_workstations(sampass, workstations, PDB_SET);
1029 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
1031 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
1032 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
1038 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
1039 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
1045 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
1046 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1047 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
1048 pdb_set_hours_len(sampass, hours_len, PDB_SET);
1049 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
1050 pdb_set_logon_count(sampass, logon_count, PDB_SET);
1051 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
1052 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
1053 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
1054 pdb_set_hours(sampass, hours, PDB_SET);
1058 SAFE_FREE(username);
1060 SAFE_FREE(nt_username);
1061 SAFE_FREE(fullname);
1063 SAFE_FREE(dir_drive);
1064 SAFE_FREE(logon_script);
1065 SAFE_FREE(profile_path);
1066 SAFE_FREE(acct_desc);
1067 SAFE_FREE(workstations);
1068 SAFE_FREE(munged_dial);
1069 SAFE_FREE(unknown_str);
1070 SAFE_FREE(lm_pw_ptr);
1071 SAFE_FREE(nt_pw_ptr);
1077 /*********************************************************************
1078 *********************************************************************/
1080 static bool init_samu_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
1083 /* times are stored as 32bit integer
1084 take care on system with 64bit wide time_t
1091 pass_can_change_time,
1092 pass_must_change_time;
1093 char *username = NULL;
1094 char *domain = NULL;
1095 char *nt_username = NULL;
1096 char *dir_drive = NULL;
1097 char *unknown_str = NULL;
1098 char *munged_dial = NULL;
1099 char *fullname = NULL;
1100 char *homedir = NULL;
1101 char *logon_script = NULL;
1102 char *profile_path = NULL;
1103 char *acct_desc = NULL;
1104 char *workstations = NULL;
1105 uint32 username_len, domain_len, nt_username_len,
1106 dir_drive_len, unknown_str_len, munged_dial_len,
1107 fullname_len, homedir_len, logon_script_len,
1108 profile_path_len, acct_desc_len, workstations_len;
1110 uint32 user_rid, group_rid, remove_me, hours_len, unknown_6;
1111 uint16 acct_ctrl, logon_divs;
1112 uint16 bad_password_count, logon_count;
1113 uint8 *hours = NULL;
1114 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
1116 uint32 lm_pw_len, nt_pw_len, hourslen;
1119 if(sampass == NULL || buf == NULL) {
1120 DEBUG(0, ("init_samu_from_buffer_v1: NULL parameters found!\n"));
1124 /* SAMU_BUFFER_FORMAT_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
1126 /* unpack the buffer into variables */
1127 len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V1,
1128 &logon_time, /* d */
1129 &logoff_time, /* d */
1130 &kickoff_time, /* d */
1131 /* Change from V0 is addition of bad_password_time field. */
1132 &bad_password_time, /* d */
1133 &pass_last_set_time, /* d */
1134 &pass_can_change_time, /* d */
1135 &pass_must_change_time, /* d */
1136 &username_len, &username, /* B */
1137 &domain_len, &domain, /* B */
1138 &nt_username_len, &nt_username, /* B */
1139 &fullname_len, &fullname, /* B */
1140 &homedir_len, &homedir, /* B */
1141 &dir_drive_len, &dir_drive, /* B */
1142 &logon_script_len, &logon_script, /* B */
1143 &profile_path_len, &profile_path, /* B */
1144 &acct_desc_len, &acct_desc, /* B */
1145 &workstations_len, &workstations, /* B */
1146 &unknown_str_len, &unknown_str, /* B */
1147 &munged_dial_len, &munged_dial, /* B */
1150 &lm_pw_len, &lm_pw_ptr, /* B */
1151 &nt_pw_len, &nt_pw_ptr, /* B */
1154 &logon_divs, /* w */
1156 &hourslen, &hours, /* B */
1157 &bad_password_count, /* w */
1158 &logon_count, /* w */
1159 &unknown_6); /* d */
1161 if (len == (uint32) -1) {
1166 pdb_set_logon_time(sampass, logon_time, PDB_SET);
1167 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
1168 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
1170 /* Change from V0 is addition of bad_password_time field. */
1171 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
1172 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
1173 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
1174 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
1176 pdb_set_username(sampass, username, PDB_SET);
1177 pdb_set_domain(sampass, domain, PDB_SET);
1178 pdb_set_nt_username(sampass, nt_username, PDB_SET);
1179 pdb_set_fullname(sampass, fullname, PDB_SET);
1182 pdb_set_homedir(sampass, homedir, PDB_SET);
1185 pdb_set_homedir(sampass,
1186 talloc_sub_basic(sampass, username, domain,
1192 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
1194 pdb_set_dir_drive(sampass,
1195 talloc_sub_basic(sampass, username, domain,
1201 pdb_set_logon_script(sampass, logon_script, PDB_SET);
1203 pdb_set_logon_script(sampass,
1204 talloc_sub_basic(sampass, username, domain,
1210 pdb_set_profile_path(sampass, profile_path, PDB_SET);
1212 pdb_set_profile_path(sampass,
1213 talloc_sub_basic(sampass, username, domain,
1218 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
1219 pdb_set_workstations(sampass, workstations, PDB_SET);
1220 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
1222 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
1223 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
1229 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
1230 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
1236 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
1238 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1239 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
1240 pdb_set_hours_len(sampass, hours_len, PDB_SET);
1241 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
1242 pdb_set_logon_count(sampass, logon_count, PDB_SET);
1243 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
1244 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
1245 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
1246 pdb_set_hours(sampass, hours, PDB_SET);
1250 SAFE_FREE(username);
1252 SAFE_FREE(nt_username);
1253 SAFE_FREE(fullname);
1255 SAFE_FREE(dir_drive);
1256 SAFE_FREE(logon_script);
1257 SAFE_FREE(profile_path);
1258 SAFE_FREE(acct_desc);
1259 SAFE_FREE(workstations);
1260 SAFE_FREE(munged_dial);
1261 SAFE_FREE(unknown_str);
1262 SAFE_FREE(lm_pw_ptr);
1263 SAFE_FREE(nt_pw_ptr);
1269 static bool init_samu_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen)
1272 /* times are stored as 32bit integer
1273 take care on system with 64bit wide time_t
1280 pass_can_change_time,
1281 pass_must_change_time;
1282 char *username = NULL;
1283 char *domain = NULL;
1284 char *nt_username = NULL;
1285 char *dir_drive = NULL;
1286 char *unknown_str = NULL;
1287 char *munged_dial = NULL;
1288 char *fullname = NULL;
1289 char *homedir = NULL;
1290 char *logon_script = NULL;
1291 char *profile_path = NULL;
1292 char *acct_desc = NULL;
1293 char *workstations = NULL;
1294 uint32 username_len, domain_len, nt_username_len,
1295 dir_drive_len, unknown_str_len, munged_dial_len,
1296 fullname_len, homedir_len, logon_script_len,
1297 profile_path_len, acct_desc_len, workstations_len;
1299 uint32 user_rid, group_rid, hours_len, unknown_6;
1300 uint16 acct_ctrl, logon_divs;
1301 uint16 bad_password_count, logon_count;
1302 uint8 *hours = NULL;
1303 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
1305 uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
1306 uint32 pwHistLen = 0;
1309 bool expand_explicit = lp_passdb_expand_explicit();
1311 if(sampass == NULL || buf == NULL) {
1312 DEBUG(0, ("init_samu_from_buffer_v2: NULL parameters found!\n"));
1316 /* SAMU_BUFFER_FORMAT_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
1318 /* unpack the buffer into variables */
1319 len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V2,
1320 &logon_time, /* d */
1321 &logoff_time, /* d */
1322 &kickoff_time, /* d */
1323 &bad_password_time, /* d */
1324 &pass_last_set_time, /* d */
1325 &pass_can_change_time, /* d */
1326 &pass_must_change_time, /* d */
1327 &username_len, &username, /* B */
1328 &domain_len, &domain, /* B */
1329 &nt_username_len, &nt_username, /* B */
1330 &fullname_len, &fullname, /* B */
1331 &homedir_len, &homedir, /* B */
1332 &dir_drive_len, &dir_drive, /* B */
1333 &logon_script_len, &logon_script, /* B */
1334 &profile_path_len, &profile_path, /* B */
1335 &acct_desc_len, &acct_desc, /* B */
1336 &workstations_len, &workstations, /* B */
1337 &unknown_str_len, &unknown_str, /* B */
1338 &munged_dial_len, &munged_dial, /* B */
1341 &lm_pw_len, &lm_pw_ptr, /* B */
1342 &nt_pw_len, &nt_pw_ptr, /* B */
1343 /* Change from V1 is addition of password history field. */
1344 &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
1346 /* Also "remove_me" field was removed. */
1347 &logon_divs, /* w */
1349 &hourslen, &hours, /* B */
1350 &bad_password_count, /* w */
1351 &logon_count, /* w */
1352 &unknown_6); /* d */
1354 if (len == (uint32) -1) {
1359 pdb_set_logon_time(sampass, logon_time, PDB_SET);
1360 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
1361 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
1362 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
1363 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
1364 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
1365 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
1367 pdb_set_username(sampass, username, PDB_SET);
1368 pdb_set_domain(sampass, domain, PDB_SET);
1369 pdb_set_nt_username(sampass, nt_username, PDB_SET);
1370 pdb_set_fullname(sampass, fullname, PDB_SET);
1373 fstrcpy( tmp_string, homedir );
1374 if (expand_explicit) {
1375 standard_sub_basic( username, domain, tmp_string,
1376 sizeof(tmp_string) );
1378 pdb_set_homedir(sampass, tmp_string, PDB_SET);
1381 pdb_set_homedir(sampass,
1382 talloc_sub_basic(sampass, username, domain,
1388 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
1390 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
1393 fstrcpy( tmp_string, logon_script );
1394 if (expand_explicit) {
1395 standard_sub_basic( username, domain, tmp_string,
1396 sizeof(tmp_string) );
1398 pdb_set_logon_script(sampass, tmp_string, PDB_SET);
1401 pdb_set_logon_script(sampass,
1402 talloc_sub_basic(sampass, username, domain,
1408 fstrcpy( tmp_string, profile_path );
1409 if (expand_explicit) {
1410 standard_sub_basic( username, domain, tmp_string,
1411 sizeof(tmp_string) );
1413 pdb_set_profile_path(sampass, tmp_string, PDB_SET);
1416 pdb_set_profile_path(sampass,
1417 talloc_sub_basic(sampass, username, domain,
1422 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
1423 pdb_set_workstations(sampass, workstations, PDB_SET);
1424 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
1426 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
1427 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
1433 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
1434 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
1440 /* Change from V1 is addition of password history field. */
1441 pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
1443 uint8 *pw_hist = SMB_MALLOC_ARRAY(uint8, pwHistLen * PW_HISTORY_ENTRY_LEN);
1448 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
1449 if (nt_pw_hist_ptr && nt_pw_hist_len) {
1451 SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
1452 nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
1453 for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
1454 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
1455 &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
1456 PW_HISTORY_ENTRY_LEN);
1459 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
1466 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
1469 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1470 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
1471 pdb_set_hours_len(sampass, hours_len, PDB_SET);
1472 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
1473 pdb_set_logon_count(sampass, logon_count, PDB_SET);
1474 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
1475 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
1476 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
1477 pdb_set_hours(sampass, hours, PDB_SET);
1481 SAFE_FREE(username);
1483 SAFE_FREE(nt_username);
1484 SAFE_FREE(fullname);
1486 SAFE_FREE(dir_drive);
1487 SAFE_FREE(logon_script);
1488 SAFE_FREE(profile_path);
1489 SAFE_FREE(acct_desc);
1490 SAFE_FREE(workstations);
1491 SAFE_FREE(munged_dial);
1492 SAFE_FREE(unknown_str);
1493 SAFE_FREE(lm_pw_ptr);
1494 SAFE_FREE(nt_pw_ptr);
1495 SAFE_FREE(nt_pw_hist_ptr);
1501 /*********************************************************************
1502 *********************************************************************/
1504 static bool init_samu_from_buffer_v3(struct samu *sampass, uint8 *buf, uint32 buflen)
1507 /* times are stored as 32bit integer
1508 take care on system with 64bit wide time_t
1515 pass_can_change_time,
1516 pass_must_change_time;
1517 char *username = NULL;
1518 char *domain = NULL;
1519 char *nt_username = NULL;
1520 char *dir_drive = NULL;
1521 char *comment = NULL;
1522 char *munged_dial = NULL;
1523 char *fullname = NULL;
1524 char *homedir = NULL;
1525 char *logon_script = NULL;
1526 char *profile_path = NULL;
1527 char *acct_desc = NULL;
1528 char *workstations = NULL;
1529 uint32 username_len, domain_len, nt_username_len,
1530 dir_drive_len, comment_len, munged_dial_len,
1531 fullname_len, homedir_len, logon_script_len,
1532 profile_path_len, acct_desc_len, workstations_len;
1534 uint32 user_rid, group_rid, hours_len, unknown_6, acct_ctrl;
1536 uint16 bad_password_count, logon_count;
1537 uint8 *hours = NULL;
1538 uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
1540 uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
1541 uint32 pwHistLen = 0;
1544 bool expand_explicit = lp_passdb_expand_explicit();
1546 if(sampass == NULL || buf == NULL) {
1547 DEBUG(0, ("init_samu_from_buffer_v3: NULL parameters found!\n"));
1551 /* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
1553 /* unpack the buffer into variables */
1554 len = tdb_unpack (buf, buflen, SAMU_BUFFER_FORMAT_V3,
1555 &logon_time, /* d */
1556 &logoff_time, /* d */
1557 &kickoff_time, /* d */
1558 &bad_password_time, /* d */
1559 &pass_last_set_time, /* d */
1560 &pass_can_change_time, /* d */
1561 &pass_must_change_time, /* d */
1562 &username_len, &username, /* B */
1563 &domain_len, &domain, /* B */
1564 &nt_username_len, &nt_username, /* B */
1565 &fullname_len, &fullname, /* B */
1566 &homedir_len, &homedir, /* B */
1567 &dir_drive_len, &dir_drive, /* B */
1568 &logon_script_len, &logon_script, /* B */
1569 &profile_path_len, &profile_path, /* B */
1570 &acct_desc_len, &acct_desc, /* B */
1571 &workstations_len, &workstations, /* B */
1572 &comment_len, &comment, /* B */
1573 &munged_dial_len, &munged_dial, /* B */
1576 &lm_pw_len, &lm_pw_ptr, /* B */
1577 &nt_pw_len, &nt_pw_ptr, /* B */
1578 /* Change from V1 is addition of password history field. */
1579 &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */
1580 /* Change from V2 is the uint32 acb_mask */
1582 /* Also "remove_me" field was removed. */
1583 &logon_divs, /* w */
1585 &hourslen, &hours, /* B */
1586 &bad_password_count, /* w */
1587 &logon_count, /* w */
1588 &unknown_6); /* d */
1590 if (len == (uint32) -1) {
1595 pdb_set_logon_time(sampass, convert_uint32_to_time_t(logon_time), PDB_SET);
1596 pdb_set_logoff_time(sampass, convert_uint32_to_time_t(logoff_time), PDB_SET);
1597 pdb_set_kickoff_time(sampass, convert_uint32_to_time_t(kickoff_time), PDB_SET);
1598 pdb_set_bad_password_time(sampass, convert_uint32_to_time_t(bad_password_time), PDB_SET);
1599 pdb_set_pass_can_change_time(sampass, convert_uint32_to_time_t(pass_can_change_time), PDB_SET);
1600 pdb_set_pass_must_change_time(sampass, convert_uint32_to_time_t(pass_must_change_time), PDB_SET);
1601 pdb_set_pass_last_set_time(sampass, convert_uint32_to_time_t(pass_last_set_time), PDB_SET);
1603 pdb_set_username(sampass, username, PDB_SET);
1604 pdb_set_domain(sampass, domain, PDB_SET);
1605 pdb_set_nt_username(sampass, nt_username, PDB_SET);
1606 pdb_set_fullname(sampass, fullname, PDB_SET);
1609 fstrcpy( tmp_string, homedir );
1610 if (expand_explicit) {
1611 standard_sub_basic( username, domain, tmp_string,
1612 sizeof(tmp_string) );
1614 pdb_set_homedir(sampass, tmp_string, PDB_SET);
1617 pdb_set_homedir(sampass,
1618 talloc_sub_basic(sampass, username, domain,
1624 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
1626 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
1629 fstrcpy( tmp_string, logon_script );
1630 if (expand_explicit) {
1631 standard_sub_basic( username, domain, tmp_string,
1632 sizeof(tmp_string) );
1634 pdb_set_logon_script(sampass, tmp_string, PDB_SET);
1637 pdb_set_logon_script(sampass,
1638 talloc_sub_basic(sampass, username, domain,
1644 fstrcpy( tmp_string, profile_path );
1645 if (expand_explicit) {
1646 standard_sub_basic( username, domain, tmp_string,
1647 sizeof(tmp_string) );
1649 pdb_set_profile_path(sampass, tmp_string, PDB_SET);
1652 pdb_set_profile_path(sampass,
1653 talloc_sub_basic(sampass, username, domain, lp_logon_path()),
1657 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
1658 pdb_set_comment(sampass, comment, PDB_SET);
1659 pdb_set_workstations(sampass, workstations, PDB_SET);
1660 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
1662 if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
1663 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
1669 if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
1670 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
1676 pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
1678 uint8 *pw_hist = (uint8 *)SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN);
1683 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
1684 if (nt_pw_hist_ptr && nt_pw_hist_len) {
1686 SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
1687 nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
1688 for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
1689 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
1690 &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
1691 PW_HISTORY_ENTRY_LEN);
1694 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
1701 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
1704 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1705 pdb_set_hours_len(sampass, hours_len, PDB_SET);
1706 pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
1707 pdb_set_logon_count(sampass, logon_count, PDB_SET);
1708 pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
1709 /* Change from V2 is the uint32 acct_ctrl */
1710 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
1711 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
1712 pdb_set_hours(sampass, hours, PDB_SET);
1716 SAFE_FREE(username);
1718 SAFE_FREE(nt_username);
1719 SAFE_FREE(fullname);
1721 SAFE_FREE(dir_drive);
1722 SAFE_FREE(logon_script);
1723 SAFE_FREE(profile_path);
1724 SAFE_FREE(acct_desc);
1725 SAFE_FREE(workstations);
1726 SAFE_FREE(munged_dial);
1728 SAFE_FREE(lm_pw_ptr);
1729 SAFE_FREE(nt_pw_ptr);
1730 SAFE_FREE(nt_pw_hist_ptr);
1736 /*********************************************************************
1737 *********************************************************************/
1739 static uint32 init_buffer_from_samu_v3 (uint8 **buf, struct samu *sampass, bool size_only)
1743 /* times are stored as 32bit integer
1744 take care on system with 64bit wide time_t
1751 pass_can_change_time,
1752 pass_must_change_time;
1754 uint32 user_rid, group_rid;
1756 const char *username;
1758 const char *nt_username;
1759 const char *dir_drive;
1760 const char *comment;
1761 const char *munged_dial;
1762 const char *fullname;
1763 const char *homedir;
1764 const char *logon_script;
1765 const char *profile_path;
1766 const char *acct_desc;
1767 const char *workstations;
1768 uint32 username_len, domain_len, nt_username_len,
1769 dir_drive_len, comment_len, munged_dial_len,
1770 fullname_len, homedir_len, logon_script_len,
1771 profile_path_len, acct_desc_len, workstations_len;
1775 const uint8 *nt_pw_hist;
1776 uint32 lm_pw_len = 16;
1777 uint32 nt_pw_len = 16;
1778 uint32 nt_pw_hist_len;
1779 uint32 pwHistLen = 0;
1784 logon_time = convert_time_t_to_uint32(pdb_get_logon_time(sampass));
1785 logoff_time = convert_time_t_to_uint32(pdb_get_logoff_time(sampass));
1786 kickoff_time = convert_time_t_to_uint32(pdb_get_kickoff_time(sampass));
1787 bad_password_time = convert_time_t_to_uint32(pdb_get_bad_password_time(sampass));
1788 pass_can_change_time = convert_time_t_to_uint32(pdb_get_pass_can_change_time_noncalc(sampass));
1789 pass_must_change_time = convert_time_t_to_uint32(pdb_get_pass_must_change_time(sampass));
1790 pass_last_set_time = convert_time_t_to_uint32(pdb_get_pass_last_set_time(sampass));
1792 user_rid = pdb_get_user_rid(sampass);
1793 group_rid = pdb_get_group_rid(sampass);
1795 username = pdb_get_username(sampass);
1797 username_len = strlen(username) +1;
1802 domain = pdb_get_domain(sampass);
1804 domain_len = strlen(domain) +1;
1809 nt_username = pdb_get_nt_username(sampass);
1811 nt_username_len = strlen(nt_username) +1;
1813 nt_username_len = 0;
1816 fullname = pdb_get_fullname(sampass);
1818 fullname_len = strlen(fullname) +1;
1824 * Only updates fields which have been set (not defaults from smb.conf)
1827 if (!IS_SAM_DEFAULT(sampass, PDB_DRIVE)) {
1828 dir_drive = pdb_get_dir_drive(sampass);
1833 dir_drive_len = strlen(dir_drive) +1;
1838 if (!IS_SAM_DEFAULT(sampass, PDB_SMBHOME)) {
1839 homedir = pdb_get_homedir(sampass);
1844 homedir_len = strlen(homedir) +1;
1849 if (!IS_SAM_DEFAULT(sampass, PDB_LOGONSCRIPT)) {
1850 logon_script = pdb_get_logon_script(sampass);
1852 logon_script = NULL;
1855 logon_script_len = strlen(logon_script) +1;
1857 logon_script_len = 0;
1860 if (!IS_SAM_DEFAULT(sampass, PDB_PROFILE)) {
1861 profile_path = pdb_get_profile_path(sampass);
1863 profile_path = NULL;
1866 profile_path_len = strlen(profile_path) +1;
1868 profile_path_len = 0;
1871 lm_pw = pdb_get_lanman_passwd(sampass);
1876 nt_pw = pdb_get_nt_passwd(sampass);
1881 pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
1882 nt_pw_hist = pdb_get_pw_history(sampass, &nt_pw_hist_len);
1883 if (pwHistLen && nt_pw_hist && nt_pw_hist_len) {
1884 nt_pw_hist_len *= PW_HISTORY_ENTRY_LEN;
1889 acct_desc = pdb_get_acct_desc(sampass);
1891 acct_desc_len = strlen(acct_desc) +1;
1896 workstations = pdb_get_workstations(sampass);
1898 workstations_len = strlen(workstations) +1;
1900 workstations_len = 0;
1903 comment = pdb_get_comment(sampass);
1905 comment_len = strlen(comment) +1;
1910 munged_dial = pdb_get_munged_dial(sampass);
1912 munged_dial_len = strlen(munged_dial) +1;
1914 munged_dial_len = 0;
1917 /* SAMU_BUFFER_FORMAT_V3 "dddddddBBBBBBBBBBBBddBBBdwdBwwd" */
1919 /* one time to get the size needed */
1920 len = tdb_pack(NULL, 0, SAMU_BUFFER_FORMAT_V3,
1922 logoff_time, /* d */
1923 kickoff_time, /* d */
1924 bad_password_time, /* d */
1925 pass_last_set_time, /* d */
1926 pass_can_change_time, /* d */
1927 pass_must_change_time, /* d */
1928 username_len, username, /* B */
1929 domain_len, domain, /* B */
1930 nt_username_len, nt_username, /* B */
1931 fullname_len, fullname, /* B */
1932 homedir_len, homedir, /* B */
1933 dir_drive_len, dir_drive, /* B */
1934 logon_script_len, logon_script, /* B */
1935 profile_path_len, profile_path, /* B */
1936 acct_desc_len, acct_desc, /* B */
1937 workstations_len, workstations, /* B */
1938 comment_len, comment, /* B */
1939 munged_dial_len, munged_dial, /* B */
1942 lm_pw_len, lm_pw, /* B */
1943 nt_pw_len, nt_pw, /* B */
1944 nt_pw_hist_len, nt_pw_hist, /* B */
1945 pdb_get_acct_ctrl(sampass), /* d */
1946 pdb_get_logon_divs(sampass), /* w */
1947 pdb_get_hours_len(sampass), /* d */
1948 MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
1949 pdb_get_bad_password_count(sampass), /* w */
1950 pdb_get_logon_count(sampass), /* w */
1951 pdb_get_unknown_6(sampass)); /* d */
1957 /* malloc the space needed */
1958 if ( (*buf=(uint8*)SMB_MALLOC(len)) == NULL) {
1959 DEBUG(0,("init_buffer_from_samu_v3: Unable to malloc() memory for buffer!\n"));
1963 /* now for the real call to tdb_pack() */
1964 buflen = tdb_pack(*buf, len, SAMU_BUFFER_FORMAT_V3,
1966 logoff_time, /* d */
1967 kickoff_time, /* d */
1968 bad_password_time, /* d */
1969 pass_last_set_time, /* d */
1970 pass_can_change_time, /* d */
1971 pass_must_change_time, /* d */
1972 username_len, username, /* B */
1973 domain_len, domain, /* B */
1974 nt_username_len, nt_username, /* B */
1975 fullname_len, fullname, /* B */
1976 homedir_len, homedir, /* B */
1977 dir_drive_len, dir_drive, /* B */
1978 logon_script_len, logon_script, /* B */
1979 profile_path_len, profile_path, /* B */
1980 acct_desc_len, acct_desc, /* B */
1981 workstations_len, workstations, /* B */
1982 comment_len, comment, /* B */
1983 munged_dial_len, munged_dial, /* B */
1986 lm_pw_len, lm_pw, /* B */
1987 nt_pw_len, nt_pw, /* B */
1988 nt_pw_hist_len, nt_pw_hist, /* B */
1989 pdb_get_acct_ctrl(sampass), /* d */
1990 pdb_get_logon_divs(sampass), /* w */
1991 pdb_get_hours_len(sampass), /* d */
1992 MAX_HOURS_LEN, pdb_get_hours(sampass), /* B */
1993 pdb_get_bad_password_count(sampass), /* w */
1994 pdb_get_logon_count(sampass), /* w */
1995 pdb_get_unknown_6(sampass)); /* d */
1997 /* check to make sure we got it correct */
1998 if (buflen != len) {
1999 DEBUG(0, ("init_buffer_from_samu_v3: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n",
2000 (unsigned long)buflen, (unsigned long)len));
2009 static bool init_samu_from_buffer_v4(struct samu *sampass, uint8 *buf, uint32 buflen)
2011 /* nothing changed between V3 and V4 */
2012 return init_samu_from_buffer_v3(sampass, buf, buflen);
2015 static uint32 init_buffer_from_samu_v4(uint8 **buf, struct samu *sampass, bool size_only)
2017 /* nothing changed between V3 and V4 */
2018 return init_buffer_from_samu_v3(buf, sampass, size_only);
2021 /**********************************************************************
2022 Intialize a struct samu struct from a BYTE buffer of size len
2023 *********************************************************************/
2025 bool init_samu_from_buffer(struct samu *sampass, uint32_t level,
2026 uint8 *buf, uint32 buflen)
2029 case SAMU_BUFFER_V0:
2030 return init_samu_from_buffer_v0(sampass, buf, buflen);
2031 case SAMU_BUFFER_V1:
2032 return init_samu_from_buffer_v1(sampass, buf, buflen);
2033 case SAMU_BUFFER_V2:
2034 return init_samu_from_buffer_v2(sampass, buf, buflen);
2035 case SAMU_BUFFER_V3:
2036 return init_samu_from_buffer_v3(sampass, buf, buflen);
2037 case SAMU_BUFFER_V4:
2038 return init_samu_from_buffer_v4(sampass, buf, buflen);
2044 /**********************************************************************
2045 Intialize a BYTE buffer from a struct samu struct
2046 *********************************************************************/
2048 uint32 init_buffer_from_samu (uint8 **buf, struct samu *sampass, bool size_only)
2050 return init_buffer_from_samu_v4(buf, sampass, size_only);
2053 /*********************************************************************
2054 *********************************************************************/
2056 bool pdb_copy_sam_account(struct samu *dst, struct samu *src )
2061 len = init_buffer_from_samu(&buf, src, False);
2062 if (len == -1 || !buf) {
2067 if (!init_samu_from_buffer( dst, SAMU_BUFFER_LATEST, buf, len )) {
2072 dst->methods = src->methods;
2074 if ( src->unix_pw ) {
2075 dst->unix_pw = tcopy_passwd( dst, src->unix_pw );
2076 if (!dst->unix_pw) {
2086 /*********************************************************************
2087 Update the bad password count checking the PDB_POLICY_RESET_COUNT_TIME
2088 *********************************************************************/
2090 bool pdb_update_bad_password_count(struct samu *sampass, bool *updated)
2092 time_t LastBadPassword;
2093 uint16 BadPasswordCount;
2097 BadPasswordCount = pdb_get_bad_password_count(sampass);
2098 if (!BadPasswordCount) {
2099 DEBUG(9, ("No bad password attempts.\n"));
2104 res = pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &resettime);
2108 DEBUG(0, ("pdb_update_bad_password_count: pdb_get_account_policy failed.\n"));
2112 /* First, check if there is a reset time to compare */
2113 if ((resettime == (uint32) -1) || (resettime == 0)) {
2114 DEBUG(9, ("No reset time, can't reset bad pw count\n"));
2118 LastBadPassword = pdb_get_bad_password_time(sampass);
2119 DEBUG(7, ("LastBadPassword=%d, resettime=%d, current time=%d.\n",
2120 (uint32) LastBadPassword, resettime, (uint32)time(NULL)));
2121 if (time(NULL) > (LastBadPassword + convert_uint32_to_time_t(resettime)*60)){
2122 pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
2123 pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
2132 /*********************************************************************
2133 Update the ACB_AUTOLOCK flag checking the PDB_POLICY_LOCK_ACCOUNT_DURATION
2134 *********************************************************************/
2136 bool pdb_update_autolock_flag(struct samu *sampass, bool *updated)
2139 time_t LastBadPassword;
2142 if (!(pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK)) {
2143 DEBUG(9, ("pdb_update_autolock_flag: Account %s not autolocked, no check needed\n",
2144 pdb_get_username(sampass)));
2149 res = pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &duration);
2153 DEBUG(0, ("pdb_update_autolock_flag: pdb_get_account_policy failed.\n"));
2157 /* First, check if there is a duration to compare */
2158 if ((duration == (uint32) -1) || (duration == 0)) {
2159 DEBUG(9, ("pdb_update_autolock_flag: No reset duration, can't reset autolock\n"));
2163 LastBadPassword = pdb_get_bad_password_time(sampass);
2164 DEBUG(7, ("pdb_update_autolock_flag: Account %s, LastBadPassword=%d, duration=%d, current time =%d.\n",
2165 pdb_get_username(sampass), (uint32)LastBadPassword, duration*60, (uint32)time(NULL)));
2167 if (LastBadPassword == (time_t)0) {
2168 DEBUG(1,("pdb_update_autolock_flag: Account %s "
2169 "administratively locked out with no bad password "
2170 "time. Leaving locked out.\n",
2171 pdb_get_username(sampass) ));
2175 if ((time(NULL) > (LastBadPassword + convert_uint32_to_time_t(duration) * 60))) {
2176 pdb_set_acct_ctrl(sampass,
2177 pdb_get_acct_ctrl(sampass) & ~ACB_AUTOLOCK,
2179 pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
2180 pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
2189 /*********************************************************************
2190 Increment the bad_password_count
2191 *********************************************************************/
2193 bool pdb_increment_bad_password_count(struct samu *sampass)
2195 uint32 account_policy_lockout;
2196 bool autolock_updated = False, badpw_updated = False;
2199 /* Retrieve the account lockout policy */
2201 ret = pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout);
2204 DEBUG(0, ("pdb_increment_bad_password_count: pdb_get_account_policy failed.\n"));
2208 /* If there is no policy, we don't need to continue checking */
2209 if (!account_policy_lockout) {
2210 DEBUG(9, ("No lockout policy, don't track bad passwords\n"));
2214 /* Check if the autolock needs to be cleared */
2215 if (!pdb_update_autolock_flag(sampass, &autolock_updated))
2218 /* Check if the badpw count needs to be reset */
2219 if (!pdb_update_bad_password_count(sampass, &badpw_updated))
2223 Ok, now we can assume that any resetting that needs to be
2224 done has been done, and just get on with incrementing
2225 and autolocking if necessary
2228 pdb_set_bad_password_count(sampass,
2229 pdb_get_bad_password_count(sampass)+1,
2231 pdb_set_bad_password_time(sampass, time(NULL), PDB_CHANGED);
2234 if (pdb_get_bad_password_count(sampass) < account_policy_lockout)
2237 if (!pdb_set_acct_ctrl(sampass,
2238 pdb_get_acct_ctrl(sampass) | ACB_AUTOLOCK,
2240 DEBUG(1, ("pdb_increment_bad_password_count:failed to set 'autolock' flag. \n"));
2247 bool is_dc_trusted_domain_situation(const char *domain_name)
2249 return IS_DC && !strequal(domain_name, lp_workgroup());
2252 /*******************************************************************
2253 Wrapper around retrieving the clear text trust account password.
2254 appropriate account name is stored in account_name.
2255 Caller must free password, but not account_name.
2256 *******************************************************************/
2258 bool get_trust_pw_clear(const char *domain, char **ret_pwd,
2259 const char **account_name,
2260 enum netr_SchannelType *channel)
2263 time_t last_set_time;
2265 /* if we are a DC and this is not our domain, then lookup an account
2266 * for the domain trust */
2268 if (is_dc_trusted_domain_situation(domain)) {
2269 if (!lp_allow_trusted_domains()) {
2273 if (!pdb_get_trusteddom_pw(domain, ret_pwd, NULL,
2276 DEBUG(0, ("get_trust_pw: could not fetch trust "
2277 "account password for trusted domain %s\n",
2282 if (channel != NULL) {
2283 *channel = SEC_CHAN_DOMAIN;
2286 if (account_name != NULL) {
2287 *account_name = lp_workgroup();
2294 * Since we can only be member of one single domain, we are now
2295 * in a member situation:
2297 * - Either we are a DC (selfjoined) and the domain is our
2299 * - Or we are on a member and the domain is our own or some
2300 * other (potentially trusted) domain.
2302 * In both cases, we can only get the machine account password
2303 * for our own domain to connect to our own dc. (For a member,
2304 * request to trusted domains are performed through our dc.)
2306 * So we simply use our own domain name to retrieve the
2307 * machine account passowrd and ignore the request domain here.
2310 pwd = secrets_fetch_machine_password(lp_workgroup(), &last_set_time, channel);
2314 if (account_name != NULL) {
2315 *account_name = global_myname();
2321 DEBUG(5, ("get_trust_pw_clear: could not fetch clear text trust "
2322 "account password for domain %s\n", domain));
2326 /*******************************************************************
2327 Wrapper around retrieving the trust account password.
2328 appropriate account name is stored in account_name.
2329 *******************************************************************/
2331 bool get_trust_pw_hash(const char *domain, uint8 ret_pwd[16],
2332 const char **account_name,
2333 enum netr_SchannelType *channel)
2336 time_t last_set_time;
2338 if (get_trust_pw_clear(domain, &pwd, account_name, channel)) {
2339 E_md4hash(pwd, ret_pwd);
2342 } else if (is_dc_trusted_domain_situation(domain)) {
2346 /* as a fallback, try to get the hashed pwd directly from the tdb... */
2348 if (secrets_fetch_trust_account_password_legacy(domain, ret_pwd,
2352 if (account_name != NULL) {
2353 *account_name = global_myname();
2359 DEBUG(5, ("get_trust_pw_hash: could not fetch trust account "
2360 "password for domain %s\n", domain));
2364 struct samr_LogonHours get_logon_hours_from_pdb(TALLOC_CTX *mem_ctx,
2367 struct samr_LogonHours hours;
2368 const int units_per_week = 168;
2371 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
2376 hours.units_per_week = units_per_week;
2377 memset(hours.bits, 0xFF, units_per_week);
2379 if (pdb_get_hours(pw)) {
2380 memcpy(hours.bits, pdb_get_hours(pw),
2381 MIN(pdb_get_hours_len(pw), units_per_week));