Patch from Benjamin Riefenstahl <Benjamin.Riefenstahl@epost.de> to add
[samba.git] / source3 / passdb / pdb_gums.c
1 /*
2  * 'Guest' password backend for samba
3  * Copyright (C) Jelmer Vernooij 2002
4  * Copyright (C) Andrew Bartlett 2003
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  * 
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 675
18  * Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22
23 #define SET_OR_FAIL(func, label) do { if (!NT_STATUS_IS_OK(func)) { DEBUG(0, ("%s: Setting gums object data failed!\n", FUNCTION_MACRO)); goto label; } } while(0)
24 #define BOOL_SET_OR_FAIL(func, label) do { if (!func) { DEBUG(0, ("%s: Setting sam object data failed!\n", FUNCTION_MACRO)); goto label; } } while(0)
25
26 struct gums_gw_data {
27         GUMS_FUNCTIONS *fns;
28         void *handle;
29 };
30
31 static NTSTATUS gums_object_to_sam_account(SAM_ACCOUNT *sa, GUMS_OBJECT *go)
32 {
33         NTSTATUS ret;
34         NTTIME nt_time;
35         DATA_BLOB pwd;
36
37         if (!go || !sa)
38                 return NT_STATUS_INVALID_PARAMETER;
39 /*
40         if (!NT_STATUS_IS_OK(ret = pdb_init_sam(sa))) {
41                 DEBUG(0, ("gums_object_to_sam_account: error occurred while creating sam_account object!\n"));
42                 goto error;
43         }
44 */
45         if (gums_get_object_type(go) != GUMS_OBJ_NORMAL_USER)
46                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
47
48         BOOL_SET_OR_FAIL(pdb_set_acct_ctrl(sa, gums_get_user_acct_ctrl(go), PDB_SET), error);
49
50         /* domain */
51         /* unix_homedir ? */
52
53         nt_time = gums_get_user_logon_time(go);
54         BOOL_SET_OR_FAIL(pdb_set_logon_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
55         nt_time = gums_get_user_logoff_time(go);
56         BOOL_SET_OR_FAIL(pdb_set_logoff_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
57         nt_time = gums_get_user_kickoff_time(go);
58         BOOL_SET_OR_FAIL(pdb_set_kickoff_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
59         nt_time = gums_get_user_pass_last_set_time(go);
60         BOOL_SET_OR_FAIL(pdb_set_pass_last_set_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
61         nt_time = gums_get_user_pass_can_change_time(go);
62         BOOL_SET_OR_FAIL(pdb_set_pass_can_change_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
63         nt_time = gums_get_user_pass_must_change_time(go);
64         BOOL_SET_OR_FAIL(pdb_set_pass_must_change_time(sa, nt_time_to_unix(&nt_time), PDB_SET), error);
65         BOOL_SET_OR_FAIL(pdb_set_hours_len(sa, gums_get_user_hours_len(go), PDB_SET), error);
66         BOOL_SET_OR_FAIL(pdb_set_logon_divs(sa, gums_get_user_logon_divs(go), PDB_SET), error);
67         BOOL_SET_OR_FAIL(pdb_set_user_sid(sa, gums_get_object_sid(go), PDB_SET), error);
68         BOOL_SET_OR_FAIL(pdb_set_group_sid(sa, gums_get_user_pri_group(go), PDB_SET), error);
69         BOOL_SET_OR_FAIL(pdb_set_username(sa, gums_get_object_name(go), PDB_SET), error);
70         BOOL_SET_OR_FAIL(pdb_set_nt_username(sa, gums_get_object_name(go), PDB_SET), error);
71         BOOL_SET_OR_FAIL(pdb_set_fullname(sa, gums_get_user_fullname(go), PDB_SET), error);
72         BOOL_SET_OR_FAIL(pdb_set_logon_script(sa, gums_get_user_logon_script(go), PDB_SET), error);
73         BOOL_SET_OR_FAIL(pdb_set_profile_path(sa, gums_get_user_profile_path(go), PDB_SET), error); 
74         BOOL_SET_OR_FAIL(pdb_set_dir_drive(sa, gums_get_user_dir_drive(go), PDB_SET), error); 
75         BOOL_SET_OR_FAIL(pdb_set_homedir(sa, gums_get_user_homedir(go), PDB_SET), error); 
76         BOOL_SET_OR_FAIL(pdb_set_acct_desc(sa, gums_get_object_description(go), PDB_SET), error); 
77         BOOL_SET_OR_FAIL(pdb_set_workstations(sa, gums_get_user_workstations(go), PDB_SET), error); 
78         BOOL_SET_OR_FAIL(pdb_set_unknown_str(sa, gums_get_user_unknown_str(go), PDB_SET), error); 
79         BOOL_SET_OR_FAIL(pdb_set_munged_dial(sa, gums_get_user_munged_dial(go), PDB_SET), error); 
80
81         pwd = gums_get_user_nt_pwd(go);
82         if (!pdb_set_nt_passwd(sa, pwd.data, PDB_SET)) {
83                 DEBUG(5, ("gums_object_to_sam_account: unable to set nt password"));
84                 data_blob_clear_free(&pwd);
85                 ret = NT_STATUS_UNSUCCESSFUL;
86                 goto error;
87         }
88         data_blob_clear_free(&pwd);
89         pwd = gums_get_user_lm_pwd(go);
90         if (!pdb_set_lanman_passwd(sa, pwd.data, PDB_SET)) {
91                 DEBUG(5, ("gums_object_to_sam_account: unable to set lanman password"));
92                 data_blob_clear_free(&pwd);
93                 ret = NT_STATUS_UNSUCCESSFUL;
94                 goto error;
95         }
96         data_blob_clear_free(&pwd);
97
98         BOOL_SET_OR_FAIL(pdb_set_unknown_3(sa, gums_get_user_unknown_3(go), PDB_SET), error); 
99         BOOL_SET_OR_FAIL(pdb_set_bad_password_count(sa, gums_get_user_bad_password_count(go), PDB_SET), error); 
100         BOOL_SET_OR_FAIL(pdb_set_unknown_6(sa, gums_get_user_unknown_6(go), PDB_SET), error); 
101         BOOL_SET_OR_FAIL(pdb_set_hours(sa, gums_get_user_hours(go), PDB_SET), error); 
102
103         return NT_STATUS_OK;
104
105 error:
106         if (sa && (sa->free_fn)) {
107                 sa->free_fn(&sa);
108         }
109
110         return ret;
111 }
112
113 static NTSTATUS sam_account_to_gums_object(GUMS_OBJECT *go, SAM_ACCOUNT *sa)
114 {
115         NTSTATUS ret;
116         NTTIME nt_time;
117         DATA_BLOB pwd;
118
119         if (!go || !sa)
120                 return NT_STATUS_INVALID_PARAMETER;
121
122 /*
123         ret = gums_create_object(go, GUMS_OBJ_NORMAL_USER);
124         if (!NT_STATUS_IS_OK(ret)) {
125                 DEBUG(0, ("sam_account_to_gums_object: error occurred while creating gums object!\n"));
126                 goto error;
127         }
128 */
129
130         /* sec_desc */
131
132         SET_OR_FAIL(gums_set_object_name(go, pdb_get_username(sa)), error);
133
134         SET_OR_FAIL(gums_set_object_sid(go, pdb_get_user_sid(sa)), error);
135         SET_OR_FAIL(gums_set_user_pri_group(go, pdb_get_group_sid(sa)), error);
136
137         if (pdb_get_acct_desc(sa))
138                 SET_OR_FAIL(gums_set_object_description(go, pdb_get_acct_desc(sa)), error);
139         if (pdb_get_fullname(sa))
140                 SET_OR_FAIL(gums_set_user_fullname(go, pdb_get_fullname(sa)), error);
141         if (pdb_get_homedir(sa))
142                 SET_OR_FAIL(gums_set_user_homedir(go, pdb_get_homedir(sa)), error);
143         if (pdb_get_dir_drive(sa))
144                 SET_OR_FAIL(gums_set_user_dir_drive(go, pdb_get_dir_drive(sa)), error);
145         if (pdb_get_logon_script(sa))
146                 SET_OR_FAIL(gums_set_user_logon_script(go, pdb_get_logon_script(sa)), error);
147         if (pdb_get_profile_path(sa))
148                 SET_OR_FAIL(gums_set_user_profile_path(go, pdb_get_profile_path(sa)), error);
149         if (pdb_get_workstations(sa))
150                 SET_OR_FAIL(gums_set_user_workstations(go, pdb_get_workstations(sa)), error);
151         if (pdb_get_unknown_str(sa))
152                 SET_OR_FAIL(gums_set_user_unknown_str(go, pdb_get_unknown_str(sa)), error);
153         if (pdb_get_munged_dial(sa))
154                 SET_OR_FAIL(gums_set_user_munged_dial(go, pdb_get_munged_dial(sa)), error);
155         SET_OR_FAIL(gums_set_user_logon_divs(go, pdb_get_logon_divs(sa)), error);
156         if (pdb_get_hours(sa))
157                 SET_OR_FAIL(gums_set_user_hours(go, pdb_get_hours_len(sa), pdb_get_hours(sa)), error);
158         SET_OR_FAIL(gums_set_user_unknown_3(go, pdb_get_unknown_3(sa)), error);
159         SET_OR_FAIL(gums_set_user_bad_password_count(go, pdb_get_bad_password_count(sa)), error);
160         SET_OR_FAIL(gums_set_user_unknown_6(go, pdb_get_unknown_6(sa)), error);
161
162         unix_to_nt_time(&nt_time, pdb_get_logon_time(sa));
163         SET_OR_FAIL(gums_set_user_logon_time(go, nt_time), error);
164         unix_to_nt_time(&nt_time, pdb_get_logoff_time(sa));
165         SET_OR_FAIL(gums_set_user_logoff_time(go, nt_time), error);
166         unix_to_nt_time(&nt_time, pdb_get_kickoff_time(sa));
167         SET_OR_FAIL(gums_set_user_kickoff_time(go, nt_time), error);
168         unix_to_nt_time(&nt_time, pdb_get_pass_last_set_time(sa));
169         SET_OR_FAIL(gums_set_user_pass_last_set_time(go, nt_time), error);
170         unix_to_nt_time(&nt_time, pdb_get_pass_can_change_time(sa));
171         SET_OR_FAIL(gums_set_user_pass_can_change_time(go, nt_time), error);
172         unix_to_nt_time(&nt_time, pdb_get_pass_must_change_time(sa));
173         SET_OR_FAIL(gums_set_user_pass_must_change_time(go, nt_time), error);
174
175         pwd = data_blob(pdb_get_nt_passwd(sa), NT_HASH_LEN);
176         ret = gums_set_user_nt_pwd(go, pwd);
177         data_blob_clear_free(&pwd);
178         if (!NT_STATUS_IS_OK(ret)) {
179                 DEBUG(5, ("sam_account_to_gums_object: failed to set nt password!\n"));
180                 goto error;
181         }
182         pwd = data_blob(pdb_get_lanman_passwd(sa), LM_HASH_LEN);
183         ret = gums_set_user_lm_pwd(go, pwd);
184         data_blob_clear_free(&pwd);
185         if (!NT_STATUS_IS_OK(ret)) {
186                 DEBUG(5, ("sam_account_to_gums_object: failed to set lanman password!\n"));
187                 goto error;
188         }
189
190         SET_OR_FAIL(gums_set_user_acct_ctrl(go, pdb_get_acct_ctrl(sa)), error);
191
192         return NT_STATUS_OK;
193
194 error:
195         gums_reset_object(go);
196         return ret;
197 }
198
199 static NTSTATUS gums_setsampwent(struct pdb_methods *methods, BOOL update)
200 {
201         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
202
203         return ggwd->fns->enumerate_objects_start(&(ggwd->handle), NULL, GUMS_OBJ_NORMAL_USER);
204 }
205
206 static NTSTATUS gums_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT *account)
207 {
208         NTSTATUS ret;
209         GUMS_OBJECT *go;
210         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
211
212         if (!NT_STATUS_IS_OK(ret = ggwd->fns->enumerate_objects_get_next(&go, ggwd->handle))) {
213                 return ret;
214         }
215
216         ret = gums_object_to_sam_account(account, go);
217
218         gums_destroy_object(&go);
219         return ret;
220 }
221
222 static void gums_endsampwent(struct pdb_methods *methods)
223 {
224         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
225
226         ggwd->fns->enumerate_objects_stop(ggwd->handle);
227 }
228
229 /******************************************************************
230   Lookup a name in the SAM database
231  ******************************************************************/
232
233 static NTSTATUS gums_getsampwnam (struct pdb_methods *methods, SAM_ACCOUNT *account, const char *name)
234 {
235         NTSTATUS ret;
236         GUMS_OBJECT *go;
237         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
238
239         if (!account || !name)
240                 return NT_STATUS_INVALID_PARAMETER;
241
242         if (!NT_STATUS_IS_OK(ret = ggwd->fns->get_object_from_name(&go, name, GUMS_OBJ_NORMAL_USER))) {
243                 DEBUG(10, ("gums_getsampwnam: unable to find account with name %s", name));
244                 return ret;
245         }
246
247         ret = gums_object_to_sam_account(account, go);
248
249         gums_destroy_object(&go);
250         return ret;
251 }
252
253 /***************************************************************************
254   Search by SID
255  **************************************************************************/
256
257 static NTSTATUS gums_getsampwsid(struct pdb_methods *methods, SAM_ACCOUNT *account, const DOM_SID *sid)
258 {
259         NTSTATUS ret;
260         GUMS_OBJECT *go;
261         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
262
263         if (!account || !sid)
264                 return NT_STATUS_INVALID_PARAMETER;
265
266         if (!NT_STATUS_IS_OK(ret = ggwd->fns->get_object_from_sid(&go, sid, GUMS_OBJ_NORMAL_USER))) {
267                 DEBUG(10, ("gums_getsampwsid: unable to find account with sid %s", sid_string_static(sid)));
268                 return ret;
269         }
270
271         ret = gums_object_to_sam_account(account, go);
272
273         gums_destroy_object(&go);
274         return ret;
275 }
276
277 /***************************************************************************
278   Search by rid
279  **************************************************************************/
280
281 #if 0
282
283 static NTSTATUS gums_getsampwrid (struct pdb_methods *methods, 
284                                  SAM_ACCOUNT *account, uint32 rid)
285 {
286         DOM_SID sid;
287
288         sid_copy(&sid, get_global_sam_sid());
289         sid_append_rid(&sid, rid);
290         gums_getsampwsid(methods, account, &sid);
291
292         return NT_STATUS_OK;
293 }
294
295 #endif
296
297 /***************************************************************************
298   Updates a SAM_ACCOUNT
299
300   This isn't a particulary practical option for pdb_guest.  We certainly don't
301   want to twidde the filesystem, so what should we do?
302
303   Current plan is to transparently add the account.  It should appear
304   as if the pdb_guest version was modified, but its actually stored somehwere.
305  ****************************************************************************/
306
307 static NTSTATUS gums_add_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *account)
308 {
309         NTSTATUS ret;
310         GUMS_OBJECT *go;
311         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
312
313         if (!account)
314                 return NT_STATUS_INVALID_PARAMETER;
315
316         if (!NT_STATUS_IS_OK(ret = gums_create_object(&go, GUMS_OBJ_NORMAL_USER))) {
317                 DEBUG(0, ("gums_add_sam_account: error occurred while creating gums object!\n"));
318                 return ret;
319         }
320
321         if (!NT_STATUS_IS_OK(ret = sam_account_to_gums_object(go, account))) {
322                 DEBUG(0, ("gums_add_sam_account: error occurred while converting object!\n"));
323                 goto done;
324         }
325
326         if (!NT_STATUS_IS_OK(ret = ggwd->fns->set_object(go))) {
327                 DEBUG(0, ("gums_add_sam_account: unable to store account!\n"));
328                 goto done;
329         }
330
331 done:
332         gums_destroy_object(&go);
333         return ret;
334 }
335
336 static NTSTATUS gums_update_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *account)
337 {
338         NTSTATUS ret;
339         GUMS_OBJECT *go;
340         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
341
342         if (!account)
343                 return NT_STATUS_INVALID_PARAMETER;
344
345         if (!NT_STATUS_IS_OK(ret = ggwd->fns->get_object_from_sid(&go, pdb_get_user_sid(account), GUMS_OBJ_NORMAL_USER))) {
346                 DEBUG(0, ("gums_update_sam_account: update on invalid account!\n"));
347                 return ret;
348         }
349
350         if (!NT_STATUS_IS_OK(ret = sam_account_to_gums_object(go, account))) {
351                 DEBUG(0, ("gums_update_sam_account: error occurred while converting object!\n"));
352                 goto done;
353         }
354
355         if (!NT_STATUS_IS_OK(ret = ggwd->fns->set_object(go))) {
356                 DEBUG(0, ("gums_update_sam_account: unable to store account!\n"));
357                 goto done;
358         }
359
360 done:
361         gums_destroy_object(&go);
362         return ret;
363 }
364
365 static NTSTATUS gums_delete_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *account)
366 {
367         NTSTATUS ret;
368         struct gums_gw_data *ggwd = (struct gums_gw_data *)(methods->private_data);
369
370         if (!account)
371                 return NT_STATUS_INVALID_PARAMETER;
372
373         if (!NT_STATUS_IS_OK(ret = ggwd->fns->delete_object(pdb_get_user_sid(account)))) {
374                 DEBUG(0, ("gums_add_sam_account: unable to store account!\n"));
375         }
376
377         return ret;
378 }
379
380
381 static void free_gw_private_data(void **vp)
382 {
383         struct gums_gw_data *ggwd = (struct gums_gw_data *)vp;
384         ggwd->fns->free_private_data(&(ggwd->fns->private_data));
385         ggwd->fns = NULL;
386         ggwd->handle = NULL;
387         SAFE_FREE(vp);
388 }
389
390 NTSTATUS pdb_init_gums_gateway(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
391 {
392         NTSTATUS ret;
393         struct gums_gw_data *ggwd;
394         
395         if (!pdb_context) {
396                 DEBUG(0, ("invalid pdb_context specified\n"));
397                 return NT_STATUS_UNSUCCESSFUL;
398         }
399
400         if (!NT_STATUS_IS_OK(ret = gums_setup_backend(lp_gums_backend()))) {
401                 DEBUG(0, ("pdb_init_gums_gateway: initialization error!\n"));
402                 return ret;
403         }
404         
405         ggwd = (struct gums_gw_data *)malloc(sizeof(struct gums_gw_data));
406         if (!ggwd)
407                 return NT_STATUS_NO_MEMORY;
408         memset(ggwd, 0, sizeof(struct gums_gw_data));
409
410         if (!NT_STATUS_IS_OK(ret = get_gums_fns(&(ggwd->fns)))) {
411                 goto error;
412         }
413
414         if (!NT_STATUS_IS_OK(ret = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
415                 goto error;
416         }
417         
418         (*pdb_method)->name = "gums_gateway";
419         
420         (*pdb_method)->setsampwent = gums_setsampwent;
421         (*pdb_method)->getsampwent = gums_getsampwent;
422         (*pdb_method)->endsampwent = gums_endsampwent;
423         (*pdb_method)->getsampwnam = gums_getsampwnam;
424         (*pdb_method)->getsampwsid = gums_getsampwsid;
425         (*pdb_method)->add_sam_account = gums_add_sam_account;
426         (*pdb_method)->update_sam_account = gums_update_sam_account;
427         (*pdb_method)->delete_sam_account = gums_delete_sam_account;
428         
429         /* we should do no group mapping here */
430 /*      (*pdb_method)->getgrsid = gums_getgrsid;
431         (*pdb_method)->getgrgid = gums_getgrgid;
432         (*pdb_method)->getgrnam = gums_getgrnam;
433         (*pdb_method)->add_group_mapping_entry = gums_add_group_mapping_entry;
434         (*pdb_method)->update_group_mapping_entry = gums_update_group_mapping_entry;
435         (*pdb_method)->delete_group_mapping_entry = gums_delete_group_mapping_entry;
436         (*pdb_method)->enum_group_mapping = gums_enum_group_mapping;*/
437         
438         /* we do not handle groups in guest backend */
439 /*      FIXME
440         (*pdb_method)->get_group_info_by_sid = gums_get_group_info_by_sid;
441         (*pdb_method)->get_group_list = gums_get_group_list;
442         (*pdb_method)->get_group_sids = gums_get_group_sids;
443         (*pdb_method)->add_group = gums_add_group;
444         (*pdb_method)->update_group = gums_update_group;
445         (*pdb_method)->delete_group = gums_delete_group;
446         (*pdb_method)->add_sid_to_group = gums_add_sid_to_group;
447         (*pdb_method)->remove_sid_from_group = gums_remove_sid_from_group;
448         (*pdb_method)->get_group_info_by_name = gums_get_group_info_by_name;
449         (*pdb_method)->get_group_info_by_nt_name = gums_get_group_info_by_nt_name;
450         (*pdb_method)->get_group_uids = gums_get_group_uids;
451 */      
452
453         (*pdb_method)->private_data = ggwd;
454         (*pdb_method)->free_private_data = free_gw_private_data;
455         
456         return NT_STATUS_OK;
457
458 error:
459         SAFE_FREE(ggwd);
460         return ret;
461 }
462
463 NTSTATUS pdb_gums_init(void)
464 {
465         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "gums", pdb_init_gums_gateway);
466 }
467