s3-samr: support some more info levels in samr_QueryUser calls.
[ira/wip.git] / source3 / rpc_server / srv_samr_util.c
1 /*
2    Unix SMB/CIFS implementation.
3    SAMR Pipe utility functions.
4
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
10
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.
15
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.
20
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/>.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_SRV
29
30 #define STRING_CHANGED (old_string && !new_string) ||\
31                     (!old_string && new_string) ||\
32                 (old_string && new_string && (strcmp(old_string, new_string) != 0))
33
34 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
35                     (!(s1) && (s2)) ||\
36                 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
37
38 /*************************************************************
39  Copies a struct samr_UserInfo18 to a struct samu
40 **************************************************************/
41
42 void copy_id18_to_sam_passwd(struct samu *to,
43                              struct samr_UserInfo18 *from)
44 {
45         struct samr_UserInfo21 i;
46
47         if (from == NULL || to == NULL) {
48                 return;
49         }
50
51         ZERO_STRUCT(i);
52
53         i.fields_present        = SAMR_FIELD_EXPIRED_FLAG;
54         i.password_expired      = from->password_expired;
55
56         copy_id21_to_sam_passwd("INFO_18", to, &i);
57 }
58
59 /*************************************************************
60  Copies a struct samr_UserInfo20 to a struct samu
61 **************************************************************/
62
63 void copy_id20_to_sam_passwd(struct samu *to,
64                              struct samr_UserInfo20 *from)
65 {
66         const char *old_string;
67         char *new_string;
68         DATA_BLOB mung;
69
70         if (from == NULL || to == NULL) {
71                 return;
72         }
73
74         if (from->parameters.array) {
75                 old_string = pdb_get_munged_dial(to);
76                 mung = data_blob_const(from->parameters.array,
77                                        from->parameters.length);
78                 new_string = (mung.length == 0) ?
79                         NULL : base64_encode_data_blob(talloc_tos(), mung);
80                 DEBUG(10,("INFO_20 PARAMETERS: %s -> %s\n",
81                         old_string, new_string));
82                 if (STRING_CHANGED_NC(old_string,new_string)) {
83                         pdb_set_munged_dial(to, new_string, PDB_CHANGED);
84                 }
85
86                 TALLOC_FREE(new_string);
87         }
88 }
89
90 /*************************************************************
91  Copies a struct samr_UserInfo21 to a struct samu
92 **************************************************************/
93
94 void copy_id21_to_sam_passwd(const char *log_prefix,
95                              struct samu *to,
96                              struct samr_UserInfo21 *from)
97 {
98         time_t unix_time, stored_time;
99         const char *old_string, *new_string;
100         const char *l;
101
102         if (from == NULL || to == NULL) {
103                 return;
104         }
105
106         if (log_prefix) {
107                 l = log_prefix;
108         } else {
109                 l = "INFO_21";
110         }
111
112         if (from->fields_present & SAMR_FIELD_LAST_LOGON) {
113                 unix_time = nt_time_to_unix(from->last_logon);
114                 stored_time = pdb_get_logon_time(to);
115                 DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l,
116                         (long unsigned int)stored_time,
117                         (long unsigned int)unix_time));
118                 if (stored_time != unix_time) {
119                         pdb_set_logon_time(to, unix_time, PDB_CHANGED);
120                 }
121         }
122
123         if (from->fields_present & SAMR_FIELD_LAST_LOGOFF) {
124                 unix_time = nt_time_to_unix(from->last_logoff);
125                 stored_time = pdb_get_logoff_time(to);
126                 DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l,
127                         (long unsigned int)stored_time,
128                         (long unsigned int)unix_time));
129                 if (stored_time != unix_time) {
130                         pdb_set_logoff_time(to, unix_time, PDB_CHANGED);
131                 }
132         }
133
134         if (from->fields_present & SAMR_FIELD_ACCT_EXPIRY) {
135                 unix_time = nt_time_to_unix(from->acct_expiry);
136                 stored_time = pdb_get_kickoff_time(to);
137                 DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l,
138                         (long unsigned int)stored_time,
139                         (long unsigned int)unix_time));
140                 if (stored_time != unix_time) {
141                         pdb_set_kickoff_time(to, unix_time , PDB_CHANGED);
142                 }
143         }
144
145         if (from->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
146                 unix_time = nt_time_to_unix(from->last_password_change);
147                 stored_time = pdb_get_pass_last_set_time(to);
148                 DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l,
149                         (long unsigned int)stored_time,
150                         (long unsigned int)unix_time));
151                 if (stored_time != unix_time) {
152                         pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED);
153                 }
154         }
155
156         if ((from->fields_present & SAMR_FIELD_ACCOUNT_NAME) &&
157             (from->account_name.string)) {
158                 old_string = pdb_get_username(to);
159                 new_string = from->account_name.string;
160                 DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l,
161                         old_string, new_string));
162                 if (STRING_CHANGED) {
163                         pdb_set_username(to, new_string, PDB_CHANGED);
164                 }
165         }
166
167         if ((from->fields_present & SAMR_FIELD_FULL_NAME) &&
168             (from->full_name.string)) {
169                 old_string = pdb_get_fullname(to);
170                 new_string = from->full_name.string;
171                 DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l,
172                         old_string, new_string));
173                 if (STRING_CHANGED) {
174                         pdb_set_fullname(to, new_string, PDB_CHANGED);
175                 }
176         }
177
178         if ((from->fields_present & SAMR_FIELD_HOME_DIRECTORY) &&
179             (from->home_directory.string)) {
180                 old_string = pdb_get_homedir(to);
181                 new_string = from->home_directory.string;
182                 DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l,
183                         old_string, new_string));
184                 if (STRING_CHANGED) {
185                         pdb_set_homedir(to, new_string, PDB_CHANGED);
186                 }
187         }
188
189         if ((from->fields_present & SAMR_FIELD_HOME_DRIVE) &&
190             (from->home_drive.string)) {
191                 old_string = pdb_get_dir_drive(to);
192                 new_string = from->home_drive.string;
193                 DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l,
194                         old_string, new_string));
195                 if (STRING_CHANGED) {
196                         pdb_set_dir_drive(to, new_string, PDB_CHANGED);
197                 }
198         }
199
200         if ((from->fields_present & SAMR_FIELD_LOGON_SCRIPT) &&
201             (from->logon_script.string)) {
202                 old_string = pdb_get_logon_script(to);
203                 new_string = from->logon_script.string;
204                 DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l,
205                         old_string, new_string));
206                 if (STRING_CHANGED) {
207                         pdb_set_logon_script(to  , new_string, PDB_CHANGED);
208                 }
209         }
210
211         if ((from->fields_present & SAMR_FIELD_PROFILE_PATH) &&
212             (from->profile_path.string)) {
213                 old_string = pdb_get_profile_path(to);
214                 new_string = from->profile_path.string;
215                 DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l,
216                         old_string, new_string));
217                 if (STRING_CHANGED) {
218                         pdb_set_profile_path(to  , new_string, PDB_CHANGED);
219                 }
220         }
221
222         if ((from->fields_present & SAMR_FIELD_DESCRIPTION) &&
223             (from->description.string)) {
224                 old_string = pdb_get_acct_desc(to);
225                 new_string = from->description.string;
226                 DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l,
227                         old_string, new_string));
228                 if (STRING_CHANGED) {
229                         pdb_set_acct_desc(to, new_string, PDB_CHANGED);
230                 }
231         }
232
233         if ((from->fields_present & SAMR_FIELD_WORKSTATIONS) &&
234             (from->workstations.string)) {
235                 old_string = pdb_get_workstations(to);
236                 new_string = from->workstations.string;
237                 DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l,
238                         old_string, new_string));
239                 if (STRING_CHANGED) {
240                         pdb_set_workstations(to  , new_string, PDB_CHANGED);
241                 }
242         }
243
244         if ((from->fields_present & SAMR_FIELD_COMMENT) &&
245             (from->comment.string)) {
246                 old_string = pdb_get_comment(to);
247                 new_string = from->comment.string;
248                 DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l,
249                         old_string, new_string));
250                 if (STRING_CHANGED) {
251                         pdb_set_comment(to, new_string, PDB_CHANGED);
252                 }
253         }
254
255         if ((from->fields_present & SAMR_FIELD_PARAMETERS) &&
256             (from->parameters.array)) {
257                 char *newstr;
258                 DATA_BLOB mung;
259                 old_string = pdb_get_munged_dial(to);
260
261                 mung = data_blob_const(from->parameters.array,
262                                        from->parameters.length);
263                 newstr = (mung.length == 0) ?
264                         NULL : base64_encode_data_blob(talloc_tos(), mung);
265                 DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l,
266                         old_string, newstr));
267                 if (STRING_CHANGED_NC(old_string,newstr)) {
268                         pdb_set_munged_dial(to, newstr, PDB_CHANGED);
269                 }
270
271                 TALLOC_FREE(newstr);
272         }
273
274         if (from->fields_present & SAMR_FIELD_RID) {
275                 if (from->rid == 0) {
276                         DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l));
277                 } else if (from->rid != pdb_get_user_rid(to)) {
278                         DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l,
279                                 pdb_get_user_rid(to), from->rid));
280                 }
281         }
282
283         if (from->fields_present & SAMR_FIELD_PRIMARY_GID) {
284                 if (from->primary_gid == 0) {
285                         DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l));
286                 } else if (from->primary_gid != pdb_get_group_rid(to)) {
287                         DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l,
288                                 pdb_get_group_rid(to), from->primary_gid));
289                         pdb_set_group_sid_from_rid(to,
290                                 from->primary_gid, PDB_CHANGED);
291                 }
292         }
293
294         if (from->fields_present & SAMR_FIELD_ACCT_FLAGS) {
295                 DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l,
296                         pdb_get_acct_ctrl(to), from->acct_flags));
297                 if (from->acct_flags != pdb_get_acct_ctrl(to)) {
298                         if (!(from->acct_flags & ACB_AUTOLOCK) &&
299                              (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
300                                 /* We're unlocking a previously locked user. Reset bad password counts.
301                                    Patch from Jianliang Lu. <Jianliang.Lu@getronics.com> */
302                                 pdb_set_bad_password_count(to, 0, PDB_CHANGED);
303                                 pdb_set_bad_password_time(to, 0, PDB_CHANGED);
304                         }
305                         pdb_set_acct_ctrl(to, from->acct_flags, PDB_CHANGED);
306                 }
307         }
308
309         if (from->fields_present & SAMR_FIELD_LOGON_HOURS) {
310                 char oldstr[44]; /* hours strings are 42 bytes. */
311                 char newstr[44];
312                 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l,
313                         pdb_get_logon_divs(to), from->logon_hours.units_per_week));
314                 if (from->logon_hours.units_per_week != pdb_get_logon_divs(to)) {
315                         pdb_set_logon_divs(to,
316                                 from->logon_hours.units_per_week, PDB_CHANGED);
317                 }
318
319                 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l,
320                         pdb_get_hours_len(to),
321                         from->logon_hours.units_per_week/8));
322                 if (from->logon_hours.units_per_week/8 != pdb_get_hours_len(to)) {
323                         pdb_set_hours_len(to,
324                                 from->logon_hours.units_per_week/8, PDB_CHANGED);
325                 }
326
327                 DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l,
328                         pdb_get_hours(to), from->logon_hours.bits));
329                 pdb_sethexhours(oldstr, pdb_get_hours(to));
330                 pdb_sethexhours(newstr, from->logon_hours.bits);
331                 if (!strequal(oldstr, newstr)) {
332                         pdb_set_hours(to, from->logon_hours.bits, PDB_CHANGED);
333                 }
334         }
335
336         if (from->fields_present & SAMR_FIELD_BAD_PWD_COUNT) {
337                 DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l,
338                         pdb_get_bad_password_count(to), from->bad_password_count));
339                 if (from->bad_password_count != pdb_get_bad_password_count(to)) {
340                         pdb_set_bad_password_count(to,
341                                 from->bad_password_count, PDB_CHANGED);
342                 }
343         }
344
345         if (from->fields_present & SAMR_FIELD_NUM_LOGONS) {
346                 DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l,
347                         pdb_get_logon_count(to), from->logon_count));
348                 if (from->logon_count != pdb_get_logon_count(to)) {
349                         pdb_set_logon_count(to, from->logon_count, PDB_CHANGED);
350                 }
351         }
352
353         /* If the must change flag is set, the last set time goes to zero.
354            the must change and can change fields also do, but they are
355            calculated from policy, not set from the wire */
356
357         if (from->fields_present & SAMR_FIELD_EXPIRED_FLAG) {
358                 DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l,
359                         from->password_expired));
360                 if (from->password_expired != 0) {
361                         pdb_set_pass_last_set_time(to, 0, PDB_CHANGED);
362                 } else {
363                         /* A subtlety here: some windows commands will
364                            clear the expired flag even though it's not
365                            set, and we don't want to reset the time
366                            in these caess.  "net user /dom <user> /active:y"
367                            for example, to clear an autolocked acct.
368                            We must check to see if it's expired first. jmcd */
369
370                         uint32_t pwd_max_age = 0;
371                         time_t now = time(NULL);
372
373                         pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &pwd_max_age);
374
375                         if (pwd_max_age == (uint32_t)-1 || pwd_max_age == 0) {
376                                 pwd_max_age = get_time_t_max();
377                         }
378
379                         stored_time = pdb_get_pass_last_set_time(to);
380
381                         /* we will only *set* a pwdlastset date when
382                            a) the last pwdlastset time was 0 (user was forced to
383                               change password).
384                            b) the users password has not expired. gd. */
385
386                         if ((stored_time == 0) ||
387                             ((now - stored_time) > pwd_max_age)) {
388                                 pdb_set_pass_last_set_time(to, now, PDB_CHANGED);
389                         }
390                 }
391         }
392 }
393
394
395 /*************************************************************
396  Copies a struct samr_UserInfo23 to a struct samu
397 **************************************************************/
398
399 void copy_id23_to_sam_passwd(struct samu *to,
400                              struct samr_UserInfo23 *from)
401 {
402         if (from == NULL || to == NULL) {
403                 return;
404         }
405
406         copy_id21_to_sam_passwd("INFO 23", to, &from->info);
407 }
408
409 /*************************************************************
410  Copies a struct samr_UserInfo24 to a struct samu
411 **************************************************************/
412
413 void copy_id24_to_sam_passwd(struct samu *to,
414                              struct samr_UserInfo24 *from)
415 {
416         struct samr_UserInfo21 i;
417
418         if (from == NULL || to == NULL) {
419                 return;
420         }
421
422         ZERO_STRUCT(i);
423
424         i.fields_present        = SAMR_FIELD_EXPIRED_FLAG;
425         i.password_expired      = from->password_expired;
426
427         copy_id21_to_sam_passwd("INFO_24", to, &i);
428 }
429
430 /*************************************************************
431  Copies a struct samr_UserInfo25 to a struct samu
432 **************************************************************/
433
434 void copy_id25_to_sam_passwd(struct samu *to,
435                              struct samr_UserInfo25 *from)
436 {
437         if (from == NULL || to == NULL) {
438                 return;
439         }
440
441         copy_id21_to_sam_passwd("INFO_25", to, &from->info);
442 }
443
444 /*************************************************************
445  Copies a struct samr_UserInfo26 to a struct samu
446 **************************************************************/
447
448 void copy_id26_to_sam_passwd(struct samu *to,
449                              struct samr_UserInfo26 *from)
450 {
451         struct samr_UserInfo21 i;
452
453         if (from == NULL || to == NULL) {
454                 return;
455         }
456
457         ZERO_STRUCT(i);
458
459         i.fields_present        = SAMR_FIELD_EXPIRED_FLAG;
460         i.password_expired      = from->password_expired;
461
462         copy_id21_to_sam_passwd("INFO_26", to, &i);
463 }