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 { "plugin", pdb_init_plugin },
41 static BOOL context_setsampwent(struct pdb_context *context, BOOL update)
43 if ((!context) || (!context->pdb_methods) || (!context->pdb_methods->setsampwent)) {
44 DEBUG(0, ("invalid pdb_context specified!\n"));
48 context->pwent_methods = context->pdb_methods;
50 if (!context->pwent_methods) {
51 /* No passdbs at all */
55 while (!(context->pwent_methods->setsampwent(context->pwent_methods, update))) {
56 context->pwent_methods = context->pwent_methods->next;
57 if (context->pwent_methods == NULL)
63 static void context_endsampwent(struct pdb_context *context)
66 DEBUG(0, ("invalid pdb_context specified!\n"));
70 if (context->pwent_methods && context->pwent_methods->endsampwent)
71 context->pwent_methods->endsampwent(context->pwent_methods);
73 /* So we won't get strange data when calling getsampwent now */
74 context->pwent_methods = NULL;
77 static BOOL context_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
79 if ((!context) || (!context->pwent_methods)) {
80 DEBUG(0, ("invalid pdb_context specified!\n"));
83 /* Loop until we find something useful */
84 while ((!context->pwent_methods->getsampwent) ||
85 context->pwent_methods->getsampwent(context->pwent_methods, user) == False){
87 if (context->pwent_methods->endsampwent)
88 context->pwent_methods->endsampwent(context->pwent_methods);
90 context->pwent_methods = context->pwent_methods->next;
92 /* All methods are checked now. There are no more entries */
93 if (context->pwent_methods == NULL)
96 if (!context->pwent_methods->setsampwent){
97 DEBUG(5, ("next backend does not implment setsampwent\n"));
101 context->pwent_methods->setsampwent(context->pwent_methods, False);
103 user->methods = context->pwent_methods;
107 static BOOL context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
109 struct pdb_methods *curmethods;
111 DEBUG(0, ("invalid pdb_context specified!\n"));
114 curmethods = context->pdb_methods;
116 if (curmethods->getsampwnam && curmethods->getsampwnam(curmethods, sam_acct, username) == True){
117 sam_acct->methods = curmethods;
120 curmethods = curmethods->next;
126 static BOOL context_getsampwsid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, DOM_SID *sid)
128 struct pdb_methods *curmethods;
130 DEBUG(0, ("invalid pdb_context specified!\n"));
134 curmethods = context->pdb_methods;
137 if (curmethods->getsampwsid && curmethods->getsampwsid(curmethods, sam_acct, sid) == True){
138 sam_acct->methods = curmethods;
141 curmethods = curmethods->next;
147 static BOOL context_add_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
149 if ((!context) || (!context->pdb_methods) || (!context->pdb_methods->add_sam_account)) {
150 DEBUG(0, ("invalid pdb_context specified!\n"));
154 /** @todo This is where a 're-read on add' should be done */
155 /* We now add a new account to the first database listed.
158 return context->pdb_methods->add_sam_account(context->pdb_methods, sam_acct);
161 static BOOL context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
164 DEBUG(0, ("invalid pdb_context specified!\n"));
168 if (!sam_acct || !sam_acct->methods){
169 DEBUG(0, ("invalid sam_acct specified\n"));
173 if (!sam_acct->methods->update_sam_account){
174 DEBUG(0, ("invalid sam_acct->methods\n"));
178 /** @todo This is where a 're-read on update' should be done */
180 return sam_acct->methods->update_sam_account(sam_acct->methods, sam_acct);
183 static BOOL context_delete_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
185 struct pdb_methods *pdb_selected;
187 DEBUG(0, ("invalid pdb_context specified!\n"));
191 if (!sam_acct->methods){
192 pdb_selected = context->pdb_methods;
193 /* There's no passdb backend specified for this account.
194 * Try to delete it in every passdb available
195 * Needed to delete accounts in smbpasswd that are not
198 while (pdb_selected){
199 if (pdb_selected->delete_sam_account && pdb_selected->delete_sam_account(pdb_selected, sam_acct)){
202 pdb_selected = pdb_selected->next;
207 if (!sam_acct->methods->delete_sam_account){
208 DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n"));
212 return sam_acct->methods->delete_sam_account(sam_acct->methods, sam_acct);
215 /******************************************************************
216 Free and cleanup a pdb context, any associated data and anything
217 that the attached modules might have associated.
218 *******************************************************************/
220 static void free_pdb_context(struct pdb_context **context)
222 struct pdb_methods *pdb_selected = (*context)->pdb_methods;
224 while (pdb_selected){
225 if (pdb_selected->free_private_data)
226 pdb_selected->free_private_data(pdb_selected->private_data);
227 pdb_selected = pdb_selected->next;
230 talloc_destroy((*context)->mem_ctx);
234 /******************************************************************
235 Make a pdb_methods from scratch
236 *******************************************************************/
238 static NTSTATUS make_pdb_methods_name(struct pdb_methods **methods, struct pdb_context *context, const char *selected)
240 char *module_name = smb_xstrdup(selected);
241 char *module_location = NULL, *p;
242 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
245 p = strchr(module_name, ':');
249 module_location = p+1;
250 trim_string(module_location, " ", " ");
253 trim_string(module_name, " ", " ");
255 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name));
256 for (i = 0; builtin_pdb_init_functions[i].name; i++)
258 if (strequal(builtin_pdb_init_functions[i].name, module_name))
260 DEBUG(5,("Found pdb backend %s (at pos %d)\n", module_name, i));
261 if (NT_STATUS_IS_OK(nt_status
262 = builtin_pdb_init_functions[i].init(context, methods, module_location))) {
263 DEBUG(5,("pdb backend %s has a valid init\n", selected));
266 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
273 /* No such backend found */
274 return NT_STATUS_INVALID_PARAMETER;
277 /******************************************************************
278 Make a pdb_context from scratch.
279 *******************************************************************/
281 static NTSTATUS make_pdb_context(struct pdb_context **context)
285 mem_ctx = talloc_init_named("pdb_context internal allocation context");
288 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
289 return NT_STATUS_NO_MEMORY;
292 *context = talloc(mem_ctx, sizeof(**context));
294 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
295 return NT_STATUS_NO_MEMORY;
298 ZERO_STRUCTP(*context);
300 (*context)->mem_ctx = mem_ctx;
302 (*context)->pdb_setsampwent = context_setsampwent;
303 (*context)->pdb_endsampwent = context_endsampwent;
304 (*context)->pdb_getsampwent = context_getsampwent;
305 (*context)->pdb_getsampwnam = context_getsampwnam;
306 (*context)->pdb_getsampwsid = context_getsampwsid;
307 (*context)->pdb_add_sam_account = context_add_sam_account;
308 (*context)->pdb_update_sam_account = context_update_sam_account;
309 (*context)->pdb_delete_sam_account = context_delete_sam_account;
311 (*context)->free_fn = free_pdb_context;
317 /******************************************************************
318 Make a pdb_context, given an array of strings
319 *******************************************************************/
321 NTSTATUS make_pdb_context_list(struct pdb_context **context, char **selected)
324 struct pdb_methods *curmethods, *tmpmethods;
325 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
327 if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) {
332 /* Try to initialise pdb */
333 DEBUG(5,("Trying to load: %s\n", selected[i]));
334 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, *context, selected[i]))) {
335 DEBUG(5, ("Loading %s failed!\n", selected[i]));
336 SAFE_FREE(curmethods);
337 free_pdb_context(context);
340 curmethods->parent = *context;
341 DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods);
348 /******************************************************************
349 Make a pdb_context, given a text string.
350 *******************************************************************/
352 NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected)
355 char **newsel = lp_list_make(selected);
356 ret = make_pdb_context_list(context, newsel);
357 lp_list_free(&newsel);
361 /******************************************************************
362 Return an already initialised pdb_context, to facilitate backward
363 compatibility (see functions below).
364 *******************************************************************/
366 static struct pdb_context *pdb_get_static_context(BOOL reload)
368 static struct pdb_context *pdb_context = NULL;
370 if ((pdb_context) && (reload)) {
371 pdb_context->free_fn(&pdb_context);
372 if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
378 if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
386 #if !defined(WITH_NISPLUS_SAM)
388 /******************************************************************
389 Backward compatibility functions for the original passdb interface
390 *******************************************************************/
392 BOOL pdb_setsampwent(BOOL update)
394 struct pdb_context *pdb_context = pdb_get_static_context(False);
400 return pdb_context->pdb_setsampwent(pdb_context, update);
403 void pdb_endsampwent(void)
405 struct pdb_context *pdb_context = pdb_get_static_context(False);
411 pdb_context->pdb_endsampwent(pdb_context);
414 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
416 struct pdb_context *pdb_context = pdb_get_static_context(False);
422 return pdb_context->pdb_getsampwent(pdb_context, user);
425 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
427 struct pdb_context *pdb_context = pdb_get_static_context(False);
433 return pdb_context->pdb_getsampwnam(pdb_context, sam_acct, username);
436 BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, DOM_SID *sid)
438 struct pdb_context *pdb_context = pdb_get_static_context(False);
444 return pdb_context->pdb_getsampwsid(pdb_context, sam_acct, sid);
447 BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct)
449 struct pdb_context *pdb_context = pdb_get_static_context(False);
455 return pdb_context->pdb_add_sam_account(pdb_context, sam_acct);
458 BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct)
460 struct pdb_context *pdb_context = pdb_get_static_context(False);
466 return pdb_context->pdb_update_sam_account(pdb_context, sam_acct);
469 BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct)
471 struct pdb_context *pdb_context = pdb_get_static_context(False);
477 return pdb_context->pdb_delete_sam_account(pdb_context, sam_acct);
480 #endif /* !defined(WITH_NISPLUS_SAM) */
482 /***************************************************************
483 Initialize the static context (at smbd startup etc).
485 If uninitialised, context will auto-init on first use.
486 ***************************************************************/
488 BOOL initialize_password_db(BOOL reload)
490 return (pdb_get_static_context(reload) != NULL);
494 NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
496 *methods = talloc(mem_ctx, sizeof(struct pdb_methods));
499 return NT_STATUS_NO_MEMORY;
502 ZERO_STRUCTP(*methods);