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
));
228 pdb_selected
= pdb_selected
->next
;
231 talloc_destroy((*context
)->mem_ctx
);
235 /******************************************************************
236 Make a pdb_methods from scratch
237 *******************************************************************/
239 static NTSTATUS
make_pdb_methods_name(struct pdb_methods
**methods
, struct pdb_context
*context
, const char *selected
)
241 char *module_name
= smb_xstrdup(selected
);
242 char *module_location
= NULL
, *p
;
243 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
246 p
= strchr(module_name
, ':');
250 module_location
= p
+1;
251 trim_string(module_location
, " ", " ");
254 trim_string(module_name
, " ", " ");
256 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected
, module_name
));
257 for (i
= 0; builtin_pdb_init_functions
[i
].name
; i
++)
259 if (strequal(builtin_pdb_init_functions
[i
].name
, module_name
))
261 DEBUG(5,("Found pdb backend %s (at pos %d)\n", module_name
, i
));
262 nt_status
= builtin_pdb_init_functions
[i
].init(context
, methods
, module_location
);
263 if (NT_STATUS_IS_OK(nt_status
)) {
264 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
)));
268 SAFE_FREE(module_name
);
270 break; /* unreached */
274 /* No such backend found */
275 SAFE_FREE(module_name
);
276 return NT_STATUS_INVALID_PARAMETER
;
279 /******************************************************************
280 Make a pdb_context from scratch.
281 *******************************************************************/
283 static NTSTATUS
make_pdb_context(struct pdb_context
**context
)
287 mem_ctx
= talloc_init_named("pdb_context internal allocation context");
290 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
291 return NT_STATUS_NO_MEMORY
;
294 *context
= talloc(mem_ctx
, sizeof(**context
));
296 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
297 return NT_STATUS_NO_MEMORY
;
300 ZERO_STRUCTP(*context
);
302 (*context
)->mem_ctx
= mem_ctx
;
304 (*context
)->pdb_setsampwent
= context_setsampwent
;
305 (*context
)->pdb_endsampwent
= context_endsampwent
;
306 (*context
)->pdb_getsampwent
= context_getsampwent
;
307 (*context
)->pdb_getsampwnam
= context_getsampwnam
;
308 (*context
)->pdb_getsampwsid
= context_getsampwsid
;
309 (*context
)->pdb_add_sam_account
= context_add_sam_account
;
310 (*context
)->pdb_update_sam_account
= context_update_sam_account
;
311 (*context
)->pdb_delete_sam_account
= context_delete_sam_account
;
313 (*context
)->free_fn
= free_pdb_context
;
319 /******************************************************************
320 Make a pdb_context, given an array of strings
321 *******************************************************************/
323 NTSTATUS
make_pdb_context_list(struct pdb_context
**context
, char **selected
)
326 struct pdb_methods
*curmethods
, *tmpmethods
;
327 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
329 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_context(context
))) {
334 /* Try to initialise pdb */
335 DEBUG(5,("Trying to load: %s\n", selected
[i
]));
336 if (!NT_STATUS_IS_OK(nt_status
= make_pdb_methods_name(&curmethods
, *context
, selected
[i
]))) {
337 DEBUG(1, ("Loading %s failed!\n", selected
[i
]));
338 free_pdb_context(context
);
341 curmethods
->parent
= *context
;
342 DLIST_ADD_END((*context
)->pdb_methods
, curmethods
, tmpmethods
);
349 /******************************************************************
350 Make a pdb_context, given a text string.
351 *******************************************************************/
353 NTSTATUS
make_pdb_context_string(struct pdb_context
**context
, const char *selected
)
356 char **newsel
= str_list_make(selected
);
357 ret
= make_pdb_context_list(context
, newsel
);
358 str_list_free(&newsel
);
362 /******************************************************************
363 Return an already initialised pdb_context, to facilitate backward
364 compatibility (see functions below).
365 *******************************************************************/
367 static struct pdb_context
*pdb_get_static_context(BOOL reload
)
369 static struct pdb_context
*pdb_context
= NULL
;
371 if ((pdb_context
) && (reload
)) {
372 pdb_context
->free_fn(&pdb_context
);
373 if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context
, lp_passdb_backend()))) {
379 if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context
, lp_passdb_backend()))) {
387 #if !defined(WITH_NISPLUS_SAM)
389 /******************************************************************
390 Backward compatibility functions for the original passdb interface
391 *******************************************************************/
393 BOOL
pdb_setsampwent(BOOL update
)
395 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
401 return pdb_context
->pdb_setsampwent(pdb_context
, update
);
404 void pdb_endsampwent(void)
406 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
412 pdb_context
->pdb_endsampwent(pdb_context
);
415 BOOL
pdb_getsampwent(SAM_ACCOUNT
*user
)
417 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
423 return pdb_context
->pdb_getsampwent(pdb_context
, user
);
426 BOOL
pdb_getsampwnam(SAM_ACCOUNT
*sam_acct
, const char *username
)
428 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
434 return pdb_context
->pdb_getsampwnam(pdb_context
, sam_acct
, username
);
437 BOOL
pdb_getsampwsid(SAM_ACCOUNT
*sam_acct
, DOM_SID
*sid
)
439 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
445 return pdb_context
->pdb_getsampwsid(pdb_context
, sam_acct
, sid
);
448 BOOL
pdb_add_sam_account(SAM_ACCOUNT
*sam_acct
)
450 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
456 return pdb_context
->pdb_add_sam_account(pdb_context
, sam_acct
);
459 BOOL
pdb_update_sam_account(SAM_ACCOUNT
*sam_acct
)
461 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
467 return pdb_context
->pdb_update_sam_account(pdb_context
, sam_acct
);
470 BOOL
pdb_delete_sam_account(SAM_ACCOUNT
*sam_acct
)
472 struct pdb_context
*pdb_context
= pdb_get_static_context(False
);
478 return pdb_context
->pdb_delete_sam_account(pdb_context
, sam_acct
);
481 #endif /* !defined(WITH_NISPLUS_SAM) */
483 /***************************************************************
484 Initialize the static context (at smbd startup etc).
486 If uninitialised, context will auto-init on first use.
487 ***************************************************************/
489 BOOL
initialize_password_db(BOOL reload
)
491 return (pdb_get_static_context(reload
) != NULL
);
495 NTSTATUS
make_pdb_methods(TALLOC_CTX
*mem_ctx
, PDB_METHODS
**methods
)
497 *methods
= talloc(mem_ctx
, sizeof(struct pdb_methods
));
500 return NT_STATUS_NO_MEMORY
;
503 ZERO_STRUCTP(*methods
);