cloud-mu 1.9.0.pre.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Berksfile +56 -0
- data/Berksfile.lock +250 -0
- data/Jenkinsfile +184 -0
- data/LICENSE.md +37 -0
- data/README.md +26 -0
- data/bin/mu-aws-setup +376 -0
- data/bin/mu-cleanup +68 -0
- data/bin/mu-configure +1133 -0
- data/bin/mu-deploy +166 -0
- data/bin/mu-firewall-allow-clients +30 -0
- data/bin/mu-gcp-setup +200 -0
- data/bin/mu-gen-docs +34 -0
- data/bin/mu-gen-env +42 -0
- data/bin/mu-load-config.rb +158 -0
- data/bin/mu-node-manage +683 -0
- data/bin/mu-self-update +228 -0
- data/bin/mu-ssh +23 -0
- data/bin/mu-tunnel-nagios +144 -0
- data/bin/mu-upload-chef-artifacts +757 -0
- data/bin/mu-user-manage +275 -0
- data/cookbooks/awscli/LICENSE +37 -0
- data/cookbooks/awscli/README.md +58 -0
- data/cookbooks/awscli/attributes/default.rb +1 -0
- data/cookbooks/awscli/libraries/instance_metadata.rb +21 -0
- data/cookbooks/awscli/metadata.rb +20 -0
- data/cookbooks/awscli/recipes/default.rb +56 -0
- data/cookbooks/awscli/templates/default/config.erb +18 -0
- data/cookbooks/mu-activedirectory/CHANGELOG.md +13 -0
- data/cookbooks/mu-activedirectory/LICENSE +37 -0
- data/cookbooks/mu-activedirectory/README.md +6 -0
- data/cookbooks/mu-activedirectory/attributes/default.rb +98 -0
- data/cookbooks/mu-activedirectory/files/default/password-auth +32 -0
- data/cookbooks/mu-activedirectory/files/default/sshd_pol.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/sshd_pol.te +32 -0
- data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.te +10 -0
- data/cookbooks/mu-activedirectory/files/default/system-auth +34 -0
- data/cookbooks/mu-activedirectory/files/default/winbindpol.pp +0 -0
- data/cookbooks/mu-activedirectory/files/default/winbindpol.te +37 -0
- data/cookbooks/mu-activedirectory/libraries/config.rb +106 -0
- data/cookbooks/mu-activedirectory/libraries/helper.rb +86 -0
- data/cookbooks/mu-activedirectory/metadata.rb +17 -0
- data/cookbooks/mu-activedirectory/providers/domain.rb +152 -0
- data/cookbooks/mu-activedirectory/providers/domain_controller.rb +89 -0
- data/cookbooks/mu-activedirectory/providers/domain_node.rb +275 -0
- data/cookbooks/mu-activedirectory/recipes/default.rb +8 -0
- data/cookbooks/mu-activedirectory/recipes/domain-controller.rb +44 -0
- data/cookbooks/mu-activedirectory/recipes/domain-node.rb +50 -0
- data/cookbooks/mu-activedirectory/recipes/domain.rb +43 -0
- data/cookbooks/mu-activedirectory/recipes/sssd.rb +185 -0
- data/cookbooks/mu-activedirectory/resources/domain.rb +25 -0
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +25 -0
- data/cookbooks/mu-activedirectory/resources/domain_node.rb +20 -0
- data/cookbooks/mu-activedirectory/templates/default/dhclient-eth0.conf.erb +4 -0
- data/cookbooks/mu-activedirectory/templates/default/interface +0 -0
- data/cookbooks/mu-activedirectory/templates/default/krb5.conf.erb +23 -0
- data/cookbooks/mu-activedirectory/templates/default/ntp.conf.erb +56 -0
- data/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +33 -0
- data/cookbooks/mu-activedirectory/templates/default/sssd.conf.erb +60 -0
- data/cookbooks/mu-activedirectory/templates/windows/Backup.xml.erb +20 -0
- data/cookbooks/mu-activedirectory/templates/windows/bkupInfo.xml.erb +1 -0
- data/cookbooks/mu-activedirectory/templates/windows/gpreprt.xml.erb +198 -0
- data/cookbooks/mu-activedirectory/templates/windows/gptmpl.inf.erb +12 -0
- data/cookbooks/mu-activedirectory/templates/windows/manifest.xml.erb +1 -0
- data/cookbooks/mu-firewall/CHANGELOG.md +11 -0
- data/cookbooks/mu-firewall/LICENSE +37 -0
- data/cookbooks/mu-firewall/README.md +5 -0
- data/cookbooks/mu-firewall/attributes/default.rb +3 -0
- data/cookbooks/mu-firewall/metadata.rb +16 -0
- data/cookbooks/mu-firewall/recipes/default.rb +10 -0
- data/cookbooks/mu-glusterfs/CHANGELOG.md +13 -0
- data/cookbooks/mu-glusterfs/LICENSE +37 -0
- data/cookbooks/mu-glusterfs/README.md +5 -0
- data/cookbooks/mu-glusterfs/attributes/default.rb +34 -0
- data/cookbooks/mu-glusterfs/metadata.rb +17 -0
- data/cookbooks/mu-glusterfs/recipes/client.rb +62 -0
- data/cookbooks/mu-glusterfs/recipes/default.rb +16 -0
- data/cookbooks/mu-glusterfs/recipes/samba.rb +57 -0
- data/cookbooks/mu-glusterfs/recipes/server.rb +200 -0
- data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +71 -0
- data/cookbooks/mu-glusterfs/templates/default/smb.conf.erb +14 -0
- data/cookbooks/mu-jenkins/CHANGELOG.md +13 -0
- data/cookbooks/mu-jenkins/LICENSE +37 -0
- data/cookbooks/mu-jenkins/README.md +105 -0
- data/cookbooks/mu-jenkins/attributes/default.rb +42 -0
- data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +73 -0
- data/cookbooks/mu-jenkins/files/default/deploy_config.xml +44 -0
- data/cookbooks/mu-jenkins/metadata.rb +21 -0
- data/cookbooks/mu-jenkins/recipes/default.rb +195 -0
- data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +54 -0
- data/cookbooks/mu-jenkins/recipes/public_key.rb +24 -0
- data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +24 -0
- data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +14 -0
- data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +6 -0
- data/cookbooks/mu-master/CHANGELOG.md +13 -0
- data/cookbooks/mu-master/LICENSE +37 -0
- data/cookbooks/mu-master/README.md +6 -0
- data/cookbooks/mu-master/attributes/default.rb +95 -0
- data/cookbooks/mu-master/files/default/0-mu-log-server.conf +19 -0
- data/cookbooks/mu-master/files/default/addRSA.ldif +8 -0
- data/cookbooks/mu-master/files/default/check_mem.pl +197 -0
- data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
- data/cookbooks/mu-master/files/default/dirsrv_admin.pp +0 -0
- data/cookbooks/mu-master/files/default/dirsrv_admin.te +13 -0
- data/cookbooks/mu-master/files/default/nagios_selinux.pp +0 -0
- data/cookbooks/mu-master/files/default/nagios_selinux.te +51 -0
- data/cookbooks/mu-master/files/default/nagios_selinux_7.pp +0 -0
- data/cookbooks/mu-master/files/default/nagios_selinux_7.te +17 -0
- data/cookbooks/mu-master/files/default/pam_sshd +18 -0
- data/cookbooks/mu-master/files/default/ssl_enable.ldif +18 -0
- data/cookbooks/mu-master/files/default/syslogd_oddjobd.pp +0 -0
- data/cookbooks/mu-master/files/default/syslogd_oddjobd.te +10 -0
- data/cookbooks/mu-master/files/default/vimrc +19 -0
- data/cookbooks/mu-master/libraries/mu.rb +29 -0
- data/cookbooks/mu-master/metadata.rb +30 -0
- data/cookbooks/mu-master/providers/user.rb +41 -0
- data/cookbooks/mu-master/recipes/389ds.rb +164 -0
- data/cookbooks/mu-master/recipes/basepackages.rb +58 -0
- data/cookbooks/mu-master/recipes/caching_nameserver.rb +37 -0
- data/cookbooks/mu-master/recipes/default.rb +451 -0
- data/cookbooks/mu-master/recipes/eks-kubectl.rb +41 -0
- data/cookbooks/mu-master/recipes/firewall-holes.rb +70 -0
- data/cookbooks/mu-master/recipes/init.rb +542 -0
- data/cookbooks/mu-master/recipes/ssl-certs.rb +109 -0
- data/cookbooks/mu-master/recipes/sssd.rb +89 -0
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +242 -0
- data/cookbooks/mu-master/recipes/vault.rb +111 -0
- data/cookbooks/mu-master/resources/user.rb +19 -0
- data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +28 -0
- data/cookbooks/mu-master/templates/default/chef-server.rb.erb +18 -0
- data/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +9 -0
- data/cookbooks/mu-master/templates/default/mu-momma-cat.erb +149 -0
- data/cookbooks/mu-master/templates/default/mu.rc.erb +9 -0
- data/cookbooks/mu-master/templates/default/openssl.cnf.erb +354 -0
- data/cookbooks/mu-master/templates/default/sssd.conf.erb +44 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +90 -0
- data/cookbooks/mu-mongo/CHANGELOG.md +13 -0
- data/cookbooks/mu-mongo/LICENSE +37 -0
- data/cookbooks/mu-mongo/README.md +5 -0
- data/cookbooks/mu-mongo/attributes/default.rb +22 -0
- data/cookbooks/mu-mongo/files/default/keyfile +16 -0
- data/cookbooks/mu-mongo/files/default/remove_nodes.js +5 -0
- data/cookbooks/mu-mongo/metadata.rb +17 -0
- data/cookbooks/mu-mongo/recipes/default.rb +149 -0
- data/cookbooks/mu-mongo/recipes/yum-update-rule.rb +18 -0
- data/cookbooks/mu-mongo/templates/default/mongo_create_openfema_db.js.erb +2 -0
- data/cookbooks/mu-mongo/templates/default/mongo_init.js.erb +1 -0
- data/cookbooks/mu-mongo/templates/default/mongo_logrotate.erb +14 -0
- data/cookbooks/mu-mongo/templates/default/mongo_replset_addnodes.js.erb +6 -0
- data/cookbooks/mu-mongo/templates/default/replset_init.js.erb +2 -0
- data/cookbooks/mu-openvpn/CHANGELOG.md +13 -0
- data/cookbooks/mu-openvpn/LICENSE +37 -0
- data/cookbooks/mu-openvpn/README.md +6 -0
- data/cookbooks/mu-openvpn/attributes/default.rb +119 -0
- data/cookbooks/mu-openvpn/metadata.rb +18 -0
- data/cookbooks/mu-openvpn/recipes/default.rb +108 -0
- data/cookbooks/mu-openvpn/templates/default/users.json.erb +42 -0
- data/cookbooks/mu-php54/CHANGELOG.md +12 -0
- data/cookbooks/mu-php54/LICENSE +37 -0
- data/cookbooks/mu-php54/README.md +0 -0
- data/cookbooks/mu-php54/files/centos/php.ini +1802 -0
- data/cookbooks/mu-php54/files/ubuntu/php.ini +1870 -0
- data/cookbooks/mu-php54/metadata.rb +21 -0
- data/cookbooks/mu-php54/recipes/default.rb +97 -0
- data/cookbooks/mu-splunk/CHANGELOG.md +37 -0
- data/cookbooks/mu-splunk/LICENSE +37 -0
- data/cookbooks/mu-splunk/README.md +451 -0
- data/cookbooks/mu-splunk/attributes/default.rb +95 -0
- data/cookbooks/mu-splunk/attributes/upgrade.rb +49 -0
- data/cookbooks/mu-splunk/definitions/splunk_installer.rb +103 -0
- data/cookbooks/mu-splunk/files/default/splunk-nocheck +10 -0
- data/cookbooks/mu-splunk/libraries/helpers.rb +72 -0
- data/cookbooks/mu-splunk/libraries/splunk_app_provider.rb +156 -0
- data/cookbooks/mu-splunk/libraries/splunk_app_resource.rb +43 -0
- data/cookbooks/mu-splunk/metadata.json +30 -0
- data/cookbooks/mu-splunk/metadata.rb +17 -0
- data/cookbooks/mu-splunk/recipes/client.rb +143 -0
- data/cookbooks/mu-splunk/recipes/default.rb +31 -0
- data/cookbooks/mu-splunk/recipes/disabled.rb +41 -0
- data/cookbooks/mu-splunk/recipes/install_forwarder.rb +23 -0
- data/cookbooks/mu-splunk/recipes/install_server.rb +23 -0
- data/cookbooks/mu-splunk/recipes/server.rb +53 -0
- data/cookbooks/mu-splunk/recipes/service.rb +95 -0
- data/cookbooks/mu-splunk/recipes/setup_auth.rb +49 -0
- data/cookbooks/mu-splunk/recipes/setup_ssl.rb +63 -0
- data/cookbooks/mu-splunk/recipes/upgrade.rb +94 -0
- data/cookbooks/mu-splunk/recipes/user.rb +34 -0
- data/cookbooks/mu-splunk/templates/default/base_logs_unix_inputs.conf.erb +26 -0
- data/cookbooks/mu-splunk/templates/default/inputs.conf.erb +13 -0
- data/cookbooks/mu-splunk/templates/default/outputs.conf.erb +9 -0
- data/cookbooks/mu-splunk/templates/default/splunk-init.erb +74 -0
- data/cookbooks/mu-splunk/templates/default/system-web.conf.erb +7 -0
- data/cookbooks/mu-tools/CHANGELOG.md +12 -0
- data/cookbooks/mu-tools/LICENSE +37 -0
- data/cookbooks/mu-tools/README.md +188 -0
- data/cookbooks/mu-tools/attributes/default.rb +142 -0
- data/cookbooks/mu-tools/attributes/ebs_rolling_snapshots.rb +3 -0
- data/cookbooks/mu-tools/files/amazon/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/centos/CentOS-Base.repo +52 -0
- data/cookbooks/mu-tools/files/centos/etc/bashrc +93 -0
- data/cookbooks/mu-tools/files/centos/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/centos/etc/login.defs +72 -0
- data/cookbooks/mu-tools/files/centos/etc/profile +77 -0
- data/cookbooks/mu-tools/files/centos/etc/security/limits.conf +57 -0
- data/cookbooks/mu-tools/files/centos/etc/sysconfig/init +19 -0
- data/cookbooks/mu-tools/files/centos/etc/sysctl.conf +82 -0
- data/cookbooks/mu-tools/files/centos-6/README_MU +0 -0
- data/cookbooks/mu-tools/files/centos-6/etc/audit/stig.rules +173 -0
- data/cookbooks/mu-tools/files/centos-6/etc/bashrc +90 -0
- data/cookbooks/mu-tools/files/centos-6/etc/login.defs +70 -0
- data/cookbooks/mu-tools/files/centos-6/etc/pam.d/su +12 -0
- data/cookbooks/mu-tools/files/centos-6/etc/profile +83 -0
- data/cookbooks/mu-tools/files/centos-6/etc/securetty +12 -0
- data/cookbooks/mu-tools/files/centos-6/etc/sysconfig/init +30 -0
- data/cookbooks/mu-tools/files/centos-6/etc/sysctl.conf +40 -0
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +34 -0
- data/cookbooks/mu-tools/files/default/PSWindowsUpdate.zip +0 -0
- data/cookbooks/mu-tools/files/default/ebs_snapshots.py +123 -0
- data/cookbooks/mu-tools/files/default/etc/BANNER +0 -0
- data/cookbooks/mu-tools/files/default/etc/BANNER-FEDERAL +19 -0
- data/cookbooks/mu-tools/files/default/gpo_no_uac.zip +0 -0
- data/cookbooks/mu-tools/files/default/mypol.pp +0 -0
- data/cookbooks/mu-tools/files/default/mypol.te +37 -0
- data/cookbooks/mu-tools/files/default/nrpe_c7.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_c7.te +31 -0
- data/cookbooks/mu-tools/files/default/nrpe_check_disk.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_check_disk.te +11 -0
- data/cookbooks/mu-tools/files/default/nrpe_disk.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_disk.te +10 -0
- data/cookbooks/mu-tools/files/default/nrpe_file.pp +0 -0
- data/cookbooks/mu-tools/files/default/nrpe_file.te +31 -0
- data/cookbooks/mu-tools/files/default/ntrights +0 -0
- data/cookbooks/mu-tools/files/default/serverclass.conf +18 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/app.conf +1 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/inputs.conf +13 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/app.conf +1 -0
- data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/inputs.conf +8 -0
- data/cookbooks/mu-tools/files/default/sshd_pol.pp +0 -0
- data/cookbooks/mu-tools/files/default/sshd_pol.te +32 -0
- data/cookbooks/mu-tools/files/redhat/etc/bashrc +93 -0
- data/cookbooks/mu-tools/files/redhat/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/redhat/etc/login.defs +72 -0
- data/cookbooks/mu-tools/files/redhat/etc/profile +77 -0
- data/cookbooks/mu-tools/files/redhat/etc/security/limits.conf +57 -0
- data/cookbooks/mu-tools/files/redhat/etc/sysconfig/init +19 -0
- data/cookbooks/mu-tools/files/redhat/etc/sysctl.conf +82 -0
- data/cookbooks/mu-tools/files/redhat-6/README_MU +0 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/audit/stig.rules +173 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/bashrc +90 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/login.defs +70 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/pam.d/su +12 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/profile +83 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/securetty +12 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/sysconfig/init +30 -0
- data/cookbooks/mu-tools/files/redhat-6/etc/sysctl.conf +40 -0
- data/cookbooks/mu-tools/files/redhat-7.1/etc/freshclam.conf +235 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/bash.bashrc +64 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/common-session +30 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/login.defs +338 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/profile +30 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/security/limits.conf +56 -0
- data/cookbooks/mu-tools/files/ubuntu-12.04/etc/sysctl.conf +60 -0
- data/cookbooks/mu-tools/libraries/helper.rb +292 -0
- data/cookbooks/mu-tools/metadata.rb +28 -0
- data/cookbooks/mu-tools/recipes/add_admin_ssh_keys.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +440 -0
- data/cookbooks/mu-tools/recipes/aws_api.rb +23 -0
- data/cookbooks/mu-tools/recipes/base_repositories.rb +31 -0
- data/cookbooks/mu-tools/recipes/cisbenchmark.rb +59 -0
- data/cookbooks/mu-tools/recipes/clamav.rb +53 -0
- data/cookbooks/mu-tools/recipes/cloudinit.rb +58 -0
- data/cookbooks/mu-tools/recipes/configure_oracle_tools.rb +81 -0
- data/cookbooks/mu-tools/recipes/disable-requiretty.rb +22 -0
- data/cookbooks/mu-tools/recipes/ebs_rolling_snapshots.rb +75 -0
- data/cookbooks/mu-tools/recipes/efs.rb +70 -0
- data/cookbooks/mu-tools/recipes/eks.rb +160 -0
- data/cookbooks/mu-tools/recipes/gcloud.rb +98 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +25 -0
- data/cookbooks/mu-tools/recipes/maldet.rb +67 -0
- data/cookbooks/mu-tools/recipes/nagios.rb +19 -0
- data/cookbooks/mu-tools/recipes/newclient.rb +23 -0
- data/cookbooks/mu-tools/recipes/nrpe.rb +115 -0
- data/cookbooks/mu-tools/recipes/python_pip.rb +35 -0
- data/cookbooks/mu-tools/recipes/retrieve_application.rb +51 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +65 -0
- data/cookbooks/mu-tools/recipes/set_local_fw.rb +57 -0
- data/cookbooks/mu-tools/recipes/set_mu_hostname.rb +81 -0
- data/cookbooks/mu-tools/recipes/split_var_partitions.rb +86 -0
- data/cookbooks/mu-tools/recipes/splunk-client.rb +69 -0
- data/cookbooks/mu-tools/recipes/splunk-server.rb +104 -0
- data/cookbooks/mu-tools/recipes/store_inspec_attr.rb +8 -0
- data/cookbooks/mu-tools/recipes/updates.rb +96 -0
- data/cookbooks/mu-tools/recipes/windows-client.rb +202 -0
- data/cookbooks/mu-tools/resources/aws_windows.rb +33 -0
- data/cookbooks/mu-tools/resources/disk.rb +88 -0
- data/cookbooks/mu-tools/resources/mommacat_request.rb +11 -0
- data/cookbooks/mu-tools/resources/scheduled_tasks.rb +29 -0
- data/cookbooks/mu-tools/resources/sshd_service.rb +45 -0
- data/cookbooks/mu-tools/resources/windows_users.rb +242 -0
- data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +168 -0
- data/cookbooks/mu-tools/templates/centos-6/sshd_config.erb +212 -0
- data/cookbooks/mu-tools/templates/centos-7/sshd_config.erb +215 -0
- data/cookbooks/mu-tools/templates/default/0-mu-log-client.conf.erb +13 -0
- data/cookbooks/mu-tools/templates/default/conf.maldet.erb +137 -0
- data/cookbooks/mu-tools/templates/default/etc_hosts.erb +30 -0
- data/cookbooks/mu-tools/templates/default/etc_pamd_password-auth.erb +14 -0
- data/cookbooks/mu-tools/templates/default/etc_pamd_system-auth.erb +14 -0
- data/cookbooks/mu-tools/templates/default/etc_sysconfig_network.erb +12 -0
- data/cookbooks/mu-tools/templates/default/kubeconfig.erb +29 -0
- data/cookbooks/mu-tools/templates/default/kubelet.service.erb +35 -0
- data/cookbooks/mu-tools/templates/default/maldet_scanall.sh.erb +15 -0
- data/cookbooks/mu-tools/templates/default/nrpe.cfg.erb +233 -0
- data/cookbooks/mu-tools/templates/redhat-6/sshd_config.erb +213 -0
- data/cookbooks/mu-tools/templates/redhat-7/sshd_config.erb +215 -0
- data/cookbooks/mu-tools/templates/ubuntu-12.04/sshd_config.erb +146 -0
- data/cookbooks/mu-tools/templates/ubuntu-14.04/sshd_config.erb +145 -0
- data/cookbooks/mu-tools/templates/windows/Backup.xml.erb +20 -0
- data/cookbooks/mu-tools/templates/windows/bkupInfo.xml.erb +1 -0
- data/cookbooks/mu-tools/templates/windows/gpreprt.xml.erb +214 -0
- data/cookbooks/mu-tools/templates/windows/gptmpl.inf.erb +12 -0
- data/cookbooks/mu-tools/templates/windows/manifest.xml.erb +1 -0
- data/cookbooks/mu-tools/templates/windows/set_ad_dns_scheduled_task.ps1.erb +6 -0
- data/cookbooks/mu-tools/templates/windows/sshd_config.erb +136 -0
- data/cookbooks/mu-utility/CHANGELOG.md +12 -0
- data/cookbooks/mu-utility/LICENSE +37 -0
- data/cookbooks/mu-utility/README.md +6 -0
- data/cookbooks/mu-utility/attributes/default.rb +1 -0
- data/cookbooks/mu-utility/libraries/matchers.rb +21 -0
- data/cookbooks/mu-utility/metadata.rb +16 -0
- data/cookbooks/mu-utility/recipes/apt.rb +23 -0
- data/cookbooks/mu-utility/recipes/cleanup_image_helper.rb +118 -0
- data/cookbooks/mu-utility/recipes/iptables.rb +26 -0
- data/cookbooks/mu-utility/recipes/luks.rb +18 -0
- data/cookbooks/mu-utility/recipes/nat.rb +104 -0
- data/cookbooks/mu-utility/recipes/php.rb +33 -0
- data/cookbooks/mu-utility/recipes/rdp_gateway.rb +83 -0
- data/cookbooks/mu-utility/recipes/remi.rb +44 -0
- data/cookbooks/mu-utility/recipes/vim.rb +26 -0
- data/cookbooks/mu-utility/recipes/windows_basics.rb +37 -0
- data/cookbooks/mu-utility/recipes/zip.rb +26 -0
- data/cookbooks/mu-utility/templates/default/BundleConfig.xml.erb +34 -0
- data/cookbooks/mu-utility/templates/default/config.xml.erb +60 -0
- data/cookbooks/nagios/Berksfile +8 -0
- data/cookbooks/nagios/CHANGELOG.md +589 -0
- data/cookbooks/nagios/CONTRIBUTING.md +11 -0
- data/cookbooks/nagios/LICENSE +37 -0
- data/cookbooks/nagios/README.md +328 -0
- data/cookbooks/nagios/TESTING.md +2 -0
- data/cookbooks/nagios/attributes/config.rb +171 -0
- data/cookbooks/nagios/attributes/default.rb +228 -0
- data/cookbooks/nagios/chefignore +102 -0
- data/cookbooks/nagios/definitions/command.rb +33 -0
- data/cookbooks/nagios/definitions/contact.rb +33 -0
- data/cookbooks/nagios/definitions/contactgroup.rb +33 -0
- data/cookbooks/nagios/definitions/host.rb +33 -0
- data/cookbooks/nagios/definitions/hostdependency.rb +33 -0
- data/cookbooks/nagios/definitions/hostescalation.rb +34 -0
- data/cookbooks/nagios/definitions/hostgroup.rb +33 -0
- data/cookbooks/nagios/definitions/nagios_conf.rb +38 -0
- data/cookbooks/nagios/definitions/resource.rb +33 -0
- data/cookbooks/nagios/definitions/service.rb +33 -0
- data/cookbooks/nagios/definitions/servicedependency.rb +33 -0
- data/cookbooks/nagios/definitions/serviceescalation.rb +34 -0
- data/cookbooks/nagios/definitions/servicegroup.rb +33 -0
- data/cookbooks/nagios/definitions/timeperiod.rb +33 -0
- data/cookbooks/nagios/libraries/base.rb +314 -0
- data/cookbooks/nagios/libraries/command.rb +91 -0
- data/cookbooks/nagios/libraries/contact.rb +230 -0
- data/cookbooks/nagios/libraries/contactgroup.rb +112 -0
- data/cookbooks/nagios/libraries/custom_option.rb +36 -0
- data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
- data/cookbooks/nagios/libraries/default.rb +90 -0
- data/cookbooks/nagios/libraries/host.rb +412 -0
- data/cookbooks/nagios/libraries/hostdependency.rb +181 -0
- data/cookbooks/nagios/libraries/hostescalation.rb +173 -0
- data/cookbooks/nagios/libraries/hostgroup.rb +119 -0
- data/cookbooks/nagios/libraries/nagios.rb +282 -0
- data/cookbooks/nagios/libraries/resource.rb +59 -0
- data/cookbooks/nagios/libraries/service.rb +455 -0
- data/cookbooks/nagios/libraries/servicedependency.rb +215 -0
- data/cookbooks/nagios/libraries/serviceescalation.rb +195 -0
- data/cookbooks/nagios/libraries/servicegroup.rb +144 -0
- data/cookbooks/nagios/libraries/timeperiod.rb +160 -0
- data/cookbooks/nagios/libraries/users_helper.rb +54 -0
- data/cookbooks/nagios/metadata.rb +25 -0
- data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
- data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
- data/cookbooks/nagios/recipes/apache.rb +48 -0
- data/cookbooks/nagios/recipes/default.rb +204 -0
- data/cookbooks/nagios/recipes/nginx.rb +82 -0
- data/cookbooks/nagios/recipes/pagerduty.rb +143 -0
- data/cookbooks/nagios/recipes/server_package.rb +40 -0
- data/cookbooks/nagios/recipes/server_source.rb +164 -0
- data/cookbooks/nagios/templates/default/apache2.conf.erb +96 -0
- data/cookbooks/nagios/templates/default/cgi.cfg.erb +266 -0
- data/cookbooks/nagios/templates/default/commands.cfg.erb +13 -0
- data/cookbooks/nagios/templates/default/contacts.cfg.erb +37 -0
- data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +25 -0
- data/cookbooks/nagios/templates/default/hosts.cfg.erb +15 -0
- data/cookbooks/nagios/templates/default/htpasswd.users.erb +6 -0
- data/cookbooks/nagios/templates/default/nagios.cfg.erb +22 -0
- data/cookbooks/nagios/templates/default/nginx.conf.erb +62 -0
- data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +185 -0
- data/cookbooks/nagios/templates/default/resource.cfg.erb +27 -0
- data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +15 -0
- data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +14 -0
- data/cookbooks/nagios/templates/default/services.cfg.erb +14 -0
- data/cookbooks/nagios/templates/default/templates.cfg.erb +31 -0
- data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +13 -0
- data/cookbooks/s3fs/CHANGELOG.md +13 -0
- data/cookbooks/s3fs/LICENSE +37 -0
- data/cookbooks/s3fs/README.md +6 -0
- data/cookbooks/s3fs/attributes/default.rb +15 -0
- data/cookbooks/s3fs/files/default/fuse-2.9.3.zip +0 -0
- data/cookbooks/s3fs/metadata.rb +16 -0
- data/cookbooks/s3fs/recipes/default.rb +91 -0
- data/data_bags/demo/app.json +7 -0
- data/data_bags/nagios_services/chef.json +6 -0
- data/data_bags/nagios_services/linux_diskspace.json +5 -0
- data/data_bags/nagios_services/momma_cat.json +6 -0
- data/data_bags/nagios_services/mu-master-memory.json +5 -0
- data/data_bags/nagios_services/nagios_ui.json +6 -0
- data/data_bags/nagios_services/node_ssh.json +6 -0
- data/data_bags/nagios_services/ssh.json +6 -0
- data/demo/lambda_test.yaml +29 -0
- data/environments/DEV.json +8 -0
- data/environments/PROD.json +8 -0
- data/environments/dev.json +8 -0
- data/environments/development.json +8 -0
- data/environments/prod.json +8 -0
- data/extras/README.md +1 -0
- data/extras/admin-role-binding.yaml +16 -0
- data/extras/admin-user.yaml +6 -0
- data/extras/aws-auth-cm.yaml.erb +12 -0
- data/extras/clean-stock-amis +48 -0
- data/extras/git-fix-permissions-hook +12 -0
- data/extras/gitlab-eks-helper.sh.erb +20 -0
- data/extras/image-generators/README.md +2 -0
- data/extras/image-generators/aws/centos6.yaml +18 -0
- data/extras/image-generators/aws/centos7-govcloud.yaml +24 -0
- data/extras/image-generators/aws/centos7.yaml +17 -0
- data/extras/image-generators/aws/rhel7.yaml +17 -0
- data/extras/image-generators/aws/win2k12.yaml +16 -0
- data/extras/image-generators/aws/win2k16.yaml +16 -0
- data/extras/image-generators/aws/windows.yaml +18 -0
- data/extras/image-generators/gcp/centos6.yaml +17 -0
- data/extras/lambda_waf_domain_blacklist.py +103 -0
- data/extras/platform_berksfile_base +50 -0
- data/extras/ruby_rpm/build.sh +17 -0
- data/extras/ruby_rpm/muby.spec +44 -0
- data/extras/vault_tools/README.md +6 -0
- data/extras/vault_tools/export_vaults.sh +3 -0
- data/extras/vault_tools/recreate_vaults.sh +5 -0
- data/extras/vault_tools/test_vaults.sh +5 -0
- data/install/README.md +8 -0
- data/install/cfn_create_mu_master.json +1034 -0
- data/install/chef-server.rb.erb +19 -0
- data/install/deprecated-bash-library.sh +1891 -0
- data/install/images/Usage.png +0 -0
- data/install/installer +71 -0
- data/install/jenkinskeys.rb +8 -0
- data/install/user-dot-murc.erb +14 -0
- data/modules/html.erb +19 -0
- data/modules/mommacat.ru +426 -0
- data/modules/mu/cleanup.rb +339 -0
- data/modules/mu/cloud.rb +1446 -0
- data/modules/mu/clouds/README.md +201 -0
- data/modules/mu/clouds/aws/alarm.rb +319 -0
- data/modules/mu/clouds/aws/cache_cluster.rb +1010 -0
- data/modules/mu/clouds/aws/collection.rb +373 -0
- data/modules/mu/clouds/aws/container_cluster.rb +667 -0
- data/modules/mu/clouds/aws/database.rb +1836 -0
- data/modules/mu/clouds/aws/dnszone.rb +911 -0
- data/modules/mu/clouds/aws/firewall_rule.rb +641 -0
- data/modules/mu/clouds/aws/folder.rb +92 -0
- data/modules/mu/clouds/aws/function.rb +349 -0
- data/modules/mu/clouds/aws/group.rb +251 -0
- data/modules/mu/clouds/aws/loadbalancer.rb +888 -0
- data/modules/mu/clouds/aws/log.rb +363 -0
- data/modules/mu/clouds/aws/msg_queue.rb +480 -0
- data/modules/mu/clouds/aws/notification.rb +139 -0
- data/modules/mu/clouds/aws/role.rb +656 -0
- data/modules/mu/clouds/aws/search_domain.rb +646 -0
- data/modules/mu/clouds/aws/server.rb +2294 -0
- data/modules/mu/clouds/aws/server_pool.rb +1388 -0
- data/modules/mu/clouds/aws/storage_pool.rb +495 -0
- data/modules/mu/clouds/aws/user.rb +382 -0
- data/modules/mu/clouds/aws/userdata/README.md +4 -0
- data/modules/mu/clouds/aws/userdata/linux.erb +179 -0
- data/modules/mu/clouds/aws/userdata/windows.erb +278 -0
- data/modules/mu/clouds/aws/vpc.rb +1943 -0
- data/modules/mu/clouds/aws.rb +1009 -0
- data/modules/mu/clouds/cloudformation/alarm.rb +146 -0
- data/modules/mu/clouds/cloudformation/cache_cluster.rb +167 -0
- data/modules/mu/clouds/cloudformation/collection.rb +117 -0
- data/modules/mu/clouds/cloudformation/database.rb +278 -0
- data/modules/mu/clouds/cloudformation/dnszone.rb +274 -0
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +308 -0
- data/modules/mu/clouds/cloudformation/loadbalancer.rb +193 -0
- data/modules/mu/clouds/cloudformation/log.rb +170 -0
- data/modules/mu/clouds/cloudformation/server.rb +370 -0
- data/modules/mu/clouds/cloudformation/server_pool.rb +279 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +322 -0
- data/modules/mu/clouds/cloudformation.rb +733 -0
- data/modules/mu/clouds/docker.rb +30 -0
- data/modules/mu/clouds/google/container_cluster.rb +290 -0
- data/modules/mu/clouds/google/database.rb +152 -0
- data/modules/mu/clouds/google/firewall_rule.rb +267 -0
- data/modules/mu/clouds/google/group.rb +164 -0
- data/modules/mu/clouds/google/loadbalancer.rb +479 -0
- data/modules/mu/clouds/google/server.rb +1510 -0
- data/modules/mu/clouds/google/server_pool.rb +274 -0
- data/modules/mu/clouds/google/user.rb +266 -0
- data/modules/mu/clouds/google/userdata/README.md +4 -0
- data/modules/mu/clouds/google/userdata/linux.erb +137 -0
- data/modules/mu/clouds/google/userdata/windows.erb +275 -0
- data/modules/mu/clouds/google/vpc.rb +890 -0
- data/modules/mu/clouds/google.rb +811 -0
- data/modules/mu/config/README.md +11 -0
- data/modules/mu/config/alarm.rb +271 -0
- data/modules/mu/config/cache_cluster.rb +172 -0
- data/modules/mu/config/collection.rb +87 -0
- data/modules/mu/config/container_cluster.rb +103 -0
- data/modules/mu/config/container_cluster.yml +36 -0
- data/modules/mu/config/database.rb +458 -0
- data/modules/mu/config/database.yml +26 -0
- data/modules/mu/config/dnszone.rb +327 -0
- data/modules/mu/config/firewall_rule.rb +118 -0
- data/modules/mu/config/folder.rb +70 -0
- data/modules/mu/config/function.rb +140 -0
- data/modules/mu/config/group.rb +64 -0
- data/modules/mu/config/loadbalancer.rb +482 -0
- data/modules/mu/config/log.rb +47 -0
- data/modules/mu/config/log.yml +6 -0
- data/modules/mu/config/msg_queue.rb +47 -0
- data/modules/mu/config/msg_queue.yml +9 -0
- data/modules/mu/config/notification.rb +44 -0
- data/modules/mu/config/project.rb +71 -0
- data/modules/mu/config/role.rb +102 -0
- data/modules/mu/config/search_domain.rb +61 -0
- data/modules/mu/config/search_domain.yml +25 -0
- data/modules/mu/config/server.rb +587 -0
- data/modules/mu/config/server.yml +8 -0
- data/modules/mu/config/server_pool.rb +216 -0
- data/modules/mu/config/server_pool.yml +71 -0
- data/modules/mu/config/storage_pool.rb +145 -0
- data/modules/mu/config/user.rb +78 -0
- data/modules/mu/config/vpc.rb +743 -0
- data/modules/mu/config/vpc.yml +6 -0
- data/modules/mu/config.rb +2000 -0
- data/modules/mu/defaults/README.md +2 -0
- data/modules/mu/defaults/amazon_images.yaml +121 -0
- data/modules/mu/defaults/google_images.yaml +16 -0
- data/modules/mu/deploy.rb +686 -0
- data/modules/mu/groomer.rb +123 -0
- data/modules/mu/groomers/README.md +58 -0
- data/modules/mu/groomers/chef.rb +1024 -0
- data/modules/mu/kittens.rb +11319 -0
- data/modules/mu/logger.rb +208 -0
- data/modules/mu/master/README.md +27 -0
- data/modules/mu/master/chef.rb +471 -0
- data/modules/mu/master/ldap.rb +1005 -0
- data/modules/mu/master.rb +415 -0
- data/modules/mu/mommacat.rb +2703 -0
- data/modules/mu-load-config.rb +1 -0
- data/modules/mu.rb +724 -0
- data/modules/scratchpad.erb +1 -0
- data/modules/tests/super_complex_bok.yml +41 -0
- data/modules/tests/super_simple_bok.yml +40 -0
- data/mu.gemspec +62 -0
- data/roles/demo-dbservice-configure.json +19 -0
- data/roles/demo-portal-configure.json +19 -0
- data/roles/mu-master-jenkins.json +24 -0
- data/roles/mu-master-nagios-only.json +13 -0
- data/roles/mu-master.json +12 -0
- data/roles/mu-node.json +19 -0
- data/roles/mu-splunk-server.json +13 -0
- data/roles/mu-splunk.json +13 -0
- data/test/clean_up.py +25 -0
- data/test/demo-test-profile/README.md +3 -0
- data/test/demo-test-profile/controls/flask.rb +84 -0
- data/test/demo-test-profile/inspec.lock +7 -0
- data/test/demo-test-profile/inspec.yml +11 -0
- data/test/etco-test-profile/README.md +3 -0
- data/test/etco-test-profile/controls/all-in-one.rb +182 -0
- data/test/etco-test-profile/inspec.lock +7 -0
- data/test/etco-test-profile/inspec.yml +11 -0
- data/test/exec_inspec.py +246 -0
- data/test/exec_mu_install.py +241 -0
- data/test/exec_retry.py +44 -0
- data/test/mu-master-test/README.md +3 -0
- data/test/mu-master-test/controls/all_in_one.rb +557 -0
- data/test/mu-master-test/inspec.lock +3 -0
- data/test/mu-master-test/inspec.yml +11 -0
- data/test/mu-tools-test/README.md +3 -0
- data/test/mu-tools-test/controls/base.rb +265 -0
- data/test/mu-tools-test/inspec.lock +3 -0
- data/test/mu-tools-test/inspec.yml +8 -0
- data/test/simple-server-php-test/README.md +3 -0
- data/test/simple-server-php-test/controls/apachephp.rb +25 -0
- data/test/simple-server-php-test/controls/example.rb +19 -0
- data/test/simple-server-php-test/inspec.lock +7 -0
- data/test/simple-server-php-test/inspec.yml +12 -0
- data/test/simple-server-rails-test/README.md +3 -0
- data/test/simple-server-rails-test/controls/rails.rb +188 -0
- data/test/simple-server-rails-test/inspec.lock +7 -0
- data/test/simple-server-rails-test/inspec.yml +11 -0
- data/test/simple-windows-test/README.md +3 -0
- data/test/simple-windows-test/controls/windows.rb +20 -0
- data/test/simple-windows-test/inspec.lock +7 -0
- data/test/simple-windows-test/inspec.yml +11 -0
- data/test/smoke_test.rb +75 -0
- data/test/wordpress-test/README.md +3 -0
- data/test/wordpress-test/controls/wordpress.rb +97 -0
- data/test/wordpress-test/inspec.lock +7 -0
- data/test/wordpress-test/inspec.yml +11 -0
- metadata +979 -0
|
@@ -0,0 +1,1005 @@
|
|
|
1
|
+
#!/usr/local/ruby-current/bin/ruby
|
|
2
|
+
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the BSD-3 license (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License in the root of the project or at
|
|
7
|
+
#
|
|
8
|
+
# http://egt-labs.com/mu/LICENSE.html
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
require 'net-ldap'
|
|
17
|
+
|
|
18
|
+
module MU
|
|
19
|
+
class Master
|
|
20
|
+
# Routines for manipulating users and groups in 389 Directory Services or Active Directory.
|
|
21
|
+
class LDAP
|
|
22
|
+
|
|
23
|
+
# Exception class specifically for LDAP-related errors
|
|
24
|
+
class MuLDAPError < MU::MuError;end
|
|
25
|
+
require 'date'
|
|
26
|
+
|
|
27
|
+
# Make sure the LDAP section of $MU_CFG makes sense.
|
|
28
|
+
def self.validateConfig(skipvaults: false)
|
|
29
|
+
ok = true
|
|
30
|
+
supported = ["Active Directory", "389 Directory Services"]
|
|
31
|
+
if !$MU_CFG
|
|
32
|
+
raise MuLDAPError, "Configuration not loaded yet, but MU::Master::LDAP.validateConfig was called!"
|
|
33
|
+
end
|
|
34
|
+
if !$MU_CFG.has_key?("ldap")
|
|
35
|
+
raise MuLDAPError "Missing 'ldap' section of config (files: #{$MU_CFG['config_files']})"
|
|
36
|
+
end
|
|
37
|
+
ldap = $MU_CFG["ldap"] # shorthand
|
|
38
|
+
if !ldap.has_key?("type") or !supported.include?(ldap["type"])
|
|
39
|
+
ok = false
|
|
40
|
+
MU.log "Bad or missing 'type' of LDAP server (should be one of #{supported})", MU::ERR
|
|
41
|
+
end
|
|
42
|
+
["base_dn", "user_ou", "domain_name", "domain_netbios_name", "user_group_dn", "user_group_name", "admin_group_dn", "admin_group_name"].each { |var|
|
|
43
|
+
if !ldap.has_key?(var) or !ldap[var].is_a?(String)
|
|
44
|
+
ok = false
|
|
45
|
+
MU.log "LDAP config section parameter '#{var}' is missing or is not a String", MU::ERR
|
|
46
|
+
end
|
|
47
|
+
}
|
|
48
|
+
if !ldap.has_key?("dcs") or !ldap["dcs"].is_a?(Array) or ldap["dcs"].size < 1
|
|
49
|
+
ok = false
|
|
50
|
+
MU.log "Missing or empty 'dcs' section of LDAP config"
|
|
51
|
+
end
|
|
52
|
+
["bind_creds", "join_creds"].each { |creds|
|
|
53
|
+
if !ldap.has_key?(creds) or !ldap[creds].is_a?(Hash) or
|
|
54
|
+
!ldap[creds].has_key?("vault") or !ldap[creds].has_key?("item") or
|
|
55
|
+
!ldap[creds].has_key?("username_field") or
|
|
56
|
+
!ldap[creds].has_key?("password_field")
|
|
57
|
+
MU.log "LDAP config subsection '#{creds}' misconfigured, should be hash containing: vault, item, username_field, password_field", MU::ERR
|
|
58
|
+
ok = false
|
|
59
|
+
next
|
|
60
|
+
end
|
|
61
|
+
if !skipvaults
|
|
62
|
+
loaded = MU::Groomer::Chef.getSecret(vault: ldap[creds]["vault"], item: ldap[creds]["item"])
|
|
63
|
+
if !loaded or !loaded.has_key?(ldap[creds]["username_field"]) or
|
|
64
|
+
loaded[ldap[creds]["username_field"]].empty? or
|
|
65
|
+
!loaded.has_key?(ldap[creds]["password_field"]) or
|
|
66
|
+
loaded[ldap[creds]["password_field"]].empty?
|
|
67
|
+
MU.log "LDAP config subsection '#{creds}' refers to a bogus vault or incorrect/missing item fields", MU::ERR, details: ldap[creds]
|
|
68
|
+
ok = false
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
}
|
|
72
|
+
if !ok
|
|
73
|
+
raise MuLDAPError, "One or more LDAP configuration errors from files #{$MU_CFG['config_files']}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
@ldap_conn = nil
|
|
78
|
+
@gid_attr = "cn"
|
|
79
|
+
@gidnum_attr = "gidNumber"
|
|
80
|
+
@member_attr = "memberUid"
|
|
81
|
+
@uid_attr = "uid"
|
|
82
|
+
@group_class = "posixGroup"
|
|
83
|
+
@uid_range_start = 10000
|
|
84
|
+
@gid_range_start = 10000
|
|
85
|
+
# Create and return a connection to our directory service. If we've
|
|
86
|
+
# already opened one, return that.
|
|
87
|
+
# @param username [String]: Optional alternative bind user, usually just used to see if someone knows their password
|
|
88
|
+
# @param password [String]: Optional alternative bind password
|
|
89
|
+
# @return [Net::LDAP]
|
|
90
|
+
def self.getLDAPConnection(username: nil, password: nil)
|
|
91
|
+
return @ldap_conn if @ldap_conn
|
|
92
|
+
validateConfig(skipvaults: (username and password))
|
|
93
|
+
if $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
94
|
+
@gid_attr = "sAMAccountName"
|
|
95
|
+
@member_attr = "member"
|
|
96
|
+
@uid_attr = "sAMAccountName"
|
|
97
|
+
@group_class = "group"
|
|
98
|
+
@user_class = "user"
|
|
99
|
+
end
|
|
100
|
+
if (username and !password) or (password and !username)
|
|
101
|
+
raise MuLDAPError, "When supply credentials to getLDAPConnection, both username and password must be specified"
|
|
102
|
+
end
|
|
103
|
+
if !username and !password
|
|
104
|
+
bind_creds = MU::Groomer::Chef.getSecret(vault: $MU_CFG["ldap"]["bind_creds"]["vault"], item: $MU_CFG["ldap"]["bind_creds"]["item"])
|
|
105
|
+
username = bind_creds[$MU_CFG["ldap"]["bind_creds"]["username_field"]]
|
|
106
|
+
password = bind_creds[$MU_CFG["ldap"]["bind_creds"]["password_field"]]
|
|
107
|
+
end
|
|
108
|
+
@ldap_conn = Net::LDAP.new(
|
|
109
|
+
:host => $MU_CFG["ldap"]["dcs"].first,
|
|
110
|
+
:encryption => {
|
|
111
|
+
:method => :simple_tls,
|
|
112
|
+
:tls_options => {}
|
|
113
|
+
},
|
|
114
|
+
:port => 636,
|
|
115
|
+
:base => $MU_CFG["ldap"]["base_dn"],
|
|
116
|
+
:auth => {
|
|
117
|
+
:method => :simple,
|
|
118
|
+
:username => username,
|
|
119
|
+
:password => password
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
@ldap_conn
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# If there is an active LDAP connection loaded, close it. Well, nil it
|
|
126
|
+
# out. There's no close method, that's theoretically handled in garbage
|
|
127
|
+
# collection.
|
|
128
|
+
def self.dropLDAPConnection
|
|
129
|
+
@ldap_conn = nil
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Fetch a list of numeric uids that are already allocated
|
|
133
|
+
def self.getUsedUids
|
|
134
|
+
used_uids = []
|
|
135
|
+
if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
136
|
+
user_filter = Net::LDAP::Filter.ne("objectclass", "computer") & Net::LDAP::Filter.ne("objectclass", "group")
|
|
137
|
+
conn = getLDAPConnection
|
|
138
|
+
conn.search(
|
|
139
|
+
:filter => user_filter,
|
|
140
|
+
:base => $MU_CFG["ldap"]["base_dn"],
|
|
141
|
+
:attributes => ["employeeNumber"]
|
|
142
|
+
) do |acct|
|
|
143
|
+
if acct[:employeenumber] and acct[:employeenumber].size > 0
|
|
144
|
+
used_uids << acct[:employeenumber].first.to_i
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
else
|
|
148
|
+
Etc.passwd{ |u|
|
|
149
|
+
if !user.nil? and u.name == user and mu_acct
|
|
150
|
+
raise MuLDAPError, "Username #{user} already exists as a system user, cannot allocate in directory"
|
|
151
|
+
end
|
|
152
|
+
used_uids << u.uid
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
used_uids
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Find a user ID not currently in use from the local system's perspective
|
|
159
|
+
def self.allocateUID
|
|
160
|
+
MU::MommaCat.lock("uid_generator", false, true)
|
|
161
|
+
used_uids = getUsedUids
|
|
162
|
+
|
|
163
|
+
for x in @uid_range_start..65535 do
|
|
164
|
+
if !used_uids.include?(x)
|
|
165
|
+
MU::MommaCat.unlock("uid_generator", true)
|
|
166
|
+
return x.to_s
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
MU::MommaCat.unlock("uid_generator", true)
|
|
170
|
+
return nil
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Find a group ID not currently in use from the local system's perspective
|
|
174
|
+
# XXX this is vulnerable to a race condition, and may not account for
|
|
175
|
+
# things in the directory
|
|
176
|
+
def self.allocateGID(group: nil)
|
|
177
|
+
MU::MommaCat.lock("gid_generator", false, true)
|
|
178
|
+
used_gids = []
|
|
179
|
+
Etc.group{ |g|
|
|
180
|
+
if !group.nil? and g.name == group
|
|
181
|
+
raise MuLDAPError, "Group #{group} already exists as a local system group, cannot allocate in directory"
|
|
182
|
+
end
|
|
183
|
+
used_gids << g.gid
|
|
184
|
+
}
|
|
185
|
+
conn = getLDAPConnection
|
|
186
|
+
conn.search(
|
|
187
|
+
:filter => Net::LDAP::Filter.eq("objectClass", @group_class),
|
|
188
|
+
:base => $MU_CFG['ldap']['base_dn'],
|
|
189
|
+
:attributes => [@gidnum_attr]
|
|
190
|
+
) { |item|
|
|
191
|
+
used_gids = used_gids + item[@gidnum_attr].map { |x| x.to_i }
|
|
192
|
+
}
|
|
193
|
+
for x in @gid_range_start..65535 do
|
|
194
|
+
if !used_gids.include?(x)
|
|
195
|
+
MU::MommaCat.unlock("gid_generator", true)
|
|
196
|
+
return x.to_s
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
MU::MommaCat.unlock("gid_generator", true)
|
|
200
|
+
return nil
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Create a directory group. Valid for 389 DS only, will fail on AD.
|
|
204
|
+
def self.createGroup(group, full_dn: nil)
|
|
205
|
+
dn = "CN=#{group},"+$MU_CFG["ldap"]["group_ou"]
|
|
206
|
+
dn = full_dn if !full_dn.nil?
|
|
207
|
+
gid = allocateGID
|
|
208
|
+
attr = {
|
|
209
|
+
:cn => group,
|
|
210
|
+
:description => "#{group} Group",
|
|
211
|
+
:gidNumber => gid,
|
|
212
|
+
:objectclass => ["top", "posixGroup"]
|
|
213
|
+
}
|
|
214
|
+
if !@ldap_conn.add(
|
|
215
|
+
:dn => dn,
|
|
216
|
+
:attributes => attr
|
|
217
|
+
) and @ldap_conn.get_operation_result.code != 68
|
|
218
|
+
MU.log "Error creating #{dn}: "+getLDAPErr, MU::ERR, details: attr
|
|
219
|
+
return false
|
|
220
|
+
elsif @ldap_conn.get_operation_result.code != 68
|
|
221
|
+
MU.log "Created group #{dn} with gid #{gid}", MU::NOTICE
|
|
222
|
+
end
|
|
223
|
+
return gid
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Intended to run when Mu's local LDAP server has been created. Use the
|
|
227
|
+
# root credentials to populate our OU structure, create other users, etc.
|
|
228
|
+
# This only needs to understand a 389 Directory style schema, since
|
|
229
|
+
# obviously we're not running Active Directory locally on Linux.
|
|
230
|
+
def self.initLocalLDAP
|
|
231
|
+
validateConfig
|
|
232
|
+
if $MU_CFG["ldap"]["type"] != "389 Directory Services" or
|
|
233
|
+
# XXX this should check all of the IPs and hostnames we're known by
|
|
234
|
+
(!$MU_CFG["ldap"]["dcs"].include?("localhost") and
|
|
235
|
+
!$MU_CFG["ldap"]["dcs"].include?("127.0.0.1"))
|
|
236
|
+
MU.log "Custom directory service configured, not initializing bundled schema", MU::NOTICE
|
|
237
|
+
return
|
|
238
|
+
end
|
|
239
|
+
root_creds = MU::Groomer::Chef.getSecret(vault: "mu_ldap", item: "root_dn_user")
|
|
240
|
+
@ldap_conn = Net::LDAP.new(
|
|
241
|
+
:host => "127.0.0.1",
|
|
242
|
+
:encryption => {
|
|
243
|
+
:method => :simple_tls,
|
|
244
|
+
:tls_options => {}
|
|
245
|
+
},
|
|
246
|
+
:port => 636,
|
|
247
|
+
:base => "",
|
|
248
|
+
:auth => {
|
|
249
|
+
:method => :simple,
|
|
250
|
+
:username => root_creds["username"],
|
|
251
|
+
:password => root_creds["password"]
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Manufacture our OU tree and groups
|
|
256
|
+
[$MU_CFG["ldap"]["base_dn"],
|
|
257
|
+
"OU=Mu-System,#{$MU_CFG["ldap"]["base_dn"]}",
|
|
258
|
+
$MU_CFG["ldap"]["user_ou"],
|
|
259
|
+
$MU_CFG["ldap"]["group_ou"],
|
|
260
|
+
$MU_CFG["ldap"]["user_group_dn"],
|
|
261
|
+
$MU_CFG["ldap"]["admin_group_dn"]
|
|
262
|
+
].each { |full_dn|
|
|
263
|
+
dn = ""
|
|
264
|
+
full_dn.split(/,/).reverse.each { |chunk|
|
|
265
|
+
if dn.empty?
|
|
266
|
+
dn = chunk
|
|
267
|
+
else
|
|
268
|
+
dn = "#{chunk},#{dn}"
|
|
269
|
+
end
|
|
270
|
+
next if chunk.match(/^DC=/i)
|
|
271
|
+
if chunk.match(/^OU=(.*)/i)
|
|
272
|
+
ou = $1
|
|
273
|
+
if !@ldap_conn.add(
|
|
274
|
+
:dn => dn,
|
|
275
|
+
:attributes => {
|
|
276
|
+
:ou => ou,
|
|
277
|
+
:objectclass =>"organizationalUnit"
|
|
278
|
+
}
|
|
279
|
+
) and @ldap_conn.get_operation_result.code != 68 # "already exists"
|
|
280
|
+
MU.log "Error creating #{dn}: "+getLDAPErr, MU::ERR
|
|
281
|
+
return false
|
|
282
|
+
elsif @ldap_conn.get_operation_result.code != 68
|
|
283
|
+
MU.log "Created OU #{dn}", MU::NOTICE
|
|
284
|
+
end
|
|
285
|
+
elsif chunk.match(/^CN=(.*)/i)
|
|
286
|
+
createGroup($1, full_dn: dn)
|
|
287
|
+
end
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
["bind_creds", "join_creds"].each { |creds|
|
|
292
|
+
data = MU::Groomer::Chef.getSecret(vault: $MU_CFG["ldap"][creds]["vault"], item: $MU_CFG["ldap"][creds]["item"])
|
|
293
|
+
user_dn = data[$MU_CFG["ldap"][creds]["username_field"]]
|
|
294
|
+
user_dn.match(/^CN=(.*?),/i)
|
|
295
|
+
username = $1
|
|
296
|
+
pw = data[$MU_CFG["ldap"][creds]["password_field"]]
|
|
297
|
+
|
|
298
|
+
attr = {
|
|
299
|
+
:cn => username,
|
|
300
|
+
:displayName => "Mu Service Account",
|
|
301
|
+
:objectclass => ["top", "person", "organizationalPerson", "inetorgperson"],
|
|
302
|
+
:uid => username,
|
|
303
|
+
:mail => $MU_CFG['mu_admin_email'],
|
|
304
|
+
:givenName => "Mu",
|
|
305
|
+
:sn => "Service",
|
|
306
|
+
:userPassword => pw
|
|
307
|
+
}
|
|
308
|
+
if !@ldap_conn.add(
|
|
309
|
+
:dn => data[$MU_CFG["ldap"][creds]["username_field"]],
|
|
310
|
+
:attributes => attr
|
|
311
|
+
) and @ldap_conn.get_operation_result.code != 68
|
|
312
|
+
raise MuLDAPError, "Failed to create user #{user_dn} (#{getLDAPErr})"
|
|
313
|
+
elsif @ldap_conn.get_operation_result.code != 68
|
|
314
|
+
MU.log "Created #{username} (#{user_dn})", MU::NOTICE
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Set the password
|
|
318
|
+
if !@ldap_conn.replace_attribute(user_dn, :userPassword, [pw])
|
|
319
|
+
MU.log "Couldn't update password for user #{username}.", MU::ERR, details: getLDAPErr
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Grant this user appropriate privileges
|
|
323
|
+
targets = []
|
|
324
|
+
if creds == "bind_creds"
|
|
325
|
+
targets << $MU_CFG["ldap"]["user_ou"]
|
|
326
|
+
targets << $MU_CFG["ldap"]["group_ou"]
|
|
327
|
+
targets << $MU_CFG["ldap"]["user_group_dn"]
|
|
328
|
+
targets << $MU_CFG["ldap"]["admin_group_dn"]
|
|
329
|
+
elsif creds == "join_creds"
|
|
330
|
+
# XXX Some machine-related OU?
|
|
331
|
+
end
|
|
332
|
+
targets.each { | target|
|
|
333
|
+
aci = "(targetattr=\"*\")(target=\"ldap:///#{target}\")(version 3.0; acl \"#{username} admin privileges for #{target}\"; allow (all) userdn=\"ldap:///#{user_dn}\";)"
|
|
334
|
+
if !@ldap_conn.modify(:dn => $MU_CFG["ldap"]["base_dn"], :operations => [[:add, :aci, aci]]) and @ldap_conn.get_operation_result.code != 20
|
|
335
|
+
MU.log "Couldn't modify permissions for user #{username}.", MU::ERR, details: getLDAPErr
|
|
336
|
+
elsif @ldap_conn.get_operation_result.code != 20
|
|
337
|
+
MU.log "Granted #{username} user admin privileges over #{target}", MU::NOTICE
|
|
338
|
+
end
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Shorthand for fetching the most recent error on the active LDAP
|
|
344
|
+
# connection
|
|
345
|
+
def self.getLDAPErr
|
|
346
|
+
return nil if !@ldap_conn
|
|
347
|
+
return @ldap_conn.get_operation_result.code.to_s+" "+@ldap_conn.get_operation_result.message.to_s
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Approximate a current Microsoft timestamp. They count the number of
|
|
351
|
+
# 100-nanoseconds intervals (1 nanosecond = one billionth of a second)
|
|
352
|
+
# since Jan 1, 1601 UTC.
|
|
353
|
+
def self.getMicrosoftTime
|
|
354
|
+
ms_epoch = DateTime.new(1601,1,1)
|
|
355
|
+
# this is in milliseconds, so multiply it for the right number of zeroes
|
|
356
|
+
elapsed = DateTime.now.strftime("%Q").to_i - ms_epoch.strftime("%Q").to_i
|
|
357
|
+
return elapsed*10000
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Convert a Microsoft timestamp to a Ruby Time object. See also #getMicrosoftTime.
|
|
361
|
+
# @param stamp [Integer]: The MS-style timestamp, e.g. 130838184558490696
|
|
362
|
+
# @return [Time]
|
|
363
|
+
def self.convertMicrosoftTime(stamp)
|
|
364
|
+
ms_epoch = DateTime.new(1601,1,1).strftime("%Q").to_i
|
|
365
|
+
unixtime = (stamp.to_i/10000) + DateTime.new(1601,1,1).strftime("%Q").to_i
|
|
366
|
+
Time.at(unixtime/1000)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
@can_write = nil
|
|
370
|
+
# Test whether our LDAP binding user has permissions to create other
|
|
371
|
+
# users, manipulate groups, and set passwords. Note that it's *not* fatal
|
|
372
|
+
# if we can't, simply a design where most account management happens on
|
|
373
|
+
# the directory side.
|
|
374
|
+
# @return [Boolean]
|
|
375
|
+
def self.canWriteLDAP?
|
|
376
|
+
return @can_write if !@can_write.nil?
|
|
377
|
+
|
|
378
|
+
conn = getLDAPConnection
|
|
379
|
+
dn = "CN=Mu Testuser #{Process.pid},#{$MU_CFG["ldap"]["user_ou"]}"
|
|
380
|
+
uid = "mu.testuser.#{Process.pid}"
|
|
381
|
+
attr = {
|
|
382
|
+
:cn => "Mu Testuser #{Process.pid}",
|
|
383
|
+
@uid_attr.to_sym => uid
|
|
384
|
+
}
|
|
385
|
+
if $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
386
|
+
attr[:objectclass] = ["user"]
|
|
387
|
+
attr[:userPrincipalName] = "#{uid}@#{$MU_CFG["ldap"]["domain_name"]}"
|
|
388
|
+
attr[:pwdLastSet] = "-1"
|
|
389
|
+
uid = dn
|
|
390
|
+
elsif $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
391
|
+
attr[:objectclass] = ["top", "person", "organizationalPerson", "inetorgperson"]
|
|
392
|
+
attr[:userPassword] = Password.pronounceable(12..14)
|
|
393
|
+
attr[:displayName] = "Mu Test User #{Process.pid}"
|
|
394
|
+
attr[:mail] = $MU_CFG['mu_admin_email']
|
|
395
|
+
attr[:givenName] = "Mu"
|
|
396
|
+
attr[:sn] = "TestUser"
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
@can_write = true
|
|
400
|
+
if !conn.add(:dn => dn, :attributes => attr)
|
|
401
|
+
MU.log "Couldn't create write-test user #{dn}, operating in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE, details: attr
|
|
402
|
+
return false
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Make sure we can write various fields that we might need to touch
|
|
406
|
+
[:displayName, :mail, :givenName, :sn].each { |field|
|
|
407
|
+
if !conn.replace_attribute(dn, field, "foo@bar.com")
|
|
408
|
+
MU.log "Couldn't modify write-test user #{dn} field #{field.to_s}, operating in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE
|
|
409
|
+
@can_write = false
|
|
410
|
+
|
|
411
|
+
end
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
# Can we add them to the Mu membership group(s)
|
|
415
|
+
[$MU_CFG["ldap"]["user_group_dn"], $MU_CFG["ldap"]["admin_group_dn"]].each { |group|
|
|
416
|
+
if !conn.modify(:dn => group, :operations => [[:add, @member_attr, uid]])
|
|
417
|
+
MU.log "Couldn't add write-test user #{dn} to #{@member_attr} in group #{group}, operating in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE
|
|
418
|
+
@can_write = false
|
|
419
|
+
end
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if !conn.delete(:dn => dn)
|
|
423
|
+
MU.log "Couldn't delete write-test user #{dn}, operating in read-only LDAP mode", MU::NOTICE
|
|
424
|
+
@can_write = false
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
@can_write
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Search for groups whose names contain any of the given search terms and
|
|
431
|
+
# return their full DNs.
|
|
432
|
+
# @param search [Array<String>]: Strings to search for.
|
|
433
|
+
# @param exact [Boolean]: Return only exact matches for whole fields.
|
|
434
|
+
# @param searchbase [String]: The DN under which to search.
|
|
435
|
+
# @return [Array<String>]
|
|
436
|
+
def self.findGroups(search = [], exact: false, searchbase: $MU_CFG['ldap']['base_dn'])
|
|
437
|
+
if search.nil? or search.size == 0
|
|
438
|
+
raise MuLDAPError, "Need something to search for in MU::Master::LDAP.findGroups"
|
|
439
|
+
end
|
|
440
|
+
conn = getLDAPConnection
|
|
441
|
+
filter = nil
|
|
442
|
+
search.each { |term|
|
|
443
|
+
curfilter = Net::LDAP::Filter.contains(@gid_attr, "#{term}")
|
|
444
|
+
if exact
|
|
445
|
+
curfilter = Net::LDAP::Filter.eq(@gid_attr, "#{term}")
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
if !filter
|
|
449
|
+
filter = curfilter
|
|
450
|
+
else
|
|
451
|
+
filter = filter | curfilter
|
|
452
|
+
end
|
|
453
|
+
}
|
|
454
|
+
filter = Net::LDAP::Filter.ne("objectclass", "computer") & (filter)
|
|
455
|
+
groups = []
|
|
456
|
+
conn.search(
|
|
457
|
+
:filter => filter,
|
|
458
|
+
:base => searchbase,
|
|
459
|
+
:attributes => ["objectclass"]
|
|
460
|
+
) do |group|
|
|
461
|
+
groups << group.dn
|
|
462
|
+
end
|
|
463
|
+
groups
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# See https://technet.microsoft.com/en-us/library/ee198831.aspx
|
|
467
|
+
AD_PW_ATTRS = {
|
|
468
|
+
'script' => 0x0001, #SCRIPT
|
|
469
|
+
# 'disable' => 0x0002, #ACCOUNTDISABLE
|
|
470
|
+
'disable' => 0b0000010, #ACCOUNTDISABLE
|
|
471
|
+
'homedirRequired' => 0x0008, #HOMEDIR_REQUIRED
|
|
472
|
+
'lockout' => 0x0010, #LOCKOUT
|
|
473
|
+
'noPwdRequired' => 0x0020, #ADS_UF_PASSWD_NOTREQD
|
|
474
|
+
'cantChangePwd' => 0x0040, #ADS_UF_PASSWD_CANT_CHANGE
|
|
475
|
+
'pwdStoredReversible' => 0x0080, #ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
|
|
476
|
+
'tempDuplicateAccount' => 0x0100, #NORMAL_ACCOUNT
|
|
477
|
+
'normal' => 0x0200, #NORMAL_ACCOUNT
|
|
478
|
+
'pwdNeverExpires' => 0x10000, #ADS_UF_DONT_EXPIRE_PASSWD
|
|
479
|
+
'pwdExpired' => 0x80000, #ADS_UF_PASSWORD_EXPIRED
|
|
480
|
+
'trustedToAuthForDelegation' => 0x1000000 #TRUSTED_TO_AUTH_FOR_DELEGATION
|
|
481
|
+
}.freeze
|
|
482
|
+
|
|
483
|
+
# Find a directory user with fuzzy string matching on sAMAccountName/uid, displayName, group memberships, or email
|
|
484
|
+
# @param search [Array<String>]: Strings to search for.
|
|
485
|
+
# @param exact [Boolean]: Return only exact matches for whole fields.
|
|
486
|
+
# @param searchbase [String]: The DN under which to search.
|
|
487
|
+
# @param extra_attrs [Array<String>]: Other LDAP attributes to search
|
|
488
|
+
# @param matchgroups [Array<String>]: An array of groups. If supplied, a user must be a member of one of these in order to match.
|
|
489
|
+
# @return [Array<Hash>]
|
|
490
|
+
def self.findUsers(search = [], exact: false, searchbase: $MU_CFG['ldap']['base_dn'], extra_attrs: [], matchgroups: [])
|
|
491
|
+
# We want to search groups, but can't search on memberOf with wildcards.
|
|
492
|
+
# So search groups independently, build a list of full CNs, and use
|
|
493
|
+
# those.
|
|
494
|
+
if search.size > 0
|
|
495
|
+
groups = findGroups(search, exact: exact, searchbase: searchbase)
|
|
496
|
+
end
|
|
497
|
+
searchattrs = [@uid_attr]
|
|
498
|
+
getattrs = []
|
|
499
|
+
if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
500
|
+
getattrs = ["uid", "displayName", "mail"] + extra_attrs
|
|
501
|
+
elsif $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
502
|
+
getattrs = ["sAMAccountName", "displayName", "mail", "lastLogon", "lockoutTime", "pwdLastSet", "memberOf", "userAccountControl"] + extra_attrs
|
|
503
|
+
end
|
|
504
|
+
if !exact
|
|
505
|
+
searchattrs = searchattrs + ["displayName", "mail"] + extra_attrs
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
conn = getLDAPConnection
|
|
509
|
+
users = {}
|
|
510
|
+
filter = nil
|
|
511
|
+
rejected = 0
|
|
512
|
+
if search.size > 0
|
|
513
|
+
search.each { |term|
|
|
514
|
+
if term.nil? or (term.length < 4 and !exact)
|
|
515
|
+
MU.log "Search term '#{term}' is too short, ignoring.", MU::WARN
|
|
516
|
+
rejected = rejected + 1
|
|
517
|
+
next
|
|
518
|
+
end
|
|
519
|
+
searchattrs.each { |attr|
|
|
520
|
+
if !filter
|
|
521
|
+
if exact
|
|
522
|
+
filter = Net::LDAP::Filter.eq(attr, "#{term}")
|
|
523
|
+
else
|
|
524
|
+
filter = Net::LDAP::Filter.contains(attr, "#{term}")
|
|
525
|
+
end
|
|
526
|
+
else
|
|
527
|
+
if exact
|
|
528
|
+
filter = filter |Net::LDAP::Filter.eq(attr, "#{term}")
|
|
529
|
+
else
|
|
530
|
+
filter = filter |Net::LDAP::Filter.contains(attr, "#{term}")
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if rejected == search.size
|
|
536
|
+
MU.log "No valid search strings provided.", MU::ERR
|
|
537
|
+
return nil
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
if groups
|
|
541
|
+
groups.each { |group|
|
|
542
|
+
filter = filter |Net::LDAP::Filter.eq("memberOf", group)
|
|
543
|
+
}
|
|
544
|
+
end
|
|
545
|
+
if filter
|
|
546
|
+
filter = Net::LDAP::Filter.ne("objectclass", "computer") & Net::LDAP::Filter.ne("objectclass", "group") & (filter)
|
|
547
|
+
else
|
|
548
|
+
filter = Net::LDAP::Filter.ne("objectclass", "computer") & Net::LDAP::Filter.ne("objectclass", "group")
|
|
549
|
+
end
|
|
550
|
+
conn.search(
|
|
551
|
+
:filter => filter,
|
|
552
|
+
:base => searchbase,
|
|
553
|
+
:attributes => getattrs
|
|
554
|
+
) do |acct|
|
|
555
|
+
begin
|
|
556
|
+
next if users.has_key?(acct[@uid_attr].first)
|
|
557
|
+
rescue NoMethodError
|
|
558
|
+
next
|
|
559
|
+
end
|
|
560
|
+
if matchgroups and matchgroups.size > 0
|
|
561
|
+
next if (acct[:memberOf] & matchgroups).size < 1
|
|
562
|
+
end
|
|
563
|
+
users[acct[@uid_attr].first] = {}
|
|
564
|
+
users[acct[@uid_attr].first]['dn'] = acct.dn
|
|
565
|
+
getattrs.each { |attr|
|
|
566
|
+
begin
|
|
567
|
+
if acct[attr].size == 1
|
|
568
|
+
users[acct[@uid_attr].first][attr] = acct[attr].first
|
|
569
|
+
else
|
|
570
|
+
users[acct[@uid_attr].first][attr] = acct[attr]
|
|
571
|
+
end
|
|
572
|
+
if attr == "userAccountControl"
|
|
573
|
+
AD_PW_ATTRS.each_pair { |pw_attr, bitmask|
|
|
574
|
+
if (bitmask | acct[attr].first.to_i) == acct[attr].first.to_i
|
|
575
|
+
users[acct[@uid_attr].first][pw_attr] = true
|
|
576
|
+
end
|
|
577
|
+
}
|
|
578
|
+
users[acct[@uid_attr].first][attr] = acct[attr].first.to_i.to_s(2)
|
|
579
|
+
end
|
|
580
|
+
end rescue NoMethodError
|
|
581
|
+
}
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Make all of the Net::BER::BerIdentifiedString leaves in a Hash into
|
|
585
|
+
# normal strings.
|
|
586
|
+
# @param tree
|
|
587
|
+
def self.hashStringify(tree)
|
|
588
|
+
newtree = nil
|
|
589
|
+
if tree.is_a?(Hash)
|
|
590
|
+
newtree = {}
|
|
591
|
+
tree.each_pair { |key, leaf|
|
|
592
|
+
newtree[key.to_s] = hashStringify(leaf)
|
|
593
|
+
}
|
|
594
|
+
elsif tree.is_a?(Array)
|
|
595
|
+
newtree = []
|
|
596
|
+
tree.each { |leaf|
|
|
597
|
+
newtree << hashStringify(leaf)
|
|
598
|
+
}
|
|
599
|
+
elsif tree.is_a?(Net::BER::BerIdentifiedString)
|
|
600
|
+
newtree = tree.to_s
|
|
601
|
+
else
|
|
602
|
+
newtree = tree
|
|
603
|
+
end
|
|
604
|
+
newtree
|
|
605
|
+
end
|
|
606
|
+
scrubbed_users = hashStringify(users)
|
|
607
|
+
scrubbed_users
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# Authenticate a user against our directory, optionally requiring them
|
|
611
|
+
# to be a member of a particular group in order to return true.
|
|
612
|
+
# @param username [String]: The bare username of the user to authorize
|
|
613
|
+
# @param password [String]: The user's password
|
|
614
|
+
# @return [Boolean]
|
|
615
|
+
def self.authorize(username, password, require_group: nil)
|
|
616
|
+
auth = nil
|
|
617
|
+
|
|
618
|
+
begin
|
|
619
|
+
# see if this user/pw combo works
|
|
620
|
+
conn = getLDAPConnection(username: username, password: password)
|
|
621
|
+
auth = conn.auth(username, password) if username and password
|
|
622
|
+
rescue Net::LDAP::LdapError
|
|
623
|
+
return false
|
|
624
|
+
end
|
|
625
|
+
if !conn.bind(auth)
|
|
626
|
+
MU.log conn.get_operation_result.message, MU::ERR
|
|
627
|
+
return false
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
return true if !require_group
|
|
631
|
+
|
|
632
|
+
shortuser = username.sub(/\@.*/, "")
|
|
633
|
+
user = findUsers(search = [shortuser], exact: true)
|
|
634
|
+
if user[shortuser]["memberOf"].is_a?(Array)
|
|
635
|
+
user[shortuser]["memberOf"].each { |group|
|
|
636
|
+
shortname = group.sub(/^CN=(.*?),.*/, '\1')
|
|
637
|
+
return true if shortname == require_group
|
|
638
|
+
}
|
|
639
|
+
elsif user[shortuser]["memberOf"].is_a?(String)
|
|
640
|
+
shortname = user[shortuser]["memberOf"].sub(/^CN=(.*?),.*/, '\1')
|
|
641
|
+
return true if shortname == require_group
|
|
642
|
+
end
|
|
643
|
+
return false
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
# @return [Array<String>]
|
|
647
|
+
def self.listUsers
|
|
648
|
+
conn = getLDAPConnection
|
|
649
|
+
users = {}
|
|
650
|
+
|
|
651
|
+
# XXX why doesn't this work?
|
|
652
|
+
# group_membership_filter = Net::LDAP::Filter.eq("memberOf", $MU_CFG["ldap"]["admin_group_name"]) | Net::LDAP::Filter.eq("memberOf", $MU_CFG["ldap"]["user_group_name"])
|
|
653
|
+
|
|
654
|
+
["admin_group_name", "user_group_name"].each { |group|
|
|
655
|
+
groupname_filter = Net::LDAP::Filter.eq(@gid_attr, $MU_CFG["ldap"][group])
|
|
656
|
+
group_filter = Net::LDAP::Filter.eq("objectClass", @group_class)
|
|
657
|
+
member_uids = []
|
|
658
|
+
|
|
659
|
+
conn.search(
|
|
660
|
+
:filter => Net::LDAP::Filter.join(groupname_filter, group_filter),
|
|
661
|
+
:attributes => [@member_attr]
|
|
662
|
+
) do |item|
|
|
663
|
+
member_uids = item[@member_attr].map { |u| u.to_s }
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
member_uids.each { |uid|
|
|
667
|
+
username_filter = Net::LDAP::Filter.eq(@uid_attr, uid)
|
|
668
|
+
if $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
669
|
+
# XXX this is a workaround, as we can't seem to look up the full
|
|
670
|
+
# DN now for some reason.
|
|
671
|
+
cn = uid.sub(/^CN=([^,]+?),.*/, "\\1")
|
|
672
|
+
username_filter = Net::LDAP::Filter.eq("cn", cn)
|
|
673
|
+
end
|
|
674
|
+
user_filter = Net::LDAP::Filter.ne("objectclass", "computer") & Net::LDAP::Filter.ne("objectclass", "group")
|
|
675
|
+
fetchattrs = ["cn", @uid_attr, "displayName", "mail"]
|
|
676
|
+
fetchattrs << "employeeNumber" if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
677
|
+
conn.search(
|
|
678
|
+
:filter => username_filter & user_filter,
|
|
679
|
+
:base => $MU_CFG["ldap"]["base_dn"],
|
|
680
|
+
:attributes => fetchattrs
|
|
681
|
+
) do |acct|
|
|
682
|
+
next if users.has_key?(acct[@uid_attr].first)
|
|
683
|
+
users[acct[@uid_attr].first] = {}
|
|
684
|
+
users[acct[@uid_attr].first]['dn'] = acct.dn
|
|
685
|
+
if group == "admin_group_name"
|
|
686
|
+
users[acct[@uid_attr].first]['admin'] = true
|
|
687
|
+
else
|
|
688
|
+
users[acct[@uid_attr].first]['admin'] = false
|
|
689
|
+
end
|
|
690
|
+
begin
|
|
691
|
+
users[acct[@uid_attr].first]['realname'] = acct.displayname.first
|
|
692
|
+
end rescue NoMethodError
|
|
693
|
+
begin
|
|
694
|
+
users[acct[@uid_attr].first]['email'] = acct.mail.first
|
|
695
|
+
end rescue NoMethodError
|
|
696
|
+
begin
|
|
697
|
+
users[acct[@uid_attr].first]['uid'] = acct.employeenumber.first
|
|
698
|
+
end rescue NoMethodError
|
|
699
|
+
end
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
users
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
# Delete a user from our directory
|
|
706
|
+
# @param user [String]: The username to remove.
|
|
707
|
+
# @return [Boolean]: Success/Failure
|
|
708
|
+
def self.deleteUser(user)
|
|
709
|
+
if canWriteLDAP?
|
|
710
|
+
conn = getLDAPConnection
|
|
711
|
+
dn = nil
|
|
712
|
+
conn.search(
|
|
713
|
+
:filter => Net::LDAP::Filter.eq(@uid_attr, user),
|
|
714
|
+
:base => $MU_CFG["ldap"]["base_dn"],
|
|
715
|
+
:attributes => [@uid_attr]
|
|
716
|
+
) do |acct|
|
|
717
|
+
dn = acct.dn
|
|
718
|
+
break
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
# Our default LDAP server doesn't cascade user deletes through groups,
|
|
722
|
+
# so help it out.
|
|
723
|
+
if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
724
|
+
conn.search(
|
|
725
|
+
:filter => Net::LDAP::Filter.eq("objectclass", @group_class),
|
|
726
|
+
:base => $MU_CFG["ldap"]["base_dn"],
|
|
727
|
+
:attributes => ["cn", @member_attr]
|
|
728
|
+
) do |group|
|
|
729
|
+
group[@member_attr].each { |member|
|
|
730
|
+
next if member.nil?
|
|
731
|
+
if member.downcase == user or (!dn.nil? and member.downcase == dn.downcase)
|
|
732
|
+
manageGroup(group.cn.first, remove_users: [user])
|
|
733
|
+
end
|
|
734
|
+
}
|
|
735
|
+
if group.cn.first.downcase == "#{user}.mu-user" and !conn.delete(:dn => group.dn)
|
|
736
|
+
MU.log "Couldn't delete user's default group #{group.dn}", MU::WARN, details: getLDAPErr
|
|
737
|
+
else
|
|
738
|
+
MU.log "Removed user's default group #{user}.mu-user", MU::NOTICE
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
if !dn.nil? and !conn.delete(:dn => dn)
|
|
743
|
+
MU.log "Failed to delete #{user} from LDAP: #{getLDAPErr}", MU::WARN, details: dn
|
|
744
|
+
return false
|
|
745
|
+
end
|
|
746
|
+
MU.log "Removed LDAP user #{user}", MU::NOTICE
|
|
747
|
+
return true
|
|
748
|
+
else
|
|
749
|
+
MU.log "We are in read-only LDAP mode. You must manually delete #{user} from your directory.", MU::WARN
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
false
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# Add/remove users to/from a group.
|
|
756
|
+
# @param group [String]: The short name of the group
|
|
757
|
+
# @param add_users [Array<String>]: The short names of users to add to the group
|
|
758
|
+
# @param remove_users [Array<String>]: The short names of users to remove from the group
|
|
759
|
+
def self.manageGroup(group, add_users: [], remove_users: [])
|
|
760
|
+
group_dn = findGroups([group], exact: true).first
|
|
761
|
+
if !group_dn or group_dn.empty?
|
|
762
|
+
raise MuLDAPError, "Failed to find a Distinguished Name for group #{group}"
|
|
763
|
+
end
|
|
764
|
+
if (add_users & remove_users).size > 0
|
|
765
|
+
raise MuError, "Can't both add and remove the same user (#{(add_users & remove_users).join(", ")}) from a group"
|
|
766
|
+
end
|
|
767
|
+
add_users = findUsers(add_users, exact: true) if add_users.size > 0
|
|
768
|
+
remove_users = findUsers(remove_users, exact: true) if remove_users.size > 0
|
|
769
|
+
|
|
770
|
+
conn = getLDAPConnection
|
|
771
|
+
if add_users.size > 0
|
|
772
|
+
add_users.each_pair { |user, data|
|
|
773
|
+
uid = user
|
|
774
|
+
uid = data["dn"] if $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
775
|
+
if !conn.modify(:dn => group_dn, :operations => [[:add, @member_attr, uid]]) and @ldap_conn.get_operation_result.code != 20
|
|
776
|
+
MU.log "Couldn't add user #{user} (#{data['dn']}) to #{@member_attr} of group #{group} (#{group_dn}).", MU::WARN, details: getLDAPErr
|
|
777
|
+
else
|
|
778
|
+
MU.log "Added #{user} to group #{group}", MU::NOTICE
|
|
779
|
+
end
|
|
780
|
+
}
|
|
781
|
+
end
|
|
782
|
+
if remove_users.size > 0
|
|
783
|
+
remove_users.each_pair { |user, data|
|
|
784
|
+
uid = user
|
|
785
|
+
uid = data["dn"] if $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
786
|
+
if !conn.modify(:dn => group_dn, :operations => [[:delete, @member_attr, uid]])
|
|
787
|
+
MU.log "Couldn't remove user #{user} from group #{group} (#{group_dn}) via #{@member_attr}.", MU::WARN, details: getLDAPErr
|
|
788
|
+
else
|
|
789
|
+
MU.log "Removed #{user} from group #{group}", MU::NOTICE
|
|
790
|
+
end
|
|
791
|
+
}
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
# Call when creating or modifying a user.
|
|
796
|
+
# @param user [String]: The username on which to operate
|
|
797
|
+
# @param password [String]: Set the user's password
|
|
798
|
+
# @param name [String]: Full name of the user
|
|
799
|
+
# @param email [String]: Set the user's email address
|
|
800
|
+
# @param admin [Boolean]: Whether to flag this user as an admin
|
|
801
|
+
# @param unlock [Boolean]: Unlock a locked account (Active Directory)
|
|
802
|
+
# @param mu_acct [Boolean]: Whether to operate on users outside of Mu (generic directory users)
|
|
803
|
+
# @param ou [String]: The OU into which to deposit new users.
|
|
804
|
+
# @param disable [Boolean]: Disabled the user's account
|
|
805
|
+
# @param enable [Boolean]: Re-enable the user's account if it's disabled
|
|
806
|
+
def self.manageUser(user, name: nil, password: nil, email: nil, admin: false, mu_acct: true, unlock: false, ou: $MU_CFG["ldap"]["user_ou"], enable: false, disable: false, change_uid: -1)
|
|
807
|
+
cur_users = listUsers
|
|
808
|
+
|
|
809
|
+
first = last = nil
|
|
810
|
+
if !name.nil?
|
|
811
|
+
last = name.split(/\s+/).pop
|
|
812
|
+
first = name.split(/\s+/).shift
|
|
813
|
+
end
|
|
814
|
+
conn = getLDAPConnection
|
|
815
|
+
|
|
816
|
+
# If we're operating on users that aren't specifically Mu users,
|
|
817
|
+
# fetch generic directory information about them instead of the Mu
|
|
818
|
+
# user descriptor.
|
|
819
|
+
if !mu_acct
|
|
820
|
+
cur_users = findUsers([user], exact: true)
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
# Oh, Microsoft. Slap quotes around it, convert it to Unicode, and call
|
|
824
|
+
# it Sally. *Then* it's a password.
|
|
825
|
+
password_attr = :userPassword
|
|
826
|
+
if !password.nil? and $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
827
|
+
password = ('"'+password+'"').encode("utf-16le").force_encoding("utf-8")
|
|
828
|
+
password_attr = :unicodePwd
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
ok = true
|
|
832
|
+
if !cur_users.has_key?(user)
|
|
833
|
+
# Creating a new user
|
|
834
|
+
if canWriteLDAP?
|
|
835
|
+
if password.nil? or email.nil? or name.nil?
|
|
836
|
+
raise MuLDAPError, "Missing one or more required fields (name, password, email) creating new user #{user}"
|
|
837
|
+
end
|
|
838
|
+
user_dn = "CN=#{name},#{ou}"
|
|
839
|
+
conn = getLDAPConnection
|
|
840
|
+
attr = {
|
|
841
|
+
:cn => name,
|
|
842
|
+
:displayName => name,
|
|
843
|
+
:givenName => first,
|
|
844
|
+
:sn => last,
|
|
845
|
+
:mail => email
|
|
846
|
+
}
|
|
847
|
+
attr[password_attr] = password
|
|
848
|
+
gid = nil
|
|
849
|
+
groups = []
|
|
850
|
+
if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
851
|
+
attr[:objectclass] = ["top", "person", "organizationalPerson", "inetorgperson"]
|
|
852
|
+
attr[:uid] = user
|
|
853
|
+
if change_uid > 0
|
|
854
|
+
used_uids = getUsedUids
|
|
855
|
+
if used_uids.include?(change_uid)
|
|
856
|
+
raise MuLDAPError, "Uid #{change_uid} is unavailable, cannot allocate to user #{user}"
|
|
857
|
+
end
|
|
858
|
+
MU.log "Forcing uid #{change_uid} to user #{user}", MU::NOTICE, details: used_uids
|
|
859
|
+
attr[:employeeNumber] = change_uid.to_s
|
|
860
|
+
else
|
|
861
|
+
attr[:employeeNumber] = allocateUID
|
|
862
|
+
end
|
|
863
|
+
if mu_acct
|
|
864
|
+
gid = createGroup("#{user}.mu-user")
|
|
865
|
+
groups << "#{user}.mu-user"
|
|
866
|
+
else
|
|
867
|
+
gid = createGroup(user)
|
|
868
|
+
groups << user
|
|
869
|
+
end
|
|
870
|
+
attr[:departmentNumber] = gid
|
|
871
|
+
elsif $MU_CFG["ldap"]["type"] == "Active Directory"
|
|
872
|
+
attr[:objectclass] = ["user"]
|
|
873
|
+
attr[:samaccountname] = user
|
|
874
|
+
attr[:userAccountControl] = AD_PW_ATTRS['normal'].to_s
|
|
875
|
+
attr[:userPrincipalName] = "#{user}@#{$MU_CFG["ldap"]["domain_name"]}"
|
|
876
|
+
attr[:pwdLastSet] = "-1"
|
|
877
|
+
attr.delete(:userPassword)
|
|
878
|
+
if mu_acct
|
|
879
|
+
attr[:userAccountControl] = (attr[:userAccountControl].to_i & AD_PW_ATTRS['pwdNeverExpires']).to_s
|
|
880
|
+
end
|
|
881
|
+
if disable
|
|
882
|
+
attr[:userAccountControl] = (attr[:userAccountControl].to_i & AD_PW_ATTRS['disable']).to_s
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
if !conn.add(:dn => user_dn, :attributes => attr)
|
|
886
|
+
if getLDAPErr.match(/53 Unwilling to perform/)
|
|
887
|
+
raise MuLDAPError, "Failed to create user #{user} (#{getLDAPErr}). Most likely the LDAP password policy objected to the password '#{password}'"
|
|
888
|
+
else
|
|
889
|
+
raise MuLDAPError, "Failed to create user #{user} (#{getLDAPErr})"
|
|
890
|
+
end
|
|
891
|
+
end
|
|
892
|
+
attr[password_attr] = "********"
|
|
893
|
+
MU.log "Created new LDAP user #{user}", details: attr
|
|
894
|
+
if mu_acct
|
|
895
|
+
groups << $MU_CFG["ldap"]["user_group_name"]
|
|
896
|
+
groups << $MU_CFG["ldap"]["admin_group_name"] if admin
|
|
897
|
+
end
|
|
898
|
+
groups.each { |group|
|
|
899
|
+
manageGroup(group, add_users: [user])
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
wait = 10
|
|
903
|
+
begin
|
|
904
|
+
%x{/usr/bin/getent passwd ; /usr/bin/getent group} # winbind is slow sometimes
|
|
905
|
+
Etc.getpwnam(user)
|
|
906
|
+
rescue ArgumentError
|
|
907
|
+
if wait >= 30
|
|
908
|
+
MU.log "User #{user} has been created in LDAP, but local system can't see it. Are PAM/LDAP configured correctly?", MU::ERR
|
|
909
|
+
return false
|
|
910
|
+
end
|
|
911
|
+
MU.log "User #{user} has been created in LDAP, but not yet visible to local system, waiting #{wait}s and checking again.", MU::WARN
|
|
912
|
+
sleep wait
|
|
913
|
+
wait = wait + 5
|
|
914
|
+
retry
|
|
915
|
+
end if user != "mu"
|
|
916
|
+
%x{/sbin/restorecon -r /home} # SELinux stupidity that oddjob misses
|
|
917
|
+
MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
|
|
918
|
+
else
|
|
919
|
+
MU.log "We are in read-only LDAP mode. You must first create #{user} in your directory and add it to #{$MU_CFG["ldap"]["user_group_dn"]}. If the user is intended to be an admin, also add it to #{$MU_CFG["ldap"]["admin_group_dn"]}.", MU::WARN
|
|
920
|
+
return true
|
|
921
|
+
end
|
|
922
|
+
else
|
|
923
|
+
gid = MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
|
|
924
|
+
# Modifying an existing user
|
|
925
|
+
|
|
926
|
+
if canWriteLDAP?
|
|
927
|
+
conn = getLDAPConnection
|
|
928
|
+
user_dn = cur_users[user]['dn']
|
|
929
|
+
if $MU_CFG["ldap"]["type"] == "389 Directory Services"
|
|
930
|
+
# Make sure we have a sensible default gid
|
|
931
|
+
conn.replace_attribute(user_dn, :departmentNumber, gid.to_s)
|
|
932
|
+
if change_uid > 0
|
|
933
|
+
used_uids = getUsedUids
|
|
934
|
+
if used_uids.include?(change_uid)
|
|
935
|
+
raise MuLDAPError, "Uid #{change_uid} is unavailable, cannot allocate to user #{user}"
|
|
936
|
+
end
|
|
937
|
+
MU.log "Forcing uid #{change_uid} to user #{user}", MU::NOTICE, details: used_uids
|
|
938
|
+
conn.replace_attribute(user_dn, :employeeNumber, change_uid.to_s)
|
|
939
|
+
end
|
|
940
|
+
end
|
|
941
|
+
if !name.nil? and cur_users[user]['realname'] != name
|
|
942
|
+
MU.log "Updating display name for #{user} to #{name}", MU::NOTICE
|
|
943
|
+
conn.replace_attribute(user_dn, :displayName, name)
|
|
944
|
+
conn.replace_attribute(user_dn, :givenName, first)
|
|
945
|
+
conn.replace_attribute(user_dn, :sn, last)
|
|
946
|
+
cur_users[user]['realname'] = name
|
|
947
|
+
end
|
|
948
|
+
if disable
|
|
949
|
+
user_props = findUsers([user], exact: true)
|
|
950
|
+
MU.log "Disabling #{user}", MU::WARN
|
|
951
|
+
conn.replace_attribute(user_dn, :userAccountControl, AD_PW_ATTRS['disable'].to_i.to_s(2))
|
|
952
|
+
elsif enable
|
|
953
|
+
user_props = findUsers([user], exact: true)
|
|
954
|
+
MU.log "Re-enabling #{user}", MU::NOTICE
|
|
955
|
+
uac = (("0b"+user_props[user]["userAccountControl"]).to_i & AD_PW_ATTRS['disable'])
|
|
956
|
+
conn.replace_attribute(user_dn, :userAccountControl, uac.to_s(2))
|
|
957
|
+
end
|
|
958
|
+
if unlock
|
|
959
|
+
conn.replace_attribute(user_dn, :lockoutTime, "0")
|
|
960
|
+
end
|
|
961
|
+
if !email.nil? and cur_users[user]['email'] != email
|
|
962
|
+
MU.log "Updating email for #{user} to #{email}", MU::NOTICE
|
|
963
|
+
conn.replace_attribute(user_dn, :mail, email)
|
|
964
|
+
cur_users[user]['email'] = email
|
|
965
|
+
end
|
|
966
|
+
if !password.nil?
|
|
967
|
+
MU.log "Updating password for #{user}", MU::NOTICE
|
|
968
|
+
if !conn.replace_attribute(user_dn, password_attr, [password])
|
|
969
|
+
MU.log "Couldn't update password for user #{user}.", MU::WARN, details: getLDAPErr
|
|
970
|
+
ok = false
|
|
971
|
+
end
|
|
972
|
+
end
|
|
973
|
+
if admin and !cur_users[user]['admin']
|
|
974
|
+
MU.log "Granting Mu admin privileges to #{user}", MU::NOTICE
|
|
975
|
+
manageGroup($MU_CFG["ldap"]["admin_group_name"], add_users: [user])
|
|
976
|
+
elsif !admin and cur_users[user]['admin']
|
|
977
|
+
MU.log "Revoking Mu admin privileges from #{user}", MU::NOTICE
|
|
978
|
+
manageGroup($MU_CFG["ldap"]["admin_group_name"], remove_users: [user])
|
|
979
|
+
end
|
|
980
|
+
else
|
|
981
|
+
MU.log "We are in read-only LDAP mode. You must manage #{user} in your directory.", MU::WARN
|
|
982
|
+
ok = false
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
return ok if !mu_acct # everything below is Mu-specific
|
|
986
|
+
|
|
987
|
+
cur_users = listUsers
|
|
988
|
+
if cur_users.has_key?(user)
|
|
989
|
+
["realname", "email", "monitoring_email"].each { |field|
|
|
990
|
+
next if !cur_users[user].has_key?(field)
|
|
991
|
+
File.open($MU_CFG['datadir']+"/users/#{user}/#{field}", File::CREAT|File::RDWR, 0640) { |f|
|
|
992
|
+
f.puts cur_users[user][field]
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
else
|
|
996
|
+
MU.log "Load of current user list didn't include #{user}, even though we just created them!", MU::WARN
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
|
|
1000
|
+
ok
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
end
|