s4-tests: register new unit tests
[Samba/ekacnet.git] / source4 / scripting / python / samba / samba3.py
blob987367990d4863b3422bda82ec8c2987a97208f9
1 #!/usr/bin/python
3 # Unix SMB/CIFS implementation.
4 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
5 #
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
27 import os
28 import struct
29 import tdb
32 def fetch_uint32(tdb, key):
33 try:
34 data = tdb[key]
35 except KeyError:
36 return None
37 assert len(data) == 4
38 return struct.unpack("<L", data)[0]
41 def fetch_int32(tdb, key):
42 try:
43 data = tdb[key]
44 except KeyError:
45 return None
46 assert len(data) == 4
47 return struct.unpack("<l", data)[0]
50 class TdbDatabase(object):
51 """Simple Samba 3 TDB database reader."""
52 def __init__(self, file):
53 """Open a file.
55 :param file: Path of the file to open.
56 """
57 self.tdb = tdb.Tdb(file, flags=os.O_RDONLY)
58 self._check_version()
60 def _check_version(self):
61 pass
63 def close(self):
64 """Close resources associated with this object."""
65 self.tdb.close()
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.
75 """
76 def __len__(self):
77 """Return the number of keys."""
78 return len(self.keys())
80 def keys(self):
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.
87 :param key: Key path.
88 :return: list with key names
89 """
90 data = self.tdb.get("%s\x00" % key)
91 if data is None:
92 return []
93 (num, ) = struct.unpack("<L", data[0:4])
94 keys = data[4:].split("\0")
95 assert keys[-1] == ""
96 keys.pop()
97 assert len(keys) == num
98 return keys
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
105 data as value."""
106 data = self.tdb.get("%s/%s\x00" % (REGISTRY_VALUE_PREFIX, key))
107 if data is None:
108 return {}
109 ret = {}
110 (num, ) = struct.unpack("<L", data[0:4])
111 data = data[4:]
112 for i in range(num):
113 # Value name
114 (name, data) = data.split("\0", 1)
116 (type, ) = struct.unpack("<L", data[0:4])
117 data = data[4:]
118 (value_len, ) = struct.unpack("<L", data[0:4])
119 data = data[4:]
121 ret[name] = (type, data[:value_len])
122 data = data[value_len:]
124 return ret
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)
165 def groupsids(self):
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))
182 if data is None:
183 return data
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)
188 def aliases(self):
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
203 IDMAP_VERSION_V2 = 2
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
210 def uids(self):
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"))
216 def gids(self):
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))
229 if data is None:
230 return data
231 return data.rstrip("\0")
233 def get_group_sid(self, gid):
234 data = self.tdb.get("%s%d\0" % (IDMAP_GROUP_PREFIX, gid))
235 if data is None:
236 return data
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)
262 def ldap_dns(self):
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")
267 def domains(self):
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
324 return secdesc
327 class Shares(object):
328 """Container for share objects."""
329 def __init__(self, lp, shareinfo):
330 self.lp = lp
331 self.shareinfo = shareinfo
333 def __len__(self):
334 """Number of shares."""
335 return len(self.lp) - 1
337 def __iter__(self):
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
347 ACB_MNS = 0x00000020
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
362 acb_info_mapping = {
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.
374 ' ': 0
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
384 ret = 0
385 for x in text:
386 ret |= acb_info_mapping[x]
387 return ret
390 class SAMUser(object):
391 """Samba 3 SAM User.
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):
403 self.username = name
404 self.uid = uid
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
417 self.domain = domain
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
432 self.hours = hours
433 self.logon_divs = logon_divs
435 def __eq__(self, other):
436 if not isinstance(other, SAMUser):
437 return False
438 return self.__dict__ == other.__dict__
441 class SmbpasswdFile(object):
442 """Samba 3 smbpasswd file reader."""
443 def __init__(self, file):
444 self.users = {}
445 f = open(file, 'r')
446 for l in f.readlines():
447 if len(l) == 0 or l[0] == "#":
448 continue # Skip comments and blank lines
449 parts = l.split(":")
450 username = parts[0]
451 uid = int(parts[1])
452 acct_ctrl = 0
453 last_change_time = None
454 if parts[2] == "NO PASSWORD":
455 acct_ctrl |= ACB_PWNOTREQ
456 lm_password = None
457 elif parts[2][0] in ("*", "X"):
458 # No password set
459 lm_password = None
460 else:
461 lm_password = parts[2]
463 if parts[3][0] in ("*", "X"):
464 # No password set
465 nt_password = None
466 else:
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)
481 f.close()
483 def __len__(self):
484 return len(self.users)
486 def __getitem__(self, name):
487 return self.users[name]
489 def __iter__(self):
490 return iter(self.users)
492 def close(self): # For consistency
493 pass
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):
505 self.ldap_url = 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)
514 def usernames(self):
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")
520 __iter__ = usernames
522 def __getitem__(self, name):
523 data = self.tdb["%s%s\0" % (TDBSAM_USER_PREFIX, name)]
524 user = SAMUser(name)
526 def unpack_string(data):
527 (length, ) = struct.unpack("<L", data[:4])
528 data = data[4:]
529 if length == 0:
530 return (None, data)
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)
549 if self.version > 0:
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)
557 if logon_time != 0:
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)
584 if self.version > 1:
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)
591 user.hours = []
592 for entry in hours:
593 for i in range(8):
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
599 return user
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.
608 ret = list()
609 inquotes = False
610 current = ""
611 for c in text:
612 if c == "\"":
613 inquotes = not inquotes
614 elif c in ("\t", "\n", " ") and not inquotes:
615 ret.append(current)
616 current = ""
617 else:
618 current += c
619 if current != "":
620 ret.append(current)
621 return ret
624 class WinsDatabase(object):
625 """Samba 3 WINS database reader."""
626 def __init__(self, file):
627 self.entries = {}
628 f = open(file, 'r')
629 assert f.readline().rstrip("\n") == "VERSION 1 0"
630 for l in f.readlines():
631 if l[0] == "#": # skip comments
632 continue
633 entries = shellsplit(l.rstrip("\n"))
634 name = entries[0]
635 ttl = int(entries[1])
636 i = 2
637 ips = []
638 while "." in entries[i]:
639 ips.append(entries[i])
640 i+=1
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)
644 f.close()
646 def __getitem__(self, name):
647 return self.entries[name]
649 def __len__(self):
650 return len(self.entries)
652 def __iter__(self):
653 return iter(self.entries)
655 def items(self):
656 """Return the entries in this WINS database."""
657 return self.entries.items()
659 def close(self): # for consistency
660 pass
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(" ","")
675 def __repr__(self):
676 return "ParamFile(%r)" % self._sections
678 def read(self, filename):
679 """Read a file.
681 :param filename: Path to the file
683 section = None
684 for i, l in enumerate(open(filename, 'r').xreadlines()):
685 l = l.strip()
686 if not l or l[0] == '#' or l[0] == ';':
687 continue
688 if l[0] == "[" and l[-1] == "]":
689 section = self._sanitize_name(l[1:-1])
690 self._sections.setdefault(section, {})
691 elif "=" in l:
692 (k, v) = l.split("=", 1)
693 self._sections[section][self._sanitize_name(k)] = v
694 else:
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.
704 if section is None:
705 section = "global"
706 section = self._sanitize_name(section)
707 if not section in self._sections:
708 return None
709 param = self._sanitize_name(param)
710 if not param in self._sections[section]:
711 return None
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
739 self.libdir = libdir
740 self.lp = ParamFile()
741 self.lp.read(self.smbconfpath)
743 def libdir_path(self, path):
744 if path[0] == "/" or path[0] == ".":
745 return path
746 return os.path.join(self.libdir, path)
748 def get_conf(self):
749 return self.lp
751 def get_sam_db(self):
752 lp = self.get_conf()
753 backends = (lp.get("passdb backend") or "").split(" ")
754 if ":" in backends[0]:
755 (name, location) = backends[0].split(":", 2)
756 else:
757 name = backends[0]
758 location = None
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"))
767 else:
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"))