diff --git a/azurelinuxagent/common/osutil/factory.py b/azurelinuxagent/common/osutil/factory.py index 0ef37f933..b63e8b111 100644 --- a/azurelinuxagent/common/osutil/factory.py +++ b/azurelinuxagent/common/osutil/factory.py @@ -33,6 +33,7 @@ from .bigip import BigIpOSUtil from .gaia import GaiaOSUtil from .iosxe import IosxeOSUtil +from .nsbsd import NSBSDOSUtil from distutils.version import LooseVersion as Version @@ -106,9 +107,12 @@ def get_osutil(distro_name=DISTRO_NAME, elif distro_name == "gaia": return GaiaOSUtil() - if distro_name == "iosxe": + elif distro_name == "iosxe": return IosxeOSUtil() + elif distro_name == "nsbsd": + return NSBSDOSUtil() + else: logger.warn("Unable to load distro implementation for {0}. Using " "default distro implementation instead.", diff --git a/azurelinuxagent/common/osutil/nsbsd.py b/azurelinuxagent/common/osutil/nsbsd.py new file mode 100644 index 000000000..db8221572 --- /dev/null +++ b/azurelinuxagent/common/osutil/nsbsd.py @@ -0,0 +1,159 @@ +# +# Copyright 2018 Stormshield +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import azurelinuxagent.common.utils.fileutil as fileutil +import azurelinuxagent.common.utils.shellutil as shellutil +import azurelinuxagent.common.utils.textutil as textutil +import azurelinuxagent.common.logger as logger +from azurelinuxagent.common.exception import OSUtilError +from azurelinuxagent.common.osutil.freebsd import FreeBSDOSUtil +from azurelinuxagent.common.future import ustr +import azurelinuxagent.common.conf as conf +import os +import time + +class NSBSDOSUtil(FreeBSDOSUtil): + + resolver = None + + def __init__(self): + super(NSBSDOSUtil, self).__init__() + + if self.resolver is None: + # NSBSD doesn't have a system resolver, configure a python one + + try: + import dns.resolver + except ImportError: + raise OSUtilError("Python DNS resolver not available. Cannot proceed!") + + self.resolver = dns.resolver.Resolver() + servers = [] + cmd = "getconf /usr/Firewall/ConfigFiles/dns Servers | tail -n +2" + ret, output = shellutil.run_get_output(cmd) + for server in output.split("\n"): + if server == '': + break + server = server[:-1] # remove last '=' + cmd = "grep '{}' /etc/hosts".format(server) + " | awk '{print $1}'" + ret, ip = shellutil.run_get_output(cmd) + servers.append(ip) + self.resolver.nameservers = servers + dns.resolver.override_system_resolver(self.resolver) + + def set_hostname(self, hostname): + shellutil.run("/usr/Firewall/sbin/setconf /usr/Firewall/System/global SystemName {0}".format(hostname)) + shellutil.run("/usr/Firewall/sbin/enlog") + shellutil.run("/usr/Firewall/sbin/enproxy -u") + shellutil.run("/usr/Firewall/sbin/ensl -u") + shellutil.run("/usr/Firewall/sbin/ennetwork -f") + + def restart_ssh_service(self): + return shellutil.run('/usr/Firewall/sbin/enservice', chk_err=False) + + def conf_sshd(self, disable_password): + option = "0" if disable_password else "1" + + shellutil.run('setconf /usr/Firewall/ConfigFiles/system SSH State 1', + chk_err=False) + shellutil.run('setconf /usr/Firewall/ConfigFiles/system SSH Password {}'.format(option), + chk_err=False) + shellutil.run('enservice', chk_err=False) + + logger.info("{0} SSH password-based authentication methods." + .format("Disabled" if disable_password else "Enabled")) + + def useradd(self, username, expiration=None): + """ + Create user account with 'username' + """ + logger.warn("User creation disabled") + return + + def del_account(self, username): + logger.warn("User deletion disabled") + + def conf_sudoer(self, username, nopasswd=False, remove=False): + logger.warn("Sudo is not enabled") + + def chpasswd(self, username, password, crypt_id=6, salt_len=10): + cmd = "/usr/Firewall/sbin/fwpasswd -p {0}".format(password) + ret, output = shellutil.run_get_output(cmd, log_cmd=False) + if ret != 0: + raise OSUtilError(("Failed to set password for admin: {0}" + "").format(output)) + + # password set, activate webadmin and ssh access + shellutil.run('setconf /usr/Firewall/ConfigFiles/webadmin ACL any && ensl', + chk_err=False) + + def deploy_ssh_pubkey(self, username, pubkey): + """ + Deploy authorized_key + """ + path, thumbprint, value = pubkey + + #overide parameters + super(NSBSDOSUtil, self).deploy_ssh_pubkey('admin', + ["/usr/Firewall/.ssh/authorized_keys", thumbprint, value]) + + def del_root_password(self): + logger.warn("Root password deletion disabled") + + def start_dhcp_service(self): + shellutil.run("/usr/Firewall/sbin/nstart dhclient", chk_err=False) + + def stop_dhcp_service(self): + shellutil.run("/usr/Firewall/sbin/nstop dhclient", chk_err=False) + + def get_dhcp_pid(self): + ret = None + pidfile = "/var/run/dhclient.pid" + + if os.path.isfile(pidfile): + ret = fileutil.read_file(pidfile, encoding='ascii') + return ret + + def eject_dvd(self, chk_err=True): + pass + + def restart_if(self, ifname): + # Restart dhclient only to publish hostname + shellutil.run("ennetwork", chk_err=False) + + def set_dhcp_hostname(self, hostname): + #already done by the dhcp client + pass + + def get_firewall_dropped_packets(self, dst_ip=None): + # disable iptables methods + return 0 + + def get_firewall_will_wait(self): + # disable iptables methods + return "" + + def _delete_rule(self, rule): + # disable iptables methods + return + + def remove_firewall(self, dst_ip=None, uid=None): + # disable iptables methods + return True + + def enable_firewall(self, dst_ip=None, uid=None): + # disable iptables methods + return True diff --git a/azurelinuxagent/common/version.py b/azurelinuxagent/common/version.py index f394df1d4..f4868e23e 100644 --- a/azurelinuxagent/common/version.py +++ b/azurelinuxagent/common/version.py @@ -82,6 +82,9 @@ def get_distro(): osinfo = ['openbsd', release, '', 'openbsd'] elif 'Linux' in platform.system(): osinfo = get_linux_distribution(0, 'alpine') + elif 'NS-BSD' in platform.system(): + release = re.sub('\-.*\Z', '', ustr(platform.release())) + osinfo = ['nsbsd', release, '', 'nsbsd'] else: try: # dist() removed in Python 3.7 diff --git a/config/nsbsd/waagent.conf b/config/nsbsd/waagent.conf new file mode 100644 index 000000000..7731da514 --- /dev/null +++ b/config/nsbsd/waagent.conf @@ -0,0 +1,117 @@ +# +# Microsoft Azure Linux Agent Configuration +# + +# Enable instance creation +Provisioning.Enabled=y + +# Rely on cloud-init to provision +Provisioning.UseCloudInit=n + +# Password authentication for root account will be unavailable. +Provisioning.DeleteRootPassword=n + +# Generate fresh host key pair. +Provisioning.RegenerateSshHostKeyPair=n + +# Supported values are "rsa", "dsa", "ecdsa", "ed25519", and "auto". +# The "auto" option is supported on OpenSSH 5.9 (2011) and later. +Provisioning.SshHostKeyPairType=rsa + +# Monitor host name changes and publish changes via DHCP requests. +Provisioning.MonitorHostName=y + +# Decode CustomData from Base64. +Provisioning.DecodeCustomData=n + +# Execute CustomData after provisioning. +Provisioning.ExecuteCustomData=n + +# Algorithm used by crypt when generating password hash. +#Provisioning.PasswordCryptId=6 + +# Length of random salt used when generating password hash. +#Provisioning.PasswordCryptSaltLength=10 + +# Format if unformatted. If 'n', resource disk will not be mounted. +ResourceDisk.Format=n + +# File system on the resource disk +# Typically ext3 or ext4. FreeBSD images should use 'ufs' here. +ResourceDisk.Filesystem=ufs + +# Mount point for the resource disk +ResourceDisk.MountPoint=/mnt/resource + +# Create and use swapfile on resource disk. +ResourceDisk.EnableSwap=n + +# Size of the swapfile. +ResourceDisk.SwapSizeMB=0 + +# Comma-seperated list of mount options. See man(8) for valid options. +ResourceDisk.MountOptions=None + +# Enable verbose logging (y|n) TODO set n +Logs.Verbose=n + +# Is FIPS enabled +OS.EnableFIPS=n + +# Root device timeout in seconds. +OS.RootDeviceScsiTimeout=300 + +# If "None", the system default version is used. +OS.OpensslPath=None + +# Set the path to SSH keys and configuration files +OS.SshDir=/etc/ssh + +OS.PasswordPath=/etc/master.passwd + +OS.SudoersDir=/usr/local/etc/sudoers.d + +# If set, agent will use proxy server to access internet +#HttpProxy.Host=None +#HttpProxy.Port=None + +# Detect Scvmm environment, default is n +# DetectScvmmEnv=n + +# +Lib.Dir=/usr/Firewall/var/waagent + +# +# DVD.MountPoint=/mnt/cdrom/secure + +# +# Pid.File=/var/run/waagent.pid + +# +Extension.LogDir=/log/azure + +# +# Home.Dir=/home + +# Enable RDMA management and set up, should only be used in HPC images +# OS.EnableRDMA=y + +# Enable or disable goal state processing auto-update, default is enabled +AutoUpdate.Enabled=n + +# Determine the update family, this should not be changed +# AutoUpdate.GAFamily=Prod + +# Determine if the overprovisioning feature is enabled. If yes, hold extension +# handling until inVMArtifactsProfile.OnHold is false. +# Default is disabled +# EnableOverProvisioning=n + +# Allow fallback to HTTP if HTTPS is unavailable +# Note: Allowing HTTP (vs. HTTPS) may cause security risks +# OS.AllowHTTP=n + +# Add firewall rules to protect access to Azure host node services +# Note: +# - The default is false to protect the state of existing VMs +OS.EnableFirewall=n