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.
Files changed (618) hide show
  1. checksums.yaml +7 -0
  2. data/Berksfile +56 -0
  3. data/Berksfile.lock +250 -0
  4. data/Jenkinsfile +184 -0
  5. data/LICENSE.md +37 -0
  6. data/README.md +26 -0
  7. data/bin/mu-aws-setup +376 -0
  8. data/bin/mu-cleanup +68 -0
  9. data/bin/mu-configure +1133 -0
  10. data/bin/mu-deploy +166 -0
  11. data/bin/mu-firewall-allow-clients +30 -0
  12. data/bin/mu-gcp-setup +200 -0
  13. data/bin/mu-gen-docs +34 -0
  14. data/bin/mu-gen-env +42 -0
  15. data/bin/mu-load-config.rb +158 -0
  16. data/bin/mu-node-manage +683 -0
  17. data/bin/mu-self-update +228 -0
  18. data/bin/mu-ssh +23 -0
  19. data/bin/mu-tunnel-nagios +144 -0
  20. data/bin/mu-upload-chef-artifacts +757 -0
  21. data/bin/mu-user-manage +275 -0
  22. data/cookbooks/awscli/LICENSE +37 -0
  23. data/cookbooks/awscli/README.md +58 -0
  24. data/cookbooks/awscli/attributes/default.rb +1 -0
  25. data/cookbooks/awscli/libraries/instance_metadata.rb +21 -0
  26. data/cookbooks/awscli/metadata.rb +20 -0
  27. data/cookbooks/awscli/recipes/default.rb +56 -0
  28. data/cookbooks/awscli/templates/default/config.erb +18 -0
  29. data/cookbooks/mu-activedirectory/CHANGELOG.md +13 -0
  30. data/cookbooks/mu-activedirectory/LICENSE +37 -0
  31. data/cookbooks/mu-activedirectory/README.md +6 -0
  32. data/cookbooks/mu-activedirectory/attributes/default.rb +98 -0
  33. data/cookbooks/mu-activedirectory/files/default/password-auth +32 -0
  34. data/cookbooks/mu-activedirectory/files/default/sshd_pol.pp +0 -0
  35. data/cookbooks/mu-activedirectory/files/default/sshd_pol.te +32 -0
  36. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.pp +0 -0
  37. data/cookbooks/mu-activedirectory/files/default/syslogd_oddjobd.te +10 -0
  38. data/cookbooks/mu-activedirectory/files/default/system-auth +34 -0
  39. data/cookbooks/mu-activedirectory/files/default/winbindpol.pp +0 -0
  40. data/cookbooks/mu-activedirectory/files/default/winbindpol.te +37 -0
  41. data/cookbooks/mu-activedirectory/libraries/config.rb +106 -0
  42. data/cookbooks/mu-activedirectory/libraries/helper.rb +86 -0
  43. data/cookbooks/mu-activedirectory/metadata.rb +17 -0
  44. data/cookbooks/mu-activedirectory/providers/domain.rb +152 -0
  45. data/cookbooks/mu-activedirectory/providers/domain_controller.rb +89 -0
  46. data/cookbooks/mu-activedirectory/providers/domain_node.rb +275 -0
  47. data/cookbooks/mu-activedirectory/recipes/default.rb +8 -0
  48. data/cookbooks/mu-activedirectory/recipes/domain-controller.rb +44 -0
  49. data/cookbooks/mu-activedirectory/recipes/domain-node.rb +50 -0
  50. data/cookbooks/mu-activedirectory/recipes/domain.rb +43 -0
  51. data/cookbooks/mu-activedirectory/recipes/sssd.rb +185 -0
  52. data/cookbooks/mu-activedirectory/resources/domain.rb +25 -0
  53. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +25 -0
  54. data/cookbooks/mu-activedirectory/resources/domain_node.rb +20 -0
  55. data/cookbooks/mu-activedirectory/templates/default/dhclient-eth0.conf.erb +4 -0
  56. data/cookbooks/mu-activedirectory/templates/default/interface +0 -0
  57. data/cookbooks/mu-activedirectory/templates/default/krb5.conf.erb +23 -0
  58. data/cookbooks/mu-activedirectory/templates/default/ntp.conf.erb +56 -0
  59. data/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +33 -0
  60. data/cookbooks/mu-activedirectory/templates/default/sssd.conf.erb +60 -0
  61. data/cookbooks/mu-activedirectory/templates/windows/Backup.xml.erb +20 -0
  62. data/cookbooks/mu-activedirectory/templates/windows/bkupInfo.xml.erb +1 -0
  63. data/cookbooks/mu-activedirectory/templates/windows/gpreprt.xml.erb +198 -0
  64. data/cookbooks/mu-activedirectory/templates/windows/gptmpl.inf.erb +12 -0
  65. data/cookbooks/mu-activedirectory/templates/windows/manifest.xml.erb +1 -0
  66. data/cookbooks/mu-firewall/CHANGELOG.md +11 -0
  67. data/cookbooks/mu-firewall/LICENSE +37 -0
  68. data/cookbooks/mu-firewall/README.md +5 -0
  69. data/cookbooks/mu-firewall/attributes/default.rb +3 -0
  70. data/cookbooks/mu-firewall/metadata.rb +16 -0
  71. data/cookbooks/mu-firewall/recipes/default.rb +10 -0
  72. data/cookbooks/mu-glusterfs/CHANGELOG.md +13 -0
  73. data/cookbooks/mu-glusterfs/LICENSE +37 -0
  74. data/cookbooks/mu-glusterfs/README.md +5 -0
  75. data/cookbooks/mu-glusterfs/attributes/default.rb +34 -0
  76. data/cookbooks/mu-glusterfs/metadata.rb +17 -0
  77. data/cookbooks/mu-glusterfs/recipes/client.rb +62 -0
  78. data/cookbooks/mu-glusterfs/recipes/default.rb +16 -0
  79. data/cookbooks/mu-glusterfs/recipes/samba.rb +57 -0
  80. data/cookbooks/mu-glusterfs/recipes/server.rb +200 -0
  81. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +71 -0
  82. data/cookbooks/mu-glusterfs/templates/default/smb.conf.erb +14 -0
  83. data/cookbooks/mu-jenkins/CHANGELOG.md +13 -0
  84. data/cookbooks/mu-jenkins/LICENSE +37 -0
  85. data/cookbooks/mu-jenkins/README.md +105 -0
  86. data/cookbooks/mu-jenkins/attributes/default.rb +42 -0
  87. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +73 -0
  88. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +44 -0
  89. data/cookbooks/mu-jenkins/metadata.rb +21 -0
  90. data/cookbooks/mu-jenkins/recipes/default.rb +195 -0
  91. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +54 -0
  92. data/cookbooks/mu-jenkins/recipes/public_key.rb +24 -0
  93. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +24 -0
  94. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +14 -0
  95. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +6 -0
  96. data/cookbooks/mu-master/CHANGELOG.md +13 -0
  97. data/cookbooks/mu-master/LICENSE +37 -0
  98. data/cookbooks/mu-master/README.md +6 -0
  99. data/cookbooks/mu-master/attributes/default.rb +95 -0
  100. data/cookbooks/mu-master/files/default/0-mu-log-server.conf +19 -0
  101. data/cookbooks/mu-master/files/default/addRSA.ldif +8 -0
  102. data/cookbooks/mu-master/files/default/check_mem.pl +197 -0
  103. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  104. data/cookbooks/mu-master/files/default/dirsrv_admin.pp +0 -0
  105. data/cookbooks/mu-master/files/default/dirsrv_admin.te +13 -0
  106. data/cookbooks/mu-master/files/default/nagios_selinux.pp +0 -0
  107. data/cookbooks/mu-master/files/default/nagios_selinux.te +51 -0
  108. data/cookbooks/mu-master/files/default/nagios_selinux_7.pp +0 -0
  109. data/cookbooks/mu-master/files/default/nagios_selinux_7.te +17 -0
  110. data/cookbooks/mu-master/files/default/pam_sshd +18 -0
  111. data/cookbooks/mu-master/files/default/ssl_enable.ldif +18 -0
  112. data/cookbooks/mu-master/files/default/syslogd_oddjobd.pp +0 -0
  113. data/cookbooks/mu-master/files/default/syslogd_oddjobd.te +10 -0
  114. data/cookbooks/mu-master/files/default/vimrc +19 -0
  115. data/cookbooks/mu-master/libraries/mu.rb +29 -0
  116. data/cookbooks/mu-master/metadata.rb +30 -0
  117. data/cookbooks/mu-master/providers/user.rb +41 -0
  118. data/cookbooks/mu-master/recipes/389ds.rb +164 -0
  119. data/cookbooks/mu-master/recipes/basepackages.rb +58 -0
  120. data/cookbooks/mu-master/recipes/caching_nameserver.rb +37 -0
  121. data/cookbooks/mu-master/recipes/default.rb +451 -0
  122. data/cookbooks/mu-master/recipes/eks-kubectl.rb +41 -0
  123. data/cookbooks/mu-master/recipes/firewall-holes.rb +70 -0
  124. data/cookbooks/mu-master/recipes/init.rb +542 -0
  125. data/cookbooks/mu-master/recipes/ssl-certs.rb +109 -0
  126. data/cookbooks/mu-master/recipes/sssd.rb +89 -0
  127. data/cookbooks/mu-master/recipes/update_nagios_only.rb +242 -0
  128. data/cookbooks/mu-master/recipes/vault.rb +111 -0
  129. data/cookbooks/mu-master/resources/user.rb +19 -0
  130. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +28 -0
  131. data/cookbooks/mu-master/templates/default/chef-server.rb.erb +18 -0
  132. data/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +9 -0
  133. data/cookbooks/mu-master/templates/default/mu-momma-cat.erb +149 -0
  134. data/cookbooks/mu-master/templates/default/mu.rc.erb +9 -0
  135. data/cookbooks/mu-master/templates/default/openssl.cnf.erb +354 -0
  136. data/cookbooks/mu-master/templates/default/sssd.conf.erb +44 -0
  137. data/cookbooks/mu-master/templates/default/web_app.conf.erb +90 -0
  138. data/cookbooks/mu-mongo/CHANGELOG.md +13 -0
  139. data/cookbooks/mu-mongo/LICENSE +37 -0
  140. data/cookbooks/mu-mongo/README.md +5 -0
  141. data/cookbooks/mu-mongo/attributes/default.rb +22 -0
  142. data/cookbooks/mu-mongo/files/default/keyfile +16 -0
  143. data/cookbooks/mu-mongo/files/default/remove_nodes.js +5 -0
  144. data/cookbooks/mu-mongo/metadata.rb +17 -0
  145. data/cookbooks/mu-mongo/recipes/default.rb +149 -0
  146. data/cookbooks/mu-mongo/recipes/yum-update-rule.rb +18 -0
  147. data/cookbooks/mu-mongo/templates/default/mongo_create_openfema_db.js.erb +2 -0
  148. data/cookbooks/mu-mongo/templates/default/mongo_init.js.erb +1 -0
  149. data/cookbooks/mu-mongo/templates/default/mongo_logrotate.erb +14 -0
  150. data/cookbooks/mu-mongo/templates/default/mongo_replset_addnodes.js.erb +6 -0
  151. data/cookbooks/mu-mongo/templates/default/replset_init.js.erb +2 -0
  152. data/cookbooks/mu-openvpn/CHANGELOG.md +13 -0
  153. data/cookbooks/mu-openvpn/LICENSE +37 -0
  154. data/cookbooks/mu-openvpn/README.md +6 -0
  155. data/cookbooks/mu-openvpn/attributes/default.rb +119 -0
  156. data/cookbooks/mu-openvpn/metadata.rb +18 -0
  157. data/cookbooks/mu-openvpn/recipes/default.rb +108 -0
  158. data/cookbooks/mu-openvpn/templates/default/users.json.erb +42 -0
  159. data/cookbooks/mu-php54/CHANGELOG.md +12 -0
  160. data/cookbooks/mu-php54/LICENSE +37 -0
  161. data/cookbooks/mu-php54/README.md +0 -0
  162. data/cookbooks/mu-php54/files/centos/php.ini +1802 -0
  163. data/cookbooks/mu-php54/files/ubuntu/php.ini +1870 -0
  164. data/cookbooks/mu-php54/metadata.rb +21 -0
  165. data/cookbooks/mu-php54/recipes/default.rb +97 -0
  166. data/cookbooks/mu-splunk/CHANGELOG.md +37 -0
  167. data/cookbooks/mu-splunk/LICENSE +37 -0
  168. data/cookbooks/mu-splunk/README.md +451 -0
  169. data/cookbooks/mu-splunk/attributes/default.rb +95 -0
  170. data/cookbooks/mu-splunk/attributes/upgrade.rb +49 -0
  171. data/cookbooks/mu-splunk/definitions/splunk_installer.rb +103 -0
  172. data/cookbooks/mu-splunk/files/default/splunk-nocheck +10 -0
  173. data/cookbooks/mu-splunk/libraries/helpers.rb +72 -0
  174. data/cookbooks/mu-splunk/libraries/splunk_app_provider.rb +156 -0
  175. data/cookbooks/mu-splunk/libraries/splunk_app_resource.rb +43 -0
  176. data/cookbooks/mu-splunk/metadata.json +30 -0
  177. data/cookbooks/mu-splunk/metadata.rb +17 -0
  178. data/cookbooks/mu-splunk/recipes/client.rb +143 -0
  179. data/cookbooks/mu-splunk/recipes/default.rb +31 -0
  180. data/cookbooks/mu-splunk/recipes/disabled.rb +41 -0
  181. data/cookbooks/mu-splunk/recipes/install_forwarder.rb +23 -0
  182. data/cookbooks/mu-splunk/recipes/install_server.rb +23 -0
  183. data/cookbooks/mu-splunk/recipes/server.rb +53 -0
  184. data/cookbooks/mu-splunk/recipes/service.rb +95 -0
  185. data/cookbooks/mu-splunk/recipes/setup_auth.rb +49 -0
  186. data/cookbooks/mu-splunk/recipes/setup_ssl.rb +63 -0
  187. data/cookbooks/mu-splunk/recipes/upgrade.rb +94 -0
  188. data/cookbooks/mu-splunk/recipes/user.rb +34 -0
  189. data/cookbooks/mu-splunk/templates/default/base_logs_unix_inputs.conf.erb +26 -0
  190. data/cookbooks/mu-splunk/templates/default/inputs.conf.erb +13 -0
  191. data/cookbooks/mu-splunk/templates/default/outputs.conf.erb +9 -0
  192. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +74 -0
  193. data/cookbooks/mu-splunk/templates/default/system-web.conf.erb +7 -0
  194. data/cookbooks/mu-tools/CHANGELOG.md +12 -0
  195. data/cookbooks/mu-tools/LICENSE +37 -0
  196. data/cookbooks/mu-tools/README.md +188 -0
  197. data/cookbooks/mu-tools/attributes/default.rb +142 -0
  198. data/cookbooks/mu-tools/attributes/ebs_rolling_snapshots.rb +3 -0
  199. data/cookbooks/mu-tools/files/amazon/etc/freshclam.conf +235 -0
  200. data/cookbooks/mu-tools/files/centos/CentOS-Base.repo +52 -0
  201. data/cookbooks/mu-tools/files/centos/etc/bashrc +93 -0
  202. data/cookbooks/mu-tools/files/centos/etc/freshclam.conf +235 -0
  203. data/cookbooks/mu-tools/files/centos/etc/login.defs +72 -0
  204. data/cookbooks/mu-tools/files/centos/etc/profile +77 -0
  205. data/cookbooks/mu-tools/files/centos/etc/security/limits.conf +57 -0
  206. data/cookbooks/mu-tools/files/centos/etc/sysconfig/init +19 -0
  207. data/cookbooks/mu-tools/files/centos/etc/sysctl.conf +82 -0
  208. data/cookbooks/mu-tools/files/centos-6/README_MU +0 -0
  209. data/cookbooks/mu-tools/files/centos-6/etc/audit/stig.rules +173 -0
  210. data/cookbooks/mu-tools/files/centos-6/etc/bashrc +90 -0
  211. data/cookbooks/mu-tools/files/centos-6/etc/login.defs +70 -0
  212. data/cookbooks/mu-tools/files/centos-6/etc/pam.d/su +12 -0
  213. data/cookbooks/mu-tools/files/centos-6/etc/profile +83 -0
  214. data/cookbooks/mu-tools/files/centos-6/etc/securetty +12 -0
  215. data/cookbooks/mu-tools/files/centos-6/etc/sysconfig/init +30 -0
  216. data/cookbooks/mu-tools/files/centos-6/etc/sysctl.conf +40 -0
  217. data/cookbooks/mu-tools/files/default/Mu_CA.pem +34 -0
  218. data/cookbooks/mu-tools/files/default/PSWindowsUpdate.zip +0 -0
  219. data/cookbooks/mu-tools/files/default/ebs_snapshots.py +123 -0
  220. data/cookbooks/mu-tools/files/default/etc/BANNER +0 -0
  221. data/cookbooks/mu-tools/files/default/etc/BANNER-FEDERAL +19 -0
  222. data/cookbooks/mu-tools/files/default/gpo_no_uac.zip +0 -0
  223. data/cookbooks/mu-tools/files/default/mypol.pp +0 -0
  224. data/cookbooks/mu-tools/files/default/mypol.te +37 -0
  225. data/cookbooks/mu-tools/files/default/nrpe_c7.pp +0 -0
  226. data/cookbooks/mu-tools/files/default/nrpe_c7.te +31 -0
  227. data/cookbooks/mu-tools/files/default/nrpe_check_disk.pp +0 -0
  228. data/cookbooks/mu-tools/files/default/nrpe_check_disk.te +11 -0
  229. data/cookbooks/mu-tools/files/default/nrpe_disk.pp +0 -0
  230. data/cookbooks/mu-tools/files/default/nrpe_disk.te +10 -0
  231. data/cookbooks/mu-tools/files/default/nrpe_file.pp +0 -0
  232. data/cookbooks/mu-tools/files/default/nrpe_file.te +31 -0
  233. data/cookbooks/mu-tools/files/default/ntrights +0 -0
  234. data/cookbooks/mu-tools/files/default/serverclass.conf +18 -0
  235. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/app.conf +1 -0
  236. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_unix/local/inputs.conf +13 -0
  237. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/app.conf +1 -0
  238. data/cookbooks/mu-tools/files/default/splunk-apps/base_logs_windows/local/inputs.conf +8 -0
  239. data/cookbooks/mu-tools/files/default/sshd_pol.pp +0 -0
  240. data/cookbooks/mu-tools/files/default/sshd_pol.te +32 -0
  241. data/cookbooks/mu-tools/files/redhat/etc/bashrc +93 -0
  242. data/cookbooks/mu-tools/files/redhat/etc/freshclam.conf +235 -0
  243. data/cookbooks/mu-tools/files/redhat/etc/login.defs +72 -0
  244. data/cookbooks/mu-tools/files/redhat/etc/profile +77 -0
  245. data/cookbooks/mu-tools/files/redhat/etc/security/limits.conf +57 -0
  246. data/cookbooks/mu-tools/files/redhat/etc/sysconfig/init +19 -0
  247. data/cookbooks/mu-tools/files/redhat/etc/sysctl.conf +82 -0
  248. data/cookbooks/mu-tools/files/redhat-6/README_MU +0 -0
  249. data/cookbooks/mu-tools/files/redhat-6/etc/audit/stig.rules +173 -0
  250. data/cookbooks/mu-tools/files/redhat-6/etc/bashrc +90 -0
  251. data/cookbooks/mu-tools/files/redhat-6/etc/login.defs +70 -0
  252. data/cookbooks/mu-tools/files/redhat-6/etc/pam.d/su +12 -0
  253. data/cookbooks/mu-tools/files/redhat-6/etc/profile +83 -0
  254. data/cookbooks/mu-tools/files/redhat-6/etc/securetty +12 -0
  255. data/cookbooks/mu-tools/files/redhat-6/etc/sysconfig/init +30 -0
  256. data/cookbooks/mu-tools/files/redhat-6/etc/sysctl.conf +40 -0
  257. data/cookbooks/mu-tools/files/redhat-7.1/etc/freshclam.conf +235 -0
  258. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/bash.bashrc +64 -0
  259. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/common-session +30 -0
  260. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/login.defs +338 -0
  261. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/profile +30 -0
  262. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/security/limits.conf +56 -0
  263. data/cookbooks/mu-tools/files/ubuntu-12.04/etc/sysctl.conf +60 -0
  264. data/cookbooks/mu-tools/libraries/helper.rb +292 -0
  265. data/cookbooks/mu-tools/metadata.rb +28 -0
  266. data/cookbooks/mu-tools/recipes/add_admin_ssh_keys.rb +35 -0
  267. data/cookbooks/mu-tools/recipes/apply_security.rb +440 -0
  268. data/cookbooks/mu-tools/recipes/aws_api.rb +23 -0
  269. data/cookbooks/mu-tools/recipes/base_repositories.rb +31 -0
  270. data/cookbooks/mu-tools/recipes/cisbenchmark.rb +59 -0
  271. data/cookbooks/mu-tools/recipes/clamav.rb +53 -0
  272. data/cookbooks/mu-tools/recipes/cloudinit.rb +58 -0
  273. data/cookbooks/mu-tools/recipes/configure_oracle_tools.rb +81 -0
  274. data/cookbooks/mu-tools/recipes/disable-requiretty.rb +22 -0
  275. data/cookbooks/mu-tools/recipes/ebs_rolling_snapshots.rb +75 -0
  276. data/cookbooks/mu-tools/recipes/efs.rb +70 -0
  277. data/cookbooks/mu-tools/recipes/eks.rb +160 -0
  278. data/cookbooks/mu-tools/recipes/gcloud.rb +98 -0
  279. data/cookbooks/mu-tools/recipes/google_api.rb +25 -0
  280. data/cookbooks/mu-tools/recipes/maldet.rb +67 -0
  281. data/cookbooks/mu-tools/recipes/nagios.rb +19 -0
  282. data/cookbooks/mu-tools/recipes/newclient.rb +23 -0
  283. data/cookbooks/mu-tools/recipes/nrpe.rb +115 -0
  284. data/cookbooks/mu-tools/recipes/python_pip.rb +35 -0
  285. data/cookbooks/mu-tools/recipes/retrieve_application.rb +51 -0
  286. data/cookbooks/mu-tools/recipes/rsyslog.rb +65 -0
  287. data/cookbooks/mu-tools/recipes/set_local_fw.rb +57 -0
  288. data/cookbooks/mu-tools/recipes/set_mu_hostname.rb +81 -0
  289. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +86 -0
  290. data/cookbooks/mu-tools/recipes/splunk-client.rb +69 -0
  291. data/cookbooks/mu-tools/recipes/splunk-server.rb +104 -0
  292. data/cookbooks/mu-tools/recipes/store_inspec_attr.rb +8 -0
  293. data/cookbooks/mu-tools/recipes/updates.rb +96 -0
  294. data/cookbooks/mu-tools/recipes/windows-client.rb +202 -0
  295. data/cookbooks/mu-tools/resources/aws_windows.rb +33 -0
  296. data/cookbooks/mu-tools/resources/disk.rb +88 -0
  297. data/cookbooks/mu-tools/resources/mommacat_request.rb +11 -0
  298. data/cookbooks/mu-tools/resources/scheduled_tasks.rb +29 -0
  299. data/cookbooks/mu-tools/resources/sshd_service.rb +45 -0
  300. data/cookbooks/mu-tools/resources/windows_users.rb +242 -0
  301. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +168 -0
  302. data/cookbooks/mu-tools/templates/centos-6/sshd_config.erb +212 -0
  303. data/cookbooks/mu-tools/templates/centos-7/sshd_config.erb +215 -0
  304. data/cookbooks/mu-tools/templates/default/0-mu-log-client.conf.erb +13 -0
  305. data/cookbooks/mu-tools/templates/default/conf.maldet.erb +137 -0
  306. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +30 -0
  307. data/cookbooks/mu-tools/templates/default/etc_pamd_password-auth.erb +14 -0
  308. data/cookbooks/mu-tools/templates/default/etc_pamd_system-auth.erb +14 -0
  309. data/cookbooks/mu-tools/templates/default/etc_sysconfig_network.erb +12 -0
  310. data/cookbooks/mu-tools/templates/default/kubeconfig.erb +29 -0
  311. data/cookbooks/mu-tools/templates/default/kubelet.service.erb +35 -0
  312. data/cookbooks/mu-tools/templates/default/maldet_scanall.sh.erb +15 -0
  313. data/cookbooks/mu-tools/templates/default/nrpe.cfg.erb +233 -0
  314. data/cookbooks/mu-tools/templates/redhat-6/sshd_config.erb +213 -0
  315. data/cookbooks/mu-tools/templates/redhat-7/sshd_config.erb +215 -0
  316. data/cookbooks/mu-tools/templates/ubuntu-12.04/sshd_config.erb +146 -0
  317. data/cookbooks/mu-tools/templates/ubuntu-14.04/sshd_config.erb +145 -0
  318. data/cookbooks/mu-tools/templates/windows/Backup.xml.erb +20 -0
  319. data/cookbooks/mu-tools/templates/windows/bkupInfo.xml.erb +1 -0
  320. data/cookbooks/mu-tools/templates/windows/gpreprt.xml.erb +214 -0
  321. data/cookbooks/mu-tools/templates/windows/gptmpl.inf.erb +12 -0
  322. data/cookbooks/mu-tools/templates/windows/manifest.xml.erb +1 -0
  323. data/cookbooks/mu-tools/templates/windows/set_ad_dns_scheduled_task.ps1.erb +6 -0
  324. data/cookbooks/mu-tools/templates/windows/sshd_config.erb +136 -0
  325. data/cookbooks/mu-utility/CHANGELOG.md +12 -0
  326. data/cookbooks/mu-utility/LICENSE +37 -0
  327. data/cookbooks/mu-utility/README.md +6 -0
  328. data/cookbooks/mu-utility/attributes/default.rb +1 -0
  329. data/cookbooks/mu-utility/libraries/matchers.rb +21 -0
  330. data/cookbooks/mu-utility/metadata.rb +16 -0
  331. data/cookbooks/mu-utility/recipes/apt.rb +23 -0
  332. data/cookbooks/mu-utility/recipes/cleanup_image_helper.rb +118 -0
  333. data/cookbooks/mu-utility/recipes/iptables.rb +26 -0
  334. data/cookbooks/mu-utility/recipes/luks.rb +18 -0
  335. data/cookbooks/mu-utility/recipes/nat.rb +104 -0
  336. data/cookbooks/mu-utility/recipes/php.rb +33 -0
  337. data/cookbooks/mu-utility/recipes/rdp_gateway.rb +83 -0
  338. data/cookbooks/mu-utility/recipes/remi.rb +44 -0
  339. data/cookbooks/mu-utility/recipes/vim.rb +26 -0
  340. data/cookbooks/mu-utility/recipes/windows_basics.rb +37 -0
  341. data/cookbooks/mu-utility/recipes/zip.rb +26 -0
  342. data/cookbooks/mu-utility/templates/default/BundleConfig.xml.erb +34 -0
  343. data/cookbooks/mu-utility/templates/default/config.xml.erb +60 -0
  344. data/cookbooks/nagios/Berksfile +8 -0
  345. data/cookbooks/nagios/CHANGELOG.md +589 -0
  346. data/cookbooks/nagios/CONTRIBUTING.md +11 -0
  347. data/cookbooks/nagios/LICENSE +37 -0
  348. data/cookbooks/nagios/README.md +328 -0
  349. data/cookbooks/nagios/TESTING.md +2 -0
  350. data/cookbooks/nagios/attributes/config.rb +171 -0
  351. data/cookbooks/nagios/attributes/default.rb +228 -0
  352. data/cookbooks/nagios/chefignore +102 -0
  353. data/cookbooks/nagios/definitions/command.rb +33 -0
  354. data/cookbooks/nagios/definitions/contact.rb +33 -0
  355. data/cookbooks/nagios/definitions/contactgroup.rb +33 -0
  356. data/cookbooks/nagios/definitions/host.rb +33 -0
  357. data/cookbooks/nagios/definitions/hostdependency.rb +33 -0
  358. data/cookbooks/nagios/definitions/hostescalation.rb +34 -0
  359. data/cookbooks/nagios/definitions/hostgroup.rb +33 -0
  360. data/cookbooks/nagios/definitions/nagios_conf.rb +38 -0
  361. data/cookbooks/nagios/definitions/resource.rb +33 -0
  362. data/cookbooks/nagios/definitions/service.rb +33 -0
  363. data/cookbooks/nagios/definitions/servicedependency.rb +33 -0
  364. data/cookbooks/nagios/definitions/serviceescalation.rb +34 -0
  365. data/cookbooks/nagios/definitions/servicegroup.rb +33 -0
  366. data/cookbooks/nagios/definitions/timeperiod.rb +33 -0
  367. data/cookbooks/nagios/libraries/base.rb +314 -0
  368. data/cookbooks/nagios/libraries/command.rb +91 -0
  369. data/cookbooks/nagios/libraries/contact.rb +230 -0
  370. data/cookbooks/nagios/libraries/contactgroup.rb +112 -0
  371. data/cookbooks/nagios/libraries/custom_option.rb +36 -0
  372. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  373. data/cookbooks/nagios/libraries/default.rb +90 -0
  374. data/cookbooks/nagios/libraries/host.rb +412 -0
  375. data/cookbooks/nagios/libraries/hostdependency.rb +181 -0
  376. data/cookbooks/nagios/libraries/hostescalation.rb +173 -0
  377. data/cookbooks/nagios/libraries/hostgroup.rb +119 -0
  378. data/cookbooks/nagios/libraries/nagios.rb +282 -0
  379. data/cookbooks/nagios/libraries/resource.rb +59 -0
  380. data/cookbooks/nagios/libraries/service.rb +455 -0
  381. data/cookbooks/nagios/libraries/servicedependency.rb +215 -0
  382. data/cookbooks/nagios/libraries/serviceescalation.rb +195 -0
  383. data/cookbooks/nagios/libraries/servicegroup.rb +144 -0
  384. data/cookbooks/nagios/libraries/timeperiod.rb +160 -0
  385. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  386. data/cookbooks/nagios/metadata.rb +25 -0
  387. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  388. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  389. data/cookbooks/nagios/recipes/apache.rb +48 -0
  390. data/cookbooks/nagios/recipes/default.rb +204 -0
  391. data/cookbooks/nagios/recipes/nginx.rb +82 -0
  392. data/cookbooks/nagios/recipes/pagerduty.rb +143 -0
  393. data/cookbooks/nagios/recipes/server_package.rb +40 -0
  394. data/cookbooks/nagios/recipes/server_source.rb +164 -0
  395. data/cookbooks/nagios/templates/default/apache2.conf.erb +96 -0
  396. data/cookbooks/nagios/templates/default/cgi.cfg.erb +266 -0
  397. data/cookbooks/nagios/templates/default/commands.cfg.erb +13 -0
  398. data/cookbooks/nagios/templates/default/contacts.cfg.erb +37 -0
  399. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +25 -0
  400. data/cookbooks/nagios/templates/default/hosts.cfg.erb +15 -0
  401. data/cookbooks/nagios/templates/default/htpasswd.users.erb +6 -0
  402. data/cookbooks/nagios/templates/default/nagios.cfg.erb +22 -0
  403. data/cookbooks/nagios/templates/default/nginx.conf.erb +62 -0
  404. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +185 -0
  405. data/cookbooks/nagios/templates/default/resource.cfg.erb +27 -0
  406. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +15 -0
  407. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +14 -0
  408. data/cookbooks/nagios/templates/default/services.cfg.erb +14 -0
  409. data/cookbooks/nagios/templates/default/templates.cfg.erb +31 -0
  410. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +13 -0
  411. data/cookbooks/s3fs/CHANGELOG.md +13 -0
  412. data/cookbooks/s3fs/LICENSE +37 -0
  413. data/cookbooks/s3fs/README.md +6 -0
  414. data/cookbooks/s3fs/attributes/default.rb +15 -0
  415. data/cookbooks/s3fs/files/default/fuse-2.9.3.zip +0 -0
  416. data/cookbooks/s3fs/metadata.rb +16 -0
  417. data/cookbooks/s3fs/recipes/default.rb +91 -0
  418. data/data_bags/demo/app.json +7 -0
  419. data/data_bags/nagios_services/chef.json +6 -0
  420. data/data_bags/nagios_services/linux_diskspace.json +5 -0
  421. data/data_bags/nagios_services/momma_cat.json +6 -0
  422. data/data_bags/nagios_services/mu-master-memory.json +5 -0
  423. data/data_bags/nagios_services/nagios_ui.json +6 -0
  424. data/data_bags/nagios_services/node_ssh.json +6 -0
  425. data/data_bags/nagios_services/ssh.json +6 -0
  426. data/demo/lambda_test.yaml +29 -0
  427. data/environments/DEV.json +8 -0
  428. data/environments/PROD.json +8 -0
  429. data/environments/dev.json +8 -0
  430. data/environments/development.json +8 -0
  431. data/environments/prod.json +8 -0
  432. data/extras/README.md +1 -0
  433. data/extras/admin-role-binding.yaml +16 -0
  434. data/extras/admin-user.yaml +6 -0
  435. data/extras/aws-auth-cm.yaml.erb +12 -0
  436. data/extras/clean-stock-amis +48 -0
  437. data/extras/git-fix-permissions-hook +12 -0
  438. data/extras/gitlab-eks-helper.sh.erb +20 -0
  439. data/extras/image-generators/README.md +2 -0
  440. data/extras/image-generators/aws/centos6.yaml +18 -0
  441. data/extras/image-generators/aws/centos7-govcloud.yaml +24 -0
  442. data/extras/image-generators/aws/centos7.yaml +17 -0
  443. data/extras/image-generators/aws/rhel7.yaml +17 -0
  444. data/extras/image-generators/aws/win2k12.yaml +16 -0
  445. data/extras/image-generators/aws/win2k16.yaml +16 -0
  446. data/extras/image-generators/aws/windows.yaml +18 -0
  447. data/extras/image-generators/gcp/centos6.yaml +17 -0
  448. data/extras/lambda_waf_domain_blacklist.py +103 -0
  449. data/extras/platform_berksfile_base +50 -0
  450. data/extras/ruby_rpm/build.sh +17 -0
  451. data/extras/ruby_rpm/muby.spec +44 -0
  452. data/extras/vault_tools/README.md +6 -0
  453. data/extras/vault_tools/export_vaults.sh +3 -0
  454. data/extras/vault_tools/recreate_vaults.sh +5 -0
  455. data/extras/vault_tools/test_vaults.sh +5 -0
  456. data/install/README.md +8 -0
  457. data/install/cfn_create_mu_master.json +1034 -0
  458. data/install/chef-server.rb.erb +19 -0
  459. data/install/deprecated-bash-library.sh +1891 -0
  460. data/install/images/Usage.png +0 -0
  461. data/install/installer +71 -0
  462. data/install/jenkinskeys.rb +8 -0
  463. data/install/user-dot-murc.erb +14 -0
  464. data/modules/html.erb +19 -0
  465. data/modules/mommacat.ru +426 -0
  466. data/modules/mu/cleanup.rb +339 -0
  467. data/modules/mu/cloud.rb +1446 -0
  468. data/modules/mu/clouds/README.md +201 -0
  469. data/modules/mu/clouds/aws/alarm.rb +319 -0
  470. data/modules/mu/clouds/aws/cache_cluster.rb +1010 -0
  471. data/modules/mu/clouds/aws/collection.rb +373 -0
  472. data/modules/mu/clouds/aws/container_cluster.rb +667 -0
  473. data/modules/mu/clouds/aws/database.rb +1836 -0
  474. data/modules/mu/clouds/aws/dnszone.rb +911 -0
  475. data/modules/mu/clouds/aws/firewall_rule.rb +641 -0
  476. data/modules/mu/clouds/aws/folder.rb +92 -0
  477. data/modules/mu/clouds/aws/function.rb +349 -0
  478. data/modules/mu/clouds/aws/group.rb +251 -0
  479. data/modules/mu/clouds/aws/loadbalancer.rb +888 -0
  480. data/modules/mu/clouds/aws/log.rb +363 -0
  481. data/modules/mu/clouds/aws/msg_queue.rb +480 -0
  482. data/modules/mu/clouds/aws/notification.rb +139 -0
  483. data/modules/mu/clouds/aws/role.rb +656 -0
  484. data/modules/mu/clouds/aws/search_domain.rb +646 -0
  485. data/modules/mu/clouds/aws/server.rb +2294 -0
  486. data/modules/mu/clouds/aws/server_pool.rb +1388 -0
  487. data/modules/mu/clouds/aws/storage_pool.rb +495 -0
  488. data/modules/mu/clouds/aws/user.rb +382 -0
  489. data/modules/mu/clouds/aws/userdata/README.md +4 -0
  490. data/modules/mu/clouds/aws/userdata/linux.erb +179 -0
  491. data/modules/mu/clouds/aws/userdata/windows.erb +278 -0
  492. data/modules/mu/clouds/aws/vpc.rb +1943 -0
  493. data/modules/mu/clouds/aws.rb +1009 -0
  494. data/modules/mu/clouds/cloudformation/alarm.rb +146 -0
  495. data/modules/mu/clouds/cloudformation/cache_cluster.rb +167 -0
  496. data/modules/mu/clouds/cloudformation/collection.rb +117 -0
  497. data/modules/mu/clouds/cloudformation/database.rb +278 -0
  498. data/modules/mu/clouds/cloudformation/dnszone.rb +274 -0
  499. data/modules/mu/clouds/cloudformation/firewall_rule.rb +308 -0
  500. data/modules/mu/clouds/cloudformation/loadbalancer.rb +193 -0
  501. data/modules/mu/clouds/cloudformation/log.rb +170 -0
  502. data/modules/mu/clouds/cloudformation/server.rb +370 -0
  503. data/modules/mu/clouds/cloudformation/server_pool.rb +279 -0
  504. data/modules/mu/clouds/cloudformation/vpc.rb +322 -0
  505. data/modules/mu/clouds/cloudformation.rb +733 -0
  506. data/modules/mu/clouds/docker.rb +30 -0
  507. data/modules/mu/clouds/google/container_cluster.rb +290 -0
  508. data/modules/mu/clouds/google/database.rb +152 -0
  509. data/modules/mu/clouds/google/firewall_rule.rb +267 -0
  510. data/modules/mu/clouds/google/group.rb +164 -0
  511. data/modules/mu/clouds/google/loadbalancer.rb +479 -0
  512. data/modules/mu/clouds/google/server.rb +1510 -0
  513. data/modules/mu/clouds/google/server_pool.rb +274 -0
  514. data/modules/mu/clouds/google/user.rb +266 -0
  515. data/modules/mu/clouds/google/userdata/README.md +4 -0
  516. data/modules/mu/clouds/google/userdata/linux.erb +137 -0
  517. data/modules/mu/clouds/google/userdata/windows.erb +275 -0
  518. data/modules/mu/clouds/google/vpc.rb +890 -0
  519. data/modules/mu/clouds/google.rb +811 -0
  520. data/modules/mu/config/README.md +11 -0
  521. data/modules/mu/config/alarm.rb +271 -0
  522. data/modules/mu/config/cache_cluster.rb +172 -0
  523. data/modules/mu/config/collection.rb +87 -0
  524. data/modules/mu/config/container_cluster.rb +103 -0
  525. data/modules/mu/config/container_cluster.yml +36 -0
  526. data/modules/mu/config/database.rb +458 -0
  527. data/modules/mu/config/database.yml +26 -0
  528. data/modules/mu/config/dnszone.rb +327 -0
  529. data/modules/mu/config/firewall_rule.rb +118 -0
  530. data/modules/mu/config/folder.rb +70 -0
  531. data/modules/mu/config/function.rb +140 -0
  532. data/modules/mu/config/group.rb +64 -0
  533. data/modules/mu/config/loadbalancer.rb +482 -0
  534. data/modules/mu/config/log.rb +47 -0
  535. data/modules/mu/config/log.yml +6 -0
  536. data/modules/mu/config/msg_queue.rb +47 -0
  537. data/modules/mu/config/msg_queue.yml +9 -0
  538. data/modules/mu/config/notification.rb +44 -0
  539. data/modules/mu/config/project.rb +71 -0
  540. data/modules/mu/config/role.rb +102 -0
  541. data/modules/mu/config/search_domain.rb +61 -0
  542. data/modules/mu/config/search_domain.yml +25 -0
  543. data/modules/mu/config/server.rb +587 -0
  544. data/modules/mu/config/server.yml +8 -0
  545. data/modules/mu/config/server_pool.rb +216 -0
  546. data/modules/mu/config/server_pool.yml +71 -0
  547. data/modules/mu/config/storage_pool.rb +145 -0
  548. data/modules/mu/config/user.rb +78 -0
  549. data/modules/mu/config/vpc.rb +743 -0
  550. data/modules/mu/config/vpc.yml +6 -0
  551. data/modules/mu/config.rb +2000 -0
  552. data/modules/mu/defaults/README.md +2 -0
  553. data/modules/mu/defaults/amazon_images.yaml +121 -0
  554. data/modules/mu/defaults/google_images.yaml +16 -0
  555. data/modules/mu/deploy.rb +686 -0
  556. data/modules/mu/groomer.rb +123 -0
  557. data/modules/mu/groomers/README.md +58 -0
  558. data/modules/mu/groomers/chef.rb +1024 -0
  559. data/modules/mu/kittens.rb +11319 -0
  560. data/modules/mu/logger.rb +208 -0
  561. data/modules/mu/master/README.md +27 -0
  562. data/modules/mu/master/chef.rb +471 -0
  563. data/modules/mu/master/ldap.rb +1005 -0
  564. data/modules/mu/master.rb +415 -0
  565. data/modules/mu/mommacat.rb +2703 -0
  566. data/modules/mu-load-config.rb +1 -0
  567. data/modules/mu.rb +724 -0
  568. data/modules/scratchpad.erb +1 -0
  569. data/modules/tests/super_complex_bok.yml +41 -0
  570. data/modules/tests/super_simple_bok.yml +40 -0
  571. data/mu.gemspec +62 -0
  572. data/roles/demo-dbservice-configure.json +19 -0
  573. data/roles/demo-portal-configure.json +19 -0
  574. data/roles/mu-master-jenkins.json +24 -0
  575. data/roles/mu-master-nagios-only.json +13 -0
  576. data/roles/mu-master.json +12 -0
  577. data/roles/mu-node.json +19 -0
  578. data/roles/mu-splunk-server.json +13 -0
  579. data/roles/mu-splunk.json +13 -0
  580. data/test/clean_up.py +25 -0
  581. data/test/demo-test-profile/README.md +3 -0
  582. data/test/demo-test-profile/controls/flask.rb +84 -0
  583. data/test/demo-test-profile/inspec.lock +7 -0
  584. data/test/demo-test-profile/inspec.yml +11 -0
  585. data/test/etco-test-profile/README.md +3 -0
  586. data/test/etco-test-profile/controls/all-in-one.rb +182 -0
  587. data/test/etco-test-profile/inspec.lock +7 -0
  588. data/test/etco-test-profile/inspec.yml +11 -0
  589. data/test/exec_inspec.py +246 -0
  590. data/test/exec_mu_install.py +241 -0
  591. data/test/exec_retry.py +44 -0
  592. data/test/mu-master-test/README.md +3 -0
  593. data/test/mu-master-test/controls/all_in_one.rb +557 -0
  594. data/test/mu-master-test/inspec.lock +3 -0
  595. data/test/mu-master-test/inspec.yml +11 -0
  596. data/test/mu-tools-test/README.md +3 -0
  597. data/test/mu-tools-test/controls/base.rb +265 -0
  598. data/test/mu-tools-test/inspec.lock +3 -0
  599. data/test/mu-tools-test/inspec.yml +8 -0
  600. data/test/simple-server-php-test/README.md +3 -0
  601. data/test/simple-server-php-test/controls/apachephp.rb +25 -0
  602. data/test/simple-server-php-test/controls/example.rb +19 -0
  603. data/test/simple-server-php-test/inspec.lock +7 -0
  604. data/test/simple-server-php-test/inspec.yml +12 -0
  605. data/test/simple-server-rails-test/README.md +3 -0
  606. data/test/simple-server-rails-test/controls/rails.rb +188 -0
  607. data/test/simple-server-rails-test/inspec.lock +7 -0
  608. data/test/simple-server-rails-test/inspec.yml +11 -0
  609. data/test/simple-windows-test/README.md +3 -0
  610. data/test/simple-windows-test/controls/windows.rb +20 -0
  611. data/test/simple-windows-test/inspec.lock +7 -0
  612. data/test/simple-windows-test/inspec.yml +11 -0
  613. data/test/smoke_test.rb +75 -0
  614. data/test/wordpress-test/README.md +3 -0
  615. data/test/wordpress-test/controls/wordpress.rb +97 -0
  616. data/test/wordpress-test/inspec.lock +7 -0
  617. data/test/wordpress-test/inspec.yml +11 -0
  618. 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