3 # Unix SMB/CIFS implementation.
4 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """Support for reading Samba 3 data files."""
22 __docformat__
= "restructuredText"
24 REGISTRY_VALUE_PREFIX
= "SAMBA_REGVAL"
25 REGISTRY_DB_VERSION
= 1
32 def fetch_uint32(tdb
, key
):
38 return struct
.unpack("<L", data
)[0]
41 def fetch_int32(tdb
, key
):
47 return struct
.unpack("<l", data
)[0]
50 class TdbDatabase(object):
51 """Simple Samba 3 TDB database reader."""
52 def __init__(self
, file):
55 :param file: Path of the file to open.
57 self
.tdb
= tdb
.Tdb(file, flags
=os
.O_RDONLY
)
60 def _check_version(self
):
64 """Close resources associated with this object."""
68 class Registry(TdbDatabase
):
69 """Simple read-only support for reading the Samba3 registry.
71 :note: This object uses the same syntax for registry key paths as
72 Samba 3. This particular format uses forward slashes for key path
73 separators and abbreviations for the predefined key names.
74 e.g.: HKLM/Software/Bar.
77 """Return the number of keys."""
78 return len(self
.keys())
81 """Return list with all the keys."""
82 return [k
.rstrip("\x00") for k
in self
.tdb
.iterkeys() if not k
.startswith(REGISTRY_VALUE_PREFIX
)]
84 def subkeys(self
, key
):
85 """Retrieve the subkeys for the specified key.
88 :return: list with key names
90 data
= self
.tdb
.get("%s\x00" % key
)
93 (num
, ) = struct
.unpack("<L", data
[0:4])
94 keys
= data
[4:].split("\0")
97 assert len(keys
) == num
100 def values(self
, key
):
101 """Return a dictionary with the values set for a specific key.
103 :param key: Key to retrieve values for.
104 :return: Dictionary with value names as key, tuple with type and
106 data
= self
.tdb
.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX
, key
))
110 (num
, ) = struct
.unpack("<L", data
[0:4])
114 (name
, data
) = data
.split("\0", 1)
116 (type, ) = struct
.unpack("<L", data
[0:4])
118 (value_len
, ) = struct
.unpack("<L", data
[0:4])
121 ret
[name
] = (type, data
[:value_len
])
122 data
= data
[value_len
:]
127 class PolicyDatabase(TdbDatabase
):
128 """Samba 3 Account Policy database reader."""
129 def __init__(self
, file):
130 """Open a policy database
132 :param file: Path to the file to open.
134 super(PolicyDatabase
, self
).__init
__(file)
135 self
.min_password_length
= fetch_uint32(self
.tdb
, "min password length\x00")
136 self
.password_history
= fetch_uint32(self
.tdb
, "password history\x00")
137 self
.user_must_logon_to_change_password
= fetch_uint32(self
.tdb
, "user must logon to change pasword\x00")
138 self
.maximum_password_age
= fetch_uint32(self
.tdb
, "maximum password age\x00")
139 self
.minimum_password_age
= fetch_uint32(self
.tdb
, "minimum password age\x00")
140 self
.lockout_duration
= fetch_uint32(self
.tdb
, "lockout duration\x00")
141 self
.reset_count_minutes
= fetch_uint32(self
.tdb
, "reset count minutes\x00")
142 self
.bad_lockout_minutes
= fetch_uint32(self
.tdb
, "bad lockout minutes\x00")
143 self
.disconnect_time
= fetch_int32(self
.tdb
, "disconnect time\x00")
144 self
.refuse_machine_password_change
= fetch_uint32(self
.tdb
, "refuse machine password change\x00")
146 # FIXME: Read privileges as well
149 GROUPDB_DATABASE_VERSION_V1
= 1 # native byte format.
150 GROUPDB_DATABASE_VERSION_V2
= 2 # le format.
152 GROUP_PREFIX
= "UNIXGROUP/"
154 # Alias memberships are stored reverse, as memberships. The performance
155 # critical operation is to determine the aliases a SID is member of, not
156 # listing alias members. So we store a list of alias SIDs a SID is member of
157 # hanging of the member as key.
158 MEMBEROF_PREFIX
= "MEMBEROF/"
160 class GroupMappingDatabase(TdbDatabase
):
161 """Samba 3 group mapping database reader."""
162 def _check_version(self
):
163 assert fetch_int32(self
.tdb
, "INFO/version\x00") in (GROUPDB_DATABASE_VERSION_V1
, GROUPDB_DATABASE_VERSION_V2
)
166 """Retrieve the SIDs for the groups in this database.
168 :return: List with sids as strings.
170 for k
in self
.tdb
.iterkeys():
171 if k
.startswith(GROUP_PREFIX
):
172 yield k
[len(GROUP_PREFIX
):].rstrip("\0")
174 def get_group(self
, sid
):
175 """Retrieve the group mapping information for a particular group.
177 :param sid: SID of the group
178 :return: None if the group can not be found, otherwise
179 a tuple with gid, sid_name_use, the NT name and comment.
181 data
= self
.tdb
.get("%s%s\0" % (GROUP_PREFIX
, sid
))
184 (gid
, sid_name_use
) = struct
.unpack("<lL", data
[0:8])
185 (nt_name
, comment
, _
) = data
[8:].split("\0")
186 return (gid
, sid_name_use
, nt_name
, comment
)
189 """Retrieve the aliases in this database."""
190 for k
in self
.tdb
.iterkeys():
191 if k
.startswith(MEMBEROF_PREFIX
):
192 yield k
[len(MEMBEROF_PREFIX
):].rstrip("\0")
195 # High water mark keys
196 IDMAP_HWM_GROUP
= "GROUP HWM\0"
197 IDMAP_HWM_USER
= "USER HWM\0"
199 IDMAP_GROUP_PREFIX
= "GID "
200 IDMAP_USER_PREFIX
= "UID "
202 # idmap version determines auto-conversion
205 class IdmapDatabase(TdbDatabase
):
206 """Samba 3 ID map database reader."""
207 def _check_version(self
):
208 assert fetch_int32(self
.tdb
, "IDMAP_VERSION\0") == IDMAP_VERSION_V2
211 """Retrieve a list of all uids in this database."""
212 for k
in self
.tdb
.iterkeys():
213 if k
.startswith(IDMAP_USER_PREFIX
):
214 yield int(k
[len(IDMAP_USER_PREFIX
):].rstrip("\0"))
217 """Retrieve a list of all gids in this database."""
218 for k
in self
.tdb
.iterkeys():
219 if k
.startswith(IDMAP_GROUP_PREFIX
):
220 yield int(k
[len(IDMAP_GROUP_PREFIX
):].rstrip("\0"))
222 def get_user_sid(self
, uid
):
223 """Retrieve the SID associated with a particular uid.
225 :param uid: UID to retrieve SID for.
226 :return: A SID or None if no mapping was found.
228 data
= self
.tdb
.get("%s%d\0" % (IDMAP_USER_PREFIX
, uid
))
231 return data
.rstrip("\0")
233 def get_group_sid(self
, gid
):
234 data
= self
.tdb
.get("%s%d\0" % (IDMAP_GROUP_PREFIX
, gid
))
237 return data
.rstrip("\0")
239 def get_user_hwm(self
):
240 """Obtain the user high-water mark."""
241 return fetch_uint32(self
.tdb
, IDMAP_HWM_USER
)
243 def get_group_hwm(self
):
244 """Obtain the group high-water mark."""
245 return fetch_uint32(self
.tdb
, IDMAP_HWM_GROUP
)
248 class SecretsDatabase(TdbDatabase
):
249 """Samba 3 Secrets database reader."""
250 def get_auth_password(self
):
251 return self
.tdb
.get("SECRETS/AUTH_PASSWORD")
253 def get_auth_domain(self
):
254 return self
.tdb
.get("SECRETS/AUTH_DOMAIN")
256 def get_auth_user(self
):
257 return self
.tdb
.get("SECRETS/AUTH_USER")
259 def get_domain_guid(self
, host
):
260 return self
.tdb
.get("SECRETS/DOMGUID/%s" % host
)
263 for k
in self
.tdb
.iterkeys():
264 if k
.startswith("SECRETS/LDAP_BIND_PW/"):
265 yield k
[len("SECRETS/LDAP_BIND_PW/"):].rstrip("\0")
268 """Iterate over domains in this database.
270 :return: Iterator over the names of domains in this database.
272 for k
in self
.tdb
.iterkeys():
273 if k
.startswith("SECRETS/SID/"):
274 yield k
[len("SECRETS/SID/"):].rstrip("\0")
276 def get_ldap_bind_pw(self
, host
):
277 return self
.tdb
.get("SECRETS/LDAP_BIND_PW/%s" % host
)
279 def get_afs_keyfile(self
, host
):
280 return self
.tdb
.get("SECRETS/AFS_KEYFILE/%s" % host
)
282 def get_machine_sec_channel_type(self
, host
):
283 return fetch_uint32(self
.tdb
, "SECRETS/MACHINE_SEC_CHANNEL_TYPE/%s" % host
)
285 def get_machine_last_change_time(self
, host
):
286 return fetch_uint32(self
.tdb
, "SECRETS/MACHINE_LAST_CHANGE_TIME/%s" % host
)
288 def get_machine_password(self
, host
):
289 return self
.tdb
.get("SECRETS/MACHINE_PASSWORD/%s" % host
)
291 def get_machine_acc(self
, host
):
292 return self
.tdb
.get("SECRETS/$MACHINE.ACC/%s" % host
)
294 def get_domtrust_acc(self
, host
):
295 return self
.tdb
.get("SECRETS/$DOMTRUST.ACC/%s" % host
)
297 def trusted_domains(self
):
298 for k
in self
.tdb
.iterkeys():
299 if k
.startswith("SECRETS/$DOMTRUST.ACC/"):
300 yield k
[len("SECRETS/$DOMTRUST.ACC/"):].rstrip("\0")
302 def get_random_seed(self
):
303 return self
.tdb
.get("INFO/random_seed")
305 def get_sid(self
, host
):
306 return self
.tdb
.get("SECRETS/SID/%s" % host
.upper())
309 SHARE_DATABASE_VERSION_V1
= 1
310 SHARE_DATABASE_VERSION_V2
= 2
312 class ShareInfoDatabase(TdbDatabase
):
313 """Samba 3 Share Info database reader."""
314 def _check_version(self
):
315 assert fetch_int32(self
.tdb
, "INFO/version\0") in (SHARE_DATABASE_VERSION_V1
, SHARE_DATABASE_VERSION_V2
)
317 def get_secdesc(self
, name
):
318 """Obtain the security descriptor on a particular share.
320 :param name: Name of the share
322 secdesc
= self
.tdb
.get("SECDESC/%s" % name
)
323 # FIXME: Run ndr_pull_security_descriptor
327 class Shares(object):
328 """Container for share objects."""
329 def __init__(self
, lp
, shareinfo
):
331 self
.shareinfo
= shareinfo
334 """Number of shares."""
335 return len(self
.lp
) - 1
338 """Iterate over the share names."""
339 return self
.lp
.__iter
__()
342 ACB_DISABLED
= 0x00000001
343 ACB_HOMDIRREQ
= 0x00000002
344 ACB_PWNOTREQ
= 0x00000004
345 ACB_TEMPDUP
= 0x00000008
346 ACB_NORMAL
= 0x00000010
348 ACB_DOMTRUST
= 0x00000040
349 ACB_WSTRUST
= 0x00000080
350 ACB_SVRTRUST
= 0x00000100
351 ACB_PWNOEXP
= 0x00000200
352 ACB_AUTOLOCK
= 0x00000400
353 ACB_ENC_TXT_PWD_ALLOWED
= 0x00000800
354 ACB_SMARTCARD_REQUIRED
= 0x00001000
355 ACB_TRUSTED_FOR_DELEGATION
= 0x00002000
356 ACB_NOT_DELEGATED
= 0x00004000
357 ACB_USE_DES_KEY_ONLY
= 0x00008000
358 ACB_DONT_REQUIRE_PREAUTH
= 0x00010000
359 ACB_PW_EXPIRED
= 0x00020000
360 ACB_NO_AUTH_DATA_REQD
= 0x00080000
363 'N': ACB_PWNOTREQ
, # 'N'o password.
364 'D': ACB_DISABLED
, # 'D'isabled.
365 'H': ACB_HOMDIRREQ
, # 'H'omedir required.
366 'T': ACB_TEMPDUP
, # 'T'emp account.
367 'U': ACB_NORMAL
, # 'U'ser account (normal).
368 'M': ACB_MNS
, # 'M'NS logon user account. What is this ?
369 'W': ACB_WSTRUST
, # 'W'orkstation account.
370 'S': ACB_SVRTRUST
, # 'S'erver account.
371 'L': ACB_AUTOLOCK
, # 'L'ocked account.
372 'X': ACB_PWNOEXP
, # No 'X'piry on password
373 'I': ACB_DOMTRUST
, # 'I'nterdomain trust account.
377 def decode_acb(text
):
378 """Decode a ACB field.
380 :param text: ACB text
381 :return: integer with flags set.
383 assert not "[" in text
and not "]" in text
386 ret |
= acb_info_mapping
[x
]
390 class SAMUser(object):
393 :note: Unknown or unset fields are set to None.
395 def __init__(self
, name
, uid
=None, lm_password
=None, nt_password
=None, acct_ctrl
=None,
396 last_change_time
=None, nt_username
=None, fullname
=None, logon_time
=None, logoff_time
=None,
397 acct_desc
=None, group_rid
=None, bad_password_count
=None, logon_count
=None,
398 domain
=None, dir_drive
=None, munged_dial
=None, homedir
=None, logon_script
=None,
399 profile_path
=None, workstations
=None, kickoff_time
=None, bad_password_time
=None,
400 pass_last_set_time
=None, pass_can_change_time
=None, pass_must_change_time
=None,
401 user_rid
=None, unknown_6
=None, nt_password_history
=None,
402 unknown_str
=None, hours
=None, logon_divs
=None):
405 self
.lm_password
= lm_password
406 self
.nt_password
= nt_password
407 self
.acct_ctrl
= acct_ctrl
408 self
.pass_last_set_time
= last_change_time
409 self
.nt_username
= nt_username
410 self
.fullname
= fullname
411 self
.logon_time
= logon_time
412 self
.logoff_time
= logoff_time
413 self
.acct_desc
= acct_desc
414 self
.group_rid
= group_rid
415 self
.bad_password_count
= bad_password_count
416 self
.logon_count
= logon_count
418 self
.dir_drive
= dir_drive
419 self
.munged_dial
= munged_dial
420 self
.homedir
= homedir
421 self
.logon_script
= logon_script
422 self
.profile_path
= profile_path
423 self
.workstations
= workstations
424 self
.kickoff_time
= kickoff_time
425 self
.bad_password_time
= bad_password_time
426 self
.pass_can_change_time
= pass_can_change_time
427 self
.pass_must_change_time
= pass_must_change_time
428 self
.user_rid
= user_rid
429 self
.unknown_6
= unknown_6
430 self
.nt_password_history
= nt_password_history
431 self
.unknown_str
= unknown_str
433 self
.logon_divs
= logon_divs
435 def __eq__(self
, other
):
436 if not isinstance(other
, SAMUser
):
438 return self
.__dict
__ == other
.__dict
__
441 class SmbpasswdFile(object):
442 """Samba 3 smbpasswd file reader."""
443 def __init__(self
, file):
446 for l
in f
.readlines():
447 if len(l
) == 0 or l
[0] == "#":
448 continue # Skip comments and blank lines
453 last_change_time
= None
454 if parts
[2] == "NO PASSWORD":
455 acct_ctrl |
= ACB_PWNOTREQ
457 elif parts
[2][0] in ("*", "X"):
461 lm_password
= parts
[2]
463 if parts
[3][0] in ("*", "X"):
467 nt_password
= parts
[3]
469 if parts
[4][0] == '[':
470 assert "]" in parts
[4]
471 acct_ctrl |
= decode_acb(parts
[4][1:-1])
472 if parts
[5].startswith("LCT-"):
473 last_change_time
= int(parts
[5][len("LCT-"):], 16)
474 else: # old style file
475 if username
[-1] == "$":
476 acct_ctrl
&= ~ACB_NORMAL
477 acct_ctrl |
= ACB_WSTRUST
479 self
.users
[username
] = SAMUser(username
, uid
, lm_password
, nt_password
, acct_ctrl
, last_change_time
)
484 return len(self
.users
)
486 def __getitem__(self
, name
):
487 return self
.users
[name
]
490 return iter(self
.users
)
492 def close(self
): # For consistency
496 TDBSAM_FORMAT_STRING_V0
= "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
497 TDBSAM_FORMAT_STRING_V1
= "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
498 TDBSAM_FORMAT_STRING_V2
= "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
499 TDBSAM_USER_PREFIX
= "USER_"
502 class LdapSam(object):
503 """Samba 3 LDAP passdb backend reader."""
504 def __init__(self
, url
):
508 class TdbSam(TdbDatabase
):
509 """Samba 3 TDB passdb backend reader."""
510 def _check_version(self
):
511 self
.version
= fetch_uint32(self
.tdb
, "INFO/version\0") or 0
512 assert self
.version
in (0, 1, 2)
515 """Iterate over the usernames in this Tdb database."""
516 for k
in self
.tdb
.iterkeys():
517 if k
.startswith(TDBSAM_USER_PREFIX
):
518 yield k
[len(TDBSAM_USER_PREFIX
):].rstrip("\0")
522 def __getitem__(self
, name
):
523 data
= self
.tdb
["%s%s\0" % (TDBSAM_USER_PREFIX
, name
)]
526 def unpack_string(data
):
527 (length
, ) = struct
.unpack("<L", data
[:4])
531 return (data
[:length
].rstrip("\0"), data
[length
:])
533 def unpack_int32(data
):
534 (value
, ) = struct
.unpack("<l", data
[:4])
535 return (value
, data
[4:])
537 def unpack_uint32(data
):
538 (value
, ) = struct
.unpack("<L", data
[:4])
539 return (value
, data
[4:])
541 def unpack_uint16(data
):
542 (value
, ) = struct
.unpack("<H", data
[:2])
543 return (value
, data
[2:])
545 (logon_time
, data
) = unpack_int32(data
)
546 (logoff_time
, data
) = unpack_int32(data
)
547 (kickoff_time
, data
) = unpack_int32(data
)
550 (bad_password_time
, data
) = unpack_int32(data
)
551 if bad_password_time
!= 0:
552 user
.bad_password_time
= bad_password_time
553 (pass_last_set_time
, data
) = unpack_int32(data
)
554 (pass_can_change_time
, data
) = unpack_int32(data
)
555 (pass_must_change_time
, data
) = unpack_int32(data
)
558 user
.logon_time
= logon_time
559 user
.logoff_time
= logoff_time
560 user
.kickoff_time
= kickoff_time
561 if pass_last_set_time
!= 0:
562 user
.pass_last_set_time
= pass_last_set_time
563 user
.pass_can_change_time
= pass_can_change_time
565 (user
.username
, data
) = unpack_string(data
)
566 (user
.domain
, data
) = unpack_string(data
)
567 (user
.nt_username
, data
) = unpack_string(data
)
568 (user
.fullname
, data
) = unpack_string(data
)
569 (user
.homedir
, data
) = unpack_string(data
)
570 (user
.dir_drive
, data
) = unpack_string(data
)
571 (user
.logon_script
, data
) = unpack_string(data
)
572 (user
.profile_path
, data
) = unpack_string(data
)
573 (user
.acct_desc
, data
) = unpack_string(data
)
574 (user
.workstations
, data
) = unpack_string(data
)
575 (user
.unknown_str
, data
) = unpack_string(data
)
576 (user
.munged_dial
, data
) = unpack_string(data
)
578 (user
.user_rid
, data
) = unpack_int32(data
)
579 (user
.group_rid
, data
) = unpack_int32(data
)
581 (user
.lm_password
, data
) = unpack_string(data
)
582 (user
.nt_password
, data
) = unpack_string(data
)
585 (user
.nt_password_history
, data
) = unpack_string(data
)
587 (user
.acct_ctrl
, data
) = unpack_uint16(data
)
588 (_
, data
) = unpack_uint32(data
) # remove_me field
589 (user
.logon_divs
, data
) = unpack_uint16(data
)
590 (hours
, data
) = unpack_string(data
)
594 user
.hours
.append(ord(entry
) & (2 ** i
) == (2 ** i
))
595 (user
.bad_password_count
, data
) = unpack_uint16(data
)
596 (user
.logon_count
, data
) = unpack_uint16(data
)
597 (user
.unknown_6
, data
) = unpack_uint32(data
)
598 assert len(data
) == 0
602 def shellsplit(text
):
603 """Very simple shell-like line splitting.
605 :param text: Text to split.
606 :return: List with parts of the line as strings.
613 inquotes
= not inquotes
614 elif c
in ("\t", "\n", " ") and not inquotes
:
624 class WinsDatabase(object):
625 """Samba 3 WINS database reader."""
626 def __init__(self
, file):
629 assert f
.readline().rstrip("\n") == "VERSION 1 0"
630 for l
in f
.readlines():
631 if l
[0] == "#": # skip comments
633 entries
= shellsplit(l
.rstrip("\n"))
635 ttl
= int(entries
[1])
638 while "." in entries
[i
]:
639 ips
.append(entries
[i
])
641 nb_flags
= int(entries
[i
][:-1], 16)
642 assert not name
in self
.entries
, "Name %s exists twice" % name
643 self
.entries
[name
] = (ttl
, ips
, nb_flags
)
646 def __getitem__(self
, name
):
647 return self
.entries
[name
]
650 return len(self
.entries
)
653 return iter(self
.entries
)
656 """Return the entries in this WINS database."""
657 return self
.entries
.items()
659 def close(self
): # for consistency
663 class ParamFile(object):
664 """Simple smb.conf-compatible file parser
666 Does not use a parameter table, unlike the "normal".
669 def __init__(self
, sections
=None):
670 self
._sections
= sections
or {}
672 def _sanitize_name(self
, name
):
673 return name
.strip().lower().replace(" ","")
676 return "ParamFile(%r)" % self
._sections
678 def read(self
, filename
):
681 :param filename: Path to the file
684 for i
, l
in enumerate(open(filename
, 'r').xreadlines()):
688 if l
[0] == "[" and l
[-1] == "]":
689 section
= self
._sanitize
_name
(l
[1:-1])
690 self
._sections
.setdefault(section
, {})
692 (k
, v
) = l
.split("=", 1)
693 self
._sections
[section
][self
._sanitize
_name
(k
)] = v
695 raise Exception("Unable to parser line %d: %r" % (i
+1,l
))
697 def get(self
, param
, section
=None):
698 """Return the value of a parameter.
700 :param param: Parameter name
701 :param section: Section name, defaults to "global"
702 :return: parameter value as string if found, None otherwise.
706 section
= self
._sanitize
_name
(section
)
707 if not section
in self
._sections
:
709 param
= self
._sanitize
_name
(param
)
710 if not param
in self
._sections
[section
]:
712 return self
._sections
[section
][param
].strip()
714 def __getitem__(self
, section
):
715 return self
._sections
[section
]
717 def get_section(self
, section
):
718 return self
._sections
.get(section
)
720 def add_section(self
, section
):
721 self
._sections
[self
._sanitize
_name
(section
)] = {}
723 def set_string(self
, name
, value
):
724 self
._sections
["global"][name
] = value
726 def get_string(self
, name
):
727 return self
._sections
["global"].get(name
)
730 class Samba3(object):
731 """Samba 3 configuration and state data reader."""
732 def __init__(self
, libdir
, smbconfpath
):
733 """Open the configuration and data for a Samba 3 installation.
735 :param libdir: Library directory
736 :param smbconfpath: Path to the smb.conf file.
738 self
.smbconfpath
= smbconfpath
740 self
.lp
= ParamFile()
741 self
.lp
.read(self
.smbconfpath
)
743 def libdir_path(self
, path
):
744 if path
[0] == "/" or path
[0] == ".":
746 return os
.path
.join(self
.libdir
, path
)
751 def get_sam_db(self
):
753 backends
= (lp
.get("passdb backend") or "").split(" ")
754 if ":" in backends
[0]:
755 (name
, location
) = backends
[0].split(":", 2)
759 if name
== "smbpasswd":
760 return SmbpasswdFile(self
.libdir_path(location
or "smbpasswd"))
761 elif name
== "tdbsam":
762 return TdbSam(self
.libdir_path(location
or "passdb.tdb"))
763 elif name
== "ldapsam":
764 if location
is not None:
765 return LdapSam("ldap:%s" % location
)
766 return LdapSam(lp
.get("ldap server"))
768 raise NotImplementedError("unsupported passdb backend %s" % backends
[0])
770 def get_policy_db(self
):
771 return PolicyDatabase(self
.libdir_path("account_policy.tdb"))
773 def get_registry(self
):
774 return Registry(self
.libdir_path("registry.tdb"))
776 def get_secrets_db(self
):
777 return SecretsDatabase(self
.libdir_path("secrets.tdb"))
779 def get_shareinfo_db(self
):
780 return ShareInfoDatabase(self
.libdir_path("share_info.tdb"))
782 def get_idmap_db(self
):
783 return IdmapDatabase(self
.libdir_path("winbindd_idmap.tdb"))
785 def get_wins_db(self
):
786 return WinsDatabase(self
.libdir_path("wins.dat"))
788 def get_shares(self
):
789 return Shares(self
.get_conf(), self
.get_shareinfo_db())
791 def get_groupmapping_db(self
):
792 return GroupMappingDatabase(self
.libdir_path("group_mapping.tdb"))