2 * GUMS password backend for samba
3 * Copyright (C) Simo Sorce 2003-2004
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 675
17 * Mass Ave, Cambridge, MA 02139, USA.
22 #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)
23 #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)
30 static NTSTATUS
gums_object_to_sam_account(SAM_ACCOUNT
*sa
, GUMS_OBJECT
*go
)
37 return NT_STATUS_INVALID_PARAMETER
;
39 if (!NT_STATUS_IS_OK(ret = pdb_init_sam(sa))) {
40 DEBUG(0, ("gums_object_to_sam_account: error occurred while creating sam_account object!\n"));
44 if (gums_get_object_type(go
) != GUMS_OBJ_NORMAL_USER
)
45 return NT_STATUS_OBJECT_TYPE_MISMATCH
;
47 BOOL_SET_OR_FAIL(pdb_set_acct_ctrl(sa
, gums_get_user_acct_ctrl(go
), PDB_SET
), error
);
52 nt_time
= gums_get_user_logon_time(go
);
53 BOOL_SET_OR_FAIL(pdb_set_logon_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
54 nt_time
= gums_get_user_logoff_time(go
);
55 BOOL_SET_OR_FAIL(pdb_set_logoff_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
56 nt_time
= gums_get_user_kickoff_time(go
);
57 BOOL_SET_OR_FAIL(pdb_set_kickoff_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
58 nt_time
= gums_get_user_pass_last_set_time(go
);
59 BOOL_SET_OR_FAIL(pdb_set_pass_last_set_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
60 nt_time
= gums_get_user_pass_can_change_time(go
);
61 BOOL_SET_OR_FAIL(pdb_set_pass_can_change_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
62 nt_time
= gums_get_user_pass_must_change_time(go
);
63 BOOL_SET_OR_FAIL(pdb_set_pass_must_change_time(sa
, nt_time_to_unix(&nt_time
), PDB_SET
), error
);
64 BOOL_SET_OR_FAIL(pdb_set_hours_len(sa
, gums_get_user_hours_len(go
), PDB_SET
), error
);
65 BOOL_SET_OR_FAIL(pdb_set_logon_divs(sa
, gums_get_user_logon_divs(go
), PDB_SET
), error
);
66 BOOL_SET_OR_FAIL(pdb_set_user_sid(sa
, gums_get_object_sid(go
), PDB_SET
), error
);
67 BOOL_SET_OR_FAIL(pdb_set_group_sid(sa
, gums_get_user_pri_group(go
), PDB_SET
), error
);
68 BOOL_SET_OR_FAIL(pdb_set_username(sa
, gums_get_object_name(go
), PDB_SET
), error
);
69 BOOL_SET_OR_FAIL(pdb_set_nt_username(sa
, gums_get_object_name(go
), PDB_SET
), error
);
70 BOOL_SET_OR_FAIL(pdb_set_fullname(sa
, gums_get_user_fullname(go
), PDB_SET
), error
);
71 BOOL_SET_OR_FAIL(pdb_set_logon_script(sa
, gums_get_user_logon_script(go
), PDB_SET
), error
);
72 BOOL_SET_OR_FAIL(pdb_set_profile_path(sa
, gums_get_user_profile_path(go
), PDB_SET
), error
);
73 BOOL_SET_OR_FAIL(pdb_set_dir_drive(sa
, gums_get_user_dir_drive(go
), PDB_SET
), error
);
74 BOOL_SET_OR_FAIL(pdb_set_homedir(sa
, gums_get_user_homedir(go
), PDB_SET
), error
);
75 BOOL_SET_OR_FAIL(pdb_set_acct_desc(sa
, gums_get_object_description(go
), PDB_SET
), error
);
76 BOOL_SET_OR_FAIL(pdb_set_workstations(sa
, gums_get_user_workstations(go
), PDB_SET
), error
);
77 BOOL_SET_OR_FAIL(pdb_set_unknown_str(sa
, gums_get_user_unknown_str(go
), PDB_SET
), error
);
78 BOOL_SET_OR_FAIL(pdb_set_munged_dial(sa
, gums_get_user_munged_dial(go
), PDB_SET
), error
);
80 pwd
= gums_get_user_nt_pwd(go
);
81 if (!pdb_set_nt_passwd(sa
, pwd
.data
, PDB_SET
)) {
82 DEBUG(5, ("gums_object_to_sam_account: unable to set nt password"));
83 data_blob_clear_free(&pwd
);
84 ret
= NT_STATUS_UNSUCCESSFUL
;
87 data_blob_clear_free(&pwd
);
88 pwd
= gums_get_user_lm_pwd(go
);
89 if (!pdb_set_lanman_passwd(sa
, pwd
.data
, PDB_SET
)) {
90 DEBUG(5, ("gums_object_to_sam_account: unable to set lanman password"));
91 data_blob_clear_free(&pwd
);
92 ret
= NT_STATUS_UNSUCCESSFUL
;
95 data_blob_clear_free(&pwd
);
97 BOOL_SET_OR_FAIL(pdb_set_bad_password_count(sa
, gums_get_user_bad_password_count(go
), PDB_SET
), error
);
98 BOOL_SET_OR_FAIL(pdb_set_unknown_6(sa
, gums_get_user_unknown_6(go
), PDB_SET
), error
);
99 BOOL_SET_OR_FAIL(pdb_set_hours(sa
, gums_get_user_hours(go
), PDB_SET
), error
);
104 if (sa
&& (sa
->free_fn
)) {
111 static NTSTATUS
sam_account_to_gums_object(GUMS_OBJECT
*go
, SAM_ACCOUNT
*sa
)
118 return NT_STATUS_INVALID_PARAMETER
;
121 ret = gums_create_object(go, GUMS_OBJ_NORMAL_USER);
122 if (!NT_STATUS_IS_OK(ret)) {
123 DEBUG(0, ("sam_account_to_gums_object: error occurred while creating gums object!\n"));
130 SET_OR_FAIL(gums_set_object_name(go
, pdb_get_username(sa
)), error
);
132 SET_OR_FAIL(gums_set_object_sid(go
, pdb_get_user_sid(sa
)), error
);
133 SET_OR_FAIL(gums_set_user_pri_group(go
, pdb_get_group_sid(sa
)), error
);
135 if (pdb_get_acct_desc(sa
))
136 SET_OR_FAIL(gums_set_object_description(go
, pdb_get_acct_desc(sa
)), error
);
137 if (pdb_get_fullname(sa
))
138 SET_OR_FAIL(gums_set_user_fullname(go
, pdb_get_fullname(sa
)), error
);
139 if (pdb_get_homedir(sa
))
140 SET_OR_FAIL(gums_set_user_homedir(go
, pdb_get_homedir(sa
)), error
);
141 if (pdb_get_dir_drive(sa
))
142 SET_OR_FAIL(gums_set_user_dir_drive(go
, pdb_get_dir_drive(sa
)), error
);
143 if (pdb_get_logon_script(sa
))
144 SET_OR_FAIL(gums_set_user_logon_script(go
, pdb_get_logon_script(sa
)), error
);
145 if (pdb_get_profile_path(sa
))
146 SET_OR_FAIL(gums_set_user_profile_path(go
, pdb_get_profile_path(sa
)), error
);
147 if (pdb_get_workstations(sa
))
148 SET_OR_FAIL(gums_set_user_workstations(go
, pdb_get_workstations(sa
)), error
);
149 if (pdb_get_unknown_str(sa
))
150 SET_OR_FAIL(gums_set_user_unknown_str(go
, pdb_get_unknown_str(sa
)), error
);
151 if (pdb_get_munged_dial(sa
))
152 SET_OR_FAIL(gums_set_user_munged_dial(go
, pdb_get_munged_dial(sa
)), error
);
153 SET_OR_FAIL(gums_set_user_logon_divs(go
, pdb_get_logon_divs(sa
)), error
);
154 if (pdb_get_hours(sa
))
155 SET_OR_FAIL(gums_set_user_hours(go
, pdb_get_hours_len(sa
), pdb_get_hours(sa
)), error
);
156 SET_OR_FAIL(gums_set_user_bad_password_count(go
, pdb_get_bad_password_count(sa
)), error
);
157 SET_OR_FAIL(gums_set_user_unknown_6(go
, pdb_get_unknown_6(sa
)), error
);
159 unix_to_nt_time(&nt_time
, pdb_get_logon_time(sa
));
160 SET_OR_FAIL(gums_set_user_logon_time(go
, nt_time
), error
);
161 unix_to_nt_time(&nt_time
, pdb_get_logoff_time(sa
));
162 SET_OR_FAIL(gums_set_user_logoff_time(go
, nt_time
), error
);
163 unix_to_nt_time(&nt_time
, pdb_get_kickoff_time(sa
));
164 SET_OR_FAIL(gums_set_user_kickoff_time(go
, nt_time
), error
);
165 unix_to_nt_time(&nt_time
, pdb_get_pass_last_set_time(sa
));
166 SET_OR_FAIL(gums_set_user_pass_last_set_time(go
, nt_time
), error
);
167 unix_to_nt_time(&nt_time
, pdb_get_pass_can_change_time(sa
));
168 SET_OR_FAIL(gums_set_user_pass_can_change_time(go
, nt_time
), error
);
169 unix_to_nt_time(&nt_time
, pdb_get_pass_must_change_time(sa
));
170 SET_OR_FAIL(gums_set_user_pass_must_change_time(go
, nt_time
), error
);
172 pwd
= data_blob(pdb_get_nt_passwd(sa
), NT_HASH_LEN
);
173 ret
= gums_set_user_nt_pwd(go
, pwd
);
174 data_blob_clear_free(&pwd
);
175 if (!NT_STATUS_IS_OK(ret
)) {
176 DEBUG(5, ("sam_account_to_gums_object: failed to set nt password!\n"));
179 pwd
= data_blob(pdb_get_lanman_passwd(sa
), LM_HASH_LEN
);
180 ret
= gums_set_user_lm_pwd(go
, pwd
);
181 data_blob_clear_free(&pwd
);
182 if (!NT_STATUS_IS_OK(ret
)) {
183 DEBUG(5, ("sam_account_to_gums_object: failed to set lanman password!\n"));
187 SET_OR_FAIL(gums_set_user_acct_ctrl(go
, pdb_get_acct_ctrl(sa
)), error
);
192 gums_reset_object(go
);
196 static NTSTATUS
gums_setsampwent(struct pdb_methods
*methods
, BOOL update
)
198 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
200 return ggwd
->fns
->enumerate_objects_start(&(ggwd
->handle
), NULL
, GUMS_OBJ_NORMAL_USER
);
203 static NTSTATUS
gums_getsampwent(struct pdb_methods
*methods
, SAM_ACCOUNT
*account
)
207 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
209 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->enumerate_objects_get_next(&go
, ggwd
->handle
))) {
213 ret
= gums_object_to_sam_account(account
, go
);
215 gums_destroy_object(&go
);
219 static void gums_endsampwent(struct pdb_methods
*methods
)
221 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
223 ggwd
->fns
->enumerate_objects_stop(ggwd
->handle
);
226 /******************************************************************
227 Lookup a name in the SAM database
228 ******************************************************************/
230 static NTSTATUS
gums_getsampwnam (struct pdb_methods
*methods
, SAM_ACCOUNT
*account
, const char *name
)
234 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
236 if (!account
|| !name
)
237 return NT_STATUS_INVALID_PARAMETER
;
239 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->get_object_from_name(&go
, global_myname(), name
, GUMS_OBJ_NORMAL_USER
))) {
240 DEBUG(10, ("gums_getsampwnam: unable to find account with name %s", name
));
244 ret
= gums_object_to_sam_account(account
, go
);
246 gums_destroy_object(&go
);
250 /***************************************************************************
252 **************************************************************************/
254 static NTSTATUS
gums_getsampwsid(struct pdb_methods
*methods
, SAM_ACCOUNT
*account
, const DOM_SID
*sid
)
258 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
260 if (!account
|| !sid
)
261 return NT_STATUS_INVALID_PARAMETER
;
263 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->get_object_from_sid(&go
, sid
, GUMS_OBJ_NORMAL_USER
))) {
264 DEBUG(10, ("gums_getsampwsid: unable to find account with sid %s", sid_string_static(sid
)));
268 ret
= gums_object_to_sam_account(account
, go
);
270 gums_destroy_object(&go
);
274 /***************************************************************************
276 **************************************************************************/
280 static NTSTATUS
gums_getsampwrid (struct pdb_methods
*methods
,
281 SAM_ACCOUNT
*account
, uint32 rid
)
285 sid_copy(&sid
, get_global_sam_sid());
286 sid_append_rid(&sid
, rid
);
287 gums_getsampwsid(methods
, account
, &sid
);
294 /***************************************************************************
295 Updates a SAM_ACCOUNT
297 This isn't a particulary practical option for pdb_guest. We certainly don't
298 want to twidde the filesystem, so what should we do?
300 Current plan is to transparently add the account. It should appear
301 as if the pdb_guest version was modified, but its actually stored somehwere.
302 ****************************************************************************/
304 static NTSTATUS
gums_add_sam_account (struct pdb_methods
*methods
, SAM_ACCOUNT
*account
)
308 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
311 return NT_STATUS_INVALID_PARAMETER
;
313 if (!NT_STATUS_IS_OK(ret
= gums_create_object(&go
, GUMS_OBJ_NORMAL_USER
))) {
314 DEBUG(0, ("gums_add_sam_account: error occurred while creating gums object!\n"));
318 if (!NT_STATUS_IS_OK(ret
= sam_account_to_gums_object(go
, account
))) {
319 DEBUG(0, ("gums_add_sam_account: error occurred while converting object!\n"));
323 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->set_object(go
))) {
324 DEBUG(0, ("gums_add_sam_account: unable to store account!\n"));
329 gums_destroy_object(&go
);
333 static NTSTATUS
gums_update_sam_account (struct pdb_methods
*methods
, SAM_ACCOUNT
*account
)
337 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
340 return NT_STATUS_INVALID_PARAMETER
;
342 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->get_object_from_sid(&go
, pdb_get_user_sid(account
), GUMS_OBJ_NORMAL_USER
))) {
343 DEBUG(0, ("gums_update_sam_account: update on invalid account!\n"));
347 if (!NT_STATUS_IS_OK(ret
= sam_account_to_gums_object(go
, account
))) {
348 DEBUG(0, ("gums_update_sam_account: error occurred while converting object!\n"));
352 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->set_object(go
))) {
353 DEBUG(0, ("gums_update_sam_account: unable to store account!\n"));
358 gums_destroy_object(&go
);
362 static NTSTATUS
gums_delete_sam_account (struct pdb_methods
*methods
, SAM_ACCOUNT
*account
)
365 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)(methods
->private_data
);
368 return NT_STATUS_INVALID_PARAMETER
;
370 if (!NT_STATUS_IS_OK(ret
= ggwd
->fns
->delete_object(pdb_get_user_sid(account
)))) {
371 DEBUG(0, ("gums_add_sam_account: unable to store account!\n"));
378 static void free_gw_private_data(void **vp
)
380 struct gums_gw_data
*ggwd
= (struct gums_gw_data
*)vp
;
381 ggwd
->fns
->free_private_data(&(ggwd
->fns
->private_data
));
387 NTSTATUS
pdb_init_gums_gateway(PDB_CONTEXT
*pdb_context
, PDB_METHODS
**pdb_method
, const char *location
)
390 struct gums_gw_data
*ggwd
;
393 DEBUG(0, ("invalid pdb_context specified\n"));
394 return NT_STATUS_UNSUCCESSFUL
;
397 if (!NT_STATUS_IS_OK(ret
= gums_setup_backend(lp_gums_backend()))) {
398 DEBUG(0, ("pdb_init_gums_gateway: initialization error!\n"));
402 ggwd
= (struct gums_gw_data
*)malloc(sizeof(struct gums_gw_data
));
404 return NT_STATUS_NO_MEMORY
;
405 memset(ggwd
, 0, sizeof(struct gums_gw_data
));
407 if (!NT_STATUS_IS_OK(ret
= get_gums_fns(&(ggwd
->fns
)))) {
411 if (!NT_STATUS_IS_OK(ret
= make_pdb_methods(pdb_context
->mem_ctx
, pdb_method
))) {
415 (*pdb_method
)->name
= "gums_gateway";
417 (*pdb_method
)->setsampwent
= gums_setsampwent
;
418 (*pdb_method
)->getsampwent
= gums_getsampwent
;
419 (*pdb_method
)->endsampwent
= gums_endsampwent
;
420 (*pdb_method
)->getsampwnam
= gums_getsampwnam
;
421 (*pdb_method
)->getsampwsid
= gums_getsampwsid
;
422 (*pdb_method
)->add_sam_account
= gums_add_sam_account
;
423 (*pdb_method
)->update_sam_account
= gums_update_sam_account
;
424 (*pdb_method
)->delete_sam_account
= gums_delete_sam_account
;
426 /* we should do no group mapping here */
427 /* (*pdb_method)->getgrsid = gums_getgrsid;
428 (*pdb_method)->getgrgid = gums_getgrgid;
429 (*pdb_method)->getgrnam = gums_getgrnam;
430 (*pdb_method)->add_group_mapping_entry = gums_add_group_mapping_entry;
431 (*pdb_method)->update_group_mapping_entry = gums_update_group_mapping_entry;
432 (*pdb_method)->delete_group_mapping_entry = gums_delete_group_mapping_entry;
433 (*pdb_method)->enum_group_mapping = gums_enum_group_mapping;*/
435 /* we do not handle groups in guest backend */
437 (*pdb_method)->get_group_info_by_sid = gums_get_group_info_by_sid;
438 (*pdb_method)->get_group_list = gums_get_group_list;
439 (*pdb_method)->get_group_sids = gums_get_group_sids;
440 (*pdb_method)->add_group = gums_add_group;
441 (*pdb_method)->update_group = gums_update_group;
442 (*pdb_method)->delete_group = gums_delete_group;
443 (*pdb_method)->add_sid_to_group = gums_add_sid_to_group;
444 (*pdb_method)->remove_sid_from_group = gums_remove_sid_from_group;
445 (*pdb_method)->get_group_info_by_name = gums_get_group_info_by_name;
446 (*pdb_method)->get_group_info_by_nt_name = gums_get_group_info_by_nt_name;
447 (*pdb_method)->get_group_uids = gums_get_group_uids;
450 (*pdb_method
)->private_data
= ggwd
;
451 (*pdb_method
)->free_private_data
= free_gw_private_data
;
460 NTSTATUS
pdb_gums_init(void)
462 return smb_register_passdb(PASSDB_INTERFACE_VERSION
, "gums", pdb_init_gums_gateway
);