const ldap = require('../util/ldapjs-extra'); const ssh = require('node-ssh'); /** * Summary of userAccountControl flags: * https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties */ const UserAccountControlFlags = { ACCOUNTDISABLE: 2 }; module.exports = Self => { Self.getSynchronizer = async function() { return await Self.findOne({ fields: [ 'host', 'adDomain', 'adController', 'adUser', 'adPassword', 'verifyCert' ] }); }; Object.assign(Self.prototype, { async init() { let sshClient = new ssh.NodeSSH(); await sshClient.connect({ host: this.adController, username: this.adUser, password: this.adPassword }); let adUser = `cn=${this.adUser},${this.usersDn()}`; let adClient = ldap.createClient({ url: `ldaps://${this.adController}:636`, tlsOptions: {rejectUnauthorized: this.verifyCert} }); await adClient.bind(adUser, this.adPassword); Object.assign(this, { sshClient, adClient }); }, async deinit() { await this.sshClient.dispose(); await this.adClient.unbind(); }, usersDn() { let dnBase = this.adDomain .split('.') .map(part => `dc=${part}`) .join(','); return `cn=Users,${dnBase}`; }, async syncUser(userName, info, password) { let {sshClient} = this; let sambaUser = await this.adClient.searchOne(this.usersDn(), { scope: 'sub', attributes: ['userAccountControl'], filter: `(&(objectClass=user)(sAMAccountName=${userName}))` }); let isEnabled = sambaUser && !(sambaUser.userAccountControl & UserAccountControlFlags.ACCOUNTDISABLE); if (process.env.NODE_ENV === 'test') return; if (info.hasAccount) { if (!sambaUser) { await sshClient.exec('samba-tool user create', [ userName, '--uid-number', `${info.uidNumber}`, '--mail-address', info.corporateMail, '--random-password' ]); await sshClient.exec('samba-tool user setexpiry', [ userName, '--noexpiry' ]); await sshClient.exec('mkhomedir_helper', [ userName, '0027' ]); } if (!isEnabled) { await sshClient.exec('samba-tool user enable', [ userName ]); } if (password) { await sshClient.exec('samba-tool user setpassword', [ userName, '--newpassword', password ]); } } else if (isEnabled) { await sshClient.exec('samba-tool user disable', [ userName ]); console.log(` -> User '${userName}' disabled on Samba`); } }, /** * Gets Samba enabled users. * * @param {Set} usersToSync */ async getUsers(usersToSync) { const LDAP_MATCHING_RULE_BIT_AND = '1.2.840.113556.1.4.803'; let filter = `!(userAccountControl:${LDAP_MATCHING_RULE_BIT_AND}:=${UserAccountControlFlags.ACCOUNTDISABLE})`; let opts = { scope: 'sub', attributes: ['sAMAccountName'], filter: `(&(objectClass=user)(${filter}))` }; await this.adClient.searchForeach(this.usersDn(), opts, o => usersToSync.add(o.sAMAccountName)); } }); };