2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2002
5 Copyright (C) Jelmer Vernooij 2002
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DBGC_CLASS DBGC_PASSDB
27 /** List of various built-in passdb modules */
29 const struct pdb_init_function_entry builtin_pdb_init_functions
[] = {
30 { "smbpasswd", pdb_init_smbpasswd
},
31 { "smbpasswd_nua", pdb_init_smbpasswd_nua
},
32 { "tdbsam", pdb_init_tdbsam
},
33 { "tdbsam_nua", pdb_init_tdbsam_nua
},
34 { "ldapsam", pdb_init_ldapsam
},
35 { "ldapsam_nua", pdb_init_ldapsam_nua
},
36 { "unixsam", pdb_init_unixsam
},
37 { "nisplussam", pdb_init_nisplussam
},
38 { "plugin", pdb_init_plugin
},
42 static NTSTATUS
context_setsampwent(struct pdb_context
*context
, BOOL update
)
44 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
47 DEBUG(0, ("invalid pdb_context specified!\n"));
51 context
->pwent_methods
= context
->pdb_methods
;
53 if (!context
->pwent_methods
) {
54 /* No passdbs at all */
58 while (NT_STATUS_IS_ERR(ret
= context
->pwent_methods
->setsampwent(context
->pwent_methods
, update
))) {
59 context
->pwent_methods
= context
->pwent_methods
->next
;
60 if (context
->pwent_methods
== NULL
)
61 return NT_STATUS_UNSUCCESSFUL
;
66 static void context_endsampwent(struct pdb_context
*context
)
69 DEBUG(0, ("invalid pdb_context specified!\n"));
73 if (context
->pwent_methods
&& context
->pwent_methods
->endsampwent
)
74 context
->pwent_methods
->endsampwent(context
->pwent_methods
);
76 /* So we won't get strange data when calling getsampwent now */
77 context
->pwent_methods
= NULL
;
80 static NTSTATUS
context_getsampwent(struct pdb_context
*context
, SAM_ACCOUNT
*user
)
82 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
84 if ((!context
) || (!context
->pwent_methods
)) {
85 DEBUG(0, ("invalid pdb_context specified!\n"));
88 /* Loop until we find something useful */
89 while (NT_STATUS_IS_ERR(ret
= context
->pwent_methods
->getsampwent(context
->pwent_methods
, user
))) {
91 context
->pwent_methods
->endsampwent(context
->pwent_methods
);
93 context
->pwent_methods
= context
->pwent_methods
->next
;
95 /* All methods are checked now. There are no more entries */
96 if (context
->pwent_methods
== NULL
)
99 context
->pwent_methods
->setsampwent(context
->pwent_methods
, False
);
101 user
->methods
= context
->pwent_methods
;
105 static NTSTATUS
context_getsampwnam(struct pdb_context
*context
, SAM_ACCOUNT
*sam_acct
, const char *username
)
107 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
109 struct pdb_methods
*curmethods
;
111 DEBUG(0, ("invalid pdb_context specified!\n"));
114 curmethods
= context
->pdb_methods
;
116 if (NT_STATUS_IS_OK(ret
= curmethods
->getsampwnam(curmethods
, sam_acct
, username
))) {
117 sam_acct
->methods
= curmethods
;
120 curmethods
= curmethods
->next
;
126 static NTSTATUS
context_getsampwsid(struct pdb_context
*context
, SAM_ACCOUNT
*sam_acct
, const DOM_SID
*sid
)
128 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
130 struct pdb_methods
*curmethods
;
132 DEBUG(0, ("invalid pdb_context specified!\n"));
136 curmethods
= context
->pdb_methods
;
139 if (NT_STATUS_IS_OK(ret
= curmethods
->getsampwsid(curmethods
, sam_acct
, sid
))) {
140 sam_acct
->methods
= curmethods
;
143 curmethods
= curmethods
->next
;
149 static NTSTATUS
context_add_sam_account(struct pdb_context
*context
, SAM_ACCOUNT
*sam_acct
)
151 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
153 if ((!context
) || (!context
->pdb_methods
)) {
154 DEBUG(0, ("invalid pdb_context specified!\n"));
158 /** @todo This is where a 're-read on add' should be done */
159 /* We now add a new account to the first database listed.
162 return context
->pdb_methods
->add_sam_account(context
->pdb_methods
, sam_acct
);
165 static NTSTATUS
context_update_sam_account(struct pdb_context
*context
, SAM_ACCOUNT
*sam_acct
)
167 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
170 DEBUG(0, ("invalid pdb_context specified!\n"));
174 if (!sam_acct
|| !sam_acct
->methods
){
175 DEBUG(0, ("invalid sam_acct specified\n"));
179 /** @todo This is where a 're-read on update' should be done */
181 return sam_acct
->methods
->update_sam_account(sam_acct
->methods
, sam_acct
);
184 static NTSTATUS
context_delete_sam_account(struct pdb_context
*context
, SAM_ACCOUNT
*sam_acct
)
186 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
188 struct pdb_methods
*pdb_selected
;
190 DEBUG(0, ("invalid pdb_context specified!\n"));
194 if (!sam_acct
->methods
){
195 pdb_selected
= context
->pdb_methods
;
196 /* There's no passdb backend specified for this account.
197 * Try to delete it in every passdb available
198 * Needed to delete accounts in smbpasswd that are not
201 while (pdb_selected
){
202 if (NT_STATUS_IS_OK(ret
= pdb_selected
->delete_sam_account(pdb_selected
, sam_acct
))) {
205 pdb_selected
= pdb_selected
->next
;
210 if (!sam_acct
->methods
->delete_sam_account
){
211 DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n"));
215 return sam_acct
->methods
->delete_sam_account(sam_acct
->methods
, sam_acct
);
218 /******************************************************************
219 Free and cleanup a pdb context, any associated data and anything
220 that the attached modules might have associated.
221 *******************************************************************/
223 static void free_pdb_context(struct pdb_context
**context
)
225 struct pdb_methods
*pdb_selected
= (*context
)->pdb_methods
;
227 while (pdb_selected
){
228 pdb_selected
->free_private_data(&(pdb_selected
->private_data
));
229 pdb_selected
= pdb_selected
->next
;
232 talloc_destroy((*context
)->mem_ctx
);
236 /******************************************************************
237 Make a pdb_methods from scratch
238 *******************************************************************/
240 static NTSTATUS
make_pdb_methods_name(struct pdb_methods
**methods
, struct pdb_context
*context
, const char *selected
)
242 char *module_name
= smb_xstrdup(selected
);
243 char *module_location
= NULL
, *p
;
244 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
247 p
= strchr(module_name
, ':');
251 module_location
= p
+1;
252 trim_string(module_location
, " ", " ");
255 trim_string(module_name
, " ", " ");
257 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected
, module_name
));
258 for (i
= 0; builtin_pdb_init_functions
[i
].name
; i
++)
260 if (strequal(builtin_pdb_init_functions
[i
].name
, module_name
))
262 DEBUG(5,("Found pdb backend %s (at pos %d)\n", module_name
, i
));
263 nt_status
= builtin_pdb_init_functions
[i
].init(context
, methods
, module_location
);
264 if (NT_STATUS_IS_OK(nt_status
)) {
265 DEBUG(5,("pdb backend %s has a valid init\n", selected
));
267 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected
, nt_errstr(nt_status
)));
269 SAFE_FREE(module_name
);
271 break; /* unreached */
275 /* No such backend found */
276 SAFE_FREE(module_name
);
277 return NT_STATUS_INVALID_PARAMETER
;
280 /******************************************************************
281 Make a pdb_context from scratch.
282 *******************************************************************/
284 static NTSTATUS
make_pdb_context(struct pdb_context
**context
)
288 mem_ctx
= talloc_init_named("pdb_context internal allocation context");
291 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
292 return NT_STATUS_NO_MEMORY
;
295 *context
= talloc(mem_ctx
, sizeof(**context
));
297 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
298 return NT_STATUS_NO_MEMORY
;
301 ZERO_STRUCTP(*context
);
303 (*context
)->mem_ctx
= mem_ctx
;
305 (*context
)->pdb_setsampwent
= context_setsampwent
;
306 (*context
)->pdb_endsampwent
= context_endsampwent
;
307 (*context
)->pdb_getsampwent
= context_getsampwent
;
308 (*context
)->pdb_getsampwnam
= context_getsampwnam
;
309 (*context
)->pdb_getsampwsid
= context_getsampwsid
;
310 (*context
)->pdb_add_sam_account
= context_add_sam_account
;
311 (*context
)->pdb_update_sam_account
= context_update_sam_account
;
312 (*context
)->pdb_delete_sam_account
= context_delete_sam_account
;
314 (*context
)->free_fn
= free_pdb_context
;
320 /******************************************************************
321 Make a pdb_context, given an array of strings
322 *******************************************************************/
324 NTSTATUS
make_pdb_context_list(struct pdb_context
**context
, char **selected
)
327 struct pdb_methods
*curmethods
, *tmpmethods
;
328 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
330 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_context(context
))) {
335 /* Try to initialise pdb */
336 DEBUG(5,("Trying to load: %s\n", selected
[i
]));
337 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_methods_name(&curmethods
, *context
, selected
[i
]))) {
338 DEBUG(1, ("Loading %s failed!\n", selected
[i
]));
339 free_pdb_context(context
);
342 curmethods
->parent
= *context
;
343 DLIST_ADD_END((*context
)->pdb_methods
, curmethods
, tmpmethods
);
350 /******************************************************************
351 Make a pdb_context, given a text string.
352 *******************************************************************/
354 NTSTATUS
make_pdb_context_string(struct pdb_context
**context
, const char *selected
)
357 char **newsel
= str_list_make(selected
, NULL
);
358 ret
= make_pdb_context_list(context
, newsel
);
359 str_list_free(&newsel
);
363 /******************************************************************
364 Return an already initialised pdb_context, to facilitate backward
365 compatibility (see functions below).
366 *******************************************************************/
368 static struct pdb_context
*pdb_get_static_context(BOOL reload
)
370 static struct pdb_context
*pdb_context
= NULL
;
372 if ((pdb_context
) && (reload
)) {
373 pdb_context
->free_fn(&pdb_context
);
374 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context
, lp_passdb_backend()))) {
380 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context
, lp_passdb_backend()))) {
388 #if !defined(WITH_NISPLUS_SAM)
390 /******************************************************************
391 Backward compatibility functions for the original passdb interface
392 *******************************************************************/
394 BOOL
pdb_setsampwent(BOOL update
)
396 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
402 return NT_STATUS_IS_OK(pdb_context
->pdb_setsampwent(pdb_context
, update
));
405 void pdb_endsampwent(void)
407 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
413 pdb_context
->pdb_endsampwent(pdb_context
);
416 BOOL
pdb_getsampwent(SAM_ACCOUNT
*user
)
418 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
424 return NT_STATUS_IS_OK(pdb_context
->pdb_getsampwent(pdb_context
, user
));
427 BOOL
pdb_getsampwnam(SAM_ACCOUNT
*sam_acct
, const char *username
)
429 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
435 return NT_STATUS_IS_OK(pdb_context
->pdb_getsampwnam(pdb_context
, sam_acct
, username
));
438 BOOL
pdb_getsampwsid(SAM_ACCOUNT
*sam_acct
, const DOM_SID
*sid
)
440 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
446 return NT_STATUS_IS_OK(pdb_context
->pdb_getsampwsid(pdb_context
, sam_acct
, sid
));
449 BOOL
pdb_add_sam_account(SAM_ACCOUNT
*sam_acct
)
451 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
457 return NT_STATUS_IS_OK(pdb_context
->pdb_add_sam_account(pdb_context
, sam_acct
));
460 BOOL
pdb_update_sam_account(SAM_ACCOUNT
*sam_acct
)
462 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
468 return NT_STATUS_IS_OK(pdb_context
->pdb_update_sam_account(pdb_context
, sam_acct
));
471 BOOL
pdb_delete_sam_account(SAM_ACCOUNT
*sam_acct
)
473 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
479 return NT_STATUS_IS_OK(pdb_context
->pdb_delete_sam_account(pdb_context
, sam_acct
));
482 #endif /* !defined(WITH_NISPLUS_SAM) */
484 /***************************************************************
485 Initialize the static context (at smbd startup etc).
487 If uninitialised, context will auto-init on first use.
488 ***************************************************************/
490 BOOL
initialize_password_db(BOOL reload
)
492 return (pdb_get_static_context(reload
) != NULL
);
496 NTSTATUS
make_pdb_methods(TALLOC_CTX
*mem_ctx
, PDB_METHODS
**methods
)
498 *methods
= talloc(mem_ctx
, sizeof(struct pdb_methods
));
501 return NT_STATUS_NO_MEMORY
;
504 ZERO_STRUCTP(*methods
);