public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogDebug("Starting"); _logger.LogDebug("Ensuring '{home}' directory exists and has correct permissions", HomeBasePath); Directory.CreateDirectory(HomeBasePath); await ProcessUtil.QuickRun("chown", $"root:root \"{HomeBasePath}\""); _logger.LogDebug("Ensuring group '{group}' exists", SftpUserInventoryGroup); if (!await GroupUtil.GroupExists(SftpUserInventoryGroup)) { _logger.LogInformation("Creating group '{group}'", SftpUserInventoryGroup); await GroupUtil.GroupCreate(SftpUserInventoryGroup, true); } await SyncUsersAndGroups(); _logger.LogInformation("Started"); }
private async Task SyncUsersAndGroups() { var config = await _mediator.Send(new SftpConfigurationRequest()); _logger.LogInformation("Synchronizing users and groups"); //Remove users that do not exist in config anymore var existingUsers = await GroupUtil.GroupListUsers(SftpUserInventoryGroup); var toRemove = existingUsers.Where(s => !config.Users.Select(t => t.Username).Contains(s)).ToList(); foreach (var user in toRemove) { _logger.LogDebug("Removing user '{user}'", user, SftpUserInventoryGroup); await UserUtil.UserDelete(user, false); } foreach (var user in config.Users) { _logger.LogInformation("Processing user '{user}'", user.Username); if (!await UserUtil.UserExists(user.Username)) { _logger.LogDebug("Creating user '{user}'", user.Username); await UserUtil.UserCreate(user.Username, true); _logger.LogDebug("Adding user '{user}' to '{group}'", user.Username, SftpUserInventoryGroup); await GroupUtil.GroupAddUser(SftpUserInventoryGroup, user.Username); } _logger.LogDebug("Updating the password for user '{user}'", user.Username); await UserUtil.UserSetPassword(user.Username, user.Password, user.PasswordIsEncrypted); if (user.UID.HasValue && await UserUtil.UserGetId(user.Username) != user.UID.Value) { _logger.LogDebug("Updating the UID for user '{user}'", user.Username); await UserUtil.UserSetId(user.Username, user.UID.Value); } if (user.GID.HasValue) { var virtualGroup = $"sftp-gid-{user.GID.Value}"; if (!await GroupUtil.GroupExists(virtualGroup)) { _logger.LogDebug("Creating group '{group}' with GID '{gid}'", virtualGroup, user.GID.Value); await GroupUtil.GroupCreate(virtualGroup, true, user.GID.Value); } _logger.LogDebug("Adding user '{user}' to '{group}'", user.Username, virtualGroup); await GroupUtil.GroupAddUser(virtualGroup, user.Username); } var homeDir = Directory.CreateDirectory(Path.Combine(HomeBasePath, user.Username)); await ProcessUtil.QuickRun("chown", $"root:root {homeDir.FullName}"); await ProcessUtil.QuickRun("chmod", $"700 {homeDir.FullName}"); var sshDir = Directory.CreateDirectory(Path.Combine(homeDir.FullName, ".ssh")); var sshKeysDir = Directory.CreateDirectory(Path.Combine(sshDir.FullName, "keys")); var sshAuthKeysPath = Path.Combine(sshDir.FullName, "authorized_keys"); if (File.Exists(sshAuthKeysPath)) { File.Delete(sshAuthKeysPath); } var authKeysBuilder = new StringBuilder(); foreach (var file in Directory.GetFiles(sshKeysDir.FullName)) { _logger.LogDebug("Adding public key '{file}' for user '{user}'", file, user.Username); authKeysBuilder.AppendLine(await File.ReadAllTextAsync(file)); } foreach (var publicKey in user.PublicKeys) { _logger.LogDebug("Adding public key from config for user '{user}'", user.Username); authKeysBuilder.AppendLine(publicKey); } await File.WriteAllTextAsync(sshAuthKeysPath, authKeysBuilder.ToString()); await ProcessUtil.QuickRun("chown", $"{user.Username} {sshAuthKeysPath}"); await ProcessUtil.QuickRun("chmod", $"400 {sshAuthKeysPath}"); } foreach (var groupDefinition in config.Groups) { _logger.LogInformation("Processing group '{group}'", groupDefinition.Name); var groupUsers = groupDefinition.Users ?? new List <string>(); if (!await GroupUtil.GroupExists(groupDefinition.Name)) { _logger.LogDebug("Creating group '{group}' with GID '{gid}'", groupDefinition.Name, groupDefinition.GID); await GroupUtil.GroupCreate(groupDefinition.Name, true, groupDefinition.GID); } if (groupDefinition.GID.HasValue) { var currentId = await GroupUtil.GroupGetId(groupDefinition.Name); if (currentId != groupDefinition.GID.Value) { _logger.LogDebug("Updating group '{group}' with GID '{gid}'", groupDefinition.Name, groupDefinition.GID); await GroupUtil.GroupSetId(groupDefinition.Name, groupDefinition.GID.Value); } } var members = await GroupUtil.GroupListUsers(groupDefinition.Name); var toAdd = groupUsers.Where(s => !members.Contains(s)).ToList(); foreach (var user in toAdd) { if (!await UserUtil.UserExists(user)) { continue; } _logger.LogDebug("Adding user '{user}' to '{group}'", user, groupDefinition.Name); await GroupUtil.GroupAddUser(groupDefinition.Name, user); } members = await GroupUtil.GroupListUsers(groupDefinition.Name); var usersToRemove = members.Where(s => !groupUsers.Contains(s)).ToList(); foreach (var user in usersToRemove) { _logger.LogDebug("Removing user '{user}'", user, groupDefinition.Name); await GroupUtil.GroupRemoveUser(groupDefinition.Name, user); } } }