All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aoindustries.aoserv.client.linux.UserServerTable Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ Platform.
 * Copyright (C) 2001-2013, 2015, 2016, 2017, 2018, 2019, 2020  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client.linux;

import com.aoindustries.aoserv.client.AOServConnector;
import com.aoindustries.aoserv.client.CachedTableIntegerKey;
import com.aoindustries.aoserv.client.account.DisableLog;
import com.aoindustries.aoserv.client.aosh.AOSH;
import com.aoindustries.aoserv.client.aosh.Command;
import com.aoindustries.aoserv.client.email.Address;
import com.aoindustries.aoserv.client.email.Domain;
import com.aoindustries.aoserv.client.email.InboxAttributes;
import com.aoindustries.aoserv.client.schema.AoservProtocol;
import com.aoindustries.aoserv.client.schema.Table;
import com.aoindustries.io.TerminalWriter;
import com.aoindustries.net.DomainName;
import com.aoindustries.sql.SQLUtility;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.security.auth.login.AccountLockedException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

/**
 * @see  UserServer
 *
 * @author  AO Industries, Inc.
 */
final public class UserServerTable extends CachedTableIntegerKey {

	UserServerTable(AOServConnector connector) {
		super(connector, UserServer.class);
	}

	private static final OrderBy[] defaultOrderBy = {
		new OrderBy(UserServer.COLUMN_USERNAME_name, ASCENDING),
		new OrderBy(UserServer.COLUMN_AO_SERVER_name+'.'+Server.COLUMN_HOSTNAME_name, ASCENDING)
	};
	@Override
	protected OrderBy[] getDefaultOrderBy() {
		return defaultOrderBy;
	}

	int addLinuxServerAccount(User linuxAccount, Server aoServer, PosixPath home) throws IOException, SQLException {
		int pkey=connector.requestIntQueryIL(
			true,
			AoservProtocol.CommandID.ADD,
			Table.TableID.LINUX_SERVER_ACCOUNTS,
			linuxAccount.getUsername_id(),
			aoServer.getPkey(),
			home
		);
		return pkey;
	}

	int addSystemUser(
		Server aoServer,
		User.Name username,
		int uid,
		int gid,
		User.Gecos fullName,
		User.Gecos officeLocation,
		User.Gecos officePhone,
		User.Gecos homePhone,
		PosixPath home,
		PosixPath shell
	) throws IOException, SQLException {
		return connector.requestIntQueryIL(
			true,
			AoservProtocol.CommandID.ADD_SYSTEM_USER,
			aoServer.getPkey(),
			username,
			uid,
			gid,
			fullName==null ? "" : fullName.toString(),
			officeLocation==null ? "" : officeLocation.toString(),
			officePhone==null ? "" : officePhone.toString(),
			homePhone==null ? "" : homePhone.toString(),
			home,
			shell
		);
	}

	@Override
	public void clearCache() {
		super.clearCache();
		synchronized(uidHash) {
			uidHashBuilt=false;
		}
		synchronized(nameHash) {
			nameHashBuilt=false;
		}
	}

	@Override
	public UserServer get(int pkey) throws IOException, SQLException {
		return getUniqueRow(UserServer.COLUMN_PKEY, pkey);
	}

	List getAlternateLinuxServerAccounts(GroupServer group) throws SQLException, IOException {
		Server aoServer = group.getServer();
		int osv = aoServer.getHost().getOperatingSystemVersion_id();
		Group.Name groupName = group.getLinuxGroup().getName();

		List rows = getRows();
		int cachedLen = rows.size();
		List matches=new ArrayList<>(cachedLen);
		for(int c = 0; c < cachedLen; c++) {
			UserServer linuxServerAccount = rows.get(c);
			if(linuxServerAccount.ao_server == aoServer.getPkey()) {
				User.Name username = linuxServerAccount.username;

				// Must also have a non-primary entry in the LinuxGroupAccounts that is also a group on this server
				for(GroupUser lga : connector.getLinux().getGroupUser().getLinuxGroupAccounts(groupName, username)) {
					if(
						!lga.isPrimary()
						&& (
							lga.getOperatingSystemVersion_pkey() == null
							|| lga.getOperatingSystemVersion_pkey() == osv
						)
					) {
						matches.add(linuxServerAccount);
						break;
					}
				}
			}
		}
		return matches;
	}

	private boolean nameHashBuilt=false;
	private final Map> nameHash=new HashMap<>();

	UserServer getLinuxServerAccount(Server aoServer, User.Name username) throws IOException, SQLException {
		synchronized(nameHash) {
			if(!nameHashBuilt) {
				nameHash.clear();

				List list=getRows();
				int len=list.size();
				for(int c=0; c serverHash=nameHash.get(I);
					if(serverHash==null) nameHash.put(I, serverHash=new HashMap<>());
					if(serverHash.put(lsa.username, lsa)!=null) throw new SQLException("LinuxServerAccount username exists more than once on server: "+lsa.username+" on "+I);
				}
				nameHashBuilt=true;
			}
			Map serverHash=nameHash.get(aoServer.getPkey());
			if(serverHash==null) return null;
			return serverHash.get(username);
		}
	}

	/**
	 * Finds a LinuxServerAccount by a username and password combination.  It tries to return an account that is not disabled and
	 * matches both username and password.
	 *
	 * @return   the LinuxServerAccount found if a non-disabled username and password are found, or {@code null} if no match found
	 *
	 * @exception  LoginException  if a possible account match is found but the account is disabled or has a different password
	 */
	public UserServer getLinuxServerAccountFromUsernamePassword(User.Name username, String password, boolean emailOnly) throws LoginException, IOException, SQLException {
		List list = getRows();
		UserServer badPasswordLSA=null;
		UserServer disabledLSA=null;
		int len = list.size();
		for (int c = 0; c < len; c++) {
			UserServer account=list.get(c);
			if(
				account.username.equals(username)
				&& (!emailOnly || account.getLinuxAccount().getType().isEmail())
			) {
				if(account.disable_log!=-1) {
					if(disabledLSA==null) disabledLSA=account;
				} else {
					if(account.passwordMatches(password)) return account;
					else {
						if(badPasswordLSA==null) badPasswordLSA=account;
					}
				}
			}
		}
		if(badPasswordLSA!=null) throw new FailedLoginException("The password does not match the password for the \""+badPasswordLSA.getLinuxAccount().getUsername().getUsername()+"\" account on the \""+badPasswordLSA.getServer().getHostname()+"\" server.");
		if(disabledLSA!=null) {
			DisableLog dl=disabledLSA.getDisableLog();
			String reason=dl==null?null:dl.getDisableReason();
			if(reason==null) throw new AccountLockedException("The \""+disabledLSA.getLinuxAccount().getUsername().getUsername()+"\" account on the \""+disabledLSA.getServer().getHostname()+"\" server has been disabled for an unspecified reason.");
			else throw new AccountLockedException("The \""+disabledLSA.getLinuxAccount().getUsername().getUsername()+"\" account on the \""+disabledLSA.getServer().getHostname()+"\" server has been disabled for the following reason: "+reason);
		}
		return null;
	}

	/**
	 * Finds a LinuxServerAccount by an email address and password combination.  It tries to return an account that is not disabled and
	 * matches both email address and password.
	 *
	 * @return   the LinuxServerAccount found if a non-disabled email address and password are found, or {@code null} if no match found
	 *
	 * @exception  LoginException  if a possible account match is found but the account is disabled or has a different password
	 */
	public UserServer getLinuxServerAccountFromEmailAddress(String address, DomainName domain, String password) throws LoginException, IOException, SQLException {
		UserServer badPasswordLSA=null;
		UserServer disabledLSA=null;

		List domains=connector.getEmail().getDomain().getRows();
		int domainsLen=domains.size();
		for(int c=0;c lsas=ea.getLinuxServerAccounts();
					int lsasLen=lsas.size();
					for(int d=0;d> uidHash=new HashMap<>();

	UserServer getLinuxServerAccount(Server aoServer, LinuxId uid) throws IOException, SQLException {
		synchronized(uidHash) {
			if(!uidHashBuilt) {
				uidHash.clear();

				List list = getRows();
				int len = list.size();
				for (int c = 0; c < len; c++) {
					UserServer lsa=list.get(c);
					LinuxId lsaUID = lsa.getUid();
					// Only hash the root user for uid of 0
					if(lsaUID.getId() != UserServer.ROOT_UID || lsa.username.equals(User.ROOT)) {
						Integer aoI=lsa.getServer().getPkey();
						Map serverHash=uidHash.get(aoI);
						if(serverHash==null) uidHash.put(aoI, serverHash=new HashMap<>());
						LinuxId I=lsaUID;
						if(!serverHash.containsKey(I)) serverHash.put(I, lsa);
					}
				}
				uidHashBuilt=true;
			}
			Map serverHash=uidHash.get(aoServer.getPkey());
			if(serverHash==null) return null;
			return serverHash.get(uid);
		}
	}

	List getLinuxServerAccounts(User linuxAccount) throws IOException, SQLException {
		return getIndexedRows(UserServer.COLUMN_USERNAME, linuxAccount.getUsername_id());
	}

	List getLinuxServerAccounts(Server aoServer) throws IOException, SQLException {
		return getIndexedRows(UserServer.COLUMN_AO_SERVER, aoServer.getPkey());
	}

	public List getMailAccounts() throws IOException, SQLException {
		List cached = getRows();
		int len = cached.size();
		List matches=new ArrayList<>(len);
		for (int c = 0; c < len; c++) {
			UserServer lsa=cached.get(c);
			if(lsa.getLinuxAccount().getType().isEmail()) matches.add(lsa);
		}
		return matches;
	}

	@Override
	public Table.TableID getTableID() {
		return Table.TableID.LINUX_SERVER_ACCOUNTS;
	}

	@Override
	@SuppressWarnings("deprecation")
	public boolean handleCommand(String[] args, Reader in, TerminalWriter out, TerminalWriter err, boolean isInteractive) throws IllegalArgumentException, IOException, SQLException {
		String command=args[0];
		if(command.equalsIgnoreCase(Command.ADD_LINUX_SERVER_ACCOUNT)) {
			if(AOSH.checkParamCount(Command.ADD_LINUX_SERVER_ACCOUNT, args, 3, err)) {
				out.println(
					connector.getSimpleAOClient().addLinuxServerAccount(
						AOSH.parseLinuxUserName(args[1], "username"),
						args[2],
						args[3].isEmpty() ? null : AOSH.parseUnixPath(args[3], "home_directory")
					)
				);
				out.flush();
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.COMPARE_LINUX_SERVER_ACCOUNT_PASSWORD)) {
			if(AOSH.checkParamCount(Command.COMPARE_LINUX_SERVER_ACCOUNT_PASSWORD, args, 3, err)) {
				boolean result=connector.getSimpleAOClient().compareLinuxServerAccountPassword(
					AOSH.parseLinuxUserName(args[1], "username"),
					args[2],
					args[3]
				);
				out.println(result);
				out.flush();
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.COPY_HOME_DIRECTORY)) {
			if(AOSH.checkParamCount(Command.COPY_HOME_DIRECTORY, args, 3, err)) {
				long byteCount=connector.getSimpleAOClient().copyHomeDirectory(
					AOSH.parseLinuxUserName(args[1], "username"),
					args[2],
					args[3]
				);
				if(isInteractive) {
					out.print(byteCount);
					out.println(byteCount==1?" byte":" bytes");
				} else out.println(byteCount);
				out.flush();
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.COPY_LINUX_SERVER_ACCOUNT_PASSWORD)) {
			if(AOSH.checkParamCount(Command.COPY_LINUX_SERVER_ACCOUNT_PASSWORD, args, 4, err)) {
				connector.getSimpleAOClient().copyLinuxServerAccountPassword(
					AOSH.parseLinuxUserName(args[1], "from_username"),
					args[2],
					AOSH.parseLinuxUserName(args[3], "to_username"),
					args[4]
				);
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.DISABLE_LINUX_SERVER_ACCOUNT)) {
			if(AOSH.checkParamCount(Command.DISABLE_LINUX_SERVER_ACCOUNT, args, 3, err)) {
				out.println(
					connector.getSimpleAOClient().disableLinuxServerAccount(
						AOSH.parseLinuxUserName(args[1], "username"),
						args[2],
						args[3]
					)
				);
				out.flush();
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.ENABLE_LINUX_SERVER_ACCOUNT)) {
			if(AOSH.checkParamCount(Command.ENABLE_LINUX_SERVER_ACCOUNT, args, 2, err)) {
				connector.getSimpleAOClient().enableLinuxServerAccount(
					AOSH.parseLinuxUserName(args[1], "username"),
					args[2]
				);
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.GET_CRON_TABLE)) {
			if(AOSH.checkParamCount(Command.GET_CRON_TABLE, args, 2, err)) {
				out.print(
					connector.getSimpleAOClient().getCronTable(
						AOSH.parseLinuxUserName(args[1], "username"),
						args[2]
					)
				);
				out.flush();
			}
			return true;
		} else if(command.equalsIgnoreCase(Command.GET_IMAP_FOLDER_SIZES)) {
			if(AOSH.checkMinParamCount(Command.GET_IMAP_FOLDER_SIZES, args, 3, err)) {
				String[] folderNames=new String[args.length-3];
				System.arraycopy(args, 3, folderNames, 0, folderNames.length);
				long[] sizes=connector.getSimpleAOClient().getImapFolderSizes(
					AOSH.parseLinuxUserName(args[1], "username"),
					args[2],
					folderNames
				);
				for(int c=0;c cached=getRows();
		int size=cached.size();
		for(int c=0;c




© 2015 - 2025 Weber Informatics LLC | Privacy Policy