#include "smb_server_prefs.h"
#include "macros.hpp"
#include "lib/common.hpp"
#include "lib/SmbConfig.hpp"
#include "lib/SmbOption.hpp"
#include <arpa/inet.h>
typedef SimpleOption<std::string> SimpleStringOption;
typedef SimpleOption<bool> SimpleBoolOption;
typedef SimpleOption<unsigned> SimpleIntOption;
typedef std::vector<std::string> string_list;
static bool
cfstring_array_convert(SmbOption& opt,
CFPropertyListRef val,
string_list& strings)
{
if (CFGetTypeID(val) == CFStringGetTypeID()) {
strings.clear();
strings.push_back(cfstring_convert((CFStringRef)val));
} else if (CFGetTypeID(val) == CFArrayGetTypeID()) {
strings.clear();
for (CFIndex i = 0; i < CFArrayGetCount((CFArrayRef)val); ++i) {
CFTypeRef strval = CFArrayGetValueAtIndex((CFArrayRef)val, i);
if (CFGetTypeID(strval) != CFStringGetTypeID()) {
VERBOSE("%s ignoring unexpected %s value\n",
opt.name(),
cftype_string(CFGetTypeID(strval)).c_str());
continue;
}
strings.push_back(cfstring_convert((CFStringRef)strval));
}
} else {
VERBOSE("%s expected %s or %s, but found %s\n",
opt.name(),
cftype_string(CFStringGetTypeID()).c_str(),
cftype_string(CFArrayGetTypeID()).c_str(),
cftype_string(CFGetTypeID(val)).c_str());
return false;
}
return true;
}
class KerberosOption : public SmbOption
{
public:
KerberosOption() : SmbOption("KerberosOption") {}
~KerberosOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
std::string m_managed;
std::string m_local;
};
void KerberosOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefKerberosRealm)))) {
CATCH_TYPE_ERROR(this->m_managed =
property_convert<std::string>(val));
}
if ((val = prefs.get_value(CFSTR(kSMBPrefLocalKerberosRealm)))) {
CATCH_TYPE_ERROR(this->m_local =
property_convert<std::string>(val));
}
}
void KerberosOption::emit(SmbConfig& smb)
{
if (this->m_managed.size() == 0 && this->m_local.size() == 0) {
return;
}
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("use kerberos keytab", true));
if (this->m_local.size() != 0) {
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("com.apple: lkdc realm", this->m_local));
}
if (this->m_managed.size() != 0) {
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("realm", this->m_managed));
} else if (this->m_local.size() != 0) {
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("realm", this->m_local));
}
}
class GuestAccessOption : public SmbOption
{
public:
GuestAccessOption(bool yesno)
: SmbOption(kSMBPrefAllowGuestAccess), m_guest(yesno) {}
~GuestAccessOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
bool m_guest;
};
void GuestAccessOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefAllowGuestAccess)))) {
CATCH_TYPE_ERROR(this->m_guest =
property_convert<bool>(val));
}
}
void GuestAccessOption::emit(SmbConfig& smb)
{
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("map to guest",
this->m_guest ? "Bad User" : "Never"));
smb.set_meta(make_smb_param("Guest access",
this->m_guest ? "per-share" : "never"));
}
class BrowseLevelOption : public SmbOption
{
public:
BrowseLevelOption() :SmbOption("BrowseLevel") {}
~BrowseLevelOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
std::string m_role;
std::string m_browse;
};
void BrowseLevelOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefServerRole)))) {
CATCH_TYPE_ERROR(this->m_role =
property_convert<std::string>(val));
}
if ((val = prefs.get_value(CFSTR(kSMBPrefMasterBrowser)))) {
CATCH_TYPE_ERROR(this->m_browse =
property_convert<std::string>(val));
}
}
void BrowseLevelOption::emit(SmbConfig& smb)
{
bool is_master = false;
if (this->m_role == kSMBPrefServerRolePDC) {
this->m_browse = kSMBPrefMasterBrowserDomain;
} else if (this->m_role == kSMBPrefServerRoleBDC) {
this->m_browse = kSMBPrefMasterBrowserLocal;
}
if (this->m_browse == kSMBPrefMasterBrowserDomain) {
smb.set_meta(make_smb_param("NetBIOS browsing",
"domain master browser"));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("domain master", true));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("preferred master", true));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("os level", 65));
is_master = true;
} else if (this->m_browse == kSMBPrefMasterBrowserLocal) {
smb.set_meta(make_smb_param("NetBIOS browsing",
"local master browser"));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("domain master", false));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("preferred master", true));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("os level", 65));
is_master = true;
} else {
smb.set_meta(make_smb_param("NetBIOS browsing",
"not a master browser"));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("domain master", false));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("preferred master", false));
}
if (is_master) {
smb.SmbdService().required(true);
smb.NmbdService().required(true);
}
}
class WinsRegisterOption : public SmbOption
{
public:
WinsRegisterOption(bool yesno)
: SmbOption(kSMBPrefRegisterWINSName), m_register(yesno) {}
~WinsRegisterOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
bool m_register;
string_list m_servers;
};
void WinsRegisterOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefRegisterWINSName)))) {
CATCH_TYPE_ERROR(this->m_register =
property_convert<bool>(val));
}
if ((val = prefs.get_value(CFSTR(kSMBPrefWINSServerAddressList)))) {
cfstring_array_convert(*this, val, this->m_servers);
}
}
void WinsRegisterOption::emit(SmbConfig& smb)
{
bool first = true;
struct in_addr addr;
std::ostringstream ostr;
if (this->m_servers.size() == 0 || !this->m_register) {
return;
}
for (string_list::const_iterator s = this->m_servers.begin();
s != this->m_servers.end(); ++s) {
if (!::inet_aton(s->c_str(), &addr)) {
VERBOSE("%s: '%s' is not a valid IPv4 address\n",
this->name(), s->c_str());
continue;
}
if (!first) {
ostr << ' ';
}
ostr << (*s);
first = false;
}
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("wins server", ostr.str()));
if (this->m_register) {
smb.NmbdService().required(true);
}
}
class ServicesOption : public SmbOption
{
public:
ServicesOption(bool disk, bool print, bool wins)
: SmbOption(kSMBPrefEnabledServices),
m_disk(disk), m_print(print), m_wins(wins)
{}
~ServicesOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
string_list m_services;
bool m_disk;
bool m_print;
bool m_wins;
};
void ServicesOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefEnabledServices)))) {
cfstring_array_convert(*this, val, this->m_services);
}
}
void ServicesOption::emit(SmbConfig& smb)
{
for (string_list::const_iterator s = this->m_services.begin();
s != this->m_services.end(); ++s) {
if (*s == kSMBPrefEnabledServicesDisk) {
this->m_disk = true;
smb.SmbdService().required(true);
smb.NmbdService().required(true);
} else if (*s == kSMBPrefEnabledServicesPrint) {
this->m_print = true;
smb.SmbdService().required(true);
smb.NmbdService().required(true);
} else if (*s == kSMBPrefEnabledServicesWins) {
this->m_wins = true;
smb.NmbdService().required(true);
}
}
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("enable disk services", this->m_disk));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("enable print services", this->m_print));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("wins support", this->m_wins));
}
class SuspendOption : public SmbOption
{
public:
SuspendOption(bool yesno)
: SmbOption(kSMBPrefSuspendServices),
m_value(yesno), m_isset(false)
{}
~SuspendOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
bool m_value;
bool m_isset;
};
void SuspendOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefSuspendServices)))) {
CATCH_TYPE_ERROR(
this->m_value = property_convert<bool>(val);
this->m_isset = true
);
}
}
void SuspendOption::emit(SmbConfig& smb)
{
if (this->m_isset) {
VERBOSE("setting %s %s\n", this->name(),
this->m_value ? "on" : "off");
Options::ForceSuspend = this->m_value;
}
}
class AutoSharesOption : public SmbOption
{
public:
AutoSharesOption(bool homes, bool admin)
: SmbOption("AutoShares"), m_homes(homes), m_admin(admin) {}
~AutoSharesOption() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
bool m_homes;
bool m_admin;
};
void AutoSharesOption::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefVirtualHomeShares)))) {
CATCH_TYPE_ERROR(this->m_homes =
property_convert<bool>(val));
}
if ((val = prefs.get_value(CFSTR(kSMBPrefVirtualAdminShares)))) {
CATCH_TYPE_ERROR(this->m_admin =
property_convert<bool>(val));
}
}
void AutoSharesOption::emit(SmbConfig& smb)
{
if (this->m_homes || this->m_admin) {
smb.set_param(SmbConfig::HOMES,
make_smb_param("comment", "User Home Directories"));
smb.set_param(SmbConfig::HOMES, make_smb_param("browseable", false));
smb.set_param(SmbConfig::HOMES, make_smb_param("read only", false));
smb.set_param(SmbConfig::HOMES, make_smb_param("create mode", "0750"));
smb.set_param(SmbConfig::HOMES, make_smb_param("guest ok", false));
}
smb.set_param(SmbConfig::HOMES,
make_smb_param("com.apple: show admin all volumes", this->m_admin));
}
class ServerRole : public SmbOption
{
public:
ServerRole(std::string role, bool guest)
: SmbOption(kSMBPrefServerRole), m_role(role), m_guest(guest) {}
~ServerRole() {}
void reset(const Preferences& prefs);
void emit(SmbConfig& smb);
private:
void configure_domain_logon(SmbConfig& smb);
std::string m_role;
bool m_guest;
static const char machine_script[];
static const char user_script[];
};
const char ServerRole::machine_script[] =
"/usr/bin/opendirectorypdbconfig -c create_computer_account "
"-r %u -n /LDAPv3/127.0.0.1";
const char ServerRole::user_script[] =
"/usr/bin/opendirectorypdbconfig -c create_user_account "
"-r %u -n /LDAPv3/127.0.0.1";
void ServerRole::reset(const Preferences& prefs)
{
CFPropertyListRef val;
if ((val = prefs.get_value(CFSTR(kSMBPrefServerRole)))) {
CATCH_TYPE_ERROR(this->m_role =
property_convert<std::string>(val));
}
if ((val = prefs.get_value(CFSTR(kSMBPrefAllowGuestAccess)))) {
CATCH_TYPE_ERROR(this->m_guest =
property_convert<bool>(val));
}
}
void ServerRole::emit(SmbConfig& smb)
{
const char * auth = "odsam";
smb.WinbindService().required(false);
if (this->m_role == kSMBPrefServerRoleADS) {
smb.WinbindService().required(true);
smb.set_param(SmbConfig::GLOBAL, make_smb_param("security", "ADS"));
} else if (this->m_role == kSMBPrefServerRolePDC) {
smb.set_param(SmbConfig::GLOBAL, make_smb_param("security", "USER"));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("add machine script", ServerRole::machine_script));
smb.set_param(SmbConfig::GLOBAL,
make_smb_param("add user script", ServerRole::user_script));
this->configure_domain_logon(smb);
} else if (this->m_role == kSMBPrefServerRoleBDC) {
smb.set_param(SmbConfig::GLOBAL, make_smb_param("security", "USER"));
this->configure_domain_logon(smb);
} else if (this->m_role == kSMBPrefServerRoleDomain) {
smb.set_param(SmbConfig::GLOBAL, make_smb_param("security", "DOMAIN"));
auth = "ntdomain odsam";
} else {
this->m_role = kSMBPrefServerRoleStandalone;
smb.set_param(SmbConfig::GLOBAL, make_smb_param("security", "USER"));
}
smb.set_param(SmbConfig::GLOBAL, make_smb_param("auth methods",
this->m_guest ? (std::string("guest ") + auth) : (auth)));
smb.set_meta(make_smb_param("Server role", this->m_role));
}
void ServerRole::configure_domain_logon(SmbConfig& smb)
{
ASSERT(this->m_role == kSMBPrefServerRoleBDC ||
this->m_role == kSMBPrefServerRolePDC);
smb.set_param(SmbConfig::GLOBAL, make_smb_param("domain logons", true));
smb.set_param(SmbConfig::HOMES, make_smb_param("root preexec",
"/usr/sbin/inituser %U"));
smb.set_param(SmbConfig::GLOBAL, make_smb_param("logon drive", "H:"));
smb.set_param(SmbConfig::GLOBAL, make_smb_param("logon path",
"\\\\%N\\profiles\\%u"));
smb.set_param(SmbConfig::NETLOGON, make_smb_param("path", "/etc/netlogon"));
smb.set_param(SmbConfig::NETLOGON, make_smb_param("browseable", false));
smb.set_param(SmbConfig::NETLOGON, make_smb_param("write list", "@admin"));
smb.set_param(SmbConfig::NETLOGON, make_smb_param("oplocks", true));
smb.set_param(SmbConfig::NETLOGON, make_smb_param("strict locking", false));
smb.set_param(SmbConfig::PROFILES, make_smb_param("path", "/Users/Profiles"));
smb.set_param(SmbConfig::PROFILES, make_smb_param("browseable", false));
smb.set_param(SmbConfig::PROFILES, make_smb_param("read only", false));
smb.set_param(SmbConfig::PROFILES, make_smb_param("oplocks", true));
smb.set_param(SmbConfig::PROFILES, make_smb_param("strict locking", false));
}
SmbRules::SmbRules()
{
this->m_version = std::string("$Id: rules.cpp 32909 2007-08-17 23:07:40Z jpeach $");
this->m_options.push_back(new ServerRole(kSMBPrefServerRoleStandalone,
false ));
this->m_options.push_back(new NullOption(kSMBPrefNetBIOSNodeType));
this->m_options.push_back(new NullOption(kSMBPrefAllowKerberosAuth));
this->m_options.push_back(new NullOption(kSMBPrefAllowNTLM2Auth));
this->m_options.push_back(new SimpleStringOption(kSMBPrefNetBIOSName,
"netbios name", ""));
this->m_options.push_back(new SimpleStringOption(kSMBPrefNetBIOSScope,
"netbios scope", ""));
this->m_options.push_back(new SimpleStringOption(kSMBPrefWorkgroup,
"workgroup", ""));
this->m_options.push_back(new SimpleStringOption(kSMBPrefKerberosRealm,
"realm", ""));
this->m_options.push_back(new SimpleStringOption(kSMBPrefDOSCodePage,
"dos charset", "CP437"));
this->m_options.push_back(new SimpleStringOption(kSMBPrefPasswordServer,
"password server", ""));
this->m_options.push_back(new SimpleStringOption(kSMBPrefServerDescription,
"server string", "Mac OS X"));
this->m_options.push_back(new SimpleBoolOption(kSMBPrefAllowNTLMAuth,
"ntlm auth", true));
this->m_options.push_back(new SimpleBoolOption(kSMBPrefAllowLanManAuth,
"lanman auth", false));
this->m_options.push_back(new SimpleIntOption(kSMBPrefMaxClients,
"max smbd processes", 10));
this->m_options.push_back(new SimpleIntOption(kSMBPrefLoggingLevel,
"log level", 1));
this->m_options.push_back(new SuspendOption(false));
this->m_options.push_back(new KerberosOption());
this->m_options.push_back(new GuestAccessOption(false));
this->m_options.push_back(new WinsRegisterOption(true ));
this->m_options.push_back(new BrowseLevelOption());
this->m_options.push_back(new AutoSharesOption(true, true));
this->m_options.push_back(new ServicesOption(false ,
false , false ));
}
SmbRules::~SmbRules()
{
for (iterator i = this->begin(); i != this->end(); ++i) {
delete *i;
}
}