Wednesday, February 5, 2025

Curbing `~/.vimrc` Sprawl

I've been using vi-based editors since the late 80s. While an .exrc – or, as I eventually settled on vim as my vi-like editor, a .vimrc – is a generically decent way to pre-configure one's edit sessions, they have their shortcomings. As my work causes me to need to edit files of ever-broadening file-types, I find, with greater frequency, that I want to tailor my editor's behavior along swaths of file-types. In the land of monolithic .exrcs/.vimrcs, setting up customized-behaviors for multiple file-types results in the monolithic .exrcs/.vimrcs becoming stoopid-long. This makes them harder to read, harder to understand a general pain in the ass to maintain.

In general, I'm a fan of smaller config-files and using some kind of inheritance structure or other conditional-read method. Wasn't until today that I decided to see, "do current iterations of vim let me do that?" Boy was I glad I did: it turns out that the answer is, "yes it does". The key is judicious use of not only one's ~/.vimrc but of files in ~/.vim/.

After some digging around in the documentation and experimentation, I was able to solve my most pressing needs with a collection of files:

  • ~/.vimrc: the grand-daddy
  • ~/.vim/filetype.vim: To handle mapping file-extensions to vim-recognized file-type handlers
  • ~/.vim/ftplugin/bash.vim: A file-type handler for files with the .bash extension
  • ~/.vim/ftplugin/sh.vim: A file-type handler for files with the .sh extension

…I'll be adding more 

~/.vim/filetype.vim:

This file provides file-extension to file-type mappings. These mappings are used when using file-type files in the ~/.vim/ftplugin/ directory.

The contents of the ~/.vim/filetype.vim file is (currently) fairly simple and straight-foward:

"An easier-to read filetype mapper routine
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au! BufRead,BufNewFile *.bash setfiletype bash
au! BufRead,BufNewFile *.sh setfiletype sh
augroup END

As the comment-line indicates, this file makes it easy to legibly extend mapping of file-suffixes to file types. This is done by using a grouping-block to apply autocmd-type directives. Such a grouping-block allow line-by-line mapping-extensions. The above replaces content like:

autocmd BufRead,BufNewFile *.sh,*.bash,*.sls,*.json,*.yml <ACTION>

Thus, if one wants to, say, add further file-type mappings (say for YAML files), one could add a line like:

au! BufRead,BufNewFile *.yml           setfiletype yaml

Or even:

au! BufRead,BufNewFile *.yml           setfiletype yaml
au! BufRead,BufNewFile *.yaml          setfiletype yaml

The latter line-pair captures YAML files that might be suffixed .yml or .yaml. As someone who does work for multiple organizations – either concurrently or serially – I've found, much to my consternation, that selected file-suffixes may differ from organization to organization.

~/.vim/ftplugin/*.vim:

The …/ftplugin directory contains the files that contain the actual, per file-type configuration-directives. The previous …/filetype.vim file's `setfiletype` command provides the value of the `*` in the header's wildcarded .vim file-names. Thus a .bash file that was mapped to the bash file-type will cause the ~/.vim/ftplugin/bash.vim file's configuration-options to be read.

Note: while my earlier file-list appears to show two, discrete config-files:

  • ~/.vim/ftplugin/bash.vim
  • ~/.vim/ftplugin/sh.vim

They are actually just one file that's hard-linked:

$ ls -il *.vim
330115 -rw-r--r-- 2 ferric ferric 453 Feb  5 16:27 bash.vim
330115 -rw-r--r-- 2 ferric ferric 453 Feb  5 16:27 sh.vim

These files (currently) contain:

"Ensure that lines break at 80 characters
set wrap
set textwidth=80
set wrapmargin=0

"Ensure linewraps happen when textwidth is reached
set formatoptions+=t

"Enable auto-indent
set autoindent

"Set 4-char tabstops
set tabstop=4

"Convert tabs to spaces
set expandtab

"Set autoindent to 4-chars
set shiftwidth=4

"Eliminate trailing whitespace
augroup prewrites
   autocmd!
    autocmd BufWritePre,FileWritePre * :%s/\s\+$//e | %s/\r$//e
augroup END

One could create equivalent *.vim files for other filetypes. One would do this if, say, you leveraged different maximum line-widths, indent-paddings or the like on a per-language file-basis.

~/.vimrc:

With the other files in place, this allows for a svelter ~/.vimrc file. Mine now looks like:

"Disable syntax-highlighting
syntax off

"Turn off search-highlighting
set nohlsearch

"Turn off angry fruit-salad
set t_Co=0

I, uh, hate the "angry fruit-salad" appearance that many distro's default vim-configs use.

Friday, January 3, 2025

SSH Problems When Using `sysadm_u` SELinux Confinement

Decided to be proactive on the security-setup for my one project. Opted to confine my default-user to sysadm_u. However, as soon as I did that, I stopped being able to ssh into the resulting EC2 as the default-user. Turns out there's a bit more requirede in order to use that confinement with a user that also needs to be able to SSH into the host.

For those reading and who don't have a Red Hat login, if I want to confine a user to the to sysadm_u, I also need to ensure that my system-configuration automation includes:

setsebool ssh_sysadm_login on
setsebool -P ssh_sysadm_login on
Without the above, doing an ssh -v to the target user will show a spurious:
Authenticated to 0.0.0.0 ([127.0.0.1]:22) using "publickey".
debug1: pkcs11_del_provider: called, provider_id = (null)
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: filesystem full
client_loop: send disconnect: Broken pipe

The `pledge: filesystem full` kinda threw me, at first, since I knew that neither my local nor my remote filesystem was full. So, I assumed that it was just a misleading error message (as seems to so often be the case when SELinux is involved). So, I searched for ssh login problems associated with the selected SELinux-confinement, which led me to the previously-linked Red Hat article.

I guess that's why the hardening guidelines show `staff_u` as the recommended confinement for administrator users?

 Ultimately, I opted to use  `staff_u`, instead. Having a cloud-config block like:

user: {
  gecos: "GitLab Provisioning-Account (LOCAL)",
  name: "${PROVISIONING_USER}",
  selinux_user: 'staff_u',
  sudo: ['ALL=(root) TYPE=sysadm_t ROLE=sysadm_r NOPASSWD:ALL']
}
Ensuring to have ROLE and TYPE SELinux transition-mappings defined for my default-user eliminates the confusion that can result when confining a user to staff_u and not supplying a mapping. Without the mapping, if an confined admin-user executes `sudo -i`, they get all sorts of unexpected `permission denied` errors.