2 Unix SMB/CIFS implementation.
3 SAMR Pipe utility functions.
5 Copyright (C) Luke Kenneth Casson Leighton 1996-1998
6 Copyright (C) Gerald (Jerry) Carter 2000-2001
7 Copyright (C) Andrew Bartlett 2001-2002
8 Copyright (C) Stefan (metze) Metzmacher 2002
9 Copyright (C) Guenther Deschner 2008
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 "rpc_server/srv_samr_util.h"
29 #define DBGC_CLASS DBGC_RPC_SRV
31 #define STRING_CHANGED (old_string && !new_string) ||\
32 (!old_string && new_string) ||\
33 (old_string && new_string && (strcmp(old_string, new_string) != 0))
35 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
37 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
39 /*************************************************************
40 Copies a struct samr_UserInfo2 to a struct samu
41 **************************************************************/
43 void copy_id2_to_sam_passwd(struct samu
*to
,
44 struct samr_UserInfo2
*from
)
46 struct samr_UserInfo21 i
;
48 if (from
== NULL
|| to
== NULL
) {
54 i
.fields_present
= SAMR_FIELD_COMMENT
|
55 SAMR_FIELD_COUNTRY_CODE
|
57 i
.comment
= from
->comment
;
58 i
.country_code
= from
->country_code
;
59 i
.code_page
= from
->code_page
;
61 copy_id21_to_sam_passwd("INFO_2", to
, &i
);
64 /*************************************************************
65 Copies a struct samr_UserInfo4 to a struct samu
66 **************************************************************/
68 void copy_id4_to_sam_passwd(struct samu
*to
,
69 struct samr_UserInfo4
*from
)
71 struct samr_UserInfo21 i
;
73 if (from
== NULL
|| to
== NULL
) {
79 i
.fields_present
= SAMR_FIELD_LOGON_HOURS
;
80 i
.logon_hours
= from
->logon_hours
;
82 copy_id21_to_sam_passwd("INFO_4", to
, &i
);
85 /*************************************************************
86 Copies a struct samr_UserInfo6 to a struct samu
87 **************************************************************/
89 void copy_id6_to_sam_passwd(struct samu
*to
,
90 struct samr_UserInfo6
*from
)
92 struct samr_UserInfo21 i
;
94 if (from
== NULL
|| to
== NULL
) {
100 i
.fields_present
= SAMR_FIELD_ACCOUNT_NAME
|
101 SAMR_FIELD_FULL_NAME
;
102 i
.account_name
= from
->account_name
;
103 i
.full_name
= from
->full_name
;
105 copy_id21_to_sam_passwd("INFO_6", to
, &i
);
108 /*************************************************************
109 Copies a struct samr_UserInfo8 to a struct samu
110 **************************************************************/
112 void copy_id8_to_sam_passwd(struct samu
*to
,
113 struct samr_UserInfo8
*from
)
115 struct samr_UserInfo21 i
;
117 if (from
== NULL
|| to
== NULL
) {
123 i
.fields_present
= SAMR_FIELD_FULL_NAME
;
124 i
.full_name
= from
->full_name
;
126 copy_id21_to_sam_passwd("INFO_8", to
, &i
);
129 /*************************************************************
130 Copies a struct samr_UserInfo10 to a struct samu
131 **************************************************************/
133 void copy_id10_to_sam_passwd(struct samu
*to
,
134 struct samr_UserInfo10
*from
)
136 struct samr_UserInfo21 i
;
138 if (from
== NULL
|| to
== NULL
) {
144 i
.fields_present
= SAMR_FIELD_HOME_DIRECTORY
|
145 SAMR_FIELD_HOME_DRIVE
;
146 i
.home_directory
= from
->home_directory
;
147 i
.home_drive
= from
->home_drive
;
149 copy_id21_to_sam_passwd("INFO_10", to
, &i
);
152 /*************************************************************
153 Copies a struct samr_UserInfo11 to a struct samu
154 **************************************************************/
156 void copy_id11_to_sam_passwd(struct samu
*to
,
157 struct samr_UserInfo11
*from
)
159 struct samr_UserInfo21 i
;
161 if (from
== NULL
|| to
== NULL
) {
167 i
.fields_present
= SAMR_FIELD_LOGON_SCRIPT
;
168 i
.logon_script
= from
->logon_script
;
170 copy_id21_to_sam_passwd("INFO_11", to
, &i
);
173 /*************************************************************
174 Copies a struct samr_UserInfo12 to a struct samu
175 **************************************************************/
177 void copy_id12_to_sam_passwd(struct samu
*to
,
178 struct samr_UserInfo12
*from
)
180 struct samr_UserInfo21 i
;
182 if (from
== NULL
|| to
== NULL
) {
188 i
.fields_present
= SAMR_FIELD_PROFILE_PATH
;
189 i
.profile_path
= from
->profile_path
;
191 copy_id21_to_sam_passwd("INFO_12", to
, &i
);
194 /*************************************************************
195 Copies a struct samr_UserInfo13 to a struct samu
196 **************************************************************/
198 void copy_id13_to_sam_passwd(struct samu
*to
,
199 struct samr_UserInfo13
*from
)
201 struct samr_UserInfo21 i
;
203 if (from
== NULL
|| to
== NULL
) {
209 i
.fields_present
= SAMR_FIELD_DESCRIPTION
;
210 i
.description
= from
->description
;
212 copy_id21_to_sam_passwd("INFO_13", to
, &i
);
215 /*************************************************************
216 Copies a struct samr_UserInfo14 to a struct samu
217 **************************************************************/
219 void copy_id14_to_sam_passwd(struct samu
*to
,
220 struct samr_UserInfo14
*from
)
222 struct samr_UserInfo21 i
;
224 if (from
== NULL
|| to
== NULL
) {
230 i
.fields_present
= SAMR_FIELD_WORKSTATIONS
;
231 i
.workstations
= from
->workstations
;
233 copy_id21_to_sam_passwd("INFO_14", to
, &i
);
236 /*************************************************************
237 Copies a struct samr_UserInfo16 to a struct samu
238 **************************************************************/
240 void copy_id16_to_sam_passwd(struct samu
*to
,
241 struct samr_UserInfo16
*from
)
243 struct samr_UserInfo21 i
;
245 if (from
== NULL
|| to
== NULL
) {
251 i
.fields_present
= SAMR_FIELD_ACCT_FLAGS
;
252 i
.acct_flags
= from
->acct_flags
;
254 copy_id21_to_sam_passwd("INFO_16", to
, &i
);
257 /*************************************************************
258 Copies a struct samr_UserInfo17 to a struct samu
259 **************************************************************/
261 void copy_id17_to_sam_passwd(struct samu
*to
,
262 struct samr_UserInfo17
*from
)
264 struct samr_UserInfo21 i
;
266 if (from
== NULL
|| to
== NULL
) {
272 i
.fields_present
= SAMR_FIELD_ACCT_EXPIRY
;
273 i
.acct_expiry
= from
->acct_expiry
;
275 copy_id21_to_sam_passwd("INFO_17", to
, &i
);
278 /*************************************************************
279 Copies a struct samr_UserInfo18 to a struct samu
280 **************************************************************/
282 void copy_id18_to_sam_passwd(struct samu
*to
,
283 struct samr_UserInfo18
*from
)
285 struct samr_UserInfo21 i
;
287 if (from
== NULL
|| to
== NULL
) {
293 i
.fields_present
= SAMR_FIELD_EXPIRED_FLAG
;
294 i
.password_expired
= from
->password_expired
;
296 copy_id21_to_sam_passwd("INFO_18", to
, &i
);
299 /*************************************************************
300 Copies a struct samr_UserInfo20 to a struct samu
301 **************************************************************/
303 void copy_id20_to_sam_passwd(struct samu
*to
,
304 struct samr_UserInfo20
*from
)
306 const char *old_string
;
310 if (from
== NULL
|| to
== NULL
) {
314 if (from
->parameters
.array
) {
315 old_string
= pdb_get_munged_dial(to
);
316 mung
= data_blob_const(from
->parameters
.array
,
317 from
->parameters
.length
);
318 new_string
= (mung
.length
== 0) ?
319 NULL
: base64_encode_data_blob(talloc_tos(), mung
);
320 DEBUG(10,("INFO_20 PARAMETERS: %s -> %s\n",
321 old_string
, new_string
));
322 if (STRING_CHANGED_NC(old_string
,new_string
)) {
323 pdb_set_munged_dial(to
, new_string
, PDB_CHANGED
);
326 TALLOC_FREE(new_string
);
330 /*************************************************************
331 Copies a struct samr_UserInfo21 to a struct samu
332 **************************************************************/
334 void copy_id21_to_sam_passwd(const char *log_prefix
,
336 struct samr_UserInfo21
*from
)
338 time_t unix_time
, stored_time
;
339 const char *old_string
, *new_string
;
342 if (from
== NULL
|| to
== NULL
) {
352 if (from
->fields_present
& SAMR_FIELD_LAST_LOGON
) {
353 unix_time
= nt_time_to_unix(from
->last_logon
);
354 stored_time
= pdb_get_logon_time(to
);
355 DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l
,
356 (long unsigned int)stored_time
,
357 (long unsigned int)unix_time
));
358 if (stored_time
!= unix_time
) {
359 pdb_set_logon_time(to
, unix_time
, PDB_CHANGED
);
363 if (from
->fields_present
& SAMR_FIELD_LAST_LOGOFF
) {
364 unix_time
= nt_time_to_unix(from
->last_logoff
);
365 stored_time
= pdb_get_logoff_time(to
);
366 DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l
,
367 (long unsigned int)stored_time
,
368 (long unsigned int)unix_time
));
369 if (stored_time
!= unix_time
) {
370 pdb_set_logoff_time(to
, unix_time
, PDB_CHANGED
);
374 if (from
->fields_present
& SAMR_FIELD_ACCT_EXPIRY
) {
375 unix_time
= nt_time_to_unix(from
->acct_expiry
);
376 stored_time
= pdb_get_kickoff_time(to
);
377 DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l
,
378 (long unsigned int)stored_time
,
379 (long unsigned int)unix_time
));
380 if (stored_time
!= unix_time
) {
381 pdb_set_kickoff_time(to
, unix_time
, PDB_CHANGED
);
385 if (from
->fields_present
& SAMR_FIELD_LAST_PWD_CHANGE
) {
386 unix_time
= nt_time_to_unix(from
->last_password_change
);
387 stored_time
= pdb_get_pass_last_set_time(to
);
388 DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l
,
389 (long unsigned int)stored_time
,
390 (long unsigned int)unix_time
));
391 if (stored_time
!= unix_time
) {
392 pdb_set_pass_last_set_time(to
, unix_time
, PDB_CHANGED
);
396 if ((from
->fields_present
& SAMR_FIELD_ACCOUNT_NAME
) &&
397 (from
->account_name
.string
)) {
398 old_string
= pdb_get_username(to
);
399 new_string
= from
->account_name
.string
;
400 DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l
,
401 old_string
, new_string
));
402 if (STRING_CHANGED
) {
403 pdb_set_username(to
, new_string
, PDB_CHANGED
);
407 if ((from
->fields_present
& SAMR_FIELD_FULL_NAME
) &&
408 (from
->full_name
.string
)) {
409 old_string
= pdb_get_fullname(to
);
410 new_string
= from
->full_name
.string
;
411 DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l
,
412 old_string
, new_string
));
413 if (STRING_CHANGED
) {
414 pdb_set_fullname(to
, new_string
, PDB_CHANGED
);
418 if ((from
->fields_present
& SAMR_FIELD_HOME_DIRECTORY
) &&
419 (from
->home_directory
.string
)) {
420 old_string
= pdb_get_homedir(to
);
421 new_string
= from
->home_directory
.string
;
422 DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l
,
423 old_string
, new_string
));
424 if (STRING_CHANGED
) {
425 pdb_set_homedir(to
, new_string
, PDB_CHANGED
);
429 if ((from
->fields_present
& SAMR_FIELD_HOME_DRIVE
) &&
430 (from
->home_drive
.string
)) {
431 old_string
= pdb_get_dir_drive(to
);
432 new_string
= from
->home_drive
.string
;
433 DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l
,
434 old_string
, new_string
));
435 if (STRING_CHANGED
) {
436 pdb_set_dir_drive(to
, new_string
, PDB_CHANGED
);
440 if ((from
->fields_present
& SAMR_FIELD_LOGON_SCRIPT
) &&
441 (from
->logon_script
.string
)) {
442 old_string
= pdb_get_logon_script(to
);
443 new_string
= from
->logon_script
.string
;
444 DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l
,
445 old_string
, new_string
));
446 if (STRING_CHANGED
) {
447 pdb_set_logon_script(to
, new_string
, PDB_CHANGED
);
451 if ((from
->fields_present
& SAMR_FIELD_PROFILE_PATH
) &&
452 (from
->profile_path
.string
)) {
453 old_string
= pdb_get_profile_path(to
);
454 new_string
= from
->profile_path
.string
;
455 DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l
,
456 old_string
, new_string
));
457 if (STRING_CHANGED
) {
458 pdb_set_profile_path(to
, new_string
, PDB_CHANGED
);
462 if ((from
->fields_present
& SAMR_FIELD_DESCRIPTION
) &&
463 (from
->description
.string
)) {
464 old_string
= pdb_get_acct_desc(to
);
465 new_string
= from
->description
.string
;
466 DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l
,
467 old_string
, new_string
));
468 if (STRING_CHANGED
) {
469 pdb_set_acct_desc(to
, new_string
, PDB_CHANGED
);
473 if ((from
->fields_present
& SAMR_FIELD_WORKSTATIONS
) &&
474 (from
->workstations
.string
)) {
475 old_string
= pdb_get_workstations(to
);
476 new_string
= from
->workstations
.string
;
477 DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l
,
478 old_string
, new_string
));
479 if (STRING_CHANGED
) {
480 pdb_set_workstations(to
, new_string
, PDB_CHANGED
);
484 if ((from
->fields_present
& SAMR_FIELD_COMMENT
) &&
485 (from
->comment
.string
)) {
486 old_string
= pdb_get_comment(to
);
487 new_string
= from
->comment
.string
;
488 DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l
,
489 old_string
, new_string
));
490 if (STRING_CHANGED
) {
491 pdb_set_comment(to
, new_string
, PDB_CHANGED
);
495 if ((from
->fields_present
& SAMR_FIELD_PARAMETERS
) &&
496 (from
->parameters
.array
)) {
499 old_string
= pdb_get_munged_dial(to
);
501 mung
= data_blob_const(from
->parameters
.array
,
502 from
->parameters
.length
);
503 newstr
= (mung
.length
== 0) ?
504 NULL
: base64_encode_data_blob(talloc_tos(), mung
);
505 DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l
,
506 old_string
, newstr
));
507 if (STRING_CHANGED_NC(old_string
,newstr
)) {
508 pdb_set_munged_dial(to
, newstr
, PDB_CHANGED
);
514 if (from
->fields_present
& SAMR_FIELD_RID
) {
515 if (from
->rid
== 0) {
516 DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l
));
517 } else if (from
->rid
!= pdb_get_user_rid(to
)) {
518 DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l
,
519 pdb_get_user_rid(to
), from
->rid
));
523 if (from
->fields_present
& SAMR_FIELD_PRIMARY_GID
) {
524 if (from
->primary_gid
== 0) {
525 DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l
));
526 } else if (from
->primary_gid
!= pdb_get_group_rid(to
)) {
527 DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l
,
528 pdb_get_group_rid(to
), from
->primary_gid
));
529 pdb_set_group_sid_from_rid(to
,
530 from
->primary_gid
, PDB_CHANGED
);
534 if (from
->fields_present
& SAMR_FIELD_ACCT_FLAGS
) {
535 DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l
,
536 pdb_get_acct_ctrl(to
), from
->acct_flags
));
537 if (from
->acct_flags
!= pdb_get_acct_ctrl(to
)) {
539 /* You cannot autolock an unlocked account via
540 * setuserinfo calls, so make sure to remove the
541 * ACB_AUTOLOCK bit here - gd */
543 if ((from
->acct_flags
& ACB_AUTOLOCK
) &&
544 !(pdb_get_acct_ctrl(to
) & ACB_AUTOLOCK
)) {
545 from
->acct_flags
&= ~ACB_AUTOLOCK
;
548 if (!(from
->acct_flags
& ACB_AUTOLOCK
) &&
549 (pdb_get_acct_ctrl(to
) & ACB_AUTOLOCK
)) {
550 /* We're unlocking a previously locked user. Reset bad password counts.
551 Patch from Jianliang Lu. <Jianliang.Lu@getronics.com> */
552 pdb_set_bad_password_count(to
, 0, PDB_CHANGED
);
553 pdb_set_bad_password_time(to
, 0, PDB_CHANGED
);
555 pdb_set_acct_ctrl(to
, from
->acct_flags
, PDB_CHANGED
);
559 if (from
->fields_present
& SAMR_FIELD_LOGON_HOURS
) {
560 char oldstr
[44]; /* hours strings are 42 bytes. */
562 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l
,
563 pdb_get_logon_divs(to
), from
->logon_hours
.units_per_week
));
564 if (from
->logon_hours
.units_per_week
!= pdb_get_logon_divs(to
)) {
565 pdb_set_logon_divs(to
,
566 from
->logon_hours
.units_per_week
, PDB_CHANGED
);
569 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l
,
570 pdb_get_hours_len(to
),
571 from
->logon_hours
.units_per_week
/8));
572 if (from
->logon_hours
.units_per_week
/8 != pdb_get_hours_len(to
)) {
573 pdb_set_hours_len(to
,
574 from
->logon_hours
.units_per_week
/8, PDB_CHANGED
);
577 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l
,
578 pdb_get_hours(to
), from
->logon_hours
.bits
));
579 pdb_sethexhours(oldstr
, pdb_get_hours(to
));
580 pdb_sethexhours(newstr
, from
->logon_hours
.bits
);
581 if (!strequal(oldstr
, newstr
)) {
582 pdb_set_hours(to
, from
->logon_hours
.bits
, PDB_CHANGED
);
586 if (from
->fields_present
& SAMR_FIELD_BAD_PWD_COUNT
) {
587 DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l
,
588 pdb_get_bad_password_count(to
), from
->bad_password_count
));
589 if (from
->bad_password_count
!= pdb_get_bad_password_count(to
)) {
590 pdb_set_bad_password_count(to
,
591 from
->bad_password_count
, PDB_CHANGED
);
595 if (from
->fields_present
& SAMR_FIELD_NUM_LOGONS
) {
596 DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l
,
597 pdb_get_logon_count(to
), from
->logon_count
));
598 if (from
->logon_count
!= pdb_get_logon_count(to
)) {
599 pdb_set_logon_count(to
, from
->logon_count
, PDB_CHANGED
);
603 /* If the must change flag is set, the last set time goes to zero.
604 the must change and can change fields also do, but they are
605 calculated from policy, not set from the wire */
607 if (from
->fields_present
& SAMR_FIELD_EXPIRED_FLAG
) {
608 DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l
,
609 from
->password_expired
));
610 if (from
->password_expired
!= 0) {
611 pdb_set_pass_last_set_time(to
, 0, PDB_CHANGED
);
613 /* A subtlety here: some windows commands will
614 clear the expired flag even though it's not
615 set, and we don't want to reset the time
616 in these caess. "net user /dom <user> /active:y"
617 for example, to clear an autolocked acct.
618 We must check to see if it's expired first. jmcd */
620 uint32_t pwd_max_age
= 0;
621 time_t now
= time(NULL
);
623 pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE
, &pwd_max_age
);
625 if (pwd_max_age
== (uint32_t)-1 || pwd_max_age
== 0) {
626 pwd_max_age
= get_time_t_max();
629 stored_time
= pdb_get_pass_last_set_time(to
);
631 /* we will only *set* a pwdlastset date when
632 a) the last pwdlastset time was 0 (user was forced to
634 b) the users password has not expired. gd. */
636 if ((stored_time
== 0) ||
637 ((now
- stored_time
) > pwd_max_age
)) {
638 pdb_set_pass_last_set_time(to
, now
, PDB_CHANGED
);
645 /*************************************************************
646 Copies a struct samr_UserInfo23 to a struct samu
647 **************************************************************/
649 void copy_id23_to_sam_passwd(struct samu
*to
,
650 struct samr_UserInfo23
*from
)
652 if (from
== NULL
|| to
== NULL
) {
656 copy_id21_to_sam_passwd("INFO 23", to
, &from
->info
);
659 /*************************************************************
660 Copies a struct samr_UserInfo24 to a struct samu
661 **************************************************************/
663 void copy_id24_to_sam_passwd(struct samu
*to
,
664 struct samr_UserInfo24
*from
)
666 struct samr_UserInfo21 i
;
668 if (from
== NULL
|| to
== NULL
) {
674 i
.fields_present
= SAMR_FIELD_EXPIRED_FLAG
;
675 i
.password_expired
= from
->password_expired
;
677 copy_id21_to_sam_passwd("INFO_24", to
, &i
);
680 /*************************************************************
681 Copies a struct samr_UserInfo25 to a struct samu
682 **************************************************************/
684 void copy_id25_to_sam_passwd(struct samu
*to
,
685 struct samr_UserInfo25
*from
)
687 if (from
== NULL
|| to
== NULL
) {
691 copy_id21_to_sam_passwd("INFO_25", to
, &from
->info
);
694 /*************************************************************
695 Copies a struct samr_UserInfo26 to a struct samu
696 **************************************************************/
698 void copy_id26_to_sam_passwd(struct samu
*to
,
699 struct samr_UserInfo26
*from
)
701 struct samr_UserInfo21 i
;
703 if (from
== NULL
|| to
== NULL
) {
709 i
.fields_present
= SAMR_FIELD_EXPIRED_FLAG
;
710 i
.password_expired
= from
->password_expired
;
712 copy_id21_to_sam_passwd("INFO_26", to
, &i
);