def add_activedirectory_conf(client, smb4_conf): try: ad = Struct( client.call('datastore.query', 'directoryservice.ActiveDirectory', None, {'get': True})) ad.ds_type = 1 # FIXME: DS_TYPE_ACTIVEDIRECTORY = 1 except: return try: os.makedirs(cachedir) os.chmod(cachedir, 0o755) except: pass ad_workgroup = None try: fad = Struct(client.call('notifier.directoryservice', 'AD')) ad_workgroup = fad.netbiosname.upper() except: return confset2(smb4_conf, "workgroup = %s", ad_workgroup) confset2(smb4_conf, "realm = %s", ad.ad_domainname.upper()) confset1(smb4_conf, "security = ADS") confset1(smb4_conf, "client use spnego = yes") confset1(smb4_conf, "local master = no") confset1(smb4_conf, "domain master = no") confset1(smb4_conf, "preferred master = no") confset2(smb4_conf, "ads dns update = %s", "yes" if ad.ad_allow_dns_updates else "no") confset1(smb4_conf, "winbind cache time = 7200") confset1(smb4_conf, "winbind offline logon = yes") confset1(smb4_conf, "winbind enum users = yes") confset1(smb4_conf, "winbind enum groups = yes") confset1(smb4_conf, "winbind nested groups = yes") confset2(smb4_conf, "winbind use default domain = %s", "yes" if ad.ad_use_default_domain else "no") confset1(smb4_conf, "winbind refresh tickets = yes") if ad.ad_nss_info: confset2(smb4_conf, "winbind nss info = %s", ad.ad_nss_info) idmap = Struct( client.call('notifier.ds_get_idmap_object', ad.ds_type, ad.id, ad.ad_idmap_backend)) configure_idmap_backend(client, smb4_conf, idmap, ad_workgroup) confset2(smb4_conf, "allow trusted domains = %s", "yes" if ad.ad_allow_trusted_doms else "no") confset2(smb4_conf, "client ldap sasl wrapping = %s", ad.ad_ldap_sasl_wrapping) confset1(smb4_conf, "template shell = /bin/sh") cifs_homedir = "%s/%%D/%%U" % get_cifs_homedir(client) confset2(smb4_conf, "template homedir = %s", cifs_homedir)
def get_samba_config_data(client): samba_config = [] cifs_config = Struct( client.call('datastore.query', 'services.cifs', None, {'get': True})) ad_config = Struct( client.call('datastore.query', 'directoryservice.activedirectory', None, {'get': True})) default_idmap_config = Struct( client.call('datastore.query', 'directoryservice.idmap_tdb', None, {'get': True})) idmap_backend_call = "directoryservice.idmap_%s" % ad_config.ad_idmap_backend try: idmap_config = Struct( client.call('datastore.query', idmap_backend_call, None, {'get': True})) except: print("failed to get idmap data via middleware calls") return False for item in [cifs_config, ad_config, idmap_config, default_idmap_config]: samba_config.append(item) return samba_config
def main(): client = Client() cifs_config = Struct( client.call('datastore.query', 'services.cifs', None, {'get': True})) krb_config = Struct( client.call('datastore.query', 'services.cifs', None, {'get': True})) if not validate_hosts(cifs_config): print("restarting ix-hostname service") service_launcher("ix-hostname", "quietstart") # validate_klist("krb_config.krb_realm") service_launcher("ix-kerberos", "quietstart") service_launcher("ix-nsswitch", "quietstart") if not service_launcher("ix-kinit", "status"): if not service_launcher("ix-kinit", "quietstart"): print("ix-kinit failed") service_launcher("ix-pre-samba", "quietstart") service_launcher("ix-activedirectory", "quietstart") service_launcher("samba_server", "restart") service_launcher("ix-pam", "quietstart") service_launcher("ix-cache", "quietstart")
def add_activedirectory_conf(client, smb4_conf): try: ad = Struct(client.call('datastore.query', 'directoryservice.ActiveDirectory', None, {'get': True})) ad.ds_type = 1 # FIXME: DS_TYPE_ACTIVEDIRECTORY = 1 except: return cachedir = "/var/tmp/.cache/.samba" try: os.makedirs(cachedir) os.chmod(cachedir, 0755) except: pass ad_workgroup = None try: fad = Struct(client.call('notifier.directoryservice', 'AD')) ad_workgroup = fad.netbiosname.upper() except: return confset2(smb4_conf, "workgroup = %s", ad_workgroup) confset2(smb4_conf, "realm = %s", ad.ad_domainname.upper()) confset1(smb4_conf, "security = ADS") confset1(smb4_conf, "client use spnego = yes") confset2(smb4_conf, "cache directory = %s", cachedir) confset1(smb4_conf, "local master = no") confset1(smb4_conf, "domain master = no") confset1(smb4_conf, "preferred master = no") confset2(smb4_conf, "ads dns update = %s", "yes" if ad.ad_allow_dns_updates else "no") confset1(smb4_conf, "winbind cache time = 7200") confset1(smb4_conf, "winbind offline logon = yes") confset1(smb4_conf, "winbind enum users = yes") confset1(smb4_conf, "winbind enum groups = yes") confset1(smb4_conf, "winbind nested groups = yes") confset2(smb4_conf, "winbind use default domain = %s", "yes" if ad.ad_use_default_domain else "no") confset1(smb4_conf, "winbind refresh tickets = yes") if ad.ad_nss_info: confset2(smb4_conf, "winbind nss info = %s", ad.ad_nss_info) idmap = Struct(client.call('notifier.ds_get_idmap_object', ad.ds_type, ad.id, ad.ad_idmap_backend)) configure_idmap_backend(client, smb4_conf, idmap, ad_workgroup) confset2(smb4_conf, "allow trusted domains = %s", "yes" if ad.ad_allow_trusted_doms else "no") confset2(smb4_conf, "client ldap sasl wrapping = %s", ad.ad_ldap_sasl_wrapping) confset1(smb4_conf, "template shell = /bin/sh") confset2(smb4_conf, "template homedir = %s", "/home/%D/%U" if not ad.ad_use_default_domain else "/home/%U")
def add_nt4_conf(client, smb4_conf): # TODO: These are unused, will they be at some point? # rid_range_start = 20000 # rid_range_end = 20000000 try: nt4 = Struct( client.call('datastore.query', 'directoryservice.nt4', None, {'get': True})) nt4.ds_type = 4 # FIXME: DS_TYPE_NT4 = 4 except: return dc_ip = None try: answers = resolver.query(nt4.nt4_dcname, 'A') dc_ip = answers[0] except Exception as e: log.debug("resolver query for {0}'s A record failed with {1}".format( nt4.nt4_dcname, e)) log_traceback(log=log) dc_ip = nt4.nt4_dcname nt4_workgroup = nt4.nt4_workgroup.upper() with open("/usr/local/etc/lmhosts", "w") as f: f.write("%s\t%s\n" % (dc_ip, nt4.nt4_dcname.upper())) confset2(smb4_conf, "workgroup = %s", nt4_workgroup) confset1(smb4_conf, "security = domain") confset1(smb4_conf, "password server = *") idmap = Struct( client.call('notifier.ds_get_idmap_object', nt4.ds_type, nt4.id, nt4.nt4_idmap_backend)) configure_idmap_backend(client, smb4_conf, idmap, nt4_workgroup) confset1(smb4_conf, "winbind cache time = 7200") confset1(smb4_conf, "winbind offline logon = yes") confset1(smb4_conf, "winbind enum users = yes") confset1(smb4_conf, "winbind enum groups = yes") confset1(smb4_conf, "winbind nested groups = yes") confset2(smb4_conf, "winbind use default domain = %s", "yes" if nt4.nt4_use_default_domain else "no") confset1(smb4_conf, "template shell = /bin/sh") confset1(smb4_conf, "local master = no") confset1(smb4_conf, "domain master = no") confset1(smb4_conf, "preferred master = no")
def add_nt4_conf(client, smb4_conf): # TODO: These are unused, will they be at some point? # rid_range_start = 20000 # rid_range_end = 20000000 try: nt4 = Struct(client.call('datastore.query', 'directoryservice.nt4', None, {'get': True})) nt4.ds_type = 4 # FIXME: DS_TYPE_NT4 = 4 except: return dc_ip = None try: answers = resolver.query(nt4.nt4_dcname, 'A') dc_ip = answers[0] except Exception as e: log.debug( "resolver query for {0}'s A record failed with {1}".format(nt4.nt4_dcname, e) ) log_traceback(log=log) dc_ip = nt4.nt4_dcname nt4_workgroup = nt4.nt4_workgroup.upper() with open("/usr/local/etc/lmhosts", "w") as f: f.write("%s\t%s\n" % (dc_ip, nt4.nt4_dcname.upper())) confset2(smb4_conf, "workgroup = %s", nt4_workgroup) confset1(smb4_conf, "security = domain") confset1(smb4_conf, "password server = *") idmap = Struct(client.call('notifier.ds_get_idmap_object', nt4.ds_type, nt4.id, nt4.nt4_idmap_backend)) configure_idmap_backend(client, smb4_conf, idmap, nt4_workgroup) confset1(smb4_conf, "winbind cache time = 7200") confset1(smb4_conf, "winbind offline logon = yes") confset1(smb4_conf, "winbind enum users = yes") confset1(smb4_conf, "winbind enum groups = yes") confset1(smb4_conf, "winbind nested groups = yes") confset2( smb4_conf, "winbind use default domain = %s", "yes" if nt4.nt4_use_default_domain else "no" ) confset1(smb4_conf, "template shell = /bin/sh") confset1(smb4_conf, "local master = no") confset1(smb4_conf, "domain master = no") confset1(smb4_conf, "preferred master = no")
def get_groups(client): _groups = {} groups = client.call('datastore.query', 'account.bsdGroups', [('bsdgrp_builtin', '=', False)]) for g in groups: g = Struct(g) key = str(g.bsdgrp_group) _groups[key] = [] members = client.call('datastore.query', 'account.bsdGroupMembership', [('bsdgrpmember_group', '=', g.id)]) for m in members: m = Struct(m) if m.bsdgrpmember_user: _groups[key].append(str(m.bsdgrpmember_user.bsdusr_username)) return _groups
def add_domaincontroller_conf(client, smb4_conf): try: dc = Struct( client.call('datastore.query', 'services.DomainController', None, {'get': True})) cifs = Struct(client.call('cifs.config')) except: return # server_services = get_server_services() # dcerpc_endpoint_servers = get_dcerpc_endpoint_servers() confset2(smb4_conf, "netbios name = %s", cifs.netbiosname.upper()) if cifs.cifs_srv_netbiosalias: confset2(smb4_conf, "netbios aliases = %s", cifs.cifs_srv_netbiosalias.upper()) confset2(smb4_conf, "workgroup = %s", dc.dc_domain.upper()) confset2(smb4_conf, "realm = %s", dc.dc_realm) confset2(smb4_conf, "dns forwarder = %s", dc.dc_dns_forwarder) confset1(smb4_conf, "idmap_ldb:use rfc2307 = yes") # confset2(smb4_conf, "server services = %s", # string.join(server_services, ',').rstrip(',')) # confset2(smb4_conf, "dcerpc endpoint servers = %s", # string.join(dcerpc_endpoint_servers, ',').rstrip(',')) ipv4_addrs = [] if cifs.cifs_srv_bindip: for i in cifs.cifs_srv_bindip: try: socket.inet_aton(i) ipv4_addrs.append(i) except: pass else: interfaces = client.call('notifier.choices', 'IPChoices', [True, False]) for i in interfaces: try: socket.inet_aton(i[0]) ipv4_addrs.append(i[0]) except: pass with open("/usr/local/etc/lmhosts", "w") as f: for ipv4 in ipv4_addrs: f.write("%s\t%s\n" % (ipv4, dc.dc_domain.upper()))
def generate_smb4_system_shares(client, smb4_shares): if client.call('notifier.common', 'system', 'domaincontroller_enabled'): try: dc = Struct( client.call('datastore.query', 'services.DomainController', None, {'get': True})) sysvol_path = "/var/db/samba4/sysvol" for share in ["sysvol", "netlogon"]: confset1(smb4_shares, "\n") confset1(smb4_shares, "[%s]" % (share), space=0) if share == "sysvol": path = sysvol_path else: path = "%s/%s/scripts" % (sysvol_path, dc.dc_realm.lower()) confset1(smb4_shares, "path = %s" % (path)) confset1(smb4_shares, "read only = no") vfs_objects = [] extend_vfs_objects_for_zfs(path, vfs_objects) config_share_for_vfs_objects(smb4_shares, vfs_objects) config_share_for_nfs4(smb4_shares) config_share_for_zfs(smb4_shares) except: pass
def idmap_backend_rfc2307(client): try: ad = Struct(client.call('datastore.query', 'directoryservice.ActiveDirectory', None, {'get': True})) except: return False return ad.ad_idmap_backend == 'rfc2307'
def ldap_conf_activedirectory(client, ldap_conf): ad = Struct(client.call('notifier.directoryservice', 'AD')) config = {} config["URI"] = "%s://%s" % ("ldaps" if ad.ssl == "on" else "ldap", ad.domainname) config["BASE"] = ad.basedn if ad.ssl in ("start_tls", "on"): if ad.certfile: config["TLS_CACERT"] = ad.certfile config["TLS_REQCERT"] = "allow" # # So what if the AD server is configured to use SSL or TLS, # and the idmap backend is as well? WTF? whaddoyoudo? # ad = Struct( client.call('datastore.query', 'directoryservice.activedirectory', None, {'get': True})) if ad.ad_idmap_backend in ("rfc2307", "ldap"): idmap = Struct( client.call('notifier.ds_get_idmap_object', ad.ds_type, ad.id, ad.ad_idmap_backend)) idmap_url = idmap.url idmap_url = re.sub('^(ldaps?://)', '', idmap_url) config["URI"] = "%s://%s" % ("ldaps" if idmap.ssl == "on" else "ldap", idmap_url) if idmap.ssl in ('start_tls', 'on'): ca = client.call('certificateauthority.query', [('id', '=', idmap.certificate.id)], {'get': True}) capath = ca['cert_ceritifcate_path'] if capath: config["TLS_CACERT"] = capath config["TLS_REQCERT"] = "allow" keys = ["URI", "BASE", "TLS_CACERT", "TLS_REQCERT"] with open(ldap_conf, "w") as f: for key in keys: if key in config: f.write("%s %s\n" % (key, config[key])) f.close() os.chmod(ldap_conf, 0644)
def set_idmap_rfc2307_secret(client): try: ad = Struct(client.call('datastore.query', 'directoryservice.ActiveDirectory', None, {'get': True})) ad.ds_type = 1 # FIXME: DS_TYPE_ACTIVEDIRECTORY = 1 except: return False domain = None # FIXME: ad ds_type, extend model idmap = Struct(client.call('notifier.ds_get_idmap_object', ad.ds_type, ad.id, ad.ad_idmap_backend)) try: fad = Struct(client.call('notifier.directoryservice', 'AD')) domain = fad.netbiosname.upper() except: return False args = [ "/usr/local/bin/net", "-d 0", "idmap", "secret" ] net_cmd = "%s '%s' '%s'" % ( ' '.join(args), domain, idmap.idmap_rfc2307_ldap_user_dn_password ) p = pipeopen(net_cmd, quiet=True) net_out = p.communicate() if net_out and net_out[0]: for line in net_out[0].split('\n'): if not line: continue print(line) ret = True if p.returncode != 0: print("Failed to set idmap secret!", file=sys.stderr) ret = False return ret
def smb4_set_database_SID(client, SID): ret = False if not SID: return ret try: cifs = Struct(client.call('datastore.query', 'services.cifs', None, {'get': True})) cifs.cifs_SID = SID cifs.save() ret = True except Exception as e: log.debug( 'The following exception occured while trying to set database SID: {0}'.format(e) ) log_traceback(log=log) ret = False return ret
def get_ldap_cookie(client): cookie = '' if client.call('notifier.common', 'system', 'ldap_enabled'): ldap = Struct(client.call('datastore.query', 'directoryservice.ldap', None, {'get': True})) cookie = ldap.ldap_hostname.upper() parts = cookie.split('.') cookie = parts[0] return cookie
def get_activedirectory_cookie(client): cookie = '' if client.call('notifier.common', 'system', 'activedirectory_enabled'): smb = Struct(client.call('smb.config')) cookie = smb.netbiosname.upper() parts = cookie.split('.') cookie = parts[0] return cookie
def smb4_autorid_enabled(client): ret = False try: ad = Struct(client.call('datastore.query', 'directoryservice.ActiveDirectory', None, {'get': True})) except: return ret if ad.ad_idmap_backend.lower() == "autorid": ret = True return ret
def add_ldap_conf(client, smb4_conf): try: ldap = Struct(client.call('datastore.query', 'directoryservice.LDAP', None, {'get': True})) ldap.ds_type = 2 # FIXME: DS_TYPE_LDAP = 2 cifs = Struct(client.call('smb.config')) except: return confset1(smb4_conf, "security = user") confset1( smb4_conf, "passdb backend = ldapsam:%s://%s" % ( "ldaps" if ldap.ldap_ssl == 'on' else "ldap", ldap.ldap_hostname ) ) ldap_workgroup = cifs.workgroup.upper() confset2(smb4_conf, "ldap admin dn = %s", ldap.ldap_binddn) confset2(smb4_conf, "ldap suffix = %s", ldap.ldap_basedn) confset2(smb4_conf, "ldap user suffix = %s", ldap.ldap_usersuffix) confset2(smb4_conf, "ldap group suffix = %s", ldap.ldap_groupsuffix) confset2(smb4_conf, "ldap machine suffix = %s", ldap.ldap_machinesuffix) confset2( smb4_conf, "ldap ssl = %s", "start tls" if (ldap.ldap_ssl == 'start_tls') else 'off' ) confset1(smb4_conf, "ldap replication sleep = 1000") confset1(smb4_conf, "ldap passwd sync = yes") confset1(smb4_conf, "ldapsam:trusted = yes") confset2(smb4_conf, "workgroup = %s", ldap_workgroup) confset1(smb4_conf, "domain logons = yes") idmap = Struct(client.call('notifier.ds_get_idmap_object', ldap.ds_type, ldap.id, ldap.ldap_idmap_backend)) configure_idmap_backend(client, smb4_conf, idmap, ldap_workgroup)
def smb4_import_users(client, smb_conf_path, smb4_tdb, exportfile=None): f = tempfile.NamedTemporaryFile(mode='w+', dir="/tmp") for line in smb4_tdb: f.write(line + '\n') f.flush() args = [ "/usr/local/bin/pdbedit", "-d 0", "-i smbpasswd:%s" % f.name, "-s %s" % smb_conf_path ] if exportfile is not None: # smb4_unlink(exportfile) args.append("-e tdbsam:%s" % exportfile) p = pipeopen(' '.join(args)) pdbedit_out = p.communicate() if pdbedit_out and pdbedit_out[0]: for line in pdbedit_out[0].split('\n'): line = line.strip() if not line: continue print(line) f.close() smb4_users = get_smb4_users(client) for u in smb4_users: u = Struct(u) smbhash = u.bsdusr_smbhash parts = smbhash.split(':') user = parts[0] flags = "-e" if u.bsdusr_locked or u.bsdusr_password_disabled: flags = "-d" p = pipeopen("/usr/local/bin/smbpasswd %s '%s'" % (flags, user)) smbpasswd_out = p.communicate() if p.returncode != 0: print("Failed to disable %s" % user, file=sys.stderr) continue if smbpasswd_out and smbpasswd_out[0]: for line in smbpasswd_out[0].split('\n'): line = line.strip() if not line: continue print(line)
def smb4_import_users(client, smb_conf_path, smb4_tdb, exportfile=None): (fd, tmpfile) = tempfile.mkstemp(dir="/tmp") for line in smb4_tdb: os.write(fd, line + '\n') os.close(fd) args = [ "/usr/local/bin/pdbedit", "-d 0", "-i smbpasswd:%s" % tmpfile, "-s %s" % smb_conf_path ] if exportfile is not None: # smb4_unlink(exportfile) args.append("-e tdbsam:%s" % exportfile) p = pipeopen(string.join(args, ' ')) pdbedit_out = p.communicate() if pdbedit_out and pdbedit_out[0]: for line in pdbedit_out[0].split('\n'): line = line.strip() if not line: continue print line os.unlink(tmpfile) smb4_users = get_smb4_users(client) for u in smb4_users: u = Struct(u) smbhash = u.bsdusr_smbhash parts = smbhash.split(':') user = parts[0] flags = "-e" if u.bsdusr_locked or u.bsdusr_password_disabled: flags = "-d" p = pipeopen("/usr/local/bin/smbpasswd %s '%s'" % (flags, user)) smbpasswd_out = p.communicate() if p.returncode != 0: print >> sys.stderr, "Failed to disable %s" % user continue if smbpasswd_out and smbpasswd_out[0]: for line in smbpasswd_out[0].split('\n'): line = line.strip() if not line: continue print line
def get_cifs_homedir(client): cifs_homedir = "/home" shares = client.call('datastore.query', 'sharing.CIFS_Share') if len(shares) == 0: return for share in shares: share = Struct(share) if share.cifs_home and share.cifs_path: cifs_homedir = share.cifs_path break return cifs_homedir
def ad_monitor(self, client, option): ad = Struct( client.call('datastore.query', 'directoryservice.activedirectory', None, {'get': True})) if ad.ad_enable_monitor and ad.ad_enable: if option == 'start': return client.call('service.enable_test_service_connection', ad.ad_monitor_frequency, ad.ad_recover_retry, ad.ad_domainname, 3268, 'activedirectory') elif option == 'stop': return client.call('service.disable_test_service_connection', ad.ad_monitor_frequency, ad.ad_recover_retry, ad.ad_domainname, 3268, 'activedirectory')
def generate_smbusers(client): # FIXME: test query users = client.call('datastore.query', 'account.bsdusers', [ ('bsdusr_microsoft_account', '=', True), ('bsdusr_email', '!=', None), ('bsdusr_email', '!=', ''), ]) if not users: return with open("/usr/local/etc/smbusers", "w") as f: for u in users: u = Struct(u) f.write("%s = %s\n" % (u.bsdusr_username, u.bsdusr_email)) os.chmod("/usr/local/etc/smbusers", 0o644)
def smb4_get_database_SID(client): SID = None try: cifs = Struct(client.call('datastore.query', 'services.cifs', None, {'get': True})) if cifs: SID = cifs.cifs_SID except Exception as e: log.debug( 'The following exception occured while trying to obtain database SID: {0}'.format(e) ) log_traceback(log=log) SID = None return SID
def set_ldap_password(client): try: ldap = Struct(client.call('datastore.query', 'directoryservice.LDAP', None, {'get': True})) except: return if ldap.ldap_bindpw: p = pipeopen("/usr/local/bin/smbpasswd -w '%s'" % ( ldap.ldap_bindpw, ), quiet=True) out = p.communicate() if out and out[1]: for line in out[1].split('\n'): if not line: continue print(line)
def ldap_conf_ldap(client, ldap_conf): try: ldap = Struct(client.call('datastore.query', 'directoryservice.ldap', None, {'get': True})) except: sys.exit(0) f = open(ldap_conf, "w") f.write("URI %s://%s\n" % ( "ldaps" if ldap.ldap_ssl == "on" else "ldap", ldap.ldap_hostname )) f.write("BASE %s\n" % ldap.ldap_basedn) if ldap.ldap_ssl in ("start_tls", "on"): ca = client.call('certificateauthority.query', [('id', '=', ldap.ldap_certificate.id)], {'get': True}) capath = ca['cert_certificate_path'] if capath: f.write("TLS_CACERT %s\n" % capath) f.write("TLS_REQCERT allow\n") f.close() os.chmod(ldap_conf, 0o644)
def ldap_conf_ldap(client, ldap_conf): try: ldap = Struct( client.call('datastore.query', 'directoryservice.LDAP', None, {'get': True})) except: sys.exit(0) f = open(ldap_conf, "w") f.write("uri %s://%s\n" % ("ldaps" if ldap.ldap_ssl == "on" else "ldap", ldap.ldap_hostname)) f.write("base %s\n" % ldap.ldap_basedn) if ldap.ldap_ssl in ("start_tls", "on"): f.write("ssl %s\n" % ldap.ldap_ssl) cert = client.call('certificateauthority.query', [('id', '=', ldap.ldap_certificate.id)], {'get': True}) capath = cert['cert_certificate_path'] if capath: f.write("tls_cacert %s\n" % capath) f.write("tls_reqcert allow\n") f.write("scope sub\n") f.write("timelimit 30\n") f.write("bind_timelimit 30\n") f.write("bind_policy soft\n") # f.write("nss_map_attribute homeDirectory unixHomeDirectory\n") f.write("nss_override_attribute_value loginShell /bin/sh\n") if ldap.ldap_auxiliary_parameters: f.write(ldap.ldap_auxiliary_parameters) f.close() os.chmod(ldap_conf, 0o644)
def generate_smb4_conf(client, smb4_conf, role): cifs = Struct(client.call('cifs.config')) if not cifs.guest: cifs.guest = 'ftp' if not cifs.filemask: cifs.filemask = "0666" if not cifs.dirmask: cifs.dirmask = "0777" # standard stuff... should probably do this differently confset1(smb4_conf, "[global]", space=0) if os.path.exists("/usr/local/etc/smbusers"): confset1(smb4_conf, "username map = /usr/local/etc/smbusers") confset2(smb4_conf, "server min protocol = %s", cifs.min_protocol) confset2(smb4_conf, "server max protocol = %s", cifs.max_protocol) if cifs.bindip: interfaces = [] bindips = ' '.join(cifs.bindip) if role != 'dc': bindips = "127.0.0.1 %s" % bindips bindips = bindips.split() for bindip in bindips: if not bindip: continue bindip = bindip.strip() iface = client.call('notifier.get_interface', bindip) if iface and client.call('notifier.is_carp_interface', iface): parent_iface = client.call('notifier.get_parent_interface', iface) if not parent_iface: continue parent_iinfo = client.call('notifier.get_interface_info', parent_iface[0]) if not parent_iinfo: continue interfaces.append("%s/%s" % (bindip, parent_iface[2])) else: interfaces.append(bindip) if interfaces: confset2(smb4_conf, "interfaces = %s", ' '.join(interfaces)) confset1(smb4_conf, "bind interfaces only = yes") confset1(smb4_conf, "encrypt passwords = yes") confset1(smb4_conf, "dns proxy = no") confset1(smb4_conf, "strict locking = no") confset1(smb4_conf, "oplocks = yes") confset1(smb4_conf, "deadtime = 15") confset1(smb4_conf, "max log size = 51200") confset2(smb4_conf, "max open files = %d", int(get_sysctl('kern.maxfilesperproc')) - 25) if cifs.loglevel and cifs.loglevel is not True: loglevel = cifs.loglevel else: loglevel = "0" if cifs.syslog: confset1(smb4_conf, "logging = syslog:%s" % loglevel) else: confset1(smb4_conf, "logging = file") confset1(smb4_conf, "load printers = no") confset1(smb4_conf, "printing = bsd") confset1(smb4_conf, "printcap name = /dev/null") confset1(smb4_conf, "disable spoolss = yes") confset1(smb4_conf, "getwd cache = yes") confset2(smb4_conf, "guest account = %s", cifs.guest) confset1(smb4_conf, "map to guest = Bad User") confset2(smb4_conf, "obey pam restrictions = %s", "yes" if cifs.obey_pam_restrictions else "no") confset2(smb4_conf, "ntlm auth = %s", "yes" if cifs.ntlmv1_auth else "no") confset1(smb4_conf, "directory name cache size = 0") confset1(smb4_conf, "kernel change notify = no") confset1(smb4_conf, "panic action = /usr/local/libexec/samba/samba-backtrace") confset1(smb4_conf, "nsupdate command = /usr/local/bin/samba-nsupdate -g") confset2(smb4_conf, "server string = %s", cifs.description) confset1(smb4_conf, "ea support = yes") confset1(smb4_conf, "store dos attributes = yes") confset1(smb4_conf, "lm announce = yes") confset2(smb4_conf, "hostname lookups = %s", "yes" if cifs.hostlookup else False) confset2(smb4_conf, "unix extensions = %s", "no" if not cifs.unixext else False) confset2(smb4_conf, "time server = %s", "yes" if cifs.timeserver else False) confset2(smb4_conf, "null passwords = %s", "yes" if cifs.nullpw else False) confset2(smb4_conf, "acl allow execute always = %s", "true" if cifs.allow_execute_always else "false") confset1(smb4_conf, "dos filemode = yes") confset2(smb4_conf, "multicast dns register = %s", "yes" if cifs.zeroconf else "no") if not smb4_ldap_enabled(client): confset2(smb4_conf, "domain logons = %s", "yes" if cifs.domain_logons else "no") if (not client.call('notifier.common', 'system', 'nt4_enabled') and not client.call('notifier.common', 'system', 'activedirectory_enabled')): confset2(smb4_conf, "local master = %s", "yes" if cifs.localmaster else "no") # 5 = DS_TYPE_CIFS idmap = Struct( client.call('notifier.ds_get_idmap_object', 5, cifs.id, 'tdb')) configure_idmap_backend(client, smb4_conf, idmap, None) if role == 'auto': confset1(smb4_conf, "server role = auto") elif role == 'classic': confset1(smb4_conf, "server role = classic primary domain controller") elif role == 'netbios': confset1(smb4_conf, "server role = netbios backup domain controller") elif role == 'dc': confset1(smb4_conf, "server role = active directory domain controller") add_domaincontroller_conf(client, smb4_conf) elif role == 'member': confset1(smb4_conf, "server role = member server") if client.call('notifier.common', 'system', 'nt4_enabled'): add_nt4_conf(client, smb4_conf) elif smb4_ldap_enabled(client): add_ldap_conf(client, smb4_conf) elif client.call('notifier.common', 'system', 'activedirectory_enabled'): add_activedirectory_conf(client, smb4_conf) confset2(smb4_conf, "netbios name = %s", cifs.netbiosname.upper()) if cifs.netbiosalias: confset2(smb4_conf, "netbios aliases = %s", cifs.netbiosalias.upper()) elif role == 'standalone': confset1(smb4_conf, "server role = standalone") confset2(smb4_conf, "netbios name = %s", cifs.netbiosname.upper()) if cifs.netbiosalias: confset2(smb4_conf, "netbios aliases = %s", cifs.netbiosalias.upper()) confset2(smb4_conf, "workgroup = %s", cifs.workgroup.upper()) confset1(smb4_conf, "security = user") if role != 'dc': confset1(smb4_conf, "pid directory = /var/run/samba") confset2(smb4_conf, "create mask = %s", cifs.filemask) confset2(smb4_conf, "directory mask = %s", cifs.dirmask) confset2(smb4_conf, "client ntlmv2 auth = %s", "yes" if not cifs.ntlmv1_auth else "no") confset2(smb4_conf, "dos charset = %s", cifs.doscharset) confset2(smb4_conf, "unix charset = %s", cifs.unixcharset) if cifs.loglevel and cifs.loglevel is not True: confset2(smb4_conf, "log level = %s", cifs.loglevel) smb_options = cifs.smb_options.strip() for line in smb_options.split('\n'): line = line.strip() if not line: continue confset1(smb4_conf, line)
def generate_smb4_shares(client, smb4_shares): shares = client.call('datastore.query', 'sharing.CIFS_Share') if len(shares) == 0: return for share in shares: share = Struct(share) if (not share.cifs_home and not os.path.isdir(share.cifs_path)): continue confset1(smb4_shares, "\n") if share.cifs_home: confset1(smb4_shares, "[homes]", space=0) valid_users_path = "%U" valid_users = "%U" if client.call('notifier.common', 'system', 'activedirectory_enabled'): valid_users_path = "%D/%U" valid_users = "%D\%U" try: ad = Struct(client.call('notifier.directoryservice', 'AD')) for w in ad.workgroups: homedir_path = "%s/%s" % (share.cifs_path, w) if not os.access(homedir_path, os.F_OK): smb4_mkdir(homedir_path) except: pass confset2(smb4_shares, "valid users = %s", valid_users) if share.cifs_path: cifs_homedir_path = ("%s/%s" % (share.cifs_path, valid_users_path)) confset2(smb4_shares, "path = %s", qw(cifs_homedir_path)) if share.cifs_comment: confset2(smb4_shares, "comment = %s", share.cifs_comment) else: confset1(smb4_shares, "comment = Home Directories") else: confset2(smb4_shares, "[%s]", share.cifs_name, space=0) confset2(smb4_shares, "path = %s", qw(share.cifs_path)) confset2(smb4_shares, "comment = %s", share.cifs_comment) confset1(smb4_shares, "printable = no") confset1(smb4_shares, "veto files = /.snapshot/.windows/.mac/.zfs/") confset2(smb4_shares, "writeable = %s", "no" if share.cifs_ro else "yes") confset2(smb4_shares, "browseable = %s", "yes" if share.cifs_browsable else "no") task = None if share.cifs_storage_task: task = share.cifs_storage_task vfs_objects = [] if task: vfs_objects.append('shadow_copy2') extend_vfs_objects_for_zfs(share.cifs_path, vfs_objects) vfs_objects.extend(share.cifs_vfsobjects) if share.cifs_recyclebin: vfs_objects.append('recycle') confset1(smb4_shares, "recycle:repository = .recycle/%U") confset1(smb4_shares, "recycle:keeptree = yes") confset1(smb4_shares, "recycle:versions = yes") confset1(smb4_shares, "recycle:touch = yes") confset1(smb4_shares, "recycle:directory_mode = 0777") confset1(smb4_shares, "recycle:subdir_mode = 0700") if task: confset1(smb4_shares, "shadow:snapdir = .zfs/snapshot") confset1(smb4_shares, "shadow:sort = desc") confset1(smb4_shares, "shadow:localtime = yes") confset1( smb4_shares, "shadow:format = auto-%%Y%%m%%d.%%H%%M-%s%s" % (task.task_ret_count, task.task_ret_unit[0])) confset1(smb4_shares, "shadow:snapdirseverywhere = yes") config_share_for_vfs_objects(smb4_shares, vfs_objects) confset2(smb4_shares, "hide dot files = %s", "no" if share.cifs_showhiddenfiles else "yes") confset2(smb4_shares, "hosts allow = %s", share.cifs_hostsallow) confset2(smb4_shares, "hosts deny = %s", share.cifs_hostsdeny) confset2(smb4_shares, "guest ok = %s", "yes" if share.cifs_guestok else "no") confset2(smb4_shares, "guest only = %s", "yes" if share.cifs_guestonly else False) config_share_for_nfs4(smb4_shares) config_share_for_zfs(smb4_shares) for line in share.cifs_auxsmbconf.split('\n'): line = line.strip() if not line: continue confset1(smb4_shares, line)
def main(middleware): """Use the middleware to generate a config file. We'll build the config file as a series of lines, and once that is done write it out in one go""" cf_contents.clear() cf_contents_shadow.clear() gconf = Struct( middleware.call_sync('datastore.query', 'services.iSCSITargetGlobalConfiguration', [], {'get': True})) if gconf.iscsi_alua: node = middleware.call_sync('failover.node') if gconf.iscsi_isns_servers: for server in gconf.iscsi_isns_servers.split(): addline('isns-server "%s"\n\n' % server) # Generate the portal-group section addline('portal-group "default" {\n}\n\n') for pg in middleware.call_sync('datastore.query', 'services.iSCSITargetPortal'): pg = Struct(pg) # Prepare auth group for the portal group if pg.iscsi_target_portal_discoveryauthgroup: auth_list = [ Struct(i) for i in middleware.call_sync( 'datastore.query', 'services.iSCSITargetAuthCredential', [( 'iscsi_target_auth_tag', '=', pg.iscsi_target_portal_discoveryauthgroup)]) ] else: auth_list = [] agname = 'ag4pg%d' % pg.iscsi_target_portal_tag if not auth_group_config( auth_tag=agname, auth_list=auth_list, auth_type=pg.iscsi_target_portal_discoveryauthmethod): agname = 'no-authentication' # Prepare IPs to listen on for all portal groups. portals = [ Struct(i) for i in middleware.call_sync( 'datastore.query', 'services.iSCSITargetPortalIP', [( 'iscsi_target_portalip_portal', '=', pg.id)]) ] listen = [] listenA = [] listenB = [] for portal in portals: if ':' in portal.iscsi_target_portalip_ip: address = '[%s]' % portal.iscsi_target_portalip_ip else: address = portal.iscsi_target_portalip_ip found = False if gconf.iscsi_alua: if address == '0.0.0.0': listenA.append( '%s:%s' % (address, portal.iscsi_target_portalip_port)) listenB.append( '%s:%s' % (address, portal.iscsi_target_portalip_port)) found = True break if not found: for net in middleware.call_sync('datastore.query', 'network.Interfaces'): if net['int_vip'] == address and net[ 'int_ipv4address'] and net['int_ipv4address_b']: listenA.append('%s:%s' % (net['int_ipv4address'], portal.iscsi_target_portalip_port)) listenB.append('%s:%s' % (net['int_ipv4address_b'], portal.iscsi_target_portalip_port)) found = True break if not found: for alias in middleware.call_sync('datastore.query', 'network.Alias'): if alias['alias_vip'] == address and alias[ 'alias_v4address'] and alias[ 'alias_v4address_b']: listenA.append('%s:%s' % (alias['alias_v4address'], portal.iscsi_target_portalip_port)) listenB.append('%s:%s' % (alias['alias_v4address_b'], portal.iscsi_target_portalip_port)) found = True break else: listen.append('%s:%s' % (address, portal.iscsi_target_portalip_port)) if gconf.iscsi_alua: # Two portal groups for ALUA HA case. addline('portal-group "pg%dA" {\n' % pg.iscsi_target_portal_tag) addline('\ttag "0x%04x"\n' % pg.iscsi_target_portal_tag) addline('\tdiscovery-filter "portal-name"\n') addline('\tdiscovery-auth-group "%s"\n' % agname) for i in listenA: addline('\tlisten "%s"\n' % i) if node != 'A': addline('\tforeign\n') addline('}\n') addline('portal-group "pg%dB" {\n' % pg.iscsi_target_portal_tag) addline('\ttag "0x%04x"\n' % (pg.iscsi_target_portal_tag + 0x8000)) addline('\tdiscovery-filter "portal-name"\n') addline('\tdiscovery-auth-group "%s"\n' % agname) for i in listenB: addline('\tlisten "%s"\n' % i) if node != 'B': addline('\tforeign\n') addline('}\n\n') else: # One portal group for non-HA and CARP HA cases. addline('portal-group "pg%d" {\n' % pg.iscsi_target_portal_tag) addline('\ttag "0x%04x"\n' % pg.iscsi_target_portal_tag) addline('\tdiscovery-filter "portal-name"\n') addline('\tdiscovery-auth-group "%s"\n' % agname) for i in listen: addline('\tlisten "%s"\n' % i) addline('\toption "ha_shared" "on"\n') addline('}\n\n') # Cache zpool threshold poolthreshold = {} zpoollist = {i['name']: i for i in middleware.call_sync('zfs.pool.query')} system_disks = middleware.call_sync('device.get_disks') # Generate the LUN section for extent in middleware.call_sync( 'datastore.query', 'services.iSCSITargetExtent', [['iscsi_target_extent_enabled', '=', True]]): extent = Struct(extent) path = extent.iscsi_target_extent_path if not path: logger.warning('Path for extent id %d is null, skipping', extent.id) continue poolname = None lunthreshold = None if extent.iscsi_target_extent_type == 'Disk': disk = middleware.call_sync('datastore.query', 'storage.Disk', [('disk_identifier', '=', path)], {'order_by': ['disk_expiretime']}) if not disk: continue disk = Struct(disk[0]) if disk.disk_multipath_name: path = '/dev/multipath/%s' % disk.disk_multipath_name else: path = '/dev/%s' % middleware.call_sync( 'disk.identifier_to_device', disk.disk_identifier, system_disks) else: if not path.startswith('/mnt'): poolname = path.split('/', 2)[1] if gconf.iscsi_pool_avail_threshold: if poolname in zpoollist: poolthreshold[poolname] = int( zpoollist[poolname]['properties']['size']['parsed'] * (gconf.iscsi_pool_avail_threshold / 100.0)) if extent.iscsi_target_extent_avail_threshold: zvolname = path.split('/', 1)[1] zfslist = middleware.call_sync('pool.dataset.query', [('id', '=', zvolname)]) if zfslist and zfslist[0]['type'] == 'VOLUME': lunthreshold = int( zfslist[0]['volsize']['parsed'] * (extent.iscsi_target_extent_avail_threshold / 100.0)) path = '/dev/' + path else: if extent.iscsi_target_extent_avail_threshold and os.path.exists( path): try: stat = os.stat(path) lunthreshold = int( stat.st_size * (extent.iscsi_target_extent_avail_threshold / 100.0)) except OSError: pass addline('lun "%s" {\n' % extent.iscsi_target_extent_name) addline('\tctl-lun "%d"\n' % (extent.id - 1)) size = extent.iscsi_target_extent_filesize addline('\tpath "%s"\n' % path) addline('\tblocksize "%s"\n' % extent.iscsi_target_extent_blocksize) if extent.iscsi_target_extent_pblocksize: addline('\toption "pblocksize" "0"\n') addline('\tserial "%s"\n' % (extent.iscsi_target_extent_serial, )) padded_serial = extent.iscsi_target_extent_serial if not extent.iscsi_target_extent_xen: for i in range(31 - len(extent.iscsi_target_extent_serial)): padded_serial += ' ' addline('\tdevice-id "iSCSI Disk %s"\n' % padded_serial) if size != '0': if size.endswith('B'): size = size.strip('B') addline('\t\tsize "%s"\n' % size) # We can't change the vendor name of existing # LUNs without angering VMWare, but we can # use the right names going forward. if extent.iscsi_target_extent_legacy is True: addline('\toption "vendor" "FreeBSD"\n') else: if middleware.call_sync('system.is_freenas'): addline('\toption "vendor" "FreeNAS"\n') else: addline('\toption "vendor" "TrueNAS"\n') addline('\toption "product" "iSCSI Disk"\n') addline('\toption "revision" "0123"\n') addline('\toption "naa" "%s"\n' % extent.iscsi_target_extent_naa) if extent.iscsi_target_extent_insecure_tpc: addline('\toption "insecure_tpc" "on"\n') if lunthreshold: addline('\toption "avail-threshold" "%s"\n' % lunthreshold) if poolname is not None and poolname in poolthreshold: addline('\toption "pool-avail-threshold" "%s"\n' % poolthreshold[poolname]) if extent.iscsi_target_extent_rpm == 'Unknown': addline('\toption "rpm" "0"\n') elif extent.iscsi_target_extent_rpm == 'SSD': addline('\toption "rpm" "1"\n') else: addline('\toption "rpm" "%s"\n' % extent.iscsi_target_extent_rpm) if extent.iscsi_target_extent_ro: addline('\toption "readonly" "on"\n') addline('}\n') addline('\n') # Generate the target section target_basename = gconf.iscsi_basename for target in middleware.call_sync('datastore.query', 'services.iSCSITarget'): target = Struct(target) authgroups = {} for grp in middleware.call_sync('datastore.query', 'services.iscsitargetgroups', [('iscsi_target', '=', target.id)]): grp = Struct(grp) if grp.iscsi_target_authgroup: auth_list = [ Struct(i) for i in middleware.call_sync( 'datastore.query', 'services.iSCSITargetAuthCredential', [( 'iscsi_target_auth_tag', '=', grp.iscsi_target_authgroup)]) ] else: auth_list = [] agname = 'ag4tg%d_%d' % (target.id, grp.id) if auth_group_config(auth_tag=agname, auth_list=auth_list, auth_type=grp.iscsi_target_authtype, initiator=grp.iscsi_target_initiatorgroup): authgroups[grp.id] = agname if (target.iscsi_target_name.startswith('iqn.') or target.iscsi_target_name.startswith('eui.') or target.iscsi_target_name.startswith('naa.')): addline('target "%s" {\n' % target.iscsi_target_name) else: addline('target "%s:%s" {\n' % (target_basename, target.iscsi_target_name)) if target.iscsi_target_alias: addline('\talias "%s"\n' % target.iscsi_target_alias) elif target.iscsi_target_name: addline('\talias "%s"\n' % target.iscsi_target_name) for fctt in middleware.call_sync('datastore.query', 'services.fibrechanneltotarget', [('fc_target', '=', target.id)]): fctt = Struct(fctt) addline('\tport "%s"\n' % fctt.fc_port) for grp in middleware.call_sync('datastore.query', 'services.iscsitargetgroups', [('iscsi_target', '=', target.id)]): grp = Struct(grp) agname = authgroups.get(grp.id) or 'no-authentication' if gconf.iscsi_alua: addline('\tportal-group "pg%dA" "%s"\n' % (grp.iscsi_target_portalgroup.iscsi_target_portal_tag, agname)) addline('\tportal-group "pg%dB" "%s"\n' % (grp.iscsi_target_portalgroup.iscsi_target_portal_tag, agname)) else: addline('\tportal-group "pg%d" "%s"\n' % (grp.iscsi_target_portalgroup.iscsi_target_portal_tag, agname)) addline('\n') used_lunids = [ o['iscsi_lunid'] for o in middleware. call_sync('datastore.query', 'services.iscsitargettoextent', [( 'iscsi_target', '=', target.id), ('iscsi_lunid', '!=', None)]) ] cur_lunid = 0 for t2e in middleware.call_sync( 'datastore.query', 'services.iscsitargettoextent', [('iscsi_target', '=', target.id)], {'order_by': ['nulls_last:iscsi_lunid']}): t2e = Struct(t2e) if not t2e.iscsi_extent.iscsi_target_extent_enabled: # Skip adding extents to targets which are not enabled continue if t2e.iscsi_lunid is None: while cur_lunid in used_lunids: cur_lunid += 1 addline('\tlun "%s" "%s"\n' % (cur_lunid, t2e.iscsi_extent.iscsi_target_extent_name)) cur_lunid += 1 else: addline('\tlun "%s" "%s"\n' % (t2e.iscsi_lunid, t2e.iscsi_extent.iscsi_target_extent_name)) addline('}\n\n') # Write out the CTL config file with open( os.open(ctl_config, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600), 'w') as fh: for line in cf_contents: fh.write(line) # Write out the CTL config file with redacted CHAP passwords with open( os.open(ctl_config_shadow, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0o600), 'w') as fh: for line in cf_contents_shadow: fh.write(line)
def render(service, middleware): """ The resulting afp.conf file will only allow kerberos authentication (add uams_gss.so) if a kerberos keytab is uploaded to the NAS. When afp_srv_map_acls is set to "mode" and the LDAP or AD directory service is enabled, the NAS is configured to query the LDAP server for a UUID attribute to present to MacOS clients. This is required for the permission editor to properly display users in the MacOS permissions editor because MacOS clients use UUIDs rather than UIDs and GIDs. SASL is not implemented in Netatalk, and so this feature requires storing the plain-text LDAP password in the afp.conf file. The default AD behavior clears the bindpw after successful domain join, and so additional configuration (persistently storing the bindpw and possibly LDAP schema changes) will be required for this feature to work correctly. """ map_acls_mode = False ds_type = None afp_config = "/etc/afp.conf" if osc.IS_FREEBSD: afp_config = f'/usr/local{afp_config}' cf_contents = [] afp = Struct( middleware.call_sync('datastore.query', 'services.afp', [], {'get': True})) cf_contents.append("[Global]\n") uam_list = ['uams_dhx.so', 'uams_dhx2.so'] if afp.afp_srv_guest: uam_list.append('uams_guest.so') cf_contents.append('\tguest account = %s\n' % afp.afp_srv_guest_user) # uams_gss.so bails out with an error if kerberos isn't configured if middleware.call_sync('datastore.query', 'directoryservice.kerberoskeytab', [], {'count': True}) > 0: uam_list.append('uams_gss.so') cf_contents.append('\tuam list = %s\n' % (" ").join(uam_list)) if afp.afp_srv_bindip: ifaces = get_interface(middleware, afp.afp_srv_bindip) if ifaces: cf_contents.append("\tafp listen = %s\n" % ' '.join(afp.afp_srv_bindip)) cf_contents.append("\tafp interfaces = %s\n" % ' '.join(ifaces)) cf_contents.append("\tmax connections = %s\n" % afp.afp_srv_connections_limit) cf_contents.append("\tmimic model = RackMac\n") cf_contents.append("\tafpstats = yes\n") if afp.afp_srv_dbpath: cf_contents.append("\tvol dbnest = no\n") cf_contents.append("\tvol dbpath = %s\n" % afp.afp_srv_dbpath) else: cf_contents.append("\tvol dbnest = yes\n") if afp.afp_srv_global_aux: cf_contents.append("\t%s\n" % afp.afp_srv_global_aux) if afp.afp_srv_map_acls: cf_contents.append("\tmap acls = %s\n" % afp.afp_srv_map_acls) if afp.afp_srv_chmod_request: cf_contents.append("\tchmod request = %s\n" % afp.afp_srv_chmod_request) if afp.afp_srv_map_acls == 'mode': if middleware.call_sync('activedirectory.get_state') != 'DISABLED': ds_type = 'AD' elif middleware.call_sync('ldap.get_state') != 'DISABLED': ds_type = 'LDAP' if ds_type is not None: ds_config = { 'bind_dn': None, 'bind_pw': None, 'server': None, 'userbase': None, 'groupbase': None, } if ds_type == 'AD': ad = middleware.call_sync('activedirectory.config') ds_config.update({ 'bind_dn': ad['bindname'], 'bind_pw': ad['bindpw'], 'server': ad['domainname'], }) elif ds_type == 'LDAP': ldap = middleware.call_sync('ldap.config') ds_config.update({ 'bind_dn': ldap['binddn'], 'bind_pw': ldap['bindpw'], 'server': ldap['hostname'], 'userbase': ldap['basedn'], 'groupbase': ldap['basedn'], }) cf_contents.append("\tldap auth method = %s\n" % "simple") cf_contents.append("\tldap auth dn = %s\n" % ds_config['bind_dn']) cf_contents.append("\tldap auth pw = %s\n" % ds_config['bind_pw']) cf_contents.append("\tldap server = %s\n" % ds_config['server']) # This should be configured when using this option if ds_config['userbase']: cf_contents.append("\tldap userbase = %s\n" % ds_config['userbase']) cf_contents.append("\tldap userscope = %s\n" % "sub") # This should be configured when using this option if ds_config['groupbase']: cf_contents.append("\tldap groupbase = %s\n" % ds_config['groupbase']) cf_contents.append("\tldap groupscope = %s\n" % "sub") cf_contents.append("\tldap user filter = %s\n" % "objectclass=user") cf_contents.append("\tldap group filter = %s\n" % "objectclass=group") cf_contents.append("\tldap uuid attr = %s\n" % "objectGUID") if ds_type == 'AD': cf_contents.append("\tldap uuid encoding = %s\n" % "ms-guid") cf_contents.append("\tldap name attr = %s\n" % "sAMAccountName") cf_contents.append("\tldap group attr = %s\n" % "sAMAccountName") cf_contents.append("\tlog file = %s\n" % "/var/log/afp.log") cf_contents.append("\tlog level = %s\n" % "default:warn") cf_contents.append("\n") for share in middleware.call_sync('datastore.query', 'sharing.afp_share', [['afp_enabled', '=', True]]): share = Struct(share) if share.afp_home: cf_contents.append("[Homes]\n") cf_contents.append("\tbasedir regex = %s\n" % share.afp_path) if share.afp_name and share.afp_name != "Homes": cf_contents.append("\thome name = %s\n" % share.afp_name) else: cf_contents.append("[%s]\n" % share.afp_name) cf_contents.append("\tpath = %s\n" % share.afp_path) if share.afp_allow: cf_contents.append("\tvalid users = %s\n" % share.afp_allow) if share.afp_deny: cf_contents.append("\tinvalid users = %s\n" % share.afp_deny) if share.afp_hostsallow: cf_contents.append("\thosts allow = %s\n" % share.afp_hostsallow) if share.afp_hostsdeny: cf_contents.append("\thosts deny = %s\n" % share.afp_hostsdeny) if share.afp_ro: cf_contents.append("\trolist = %s\n" % share.afp_ro) if share.afp_rw: cf_contents.append("\trwlist = %s\n" % share.afp_rw) if share.afp_timemachine: cf_contents.append("\ttime machine = yes\n") if not share.afp_nodev: cf_contents.append("\tcnid dev = no\n") if share.afp_nostat: cf_contents.append("\tstat vol = no\n") if not share.afp_upriv: cf_contents.append("\tunix priv = no\n") else: if share.afp_fperm and not map_acls_mode: cf_contents.append("\tfile perm = %s\n" % share.afp_fperm) if share.afp_dperm and not map_acls_mode: cf_contents.append("\tdirectory perm = %s\n" % share.afp_dperm) if share.afp_umask and not map_acls_mode: cf_contents.append("\tumask = %s\n" % share.afp_umask) cf_contents.append("\tveto files = .windows/.mac/\n") if map_acls_mode: cf_contents.append("\tacls = yes\n") # Do not fail if aux params are not properly entered by the user try: aux_params = [ "\t{0}\n".format(p) for p in share.afp_auxparams.split("\n") ] except: pass else: cf_contents += aux_params # Update TimeMachine special files timemachine_supported_path = os.path.join( share.afp_path, ".com.apple.timemachine.supported") timemachine_quota_plist_path = os.path.join( share.afp_path, ".com.apple.TimeMachine.quota.plist") timemachine_quota_plist_managed_flag = os.path.join( share.afp_path, ".com.apple.TimeMachine.quota.plist.FreeNAS-managed") if share.afp_timemachine and share.afp_timemachine_quota: try: with open(timemachine_supported_path, "w"): pass except IOError: pass try: with open(timemachine_quota_plist_path, "w") as f: f.write( textwrap.dedent("""\ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>GlobalQuota</key> <integer>%d</integer> </dict> </plist> """ % (share.afp_timemachine_quota * 1024 * 1024 * 1024))) except IOError: pass try: with open(timemachine_quota_plist_managed_flag, "w") as f: pass except IOError: pass try: stat = os.stat(share.afp_path) os.chmod(timemachine_supported_path, 0o644) os.chown(timemachine_supported_path, stat.st_uid, stat.st_gid) os.chmod(timemachine_quota_plist_path, 0o644) os.chown(timemachine_quota_plist_path, stat.st_uid, stat.st_gid) os.chmod(timemachine_quota_plist_managed_flag, 0o644) os.chown(timemachine_quota_plist_managed_flag, stat.st_uid, stat.st_gid) except IOError: pass else: if os.path.exists(timemachine_quota_plist_managed_flag): try: os.unlink(timemachine_supported_path) except IOError: pass try: os.unlink(timemachine_quota_plist_path) except IOError: pass with open(afp_config, "w") as fh: for line in cf_contents: fh.write(line)
def main(): """Use the django ORM to generate a config file. We'll build the config file as a series of lines, and once that is done write it out in one go""" map_acls_mode = False afp_config = "/usr/local/etc/afp.conf" cf_contents = [] client = Client() afp = Struct( client.call('datastore.query', 'services.afp', None, {'get': True})) cf_contents.append("[Global]\n") uam_list = ['uams_dhx.so', 'uams_dhx2.so'] if afp.afp_srv_guest: uam_list.append('uams_guest.so') cf_contents.append('\tguest account = %s\n' % afp.afp_srv_guest_user) # uams_gss.so bails out with an error if kerberos isn't configured if client.call('datastore.query', 'directoryservice.kerberoskeytab', None, {'count': True}) > 0: uam_list.append('uams_gss.so') cf_contents.append('\tuam list = %s\n' % (" ").join(uam_list)) if afp.afp_srv_bindip: cf_contents.append("\tafp listen = %s\n" % ' '.join(afp.afp_srv_bindip)) ifaces = get_interface(afp.afp_srv_bindip) cf_contents.append("\tafp interfaces = %s\n" % ' '.join(ifaces)) cf_contents.append("\tmax connections = %s\n" % afp.afp_srv_connections_limit) cf_contents.append("\tmimic model = RackMac\n") if afp.afp_srv_dbpath: cf_contents.append("\tvol dbnest = no\n") cf_contents.append("\tvol dbpath = %s\n" % afp.afp_srv_dbpath) else: cf_contents.append("\tvol dbnest = yes\n") if afp.afp_srv_global_aux: cf_contents.append("\t%s\n" % afp.afp_srv_global_aux) if afp.afp_srv_map_acls: cf_contents.append("\tmap acls = %s\n" % afp.afp_srv_map_acls) if afp.afp_srv_chmod_request: cf_contents.append("\tchmod request = %s\n" % afp.afp_srv_chmod_request) if afp.afp_srv_map_acls == 'mode' and client.call( 'notifier.common', 'system', 'activedirectory_enabled'): map_acls_mode = True if map_acls_mode: ad = Struct(client.call('notifier.directoryservice', 'AD')) cf_contents.append("\tldap auth method = %s\n" % "simple") cf_contents.append("\tldap auth dn = %s\n" % ad.binddn) cf_contents.append("\tldap auth pw = %s\n" % ad.bindpw) cf_contents.append("\tldap server = %s\n" % ad.domainname) # This should be configured when using this option if ad.userdn: cf_contents.append("\tldap userbase = %s\n" % ad.userdn) cf_contents.append("\tldap userscope = %s\n" % "sub") # This should be configured when using this option if ad.groupdn: cf_contents.append("\tldap groupbase = %s\n" % ad.groupdn) cf_contents.append("\tldap groupscope = %s\n" % "sub") cf_contents.append("\tldap user filter = %s\n" % "objectclass=user") cf_contents.append("\tldap group filter = %s\n" % "objectclass=group") cf_contents.append("\tldap uuid attr = %s\n" % "objectGUID") cf_contents.append("\tldap uuid encoding = %s\n" % "ms-guid") cf_contents.append("\tldap name attr = %s\n" % "sAMAccountName") cf_contents.append("\tldap group attr = %s\n" % "sAMAccountName") cf_contents.append("\n") for share in client.call('datastore.query', 'sharing.afp_share'): share = Struct(share) if share.afp_home: cf_contents.append("[Homes]\n") cf_contents.append("\tbasedir regex = %s\n" % share.afp_path) if share.afp_name and share.afp_name != "Homes": cf_contents.append("\thome name = %s\n" % share.afp_name) else: cf_contents.append("[%s]\n" % share.afp_name) cf_contents.append("\tpath = %s\n" % share.afp_path) if share.afp_allow: cf_contents.append("\tvalid users = %s\n" % share.afp_allow) if share.afp_deny: cf_contents.append("\tinvalid users = %s\n" % share.afp_deny) if share.afp_hostsallow: cf_contents.append("\thosts allow = %s\n" % share.afp_hostsallow) if share.afp_hostsdeny: cf_contents.append("\thosts deny = %s\n" % share.afp_hostsdeny) if share.afp_ro: cf_contents.append("\trolist = %s\n" % share.afp_ro) if share.afp_rw: cf_contents.append("\trwlist = %s\n" % share.afp_rw) if share.afp_timemachine: cf_contents.append("\ttime machine = yes\n") if not share.afp_nodev: cf_contents.append("\tcnid dev = no\n") if share.afp_nostat: cf_contents.append("\tstat vol = no\n") if not share.afp_upriv: cf_contents.append("\tunix priv = no\n") else: if share.afp_fperm and not map_acls_mode: cf_contents.append("\tfile perm = %s\n" % share.afp_fperm) if share.afp_dperm and not map_acls_mode: cf_contents.append("\tdirectory perm = %s\n" % share.afp_dperm) if share.afp_umask and not map_acls_mode: cf_contents.append("\tumask = %s\n" % share.afp_umask) cf_contents.append("\tveto files = .windows/.mac/\n") if map_acls_mode: cf_contents.append("\tacls = yes\n") # Do not fail if aux params are not properly entered by the user try: aux_params = [ "\t{0}\n".format(p) for p in share.afp_auxparams.split("\n") ] except: pass else: cf_contents += aux_params # Update TimeMachine special files timemachine_supported_path = os.path.join( share.afp_path, ".com.apple.timemachine.supported") timemachine_quota_plist_path = os.path.join( share.afp_path, ".com.apple.TimeMachine.quota.plist") timemachine_quota_plist_managed_flag = os.path.join( share.afp_path, ".com.apple.TimeMachine.quota.plist.FreeNAS-managed") if share.afp_timemachine and share.afp_timemachine_quota: try: with open(timemachine_supported_path, "w"): pass except IOError: pass try: with open(timemachine_quota_plist_path, "w") as f: f.write( textwrap.dedent("""\ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>GlobalQuota</key> <integer>%d</integer> </dict> </plist> """ % (share.afp_timemachine_quota * 1024 * 1024))) except IOError: pass try: with open(timemachine_quota_plist_managed_flag, "w") as f: pass except IOError: pass try: stat = os.stat(share.afp_path) os.chmod(timemachine_supported_path, 0o644) os.chown(timemachine_supported_path, stat.st_uid, stat.st_gid) os.chmod(timemachine_quota_plist_path, 0o644) os.chown(timemachine_quota_plist_path, stat.st_uid, stat.st_gid) os.chmod(timemachine_quota_plist_managed_flag, 0o644) os.chown(timemachine_quota_plist_managed_flag, stat.st_uid, stat.st_gid) except IOError: pass else: if os.path.exists(timemachine_quota_plist_managed_flag): try: os.unlink(timemachine_supported_path) except IOError: pass try: os.unlink(timemachine_quota_plist_path) except IOError: pass with open(afp_config, "w") as fh: for line in cf_contents: fh.write(line)
def main(): """Use the django ORM to generate a config file. We'll build the config file as a series of lines, and once that is done write it out in one go""" map_acls_mode = False afp_config = "/usr/local/etc/afp.conf" cf_contents = [] client = Client() afp = Struct( client.call('datastore.query', 'services.afp', None, {'get': True})) cf_contents.append("[Global]\n") uam_list = ['uams_dhx.so', 'uams_dhx2.so'] if afp.afp_srv_guest: uam_list.append('uams_guest.so') cf_contents.append('\tguest account = %s\n' % afp.afp_srv_guest_user) # uams_gss.so bails out with an error if kerberos isn't configured if client.call('datastore.query', 'directoryservice.kerberoskeytab', None, {'count': True}) > 0: uam_list.append('uams_gss.so') cf_contents.append('\tuam list = %s\n' % (" ").join(uam_list)) if afp.afp_srv_bindip: cf_contents.append("\tafp listen = %s\n" % ' '.join(afp.afp_srv_bindip)) ifaces = get_interface(afp.afp_srv_bindip) cf_contents.append("\tafp interfaces = %s\n" % ' '.join(ifaces)) cf_contents.append("\tmax connections = %s\n" % afp.afp_srv_connections_limit) cf_contents.append("\tmimic model = RackMac\n") if afp.afp_srv_dbpath: cf_contents.append("\tvol dbnest = no\n") cf_contents.append("\tvol dbpath = %s\n" % afp.afp_srv_dbpath) else: cf_contents.append("\tvol dbnest = yes\n") if afp.afp_srv_global_aux: cf_contents.append("\t%s\n" % afp.afp_srv_global_aux) if afp.afp_srv_map_acls: cf_contents.append("\tmap acls = %s\n" % afp.afp_srv_map_acls) if afp.afp_srv_chmod_request: cf_contents.append("\tchmod request = %s\n" % afp.afp_srv_chmod_request) if afp.afp_srv_map_acls == 'mode' and client.call( 'notifier.common', 'system', 'activedirectory_enabled'): map_acls_mode = True if map_acls_mode: ad = Struct(client.call('notifier.directoryservice', 'AD')) cf_contents.append("\tldap auth method = %s\n" % "simple") cf_contents.append("\tldap auth dn = %s\n" % ad.binddn) cf_contents.append("\tldap auth pw = %s\n" % ad.bindpw) cf_contents.append("\tldap server = %s\n" % ad.domainname) # This should be configured when using this option if ad.userdn: cf_contents.append("\tldap userbase = %s\n" % ad.userdn) cf_contents.append("\tldap userscope = %s\n" % "sub") # This should be configured when using this option if ad.groupdn: cf_contents.append("\tldap groupbase = %s\n" % ad.groupdn) cf_contents.append("\tldap groupscope = %s\n" % "sub") cf_contents.append("\tldap user filter = %s\n" % "objectclass=user") cf_contents.append("\tldap group filter = %s\n" % "objectclass=group") cf_contents.append("\tldap uuid attr = %s\n" % "objectGUID") cf_contents.append("\tldap uuid encoding = %s\n" % "ms-guid") cf_contents.append("\tldap name attr = %s\n" % "sAMAccountName") cf_contents.append("\tldap group attr = %s\n" % "sAMAccountName") cf_contents.append("\n") if afp.afp_srv_homedir_enable: cf_contents.append("[Homes]\n") cf_contents.append("\tbasedir regex = %s\n" % afp.afp_srv_homedir) if afp.afp_srv_homename: cf_contents.append("\thome name = %s\n" % afp.afp_srv_homename) if afp.afp_srv_hometimemachine: cf_contents.append(f"\ttime machine = yes\n") cf_contents.append("\n") for share in client.call('datastore.query', 'sharing.afp_share'): share = Struct(share) cf_contents.append("[%s]\n" % share.afp_name) cf_contents.append("\tpath = %s\n" % share.afp_path) if share.afp_allow: cf_contents.append("\tvalid users = %s\n" % share.afp_allow) if share.afp_deny: cf_contents.append("\tinvalid users = %s\n" % share.afp_deny) if share.afp_hostsallow: cf_contents.append("\thosts allow = %s\n" % share.afp_hostsallow) if share.afp_hostsdeny: cf_contents.append("\thosts deny = %s\n" % share.afp_hostsdeny) if share.afp_ro: cf_contents.append("\trolist = %s\n" % share.afp_ro) if share.afp_rw: cf_contents.append("\trwlist = %s\n" % share.afp_rw) if share.afp_timemachine: cf_contents.append("\ttime machine = yes\n") if not share.afp_nodev: cf_contents.append("\tcnid dev = no\n") if share.afp_nostat: cf_contents.append("\tstat vol = no\n") if not share.afp_upriv: cf_contents.append("\tunix priv = no\n") else: if share.afp_fperm and not map_acls_mode: cf_contents.append("\tfile perm = %s\n" % share.afp_fperm) if share.afp_dperm and not map_acls_mode: cf_contents.append("\tdirectory perm = %s\n" % share.afp_dperm) if share.afp_umask and not map_acls_mode: cf_contents.append("\tumask = %s\n" % share.afp_umask) cf_contents.append("\tveto files = .windows/.mac/\n") if map_acls_mode: cf_contents.append("\tacls = yes\n") # Do not fail if aux params are not properly entered by the user try: aux_params = [ "\t{0}\n".format(p) for p in share.afp_auxparams.split("\n") ] except: pass else: cf_contents += aux_params with open(afp_config, "w") as fh: for line in cf_contents: fh.write(line)
def generate_smb4_conf(client, smb4_conf, role): cifs = Struct(client.call('smb.config')) if not cifs.guest: cifs.guest = 'ftp' if not cifs.filemask: cifs.filemask = "0666" if not cifs.dirmask: cifs.dirmask = "0777" # standard stuff... should probably do this differently confset1(smb4_conf, "[global]", space=0) if os.path.exists("/usr/local/etc/smbusers"): confset1(smb4_conf, "username map = /usr/local/etc/smbusers") confset2(smb4_conf, "server min protocol = %s", cifs.min_protocol) confset2(smb4_conf, "server max protocol = %s", cifs.max_protocol) if cifs.bindip: interfaces = [] bindips = ' '.join(cifs.bindip) if role != 'dc': bindips = "127.0.0.1 %s" % bindips bindips = bindips.split() for bindip in bindips: if not bindip: continue bindip = bindip.strip() iface = client.call('notifier.get_interface', bindip) is_carp_interface = False if iface: try: is_carp_interface = client.call('notifier.is_carp_interface', iface) except: pass if iface and is_carp_interface: parent_iface = client.call('notifier.get_parent_interface', iface) if not parent_iface: continue parent_iinfo = client.call('notifier.get_interface_info', parent_iface[0]) if not parent_iinfo: continue interfaces.append("%s/%s" % (bindip, parent_iface[2])) else: interfaces.append(bindip) if interfaces: confset2(smb4_conf, "interfaces = %s", ' '.join(interfaces)) confset1(smb4_conf, "bind interfaces only = yes") confset1(smb4_conf, "encrypt passwords = yes") confset1(smb4_conf, "dns proxy = no") confset1(smb4_conf, "strict locking = no") confset1(smb4_conf, "oplocks = yes") confset1(smb4_conf, "deadtime = 15") confset1(smb4_conf, "max log size = 51200") confset2(smb4_conf, "max open files = %d", int(get_sysctl('kern.maxfilesperproc')) - 25) if cifs.loglevel and cifs.loglevel is not True: loglevel = cifs.loglevel else: loglevel = "0" if cifs.syslog: confset1(smb4_conf, "logging = syslog:%s" % loglevel) else: confset1(smb4_conf, "logging = file") confset1(smb4_conf, "load printers = no") confset1(smb4_conf, "printing = bsd") confset1(smb4_conf, "printcap name = /dev/null") confset1(smb4_conf, "disable spoolss = yes") confset1(smb4_conf, "getwd cache = yes") confset2(smb4_conf, "guest account = %s", cifs.guest) confset1(smb4_conf, "map to guest = Bad User") confset2(smb4_conf, "obey pam restrictions = %s", "yes" if cifs.obey_pam_restrictions else "no") confset2(smb4_conf, "ntlm auth = %s", "yes" if cifs.ntlmv1_auth else "no") confset1(smb4_conf, "directory name cache size = 0") confset1(smb4_conf, "kernel change notify = no") confset1(smb4_conf, "panic action = /usr/local/libexec/samba/samba-backtrace") confset1(smb4_conf, "nsupdate command = /usr/local/bin/samba-nsupdate -g") confset2(smb4_conf, "server string = %s", cifs.description) confset1(smb4_conf, "ea support = yes") confset1(smb4_conf, "store dos attributes = yes") confset1(smb4_conf, "lm announce = yes") confset2(smb4_conf, "hostname lookups = %s", "yes" if cifs.hostlookup else False) confset2(smb4_conf, "unix extensions = %s", "no" if not cifs.unixext else False) confset2(smb4_conf, "time server = %s", "yes" if cifs.timeserver else False) confset2(smb4_conf, "null passwords = %s", "yes" if cifs.nullpw else False) confset2(smb4_conf, "acl allow execute always = %s", "true" if cifs.allow_execute_always else "false") confset1(smb4_conf, "dos filemode = yes") confset2(smb4_conf, "multicast dns register = %s", "yes" if cifs.zeroconf else "no") if not smb4_ldap_enabled(client): confset2(smb4_conf, "domain logons = %s", "yes" if cifs.domain_logons else "no") if not client.call('notifier.common', 'system', 'activedirectory_enabled'): confset2(smb4_conf, "local master = %s", "yes" if cifs.localmaster else "no") if not smb4_autorid_enabled(client): # 5 = DS_TYPE_CIFS idmap = Struct(client.call('notifier.ds_get_idmap_object', 5, cifs.id, 'tdb')) configure_idmap_backend(client, smb4_conf, idmap, None) if role == 'auto': confset1(smb4_conf, "server role = auto") elif role == 'classic': confset1(smb4_conf, "server role = classic primary domain controller") elif role == 'netbios': confset1(smb4_conf, "server role = netbios backup domain controller") elif role == 'dc': confset1(smb4_conf, "server role = active directory domain controller") add_domaincontroller_conf(client, smb4_conf) elif role == 'member': confset1(smb4_conf, "server role = member server") if smb4_ldap_enabled(client): add_ldap_conf(client, smb4_conf) elif client.call('notifier.common', 'system', 'activedirectory_enabled'): add_activedirectory_conf(client, smb4_conf) confset2(smb4_conf, "netbios name = %s", cifs.netbiosname.upper()) if cifs.netbiosalias: confset2(smb4_conf, "netbios aliases = %s", cifs.netbiosalias.upper()) elif role == 'standalone': confset1(smb4_conf, "server role = standalone") confset2(smb4_conf, "netbios name = %s", cifs.netbiosname.upper()) if cifs.netbiosalias: confset2(smb4_conf, "netbios aliases = %s", cifs.netbiosalias.upper()) confset2(smb4_conf, "workgroup = %s", cifs.workgroup.upper()) confset1(smb4_conf, "security = user") confset2(smb4_conf, "create mask = %s", cifs.filemask) confset2(smb4_conf, "directory mask = %s", cifs.dirmask) confset2(smb4_conf, "client ntlmv2 auth = %s", "yes" if not cifs.ntlmv1_auth else "no") confset2(smb4_conf, "dos charset = %s", cifs.doscharset) confset2(smb4_conf, "unix charset = %s", cifs.unixcharset) if cifs.loglevel and cifs.loglevel is not True: confset2(smb4_conf, "log level = %s", cifs.loglevel) smb_options = cifs.smb_options.strip() for line in smb_options.split('\n'): line = line.strip() if not line: continue confset1(smb4_conf, line)