diff options
| author | Mattias Andrée <m@maandree.se> | 2026-02-22 13:49:08 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2026-02-22 13:49:08 +0100 |
| commit | 86138fc92d6e5f92d9d3fcceb32b849e8504f619 (patch) | |
| tree | f361b9cea99dbe4d77d0dd8f9cbc00f67c105d6b | |
| parent | Udpdate for new version of glibc (diff) | |
| download | cerberus-86138fc92d6e5f92d9d3fcceb32b849e8504f619.tar.gz cerberus-86138fc92d6e5f92d9d3fcceb32b849e8504f619.tar.bz2 cerberus-86138fc92d6e5f92d9d3fcceb32b849e8504f619.tar.xz | |
Signed-off-by: Mattias Andrée <m@maandree.se>
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | COPYING | 2 | ||||
| -rw-r--r-- | DEPENDENCIES | 1 | ||||
| -rw-r--r-- | Makefile | 57 | ||||
| -rw-r--r-- | README | 1 | ||||
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | configurable-definitions | 1 | ||||
| -rw-r--r-- | info/cerberus.texinfo | 1 | ||||
| -rw-r--r-- | src/auth.h | 43 | ||||
| -rw-r--r-- | src/auth/crypt.c | 101 | ||||
| -rw-r--r-- | src/auth/crypt.h | 7 | ||||
| -rw-r--r-- | src/auth/pam.c | 248 | ||||
| -rw-r--r-- | src/auth/pam.h | 7 | ||||
| -rw-r--r-- | src/cerberus.c | 694 | ||||
| -rw-r--r-- | src/cerberus.h | 29 | ||||
| -rw-r--r-- | src/config.h | 3 | ||||
| -rw-r--r-- | src/login.c | 229 | ||||
| -rw-r--r-- | src/login.h | 13 | ||||
| -rw-r--r-- | src/quit.c | 35 | ||||
| -rw-r--r-- | src/quit.h | 3 | ||||
| -rw-r--r-- | src/security.c | 187 | ||||
| -rw-r--r-- | src/security.h | 3 |
22 files changed, 802 insertions, 866 deletions
@@ -1,4 +1,3 @@ -_/ bin/ obj/ \#*\# @@ -18,4 +17,3 @@ obj/ *.gz *.bz2 *.xz - @@ -1,6 +1,6 @@ cerberus – Minimal login program -Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) +Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/DEPENDENCIES b/DEPENDENCIES index 0691c7a..857721e 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -20,4 +20,3 @@ INSTALL DEPENDENCIES: make coreutils - @@ -27,6 +27,9 @@ _LS = $(LOCAL_PREFIX)$(SBIN) _US = $(USR_PREFIX)$(SBIN) _SS = $(SBIN) +TEXI2DVI = texi2dvi +CC = gcc -std=gnu99 + AUTH = pam TTY_GROUP = tty DEFAULT_HOME = / @@ -53,21 +56,8 @@ VRB_DEFS = VCS_LEN VCSA_LEN STR_CPPFLAGS = $(foreach D, $(STR_DEFS), -D'$(D)="$($(D))"') VRB_CPPFLAGS = $(foreach D, $(VRB_DEFS), -D'$(D)=$($(D))') -DAUTH=$(auth_$(AUTH)) -OPTIMISE = -Os -STD=gnu99 -WARN = -Wall -Wextra -Wdouble-promotion -Wformat=2 -Winit-self -Wmissing-include-dirs \ - -Wtrampolines -Wfloat-equal -Wshadow -Wmissing-prototypes -Wmissing-declarations \ - -Wredundant-decls -Wnested-externs -Winline -Wno-variadic-macros -Wsync-nand \ - -Wunsafe-loop-optimizations -Wcast-align -Wstrict-overflow -Wdeclaration-after-statement \ - -Wundef -Wbad-function-cast -Wcast-qual -Wwrite-strings -Wlogical-op -Waggregate-return \ - -Wstrict-prototypes -Wold-style-definition -Wpacked -Wvector-operation-performance \ - -Wunsuffixed-float-constants -Wsuggest-attribute=const -Wsuggest-attribute=noreturn \ - -Wsuggest-attribute=pure -Wsuggest-attribute=format -Wnormalized=nfkc -Wconversion \ - -fstrict-aliasing -fstrict-overflow -fipa-pure-const -ftree-vrp -fstack-usage \ - -funsafe-loop-optimizations -# excluded: -pedantic CPPFLAGS_ = $(EXTRA_CPP_FLAGS) $(STR_CPPFLAGS) $(VRB_CPPFLAGS) -CFLAGS_ = -std=$(STD) $(WARN) +CFLAGS_ = -Os LDFLAGS_ = ifneq ($(AUTH),none) LDFLAGS_ += -lpassphrase @@ -79,8 +69,8 @@ ifeq ($(AUTH),pam) LDFLAGS_ += -lpam endif -CC_FLAGS = $(CPPFLAGS_) $(CFLAGS_) $(OPTIMISE) $(CPPFLAGS) $(CFLAGS) -LD_FLAGS = $(LDFLAGS_) $(CFLAGS_) $(OPTIMISE) $(LDFLAGS) +CC_FLAGS = $(CPPFLAGS_) $(CFLAGS_) $(CPPFLAGS) $(CFLAGS) +LD_FLAGS = $(LDFLAGS_) $(CFLAGS_) $(LDFLAGS) SRC = cerberus quit security login ifneq ($(AUTH),none) @@ -104,11 +94,11 @@ cerberus: bin/cerberus bin/cerberus: $(OBJ) @mkdir -p bin - $(CC) $(LD_FLAGS) -o "$@" $^ + $(CC) $(LD_FLAGS) -o "$@" $(OBJ) obj/cerberus.o: $(foreach H, $(SRC), src/$(H).h) src/auth.h obj/%.o: src/%.c src/%.h src/config.h - @mkdir -p "$(shell dirname "$@")" + @mkdir -p -- "$$(dirname "$@")" $(CC) $(CC_FLAGS) -o "$@" -c "$<" @@ -124,21 +114,21 @@ info: cerberus.info pdf: cerberus.pdf %.pdf: info/%.texinfo info/fdl.texinfo @mkdir -p obj/pdf - cd obj/pdf ; yes X | texi2pdf ../../$< + cd obj/pdf && texi2pdf ../../$< < /dev/null mv obj/pdf/$@ $@ .PHONY: dvi dvi: cerberus.dvi %.dvi: info/%.texinfo info/fdl.texinfo @mkdir -p obj/dvi - cd obj/dvi ; yes X | $(TEXI2DVI) ../../$< + cd obj/dvi && $(TEXI2DVI) ../../$< < /dev/null mv obj/dvi/$@ $@ .PHONY: ps ps: cerberus.ps %.ps: info/%.texinfo info/fdl.texinfo @mkdir -p obj/ps - cd obj/ps ; yes X | texi2pdf --ps ../../$< + cd obj/ps && texi2pdf --ps ../../$< < /dev/null mv obj/ps/$@ $@ @@ -153,36 +143,36 @@ install-base: install-command install-license .PHONY: install-command install-command: bin/cerberus - install -dm755 -- "$(DESTDIR)$(PREFIX)$(INSTALL_BIN)" - install -m755 -- bin/cerberus "$(DESTDIR)$(PREFIX)$(INSTALL_BIN)/$(COMMAND)" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(INSTALL_BIN)" + cp -- bin/cerberus "$(DESTDIR)$(PREFIX)$(INSTALL_BIN)/$(COMMAND)" .PHONY: install-license install-license: - install -dm755 -- "$(DESTDIR)$(PREFIX)$(LICENSES)/$(PKGNAME)" - install -m644 -- COPYING LICENSE "$(DESTDIR)$(PREFIX)$(LICENSES)/$(PKGNAME)" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(LICENSES)/$(PKGNAME)" + cp -- COPYING LICENSE "$(DESTDIR)$(PREFIX)$(LICENSES)/$(PKGNAME)" .PHONY: install-doc install-doc: install-info install-pdf install-ps install-dvi .PHONY: install-info install-info: cerberus.info - install -dm755 -- "$(DESTDIR)$(PREFIX)$(DATA)/info" - install -m644 -- "$<" "$(DESTDIR)$(PREFIX)$(DATA)/info/$(PKGNAME).info" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(DATA)/info" + cp -- cerberus.info "$(DESTDIR)$(PREFIX)$(DATA)/info/$(PKGNAME).info" .PHONY: install-pdf install-pdf: cerberus.pdf - install -dm755 -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" - install -m644 -- "$<" "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).pdf" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" + cp -- cerberus.pdf "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).pdf" .PHONY: install-ps install-ps: cerberus.ps - install -dm755 -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" - install -m644 -- "$<" "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).ps" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" + cp -- cerberus.ps "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).ps" .PHONY: install-dvi install-dvi: cerberus.dvi - install -dm755 -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" - install -m644 -- "$<" "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).dvi" + mkdir -p -- "$(DESTDIR)$(PREFIX)$(DATA)/doc" + cp -- cerberus.dvi "$(DESTDIR)$(PREFIX)$(DATA)/doc/$(PKGNAME).dvi" .PHONY: uninstall @@ -201,4 +191,3 @@ uninstall: .PHONY: clean clean: -rm -rf -- bin obj cerberus.info cerberus.pdf cerberus.ps cerberus.dvi - @@ -5,4 +5,3 @@ you want last login and motto of the day to be printed, do so from your shell if $0 starts with a dash (-) or in your ~/.${SHELL}_profile. - @@ -1,2 +1 @@ Investigate whether it is worth it to exec into a small process image after the login. - diff --git a/configurable-definitions b/configurable-definitions index 8d5a946..4ec0a1e 100644 --- a/configurable-definitions +++ b/configurable-definitions @@ -46,4 +46,3 @@ AUTH (default: pam, type: name) NO_SHADOW (default: undefined, type: #ifdef, required: AUTH=crypt) Do not use /etc/shadow (shadow.h) unless HAVE_SHADOW is definied - diff --git a/info/cerberus.texinfo b/info/cerberus.texinfo index 0428707..14b739f 100644 --- a/info/cerberus.texinfo +++ b/info/cerberus.texinfo @@ -352,4 +352,3 @@ The user provided an incorrect passphrase. @include fdl.texinfo @bye - @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,33 +22,26 @@ #if AUTH == 0 - -#define close_login_session(...) /* do nothing */ -#define initialise_login(...) (void) hostname -#define authenticate_login(...) 1 -#define verify_account(...) /* do nothing */ -#define open_login_session(...) /* do nothing */ - +# define close_login_session(...) /* do nothing */ +# define initialise_login(...) (void) hostname +# define authenticate_login(...) 1 +# define verify_account(...) /* do nothing */ +# define open_login_session(...) /* do nothing */ #elif AUTH == 1 - -#include "auth/crypt.h" -#define close_login_session(...) /* do nothing */ -#define initialise_login initialise_crypt -#define authenticate_login authenticate_crypt -#define verify_account(...) /* do nothing */ -#define open_login_session(...) /* do nothing */ - +# include "auth/crypt.h" +# define close_login_session(...) /* do nothing */ +# define initialise_login initialise_crypt +# define authenticate_login authenticate_crypt +# define verify_account(...) /* do nothing */ +# define open_login_session(...) /* do nothing */ #elif AUTH == 2 - -#include "auth/pam.h" -#define close_login_session close_session_pam -#define initialise_login initialise_pam -#define authenticate_login authenticate_pam -#define verify_account verify_account_pam -#define open_login_session open_session_pam - +# include "auth/pam.h" +# define close_login_session close_session_pam +# define initialise_login initialise_pam +# define authenticate_login authenticate_pam +# define verify_account verify_account_pam +# define open_login_session open_session_pam #endif #endif - diff --git a/src/auth/crypt.c b/src/auth/crypt.c index 4573c5a..5012580 100644 --- a/src/auth/crypt.c +++ b/src/auth/crypt.c @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,12 +46,12 @@ /** * Function that can be used to read a passphrase from the terminal */ -static char* (*passphrase_reader)(void) = NULL; +static char *(*passphrase_reader)(void) = NULL; /** * The username of the user to log in to */ -static char* login_username; +static char *login_username; @@ -62,12 +62,13 @@ static char* login_username; * @param username The username of the user to log in to * @param reader Function that can be used to read a passphrase from the terminal */ -void initialise_crypt(char* remote, char* username, char* (*reader)(void)) +void +initialise_crypt(char *remote, char *username, char *(*reader)(void)) { - (void) remote; - - login_username = username; - passphrase_reader = reader; + (void) remote; + + login_username = username; + passphrase_reader = reader; } @@ -76,54 +77,52 @@ void initialise_crypt(char* remote, char* username, char* (*reader)(void)) * * @return 0: failed, 1: success, 2: auto-authenticated */ -char authenticate_crypt(void) +char +authenticate_crypt(void) { #ifdef HAVE_SHADOW - struct spwd* shadow_entry = NULL; + struct spwd *shadow_entry = NULL; #endif - struct passwd* passwd_entry = NULL; - char* crypted; - char* entered; - struct termios stty; - + struct passwd *passwd_entry = NULL; + char *crypted; + char *entered; + struct termios stty; + #ifdef HAVE_SHADOW - shadow_entry = getspnam(login_username); - endspent(); - - if (shadow_entry) - crypted = shadow_entry->sp_pwdp; - else - { + shadow_entry = getspnam(login_username); + endspent(); + + if (shadow_entry) { + crypted = shadow_entry->sp_pwdp; + } else { #endif - passwd_entry = getpwnam(login_username); - if (passwd_entry) - crypted = passwd_entry->pw_passwd; - else - { - perror("getpwnam"); - endpwent(); - sleep(ERROR_SLEEP); - _exit(1); - } - endpwent(); + passwd_entry = getpwnam(login_username); + if (passwd_entry) { + crypted = passwd_entry->pw_passwd; + } else { + perror("getpwnam"); + endpwent(); + sleep(ERROR_SLEEP); + _exit(1); + } + endpwent(); #ifdef HAVE_SHADOW - } + } #endif - - if (!(crypted && *crypted)) /* empty means that no passphrase is required (not even Enter) */ - return 2; - - entered = crypt(passphrase_reader(), crypted /* salt argument stops parsing when encrypted begins */); - if (entered && !strcmp(entered, crypted)) - return 1; - - /* Clear ISIG (and everything else) to prevent the user - * from skipping the brute force protection sleep. */ - tcgetattr(STDIN_FILENO, &stty); - stty.c_lflag = 0; - tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty); - - printf("\nPassphrase incorrect.\nOnly perfect spellers may\nenter this system.\n"); - return 0; -} + if (!(crypted && *crypted)) /* empty means that no passphrase is required (not even Enter) */ + return 2; + + entered = crypt(passphrase_reader(), crypted /* salt argument stops parsing when encrypted begins */); + if (entered && !strcmp(entered, crypted)) + return 1; + + /* Clear ISIG (and everything else) to prevent the user + * from skipping the brute force protection sleep. */ + tcgetattr(STDIN_FILENO, &stty); + stty.c_lflag = 0; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty); + + printf("\nPassphrase incorrect.\nOnly perfect spellers may\nenter this system.\n"); + return 0; +} diff --git a/src/auth/crypt.h b/src/auth/crypt.h index 4478929..cfcfc4f 100644 --- a/src/auth/crypt.h +++ b/src/auth/crypt.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +23,11 @@ /** * Initialise crypt authentication module * - * @param remote The remote computer, {@code NULL} for local login + * @param remote The remote computer, `NULL` for local login * @param username The username of the user to log in to * @param reader Function that can be used to read a passphrase from the terminal */ -void initialise_crypt(char* remote, char* username, char* (*reader)(void)); +void initialise_crypt(char *remote, char *username, char *(*reader)(void)); /** * Perform token authentication @@ -38,4 +38,3 @@ char authenticate_crypt(void); #endif - diff --git a/src/auth/pam.c b/src/auth/pam.c index 106462a..7ddc874 100644 --- a/src/auth/pam.c +++ b/src/auth/pam.c @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ __attribute__((noreturn)) #endif static void quit_pam(int sig); -static int conv_pam(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr); +static int conv_pam(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); /** @@ -73,7 +73,7 @@ static char auto_authenticated = 1; /** * Function that can be used to read a passphrase from the terminal */ -static char* (*passphrase_reader)(void) = NULL; +static char *(*passphrase_reader)(void) = NULL; #ifdef __GNUC__ @@ -85,17 +85,17 @@ static char* (*passphrase_reader)(void) = NULL; * * @param rc What the PAM instruction return */ -static void do_pam(int rc) +static void +do_pam(int rc) { - if (__failed(rc)) - { - const char* msg = pam_strerror(handle, rc); - if (msg) - fprintf(stderr, "%s\n", msg); - pam_end(handle, rc); - sleep(ERROR_SLEEP); - _exit(1); - } + if (__failed(rc)) { + const char *msg = pam_strerror(handle, rc); + if (msg) + fprintf(stderr, "%s\n", msg); + pam_end(handle, rc); + sleep(ERROR_SLEEP); + _exit(1); + } } #ifdef __GNUC__ # pragma GCC diagnostic pop @@ -109,91 +109,92 @@ static void do_pam(int rc) * @param username The username of the user to log in to * @param reader Function that can be used to read a passphrase from the terminal */ -void initialise_pam(char* remote, char* username, char* (*reader)(void)) +void +initialise_pam(char *remote, char *username, char *(*reader)(void)) { - passphrase_reader = reader; - - if (pam_start(remote ? "remote" : "local", username, &conv, &handle) != PAM_SUCCESS) - { - fprintf(stderr, "Cannot initialise PAM\n"); - sleep(ERROR_SLEEP); - _exit(1); - } - - do_pam(pam_set_item(handle, PAM_RHOST, remote ?: "localhost")); - do_pam(pam_set_item(handle, PAM_TTY, ttyname(STDIN_FILENO) ?: "(none)")); - do_pam(pam_set_item(handle, PAM_USER_PROMPT, "Username: ")); + passphrase_reader = reader; + + if (pam_start(remote ? "remote" : "local", username, &conv, &handle) != PAM_SUCCESS) { + fprintf(stderr, "Cannot initialise PAM\n"); + sleep(ERROR_SLEEP); + _exit(1); + } + + do_pam(pam_set_item(handle, PAM_RHOST, remote ?: "localhost")); + do_pam(pam_set_item(handle, PAM_TTY, ttyname(STDIN_FILENO) ?: "(none)")); + do_pam(pam_set_item(handle, PAM_USER_PROMPT, "Username: ")); } /** * Verify that the account may be used */ -void verify_account_pam(void) +void +verify_account_pam(void) { - /* FIXME pam_acct_mgmt exits the program, but freezes if PAM_USER_PROMPT has not been set. */ - /* however, if -f is used there is no problem. */ - /* - int rc = pam_acct_mgmt(handle, 0); - if (rc == PAM_NEW_AUTHTOK_REQD) - rc = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK); - do_pam(rc); - */ + /* FIXME pam_acct_mgmt exits the program, but freezes if PAM_USER_PROMPT has not been set. */ + /* however, if -f is used there is no problem. */ + /* + int rc = pam_acct_mgmt(handle, 0); + if (rc == PAM_NEW_AUTHTOK_REQD) + rc = pam_chauthtok(handle, PAM_CHANGE_EXPIRED_AUTHTOK); + do_pam(rc); + */ } /** * Open PAM session */ -void open_session_pam(void) +void +open_session_pam(void) { - int rc; - char** env; - struct sigaction signal_action; - - do_pam(pam_setcred(handle, PAM_ESTABLISH_CRED)); - - if (__failed(rc = pam_open_session(handle, 0))) - { - pam_setcred(handle, PAM_DELETE_CRED); - do_pam(rc); - } - - if (__failed(rc = pam_setcred(handle, PAM_REINITIALIZE_CRED))) - { - pam_close_session(handle, 0); - do_pam(rc); - } - - memset(&signal_action, 0, sizeof(signal_action)); - signal_action.sa_handler = SIG_IGN; - sigaction(SIGINT, &signal_action, NULL); - sigaction(SIGHUP, &signal_action, &signal_action_hup); - signal_action.sa_handler = quit_pam; - sigaction(SIGHUP, &signal_action, NULL); - sigaction(SIGTERM, &signal_action, &signal_action_term); - - for (env = pam_getenvlist(handle); env && *env; env++) - if (putenv(*env)) - { - pam_setcred(handle, PAM_DELETE_CRED); - pam_end(handle, pam_close_session(handle, 0)); - sleep(ERROR_SLEEP); - _exit(1); - } + int rc; + char **env; + struct sigaction signal_action; + + do_pam(pam_setcred(handle, PAM_ESTABLISH_CRED)); + + if (__failed(rc = pam_open_session(handle, 0))) { + pam_setcred(handle, PAM_DELETE_CRED); + do_pam(rc); + } + + if (__failed(rc = pam_setcred(handle, PAM_REINITIALIZE_CRED))) { + pam_close_session(handle, 0); + do_pam(rc); + } + + memset(&signal_action, 0, sizeof(signal_action)); + signal_action.sa_handler = SIG_IGN; + sigaction(SIGINT, &signal_action, NULL); + sigaction(SIGHUP, &signal_action, &signal_action_hup); + signal_action.sa_handler = quit_pam; + sigaction(SIGHUP, &signal_action, NULL); + sigaction(SIGTERM, &signal_action, &signal_action_term); + + for (env = pam_getenvlist(handle); env && *env; env++) { + if (putenv(*env)) { + pam_setcred(handle, PAM_DELETE_CRED); + pam_end(handle, pam_close_session(handle, 0)); + sleep(ERROR_SLEEP); + _exit(1); + } + } } /** * Close PAM session */ -void close_session_pam(void) +void +close_session_pam(void) { - sigaction(SIGHUP, &signal_action_hup, NULL); - sigaction(SIGTERM, &signal_action_term, NULL); - - pam_setcred(handle, PAM_DELETE_CRED); - pam_end(handle, pam_close_session(handle, 0)); + sigaction(SIGHUP, &signal_action_hup, NULL); + sigaction(SIGTERM, &signal_action_term, NULL); + + pam_setcred(handle, PAM_DELETE_CRED); + pam_end(handle, pam_close_session(handle, 0)); } @@ -202,17 +203,18 @@ void close_session_pam(void) * * @param sig The received signal */ -void quit_pam(int sig) +void +quit_pam(int sig) { - if (child_pid) - kill(-child_pid, sig); - if (sig == SIGTERM) - kill(-child_pid, SIGHUP); - - pam_setcred(handle, PAM_DELETE_CRED); - pam_end(handle, pam_close_session(handle, 0)); - - _exit(sig); + if (child_pid) + kill(-child_pid, sig); + if (sig == SIGTERM) + kill(-child_pid, SIGHUP); + + pam_setcred(handle, PAM_DELETE_CRED); + pam_end(handle, pam_close_session(handle, 0)); + + _exit(sig); } @@ -221,25 +223,25 @@ void quit_pam(int sig) * * @return 0: failed, 1: success, 2: auto-authenticated */ -char authenticate_pam(void) +char +authenticate_pam(void) { - int rc; - - if (__failed(rc = pam_authenticate(handle, 0))) - { - /* Clear ISIG (and everything else) to prevent the user - * from skipping the brute force protection sleep. */ - struct termios stty; - tcgetattr(STDIN_FILENO, &stty); - stty.c_lflag = 0; - tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty); - - printf("\nPassphrase incorrect.\nOnly perfect spellers may\nenter this system.\n"); - pam_end(handle, rc); - return 0; - } - - return auto_authenticated ? 2 : 1; + int rc; + + if (__failed(rc = pam_authenticate(handle, 0))) { + /* Clear ISIG (and everything else) to prevent the user + * from skipping the brute force protection sleep. */ + struct termios stty; + tcgetattr(STDIN_FILENO, &stty); + stty.c_lflag = 0; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty); + + printf("\nPassphrase incorrect.\nOnly perfect spellers may\nenter this system.\n"); + pam_end(handle, rc); + return 0; + } + + return auto_authenticated ? 2 : 1; } @@ -252,26 +254,24 @@ char authenticate_pam(void) * @param appdata_ptr (Not used) * @return `PAM_SUCCESS`, `PAM_CONV_ERR` or `PAM_BUF_ERR` */ -int conv_pam(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) +int +conv_pam(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { - int i; - - (void) appdata_ptr; - - *resp = calloc((size_t)num_msg, sizeof(struct pam_response)); - - for (i = 0; i < num_msg; i++) - { - ((*resp) + i)->resp = NULL; - ((*resp) + i)->resp_retcode = 0; - - if ((**(msg + i)).msg_style == PAM_PROMPT_ECHO_OFF) - { - (*resp + i)->resp = passphrase_reader(); - auto_authenticated = 0; + int i; + + (void) appdata_ptr; + + *resp = calloc((size_t)num_msg, sizeof(struct pam_response)); + + for (i = 0; i < num_msg; i++) { + (*resp)[i].resp = NULL; + (*resp)[i].resp_retcode = 0; + + if ((**msg[i]).msg_style == PAM_PROMPT_ECHO_OFF) { + (*resp)[i].resp = passphrase_reader(); + auto_authenticated = 0; + } } - } - - return PAM_SUCCESS; -} + return PAM_SUCCESS; +} diff --git a/src/auth/pam.h b/src/auth/pam.h index ecfe03a..0b85631 100644 --- a/src/auth/pam.h +++ b/src/auth/pam.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +23,11 @@ /** * Initialise PAM * - * @param remote The remote computer, {@code NULL} for local login + * @param remote The remote computer, `NULL` for local login * @param username The username of the user to log in to * @param reader Function that can be used to read a passphrase from the terminal */ -void initialise_pam(char* remote, char* username, char* (*reader)(void)); +void initialise_pam(char *remote, char *username, char *(*reader)(void)); /** * Verify that the account may be used @@ -53,4 +53,3 @@ char authenticate_pam(void); #endif - diff --git a/src/cerberus.c b/src/cerberus.c index 0cd06b4..9fccbf9 100644 --- a/src/cerberus.c +++ b/src/cerberus.c @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,7 +72,7 @@ static char skip_auth = 0; /** * The passphrase */ -char* passphrase = NULL; +char *passphrase = NULL; #endif @@ -81,59 +81,59 @@ char* passphrase = NULL; * * @param s The number of seconds to sleep */ -static void xsleep(unsigned int s) +static void +xsleep(unsigned int s) { - sigset_t sigset; - sigset_t old_sigset; - - sigfillset(&sigset); - sigprocmask(SIG_BLOCK, &sigset, &old_sigset); - - while ((s = sleep(s))); - - sigprocmask(SIG_SETMASK, &old_sigset, NULL); + sigset_t sigset; + sigset_t old_sigset; + + sigfillset(&sigset); + sigprocmask(SIG_BLOCK, &sigset, &old_sigset); + + while ((s = sleep(s))); + + sigprocmask(SIG_SETMASK, &old_sigset, NULL); } /** - * Mane method + * Main method * * @param argc The number of command line arguments * @param argv The command line arguments * @return Return code */ -int main(int argc, char** argv) +int +main(int argc, char **argv) { - char* tty_device = ttyname(STDIN_FILENO); - - do_login(argc, argv); - - /* Ignore signals */ - signal(SIGQUIT, SIG_IGN); - signal(SIGINT, SIG_IGN); - - /* Wait for the login shell and all grandchildren to exit */ - while ((wait(NULL) == -1) && (errno == EINTR)) - ; - - /* Regain access to the terminal */ - if (tty_device) - { - int fd = open(tty_device, O_RDWR | O_NONBLOCK); - if (fd != 0) dup2(fd, 0); - if (fd != 1) dup2(fd, 1); - if (fd != 2) dup2(fd, 2); - } - - /* Reset terminal ownership and mode */ - chown_tty(0, tty_group, 0); - - /* Close login session */ - close_login_session(); - - /* Run logout hook */ - exec_hook(HOOK_LOGOUT, argc, argv); - return 0; + char *tty_device = ttyname(STDIN_FILENO); + + do_login(argc, argv); + + /* Ignore signals */ + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + + /* Wait for the login shell and all grandchildren to exit */ + while (wait(NULL) == -1 && errno == EINTR); + + /* Regain access to the terminal */ + if (tty_device) { + int fd = open(tty_device, O_RDWR | O_NONBLOCK); + if (fd != 0) dup2(fd, 0); + if (fd != 1) dup2(fd, 1); + if (fd != 2) dup2(fd, 2); + } + + /* Reset terminal ownership and mode */ + chown_tty(0, tty_group, 0); + + /* Close login session */ + close_login_session(); + + /* Run logout hook */ + exec_hook(HOOK_LOGOUT, argc, argv); + return 0; } @@ -144,33 +144,32 @@ int main(int argc, char** argv) * @param argc The number of command line arguments * @param argv The command line arguments */ -void exec_hook(int hook, int argc, char** argv) +void +exec_hook(int hook, int argc, char **argv) { - static char cerberusrc[] = CERBERUSRC; - static char hooks[][7] = - { - [HOOK_LOGIN] = "login", - [HOOK_LOGOUT] = "logout", - [HOOK_DENIED] = "denied", - [HOOK_VERIFY] = "verify", - }; - char** args; - int i; - - args = malloc((size_t)(argc + 2) * sizeof(char*)); - if (args == NULL) - { - perror("malloc"); - return; - } - - args[0] = cerberusrc; - args[1] = hooks[hook]; - for (i = 1; i < argc; i++) - args[i + 1] = argv[i]; - args[argc + 1] = NULL; - - execv(CERBERUSRC, args); + static char cerberusrc[] = CERBERUSRC; + static char hooks[][7] = { + [HOOK_LOGIN] = "login", + [HOOK_LOGOUT] = "logout", + [HOOK_DENIED] = "denied", + [HOOK_VERIFY] = "verify", + }; + char **args; + int i; + + args = malloc((size_t)(argc + 2) * sizeof(char*)); + if (!args) { + perror("malloc"); + return; + } + + args[0] = cerberusrc; + args[1] = hooks[hook]; + for (i = 1; i < argc; i++) + args[i + 1] = argv[i]; + args[argc + 1] = NULL; + + execv(CERBERUSRC, args); } @@ -182,30 +181,28 @@ void exec_hook(int hook, int argc, char** argv) * @param argv The command line arguments * @return The exit value of the hook */ -int fork_exec_wait_hook(int hook, int argc, char** argv) +int +fork_exec_wait_hook(int hook, int argc, char **argv) { - pid_t pid, reaped; - int status; - pid = fork(); - if (pid == -1) - return -1; - if (pid == 0) - { - close(STDIN_FILENO); - exec_hook(hook, argc, argv); - _exit(138); - } - for (;;) - { - reaped = wait(&status); - if (reaped == -1) - { - perror("wait"); - return -1; + pid_t pid, reaped; + int status; + pid = fork(); + if (pid == -1) + return -1; + if (pid == 0) { + close(STDIN_FILENO); + exec_hook(hook, argc, argv); + _exit(138); + } + for (;;) { + reaped = wait(&status); + if (reaped == -1) { + perror("wait"); + return -1; + } + if (reaped == pid) + return status == 138 ? -1 : status; } - if (reaped == pid) - return status == 138 ? -1 : status; - } } @@ -215,246 +212,229 @@ int fork_exec_wait_hook(int hook, int argc, char** argv) * @param argc The number of command line arguments * @param argv The command line arguments */ -void do_login(int argc, char** argv) +void +do_login(int argc, char **argv) { - char* username = NULL; - char* hostname = NULL; - char preserve_env = 0; - int ret; - #ifdef USE_TTY_GROUP - struct group* group; - #endif - - - #if AUTH > 0 - /* Disable echoing */ - passphrase_disable_echo1(STDIN_FILENO /* Will be the terminal. */); - /* This should be done as early and quickly as possible so as little - as possible of the passphrase gets leaked to the output if the user - begins entering the passphrase directly after the username. */ - #endif - - - /* Set process group ID */ - setpgrp(); - - - /* Parse command line arguments */ - { - char double_dashed = 0; - char hostname_on_next = 0; - int i; - for (i = 1; i < argc; i++) - { - char *arg = *(argv + i); - char c; - - if (*arg == 0) - ; - else if ((*arg == '-') && (double_dashed == 0)) - while ((c = *(++arg))) - if (c == 'H') - ; - else if (c == 'V') - _exit(2); - else if (c == 'p') - preserve_env = 1; - else if (c == 'h') - { - if (*(arg + 1)) - hostname = arg + 1; - else - hostname_on_next = 1; - break; - } - else if (c == 'f') - { - if (*(arg + 1)) - username = arg + 1; - skip_auth = 1; - break; - } - else if (c == '-') - { - double_dashed = 1; - break; - } - else - printf("%s: unrecognised options: -%c\n", *argv, c); - else if (hostname_on_next) - { - hostname = arg; - hostname_on_next = 0; - } - else - username = arg; - } - } - - - /* Change that a username has been specified */ - if (username == NULL) - { - printf("%s: no username specified\n", *argv); - sleep(ERROR_SLEEP); - _exit(2); - } - - - /* Verify that the user may login */ - ret = fork_exec_wait_hook(HOOK_VERIFY, argc, argv); - if ((ret >= 0) && WIFEXITED(ret) && (WEXITSTATUS(ret) == 1)) - { - sleep(ERROR_SLEEP); - _exit(2); - } - - - if (skip_auth) - { - /* Reset terminal settings */ - passphrase_reenable_echo1(STDIN_FILENO); - - /* Only root may bypass authentication */ - if (getuid()) + char *username = NULL; + char *hostname = NULL; + char preserve_env = 0; + int ret; +#ifdef USE_TTY_GROUP + struct group *group; +#endif + + +#if AUTH > 0 + /* Disable echoing */ + passphrase_disable_echo1(STDIN_FILENO /* Will be the terminal. */); + /* This should be done as early and quickly as possible so as little + as possible of the passphrase gets leaked to the output if the user + begins entering the passphrase directly after the username. */ +#endif + + + /* Set process group ID */ + setpgrp(); + + + /* Parse command line arguments */ { - printf("%s: only root by use the -f option\n", *argv); - sleep(ERROR_SLEEP); - _exit(2); + char double_dashed = 0; + char hostname_on_next = 0; + int i; + for (i = 1; i < argc; i++) { + char *arg = *(argv + i); + char c; + + if (*arg == 0) { + continue; + } else if (*arg == '-' && !double_dashed) { + while ((c = *++arg)) + if (c == 'H') { + continue; + } else if (c == 'V') { + _exit(2); + } else if (c == 'p') { + preserve_env = 1; + } else if (c == 'h') { + if (arg[1]) + hostname = arg + 1; + else + hostname_on_next = 1; + break; + } else if (c == 'f') { + if (arg[1]) + username = arg + 1; + skip_auth = 1; + break; + } else if (c == '-') { + double_dashed = 1; + break; + } else { + printf("%s: unrecognised options: -%c\n", *argv, c); + } + } else if (hostname_on_next) { + hostname = arg; + hostname_on_next = 0; + } else { + username = arg; + } + } + } + + + /* Change that a username has been specified */ + if (!username) { + printf("%s: no username specified\n", *argv); + sleep(ERROR_SLEEP); + _exit(2); + } + + + /* Verify that the user may login */ + ret = fork_exec_wait_hook(HOOK_VERIFY, argc, argv); + if (ret >= 0 && WIFEXITED(ret) && WEXITSTATUS(ret) == 1) { + sleep(ERROR_SLEEP); + _exit(2); + } + + + if (skip_auth) { + /* Reset terminal settings */ + passphrase_reenable_echo1(STDIN_FILENO); + + /* Only root may bypass authentication */ + if (getuid()) { + printf("%s: only root by use the -f option\n", *argv); + sleep(ERROR_SLEEP); + _exit(2); + } + } else { + /* Print ant we want a passphrase, if -f has not been used */ + printf("Passphrase: "); + fflush(stdout); } - } - /* Print ant we want a passphrase, if -f has not been used */ - else - { - printf("Passphrase: "); - fflush(stdout); - } - /* Done early to make to program look like it is even faster than it is */ - - - /* Make sure nopony is spying */ - #ifdef USE_TTY_GROUP - if ((group = getgrnam(TTY_GROUP))) - tty_group = group->gr_gid; - endgrent(); - #endif - secure_tty(tty_group); - - #if AUTH > 0 - if (skip_auth == 0) - { - /* Redisable echoing */ - passphrase_disable_echo1(STDIN_FILENO); - } - #endif - - - /* Set up clean quiting and time out */ - signal(SIGALRM, timeout_quit); - signal(SIGQUIT, user_quit); - signal(SIGINT, user_quit); - siginterrupt(SIGALRM, 1); - siginterrupt(SIGQUIT, 1); - siginterrupt(SIGINT, 1); - #if AUTH > 0 - alarm(TIMEOUT_SECONDS); - #endif - - - /* Get user information */ - if ((entry = getpwnam(username)) == NULL) - { - if (errno == EIO /* seriously...? */ || !errno) - printf("User does not exist\n"); - else if (errno) - perror("getpwnam"); - sleep(ERROR_SLEEP); - _exit(1); - } - endpwent(); - username = entry->pw_name; - - - /* Verify passphrase or other token, if -f has not been used */ - ret = 2; - #if AUTH == 0 - (void) hostname; - #else - initialise_login(hostname, username, read_passphrase); - if (skip_auth == 0) - ret = authenticate_login(); - /* Passphrase entered, turn off timeout */ - alarm(0); - #endif - if (ret == 2) - printf("(auto-authenticated)\n"); - if (ret == 0) - { - preexit(); - fork_exec_wait_hook(HOOK_DENIED, argc, argv); - xsleep(FAILURE_SLEEP); - _exit(1); - } - - preexit(); - - - /* Verify account, such as that it is enabled */ - verify_account(); - - - /* Run login hook */ - fork_exec_wait_hook(HOOK_LOGIN, argc, argv); - - - /* Partial login */ - chown_tty(entry->pw_uid, tty_group, 0); - chdir_home(entry); - ensure_shell(entry); - set_environ(entry, preserve_env); - open_login_session(); - - - /* Stop signal handling */ - signal(SIGALRM, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTSTP, SIG_IGN); - - - child_pid = fork(); - /* vfork cannot be used as the child changes the user, - the parent would not be able to chown the TTY */ - - if (child_pid == -1) - { - perror("fork"); - close_login_session(); - sleep(ERROR_SLEEP); - _exit(1); - } - else if (child_pid) - return; /* Do not go beyond this in the parent */ - - /* In case the shell does not do this */ - setsid(); - - /* Set controlling terminal */ - if (ioctl(STDIN_FILENO, TIOCSCTTY, 1)) - perror("TIOCSCTTY"); - signal(SIGINT, SIG_DFL); - - /* Partial login */ - ret = entry->pw_uid - ? initgroups(username, entry->pw_gid) /* supplemental groups for user, can require network */ - : setgroups(0, NULL); /* supplemental groups for root, does not require netork */ - if (ret == -1) - { - perror(entry->pw_uid ? "initgroups" : "setgroups"); - sleep(ERROR_SLEEP); - _exit(1); - } - set_user(entry); - exec_shell(entry); + /* Done early to make to program look like it is even faster than it is */ + + + /* Make sure nobody is spying */ +#ifdef USE_TTY_GROUP + if ((group = getgrnam(TTY_GROUP))) + tty_group = group->gr_gid; + endgrent(); +#endif + secure_tty(tty_group); + +#if AUTH > 0 + if (!skip_auth) { + /* Redisable echoing */ + passphrase_disable_echo1(STDIN_FILENO); + } +#endif + + + /* Set up clean quiting and time out */ + signal(SIGALRM, timeout_quit); + signal(SIGQUIT, user_quit); + signal(SIGINT, user_quit); + siginterrupt(SIGALRM, 1); + siginterrupt(SIGQUIT, 1); + siginterrupt(SIGINT, 1); +#if AUTH > 0 + alarm(TIMEOUT_SECONDS); +#endif + + + /* Get user information */ + if (!(entry = getpwnam(username))) { + if (errno == EIO /* seriously...? */ || !errno) + printf("User does not exist\n"); + else if (errno) + perror("getpwnam"); + sleep(ERROR_SLEEP); + _exit(1); + } + endpwent(); + username = entry->pw_name; + + + /* Verify passphrase or other token, if -f has not been used */ + ret = 2; +#if AUTH == 0 + (void) hostname; +#else + initialise_login(hostname, username, read_passphrase); + if (skip_auth == 0) + ret = authenticate_login(); + /* Passphrase entered, turn off timeout */ + alarm(0); +#endif + if (ret == 2) + printf("(auto-authenticated)\n"); + if (ret == 0) { + preexit(); + fork_exec_wait_hook(HOOK_DENIED, argc, argv); + xsleep(FAILURE_SLEEP); + _exit(1); + } + + preexit(); + + + /* Verify account, such as that it is enabled */ + verify_account(); + + + /* Run login hook */ + fork_exec_wait_hook(HOOK_LOGIN, argc, argv); + + + /* Partial login */ + chown_tty(entry->pw_uid, tty_group, 0); + chdir_home(entry); + ensure_shell(entry); + set_environ(entry, preserve_env); + open_login_session(); + + + /* Stop signal handling */ + signal(SIGALRM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTSTP, SIG_IGN); + + + child_pid = fork(); + /* vfork cannot be used as the child changes the user, + the parent would not be able to chown the TTY */ + + if (child_pid == -1) { + perror("fork"); + close_login_session(); + sleep(ERROR_SLEEP); + _exit(1); + } else if (child_pid) { + return; /* Do not go beyond this in the parent */ + } + + /* In case the shell does not do this */ + setsid(); + + /* Set controlling terminal */ + if (ioctl(STDIN_FILENO, TIOCSCTTY, 1)) + perror("TIOCSCTTY"); + signal(SIGINT, SIG_DFL); + + /* Partial login */ + ret = entry->pw_uid + ? initgroups(username, entry->pw_gid) /* supplemental groups for user, can require network */ + : setgroups(0, NULL); /* supplemental groups for root, does not require netork */ + if (ret == -1) { + perror(entry->pw_uid ? "initgroups" : "setgroups"); + sleep(ERROR_SLEEP); + _exit(1); + } + set_user(entry); + exec_shell(entry); } @@ -463,16 +443,16 @@ void do_login(int argc, char** argv) /** * Called before the process exits, to do cleanup */ -void preexit(void) +void +preexit(void) { - if (skip_auth == 0) - { - /* Wipe and free the passphrase from the memory */ - destroy_passphrase(); - - /* Reset terminal settings */ - passphrase_reenable_echo1(STDIN_FILENO); - } + if (!skip_auth) { + /* Wipe and free the passphrase from the memory */ + destroy_passphrase(); + + /* Reset terminal settings */ + passphrase_reenable_echo1(STDIN_FILENO); + } } @@ -481,16 +461,16 @@ void preexit(void) * * @return The entered passphrase */ -char* read_passphrase(void) +char * +read_passphrase(void) { - passphrase = passphrase_read2(STDIN_FILENO, PASSPHRASE_READ_EXISTING); - if (passphrase == NULL) - { - perror("passphrase_read"); - sleep(ERROR_SLEEP); - _exit(1); - } - return passphrase; + passphrase = passphrase_read2(STDIN_FILENO, PASSPHRASE_READ_EXISTING); + if (!passphrase) { + perror("passphrase_read"); + sleep(ERROR_SLEEP); + _exit(1); + } + return passphrase; } #endif @@ -503,14 +483,14 @@ char* read_passphrase(void) /** * Wipe and free the passphrase if it is allocated */ -void destroy_passphrase(void) +void +destroy_passphrase(void) { - if (passphrase) - { - passphrase_wipe(passphrase, strlen(passphrase)); - free(passphrase); - passphrase = NULL; - } + if (passphrase) { + passphrase_wipe(passphrase, strlen(passphrase)); + free(passphrase); + passphrase = NULL; + } } @@ -520,8 +500,8 @@ void destroy_passphrase(void) #ifdef __GNUC__ __attribute__((destructor)) #endif -static void passphrase_destructor(void) +static void +passphrase_destructor(void) { - destroy_passphrase(); + destroy_passphrase(); } - diff --git a/src/cerberus.h b/src/cerberus.h index a81b8a0..038ce2a 100644 --- a/src/cerberus.h +++ b/src/cerberus.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +20,18 @@ #define CERBERUS_CERBERUS_H -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <pwd.h> -#include <errno.h> -#include <termios.h> -#include <fcntl.h> -#include <sys/wait.h> #include <sys/ioctl.h> #include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> #include <grp.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> #if AUTH > 0 #include <passphrase.h> @@ -50,13 +50,13 @@ #endif -int fork_exec_wait_hook(int hook, int argc, char** argv); -void exec_hook(int hook, int argc, char** argv); -void do_login(int argc, char** argv); +int fork_exec_wait_hook(int hook, int argc, char **argv); +void exec_hook(int hook, int argc, char **argv); +void do_login(int argc, char **argv); #if AUTH > 0 void preexit(void); -char* read_passphrase(void); +char *read_passphrase(void); #else #define preexit() /* do nothing */ #define read_passphrase() NULL @@ -69,4 +69,3 @@ void destroy_passphrase(void); #endif - diff --git a/src/config.h b/src/config.h index aa144b2..761be58 100644 --- a/src/config.h +++ b/src/config.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,4 +58,3 @@ #endif - diff --git a/src/login.c b/src/login.c index e99b77f..3cb0877 100644 --- a/src/login.c +++ b/src/login.c @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ /** * The environment variables */ -extern char** environ; +extern char **environ; /** @@ -38,19 +38,18 @@ extern char** environ; * * @param entry The user entry in the password file */ -void set_user(struct passwd* entry) +void +set_user(struct passwd *entry) { - if (setgid(entry->pw_gid) && entry->pw_gid) - { - perror("setgid"); - _exit(1); - } - - if (setuid(entry->pw_uid) && entry->pw_uid) - { - perror("setuid"); - _exit(1); - } + if (setgid(entry->pw_gid) && entry->pw_gid) { + perror("setgid"); + _exit(1); + } + + if (setuid(entry->pw_uid) && entry->pw_uid) { + perror("setuid"); + _exit(1); + } } @@ -59,19 +58,18 @@ void set_user(struct passwd* entry) * * @param entry The user entry in the password file */ -void chdir_home(struct passwd* entry) +void +chdir_home(struct passwd *entry) { - if (chdir(entry->pw_dir)) - { - perror("chdir"); - if (chdir(DEFAULT_HOME)) - { - perror("chdir"); - sleep(ERROR_SLEEP); - _exit(1); + if (chdir(entry->pw_dir)) { + perror("chdir"); + if (chdir(DEFAULT_HOME)) { + perror("chdir"); + sleep(ERROR_SLEEP); + _exit(1); + } + entry->pw_dir = strdup(DEFAULT_HOME); } - entry->pw_dir = strdup(DEFAULT_HOME); - } } @@ -80,10 +78,11 @@ void chdir_home(struct passwd* entry) * * @param entry The user entry in the password file */ -void ensure_shell(struct passwd* entry) +void +ensure_shell(struct passwd *entry) { - if ((entry->pw_shell && *(entry->pw_shell)) == 0) - entry->pw_shell = strdup(DEFAULT_SHELL); + if (!entry->pw_shell || !*entry->pw_shell) + entry->pw_shell = strdup(DEFAULT_SHELL); } @@ -93,47 +92,43 @@ void ensure_shell(struct passwd* entry) * @param entry The user entry in the password file * @param preserve_env Whether to preserve the environment */ -void set_environ(struct passwd* entry, char preserve_env) +void +set_environ(struct passwd *entry, char preserve_env) { - char* _term = getenv("TERM"); - char* term = NULL; - if (_term) - { - size_t n = 0, i; - while (*(_term + n++)) - ; - term = malloc(n * sizeof(char)); - if (term == NULL) - { - perror("malloc"); - sleep(ERROR_SLEEP); - _exit(1); + char *_term = getenv("TERM"); + char *term = NULL; + if (_term) { + size_t n = 0, i; + while (_term[n++]) ; + term = malloc(n * sizeof(char)); + if (!term) { + perror("malloc"); + sleep(ERROR_SLEEP); + _exit(1); + } + for (i = 0; i < n; i++) + *(term + i) = *(_term + i); } - for (i = 0; i < n; i++) - *(term + i) = *(_term + i); - } - - if (preserve_env == 0) - { - environ = malloc(sizeof(char*)); - if (environ == NULL) - { - perror("malloc"); - sleep(ERROR_SLEEP); - _exit(1); + + if (!preserve_env) { + environ = malloc(sizeof(char*)); + if (!environ) { + perror("malloc"); + sleep(ERROR_SLEEP); + _exit(1); + } + *environ = NULL; } - *environ = NULL; - } - - setenv("HOME", entry->pw_dir, 1); - setenv("USER", entry->pw_name, 1); - setenv("LOGUSER", entry->pw_name, 1); - setenv("SHELL", entry->pw_shell, 1); - setenv("TERM", term ?: DEFAULT_TERM, 1); - setenv("PATH", entry->pw_uid ? PATH : PATH_ROOT, 1); - - if (term) - free(term); + + setenv("HOME", entry->pw_dir, 1); + setenv("USER", entry->pw_name, 1); + setenv("LOGUSER", entry->pw_name, 1); + setenv("SHELL", entry->pw_shell, 1); + setenv("TERM", term ?: DEFAULT_TERM, 1); + setenv("PATH", entry->pw_uid ? PATH : PATH_ROOT, 1); + + if (term) + free(term); } @@ -142,59 +137,53 @@ void set_environ(struct passwd* entry, char preserve_env) * * @param entry The user entry in the password file */ -void exec_shell(struct passwd* entry) +void +exec_shell(struct passwd *entry) { - int child_argc = 0; - char** child_argv = malloc(5 * sizeof(char*)); - size_t n = 0; - char* sh = entry->pw_shell; - char* login_sh; - - while (*(sh + n++)) - ; - - login_sh = malloc((n + (strchr(sh, ' ') ? 5 : 1)) * sizeof(char)); - if (login_sh == NULL) - { - perror("malloc"); - sleep(ERROR_SLEEP); - _exit(1); - } - - if (strchr(sh, ' ')) - { - login_sh += 5; - strcpy(login_sh, "exec "); - *(login_sh + n) = 0; - - *(child_argv + child_argc++) = strdup(DEFAULT_SHELL); - *(child_argv + child_argc++) = strdup("-" DEFAULT_SH); - *(child_argv + child_argc++) = strdup("-c"); - *(child_argv + child_argc++) = login_sh - 5; - } - else - { - ssize_t i; - for (i = (ssize_t)n - 1; i >= 0; i--) - if (*(sh + i) == '/') - { - i++; - break; - } - - login_sh = malloc((n + 1) * sizeof(char)); - *login_sh++ = '-'; - strcpy(login_sh, sh + i); - *(login_sh + n) = 0; - - *(child_argv + child_argc++) = sh; - *(child_argv + child_argc++) = login_sh - 1; - } - - *(child_argv + child_argc) = NULL; - execvp(*child_argv, child_argv + 1); - perror("execvp"); - sleep(ERROR_SLEEP); - _exit(1); -} + int child_argc = 0; + char **child_argv = malloc(5 * sizeof(char *)); + size_t n = 0; + char *sh = entry->pw_shell; + char *login_sh; + + while (sh[n++]) ; + login_sh = malloc((n + (strchr(sh, ' ') ? 5 : 1)) * sizeof(char)); + if (!login_sh) { + perror("malloc"); + sleep(ERROR_SLEEP); + _exit(1); + } + + if (strchr(sh, ' ')) { + login_sh += 5; + strcpy(login_sh, "exec "); + login_sh[n] = 0; + + child_argv[child_argc++] = strdup(DEFAULT_SHELL); + child_argv[child_argc++] = strdup("-" DEFAULT_SH); + child_argv[child_argc++] = strdup("-c"); + child_argv[child_argc++] = login_sh - 5; + } else { + ssize_t i; + for (i = (ssize_t)n - 1; i >= 0; i--) + if (sh[i] == '/') { + i++; + break; + } + + login_sh = malloc((n + 1U) * sizeof(char)); + *login_sh++ = '-'; + strcpy(login_sh, &sh[i]); + login_sh[n] = 0; + + child_argv[child_argc++] = sh; + child_argv[child_argc++] = &login_sh[-1]; + } + + child_argv[child_argc] = NULL; + execvp(child_argv[0], &child_argv[1]); + perror("execvp"); + sleep(ERROR_SLEEP); + _exit(1); +} diff --git a/src/login.h b/src/login.h index a672434..ecf4107 100644 --- a/src/login.h +++ b/src/login.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,21 +27,21 @@ * * @param entry The user entry in the password file */ -void set_user(struct passwd* entry); +void set_user(struct passwd *entry); /** * Change directory to the user's home directory * * @param entry The user entry in the password file */ -void chdir_home(struct passwd* entry); +void chdir_home(struct passwd *entry); /** * Make sure the shell to use is definied * * @param entry The user entry in the password file */ -void ensure_shell(struct passwd* entry); +void ensure_shell(struct passwd *entry); /** * Set environment variables @@ -49,7 +49,7 @@ void ensure_shell(struct passwd* entry); * @param entry The user entry in the password file * @param preserve_env Whether to preserve the environment */ -void set_environ(struct passwd* entry, char preserve_env); +void set_environ(struct passwd *entry, char preserve_env); /** * Replace the current image with the user's login shell @@ -59,8 +59,7 @@ void set_environ(struct passwd* entry, char preserve_env); #ifdef __GNUC__ __attribute__((noreturn)) #endif -void exec_shell(struct passwd* entry); +void exec_shell(struct passwd *entry); #endif - @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,15 +31,16 @@ * * @param signal The signal the program received */ -void timeout_quit(int signal) +void +timeout_quit(int signal) { - (void) signal; - printf("\nTimed out.\n"); - #if AUTH != 0 - passphrase_reenable_echo1(STDIN_FILENO); - #endif - sleep(ERROR_SLEEP); - _exit(10); + (void) signal; + printf("\nTimed out.\n"); +#if AUTH != 0 + passphrase_reenable_echo1(STDIN_FILENO); +#endif + sleep(ERROR_SLEEP); + _exit(10); } @@ -48,13 +49,13 @@ void timeout_quit(int signal) * * @param signal The signal the program received */ -void user_quit(int signal) +void +user_quit(int signal) { - (void) signal; - printf("\n"); - #if AUTH != 0 - passphrase_reenable_echo1(STDIN_FILENO); - #endif - _exit(130); + (void) signal; + printf("\n"); +#if AUTH != 0 + passphrase_reenable_echo1(STDIN_FILENO); +#endif + _exit(130); } - @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,4 +42,3 @@ void user_quit(int signal); #endif - diff --git a/src/security.c b/src/security.c index 9a1faf3..54ab501 100644 --- a/src/security.c +++ b/src/security.c @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,11 +39,12 @@ * * @param str The function that failed. */ -static void fail(const char* str) +static +void fail(const char *str) { - perror(str); - sleep(ERROR_SLEEP); - _exit(1); + perror(str); + sleep(ERROR_SLEEP); + _exit(1); } @@ -52,44 +53,45 @@ static void fail(const char* str) * * @param group The group, -1 for unchanged */ -void secure_tty(gid_t group) +void +secure_tty(gid_t group) { - struct termios tty; - struct termios saved_tty; - char* tty_device; - int fd, i; - - /* Set ownership of this TTY to root:root */ - chown_tty(0, group, 1); - - /* Get TTY name for last part of this functions */ - tty_device = ttyname(STDIN_FILENO); - - /* Kill other processes on this TTY */ - tcgetattr(STDIN_FILENO, &tty); - saved_tty = tty; - tty.c_cflag &= (tcflag_t)~HUPCL; - tcsetattr(0, TCSANOW, &tty); - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - signal(SIGHUP, SIG_IGN); - vhangup(); - signal(SIGHUP, SIG_DFL); - - /* Restore terminal and TTY modes */ - fd = open(tty_device, O_RDWR | O_NONBLOCK); - if (fd == -1) - fail("open"); - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); - for (i = 0; i < fd; i++) - close(i); - for (i = 0; i < 3; i++) - if (i != fd) - dup2(fd, i); - if (fd > 2) - close(fd); - tcgetattr(STDIN_FILENO, &saved_tty); + struct termios tty; + struct termios saved_tty; + char *tty_device; + int fd, i; + + /* Set ownership of this TTY to root:root */ + chown_tty(0, group, 1); + + /* Get TTY name for last part of this functions */ + tty_device = ttyname(STDIN_FILENO); + + /* Kill other processes on this TTY */ + tcgetattr(STDIN_FILENO, &tty); + saved_tty = tty; + tty.c_cflag &= (tcflag_t)~HUPCL; + tcsetattr(0, TCSANOW, &tty); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + signal(SIGHUP, SIG_IGN); + vhangup(); + signal(SIGHUP, SIG_DFL); + + /* Restore terminal and TTY modes */ + fd = open(tty_device, O_RDWR | O_NONBLOCK); + if (fd == -1) + fail("open"); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); + for (i = 0; i < fd; i++) + close(i); + for (i = 0; i < 3; i++) + if (i != fd) + dup2(fd, i); + if (fd > 2) + close(fd); + tcgetattr(STDIN_FILENO, &saved_tty); } @@ -100,57 +102,54 @@ void secure_tty(gid_t group) * @param group The group, -1 for unchanged * @param with_fail Abort on failure */ -void chown_tty(uid_t owner, gid_t group, char with_fail) +void +chown_tty(uid_t owner, gid_t group, char with_fail) { - #if defined(OWN_VCSA) || defined(OWN_VCS) - struct vt_stat vtstat; - #endif - - /* Set ownership of this TTY */ - if (fchown(STDIN_FILENO, owner, group) && with_fail) - fail("fchown"); - - /* Restrict others from using this TTY */ - if (fchmod(STDIN_FILENO, TTY_PERM) && with_fail) - fail("fchmod"); - - /* Also do the above for /dev/vcs[a][0-9]+ */ - #if defined(OWN_VCSA) || defined(OWN_VCS) - if (ioctl(STDIN_FILENO, VT_GETSTATE, &vtstat) == 0) - { - int n = vtstat.v_active; - char _vcs[VCS_LEN + 6]; - char _vcsa[VCSA_LEN + 6]; - - char* vcs = _vcs; - char* vcsa = _vcsa; - vcs += VCS_LEN + 6; - vcsa += VCSA_LEN + 6; - - if (n) - { - *--vcs = *--vcsa = 0; - while (n) - { - *--vcs = *--vcsa = (char)((n % 10) + '0'); - n /= 10; - } - - vcs -= VCS_LEN; - vcsa -= VCSA_LEN; - strncpy(vcs, VCS, VCS_LEN); - strncpy(vcsa, VCSA, VCSA_LEN); - - #ifdef OWN_VCS - if (chown(vcs, owner, group) && with_fail) fail("chown"); - if (chmod(vcs, TTY_PERM) && with_fail) fail("chmod"); - #endif - #ifdef OWN_VCSA - if (chown(vcsa, owner, group) && with_fail) fail("chown"); - if (chmod(vcsa, TTY_PERM) && with_fail) fail("chmod"); - #endif - } - } - #endif -} +#if defined(OWN_VCSA) || defined(OWN_VCS) + struct vt_stat vtstat; +#endif + + /* Set ownership of this TTY */ + if (fchown(STDIN_FILENO, owner, group) && with_fail) + fail("fchown"); + + /* Restrict others from using this TTY */ + if (fchmod(STDIN_FILENO, TTY_PERM) && with_fail) + fail("fchmod"); + /* Also do the above for /dev/vcs[a][0-9]+ */ +#if defined(OWN_VCSA) || defined(OWN_VCS) + if (!ioctl(STDIN_FILENO, VT_GETSTATE, &vtstat)) { + int n = vtstat.v_active; + char _vcs[VCS_LEN + 6]; + char _vcsa[VCSA_LEN + 6]; + + char *vcs = _vcs; + char *vcsa = _vcsa; + vcs += VCS_LEN + 6; + vcsa += VCSA_LEN + 6; + + if (n) { + *--vcs = *--vcsa = 0; + while (n) { + *--vcs = *--vcsa = (char)((n % 10) + '0'); + n /= 10; + } + + vcs -= VCS_LEN; + vcsa -= VCSA_LEN; + strncpy(vcs, VCS, VCS_LEN); + strncpy(vcsa, VCSA, VCSA_LEN); + +#ifdef OWN_VCS + if (chown(vcs, owner, group) && with_fail) fail("chown"); + if (chmod(vcs, TTY_PERM) && with_fail) fail("chmod"); +#endif +#ifdef OWN_VCSA + if (chown(vcsa, owner, group) && with_fail) fail("chown"); + if (chmod(vcsa, TTY_PERM) && with_fail) fail("chmod"); +#endif + } + } +#endif +} diff --git a/src/security.h b/src/security.h index d367dc7..3744c9c 100644 --- a/src/security.h +++ b/src/security.h @@ -1,7 +1,7 @@ /** * cerberus – Minimal login program * - * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (maandree@kth.se) + * Copyright © 2013, 2014, 2015, 2016, 2020 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,4 +40,3 @@ void chown_tty(uid_t owner, gid_t group, char with_fail); #endif - |
