sync with the sec_desc parsing fix from APP_HEAD. I will probably need
[Samba.git] / source / passdb / pdb_interface.c
blob3b0f54b2b3ac037d3126d969fefc30436fe18639
1 /*
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.
22 #include "includes.h"
24 #undef DBGC_CLASS
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 },
38 { NULL, NULL}
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"));
45 return False;
48 context->pwent_methods = context->pdb_methods;
50 if (!context->pwent_methods) {
51 /* No passdbs at all */
52 return True;
55 while (!(context->pwent_methods->setsampwent(context->pwent_methods, update))) {
56 context->pwent_methods = context->pwent_methods->next;
57 if (context->pwent_methods == NULL)
58 return False;
60 return True;
63 static void context_endsampwent(struct pdb_context *context)
65 if ((!context)){
66 DEBUG(0, ("invalid pdb_context specified!\n"));
67 return;
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"));
81 return False;
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)
94 return False;
96 if (!context->pwent_methods->setsampwent){
97 DEBUG(5, ("next backend does not implment setsampwent\n"));
98 return False;
101 context->pwent_methods->setsampwent(context->pwent_methods, False);
103 user->methods = context->pwent_methods;
104 return True;
107 static BOOL context_getsampwnam(struct pdb_context *context, SAM_ACCOUNT *sam_acct, const char *username)
109 struct pdb_methods *curmethods;
110 if ((!context)) {
111 DEBUG(0, ("invalid pdb_context specified!\n"));
112 return False;
114 curmethods = context->pdb_methods;
115 while (curmethods){
116 if (curmethods->getsampwnam && curmethods->getsampwnam(curmethods, sam_acct, username) == True){
117 sam_acct->methods = curmethods;
118 return True;
120 curmethods = curmethods->next;
123 return False;
126 static BOOL context_getsampwsid(struct pdb_context *context, SAM_ACCOUNT *sam_acct, DOM_SID *sid)
128 struct pdb_methods *curmethods;
129 if ((!context)) {
130 DEBUG(0, ("invalid pdb_context specified!\n"));
131 return False;
134 curmethods = context->pdb_methods;
136 while (curmethods){
137 if (curmethods->getsampwsid && curmethods->getsampwsid(curmethods, sam_acct, sid) == True){
138 sam_acct->methods = curmethods;
139 return True;
141 curmethods = curmethods->next;
144 return False;
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"));
151 return False;
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.
156 * Should we? */
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)
163 if (!context) {
164 DEBUG(0, ("invalid pdb_context specified!\n"));
165 return False;
168 if (!sam_acct || !sam_acct->methods){
169 DEBUG(0, ("invalid sam_acct specified\n"));
170 return False;
173 if (!sam_acct->methods->update_sam_account){
174 DEBUG(0, ("invalid sam_acct->methods\n"));
175 return False;
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;
186 if (!context) {
187 DEBUG(0, ("invalid pdb_context specified!\n"));
188 return False;
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
196 * in /etc/passwd.
198 while (pdb_selected){
199 if (pdb_selected->delete_sam_account && pdb_selected->delete_sam_account(pdb_selected, sam_acct)){
200 return True;
202 pdb_selected = pdb_selected->next;
204 return False;
207 if (!sam_acct->methods->delete_sam_account){
208 DEBUG(0,("invalid sam_acct->methods->delete_sam_account\n"));
209 return False;
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);
232 *context = NULL;
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;
244 int i;
246 p = strchr(module_name, ':');
248 if (p) {
249 *p = 0;
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));
265 } else {
266 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n", selected, nt_errstr(nt_status)));
268 SAFE_FREE(module_name);
269 return nt_status;
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)
285 TALLOC_CTX *mem_ctx;
287 mem_ctx = talloc_init_named("pdb_context internal allocation context");
289 if (!mem_ctx) {
290 DEBUG(0, ("make_pdb_context: talloc init failed!\n"));
291 return NT_STATUS_NO_MEMORY;
294 *context = talloc(mem_ctx, sizeof(**context));
295 if (!*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;
315 return NT_STATUS_OK;
319 /******************************************************************
320 Make a pdb_context, given an array of strings
321 *******************************************************************/
323 NTSTATUS make_pdb_context_list(struct pdb_context **context, char **selected)
325 int i = 0;
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))) {
330 return nt_status;
333 while (selected[i]){
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);
339 return nt_status;
341 curmethods->parent = *context;
342 DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods);
343 i++;
346 return NT_STATUS_OK;
349 /******************************************************************
350 Make a pdb_context, given a text string.
351 *******************************************************************/
353 NTSTATUS make_pdb_context_string(struct pdb_context **context, const char *selected)
355 NTSTATUS ret;
356 char **newsel = str_list_make(selected);
357 ret = make_pdb_context_list(context, newsel);
358 str_list_free(&newsel);
359 return ret;
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()))) {
374 return NULL;
378 if (!pdb_context) {
379 if (!NT_STATUS_IS_OK(make_pdb_context_list(&pdb_context, lp_passdb_backend()))) {
380 return NULL;
384 return pdb_context;
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);
397 if (!pdb_context) {
398 return 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);
408 if (!pdb_context) {
409 return;
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);
419 if (!pdb_context) {
420 return 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);
430 if (!pdb_context) {
431 return 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);
441 if (!pdb_context) {
442 return 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);
452 if (!pdb_context) {
453 return 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);
463 if (!pdb_context) {
464 return 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);
474 if (!pdb_context) {
475 return 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));
499 if (!*methods) {
500 return NT_STATUS_NO_MEMORY;
503 ZERO_STRUCTP(*methods);
505 return NT_STATUS_OK;