summaryrefslogtreecommitdiff
path: root/azurelinuxagent/distro/default/osutil.py
diff options
context:
space:
mode:
Diffstat (limited to 'azurelinuxagent/distro/default/osutil.py')
-rw-r--r--azurelinuxagent/distro/default/osutil.py623
1 files changed, 0 insertions, 623 deletions
diff --git a/azurelinuxagent/distro/default/osutil.py b/azurelinuxagent/distro/default/osutil.py
deleted file mode 100644
index 18ab2ba..0000000
--- a/azurelinuxagent/distro/default/osutil.py
+++ /dev/null
@@ -1,623 +0,0 @@
-#
-# Copyright 2014 Microsoft Corporation
-#
-# 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.
-#
-# Requires Python 2.4+ and Openssl 1.0+
-#
-
-import os
-import re
-import shutil
-import socket
-import array
-import struct
-import time
-import pwd
-import fcntl
-import base64
-import azurelinuxagent.logger as logger
-import azurelinuxagent.conf as conf
-from azurelinuxagent.exception import OSUtilError
-from azurelinuxagent.future import ustr
-import azurelinuxagent.utils.fileutil as fileutil
-import azurelinuxagent.utils.shellutil as shellutil
-import azurelinuxagent.utils.textutil as textutil
-from azurelinuxagent.utils.cryptutil import CryptUtil
-
-__RULES_FILES__ = [ "/lib/udev/rules.d/75-persistent-net-generator.rules",
- "/etc/udev/rules.d/70-persistent-net.rules" ]
-
-"""
-Define distro specific behavior. OSUtil class defines default behavior
-for all distros. Each concrete distro classes could overwrite default behavior
-if needed.
-"""
-
-class DefaultOSUtil(object):
-
- def __init__(self):
- self.agent_conf_file_path = '/etc/waagent.conf'
- self.selinux=None
-
- def get_agent_conf_file_path(self):
- return self.agent_conf_file_path
-
- def get_userentry(self, username):
- try:
- return pwd.getpwnam(username)
- except KeyError:
- return None
-
- def is_sys_user(self, username):
- """
- Check whether use is a system user.
- If reset sys user is allowed in conf, return False
- Otherwise, check whether UID is less than UID_MIN
- """
- if conf.get_allow_reset_sys_user():
- return False
-
- userentry = self.get_userentry(username)
- uidmin = None
- try:
- uidmin_def = fileutil.get_line_startingwith("UID_MIN",
- "/etc/login.defs")
- if uidmin_def is not None:
- uidmin = int(uidmin_def.split()[1])
- except IOError as e:
- pass
- if uidmin == None:
- uidmin = 100
- if userentry != None and userentry[2] < uidmin:
- return True
- else:
- return False
-
- def useradd(self, username, expiration=None):
- """
- Create user account with 'username'
- """
- userentry = self.get_userentry(username)
- if userentry is not None:
- logger.info("User {0} already exists, skip useradd", username)
- return
-
- if expiration is not None:
- cmd = "useradd -m {0} -e {1}".format(username, expiration)
- else:
- cmd = "useradd -m {0}".format(username)
- retcode, out = shellutil.run_get_output(cmd)
- if retcode != 0:
- raise OSUtilError(("Failed to create user account:{0}, "
- "retcode:{1}, "
- "output:{2}").format(username, retcode, out))
-
- def chpasswd(self, username, password, crypt_id=6, salt_len=10):
- if self.is_sys_user(username):
- raise OSUtilError(("User {0} is a system user. "
- "Will not set passwd.").format(username))
- passwd_hash = textutil.gen_password_hash(password, crypt_id, salt_len)
- cmd = "usermod -p '{0}' {1}".format(passwd_hash, username)
- ret, output = shellutil.run_get_output(cmd, log_cmd=False)
- if ret != 0:
- raise OSUtilError(("Failed to set password for {0}: {1}"
- "").format(username, output))
-
- def conf_sudoer(self, username, nopasswd):
- # for older distros create sudoers.d
- if not os.path.isdir('/etc/sudoers.d/'):
- # create the /etc/sudoers.d/ directory
- os.mkdir('/etc/sudoers.d/')
- # add the include of sudoers.d to the /etc/sudoers
- sudoers = '\n' + '#includedir /etc/sudoers.d/\n'
- fileutil.append_file('/etc/sudoers', sudoers)
- sudoer = None
- if nopasswd:
- sudoer = "{0} ALL = (ALL) NOPASSWD\n".format(username)
- else:
- sudoer = "{0} ALL = (ALL) ALL\n".format(username)
- fileutil.append_file('/etc/sudoers.d/waagent', sudoer)
- fileutil.chmod('/etc/sudoers.d/waagent', 0o440)
-
- def del_root_password(self):
- try:
- passwd_file_path = conf.get_passwd_file_path()
- passwd_content = fileutil.read_file(passwd_file_path)
- passwd = passwd_content.split('\n')
- new_passwd = [x for x in passwd if not x.startswith("root:")]
- new_passwd.insert(0, "root:*LOCK*:14600::::::")
- fileutil.write_file(passwd_file_path, "\n".join(new_passwd))
- except IOError as e:
- raise OSUtilError("Failed to delete root password:{0}".format(e))
-
- def _norm_path(self, filepath):
- home = conf.get_home_dir()
- # Expand HOME variable if present in path
- path = os.path.normpath(filepath.replace("$HOME", home))
- return path
-
- def deploy_ssh_keypair(self, username, keypair):
- """
- Deploy id_rsa and id_rsa.pub
- """
- path, thumbprint = keypair
- path = self._norm_path(path)
- dir_path = os.path.dirname(path)
- fileutil.mkdir(dir_path, mode=0o700, owner=username)
- lib_dir = conf.get_lib_dir()
- prv_path = os.path.join(lib_dir, thumbprint + '.prv')
- if not os.path.isfile(prv_path):
- raise OSUtilError("Can't find {0}.prv".format(thumbprint))
- shutil.copyfile(prv_path, path)
- pub_path = path + '.pub'
- crytputil = CryptUtil(conf.get_openssl_cmd())
- pub = crytputil.get_pubkey_from_prv(prv_path)
- fileutil.write_file(pub_path, pub)
- self.set_selinux_context(pub_path, 'unconfined_u:object_r:ssh_home_t:s0')
- self.set_selinux_context(path, 'unconfined_u:object_r:ssh_home_t:s0')
- os.chmod(path, 0o644)
- os.chmod(pub_path, 0o600)
-
- def openssl_to_openssh(self, input_file, output_file):
- cryptutil = CryptUtil(conf.get_openssl_cmd())
- cryptutil.crt_to_ssh(input_file, output_file)
-
- def deploy_ssh_pubkey(self, username, pubkey):
- """
- Deploy authorized_key
- """
- path, thumbprint, value = pubkey
- if path is None:
- raise OSUtilError("Publich key path is None")
-
- crytputil = CryptUtil(conf.get_openssl_cmd())
-
- path = self._norm_path(path)
- dir_path = os.path.dirname(path)
- fileutil.mkdir(dir_path, mode=0o700, owner=username)
- if value is not None:
- if not value.startswith("ssh-"):
- raise OSUtilError("Bad public key: {0}".format(value))
- fileutil.write_file(path, value)
- elif thumbprint is not None:
- lib_dir = conf.get_lib_dir()
- crt_path = os.path.join(lib_dir, thumbprint + '.crt')
- if not os.path.isfile(crt_path):
- raise OSUtilError("Can't find {0}.crt".format(thumbprint))
- pub_path = os.path.join(lib_dir, thumbprint + '.pub')
- pub = crytputil.get_pubkey_from_crt(crt_path)
- fileutil.write_file(pub_path, pub)
- self.set_selinux_context(pub_path,
- 'unconfined_u:object_r:ssh_home_t:s0')
- self.openssl_to_openssh(pub_path, path)
- fileutil.chmod(pub_path, 0o600)
- else:
- raise OSUtilError("SSH public key Fingerprint and Value are None")
-
- self.set_selinux_context(path, 'unconfined_u:object_r:ssh_home_t:s0')
- fileutil.chowner(path, username)
- fileutil.chmod(path, 0o644)
-
- def is_selinux_system(self):
- """
- Checks and sets self.selinux = True if SELinux is available on system.
- """
- if self.selinux == None:
- if shellutil.run("which getenforce", chk_err=False) == 0:
- self.selinux = True
- else:
- self.selinux = False
- return self.selinux
-
- def is_selinux_enforcing(self):
- """
- Calls shell command 'getenforce' and returns True if 'Enforcing'.
- """
- if self.is_selinux_system():
- output = shellutil.run_get_output("getenforce")[1]
- return output.startswith("Enforcing")
- else:
- return False
-
- def set_selinux_enforce(self, state):
- """
- Calls shell command 'setenforce' with 'state'
- and returns resulting exit code.
- """
- if self.is_selinux_system():
- if state: s = '1'
- else: s='0'
- return shellutil.run("setenforce "+s)
-
- def set_selinux_context(self, path, con):
- """
- Calls shell 'chcon' with 'path' and 'con' context.
- Returns exit result.
- """
- if self.is_selinux_system():
- return shellutil.run('chcon ' + con + ' ' + path)
-
- def set_ssh_client_alive_interval(self):
- conf_file_path = conf.get_sshd_conf_file_path()
- conf_file = fileutil.read_file(conf_file_path).split("\n")
- textutil.set_ssh_config(conf_file, "ClientAliveInterval", "180")
- fileutil.write_file(conf_file_path, '\n'.join(conf_file))
- logger.info("Configured SSH client probing to keep connections alive.")
-
- def conf_sshd(self, disable_password):
- option = "no" if disable_password else "yes"
- conf_file_path = conf.get_sshd_conf_file_path()
- conf_file = fileutil.read_file(conf_file_path).split("\n")
- textutil.set_ssh_config(conf_file, "PasswordAuthentication", option)
- textutil.set_ssh_config(conf_file, "ChallengeResponseAuthentication",
- option)
- fileutil.write_file(conf_file_path, "\n".join(conf_file))
- logger.info("Disabled SSH password-based authentication methods.")
-
-
- def get_dvd_device(self, dev_dir='/dev'):
- patten=r'(sr[0-9]|hd[c-z]|cdrom[0-9])'
- for dvd in [re.match(patten, dev) for dev in os.listdir(dev_dir)]:
- if dvd is not None:
- return "/dev/{0}".format(dvd.group(0))
- raise OSUtilError("Failed to get dvd device")
-
- def mount_dvd(self, max_retry=6, chk_err=True):
- dvd = self.get_dvd_device()
- mount_point = conf.get_dvd_mount_point()
- mountlist = shellutil.run_get_output("mount")[1]
- existing = self.get_mount_point(mountlist, dvd)
- if existing is not None: #Already mounted
- logger.info("{0} is already mounted at {1}", dvd, existing)
- return
- if not os.path.isdir(mount_point):
- os.makedirs(mount_point)
-
- for retry in range(0, max_retry):
- retcode = self.mount(dvd, mount_point, option="-o ro -t iso9660,udf",
- chk_err=chk_err)
- if retcode == 0:
- logger.info("Successfully mounted dvd")
- return
- if retry < max_retry - 1:
- logger.warn("Mount dvd failed: retry={0}, ret={1}", retry,
- retcode)
- time.sleep(5)
- if chk_err:
- raise OSUtilError("Failed to mount dvd.")
-
- def umount_dvd(self, chk_err=True):
- mount_point = conf.get_dvd_mount_point()
- retcode = self.umount(mount_point, chk_err=chk_err)
- if chk_err and retcode != 0:
- raise OSUtilError("Failed to umount dvd.")
-
- def eject_dvd(self, chk_err=True):
- dvd = self.get_dvd_device()
- retcode = shellutil.run("eject {0}".format(dvd))
- if chk_err and retcode != 0:
- raise OSUtilError("Failed to eject dvd: ret={0}".format(retcode))
-
- def load_atappix_mod(self):
- if self.is_atapiix_mod_loaded():
- return
- ret, kern_version = shellutil.run_get_output("uname -r")
- if ret != 0:
- raise Exception("Failed to call uname -r")
- mod_path = os.path.join('/lib/modules',
- kern_version.strip('\n'),
- 'kernel/drivers/ata/ata_piix.ko')
- if not os.path.isfile(mod_path):
- raise Exception("Can't find module file:{0}".format(mod_path))
-
- ret, output = shellutil.run_get_output("insmod " + mod_path)
- if ret != 0:
- raise Exception("Error calling insmod for ATAPI CD-ROM driver")
- if not self.is_atapiix_mod_loaded(max_retry=3):
- raise Exception("Failed to load ATAPI CD-ROM driver")
-
- def is_atapiix_mod_loaded(self, max_retry=1):
- for retry in range(0, max_retry):
- ret = shellutil.run("lsmod | grep ata_piix", chk_err=False)
- if ret == 0:
- logger.info("Module driver for ATAPI CD-ROM is already present.")
- return True
- if retry < max_retry - 1:
- time.sleep(1)
- return False
-
- def mount(self, dvd, mount_point, option="", chk_err=True):
- cmd = "mount {0} {1} {2}".format(dvd, option, mount_point)
- return shellutil.run_get_output(cmd, chk_err)[0]
-
- def umount(self, mount_point, chk_err=True):
- return shellutil.run("umount {0}".format(mount_point), chk_err=chk_err)
-
- def allow_dhcp_broadcast(self):
- #Open DHCP port if iptables is enabled.
- # We supress error logging on error.
- shellutil.run("iptables -D INPUT -p udp --dport 68 -j ACCEPT",
- chk_err=False)
- shellutil.run("iptables -I INPUT -p udp --dport 68 -j ACCEPT",
- chk_err=False)
-
-
- def remove_rules_files(self, rules_files=__RULES_FILES__):
- lib_dir = conf.get_lib_dir()
- for src in rules_files:
- file_name = fileutil.base_name(src)
- dest = os.path.join(lib_dir, file_name)
- if os.path.isfile(dest):
- os.remove(dest)
- if os.path.isfile(src):
- logger.warn("Move rules file {0} to {1}", file_name, dest)
- shutil.move(src, dest)
-
- def restore_rules_files(self, rules_files=__RULES_FILES__):
- lib_dir = conf.get_lib_dir()
- for dest in rules_files:
- filename = fileutil.base_name(dest)
- src = os.path.join(lib_dir, filename)
- if os.path.isfile(dest):
- continue
- if os.path.isfile(src):
- logger.warn("Move rules file {0} to {1}", filename, dest)
- shutil.move(src, dest)
-
- def get_mac_addr(self):
- """
- Convienience function, returns mac addr bound to
- first non-loobback interface.
- """
- ifname=''
- while len(ifname) < 2 :
- ifname=self.get_first_if()[0]
- addr = self.get_if_mac(ifname)
- return textutil.hexstr_to_bytearray(addr)
-
- def get_if_mac(self, ifname):
- """
- Return the mac-address bound to the socket.
- """
- sock = socket.socket(socket.AF_INET,
- socket.SOCK_DGRAM,
- socket.IPPROTO_UDP)
- param = struct.pack('256s', (ifname[:15]+('\0'*241)).encode('latin-1'))
- info = fcntl.ioctl(sock.fileno(), 0x8927, param)
- return ''.join(['%02X' % textutil.str_to_ord(char) for char in info[18:24]])
-
- def get_first_if(self):
- """
- Return the interface name, and ip addr of the
- first active non-loopback interface.
- """
- iface=''
- expected=16 # how many devices should I expect...
- struct_size=40 # for 64bit the size is 40 bytes
- sock = socket.socket(socket.AF_INET,
- socket.SOCK_DGRAM,
- socket.IPPROTO_UDP)
- buff=array.array('B', b'\0' * (expected * struct_size))
- param = struct.pack('iL',
- expected*struct_size,
- buff.buffer_info()[0])
- ret = fcntl.ioctl(sock.fileno(), 0x8912, param)
- retsize=(struct.unpack('iL', ret)[0])
- if retsize == (expected * struct_size):
- logger.warn(('SIOCGIFCONF returned more than {0} up '
- 'network interfaces.'), expected)
- sock = buff.tostring()
- for i in range(0, struct_size * expected, struct_size):
- iface=sock[i:i+16].split(b'\0', 1)[0]
- if iface == b'lo':
- continue
- else:
- break
- return iface.decode('latin-1'), socket.inet_ntoa(sock[i+20:i+24])
-
- def is_missing_default_route(self):
- routes = shellutil.run_get_output("route -n")[1]
- for route in routes.split("\n"):
- if route.startswith("0.0.0.0 ") or route.startswith("default "):
- return False
- return True
-
- def get_if_name(self):
- return self.get_first_if()[0]
-
- def get_ip4_addr(self):
- return self.get_first_if()[1]
-
- def set_route_for_dhcp_broadcast(self, ifname):
- return shellutil.run("route add 255.255.255.255 dev {0}".format(ifname),
- chk_err=False)
-
- def remove_route_for_dhcp_broadcast(self, ifname):
- shellutil.run("route del 255.255.255.255 dev {0}".format(ifname),
- chk_err=False)
-
- def is_dhcp_enabled(self):
- return False
-
- def stop_dhcp_service(self):
- pass
-
- def start_dhcp_service(self):
- pass
-
- def start_network(self):
- pass
-
- def start_agent_service(self):
- pass
-
- def stop_agent_service(self):
- pass
-
- def register_agent_service(self):
- pass
-
- def unregister_agent_service(self):
- pass
-
- def restart_ssh_service(self):
- pass
-
- def route_add(self, net, mask, gateway):
- """
- Add specified route using /sbin/route add -net.
- """
- cmd = ("/sbin/route add -net "
- "{0} netmask {1} gw {2}").format(net, mask, gateway)
- return shellutil.run(cmd, chk_err=False)
-
- def get_dhcp_pid(self):
- ret= shellutil.run_get_output("pidof dhclient")
- return ret[1] if ret[0] == 0 else None
-
- def set_hostname(self, hostname):
- fileutil.write_file('/etc/hostname', hostname)
- shellutil.run("hostname {0}".format(hostname), chk_err=False)
-
- def set_dhcp_hostname(self, hostname):
- autosend = r'^[^#]*?send\s*host-name.*?(<hostname>|gethostname[(,)])'
- dhclient_files = ['/etc/dhcp/dhclient.conf', '/etc/dhcp3/dhclient.conf']
- for conf_file in dhclient_files:
- if not os.path.isfile(conf_file):
- continue
- if fileutil.findstr_in_file(conf_file, autosend):
- #Return if auto send host-name is configured
- return
- fileutil.update_conf_file(conf_file,
- 'send host-name',
- 'send host-name {0}'.format(hostname))
-
- def restart_if(self, ifname):
- shellutil.run("ifdown {0} && ifup {1}".format(ifname, ifname))
-
- def publish_hostname(self, hostname):
- self.set_dhcp_hostname(hostname)
- ifname = self.get_if_name()
- self.restart_if(ifname)
-
- def set_scsi_disks_timeout(self, timeout):
- for dev in os.listdir("/sys/block"):
- if dev.startswith('sd'):
- self.set_block_device_timeout(dev, timeout)
-
- def set_block_device_timeout(self, dev, timeout):
- if dev is not None and timeout is not None:
- file_path = "/sys/block/{0}/device/timeout".format(dev)
- content = fileutil.read_file(file_path)
- original = content.splitlines()[0].rstrip()
- if original != timeout:
- fileutil.write_file(file_path, timeout)
- logger.info("Set block dev timeout: {0} with timeout: {1}",
- dev, timeout)
-
- def get_mount_point(self, mountlist, device):
- """
- Example of mountlist:
- /dev/sda1 on / type ext4 (rw)
- proc on /proc type proc (rw)
- sysfs on /sys type sysfs (rw)
- devpts on /dev/pts type devpts (rw,gid=5,mode=620)
- tmpfs on /dev/shm type tmpfs
- (rw,rootcontext="system_u:object_r:tmpfs_t:s0")
- none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
- /dev/sdb1 on /mnt/resource type ext4 (rw)
- """
- if (mountlist and device):
- for entry in mountlist.split('\n'):
- if(re.search(device, entry)):
- tokens = entry.split()
- #Return the 3rd column of this line
- return tokens[2] if len(tokens) > 2 else None
- return None
-
- def device_for_ide_port(self, port_id):
- """
- Return device name attached to ide port 'n'.
- """
- if port_id > 3:
- return None
- g0 = "00000000"
- if port_id > 1:
- g0 = "00000001"
- port_id = port_id - 2
- device = None
- path = "/sys/bus/vmbus/devices/"
- for vmbus in os.listdir(path):
- deviceid = fileutil.read_file(os.path.join(path, vmbus, "device_id"))
- guid = deviceid.lstrip('{').split('-')
- if guid[0] == g0 and guid[1] == "000" + ustr(port_id):
- for root, dirs, files in os.walk(path + vmbus):
- if root.endswith("/block"):
- device = dirs[0]
- break
- else : #older distros
- for d in dirs:
- if ':' in d and "block" == d.split(':')[0]:
- device = d.split(':')[1]
- break
- break
- return device
-
- def del_account(self, username):
- if self.is_sys_user(username):
- logger.error("{0} is a system user. Will not delete it.", username)
- shellutil.run("> /var/run/utmp")
- shellutil.run("userdel -f -r " + username)
- #Remove user from suders
- if os.path.isfile("/etc/suders.d/waagent"):
- try:
- content = fileutil.read_file("/etc/sudoers.d/waagent")
- sudoers = content.split("\n")
- sudoers = [x for x in sudoers if username not in x]
- fileutil.write_file("/etc/sudoers.d/waagent",
- "\n".join(sudoers))
- except IOError as e:
- raise OSUtilError("Failed to remove sudoer: {0}".format(e))
-
- def decode_customdata(self, data):
- return base64.b64decode(data)
-
- def get_total_mem(self):
- cmd = "grep MemTotal /proc/meminfo |awk '{print $2}'"
- ret = shellutil.run_get_output(cmd)
- if ret[0] == 0:
- return int(ret[1])/1024
- else:
- raise OSUtilError("Failed to get total memory: {0}".format(ret[1]))
-
- def get_processor_cores(self):
- ret = shellutil.run_get_output("grep 'processor.*:' /proc/cpuinfo |wc -l")
- if ret[0] == 0:
- return int(ret[1])
- else:
- raise OSUtilError("Failed to get procerssor cores")
-
- def set_admin_access_to_ip(self, dest_ip):
- #This allows root to access dest_ip
- rm_old= "iptables -D OUTPUT -d {0} -j ACCEPT -m owner --uid-owner 0"
- rule = "iptables -A OUTPUT -d {0} -j ACCEPT -m owner --uid-owner 0"
- shellutil.run(rm_old.format(dest_ip), chk_err=False)
- shellutil.run(rule.format(dest_ip))
-
- #This blocks all other users to access dest_ip
- rm_old = "iptables -D OUTPUT -d {0} -j DROP"
- rule = "iptables -A OUTPUT -d {0} -j DROP"
- shellutil.run(rm_old.format(dest_ip), chk_err=False)
- shellutil.run(rule.format(dest_ip))
-