From 118b0019658890837ab8e19608ce0779cb6f4d9a Mon Sep 17 00:00:00 2001 From: Dante Catalfamo Date: Tue, 7 Jul 2020 22:28:28 -0400 Subject: Move WIP posts to WIP folders --- .../WIP-how-bsd-authentication-works/graph.dot | 67 +++ .../WIP-how-bsd-authentication-works/index.org | 473 +++++++++++++++++++++ content/posts/WIP-how-this-blog-works.org | 239 +++++++++++ .../WIP-installing-openbsd-on-pcengines/index.org | 87 ++++ .../posts/how-bsd-authentication-works/graph.dot | 67 --- .../posts/how-bsd-authentication-works/index.org | 473 --------------------- content/posts/how-this-blog-works.org | 239 ----------- content/posts/openbsd-dhcp-server/index.org | 8 - 8 files changed, 866 insertions(+), 787 deletions(-) create mode 100644 content/posts/WIP-how-bsd-authentication-works/graph.dot create mode 100644 content/posts/WIP-how-bsd-authentication-works/index.org create mode 100644 content/posts/WIP-how-this-blog-works.org create mode 100644 content/posts/WIP-installing-openbsd-on-pcengines/index.org delete mode 100644 content/posts/how-bsd-authentication-works/graph.dot delete mode 100644 content/posts/how-bsd-authentication-works/index.org delete mode 100644 content/posts/how-this-blog-works.org delete mode 100644 content/posts/openbsd-dhcp-server/index.org (limited to 'content/posts') diff --git a/content/posts/WIP-how-bsd-authentication-works/graph.dot b/content/posts/WIP-how-bsd-authentication-works/graph.dot new file mode 100644 index 0000000..6414b11 --- /dev/null +++ b/content/posts/WIP-how-bsd-authentication-works/graph.dot @@ -0,0 +1,67 @@ +digraph G { + subgraph cluster_authenticate { + label = "authenticate.c" + auth_userokay; + auth_usercheck; + auth_verify; + } + + subgraph cluster_auth_subr { + label = "auth_subr.c" + auth_open; + auth_call; + auth_close; + // auth_setitem; + // auth_setdata; + // auth_setopts; + auth_set[label="auth_set*"]; + auth_setstate; + // _auth_spool; + } + + subgraph cluster_login_cap { + label = "libc/login_cap.c" + login_getclass + login_getstyle + } + + subgraph cluster_getpwent { + label = "libc/getpwent.c" + getpwnam_r; + } + + subgraph cluster_exec { + login[label="login_*"]; + execve; + } + + + start -> auth_userokay; + auth_userokay -> auth_usercheck; + auth_usercheck -> getpwnam_r; + auth_usercheck -> login_getclass; + auth_usercheck -> login_getstyle; + // if password given + auth_usercheck -> auth_open; + // auth_usercheck -> auth_setitem; + // auth_usercheck -> auth_setdata; + auth_usercheck -> auth_set; + // fi + auth_usercheck -> auth_verify; + + auth_verify -> auth_setstate; + auth_verify -> auth_call; + + auth_call -> execve[label="fork()"]; + // auth_call -> _auth_spool; + + execve -> login; + login -> auth_call[label="back channel"]; + // login -> _auth_spool[label="back channel"]; + + + // auth_usercheck -> { auth_setitem auth_setdata auth_setopts } + + // auth_call -> auth_userokay; + auth_userokay -> auth_close; +} diff --git a/content/posts/WIP-how-bsd-authentication-works/index.org b/content/posts/WIP-how-bsd-authentication-works/index.org new file mode 100644 index 0000000..4126284 --- /dev/null +++ b/content/posts/WIP-how-bsd-authentication-works/index.org @@ -0,0 +1,473 @@ +#+TITLE: How BSD Authentication Works +#+DATE: 2020-06-26T18:31:36-04:00 +#+DRAFT: true +#+DESCRIPTION: +#+TAGS[]: openbsd +#+KEYWORDS[]: openbsd +#+SLUG: +#+SUMMARY: +#+SHOWTOC: true + +[[https://web.archive.org/web/20170327150148/http://www.penzin.net/bsdauth/]] +* History + + OpenBSD is quite different from many other Unix-like operating systems + in many ways, but one way which I find interesting is the + authentication system. Most systems from AIX, Solaris, and Linux to + most BSDs including MacOS use some form of a system called Pluggable + Authentication Module (PAM). The two main implementations of PAM are + [[http://www.linux-pam.org/][Linux PAM]] and [[https://www.openpam.org/][OpenPAM]]. PAM modules are created a dynamically loaded + shared objects, which communicate using a set of standard + interfaces ([[https://linux.die.net/man/3/pam][Linux-PAM]] and [[https://www.freebsd.org/cgi/man.cgi?query=pam&apropos=0&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports&arch=default&format=html][OpenPAM]]). PAM is configured using the [[https://linux.die.net/man/5/pam.d][pam.d]] + directory and [[https://www.freebsd.org/cgi/man.cgi?query=pam.conf&sektion=5&apropos=0&manpath=FreeBSD+12.1-RELEASE+and+Ports][pam.conf]]. + + OpenBSD on the other hand uses a mechanism called BSD + Authentication. It was originally developed for a proprietary + operating system called [[https://en.wikipedia.org/wiki/BSD/OS][BSD/OS]] by [[https://en.wikipedia.org/wiki/Berkeley_Software_Design][Berkeley Software Design Inc.]], who + later donated the system. It was adopted by OpenBSD in release + 2.9. BSD Auth is comparatively much simpler than PAM. Modules or, + authentication "styles", are instead stand alone applications or + scripts that communicate over IPC (=PF_LOCAL, SOCK_STREAM=, + specifically). The program or script has no ability to interfere + with the parent and can very easily revoke permissions using + [[https://man.openbsd.org/pledge][=pledge(2)=]] or [[https://man.openbsd.org/unveil][=unveil(2)=]]. The BSD Authentication system of + configured through [[https://man.openbsd.org/login.conf][=login.conf(5)=]]. + +* Why + + This one is pretty difficult, since there seems to be very little + information about how BSD Auth works apart from the source code + itself. This is my best attempt to understand the flow of BSD Auth + from what I've read. + +* BSD Auth Modules + + These programs or scripts are located in =/usr/libexec/auth/= with the + naming convention =login_<style>=. They take arguments in the form of + + #+BEGIN_SRC shell + login_<style> [-s service] [-v key=value] user [class] + #+END_SRC + + - =<style>= is the authentication method. This could be =passwd=, + =radius=, =skey=, =yubikey=, etc. There's more information about + available styles in [[https://man.openbsd.org/login.conf][=login.conf(5)=]] under the [[https://man.openbsd.org/login.conf#AUTHENTICATION][=AUTHENTICATION=]] + header. + - =service= is the service type. Typically authentication methods will + accept one of three values here, =login=, =challenge=, or + =response=. =login= is the default if it's not specified, and is + usually the right choice. Read the style's man page for details. + - =-v key=value= is an optional argument. There is no limit to the + number of =-v= arguments. This is used to pass extra data to the + program under certain circumstances. + - =user= is the name of the user to be authenticated. + - =class= is optional and specifies the class of the user to be + authenticated. + + =login= and =su= pass in extra data as =-v= flags. + + #+CAPTION: Taken from [[https://man.openbsd.org/login.conf][=login.conf(5)=]] + #+BEGIN_SRC + The login(1) program provides the following through the -v option: + + auth_type The type of authentication to use. + + fqdn The hostname provided to login by the -h option. + + hostname The name login(1) will place in the utmp file for the + remote hostname. + + local_addr The local IP address given to login(1) by the -L option. + + lastchance Set to "yes" when a user's password has expired but the + user is being given one last chance to login and update + the password. + + login This is a new login session (as opposed to a simple + identity check). + + remote_addr The remote IP address given to login(1) by the -R option. + + style The style of authentication used for this user (see + approval scripts below). + + The su(1) program provides the following through the -v option: + + wheel Set to either "yes" or "no" to indicate if the user is in + group wheel when they are trying to become root. Some + authentication types require the user to be in group + wheel when using the su(1) program to become super user. + #+END_SRC + + The auth module communicates with its caller through file descriptor 3. + +* Documentation + + All of the high level authentication functions are described in + [[https://man.openbsd.org/authenticate][=authenticate(3)=]], with the lower level functions being described in + [[https://man.openbsd.org/auth_subr][=auth_subr(3)=]]. + +* auth_userokay + + The highest level function, and easiest to use is =auth_userokay=. It + takes four character arrays as arguments, =name=, =style=, =type=, and + =password=. It returns either a =0= for failure, of a non-zero value + for success. + + This function lives inside =/lib/libc/gen/authenticate.c= + + #+BEGIN_SRC c + int auth_userokay(char *name, char *style, char *type, char *password); + #+END_SRC + + - =name= is the name of the user to be authenticated + - =style= is the login method to be used + - If =style= is =NULL=, the user's default login style will be + used. By default this is =passwd= on normal accounts. + - The style can be one of the installed authentication methods, like + =passwd=, =radius=, =skey=, =yubikey=, etc. + - There's more information about available styles in =login.conf(5)= + - Styles can also be installed through BSD Auth module packages + - =type= is the authentication type + - Types are defined in =login.conf= and define a group of allowed + auth styles + - If =type= is =NULL=, use the auth type for the user's login + class. The default type is =auth-default=, which allows + =psaswd= and =skey= auth methods. + - There's more information about how to add methods in =login.conf(5)= + - =password= is the password to test + - If =password= is =NULL=, then the user is interactively + prompted. This is required for auth styles using + challenge-response methods. + - If =password= is specified, then it's non-interactively tested + + =auth_userokay= is just a wrapper around =auth_usercheck=, which + returns a finished auth session of type =auth_session_t=. It closes + the auth session using =auth_close= and returns the value returned + from closing. + +* auth_session_t + + #+BEGIN_SRC c + struct auth_session_t { + char *name; /* name of use being authenticated */ + char *style; /* style of authentication used */ + char *class; /* class of user */ + char *service; /* type of service being performed */ + char *challenge; /* last challenge issued */ + int flags; /* see below */ + struct passwd *pwd; /* password entry for user */ + struct timeval now; /* time of authentication */ + + int state; /* authenticated state */ + + struct rmfiles *rmlist; /* list of files to remove on failure */ + struct authopts *optlist; /* list of options to scripts */ + struct authdata *data; /* additional data to send to scripts */ + + char spool[MAXSPOOLSIZE]; /* data returned from login script */ + int index; /* how much returned thus far */ + + int fd; /* connection to authenticator */ + + va_list ap0; /* argument list to auth_call */ + va_list ap; /* additional arguments to auth_call */ + }; + #+END_SRC + + Where =authdata=, =authopts=, and =rmfiles= are defined as + + #+BEGIN_SRC c + struct rmfiles { + struct rmfiles *next; + char *file; + }; + + struct authopts { + struct authopts *next; + char *opt; + }; + + struct authdata { + struct authdata *next; + void *ptr; + size_t len; + }; + #+END_SRC + +** auth_setdata + +** auth_setitem + +** auth_setoption + +** auth_setstate +* auth_open + + The =auth_open= function is used by several functions to create a + new auth session. It allocates an =auth_session_t= struct on the + heap, sets its default =service= to =login=, and it's =fd= to =-1=, + and returns the pointer. + +* auth_usercheck + + #+BEGIN_SRC c + auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password) + #+END_SRC + + =auth_usercheck= checks the user name against the passwd db. It also + checks the login class against the =login.conf= db, along with + confirming the login styles available. + + If the password is non-=NULL=, then it creates a new session using + =auth_open=. With the new session, =auth_usercheck= calls (with =as= + as the session struct) + + #+BEGIN_SRC c + auth_setitem(as, AUTHV_SERVICE, "response"); + auth_setdata(as, "", 1); + auth_setdata(as, password, strlen(password) + 1); + #+END_SRC + + setting the service protocol to =response=, adding an empty line to + the session data, then adding the password as data. If the password is + =NULL=, it sets the =auth_session_t= pointer to =NULL=. It then passes + the user name, style, login class, and =NULL= char pointer to + =auth_verify=. The last two variables are received as variable + arguments. It then returns the auth session pointer the call + returns. + +* auth_verify + + #+BEGIN_SRC c + auth_session_t *auth_verify(auth_session_t *as, char *style, char *name, ...) + #+END_SRC + + =auth_verify= creates an auth session using =auth_open= if =as= is + =NULL=. It then sets the user name and style of the session, if the + respective arguments are non-=NULL=. It then copies its variable + arguments to the auth session's =va_list ap=, which is used inside + of =auth_call=. + + After that it constructs the path of the authentication module by + combining =_PATH_AUTHPROG=, which is defined in =login_cap.h= as + =/usr/libexec/auth/login_=, and the authentication style. For the + case of auth style =passwd=, it would result in the path + =/usr/libexec/auth/login_passwd=. + + Then =auth_call= is called with the struct, the path to the auth + module, the auth style, the "-s" flag followed by the service (login, + challenge, response), a double dash, the user name, and a =NULL= + character pointer. The return value of =auth_call= is ignored and a + pointer to the auth session is returned immediately afterwards. + + #+BEGIN_SRC c + auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s", + auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL); + #+END_SRC + +* auth_call + + #+BEGIN_SRC c + int auth_call(auth_session_t *as, char *path, ...) + #+END_SRC + + <<here>> + + --- + note: In the man page auth_subr it says + #+begin_quote + path The full path name of the login script to run. The call will + fail if path does not pass the requirements of the secure_path(3) + function. + #+end_quote + However I don't see this enforced anywhere, I even wrote a small test + script to prove that's the case on =vfwall ~/authtest=. + + The manpage also says the path is limited to =/bin/= and =/usr/bin=, + which is also not the case. + + Ask jcs about the file descriptor situation, I don't understand it + after reading both the man page and source. + --- + + Inside of =auth_call=, a socket pair of type =PF_LOCAL, SOCK_STREAM= + is created. This is called the "back channel", and is used to + communicate with the authentication module. The process then forks, + calling ~execve(path, argv, auth_environ)~, where the =argv= is + everything after =path= in the =auth_call= arguments. Any =authopts= + set in the auth session are also passed as arguments in the format =-v + opt1 -v opt2 -v opt3=, etc. =auth_environ= is defined at the top of + the file as + + #+BEGIN_SRC c + static char *auth_environ[] = { + "PATH=" _PATH_DEFPATH, + "SHELL=" _PATH_BSHELL, + NULL, + }; + #+END_SRC + + Where both constants are defined in =paths.h= as + + #+BEGIN_SRC c + #define _PATH_DEFPATH "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin" + #define _PATH_BSHELL "/bin/sh" + #+END_SRC + + + The =exec='d process then listens on FD 3, which is one half of the + =sockpair= that was created earlier. + + In the non-exec'd process, first the contents of the auth session's + =*data= are read in one at a time. + + The data received through the back channel is then put into the + =spool= of the auth session using =_auth_spool(as, pfd[0])=. After + that the spooled data is scanned for key words defined in + =login_cap.h=. + + #+BEGIN_SRC c + #define BI_AUTH "authorize" /* Accepted authentication */ + #define BI_REJECT "reject" /* Rejected authentication */ + #define BI_CHALLENGE "reject challenge" /* Reject with a challenge */ + #define BI_SILENT "reject silent" /* Reject silently */ + #define BI_REMOVE "remove" /* remove file on error */ + #define BI_ROOTOKAY "authorize root" /* root authenticated */ + #define BI_SECURE "authorize secure" /* okay on non-secure line */ + #define BI_SETENV "setenv" /* set environment variable */ + #define BI_UNSETENV "unsetenv" /* unset environment variable */ + #define BI_VALUE "value" /* set local variable */ + #define BI_EXPIRED "reject expired" /* account expired */ + #define BI_PWEXPIRED "reject pwexpired" /* password expired */ + #define BI_FDPASS "fd" /* child is passing an fd */ + #+END_SRC + + The [[https://man.openbsd.org/login.conf][=login.conf(5)=]] man page once again goes into greater detail on + these values. + + #+BEGIN_SRC + authorize The user has been authorized. + + authorize secure + The user has been authorized and root should be allowed to + login even if this is not a secure terminal. This should only + be sent by authentication styles that are secure over insecure + lines. + + reject Authorization is rejected. This overrides any indication that + the user was authorized (though one would question the wisdom + in sending both a reject and an authorize command). + + reject challenge + Authorization was rejected and a challenge has been made + available via the value challenge. + + reject silent + Authorization is rejected, but no error messages should be + generated. + + remove file + If the login session fails for any reason, remove file before + termination. + + setenv name value + If the login session succeeds, the environment variable name + should be set to the specified value. + + unsetenv name + If the login session succeeds, the environment variable name + should be removed. + + value name value + Set the internal variable name to the specified value. The + value should only contain printable characters. Several \ + sequences may be used to introduce non printing characters. + These are: + + \n A newline. + + \r A carriage return. + + \t A tab. + + \xxx The character represented by the octal value xxx. The + value may be one, two, or three octal digits. + + \c The string is replaced by the value of c. This allows + quoting an initial space or the \ character itself. + + + The following values are currently defined: + + challenge + See section on challenges below. + + errormsg + If set, the value is the reason authentication failed. + The calling program may choose to display this when + rejecting the user, but display is not required. + + #+END_SRC + + + It is looking for lines that start with either =BI_AUTH= + (=authorize=), or =BI_REJECT= (=reject=). If the line is still longer, + it continues to scan for any other qualifiers such as =pwexpired= or + =silent=. The struct's =state= is set to one using the =AUTH_= values + from =login_cap.h= accordingly. + + #+BEGIN_SRC c + /* + * bits which can be returned by authenticate()/auth_scan() + */ + #define AUTH_OKAY 0x01 /* user authenticated */ + #define AUTH_ROOTOKAY 0x02 /* authenticated as root */ + #define AUTH_SECURE 0x04 /* secure login */ + #define AUTH_SILENT 0x08 /* silent rejection */ + #define AUTH_CHALLENGE 0x10 /* a challenge was given */ + #define AUTH_EXPIRED 0x20 /* account expired */ + #define AUTH_PWEXPIRED 0x40 /* password expired */ + #+END_SRC + +** _auth_spool + +** _recv_fd + +* auth_close + =auth_close= is the function responsible for cleaning up the session + and taking care of the values returned though the back channel. + + It first sets the environment variables returned through the back + channel by passing the auth session to =auth_setenv=. It then goes + through the =rmlist= of the session, deleting the files if the + session reported a failure. It then zeroes out all sensitive + information, and frees the various structs associated with the current + =auth_session_t=, and then the session itself. Finally it returns + the session's state =&='ed with =AUTH_ALLOW=. +* grapgh? +# Setting env on auth_close(as) +# partual rewrite below + +The call graph for =auth_userokay= looks something like this: + +#+BEGIN_SRC c +int auth_userokay(char *name, char *style, char *type, char *password) +#+END_SRC + +calls ~auth_usercheck~ and then calls ~auth_close~ on the returned +~auth_session_t~. The value returned from ~auth_close~ is then +returned. + +#+BEGIN_SRC c +auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password) +#+END_SRC + +Validates the checks that the user exists, gets the user's login +class, verifies the auth type, and that the auth style can be used. + +It creates an auth session struct. + +If the password is provided it sets the service type to =response=, +and adds the adds the password to the auth data. Otherwise it +leaves it empty. diff --git a/content/posts/WIP-how-this-blog-works.org b/content/posts/WIP-how-this-blog-works.org new file mode 100644 index 0000000..80fa1ca --- /dev/null +++ b/content/posts/WIP-how-this-blog-works.org @@ -0,0 +1,239 @@ +#+TITLE: Creating Self-Hosted Hugo Blog on OpenBSD +#+DATE: 2020-06-17T21:03:26-04:00 +#+DRAFT: true +#+DESCRIPTION: +#+TAGS[]: hugo openbsd +#+KEYWORDS[]: +#+SLUG: +#+SUMMARY: +#+SHOWTOC: true + +When creating this blog, there were a couple of factors I kept in mind +while trying to figure out how I was going to set it up: + +- Simple +- Version controlled +- Easy to host on OpenBSD +- Minimal maintenance +- Good integration with Emacs +# more +That's how I came up with what I currently use. Let's walk through how +it works. + +* Framework + + The blog engine is [[https://gohugo.io/][hugo]], a static site generator. I chose this over + something dynamic like wordpress for several reasons. + + First of all, it's very easy to manage, blog posts are just simple + files written in one of the markup languages hugo supports. Being + statically generated is also a massive advantage in terms of + maintenance. With something like wordpress, you have to be careful to + keep your site and plugins up to date. + + Since there's no dynamic content generation or database involved with + hugo, the attack surface is dramatically decreased. No possibility for + SQL injection, PHP RATs, accidental shell access, or hacked + credentials. The entire site is generated using a single command after + a new post is created, and then moved to the web server's root + directory. + + Being all flat files also means the entire thing can very easily be + tracked using =git= (or maybe [[https://gameoftrees.org/][got]], eventually), in fact that's the + recommended way to use hugo. There's no fear I'll accidentally delete + something, as I can always go back to a previous commit and restore + it. + + Since hugo is written in go, it's trivial to compile on OpenBSD, and + is actually available directly from the OpenBSD package manager right + out of the gate. + + Maybe the most important thing to be however, is that hugo natively + supports org-mode markup. I write all my notes, both personal and work + related, in org-mode. It makes converting my notes into blog posts + really easy. It also lets me leverage my existing Emacs setup, which + comes in handy often. While it's not very well documented, since + org-mode markup is a bit of a second class citizen in the hugo world, + it's pretty easy to figure out. + +* Prerequisites + + This can be hosted on a very cheap VPS since it only has to serve + static pages. For OpenBSD hosting I would recommend either [[https://www.vultr.com/][Vultr]] or + [[https://openbsd.amsterdam/][OpenBSD Amsterdam]]. + +** Server + The only thing that's required on the host server is =git=, although + you could even get away without that if you chose to host your git + repository elsewhere, like on github. + + #+BEGIN_SRC shell + pkg_add git + #+END_SRC + +** Local machine + On the local machine you'll need both =git= and =rsync=. Both might + already be installed depending on the system you're on. If not, + check your package manager for details on how to install them. In + the case of Ubuntu or Debian it would be + + #+BEGIN_SRC shell + sudo apt install git rsync + #+END_SRC + + or for Fedora + + #+BEGIN_SRC shell + sudo dnf install git rsync + #+END_SRC + +* Version Control + + I wanted to try to keep things as simple as possible for this. The + "origin" for the blog is simply a bare git repository in the =blog= + user's home directory. + +** Setting up the blog user + + First I set up the blog user + #+BEGIN_SRC shell + useradd -m blog + #+END_SRC + + I then placed my public SSH key in its =authorized_keys= file + + #+BEGIN_SRC shell + mkdir -m 700 /home/blog/.ssh + cp /root/.ssh/authorized_keys /home/blog/.ssh/ + chown -R blog:blog /home/blog + #+END_SRC + + I then logged in as the blog user and initialize the bare git + repository. + + #+BEGIN_SRC shell + su blog + cd # cd with no arguments goes to home directory + git init --bare blog.git + #+END_SRC + +** Cloning the repository + + Cloning the repository onto my local machine is very easy at this + point. As long as my private keys are in the =blog= user's + =authorized_keys=, git will take care of the rest. + + #+BEGIN_SRC shell + # on my local machine + git clone blog@lambda.cx:blog.git + #+END_SRC + + I can now work on the blog as I would any other git repository, + pulling with =git pull= and pushing with =git push=. + +* Web Server + + Since this blog is going to be hosted on OpenBSD, we don't need to + install a web server, as it already comes with one built in. + + Setting up =httpd= couldn't be easier, the configuration syntax is + very straight forward. If you would like to see a full breakdown of + the options available, check out the man page with =man + httpd.conf=. The example configuration in =/etc/examples/httpd.conf= + is also a good starting point. + + In this case the simplest configuration would be as follows + + # js chosen for prism.js syntax highlighting + #+BEGIN_SRC js + server "blog.lambda.cx" { + listen on * port 80 + root "/htdocs/blog.lambda.cx" + } + #+END_SRC + + Despite how it looks, the =htdocs= folder doesn't reside in the + system root (=/=) directory. It actually lives in =/var/www/htdocs=, + and only appears that way because =httpd= gets automatically + =chroot='ed in =/var/www/= for security reasons. + + Finally we start and enable =httpd= using =rcctl= + + #+BEGIN_SRC shell + rcctl enable httpd + rcctl start httpd + #+END_SRC + + + For more information about how to set up SSL with Let's Encrypt, + check out [[{{< ref "posts/letsencrypt-on-openbsd" >}}][this post]]. + +* Using Hugo + + There's not much to say here. Hugo's [[https://gohugo.io/][website]] has good documentation + on how to get started creating a blog. I'll be covering the + intricacies of using org-mode with hugo in the future. + +* Deployment + + The system used to deploy this blog is incredibly simple, involving + only =rsync=, =hugo=, and a small shell script. + +** Server + First you have to allow the =blog= user to write to the website + root. We'll do this by making it the owner of + =/var/www/htdocs/blog.lambda.cx=. + + #+BEGIN_SRC shell + chown -R blog /var/www/htdocs/blog.lambda.cx + #+END_SRC + +** Local machine + + This is the script used to deploy the website. It's placed in the + root of the hugo git repository. + + #+BEGIN_SRC shell + #!/bin/sh + set -e + + cd '$(dirname "$0")' + hugo + rsync -va --progress --delete --rsync-path="/usr/bin/openrsync" public/ blog@lambda.cx:/var/www/htdocs/lambda.cx/blog + #+END_SRC + + Going through it line by line: + + - ~set -e~ Tells the shell to exit if any commands fail instead of + continuing execution. If ~hugo~ has a problem and exits with an + error, don't sync with the server. + - ~cd '$(dirname "$0")'~ Changes to the script's directory. This is + used in case you're running it from somewhere else. + - ~hugo~ Compile the website into static files located in the + =public= directory. + - ~rsync -va --progress --rsync-path="/usr/bin/openrsync" public/ + blog@lambda.cx:/var/www/htdocs/lambda.cx/blog~ This one is bigger + so I'll break it down. + - =rsync= A command that synchronizes files between two directories + - =-v= Be verbose, this is optional but I like it + - =-a= Stands for "archive": copy recursively, keep + permissions, etc. See the =rsync= man page if you're curious. + - =--progress= Show progress, also optional + - =--delete= Removed files on the server that no longer exist on + the client + - ~--rsync-path="/usr/bin/openrsync"~ This line is very important + for OpenBSD servers. OpenBSD has its own =rsync= implementation + called =openrsync=. Without this argument, =rsync= will connect + to the server, see that the =rsync= command doesn't exist, and + fail. + - =public/= Specify which folder we want to sync. The trailing + =/= is important. Without it =rsync= will copy the folder + instead of the folder's contents, which is what we want. + - =blog@lambda.cx:/var/www/htdocs/lambda.cx/blog= Login to user + =blog= on server =lambda.cx=, syncing files with the + =/var/www/htdocs/lambda.cx/blog= directory. + + The reason to use =rsync= here instead of something like =scp= is + that =rsync= won't upload files it doesn't need to, so if 3/4 of + the files didn't change when you updated the blog, it won't waste + time re-uploading them. diff --git a/content/posts/WIP-installing-openbsd-on-pcengines/index.org b/content/posts/WIP-installing-openbsd-on-pcengines/index.org new file mode 100644 index 0000000..11a0436 --- /dev/null +++ b/content/posts/WIP-installing-openbsd-on-pcengines/index.org @@ -0,0 +1,87 @@ +#+TITLE: Installing OpenBSD on a PC Engines APU2 +#+DATE: 2020-07-07T21:21:18-04:00 +#+DRAFT: false +#+DESCRIPTION: +#+TAGS[]: openbsd pcengines +#+KEYWORDS[]: openbsd pcengines +#+SLUG: +#+SUMMARY: + +I recently purchased a new PC Engines APU2E4 to use as a home +router. I purchased the kit, which includes the board, case, and power +supply from https://corpshadow.biz/. I also ordered the DB9F to USB +adapter (Silicon Labs CP2104), so I don't need to get a separate null +modem connector. They're the only PC Engines distributor in Canada +listed on the PC Engines website. I had a great experience with +CorpShadow, they also sell a lot of other small single board PCs, so +check them out if you live in Canada. + +I also ordered a 128 GB mSATA SSD, as it significantly out-performs +any SD card you might put in the machine. While it's not necessary, +and an SD card would be much cheaper, I find the improved read and +write speeds are worth it. I got it from Canada Computers, as they +seemed to have the best price on one. mSATA SSDs are surprisingly not +as common as one might think on PC parts websites. And even when they +have one, I've found most sites will only carry one brand. + +The first step was to install the heat sync onto the CPU. This is +described on the PC Engines website. The heat sync is effectively just +a block of aluminum that you use to thermally bridge the CPU to the +enclosure. They're connected with, what I assume is, thermally +conductive double sided tape, which they provide for you. + +After the CPU is stuck to the enclosure using the tape and the board +is screwed in place, I installed the mSATA SSD into the first +expansion slot labelled =mSATA=. Then I screwed the top of the case +on, plugged the antenna holes with the provided rubber stoppers, and +screwed the bolts back on the RS232 port. These things are really easy +to put together! + +I downloaded the AMD64 =installXX.fs= image from the OpenBSD website and +burned it onto a spare USB drive I had lying around using =dd=. After +that I inserted the drive into the USB port on the APU2. + +I then plugged one end of the DB9F end of the serial adapter into the +APU2, and the USB end into my PC. My desktop runs Fedora, so I had to +install the =cu= utility using =sudo dnf install cu=. I then dialed it +up using the serial adapter with the command =sudo cu -s 115200 -l +/dev/ttyUSB0=. + +I plugged in the power connector into the APU2, and I saw the boot +info in my terminal! It's really cool that these things use SeaBIOS +and Coreboot. + +It automatically booted from the USB device, and I got dropped into +the OpenBSD =boot>= prompt. Instead of pressing enter like normal, I +entered +#+BEGIN_SRC +boot> stty com0 115200 +boot> set tty com0 +#+END_SRC + +The first command sets the baud rate for the serial connection. The +second command tells the OpenBSD installer to set the default TTY to +the serial port =COM0=. Without these, the machine will start to boot, +fail to find an output, and reboot. + +After that the installation went along as a normal install would. I +wasn't connected to the internet, but I already knew what IP was +assigning it, so I entered that manually when asked. I also installed +the sets from the USB. To do that, when prompted for the location of +the sets, type =disk=, when asked if it's already mounted type =no=, +then select the default partition and path, and continue without +signature. The signature isn't required since it's part of the install +media (assuming you verified the signature of the install media). + +After the install was done, I moved it to where I will be leaving it +to run, plugged in the power and ethernet, and SSH'd in. At that point +I ran =fw_update= to pull in any extra firmware I might need, and +=syspatch= to keep myself up to date with security patches. + +I kept the serial adapter connected and plugged it into another +machine I have right next to it, so if I ever have any trouble +booting, I can always SSH into the other machine and dial into the +serial connector to work things out without having to physically plug +the APU2 into my laptop. + +Finally I added the OpenBSD sticker! diff --git a/content/posts/how-bsd-authentication-works/graph.dot b/content/posts/how-bsd-authentication-works/graph.dot deleted file mode 100644 index 6414b11..0000000 --- a/content/posts/how-bsd-authentication-works/graph.dot +++ /dev/null @@ -1,67 +0,0 @@ -digraph G { - subgraph cluster_authenticate { - label = "authenticate.c" - auth_userokay; - auth_usercheck; - auth_verify; - } - - subgraph cluster_auth_subr { - label = "auth_subr.c" - auth_open; - auth_call; - auth_close; - // auth_setitem; - // auth_setdata; - // auth_setopts; - auth_set[label="auth_set*"]; - auth_setstate; - // _auth_spool; - } - - subgraph cluster_login_cap { - label = "libc/login_cap.c" - login_getclass - login_getstyle - } - - subgraph cluster_getpwent { - label = "libc/getpwent.c" - getpwnam_r; - } - - subgraph cluster_exec { - login[label="login_*"]; - execve; - } - - - start -> auth_userokay; - auth_userokay -> auth_usercheck; - auth_usercheck -> getpwnam_r; - auth_usercheck -> login_getclass; - auth_usercheck -> login_getstyle; - // if password given - auth_usercheck -> auth_open; - // auth_usercheck -> auth_setitem; - // auth_usercheck -> auth_setdata; - auth_usercheck -> auth_set; - // fi - auth_usercheck -> auth_verify; - - auth_verify -> auth_setstate; - auth_verify -> auth_call; - - auth_call -> execve[label="fork()"]; - // auth_call -> _auth_spool; - - execve -> login; - login -> auth_call[label="back channel"]; - // login -> _auth_spool[label="back channel"]; - - - // auth_usercheck -> { auth_setitem auth_setdata auth_setopts } - - // auth_call -> auth_userokay; - auth_userokay -> auth_close; -} diff --git a/content/posts/how-bsd-authentication-works/index.org b/content/posts/how-bsd-authentication-works/index.org deleted file mode 100644 index 4126284..0000000 --- a/content/posts/how-bsd-authentication-works/index.org +++ /dev/null @@ -1,473 +0,0 @@ -#+TITLE: How BSD Authentication Works -#+DATE: 2020-06-26T18:31:36-04:00 -#+DRAFT: true -#+DESCRIPTION: -#+TAGS[]: openbsd -#+KEYWORDS[]: openbsd -#+SLUG: -#+SUMMARY: -#+SHOWTOC: true - -[[https://web.archive.org/web/20170327150148/http://www.penzin.net/bsdauth/]] -* History - - OpenBSD is quite different from many other Unix-like operating systems - in many ways, but one way which I find interesting is the - authentication system. Most systems from AIX, Solaris, and Linux to - most BSDs including MacOS use some form of a system called Pluggable - Authentication Module (PAM). The two main implementations of PAM are - [[http://www.linux-pam.org/][Linux PAM]] and [[https://www.openpam.org/][OpenPAM]]. PAM modules are created a dynamically loaded - shared objects, which communicate using a set of standard - interfaces ([[https://linux.die.net/man/3/pam][Linux-PAM]] and [[https://www.freebsd.org/cgi/man.cgi?query=pam&apropos=0&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports&arch=default&format=html][OpenPAM]]). PAM is configured using the [[https://linux.die.net/man/5/pam.d][pam.d]] - directory and [[https://www.freebsd.org/cgi/man.cgi?query=pam.conf&sektion=5&apropos=0&manpath=FreeBSD+12.1-RELEASE+and+Ports][pam.conf]]. - - OpenBSD on the other hand uses a mechanism called BSD - Authentication. It was originally developed for a proprietary - operating system called [[https://en.wikipedia.org/wiki/BSD/OS][BSD/OS]] by [[https://en.wikipedia.org/wiki/Berkeley_Software_Design][Berkeley Software Design Inc.]], who - later donated the system. It was adopted by OpenBSD in release - 2.9. BSD Auth is comparatively much simpler than PAM. Modules or, - authentication "styles", are instead stand alone applications or - scripts that communicate over IPC (=PF_LOCAL, SOCK_STREAM=, - specifically). The program or script has no ability to interfere - with the parent and can very easily revoke permissions using - [[https://man.openbsd.org/pledge][=pledge(2)=]] or [[https://man.openbsd.org/unveil][=unveil(2)=]]. The BSD Authentication system of - configured through [[https://man.openbsd.org/login.conf][=login.conf(5)=]]. - -* Why - - This one is pretty difficult, since there seems to be very little - information about how BSD Auth works apart from the source code - itself. This is my best attempt to understand the flow of BSD Auth - from what I've read. - -* BSD Auth Modules - - These programs or scripts are located in =/usr/libexec/auth/= with the - naming convention =login_<style>=. They take arguments in the form of - - #+BEGIN_SRC shell - login_<style> [-s service] [-v key=value] user [class] - #+END_SRC - - - =<style>= is the authentication method. This could be =passwd=, - =radius=, =skey=, =yubikey=, etc. There's more information about - available styles in [[https://man.openbsd.org/login.conf][=login.conf(5)=]] under the [[https://man.openbsd.org/login.conf#AUTHENTICATION][=AUTHENTICATION=]] - header. - - =service= is the service type. Typically authentication methods will - accept one of three values here, =login=, =challenge=, or - =response=. =login= is the default if it's not specified, and is - usually the right choice. Read the style's man page for details. - - =-v key=value= is an optional argument. There is no limit to the - number of =-v= arguments. This is used to pass extra data to the - program under certain circumstances. - - =user= is the name of the user to be authenticated. - - =class= is optional and specifies the class of the user to be - authenticated. - - =login= and =su= pass in extra data as =-v= flags. - - #+CAPTION: Taken from [[https://man.openbsd.org/login.conf][=login.conf(5)=]] - #+BEGIN_SRC - The login(1) program provides the following through the -v option: - - auth_type The type of authentication to use. - - fqdn The hostname provided to login by the -h option. - - hostname The name login(1) will place in the utmp file for the - remote hostname. - - local_addr The local IP address given to login(1) by the -L option. - - lastchance Set to "yes" when a user's password has expired but the - user is being given one last chance to login and update - the password. - - login This is a new login session (as opposed to a simple - identity check). - - remote_addr The remote IP address given to login(1) by the -R option. - - style The style of authentication used for this user (see - approval scripts below). - - The su(1) program provides the following through the -v option: - - wheel Set to either "yes" or "no" to indicate if the user is in - group wheel when they are trying to become root. Some - authentication types require the user to be in group - wheel when using the su(1) program to become super user. - #+END_SRC - - The auth module communicates with its caller through file descriptor 3. - -* Documentation - - All of the high level authentication functions are described in - [[https://man.openbsd.org/authenticate][=authenticate(3)=]], with the lower level functions being described in - [[https://man.openbsd.org/auth_subr][=auth_subr(3)=]]. - -* auth_userokay - - The highest level function, and easiest to use is =auth_userokay=. It - takes four character arrays as arguments, =name=, =style=, =type=, and - =password=. It returns either a =0= for failure, of a non-zero value - for success. - - This function lives inside =/lib/libc/gen/authenticate.c= - - #+BEGIN_SRC c - int auth_userokay(char *name, char *style, char *type, char *password); - #+END_SRC - - - =name= is the name of the user to be authenticated - - =style= is the login method to be used - - If =style= is =NULL=, the user's default login style will be - used. By default this is =passwd= on normal accounts. - - The style can be one of the installed authentication methods, like - =passwd=, =radius=, =skey=, =yubikey=, etc. - - There's more information about available styles in =login.conf(5)= - - Styles can also be installed through BSD Auth module packages - - =type= is the authentication type - - Types are defined in =login.conf= and define a group of allowed - auth styles - - If =type= is =NULL=, use the auth type for the user's login - class. The default type is =auth-default=, which allows - =psaswd= and =skey= auth methods. - - There's more information about how to add methods in =login.conf(5)= - - =password= is the password to test - - If =password= is =NULL=, then the user is interactively - prompted. This is required for auth styles using - challenge-response methods. - - If =password= is specified, then it's non-interactively tested - - =auth_userokay= is just a wrapper around =auth_usercheck=, which - returns a finished auth session of type =auth_session_t=. It closes - the auth session using =auth_close= and returns the value returned - from closing. - -* auth_session_t - - #+BEGIN_SRC c - struct auth_session_t { - char *name; /* name of use being authenticated */ - char *style; /* style of authentication used */ - char *class; /* class of user */ - char *service; /* type of service being performed */ - char *challenge; /* last challenge issued */ - int flags; /* see below */ - struct passwd *pwd; /* password entry for user */ - struct timeval now; /* time of authentication */ - - int state; /* authenticated state */ - - struct rmfiles *rmlist; /* list of files to remove on failure */ - struct authopts *optlist; /* list of options to scripts */ - struct authdata *data; /* additional data to send to scripts */ - - char spool[MAXSPOOLSIZE]; /* data returned from login script */ - int index; /* how much returned thus far */ - - int fd; /* connection to authenticator */ - - va_list ap0; /* argument list to auth_call */ - va_list ap; /* additional arguments to auth_call */ - }; - #+END_SRC - - Where =authdata=, =authopts=, and =rmfiles= are defined as - - #+BEGIN_SRC c - struct rmfiles { - struct rmfiles *next; - char *file; - }; - - struct authopts { - struct authopts *next; - char *opt; - }; - - struct authdata { - struct authdata *next; - void *ptr; - size_t len; - }; - #+END_SRC - -** auth_setdata - -** auth_setitem - -** auth_setoption - -** auth_setstate -* auth_open - - The =auth_open= function is used by several functions to create a - new auth session. It allocates an =auth_session_t= struct on the - heap, sets its default =service= to =login=, and it's =fd= to =-1=, - and returns the pointer. - -* auth_usercheck - - #+BEGIN_SRC c - auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password) - #+END_SRC - - =auth_usercheck= checks the user name against the passwd db. It also - checks the login class against the =login.conf= db, along with - confirming the login styles available. - - If the password is non-=NULL=, then it creates a new session using - =auth_open=. With the new session, =auth_usercheck= calls (with =as= - as the session struct) - - #+BEGIN_SRC c - auth_setitem(as, AUTHV_SERVICE, "response"); - auth_setdata(as, "", 1); - auth_setdata(as, password, strlen(password) + 1); - #+END_SRC - - setting the service protocol to =response=, adding an empty line to - the session data, then adding the password as data. If the password is - =NULL=, it sets the =auth_session_t= pointer to =NULL=. It then passes - the user name, style, login class, and =NULL= char pointer to - =auth_verify=. The last two variables are received as variable - arguments. It then returns the auth session pointer the call - returns. - -* auth_verify - - #+BEGIN_SRC c - auth_session_t *auth_verify(auth_session_t *as, char *style, char *name, ...) - #+END_SRC - - =auth_verify= creates an auth session using =auth_open= if =as= is - =NULL=. It then sets the user name and style of the session, if the - respective arguments are non-=NULL=. It then copies its variable - arguments to the auth session's =va_list ap=, which is used inside - of =auth_call=. - - After that it constructs the path of the authentication module by - combining =_PATH_AUTHPROG=, which is defined in =login_cap.h= as - =/usr/libexec/auth/login_=, and the authentication style. For the - case of auth style =passwd=, it would result in the path - =/usr/libexec/auth/login_passwd=. - - Then =auth_call= is called with the struct, the path to the auth - module, the auth style, the "-s" flag followed by the service (login, - challenge, response), a double dash, the user name, and a =NULL= - character pointer. The return value of =auth_call= is ignored and a - pointer to the auth session is returned immediately afterwards. - - #+BEGIN_SRC c - auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s", - auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL); - #+END_SRC - -* auth_call - - #+BEGIN_SRC c - int auth_call(auth_session_t *as, char *path, ...) - #+END_SRC - - <<here>> - - --- - note: In the man page auth_subr it says - #+begin_quote - path The full path name of the login script to run. The call will - fail if path does not pass the requirements of the secure_path(3) - function. - #+end_quote - However I don't see this enforced anywhere, I even wrote a small test - script to prove that's the case on =vfwall ~/authtest=. - - The manpage also says the path is limited to =/bin/= and =/usr/bin=, - which is also not the case. - - Ask jcs about the file descriptor situation, I don't understand it - after reading both the man page and source. - --- - - Inside of =auth_call=, a socket pair of type =PF_LOCAL, SOCK_STREAM= - is created. This is called the "back channel", and is used to - communicate with the authentication module. The process then forks, - calling ~execve(path, argv, auth_environ)~, where the =argv= is - everything after =path= in the =auth_call= arguments. Any =authopts= - set in the auth session are also passed as arguments in the format =-v - opt1 -v opt2 -v opt3=, etc. =auth_environ= is defined at the top of - the file as - - #+BEGIN_SRC c - static char *auth_environ[] = { - "PATH=" _PATH_DEFPATH, - "SHELL=" _PATH_BSHELL, - NULL, - }; - #+END_SRC - - Where both constants are defined in =paths.h= as - - #+BEGIN_SRC c - #define _PATH_DEFPATH "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin" - #define _PATH_BSHELL "/bin/sh" - #+END_SRC - - - The =exec='d process then listens on FD 3, which is one half of the - =sockpair= that was created earlier. - - In the non-exec'd process, first the contents of the auth session's - =*data= are read in one at a time. - - The data received through the back channel is then put into the - =spool= of the auth session using =_auth_spool(as, pfd[0])=. After - that the spooled data is scanned for key words defined in - =login_cap.h=. - - #+BEGIN_SRC c - #define BI_AUTH "authorize" /* Accepted authentication */ - #define BI_REJECT "reject" /* Rejected authentication */ - #define BI_CHALLENGE "reject challenge" /* Reject with a challenge */ - #define BI_SILENT "reject silent" /* Reject silently */ - #define BI_REMOVE "remove" /* remove file on error */ - #define BI_ROOTOKAY "authorize root" /* root authenticated */ - #define BI_SECURE "authorize secure" /* okay on non-secure line */ - #define BI_SETENV "setenv" /* set environment variable */ - #define BI_UNSETENV "unsetenv" /* unset environment variable */ - #define BI_VALUE "value" /* set local variable */ - #define BI_EXPIRED "reject expired" /* account expired */ - #define BI_PWEXPIRED "reject pwexpired" /* password expired */ - #define BI_FDPASS "fd" /* child is passing an fd */ - #+END_SRC - - The [[https://man.openbsd.org/login.conf][=login.conf(5)=]] man page once again goes into greater detail on - these values. - - #+BEGIN_SRC - authorize The user has been authorized. - - authorize secure - The user has been authorized and root should be allowed to - login even if this is not a secure terminal. This should only - be sent by authentication styles that are secure over insecure - lines. - - reject Authorization is rejected. This overrides any indication that - the user was authorized (though one would question the wisdom - in sending both a reject and an authorize command). - - reject challenge - Authorization was rejected and a challenge has been made - available via the value challenge. - - reject silent - Authorization is rejected, but no error messages should be - generated. - - remove file - If the login session fails for any reason, remove file before - termination. - - setenv name value - If the login session succeeds, the environment variable name - should be set to the specified value. - - unsetenv name - If the login session succeeds, the environment variable name - should be removed. - - value name value - Set the internal variable name to the specified value. The - value should only contain printable characters. Several \ - sequences may be used to introduce non printing characters. - These are: - - \n A newline. - - \r A carriage return. - - \t A tab. - - \xxx The character represented by the octal value xxx. The - value may be one, two, or three octal digits. - - \c The string is replaced by the value of c. This allows - quoting an initial space or the \ character itself. - - - The following values are currently defined: - - challenge - See section on challenges below. - - errormsg - If set, the value is the reason authentication failed. - The calling program may choose to display this when - rejecting the user, but display is not required. - - #+END_SRC - - - It is looking for lines that start with either =BI_AUTH= - (=authorize=), or =BI_REJECT= (=reject=). If the line is still longer, - it continues to scan for any other qualifiers such as =pwexpired= or - =silent=. The struct's =state= is set to one using the =AUTH_= values - from =login_cap.h= accordingly. - - #+BEGIN_SRC c - /* - * bits which can be returned by authenticate()/auth_scan() - */ - #define AUTH_OKAY 0x01 /* user authenticated */ - #define AUTH_ROOTOKAY 0x02 /* authenticated as root */ - #define AUTH_SECURE 0x04 /* secure login */ - #define AUTH_SILENT 0x08 /* silent rejection */ - #define AUTH_CHALLENGE 0x10 /* a challenge was given */ - #define AUTH_EXPIRED 0x20 /* account expired */ - #define AUTH_PWEXPIRED 0x40 /* password expired */ - #+END_SRC - -** _auth_spool - -** _recv_fd - -* auth_close - =auth_close= is the function responsible for cleaning up the session - and taking care of the values returned though the back channel. - - It first sets the environment variables returned through the back - channel by passing the auth session to =auth_setenv=. It then goes - through the =rmlist= of the session, deleting the files if the - session reported a failure. It then zeroes out all sensitive - information, and frees the various structs associated with the current - =auth_session_t=, and then the session itself. Finally it returns - the session's state =&='ed with =AUTH_ALLOW=. -* grapgh? -# Setting env on auth_close(as) -# partual rewrite below - -The call graph for =auth_userokay= looks something like this: - -#+BEGIN_SRC c -int auth_userokay(char *name, char *style, char *type, char *password) -#+END_SRC - -calls ~auth_usercheck~ and then calls ~auth_close~ on the returned -~auth_session_t~. The value returned from ~auth_close~ is then -returned. - -#+BEGIN_SRC c -auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password) -#+END_SRC - -Validates the checks that the user exists, gets the user's login -class, verifies the auth type, and that the auth style can be used. - -It creates an auth session struct. - -If the password is provided it sets the service type to =response=, -and adds the adds the password to the auth data. Otherwise it -leaves it empty. diff --git a/content/posts/how-this-blog-works.org b/content/posts/how-this-blog-works.org deleted file mode 100644 index 80fa1ca..0000000 --- a/content/posts/how-this-blog-works.org +++ /dev/null @@ -1,239 +0,0 @@ -#+TITLE: Creating Self-Hosted Hugo Blog on OpenBSD -#+DATE: 2020-06-17T21:03:26-04:00 -#+DRAFT: true -#+DESCRIPTION: -#+TAGS[]: hugo openbsd -#+KEYWORDS[]: -#+SLUG: -#+SUMMARY: -#+SHOWTOC: true - -When creating this blog, there were a couple of factors I kept in mind -while trying to figure out how I was going to set it up: - -- Simple -- Version controlled -- Easy to host on OpenBSD -- Minimal maintenance -- Good integration with Emacs -# more -That's how I came up with what I currently use. Let's walk through how -it works. - -* Framework - - The blog engine is [[https://gohugo.io/][hugo]], a static site generator. I chose this over - something dynamic like wordpress for several reasons. - - First of all, it's very easy to manage, blog posts are just simple - files written in one of the markup languages hugo supports. Being - statically generated is also a massive advantage in terms of - maintenance. With something like wordpress, you have to be careful to - keep your site and plugins up to date. - - Since there's no dynamic content generation or database involved with - hugo, the attack surface is dramatically decreased. No possibility for - SQL injection, PHP RATs, accidental shell access, or hacked - credentials. The entire site is generated using a single command after - a new post is created, and then moved to the web server's root - directory. - - Being all flat files also means the entire thing can very easily be - tracked using =git= (or maybe [[https://gameoftrees.org/][got]], eventually), in fact that's the - recommended way to use hugo. There's no fear I'll accidentally delete - something, as I can always go back to a previous commit and restore - it. - - Since hugo is written in go, it's trivial to compile on OpenBSD, and - is actually available directly from the OpenBSD package manager right - out of the gate. - - Maybe the most important thing to be however, is that hugo natively - supports org-mode markup. I write all my notes, both personal and work - related, in org-mode. It makes converting my notes into blog posts - really easy. It also lets me leverage my existing Emacs setup, which - comes in handy often. While it's not very well documented, since - org-mode markup is a bit of a second class citizen in the hugo world, - it's pretty easy to figure out. - -* Prerequisites - - This can be hosted on a very cheap VPS since it only has to serve - static pages. For OpenBSD hosting I would recommend either [[https://www.vultr.com/][Vultr]] or - [[https://openbsd.amsterdam/][OpenBSD Amsterdam]]. - -** Server - The only thing that's required on the host server is =git=, although - you could even get away without that if you chose to host your git - repository elsewhere, like on github. - - #+BEGIN_SRC shell - pkg_add git - #+END_SRC - -** Local machine - On the local machine you'll need both =git= and =rsync=. Both might - already be installed depending on the system you're on. If not, - check your package manager for details on how to install them. In - the case of Ubuntu or Debian it would be - - #+BEGIN_SRC shell - sudo apt install git rsync - #+END_SRC - - or for Fedora - - #+BEGIN_SRC shell - sudo dnf install git rsync - #+END_SRC - -* Version Control - - I wanted to try to keep things as simple as possible for this. The - "origin" for the blog is simply a bare git repository in the =blog= - user's home directory. - -** Setting up the blog user - - First I set up the blog user - #+BEGIN_SRC shell - useradd -m blog - #+END_SRC - - I then placed my public SSH key in its =authorized_keys= file - - #+BEGIN_SRC shell - mkdir -m 700 /home/blog/.ssh - cp /root/.ssh/authorized_keys /home/blog/.ssh/ - chown -R blog:blog /home/blog - #+END_SRC - - I then logged in as the blog user and initialize the bare git - repository. - - #+BEGIN_SRC shell - su blog - cd # cd with no arguments goes to home directory - git init --bare blog.git - #+END_SRC - -** Cloning the repository - - Cloning the repository onto my local machine is very easy at this - point. As long as my private keys are in the =blog= user's - =authorized_keys=, git will take care of the rest. - - #+BEGIN_SRC shell - # on my local machine - git clone blog@lambda.cx:blog.git - #+END_SRC - - I can now work on the blog as I would any other git repository, - pulling with =git pull= and pushing with =git push=. - -* Web Server - - Since this blog is going to be hosted on OpenBSD, we don't need to - install a web server, as it already comes with one built in. - - Setting up =httpd= couldn't be easier, the configuration syntax is - very straight forward. If you would like to see a full breakdown of - the options available, check out the man page with =man - httpd.conf=. The example configuration in =/etc/examples/httpd.conf= - is also a good starting point. - - In this case the simplest configuration would be as follows - - # js chosen for prism.js syntax highlighting - #+BEGIN_SRC js - server "blog.lambda.cx" { - listen on * port 80 - root "/htdocs/blog.lambda.cx" - } - #+END_SRC - - Despite how it looks, the =htdocs= folder doesn't reside in the - system root (=/=) directory. It actually lives in =/var/www/htdocs=, - and only appears that way because =httpd= gets automatically - =chroot='ed in =/var/www/= for security reasons. - - Finally we start and enable =httpd= using =rcctl= - - #+BEGIN_SRC shell - rcctl enable httpd - rcctl start httpd - #+END_SRC - - - For more information about how to set up SSL with Let's Encrypt, - check out [[{{< ref "posts/letsencrypt-on-openbsd" >}}][this post]]. - -* Using Hugo - - There's not much to say here. Hugo's [[https://gohugo.io/][website]] has good documentation - on how to get started creating a blog. I'll be covering the - intricacies of using org-mode with hugo in the future. - -* Deployment - - The system used to deploy this blog is incredibly simple, involving - only =rsync=, =hugo=, and a small shell script. - -** Server - First you have to allow the =blog= user to write to the website - root. We'll do this by making it the owner of - =/var/www/htdocs/blog.lambda.cx=. - - #+BEGIN_SRC shell - chown -R blog /var/www/htdocs/blog.lambda.cx - #+END_SRC - -** Local machine - - This is the script used to deploy the website. It's placed in the - root of the hugo git repository. - - #+BEGIN_SRC shell - #!/bin/sh - set -e - - cd '$(dirname "$0")' - hugo - rsync -va --progress --delete --rsync-path="/usr/bin/openrsync" public/ blog@lambda.cx:/var/www/htdocs/lambda.cx/blog - #+END_SRC - - Going through it line by line: - - - ~set -e~ Tells the shell to exit if any commands fail instead of - continuing execution. If ~hugo~ has a problem and exits with an - error, don't sync with the server. - - ~cd '$(dirname "$0")'~ Changes to the script's directory. This is - used in case you're running it from somewhere else. - - ~hugo~ Compile the website into static files located in the - =public= directory. - - ~rsync -va --progress --rsync-path="/usr/bin/openrsync" public/ - blog@lambda.cx:/var/www/htdocs/lambda.cx/blog~ This one is bigger - so I'll break it down. - - =rsync= A command that synchronizes files between two directories - - =-v= Be verbose, this is optional but I like it - - =-a= Stands for "archive": copy recursively, keep - permissions, etc. See the =rsync= man page if you're curious. - - =--progress= Show progress, also optional - - =--delete= Removed files on the server that no longer exist on - the client - - ~--rsync-path="/usr/bin/openrsync"~ This line is very important - for OpenBSD servers. OpenBSD has its own =rsync= implementation - called =openrsync=. Without this argument, =rsync= will connect - to the server, see that the =rsync= command doesn't exist, and - fail. - - =public/= Specify which folder we want to sync. The trailing - =/= is important. Without it =rsync= will copy the folder - instead of the folder's contents, which is what we want. - - =blog@lambda.cx:/var/www/htdocs/lambda.cx/blog= Login to user - =blog= on server =lambda.cx=, syncing files with the - =/var/www/htdocs/lambda.cx/blog= directory. - - The reason to use =rsync= here instead of something like =scp= is - that =rsync= won't upload files it doesn't need to, so if 3/4 of - the files didn't change when you updated the blog, it won't waste - time re-uploading them. diff --git a/content/posts/openbsd-dhcp-server/index.org b/content/posts/openbsd-dhcp-server/index.org deleted file mode 100644 index 0578f87..0000000 --- a/content/posts/openbsd-dhcp-server/index.org +++ /dev/null @@ -1,8 +0,0 @@ -#+TITLE: How to Setup a DHCP server on OpenBSD -#+DATE: 2020-07-07T19:22:38-04:00 -#+DRAFT: true -#+DESCRIPTION: -#+TAGS[]: openbsd dhcp -#+KEYWORDS[]: openbsd dhcp -#+SLUG: -#+SUMMARY: -- cgit v1.2.3