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 static NTSTATUS context_getgrsid(struct pdb_context *context,
219 GROUP_MAP *map, DOM_SID sid, BOOL with_priv)
221 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
223 struct pdb_methods *curmethods;
225 DEBUG(0, ("invalid pdb_context specified!\n"));
228 curmethods = context->pdb_methods;
230 ret = curmethods->getgrsid(curmethods, map, sid, with_priv);
231 if (NT_STATUS_IS_OK(ret)) {
232 map->methods = curmethods;
235 curmethods = curmethods->next;
241 static NTSTATUS context_getgrgid(struct pdb_context *context,
242 GROUP_MAP *map, gid_t gid, BOOL with_priv)
244 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
246 struct pdb_methods *curmethods;
248 DEBUG(0, ("invalid pdb_context specified!\n"));
251 curmethods = context->pdb_methods;
253 ret = curmethods->getgrgid(curmethods, map, gid, with_priv);
254 if (NT_STATUS_IS_OK(ret)) {
255 map->methods = curmethods;
258 curmethods = curmethods->next;
264 static NTSTATUS context_getgrnam(struct pdb_context *context,
265 GROUP_MAP *map, char *name, BOOL with_priv)
267 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
269 struct pdb_methods *curmethods;
271 DEBUG(0, ("invalid pdb_context specified!\n"));
274 curmethods = context->pdb_methods;
276 ret = curmethods->getgrnam(curmethods, map, name, with_priv);
277 if (NT_STATUS_IS_OK(ret)) {
278 map->methods = curmethods;
281 curmethods = curmethods->next;
287 static NTSTATUS context_add_group_mapping_entry(struct pdb_context *context,
290 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
292 if ((!context) || (!context->pdb_methods)) {
293 DEBUG(0, ("invalid pdb_context specified!\n"));
297 return context->pdb_methods->add_group_mapping_entry(context->pdb_methods,
301 static NTSTATUS context_update_group_mapping_entry(struct pdb_context *context,
304 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
306 if ((!context) || (!context->pdb_methods)) {
307 DEBUG(0, ("invalid pdb_context specified!\n"));
312 pdb_methods->update_group_mapping_entry(context->pdb_methods, map);
315 static NTSTATUS context_delete_group_mapping_entry(struct pdb_context *context,
318 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
320 if ((!context) || (!context->pdb_methods)) {
321 DEBUG(0, ("invalid pdb_context specified!\n"));
326 pdb_methods->delete_group_mapping_entry(context->pdb_methods, sid);
329 static NTSTATUS context_enum_group_mapping(struct pdb_context *context,
330 enum SID_NAME_USE sid_name_use,
331 GROUP_MAP **rmap, int *num_entries,
332 BOOL unix_only, BOOL with_priv)
334 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
336 if ((!context) || (!context->pdb_methods)) {
337 DEBUG(0, ("invalid pdb_context specified!\n"));
341 return context->pdb_methods->enum_group_mapping(context->pdb_methods,
343 num_entries, unix_only,
347 /******************************************************************
348 Free and cleanup a pdb context, any associated data and anything
349 that the attached modules might have associated.
350 *******************************************************************/
352 static void free_pdb_context(struct pdb_context **context)
354 struct pdb_methods *pdb_selected = (*context)->pdb_methods;
356 while (pdb_selected){
357 if(pdb_selected->free_private_data)
358 pdb_selected->free_private_data(&(pdb_selected->private_data));
359 pdb_selected = pdb_selected->next;
362 talloc_destroy((*context)->mem_ctx);
366 /******************************************************************
367 Make a pdb_methods from scratch
368 *******************************************************************/
370 static NTSTATUS make_pdb_methods_name(struct pdb_methods **methods, struct pdb_context *context, const char *selected)
372 char *module_name = smb_xstrdup(selected);
373 char *module_location = NULL, *p;
374 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
377 p = strchr(module_name, ':');
381 module_location = p+1;
382 trim_string(module_location, " ", " ");
385 trim_string(module_name, " ", " ");
387 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name));
388 for (i = 0; builtin_pdb_init_functions[i].name; i++)
390 if (strequal(builtin_pdb_init_functions[i].name, module_name))
392 DEBUG(5,("Found pdb backend %s (at pos %d)\n", module_name, i));
393 nt_status = builtin_pdb_init_functions[i].init(context, methods, module_location);
394 if (NT_STATUS_IS_OK(nt_status)) {
395 DEBUG(5,("pdb backend %s has a valid init\n", selected));
397 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
399 SAFE_FREE(module_name);
401 break; /* unreached */
405 /* No such backend found */
406 SAFE_FREE(module_name);
407 return NT_STATUS_INVALID_PARAMETER;
410 /******************************************************************
411 Make a pdb_context from scratch.
412 *******************************************************************/
414 static NTSTATUS make_pdb_context(struct pdb_context **context)
418 mem_ctx = talloc_init_named("pdb_context internal allocation context");
421 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
422 return NT_STATUS_NO_MEMORY;
425 *context = talloc(mem_ctx, sizeof(**context));
427 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
428 return NT_STATUS_NO_MEMORY;
431 ZERO_STRUCTP(*context);
433 (*context)->mem_ctx = mem_ctx;
435 (*context)->pdb_setsampwent = context_setsampwent;
436 (*context)->pdb_endsampwent = context_endsampwent;
437 (*context)->pdb_getsampwent = context_getsampwent;
438 (*context)->pdb_getsampwnam = context_getsampwnam;
439 (*context)->pdb_getsampwsid = context_getsampwsid;
440 (*context)->pdb_add_sam_account = context_add_sam_account;
441 (*context)->pdb_update_sam_account = context_update_sam_account;
442 (*context)->pdb_delete_sam_account = context_delete_sam_account;
443 (*context)->pdb_getgrsid = context_getgrsid;
444 (*context)->pdb_getgrgid = context_getgrgid;
445 (*context)->pdb_getgrnam = context_getgrnam;
446 (*context)->pdb_add_group_mapping_entry = context_add_group_mapping_entry;
447 (*context)->pdb_update_group_mapping_entry = context_update_group_mapping_entry;
448 (*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry;
449 (*context)->pdb_enum_group_mapping = context_enum_group_mapping;
451 (*context)->free_fn = free_pdb_context;
457 /******************************************************************
458 Make a pdb_context, given an array of strings
459 *******************************************************************/
461 NTSTATUS make_pdb_context_list(struct pdb_context **context, char **selected)
464 struct pdb_methods *curmethods, *tmpmethods;
465 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
467 if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) {
472 /* Try to initialise pdb */
473 DEBUG(5,("Trying to load: %s\n", selected[i]));
474 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, *context, selected[i]))) {
475 DEBUG(1, ("Loading %s failed!\n", selected[i]));
476 free_pdb_context(context);
479 curmethods->parent = *context;
480 DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods);
487 /******************************************************************
488 Make a pdb_context, given a text string.
489 *******************************************************************/
491 NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected)
494 char **newsel = str_list_make(selected, NULL);
495 ret = make_pdb_context_list(context, newsel);
496 str_list_free(&newsel);
500 /******************************************************************
501 Return an already initialised pdb_context, to facilitate backward
502 compatibility (see functions below).
503 *******************************************************************/
505 static struct pdb_context *pdb_get_static_context(BOOL reload)
507 static struct pdb_context *pdb_context = NULL;
509 if ((pdb_context) && (reload)) {
510 pdb_context->free_fn(&pdb_context);
511 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
517 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
525 #if !defined(WITH_NISPLUS_SAM)
527 /******************************************************************
528 Backward compatibility functions for the original passdb interface
529 *******************************************************************/
531 BOOL pdb_setsampwent(BOOL update)
533 struct pdb_context *pdb_context = pdb_get_static_context(False);
539 return NT_STATUS_IS_OK(pdb_context->pdb_setsampwent(pdb_context, update));
542 void pdb_endsampwent(void)
544 struct pdb_context *pdb_context = pdb_get_static_context(False);
550 pdb_context->pdb_endsampwent(pdb_context);
553 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
555 struct pdb_context *pdb_context = pdb_get_static_context(False);
561 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwent(pdb_context, user));
564 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
566 struct pdb_context *pdb_context = pdb_get_static_context(False);
572 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwnam(pdb_context, sam_acct, username));
575 BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
577 struct pdb_context *pdb_context = pdb_get_static_context(False);
583 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwsid(pdb_context, sam_acct, sid));
586 BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct)
588 struct pdb_context *pdb_context = pdb_get_static_context(False);
594 return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct));
597 BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct)
599 struct pdb_context *pdb_context = pdb_get_static_context(False);
605 return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct));
608 BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct)
610 struct pdb_context *pdb_context = pdb_get_static_context(False);
616 return NT_STATUS_IS_OK(pdb_context->pdb_delete_sam_account(pdb_context, sam_acct));
619 BOOL pdb_getgrsid(GROUP_MAP *map, DOM_SID sid, BOOL with_priv)
621 struct pdb_context *pdb_context = pdb_get_static_context(False);
627 return NT_STATUS_IS_OK(pdb_context->
628 pdb_getgrsid(pdb_context, map, sid, with_priv));
631 BOOL pdb_getgrgid(GROUP_MAP *map, gid_t gid, BOOL with_priv)
633 struct pdb_context *pdb_context = pdb_get_static_context(False);
639 return NT_STATUS_IS_OK(pdb_context->
640 pdb_getgrgid(pdb_context, map, gid, with_priv));
643 BOOL pdb_getgrnam(GROUP_MAP *map, char *name, BOOL with_priv)
645 struct pdb_context *pdb_context = pdb_get_static_context(False);
651 return NT_STATUS_IS_OK(pdb_context->
652 pdb_getgrnam(pdb_context, map, name, with_priv));
655 BOOL pdb_add_group_mapping_entry(GROUP_MAP *map)
657 struct pdb_context *pdb_context = pdb_get_static_context(False);
663 return NT_STATUS_IS_OK(pdb_context->
664 pdb_add_group_mapping_entry(pdb_context, map));
667 BOOL pdb_update_group_mapping_entry(GROUP_MAP *map)
669 struct pdb_context *pdb_context = pdb_get_static_context(False);
675 return NT_STATUS_IS_OK(pdb_context->
676 pdb_update_group_mapping_entry(pdb_context, map));
679 BOOL pdb_delete_group_mapping_entry(DOM_SID sid)
681 struct pdb_context *pdb_context = pdb_get_static_context(False);
687 return NT_STATUS_IS_OK(pdb_context->
688 pdb_delete_group_mapping_entry(pdb_context, sid));
691 BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
692 int *num_entries, BOOL unix_only, BOOL with_priv)
694 struct pdb_context *pdb_context = pdb_get_static_context(False);
700 return NT_STATUS_IS_OK(pdb_context->
701 pdb_enum_group_mapping(pdb_context, sid_name_use,
702 rmap, num_entries, unix_only,
706 #endif /* !defined(WITH_NISPLUS_SAM) */
708 /***************************************************************
709 Initialize the static context (at smbd startup etc).
711 If uninitialised, context will auto-init on first use.
712 ***************************************************************/
714 BOOL initialize_password_db(BOOL reload)
716 return (pdb_get_static_context(reload) != NULL);
720 NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
722 *methods = talloc(mem_ctx, sizeof(struct pdb_methods));
725 return NT_STATUS_NO_MEMORY;
728 ZERO_STRUCTP(*methods);