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 { "guest", pdb_init_guestsam },
41 { "nisplussam", pdb_init_nisplussam },
45 static struct pdb_init_function_entry *backends;
46 static void lazy_initialize_passdb(void);
48 static void lazy_initialize_passdb()
51 static BOOL initialised = False;
56 for(i = 0; builtin_pdb_init_functions[i].name; i++) {
57 smb_register_passdb(builtin_pdb_init_functions[i].name, builtin_pdb_init_functions[i].init, PASSDB_INTERFACE_VERSION);
62 BOOL smb_register_passdb(const char *name, pdb_init_function init, int version)
64 struct pdb_init_function_entry *entry = backends;
66 if(version != PASSDB_INTERFACE_VERSION)
69 DEBUG(5,("Attempting to register passdb backend %s\n", name));
71 /* Check for duplicates */
73 if(strcasecmp(name, entry->name) == 0) {
74 DEBUG(0,("There already is a passdb backend registered with the name %s!\n", name));
80 entry = smb_xmalloc(sizeof(struct pdb_init_function_entry));
84 DLIST_ADD(backends, entry);
85 DEBUG(5,("Successfully added passdb backend '%s'\n", name));
89 struct pdb_init_function_entry *pdb_find_backend_entry(const char *name)
91 struct pdb_init_function_entry *entry = backends;
94 if (strequal(entry->name, name)) return entry;
101 static NTSTATUS context_setsampwent(struct pdb_context *context, BOOL update)
103 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
106 DEBUG(0, ("invalid pdb_context specified!\n"));
110 context->pwent_methods = context->pdb_methods;
112 if (!context->pwent_methods) {
113 /* No passdbs at all */
117 while (NT_STATUS_IS_ERR(ret = context->pwent_methods->setsampwent(context->pwent_methods, update))) {
118 context->pwent_methods = context->pwent_methods->next;
119 if (context->pwent_methods == NULL)
120 return NT_STATUS_UNSUCCESSFUL;
125 static void context_endsampwent(struct pdb_context *context)
128 DEBUG(0, ("invalid pdb_context specified!\n"));
132 if (context->pwent_methods && context->pwent_methods->endsampwent)
133 context->pwent_methods->endsampwent(context->pwent_methods);
135 /* So we won't get strange data when calling getsampwent now */
136 context->pwent_methods = NULL;
139 static NTSTATUS context_getsampwent(struct pdb_context *context, SAM_ACCOUNT *user)
141 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
143 if ((!context) || (!context->pwent_methods)) {
144 DEBUG(0, ("invalid pdb_context specified!\n"));
147 /* Loop until we find something useful */
148 while (NT_STATUS_IS_ERR(ret = context->pwent_methods->getsampwent(context->pwent_methods, user))) {
150 context->pwent_methods->endsampwent(context->pwent_methods);
152 context->pwent_methods = context->pwent_methods->next;
154 /* All methods are checked now. There are no more entries */
155 if (context->pwent_methods == NULL)
158 context->pwent_methods->setsampwent(context->pwent_methods, False);
160 user->methods = context->pwent_methods;
164 static NTSTATUS context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
166 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
168 struct pdb_methods *curmethods;
170 DEBUG(0, ("invalid pdb_context specified!\n"));
173 curmethods = context->pdb_methods;
175 if (NT_STATUS_IS_OK(ret = curmethods->getsampwnam(curmethods, sam_acct, username))) {
176 sam_acct->methods = curmethods;
179 curmethods = curmethods->next;
185 static NTSTATUS context_getsampwsid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
187 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
189 struct pdb_methods *curmethods;
191 DEBUG(0, ("invalid pdb_context specified!\n"));
195 curmethods = context->pdb_methods;
198 if (NT_STATUS_IS_OK(ret = curmethods->getsampwsid(curmethods, sam_acct, sid))) {
199 sam_acct->methods = curmethods;
202 curmethods = curmethods->next;
208 static NTSTATUS context_add_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
210 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
212 if ((!context) || (!context->pdb_methods)) {
213 DEBUG(0, ("invalid pdb_context specified!\n"));
217 /** @todo This is where a 're-read on add' should be done */
218 /* We now add a new account to the first database listed.
221 return context->pdb_methods->add_sam_account(context->pdb_methods, sam_acct);
224 static NTSTATUS context_update_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
226 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
229 DEBUG(0, ("invalid pdb_context specified!\n"));
233 if (!sam_acct || !sam_acct->methods){
234 DEBUG(0, ("invalid sam_acct specified\n"));
238 /** @todo This is where a 're-read on update' should be done */
240 return sam_acct->methods->update_sam_account(sam_acct->methods, sam_acct);
243 static NTSTATUS context_delete_sam_account(struct pdb_context *context, SAM_ACCOUNT *sam_acct)
245 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
247 struct pdb_methods *pdb_selected;
249 DEBUG(0, ("invalid pdb_context specified!\n"));
253 if (!sam_acct->methods){
254 pdb_selected = context->pdb_methods;
255 /* There's no passdb backend specified for this account.
256 * Try to delete it in every passdb available
257 * Needed to delete accounts in smbpasswd that are not
260 while (pdb_selected){
261 if (NT_STATUS_IS_OK(ret = pdb_selected->delete_sam_account(pdb_selected, sam_acct))) {
264 pdb_selected = pdb_selected->next;
269 if (!sam_acct->methods->delete_sam_account){
270 DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n"));
274 return sam_acct->methods->delete_sam_account(sam_acct->methods, sam_acct);
277 static NTSTATUS context_getgrsid(struct pdb_context *context,
278 GROUP_MAP *map, DOM_SID sid, BOOL with_priv)
280 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
282 struct pdb_methods *curmethods;
284 DEBUG(0, ("invalid pdb_context specified!\n"));
287 curmethods = context->pdb_methods;
289 ret = curmethods->getgrsid(curmethods, map, sid, with_priv);
290 if (NT_STATUS_IS_OK(ret)) {
291 map->methods = curmethods;
294 curmethods = curmethods->next;
300 static NTSTATUS context_getgrgid(struct pdb_context *context,
301 GROUP_MAP *map, gid_t gid, BOOL with_priv)
303 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
305 struct pdb_methods *curmethods;
307 DEBUG(0, ("invalid pdb_context specified!\n"));
310 curmethods = context->pdb_methods;
312 ret = curmethods->getgrgid(curmethods, map, gid, with_priv);
313 if (NT_STATUS_IS_OK(ret)) {
314 map->methods = curmethods;
317 curmethods = curmethods->next;
323 static NTSTATUS context_getgrnam(struct pdb_context *context,
324 GROUP_MAP *map, char *name, BOOL with_priv)
326 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
328 struct pdb_methods *curmethods;
330 DEBUG(0, ("invalid pdb_context specified!\n"));
333 curmethods = context->pdb_methods;
335 ret = curmethods->getgrnam(curmethods, map, name, with_priv);
336 if (NT_STATUS_IS_OK(ret)) {
337 map->methods = curmethods;
340 curmethods = curmethods->next;
346 static NTSTATUS context_add_group_mapping_entry(struct pdb_context *context,
349 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
351 if ((!context) || (!context->pdb_methods)) {
352 DEBUG(0, ("invalid pdb_context specified!\n"));
356 return context->pdb_methods->add_group_mapping_entry(context->pdb_methods,
360 static NTSTATUS context_update_group_mapping_entry(struct pdb_context *context,
363 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
365 if ((!context) || (!context->pdb_methods)) {
366 DEBUG(0, ("invalid pdb_context specified!\n"));
371 pdb_methods->update_group_mapping_entry(context->pdb_methods, map);
374 static NTSTATUS context_delete_group_mapping_entry(struct pdb_context *context,
377 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
379 if ((!context) || (!context->pdb_methods)) {
380 DEBUG(0, ("invalid pdb_context specified!\n"));
385 pdb_methods->delete_group_mapping_entry(context->pdb_methods, sid);
388 static NTSTATUS context_enum_group_mapping(struct pdb_context *context,
389 enum SID_NAME_USE sid_name_use,
390 GROUP_MAP **rmap, int *num_entries,
391 BOOL unix_only, BOOL with_priv)
393 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
395 if ((!context) || (!context->pdb_methods)) {
396 DEBUG(0, ("invalid pdb_context specified!\n"));
400 return context->pdb_methods->enum_group_mapping(context->pdb_methods,
402 num_entries, unix_only,
406 /******************************************************************
407 Free and cleanup a pdb context, any associated data and anything
408 that the attached modules might have associated.
409 *******************************************************************/
411 static void free_pdb_context(struct pdb_context **context)
413 struct pdb_methods *pdb_selected = (*context)->pdb_methods;
415 while (pdb_selected){
416 if(pdb_selected->free_private_data)
417 pdb_selected->free_private_data(&(pdb_selected->private_data));
418 pdb_selected = pdb_selected->next;
421 talloc_destroy((*context)->mem_ctx);
425 /******************************************************************
426 Make a pdb_methods from scratch
427 *******************************************************************/
429 static NTSTATUS make_pdb_methods_name(struct pdb_methods **methods, struct pdb_context *context, const char *selected)
431 char *module_name = smb_xstrdup(selected);
432 char *module_location = NULL, *p;
433 struct pdb_init_function_entry *entry;
434 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
436 lazy_initialize_passdb();
438 p = strchr(module_name, ':');
442 module_location = p+1;
443 trim_string(module_location, " ", " ");
446 trim_string(module_name, " ", " ");
449 DEBUG(5,("Attempting to find an passdb backend to match %s (%s)\n", selected, module_name));
451 entry = pdb_find_backend_entry(module_name);
453 /* Try to find a module that contains this module */
455 smb_probe_module("passdb", module_name);
456 entry = pdb_find_backend_entry(module_name);
459 /* No such backend found */
461 SAFE_FREE(module_name);
462 return NT_STATUS_INVALID_PARAMETER;
465 DEBUG(5,("Found pdb backend %s\n", module_name));
466 nt_status = entry->init(context, methods, module_location);
467 if (NT_STATUS_IS_OK(nt_status)) {
468 DEBUG(5,("pdb backend %s has a valid init\n", selected));
470 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
472 SAFE_FREE(module_name);
476 /******************************************************************
477 Make a pdb_context from scratch.
478 *******************************************************************/
480 static NTSTATUS make_pdb_context(struct pdb_context **context)
484 mem_ctx = talloc_init("pdb_context internal allocation context");
487 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
488 return NT_STATUS_NO_MEMORY;
491 *context = talloc(mem_ctx, sizeof(**context));
493 DEBUG(0, ("make_pdb_context: talloc failed!\n"));
494 return NT_STATUS_NO_MEMORY;
497 ZERO_STRUCTP(*context);
499 (*context)->mem_ctx = mem_ctx;
501 (*context)->pdb_setsampwent = context_setsampwent;
502 (*context)->pdb_endsampwent = context_endsampwent;
503 (*context)->pdb_getsampwent = context_getsampwent;
504 (*context)->pdb_getsampwnam = context_getsampwnam;
505 (*context)->pdb_getsampwsid = context_getsampwsid;
506 (*context)->pdb_add_sam_account = context_add_sam_account;
507 (*context)->pdb_update_sam_account = context_update_sam_account;
508 (*context)->pdb_delete_sam_account = context_delete_sam_account;
509 (*context)->pdb_getgrsid = context_getgrsid;
510 (*context)->pdb_getgrgid = context_getgrgid;
511 (*context)->pdb_getgrnam = context_getgrnam;
512 (*context)->pdb_add_group_mapping_entry = context_add_group_mapping_entry;
513 (*context)->pdb_update_group_mapping_entry = context_update_group_mapping_entry;
514 (*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry;
515 (*context)->pdb_enum_group_mapping = context_enum_group_mapping;
517 (*context)->free_fn = free_pdb_context;
523 /******************************************************************
524 Make a pdb_context, given an array of strings
525 *******************************************************************/
527 NTSTATUS make_pdb_context_list(struct pdb_context **context, const char **selected)
530 struct pdb_methods *curmethods, *tmpmethods;
531 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
533 if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) {
538 /* Try to initialise pdb */
539 DEBUG(5,("Trying to load: %s\n", selected[i]));
540 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods_name(&curmethods, *context, selected[i]))) {
541 DEBUG(1, ("Loading %s failed!\n", selected[i]));
542 free_pdb_context(context);
545 curmethods->parent = *context;
546 DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods);
553 /******************************************************************
554 Make a pdb_context, given a text string.
555 *******************************************************************/
557 NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected)
560 char **newsel = str_list_make(selected, NULL);
561 ret = make_pdb_context_list(context, (const char **)newsel);
562 str_list_free(&newsel);
566 /******************************************************************
567 Return an already initialised pdb_context, to facilitate backward
568 compatibility (see functions below).
569 *******************************************************************/
571 static struct pdb_context *pdb_get_static_context(BOOL reload)
573 static struct pdb_context *pdb_context = NULL;
575 if ((pdb_context) && (reload)) {
576 pdb_context->free_fn(&pdb_context);
577 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
583 if (NT_STATUS_IS_ERR(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
591 /******************************************************************
592 Backward compatibility functions for the original passdb interface
593 *******************************************************************/
595 BOOL pdb_setsampwent(BOOL update)
597 struct pdb_context *pdb_context = pdb_get_static_context(False);
603 return NT_STATUS_IS_OK(pdb_context->pdb_setsampwent(pdb_context, update));
606 void pdb_endsampwent(void)
608 struct pdb_context *pdb_context = pdb_get_static_context(False);
614 pdb_context->pdb_endsampwent(pdb_context);
617 BOOL pdb_getsampwent(SAM_ACCOUNT *user)
619 struct pdb_context *pdb_context = pdb_get_static_context(False);
625 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwent(pdb_context, user));
628 BOOL pdb_getsampwnam(SAM_ACCOUNT *sam_acct, const char *username)
630 struct pdb_context *pdb_context = pdb_get_static_context(False);
636 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwnam(pdb_context, sam_acct, username));
639 BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
641 struct pdb_context *pdb_context = pdb_get_static_context(False);
647 return NT_STATUS_IS_OK(pdb_context->pdb_getsampwsid(pdb_context, sam_acct, sid));
650 BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct)
652 struct pdb_context *pdb_context = pdb_get_static_context(False);
658 return NT_STATUS_IS_OK(pdb_context->pdb_add_sam_account(pdb_context, sam_acct));
661 BOOL pdb_update_sam_account(SAM_ACCOUNT *sam_acct)
663 struct pdb_context *pdb_context = pdb_get_static_context(False);
669 return NT_STATUS_IS_OK(pdb_context->pdb_update_sam_account(pdb_context, sam_acct));
672 BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct)
674 struct pdb_context *pdb_context = pdb_get_static_context(False);
680 return NT_STATUS_IS_OK(pdb_context->pdb_delete_sam_account(pdb_context, sam_acct));
683 BOOL pdb_getgrsid(GROUP_MAP *map, DOM_SID sid, BOOL with_priv)
685 struct pdb_context *pdb_context = pdb_get_static_context(False);
691 return NT_STATUS_IS_OK(pdb_context->
692 pdb_getgrsid(pdb_context, map, sid, with_priv));
695 BOOL pdb_getgrgid(GROUP_MAP *map, gid_t gid, BOOL with_priv)
697 struct pdb_context *pdb_context = pdb_get_static_context(False);
703 return NT_STATUS_IS_OK(pdb_context->
704 pdb_getgrgid(pdb_context, map, gid, with_priv));
707 BOOL pdb_getgrnam(GROUP_MAP *map, char *name, BOOL with_priv)
709 struct pdb_context *pdb_context = pdb_get_static_context(False);
715 return NT_STATUS_IS_OK(pdb_context->
716 pdb_getgrnam(pdb_context, map, name, with_priv));
719 BOOL pdb_add_group_mapping_entry(GROUP_MAP *map)
721 struct pdb_context *pdb_context = pdb_get_static_context(False);
727 return NT_STATUS_IS_OK(pdb_context->
728 pdb_add_group_mapping_entry(pdb_context, map));
731 BOOL pdb_update_group_mapping_entry(GROUP_MAP *map)
733 struct pdb_context *pdb_context = pdb_get_static_context(False);
739 return NT_STATUS_IS_OK(pdb_context->
740 pdb_update_group_mapping_entry(pdb_context, map));
743 BOOL pdb_delete_group_mapping_entry(DOM_SID sid)
745 struct pdb_context *pdb_context = pdb_get_static_context(False);
751 return NT_STATUS_IS_OK(pdb_context->
752 pdb_delete_group_mapping_entry(pdb_context, sid));
755 BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
756 int *num_entries, BOOL unix_only, BOOL with_priv)
758 struct pdb_context *pdb_context = pdb_get_static_context(False);
764 return NT_STATUS_IS_OK(pdb_context->
765 pdb_enum_group_mapping(pdb_context, sid_name_use,
766 rmap, num_entries, unix_only,
770 /***************************************************************
771 Initialize the static context (at smbd startup etc).
773 If uninitialised, context will auto-init on first use.
774 ***************************************************************/
776 BOOL initialize_password_db(BOOL reload)
778 return (pdb_get_static_context(reload) != NULL);
782 /***************************************************************************
783 Default implementations of some functions.
784 ****************************************************************************/
786 static NTSTATUS pdb_default_getsampwnam (struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname)
788 return NT_STATUS_NO_SUCH_USER;
791 static NTSTATUS pdb_default_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
793 return NT_STATUS_NO_SUCH_USER;
796 static NTSTATUS pdb_default_add_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *newpwd)
798 DEBUG(0,("this backend (%s) should not be listed as the first passdb backend! You can't add users to it.\n", methods->name));
799 return NT_STATUS_NOT_IMPLEMENTED;
802 static NTSTATUS pdb_default_update_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *newpwd)
804 return NT_STATUS_NOT_IMPLEMENTED;
807 static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *pwd)
809 return NT_STATUS_NOT_IMPLEMENTED;
812 static NTSTATUS pdb_default_setsampwent(struct pdb_methods *methods, BOOL update)
814 return NT_STATUS_NOT_IMPLEMENTED;
817 static NTSTATUS pdb_default_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT *user)
819 return NT_STATUS_NOT_IMPLEMENTED;
822 static void pdb_default_endsampwent(struct pdb_methods *methods)
824 return; /* NT_STATUS_NOT_IMPLEMENTED; */
827 NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
829 *methods = talloc(mem_ctx, sizeof(struct pdb_methods));
832 return NT_STATUS_NO_MEMORY;
835 ZERO_STRUCTP(*methods);
837 (*methods)->setsampwent = pdb_default_setsampwent;
838 (*methods)->endsampwent = pdb_default_endsampwent;
839 (*methods)->getsampwent = pdb_default_getsampwent;
840 (*methods)->getsampwnam = pdb_default_getsampwnam;
841 (*methods)->getsampwsid = pdb_default_getsampwsid;
842 (*methods)->add_sam_account = pdb_default_add_sam_account;
843 (*methods)->update_sam_account = pdb_default_update_sam_account;
844 (*methods)->delete_sam_account = pdb_default_delete_sam_account;
846 (*methods)->getgrsid = pdb_default_getgrsid;
847 (*methods)->getgrgid = pdb_default_getgrgid;
848 (*methods)->getgrnam = pdb_default_getgrnam;
849 (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry;
850 (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry;
851 (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry;
852 (*methods)->enum_group_mapping = pdb_default_enum_group_mapping;