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 */
30 /* Function to create a member of the pdb_methods list */
31 pdb_init_function init;
32 } builtin_pdb_init_functions[] = {
33 { "smbpasswd", pdb_init_smbpasswd },
34 { "smbpasswd_nua", pdb_init_smbpasswd_nua },
35 { "tdbsam", pdb_init_tdbsam },
36 { "tdbsam_nua", pdb_init_tdbsam_nua },
37 { "ldapsam", pdb_init_ldapsam },
38 { "ldapsam_nua", pdb_init_ldapsam_nua },
39 { "unixsam", pdb_init_unixsam },
40 { "nisplussam", pdb_init_nisplussam },
44 static struct pdb_init_function_entry *backends;
45 static void lazy_initialize_passdb(void);
47 static void lazy_initialize_passdb()
50 static BOOL initialised = False;
55 for(i = 0; builtin_pdb_init_functions[i].name; i++) {
56 smb_register_passdb(builtin_pdb_init_functions[i].name, builtin_pdb_init_functions[i].init, PASSDB_INTERFACE_VERSION);
61 BOOL smb_register_passdb(const char *name, pdb_init_function init, int version)
63 struct pdb_init_function_entry *entry = backends;
65 if(version != PASSDB_INTERFACE_VERSION)
68 DEBUG(5,("Attempting to register passdb backend %s\n", name));
70 /* Check for duplicates */
72 if(strcasecmp(name, entry->name) == 0) {
73 DEBUG(0,("There already is a passdb backend registered with the name %s!\n", name));
79 entry = smb_xmalloc(sizeof(struct pdb_init_function_entry));
83 DLIST_ADD(backends, entry);
84 DEBUG(5,("Successfully added passdb backend '%s'\n", name));
88 static NTSTATUS context_setsampwent(struct pdb_context *context, BOOL update)
90 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
93 DEBUG(0, ("invalid pdb_context specified!\n"));
97 context->pwent_methods = context->pdb_methods;
99 if (!context->pwent_methods) {
100 /* No passdbs at all */
104 while (NT_STATUS_IS_ERR(ret = context->pwent_methods->setsampwent(context->pwent_methods, update))) {
105 context->pwent_methods = context->pwent_methods->next;
106 if (context->pwent_methods == NULL)
107 return NT_STATUS_UNSUCCESSFUL;
112 static void context_endsampwent(struct pdb_context *context)
115 DEBUG(0, ("invalid pdb_context specified!\n"));
119 if (context->pwent_methods && context->pwent_methods->endsampwent)
120 context->pwent_methods->endsampwent(context->pwent_methods);
122 /* So we won't get strange data when calling getsampwent now */
123 context->pwent_methods = NULL;
126 static NTSTATUS context_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
128 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
130 if ((!context) || (!context->pwent_methods)) {
131 DEBUG(0, ("invalid pdb_context specified!\n"));
134 /* Loop until we find something useful */
135 while (NT_STATUS_IS_ERR(ret = context->pwent_methods->getsampwent(context->pwent_methods, user))) {
137 context->pwent_methods->endsampwent(context->pwent_methods);
139 context->pwent_methods = context->pwent_methods->next;
141 /* All methods are checked now. There are no more entries */
142 if (context->pwent_methods == NULL)
145 context->pwent_methods->setsampwent(context->pwent_methods, False);
147 user->methods = context->pwent_methods;
151 static NTSTATUS context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
153 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
155 struct pdb_methods *curmethods;
157 DEBUG(0, ("invalid pdb_context specified!\n"));
160 curmethods = context->pdb_methods;
162 if (NT_STATUS_IS_OK(ret = curmethods->getsampwnam(curmethods, sam_acct, username))) {
163 sam_acct->methods = curmethods;
166 curmethods = curmethods->next;
172 static NTSTATUS context_getsampwsid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
174 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
176 struct pdb_methods *curmethods;
178 DEBUG(0, ("invalid pdb_context specified!\n"));
182 curmethods = context->pdb_methods;
185 if (NT_STATUS_IS_OK(ret = curmethods->getsampwsid(curmethods, sam_acct, sid))) {
186 sam_acct->methods = curmethods;
189 curmethods = curmethods->next;
195 static NTSTATUS context_add_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
197 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
199 if ((!context) || (!context->pdb_methods)) {
200 DEBUG(0, ("invalid pdb_context specified!\n"));
204 /** @todo This is where a 're-read on add' should be done */
205 /* We now add a new account to the first database listed.
208 return context->pdb_methods->add_sam_account(context->pdb_methods, sam_acct);
211 static NTSTATUS context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
213 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
216 DEBUG(0, ("invalid pdb_context specified!\n"));
220 if (!sam_acct || !sam_acct->methods){
221 DEBUG(0, ("invalid sam_acct specified\n"));
225 /** @todo This is where a 're-read on update' should be done */
227 return sam_acct->methods->update_sam_account(sam_acct->methods, sam_acct);
230 static NTSTATUS context_delete_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
232 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
234 struct pdb_methods *pdb_selected;
236 DEBUG(0, ("invalid pdb_context specified!\n"));
240 if (!sam_acct->methods){
241 pdb_selected = context->pdb_methods;
242 /* There's no passdb backend specified for this account.
243 * Try to delete it in every passdb available
244 * Needed to delete accounts in smbpasswd that are not
247 while (pdb_selected){
248 if (NT_STATUS_IS_OK(ret = pdb_selected->delete_sam_account(pdb_selected, sam_acct))) {
251 pdb_selected = pdb_selected->next;
256 if (!sam_acct->methods->delete_sam_account){
257 DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n"));
261 return sam_acct->methods->delete_sam_account(sam_acct->methods, sam_acct);
264 static NTSTATUS context_getgrsid(struct pdb_context *context,
265 GROUP_MAP *map, DOM_SID sid, 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->getgrsid(curmethods, map, sid, with_priv);
277 if (NT_STATUS_IS_OK(ret)) {
278 map->methods = curmethods;
281 curmethods = curmethods->next;
287 static NTSTATUS context_getgrgid(struct pdb_context *context,
288 GROUP_MAP *map, gid_t gid, BOOL with_priv)
290 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
292 struct pdb_methods *curmethods;
294 DEBUG(0, ("invalid pdb_context specified!\n"));
297 curmethods = context->pdb_methods;
299 ret = curmethods->getgrgid(curmethods, map, gid, with_priv);
300 if (NT_STATUS_IS_OK(ret)) {
301 map->methods = curmethods;
304 curmethods = curmethods->next;
310 static NTSTATUS context_getgrnam(struct pdb_context *context,
311 GROUP_MAP *map, char *name, BOOL with_priv)
313 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
315 struct pdb_methods *curmethods;
317 DEBUG(0, ("invalid pdb_context specified!\n"));
320 curmethods = context->pdb_methods;
322 ret = curmethods->getgrnam(curmethods, map, name, with_priv);
323 if (NT_STATUS_IS_OK(ret)) {
324 map->methods = curmethods;
327 curmethods = curmethods->next;
333 static NTSTATUS context_add_group_mapping_entry(struct pdb_context *context,
336 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
338 if ((!context) || (!context->pdb_methods)) {
339 DEBUG(0, ("invalid pdb_context specified!\n"));
343 return context->pdb_methods->add_group_mapping_entry(context->pdb_methods,
347 static NTSTATUS context_update_group_mapping_entry(struct pdb_context *context,
350 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
352 if ((!context) || (!context->pdb_methods)) {
353 DEBUG(0, ("invalid pdb_context specified!\n"));
358 pdb_methods->update_group_mapping_entry(context->pdb_methods, map);
361 static NTSTATUS context_delete_group_mapping_entry(struct pdb_context *context,
364 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
366 if ((!context) || (!context->pdb_methods)) {
367 DEBUG(0, ("invalid pdb_context specified!\n"));
372 pdb_methods->delete_group_mapping_entry(context->pdb_methods, sid);
375 static NTSTATUS context_enum_group_mapping(struct pdb_context *context,
376 enum SID_NAME_USE sid_name_use,
377 GROUP_MAP **rmap, int *num_entries,
378 BOOL unix_only, BOOL with_priv)
380 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
382 if ((!context) || (!context->pdb_methods)) {
383 DEBUG(0, ("invalid pdb_context specified!\n"));
387 return context->pdb_methods->enum_group_mapping(context->pdb_methods,
389 num_entries, unix_only,
393 /******************************************************************
394 Free and cleanup a pdb context, any associated data and anything
395 that the attached modules might have associated.
396 *******************************************************************/
398 static void free_pdb_context(struct pdb_context **context)
400 struct pdb_methods *pdb_selected = (*context)->pdb_methods;
402 while (pdb_selected){
403 if(pdb_selected->free_private_data)
404 pdb_selected->free_private_data(&(pdb_selected->private_data));
405 pdb_selected = pdb_selected->next;
408 talloc_destroy((*context)->mem_ctx);
412 /******************************************************************
413 Make a pdb_methods from scratch
414 *******************************************************************/
416 static NTSTATUS make_pdb_methods_name(struct pdb_methods **methods, struct pdb_context *context, const char *selected)
418 char *module_name = smb_xstrdup(selected);
419 char *module_location = NULL, *p;
420 struct pdb_init_function_entry *entry;
421 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
423 lazy_initialize_passdb();
427 p = strchr(module_name, ':');
431 module_location = p+1;
432 trim_string(module_location, " ", " ");
435 trim_string(module_name, " ", " ");
437 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name));
439 if (strequal(entry->name, module_name))
441 DEBUG(5,("Found pdb backend %s\n", module_name));
442 nt_status = entry->init(context, methods, module_location);
443 if (NT_STATUS_IS_OK(nt_status)) {
444 DEBUG(5,("pdb backend %s has a valid init\n", selected));
446 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
448 SAFE_FREE(module_name);
450 break; /* unreached */
455 /* No such backend found */
456 SAFE_FREE(module_name);
457 return NT_STATUS_INVALID_PARAMETER;
460 /******************************************************************
461 Make a pdb_context from scratch.
462 *******************************************************************/
464 static NTSTATUS make_pdb_context(struct pdb_context **context)
468 mem_ctx = talloc_init("pdb_context internal allocation context");
471 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
472 return NT_STATUS_NO_MEMORY;
475 *context = talloc(mem_ctx, sizeof(**context));
477 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
478 return NT_STATUS_NO_MEMORY;
481 ZERO_STRUCTP(*context);
483 (*context)->mem_ctx = mem_ctx;
485 (*context)->pdb_setsampwent = context_setsampwent;
486 (*context)->pdb_endsampwent = context_endsampwent;
487 (*context)->pdb_getsampwent = context_getsampwent;
488 (*context)->pdb_getsampwnam = context_getsampwnam;
489 (*context)->pdb_getsampwsid = context_getsampwsid;
490 (*context)->pdb_add_sam_account = context_add_sam_account;
491 (*context)->pdb_update_sam_account = context_update_sam_account;
492 (*context)->pdb_delete_sam_account = context_delete_sam_account;
493 (*context)->pdb_getgrsid = context_getgrsid;
494 (*context)->pdb_getgrgid = context_getgrgid;
495 (*context)->pdb_getgrnam = context_getgrnam;
496 (*context)->pdb_add_group_mapping_entry = context_add_group_mapping_entry;
497 (*context)->pdb_update_group_mapping_entry = context_update_group_mapping_entry;
498 (*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry;
499 (*context)->pdb_enum_group_mapping = context_enum_group_mapping;
501 (*context)->free_fn = free_pdb_context;
507 /******************************************************************
508 Make a pdb_context, given an array of strings
509 *******************************************************************/
511 NTSTATUS make_pdb_context_list(struct pdb_context **context, const char **selected)
514 struct pdb_methods *curmethods, *tmpmethods;
515 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
517 if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) {
522 /* Try to initialise pdb */
523 DEBUG(5,("Trying to load: %s\n", selected[i]));
524 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, *context, selected[i]))) {
525 DEBUG(1, ("Loading %s failed!\n", selected[i]));
526 free_pdb_context(context);
529 curmethods->parent = *context;
530 DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods);
537 /******************************************************************
538 Make a pdb_context, given a text string.
539 *******************************************************************/
541 NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected)
544 char **newsel = str_list_make(selected, NULL);
545 ret = make_pdb_context_list(context, (const char **)newsel);
546 str_list_free(&newsel);
550 /******************************************************************
551 Return an already initialised pdb_context, to facilitate backward
552 compatibility (see functions below).
553 *******************************************************************/
555 static struct pdb_context *pdb_get_static_context(BOOL reload)
557 static struct pdb_context *pdb_context = NULL;
559 if ((pdb_context) && (reload)) {
560 pdb_context->free_fn(&pdb_context);
561 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
567 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
575 /******************************************************************
576 Backward compatibility functions for the original passdb interface
577 *******************************************************************/
579 BOOL pdb_setsampwent(BOOL update)
581 struct pdb_context *pdb_context = pdb_get_static_context(False);
587 return NT_STATUS_IS_OK(pdb_context->pdb_setsampwent(pdb_context, update));
590 void pdb_endsampwent(void)
592 struct pdb_context *pdb_context = pdb_get_static_context(False);
598 pdb_context->pdb_endsampwent(pdb_context);
601 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
603 struct pdb_context *pdb_context = pdb_get_static_context(False);
609 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwent(pdb_context, user));
612 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
614 struct pdb_context *pdb_context = pdb_get_static_context(False);
620 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwnam(pdb_context, sam_acct, username));
623 BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
625 struct pdb_context *pdb_context = pdb_get_static_context(False);
631 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwsid(pdb_context, sam_acct, sid));
634 BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct)
636 struct pdb_context *pdb_context = pdb_get_static_context(False);
642 return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct));
645 BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct)
647 struct pdb_context *pdb_context = pdb_get_static_context(False);
653 return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct));
656 BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct)
658 struct pdb_context *pdb_context = pdb_get_static_context(False);
664 return NT_STATUS_IS_OK(pdb_context->pdb_delete_sam_account(pdb_context, sam_acct));
667 BOOL pdb_getgrsid(GROUP_MAP *map, DOM_SID sid, BOOL with_priv)
669 struct pdb_context *pdb_context = pdb_get_static_context(False);
675 return NT_STATUS_IS_OK(pdb_context->
676 pdb_getgrsid(pdb_context, map, sid, with_priv));
679 BOOL pdb_getgrgid(GROUP_MAP *map, gid_t gid, BOOL with_priv)
681 struct pdb_context *pdb_context = pdb_get_static_context(False);
687 return NT_STATUS_IS_OK(pdb_context->
688 pdb_getgrgid(pdb_context, map, gid, with_priv));
691 BOOL pdb_getgrnam(GROUP_MAP *map, char *name, BOOL with_priv)
693 struct pdb_context *pdb_context = pdb_get_static_context(False);
699 return NT_STATUS_IS_OK(pdb_context->
700 pdb_getgrnam(pdb_context, map, name, with_priv));
703 BOOL pdb_add_group_mapping_entry(GROUP_MAP *map)
705 struct pdb_context *pdb_context = pdb_get_static_context(False);
711 return NT_STATUS_IS_OK(pdb_context->
712 pdb_add_group_mapping_entry(pdb_context, map));
715 BOOL pdb_update_group_mapping_entry(GROUP_MAP *map)
717 struct pdb_context *pdb_context = pdb_get_static_context(False);
723 return NT_STATUS_IS_OK(pdb_context->
724 pdb_update_group_mapping_entry(pdb_context, map));
727 BOOL pdb_delete_group_mapping_entry(DOM_SID sid)
729 struct pdb_context *pdb_context = pdb_get_static_context(False);
735 return NT_STATUS_IS_OK(pdb_context->
736 pdb_delete_group_mapping_entry(pdb_context, sid));
739 BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
740 int *num_entries, BOOL unix_only, BOOL with_priv)
742 struct pdb_context *pdb_context = pdb_get_static_context(False);
748 return NT_STATUS_IS_OK(pdb_context->
749 pdb_enum_group_mapping(pdb_context, sid_name_use,
750 rmap, num_entries, unix_only,
754 /***************************************************************
755 Initialize the static context (at smbd startup etc).
757 If uninitialised, context will auto-init on first use.
758 ***************************************************************/
760 BOOL initialize_password_db(BOOL reload)
762 return (pdb_get_static_context(reload) != NULL);
766 NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
768 *methods = talloc(mem_ctx, sizeof(struct pdb_methods));
771 return NT_STATUS_NO_MEMORY;
774 ZERO_STRUCTP(*methods);