package org.openslx.taskmanager.tasks; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.io.FileUtils; import org.openslx.satserver.util.Archive; import org.openslx.satserver.util.Constants; import org.openslx.satserver.util.Exec; import org.openslx.satserver.util.Template; import org.openslx.satserver.util.Util; import org.openslx.taskmanager.api.AbstractTask; import com.google.gson.annotations.Expose; public class CreateLdapConfig extends AbstractTask { @Expose private int moduleid = 0; @Expose private String filename = null; @Expose private String server = null; @Expose private String searchbase = null; @Expose private String binddn = null; @Expose private String bindpw = null; @Expose private String proxyip = null; @Expose private int proxyport = 0; @Expose private int adport = 0; @Expose private String home = null; @Expose private String fingerprint = ""; @Expose private boolean plainldap = false; private Output status = new Output(); @Override protected boolean initTask() { // TODO: Check path is allowed this.setStatusObject( this.status ); if ( filename == null || server == null || searchbase == null || proxyip == null || proxyport == 0 || moduleid == 0 ) { status.error = "Missing argument to task"; return false; } if ( this.home == null ) this.home = ""; if ( this.binddn == null ) this.binddn = ""; if ( this.bindpw == null ) this.bindpw = ""; return true; } @Override protected boolean execute() { TarArchiveOutputStream outArchive = null; File keyFile = new File( "/opt/ldadp/configs/" + this.moduleid + ".key.pem" ); File certFile = new File( "/opt/ldadp/configs/" + this.moduleid + ".crt.pem" ); String uri = "ldaps://" + this.proxyip + ":" + this.proxyport + "/"; String cacertPath = "/etc/ldap-proxy.pem"; try { // Generate keys if not existent if ( !keyFile.exists() || !certFile.exists() ) { int ret = Exec.sync( 20, "openssl", "req", "-x509", "-new", "-newkey", "rsa:4096", "-keyout", keyFile.getAbsolutePath(), "-out", certFile.getAbsolutePath(), "-days", "5000", "-nodes", "-subj", "/C=DE/ST=Nowhere/L=Springfield/O=Dis/CN=" + this.proxyip ); if ( ret == -1 ) { status.error = "openssl process didn't finish in time."; } else if ( ret == -2 ) { status.error = "Internal error generating certificate."; } else if ( ret != 0 ) { status.error = "openssl exited with code " + ret; } if ( ret != 0 ) return false; } // ldadp config String ldadpConf = String.format( "[%s]\n" + "binddn=%s\n" + "bindpw=%s\n" + "base=%s\n" + "home=%s\n" + "port=%s\n" + "fingerprint=%s\n" + "plainldap=%s\n" + "[local]\n" + "port=%s\n" + "cert=%s\n" + "privkey=%s\n" + "\n", this.server, this.binddn, this.bindpw, this.searchbase, this.home, this.adport, this.fingerprint, Boolean.toString( this.plainldap ), this.proxyport, certFile, keyFile ); // Generic ldap config final Template ldapConf = new Template( "./data/ad/ldap.conf.template" ); ldapConf.replace( "%URI%", uri ); ldapConf.replace( "%SEARCHBASE%", this.searchbase ); ldapConf.replace( "%CACERT%", cacertPath ); // sssd config final Template sssdConf = new Template( "./data/ad/sssd.conf.template" ); sssdConf.replace( "%URI%", uri ); sssdConf.replace( "%SEARCHBASE%", this.searchbase ); sssdConf.replace( "%CACERT%", cacertPath ); String fileName = "/opt/ldadp/configs/" + this.moduleid + ".cfg"; try { Files.deleteIfExists( Paths.get( this.filename ) ); } catch ( IOException e1 ) { } try { FileUtils.writeStringToFile( new File( fileName ), ldadpConf, StandardCharsets.UTF_8 ); if ( 0 != Exec.sync( 10, "/usr/bin/sudo", "-n", "-u", "root", Constants.BASEDIR + "/scripts/ldadp-setperms", Integer.toString( this.moduleid ) ) ) status.error = "Warning: Could not chown/chmod ldadp config!"; } catch ( IOException e ) { status.error = e.toString(); return false; } try { outArchive = Archive.createTarArchive( this.filename ); } catch ( IOException e ) { status.error = "Could not create archive at " + this.filename; return false; } // The cert we just created if ( !Archive.tarAddFile( outArchive, cacertPath, certFile, 0644 ) ) { status.error = "Could not add ldap-proxy.pem to module"; return false; } // nsswitch.conf with ldap enabled if ( !Archive.tarAddFile( outArchive, "/etc/nsswitch.conf", new File( "./data/ad/nsswitch.conf" ), 0644 ) ) { status.error = "Could not add nsswitch.conf to module"; return false; } // All the pam.d common-XXXX files for ( String file : new String[] { "common-auth", "common-account", "common-session", "common-session-noninteractive", "common-password" } ) { if ( !Archive.tarAddFile( outArchive, "/etc/pam.d/" + file, new File( "./data/ad/" + file ), 0644 ) ) { status.error = "Could not add " + file + " to module"; return false; } } // Home if present if ( !Archive.tarAddFile( outArchive, "/opt/openslx/scripts/pam_script_mount_persistent", new File( "./data/ad/mountscript" ), 0644 ) ) { status.error = "Could not add mount script to module"; return false; } boolean ret = Archive.tarCreateFileFromString( outArchive, "/etc/ldap.conf", ldapConf.toString(), 0644 ) && Archive.tarCreateFileFromString( outArchive, "/etc/sssd/sssd.conf", sssdConf.toString(), 0600 ) && Archive.tarCreateSymlink( outArchive, "/etc/ldap.conf", "/etc/ldap/ldap.conf" ) && Archive.tarCreateSymlink( outArchive, "/etc/ldap.conf", "/etc/openldap/ldap.conf" ) && Archive.tarCreateSymlink( outArchive, "../sssd.service", "/etc/systemd/system/basic.target.wants/sssd.service" ); if ( !ret ) { status.error = "Could not add ldap configs to module"; } return ret; } catch ( IOException e ) { status.error = e.toString(); return false; } finally { Util.multiClose( outArchive ); } } /** * Output - contains additional status data of this task */ @SuppressWarnings( "unused" ) private static class Output { protected String error = null; } }