source: vendor/current/source3/passdb/pdb_interface.c@ 414

Last change on this file since 414 was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 50.7 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2002
5 Copyright (C) Jelmer Vernooij 2002
6 Copyright (C) Simo Sorce 2003
7 Copyright (C) Volker Lendecke 2006
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "includes.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_PASSDB
27
28static_decl_pdb;
29
30static struct pdb_init_function_entry *backends = NULL;
31
32static void lazy_initialize_passdb(void)
33{
34 static bool initialized = False;
35 if(initialized) {
36 return;
37 }
38 static_init_pdb;
39 initialized = True;
40}
41
42static bool lookup_global_sam_rid(TALLOC_CTX *mem_ctx, uint32 rid,
43 const char **name,
44 enum lsa_SidType *psid_name_use,
45 union unid_t *unix_id);
46
47NTSTATUS smb_register_passdb(int version, const char *name, pdb_init_function init)
48{
49 struct pdb_init_function_entry *entry = backends;
50
51 if(version != PASSDB_INTERFACE_VERSION) {
52 DEBUG(0,("Can't register passdb backend!\n"
53 "You tried to register a passdb module with PASSDB_INTERFACE_VERSION %d, "
54 "while this version of samba uses version %d\n",
55 version,PASSDB_INTERFACE_VERSION));
56 return NT_STATUS_OBJECT_TYPE_MISMATCH;
57 }
58
59 if (!name || !init) {
60 return NT_STATUS_INVALID_PARAMETER;
61 }
62
63 DEBUG(5,("Attempting to register passdb backend %s\n", name));
64
65 /* Check for duplicates */
66 if (pdb_find_backend_entry(name)) {
67 DEBUG(0,("There already is a passdb backend registered with the name %s!\n", name));
68 return NT_STATUS_OBJECT_NAME_COLLISION;
69 }
70
71 entry = SMB_XMALLOC_P(struct pdb_init_function_entry);
72 entry->name = smb_xstrdup(name);
73 entry->init = init;
74
75 DLIST_ADD(backends, entry);
76 DEBUG(5,("Successfully added passdb backend '%s'\n", name));
77 return NT_STATUS_OK;
78}
79
80struct pdb_init_function_entry *pdb_find_backend_entry(const char *name)
81{
82 struct pdb_init_function_entry *entry = backends;
83
84 while(entry) {
85 if (strcmp(entry->name, name)==0) return entry;
86 entry = entry->next;
87 }
88
89 return NULL;
90}
91
92/*
93 * The event context for the passdb backend. I know this is a bad hack and yet
94 * another static variable, but our pdb API is a global thing per
95 * definition. The first use for this is the LDAP idle function, more might be
96 * added later.
97 *
98 * I don't feel too bad about this static variable, it replaces the
99 * smb_idle_event_list that used to exist in lib/module.c. -- VL
100 */
101
102static struct event_context *pdb_event_ctx;
103
104struct event_context *pdb_get_event_context(void)
105{
106 return pdb_event_ctx;
107}
108
109/******************************************************************
110 Make a pdb_methods from scratch
111 *******************************************************************/
112
113NTSTATUS make_pdb_method_name(struct pdb_methods **methods, const char *selected)
114{
115 char *module_name = smb_xstrdup(selected);
116 char *module_location = NULL, *p;
117 struct pdb_init_function_entry *entry;
118 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
119
120 lazy_initialize_passdb();
121
122 p = strchr(module_name, ':');
123
124 if (p) {
125 *p = 0;
126 module_location = p+1;
127 trim_char(module_location, ' ', ' ');
128 }
129
130 trim_char(module_name, ' ', ' ');
131
132
133 DEBUG(5,("Attempting to find a passdb backend to match %s (%s)\n", selected, module_name));
134
135 entry = pdb_find_backend_entry(module_name);
136
137 /* Try to find a module that contains this module */
138 if (!entry) {
139 DEBUG(2,("No builtin backend found, trying to load plugin\n"));
140 if(NT_STATUS_IS_OK(smb_probe_module("pdb", module_name)) && !(entry = pdb_find_backend_entry(module_name))) {
141 DEBUG(0,("Plugin is available, but doesn't register passdb backend %s\n", module_name));
142 SAFE_FREE(module_name);
143 return NT_STATUS_UNSUCCESSFUL;
144 }
145 }
146
147 /* No such backend found */
148 if(!entry) {
149 DEBUG(0,("No builtin nor plugin backend for %s found\n", module_name));
150 SAFE_FREE(module_name);
151 return NT_STATUS_INVALID_PARAMETER;
152 }
153
154 DEBUG(5,("Found pdb backend %s\n", module_name));
155
156 if ( !NT_STATUS_IS_OK( nt_status = entry->init(methods, module_location) ) ) {
157 DEBUG(0,("pdb backend %s did not correctly init (error was %s)\n",
158 selected, nt_errstr(nt_status)));
159 SAFE_FREE(module_name);
160 return nt_status;
161 }
162
163 SAFE_FREE(module_name);
164
165 DEBUG(5,("pdb backend %s has a valid init\n", selected));
166
167 return nt_status;
168}
169
170/******************************************************************
171 Return an already initialized pdb_methods structure
172*******************************************************************/
173
174static struct pdb_methods *pdb_get_methods_reload( bool reload )
175{
176 static struct pdb_methods *pdb = NULL;
177
178 if ( pdb && reload ) {
179 pdb->free_private_data( &(pdb->private_data) );
180 if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) {
181 char *msg = NULL;
182 if (asprintf(&msg, "pdb_get_methods_reload: "
183 "failed to get pdb methods for backend %s\n",
184 lp_passdb_backend()) > 0) {
185 smb_panic(msg);
186 } else {
187 smb_panic("pdb_get_methods_reload");
188 }
189 }
190 }
191
192 if ( !pdb ) {
193 if ( !NT_STATUS_IS_OK( make_pdb_method_name( &pdb, lp_passdb_backend() ) ) ) {
194 char *msg = NULL;
195 if (asprintf(&msg, "pdb_get_methods_reload: "
196 "failed to get pdb methods for backend %s\n",
197 lp_passdb_backend()) > 0) {
198 smb_panic(msg);
199 } else {
200 smb_panic("pdb_get_methods_reload");
201 }
202 }
203 }
204
205 return pdb;
206}
207
208static struct pdb_methods *pdb_get_methods(void)
209{
210 return pdb_get_methods_reload(False);
211}
212
213struct pdb_domain_info *pdb_get_domain_info(TALLOC_CTX *mem_ctx)
214{
215 struct pdb_methods *pdb = pdb_get_methods();
216 return pdb->get_domain_info(pdb, mem_ctx);
217}
218
219bool pdb_getsampwnam(struct samu *sam_acct, const char *username)
220{
221 struct pdb_methods *pdb = pdb_get_methods();
222 struct samu *for_cache;
223 const struct dom_sid *user_sid;
224
225 if (!NT_STATUS_IS_OK(pdb->getsampwnam(pdb, sam_acct, username))) {
226 return False;
227 }
228
229 for_cache = samu_new(NULL);
230 if (for_cache == NULL) {
231 return False;
232 }
233
234 if (!pdb_copy_sam_account(for_cache, sam_acct)) {
235 TALLOC_FREE(for_cache);
236 return False;
237 }
238
239 user_sid = pdb_get_user_sid(for_cache);
240
241 memcache_add_talloc(NULL, PDB_GETPWSID_CACHE,
242 data_blob_const(user_sid, sizeof(*user_sid)),
243 &for_cache);
244
245 return True;
246}
247
248/**********************************************************************
249**********************************************************************/
250
251bool guest_user_info( struct samu *user )
252{
253 struct passwd *pwd;
254 NTSTATUS result;
255 const char *guestname = lp_guestaccount();
256
257 if ( !(pwd = getpwnam_alloc(talloc_autofree_context(), guestname ) ) ) {
258 DEBUG(0,("guest_user_info: Unable to locate guest account [%s]!\n",
259 guestname));
260 return False;
261 }
262
263 result = samu_set_unix(user, pwd );
264
265 TALLOC_FREE( pwd );
266
267 return NT_STATUS_IS_OK( result );
268}
269
270/**********************************************************************
271**********************************************************************/
272
273bool pdb_getsampwsid(struct samu *sam_acct, const DOM_SID *sid)
274{
275 struct pdb_methods *pdb = pdb_get_methods();
276 uint32 rid;
277 void *cache_data;
278
279 /* hard code the Guest RID of 501 */
280
281 if ( !sid_peek_check_rid( get_global_sam_sid(), sid, &rid ) )
282 return False;
283
284 if ( rid == DOMAIN_USER_RID_GUEST ) {
285 DEBUG(6,("pdb_getsampwsid: Building guest account\n"));
286 return guest_user_info( sam_acct );
287 }
288
289 /* check the cache first */
290
291 cache_data = memcache_lookup_talloc(
292 NULL, PDB_GETPWSID_CACHE, data_blob_const(sid, sizeof(*sid)));
293
294 if (cache_data != NULL) {
295 struct samu *cache_copy = talloc_get_type_abort(
296 cache_data, struct samu);
297
298 return pdb_copy_sam_account(sam_acct, cache_copy);
299 }
300
301 return NT_STATUS_IS_OK(pdb->getsampwsid(pdb, sam_acct, sid));
302}
303
304static NTSTATUS pdb_default_create_user(struct pdb_methods *methods,
305 TALLOC_CTX *tmp_ctx, const char *name,
306 uint32 acb_info, uint32 *rid)
307{
308 struct samu *sam_pass;
309 NTSTATUS status;
310 struct passwd *pwd;
311
312 if ((sam_pass = samu_new(tmp_ctx)) == NULL) {
313 return NT_STATUS_NO_MEMORY;
314 }
315
316 if ( !(pwd = Get_Pwnam_alloc(tmp_ctx, name)) ) {
317 char *add_script = NULL;
318 int add_ret;
319 fstring name2;
320
321 if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') {
322 add_script = talloc_strdup(tmp_ctx,
323 lp_adduser_script());
324 } else {
325 add_script = talloc_strdup(tmp_ctx,
326 lp_addmachine_script());
327 }
328
329 if (!add_script || add_script[0] == '\0') {
330 DEBUG(3, ("Could not find user %s and no add script "
331 "defined\n", name));
332 return NT_STATUS_NO_SUCH_USER;
333 }
334
335 /* lowercase the username before creating the Unix account for
336 compatibility with previous Samba releases */
337 fstrcpy( name2, name );
338 strlower_m( name2 );
339 add_script = talloc_all_string_sub(tmp_ctx,
340 add_script,
341 "%u",
342 name2);
343 if (!add_script) {
344 return NT_STATUS_NO_MEMORY;
345 }
346 add_ret = smbrun(add_script,NULL);
347 DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the command `%s' gave %d\n",
348 add_script, add_ret));
349 if (add_ret == 0) {
350 smb_nscd_flush_user_cache();
351 }
352
353 flush_pwnam_cache();
354
355 pwd = Get_Pwnam_alloc(tmp_ctx, name);
356 }
357
358 /* we have a valid SID coming out of this call */
359
360 status = samu_alloc_rid_unix( sam_pass, pwd );
361
362 TALLOC_FREE( pwd );
363
364 if (!NT_STATUS_IS_OK(status)) {
365 DEBUG(3, ("pdb_default_create_user: failed to create a new user structure: %s\n", nt_errstr(status)));
366 return status;
367 }
368
369 if (!sid_peek_check_rid(get_global_sam_sid(),
370 pdb_get_user_sid(sam_pass), rid)) {
371 DEBUG(0, ("Could not get RID of fresh user\n"));
372 return NT_STATUS_INTERNAL_ERROR;
373 }
374
375 /* Use the username case specified in the original request */
376
377 pdb_set_username( sam_pass, name, PDB_SET );
378
379 /* Disable the account on creation, it does not have a reasonable password yet. */
380
381 acb_info |= ACB_DISABLED;
382
383 pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED);
384
385 status = pdb_add_sam_account(sam_pass);
386
387 TALLOC_FREE(sam_pass);
388
389 return status;
390}
391
392NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32 flags,
393 uint32 *rid)
394{
395 struct pdb_methods *pdb = pdb_get_methods();
396 return pdb->create_user(pdb, mem_ctx, name, flags, rid);
397}
398
399/****************************************************************************
400 Delete a UNIX user on demand.
401****************************************************************************/
402
403static int smb_delete_user(const char *unix_user)
404{
405 char *del_script = NULL;
406 int ret;
407
408 /* safety check */
409
410 if ( strequal( unix_user, "root" ) ) {
411 DEBUG(0,("smb_delete_user: Refusing to delete local system root account!\n"));
412 return -1;
413 }
414
415 del_script = talloc_strdup(talloc_tos(), lp_deluser_script());
416 if (!del_script || !*del_script) {
417 return -1;
418 }
419 del_script = talloc_all_string_sub(talloc_tos(),
420 del_script,
421 "%u",
422 unix_user);
423 if (!del_script) {
424 return -1;
425 }
426 ret = smbrun(del_script,NULL);
427 flush_pwnam_cache();
428 if (ret == 0) {
429 smb_nscd_flush_user_cache();
430 }
431 DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
432
433 return ret;
434}
435
436static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods,
437 TALLOC_CTX *mem_ctx,
438 struct samu *sam_acct)
439{
440 NTSTATUS status;
441 fstring username;
442
443 status = pdb_delete_sam_account(sam_acct);
444 if (!NT_STATUS_IS_OK(status)) {
445 return status;
446 }
447
448 /*
449 * Now delete the unix side ....
450 * note: we don't check if the delete really happened as the script is
451 * not necessary present and maybe the sysadmin doesn't want to delete
452 * the unix side
453 */
454
455 /* always lower case the username before handing it off to
456 external scripts */
457
458 fstrcpy( username, pdb_get_username(sam_acct) );
459 strlower_m( username );
460
461 smb_delete_user( username );
462
463 return status;
464}
465
466NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, struct samu *sam_acct)
467{
468 struct pdb_methods *pdb = pdb_get_methods();
469 uid_t uid = -1;
470
471 /* sanity check to make sure we don't delete root */
472
473 if ( !sid_to_uid( pdb_get_user_sid(sam_acct), &uid ) ) {
474 return NT_STATUS_NO_SUCH_USER;
475 }
476
477 if ( uid == 0 ) {
478 return NT_STATUS_ACCESS_DENIED;
479 }
480
481 return pdb->delete_user(pdb, mem_ctx, sam_acct);
482}
483
484NTSTATUS pdb_add_sam_account(struct samu *sam_acct)
485{
486 struct pdb_methods *pdb = pdb_get_methods();
487 return pdb->add_sam_account(pdb, sam_acct);
488}
489
490NTSTATUS pdb_update_sam_account(struct samu *sam_acct)
491{
492 struct pdb_methods *pdb = pdb_get_methods();
493
494 memcache_flush(NULL, PDB_GETPWSID_CACHE);
495
496 return pdb->update_sam_account(pdb, sam_acct);
497}
498
499NTSTATUS pdb_delete_sam_account(struct samu *sam_acct)
500{
501 struct pdb_methods *pdb = pdb_get_methods();
502
503 memcache_flush(NULL, PDB_GETPWSID_CACHE);
504
505 return pdb->delete_sam_account(pdb, sam_acct);
506}
507
508NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname)
509{
510 struct pdb_methods *pdb = pdb_get_methods();
511 uid_t uid;
512 NTSTATUS status;
513
514 memcache_flush(NULL, PDB_GETPWSID_CACHE);
515
516 /* sanity check to make sure we don't rename root */
517
518 if ( !sid_to_uid( pdb_get_user_sid(oldname), &uid ) ) {
519 return NT_STATUS_NO_SUCH_USER;
520 }
521
522 if ( uid == 0 ) {
523 return NT_STATUS_ACCESS_DENIED;
524 }
525
526 status = pdb->rename_sam_account(pdb, oldname, newname);
527
528 /* always flush the cache here just to be safe */
529 flush_pwnam_cache();
530
531 return status;
532}
533
534NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, bool success)
535{
536 struct pdb_methods *pdb = pdb_get_methods();
537 return pdb->update_login_attempts(pdb, sam_acct, success);
538}
539
540bool pdb_getgrsid(GROUP_MAP *map, DOM_SID sid)
541{
542 struct pdb_methods *pdb = pdb_get_methods();
543 return NT_STATUS_IS_OK(pdb->getgrsid(pdb, map, sid));
544}
545
546bool pdb_getgrgid(GROUP_MAP *map, gid_t gid)
547{
548 struct pdb_methods *pdb = pdb_get_methods();
549 return NT_STATUS_IS_OK(pdb->getgrgid(pdb, map, gid));
550}
551
552bool pdb_getgrnam(GROUP_MAP *map, const char *name)
553{
554 struct pdb_methods *pdb = pdb_get_methods();
555 return NT_STATUS_IS_OK(pdb->getgrnam(pdb, map, name));
556}
557
558static NTSTATUS pdb_default_create_dom_group(struct pdb_methods *methods,
559 TALLOC_CTX *mem_ctx,
560 const char *name,
561 uint32 *rid)
562{
563 DOM_SID group_sid;
564 struct group *grp;
565 fstring tmp;
566
567 grp = getgrnam(name);
568
569 if (grp == NULL) {
570 gid_t gid;
571
572 if (smb_create_group(name, &gid) != 0) {
573 return NT_STATUS_ACCESS_DENIED;
574 }
575
576 grp = getgrgid(gid);
577 }
578
579 if (grp == NULL) {
580 return NT_STATUS_ACCESS_DENIED;