mirror of https://github.com/fairyglade/ly
restarted from scratch
parent
244f072d11
commit
d285d558cd
@ -1,13 +0,0 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
@ -1,67 +0,0 @@
|
||||
### Ly - ncurses display manager
|
||||
|
||||
![ly screenshot](https://user-images.githubusercontent.com/5473047/42466218-8cb53d3c-83ae-11e8-8e53-bae3669f959c.png "ly on st")
|
||||
|
||||
This is a lightweight login/display manager for linux made with ncurses.
|
||||
It is based on linux-pam and systemd and was developped in good old C99.
|
||||
This program was designed to be simple, modular and highly configurable.
|
||||
Ly was made for crazy people. If you're not insane, run away.
|
||||
|
||||
### Configuration and installation
|
||||
Ly tries not to reinvent the wheel and uses linux-utils and xorg-xinit
|
||||
instead of providing heavy, incomplete and outdated implementations.
|
||||
Make sure all the following tools and libraries are available on your
|
||||
distribution before going further:
|
||||
- make
|
||||
- a c99 compiler
|
||||
- systemd
|
||||
- linux-pam
|
||||
- ncurses
|
||||
- tput
|
||||
- libX11 (required if you wish to use X)
|
||||
- xorg-xinit (required if you wish to use X)
|
||||
- xorg-xauth (required if you wish to use X)
|
||||
- mcookie (required if you wish to use X)
|
||||
|
||||
You can now configure Ly by editing "src/config.h". Modify "ly.service"
|
||||
as well if you changed the default tty, then build the executable:
|
||||
```
|
||||
make
|
||||
```
|
||||
Check if it works on the tty you configured (default is tty2). You can
|
||||
also run it in terminal emulators, but desktop environments won't start.
|
||||
```
|
||||
sudo build/ly
|
||||
```
|
||||
Then, install Ly and the systemd service file:
|
||||
```
|
||||
sudo make install
|
||||
```
|
||||
Now enable the systemd service to make it spawn on startup:
|
||||
```
|
||||
sudo systemctl enable ly.service
|
||||
```
|
||||
If you need to switch between ttys after Ly's start you also have to
|
||||
disable getty on Ly's tty to prevent "login" from spawning on top of it:
|
||||
```
|
||||
sudo systemctl disable getty@tty2.service
|
||||
```
|
||||
If messages from other services pops-up over the login prompt, you have to edit the service in order to run it last. In order to do this, simply edit the following file:
|
||||
```
|
||||
/usr/lib/systemd/system/ly.service
|
||||
```
|
||||
Just under the "After getty", add another one with your last-launching service. Example on my computer:
|
||||
```
|
||||
After=tlp.service
|
||||
```
|
||||
|
||||
### Controls
|
||||
Use the up and down arrow keys to change the current field, and the
|
||||
left and right arrow keys to change the target desktop environment
|
||||
while on the desktop field (above the username field).
|
||||
|
||||
### Additionnal informations
|
||||
The name "Ly" is a tribute to the fairy from the game Rayman.
|
||||
Ly was tested by oxodao, who is some seriously awesome dude. (you rock!)
|
||||
I wish to thank ncurses, linux-pam, X11 and systemd developers for not
|
||||
providing anything close to a reference or documentation.
|
@ -1,15 +0,0 @@
|
||||
[Unit]
|
||||
Description=ly ncurses display manager
|
||||
After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||
After=getty@tty2.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/ly
|
||||
StandardInput=tty
|
||||
TTYPath=/dev/tty2
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
|
||||
[Install]
|
||||
Alias=display-manager.service
|
@ -1,67 +0,0 @@
|
||||
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||
|
||||
######## CONFIG ########
|
||||
|
||||
NAME := ly
|
||||
|
||||
CXX := cc
|
||||
INSTALL = ln -sf /usr/lib/security/pam_loginuid.so ${DESTDIR}/usr/lib/pam_loginuid.so
|
||||
|
||||
SRCD := src
|
||||
INCD := src
|
||||
BIND := build
|
||||
OBJD := obj
|
||||
DEPD := dep
|
||||
LIBS := -lform -lncurses -lpam -lpam_misc -lX11
|
||||
LIBSUSR = -L/usr/lib/security -l:pam_loginuid.so
|
||||
|
||||
VPATH = $(SRCD) $(INCD) $(OBJD) $(DEPD)
|
||||
|
||||
######## STOP ########
|
||||
|
||||
SRCS := $(call rwildcard,$(SRCD)/,*.c)
|
||||
OBJS := $(patsubst $(SRCD)/%.c,$(OBJD)/%.o,$(SRCS))
|
||||
DEPS := $(patsubst $(SRCD)/%.c,$(DEPD)/%.d,$(SRCS))
|
||||
|
||||
CXXFLAGS := -Wall -g -I$(INCD)
|
||||
LDDFLAGS := $(LIBS)
|
||||
|
||||
.PHONY: all install uninstall clean distclean
|
||||
.PRECIOUS: $(DEPD)/%.d
|
||||
|
||||
all: $(BIND)/$(NAME)
|
||||
|
||||
$(DEPD)/%.d : $(SRCD)/%.c
|
||||
@echo "listing dependencies for source file $<"
|
||||
@mkdir -p $(@D)
|
||||
@$(CXX) $(CXXFLAGS) -M -c $< -o $@
|
||||
|
||||
$(OBJD)/%.o : $(SRCD)/%.c $(DEPD)/%.d
|
||||
@echo "building object $@"
|
||||
@mkdir -p $(@D)
|
||||
@$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(BIND)/$(NAME): $(OBJS)
|
||||
@echo "compiling $@"
|
||||
@mkdir -p $(BIND)
|
||||
@$(CXX) $(CXXFLAGS) $(LDDFLAGS) $(OBJS) -o $(BIND)/$(NAME)
|
||||
|
||||
install : $(BIND)/$(NAME)
|
||||
install -dZ ${DESTDIR}/etc/ly
|
||||
install -DZ $(BIND)/$(NAME) -t ${DESTDIR}/usr/bin
|
||||
install -DZ xsetup.sh -t ${DESTDIR}/etc/ly
|
||||
install -DZ ly.service -t ${DESTDIR}/usr/lib/systemd/system
|
||||
$(INSTALL)
|
||||
|
||||
uninstall:
|
||||
rm -rf ${DESTDIR}/etc/ly
|
||||
rm -f ${DESTDIR}/usr/bin/ly
|
||||
rm -f ${DESTDIR}/usr/lib/systemd/system/ly.service
|
||||
|
||||
clean:
|
||||
@echo "cleaning workspace"
|
||||
@rm -rf $(BIND)
|
||||
@rm -rf $(OBJD)
|
||||
@rm -rf $(DEPD)
|
||||
|
||||
distclean: clean
|
@ -1,47 +0,0 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
/* UI */
|
||||
#define LY_MARGIN_H 3
|
||||
#define LY_MARGIN_V 2
|
||||
|
||||
/* array sizes */
|
||||
#define LY_LIM_LINE_FILE 256
|
||||
#define LY_LIM_LINE_CONSOLE 256
|
||||
#define LY_LIM_PATH 512
|
||||
#define LY_LIM_CMD 256
|
||||
|
||||
/* behaviour */
|
||||
#define LY_CFG_SAVE "/etc/ly/ly.save"
|
||||
#define LY_CFG_READ_SAVE 1
|
||||
#define LY_CFG_WRITE_SAVE 1
|
||||
#define LY_CFG_CLR_USR 0
|
||||
/* 0-10 */
|
||||
#define LY_CFG_FCHANCE 7
|
||||
#define LY_CFG_AUTH_TRIG 10
|
||||
#define LY_CFG_FPS 60
|
||||
#define LY_CFG_FMAX 100
|
||||
|
||||
/* commands */
|
||||
#define LY_CMD_X "/usr/bin/X"
|
||||
#define LY_CMD_TPUT "/usr/bin/tput"
|
||||
#define LY_CMD_HALT "/sbin/shutdown"
|
||||
#define LY_CMD_XINITRC "~/.xinitrc"
|
||||
#define LY_CMD_MCOOKIE "/usr/bin/mcookie"
|
||||
#define LY_CMD_XSETUP "/etc/ly/xsetup.sh"
|
||||
#define LY_XAUTHORITY ".lyxauth"
|
||||
|
||||
/* paths */
|
||||
#define LY_PATH "/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/env"
|
||||
#define LY_PATH_XSESSIONS "/usr/share/xsessions"
|
||||
#define LY_PATH_WSESSIONS "/usr/share/wayland-sessions"
|
||||
|
||||
/* console */
|
||||
#define LY_CONSOLE_DEV "/dev/console"
|
||||
#define LY_CONSOLE_TERM "TERM=linux"
|
||||
#define LY_CONSOLE_TTY 2
|
||||
|
||||
/* pam breaks if you don't set the service name at "login" */
|
||||
#define LY_SERVICE_NAME "login"
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
@ -1,180 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lang.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "desktop.h"
|
||||
|
||||
#define LY_XSESSION_EXEC "Exec="
|
||||
#define LY_XSESSION_NAME "Name="
|
||||
|
||||
// searches a folder
|
||||
short get_desktops(char* sessions_dir, struct delist_t* list, int* remote_count, short x)
|
||||
{
|
||||
/* xsession */
|
||||
FILE* file;
|
||||
DIR* dir;
|
||||
struct dirent* dir_info;
|
||||
/* buffers */
|
||||
char path[LY_LIM_PATH];
|
||||
char* name;
|
||||
char* command;
|
||||
int count = *remote_count;
|
||||
|
||||
if(access(sessions_dir, F_OK) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reads xorg's desktop environments entries */
|
||||
dir = opendir(sessions_dir);
|
||||
|
||||
/* exits if the folder can't be read */
|
||||
if(!dir)
|
||||
{
|
||||
error_print(LY_ERR_DELIST);
|
||||
end_list(list, count);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* cycles through the folder */
|
||||
while((dir_info = readdir(dir)))
|
||||
{
|
||||
/* gets rid of ".", ".." and ".*" files */
|
||||
if((dir_info->d_name)[0] == '.')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* opens xsession file */
|
||||
snprintf(path, sizeof(path), "%s/%s", sessions_dir,
|
||||
dir_info->d_name);
|
||||
file = fopen(path, "r");
|
||||
|
||||
/* stops the entire procedure if the file can't be read */
|
||||
if(!file)
|
||||
{
|
||||
error_print(LY_ERR_DELIST);
|
||||
closedir(dir);
|
||||
break;
|
||||
}
|
||||
|
||||
/* reads xsession file */
|
||||
name = NULL;
|
||||
command = NULL;
|
||||
get_props(file, &name, &command);
|
||||
|
||||
/* frees memory when the entries are incomplete */
|
||||
if((name && !command) || (!name && command))
|
||||
{
|
||||
free(name ? name : command);
|
||||
break;
|
||||
}
|
||||
|
||||
/* adds the new entry to the list */
|
||||
list->names = realloc(list->names,
|
||||
(count + 2) * (sizeof * (list->names)));
|
||||
list->names[count] = name;
|
||||
list->props = realloc(list->props,
|
||||
(count + 1) * (sizeof * (list->props)));
|
||||
list->props[count].cmd = command;
|
||||
list->props[count].type = x ? xorg : wayland;
|
||||
++count;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
*remote_count = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns a list containing all the DE for all the display servers */
|
||||
struct delist_t* list_de(void)
|
||||
{
|
||||
/* de list */
|
||||
int count = 2;
|
||||
short errors = 0;
|
||||
struct delist_t* list = init_list(count);
|
||||
|
||||
if(get_desktops(LY_PATH_XSESSIONS, list, &count, true) != 0)
|
||||
{
|
||||
++errors;
|
||||
}
|
||||
|
||||
if(get_desktops(LY_PATH_WSESSIONS, list, &count, false))
|
||||
{
|
||||
++errors;
|
||||
}
|
||||
|
||||
if(errors > 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end_list(list, count);
|
||||
return list;
|
||||
}
|
||||
|
||||
/* writes default entries to the DE list */
|
||||
struct delist_t* init_list(int count)
|
||||
{
|
||||
struct delist_t* list = malloc(sizeof * list);
|
||||
list->names = malloc((count + 1) * (sizeof * (list->names)));
|
||||
list->names[0] = strdup(LY_LANG_SHELL);
|
||||
list->names[1] = strdup(LY_LANG_XINITRC);
|
||||
list->props = malloc(count * (sizeof * (list->props)));
|
||||
list->props[0].cmd = strdup("");
|
||||
list->props[0].type = shell;
|
||||
list->props[1].cmd = strdup(LY_CMD_XINITRC);
|
||||
list->props[1].type = xinitrc;
|
||||
return list;
|
||||
}
|
||||
|
||||
void end_list(struct delist_t* list, int count)
|
||||
{
|
||||
list->names[count] = NULL;
|
||||
list->count = count;
|
||||
}
|
||||
|
||||
/* extracts the name and command of a DE from its .desktop file */
|
||||
void get_props(FILE* file, char** name, char** command)
|
||||
{
|
||||
char line[LY_LIM_LINE_FILE];
|
||||
|
||||
while(fgets(line, sizeof(line), file))
|
||||
{
|
||||
if(!strncmp(LY_XSESSION_NAME, line, (sizeof(LY_XSESSION_NAME) - 1)))
|
||||
{
|
||||
*name = strdup(trim(line + (sizeof(LY_XSESSION_NAME) - 1)));
|
||||
}
|
||||
else if(!strncmp(LY_XSESSION_EXEC, line,
|
||||
(sizeof(LY_XSESSION_EXEC) - 1)))
|
||||
{
|
||||
*command = strdup(trim(line + (sizeof(LY_XSESSION_EXEC) - 1)));
|
||||
}
|
||||
|
||||
if(*name && *command)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void free_list(struct delist_t* list)
|
||||
{
|
||||
int count;
|
||||
|
||||
for(count = 0; count < list->count; ++count)
|
||||
{
|
||||
free(list->names[count]);
|
||||
free(list->props[count].cmd);
|
||||
}
|
||||
|
||||
free(list->names);
|
||||
free(list->props);
|
||||
free(list);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef _DESKTOP_H_
|
||||
#define _DESKTOP_H_
|
||||
|
||||
enum deserv_t {shell, xorg, xinitrc, wayland};
|
||||
|
||||
struct deprops_t
|
||||
{
|
||||
char* cmd;
|
||||
enum deserv_t type;
|
||||
};
|
||||
|
||||
struct delist_t
|
||||
{
|
||||
char** names;
|
||||
struct deprops_t* props;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct delist_t* init_list(int count);
|
||||
void end_list(struct delist_t* list, int count);
|
||||
void get_props(FILE* file, char** name, char** command);
|
||||
struct delist_t* list_de(void);
|
||||
void free_list(struct delist_t* list);
|
||||
|
||||
#endif /* _DESKTOP_H_ */
|
@ -1,49 +0,0 @@
|
||||
#ifndef _LANG_H_
|
||||
#define _LANG_H_
|
||||
|
||||
/* UI strings */
|
||||
#define LY_LANG_VALID_CREDS "Logged In"
|
||||
#define LY_LANG_LOGOUT "Logged out"
|
||||
#define LY_LANG_SHELL "shell"
|
||||
#define LY_LANG_XINITRC "xinitrc"
|
||||
#define LY_LANG_SHUTDOWN "shutdown"
|
||||
#define LY_LANG_REBOOT "reboot"
|
||||
#define LY_LANG_LOGIN "login : "
|
||||
#define LY_LANG_PASSWORD "password : "
|
||||
|
||||
/* ioctl */
|
||||
#define LY_ERR_FD_CONSOLE "Failed to create the console file descriptor"
|
||||
#define LY_ERR_FD_CONSOLE_ADVICE "(ly probably wasn't run with enough privileges)"
|
||||
#define LY_ERR_FD_CFG_SAVE "Failed to create the config file"
|
||||
|
||||
/* pam */
|
||||
#define LY_ERR_PAM_BUF "Memory buffer error"
|
||||
#define LY_ERR_PAM_SYSTEM "System error"
|
||||
#define LY_ERR_PAM_ABORT "Pam transaction aborted"
|
||||
#define LY_ERR_PAM_AUTH "Authentication error"
|
||||
#define LY_ERR_PAM_CRED_INSUFFICIENT "Insufficient credentials"
|
||||
#define LY_ERR_PAM_AUTHINFO_UNAVAIL "Failed to get user info"
|
||||
#define LY_ERR_PAM_MAXTRIES "Reached maximum tries limit"
|
||||
#define LY_ERR_PAM_USER_UNKNOWN "Unknown user"
|
||||
#define LY_ERR_PAM_ACCT_EXPIRED "Account expired"
|
||||
#define LY_ERR_PAM_NEW_AUTHTOK_REQD "Token expired"
|
||||
#define LY_ERR_PAM_PERM_DENIED "Permission denied"
|
||||
#define LY_ERR_PAM_CRED "Failed to set credentials"
|
||||
#define LY_ERR_PAM_CRED_EXPIRED "Credentials expired"
|
||||
#define LY_ERR_PAM_CRED_UNAVAIL "Failed to get credentials"
|
||||
#define LY_ERR_PAM_SESSION "Session error"
|
||||
#define LY_ERR_PAM_SET_TTY "Failed to set tty for pam"
|
||||
#define LY_ERR_PAM_SET_RUSER "Failed to set ruser for pam"
|
||||
|
||||
/* ncurses */
|
||||
#define LY_ERR_NC_BUFFER "Failed to refresh ncurses buffer"
|
||||
|
||||
/* de listing */
|
||||
#define LY_ERR_DELIST "Failed to open xsessions"
|
||||
|
||||
/* permissions */
|
||||
#define LY_ERR_PERM_GROUP "Failed to downgrade group permissions"
|
||||
#define LY_ERR_PERM_USER "Failed to downgrade user permissions"
|
||||
#define LY_ERR_PERM_DIR "Failed to change current directory"
|
||||
|
||||
#endif /* _LANG_H_ */
|
@ -1,625 +0,0 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
/* std lib */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
/* linux */
|
||||
#include <sys/wait.h>
|
||||
#include <paths.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/limits.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
/* pam */
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
#define PAM_SYSTEMD
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/pam_modutil.h>
|
||||
/* ly */
|
||||
#include "lang.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "login.h"
|
||||
#include "desktop.h"
|
||||
|
||||
int login_conv(int num_msg, const struct pam_message** msg,
|
||||
struct pam_response** resp, void* appdata_ptr)
|
||||
{
|
||||
int i;
|
||||
int result = PAM_SUCCESS;
|
||||
|
||||
if(!(*resp = calloc(num_msg, sizeof(struct pam_response))))
|
||||
{
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
for(i = 0; i < num_msg; i++)
|
||||
{
|
||||
char* username, *password;
|
||||
|
||||
switch(msg[i]->msg_style)
|
||||
{
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
username = ((char**) appdata_ptr)[0];
|
||||
(*resp)[i].resp = strdup(username);
|
||||
break;
|
||||
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
password = ((char**) appdata_ptr)[1];
|
||||
(*resp)[i].resp = strdup(password);
|
||||
break;
|
||||
|
||||
case PAM_ERROR_MSG:
|
||||
fprintf(stderr, "%s\n", msg[i]->msg);
|
||||
result = PAM_CONV_ERR;
|
||||
break;
|
||||
|
||||
case PAM_TEXT_INFO:
|
||||
printf("%s\n", msg[i]->msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if(result != PAM_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(result != PAM_SUCCESS)
|
||||
{
|
||||
free(*resp);
|
||||
*resp = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int start_env(const char* username, const char* password,
|
||||
const char* de_command, enum deserv_t display_server)
|
||||
{
|
||||
pid_t pid_display;
|
||||
int display_status;
|
||||
/* login info */
|
||||
int pam_result;
|
||||
const char* creds[2] = {username, password};
|
||||
struct pam_conv conv = {login_conv, creds};
|
||||
struct passwd* pwd = NULL;
|
||||
pam_handle_t* login_handle;
|
||||
/* session info */
|
||||
int display_id;
|
||||
char display_name[3];
|
||||
char tty_id[3];
|
||||
char vt[5];
|
||||
/* generates console and display id and updates the environment */
|
||||
destroy_env();
|
||||
display_id = get_free_display();
|
||||
snprintf(display_name, sizeof(display_name), ":%d", display_id);
|
||||
snprintf(tty_id, sizeof(tty_id), "%d", LY_CONSOLE_TTY);
|
||||
snprintf(vt, sizeof(vt), "vt%d", LY_CONSOLE_TTY);
|
||||
init_xdg(tty_id, display_name, display_server);
|
||||
/* pam_start and error handling */
|
||||
pam_result = pam_start(LY_SERVICE_NAME, username, &conv, &login_handle);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_BUF_ERR :
|
||||
error_print(LY_ERR_PAM_BUF);
|
||||
break;
|
||||
|
||||
case PAM_SYSTEM_ERR :
|
||||
error_print(LY_ERR_PAM_SYSTEM);
|
||||
break;
|
||||
|
||||
case PAM_ABORT :
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_authenticate and error handling */
|
||||
pam_result = pam_authenticate(login_handle, 0);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_AUTH_ERR :
|
||||
error_print(LY_ERR_PAM_AUTH);
|
||||
break;
|
||||
|
||||
case PAM_CRED_INSUFFICIENT :
|
||||
error_print(LY_ERR_PAM_CRED_INSUFFICIENT);
|
||||
break;
|
||||
|
||||
case PAM_AUTHINFO_UNAVAIL :
|
||||
error_print(LY_ERR_PAM_AUTHINFO_UNAVAIL);
|
||||
break;
|
||||
|
||||
case PAM_MAXTRIES :
|
||||
error_print(LY_ERR_PAM_MAXTRIES);
|
||||
break;
|
||||
|
||||
case PAM_USER_UNKNOWN :
|
||||
error_print(LY_ERR_PAM_USER_UNKNOWN);
|
||||
break;
|
||||
|
||||
case PAM_ABORT :
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_acct_mgmt and error handling */
|
||||
pam_result = pam_acct_mgmt(login_handle, 0);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_ACCT_EXPIRED :
|
||||
error_print(LY_ERR_PAM_ACCT_EXPIRED);
|
||||
break;
|
||||
|
||||
case PAM_AUTH_ERR :
|
||||
error_print(LY_ERR_PAM_AUTH);
|
||||
break;
|
||||
|
||||
case PAM_NEW_AUTHTOK_REQD :
|
||||
error_print(LY_ERR_PAM_NEW_AUTHTOK_REQD);
|
||||
break;
|
||||
|
||||
case PAM_PERM_DENIED :
|
||||
error_print(LY_ERR_PAM_PERM_DENIED);
|
||||
break;
|
||||
|
||||
case PAM_USER_UNKNOWN :
|
||||
error_print(LY_ERR_PAM_USER_UNKNOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialise user groups */
|
||||
/* Get pwd structure for the user to get his group id */
|
||||
struct passwd* pw = getpwnam(username);
|
||||
|
||||
if(!pw)
|
||||
{
|
||||
error_print(strerror(errno));
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int grp_result = initgroups(username, pw->pw_gid);
|
||||
|
||||
if(grp_result == -1)
|
||||
{
|
||||
error_print(strerror(errno));
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_setcred and error handling */
|
||||
pam_result = pam_setcred(login_handle, PAM_ESTABLISH_CRED);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_BUF_ERR :
|
||||
error_print(LY_ERR_PAM_BUF);
|
||||
break;
|
||||
|
||||
case PAM_CRED_ERR :
|
||||
error_print(LY_ERR_PAM_CRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_EXPIRED :
|
||||
error_print(LY_ERR_PAM_CRED_EXPIRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_UNAVAIL :
|
||||
error_print(LY_ERR_PAM_CRED_UNAVAIL);
|
||||
break;
|
||||
|
||||
case PAM_SYSTEM_ERR :
|
||||
error_print(LY_ERR_PAM_SYSTEM);
|
||||
break;
|
||||
|
||||
case PAM_USER_UNKNOWN :
|
||||
error_print(LY_ERR_PAM_USER_UNKNOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_open_session and error handling */
|
||||
pam_result = pam_open_session(login_handle, 0);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_setcred(login_handle, PAM_DELETE_CRED);
|
||||
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_BUF_ERR :
|
||||
error_print(LY_ERR_PAM_BUF);
|
||||
break;
|
||||
|
||||
case PAM_CRED_ERR :
|
||||
error_print(LY_ERR_PAM_CRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_EXPIRED :
|
||||
error_print(LY_ERR_PAM_CRED_EXPIRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_UNAVAIL :
|
||||
error_print(LY_ERR_PAM_CRED_UNAVAIL);
|
||||
break;
|
||||
|
||||
case PAM_SYSTEM_ERR :
|
||||
error_print(LY_ERR_PAM_SYSTEM);
|
||||
break;
|
||||
|
||||
case PAM_USER_UNKNOWN :
|
||||
error_print(LY_ERR_PAM_USER_UNKNOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* login error */
|
||||
if(login_handle == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* temporarily exits ncurses mode */
|
||||
def_prog_mode();
|
||||
endwin();
|
||||
pwd = getpwnam(username);
|
||||
/* launches the DE */
|
||||
pid_display = fork();
|
||||
|
||||
if(pid_display == 0)
|
||||
{
|
||||
/* downgrades group permissions and checks for an error */
|
||||
if(setgid(pwd->pw_gid) < 0)
|
||||
{
|
||||
error_print(LY_ERR_PERM_GROUP);
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* initializes environment variables */
|
||||
init_env(login_handle, pwd);
|
||||
|
||||
/* downgrades user permissions and checks for an error */
|
||||
if(setuid(pwd->pw_uid) < 0)
|
||||
{
|
||||
error_print(LY_ERR_PERM_USER);
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* changes directory and checks for an error */
|
||||
if(chdir(pwd->pw_dir) < 0)
|
||||
{
|
||||
error_print(LY_ERR_PERM_DIR);
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* starts the chosen environment */
|
||||
switch(display_server)
|
||||
{
|
||||
case shell:
|
||||
launch_shell(pwd, login_handle);
|
||||
|
||||
case wayland:
|
||||
launch_wayland(pwd, login_handle, de_command);
|
||||
break;
|
||||
|
||||
case xorg:
|
||||
launch_xorg(pwd, login_handle, de_command, display_name, vt, 0);
|
||||
break;
|
||||
|
||||
case xinitrc:
|
||||
default :
|
||||
launch_xorg(pwd, login_handle, de_command, display_name, vt, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* waits for the de/shell to exit */
|
||||
waitpid(pid_display, &display_status, 0);
|
||||
/* pam_close_session and error handling */
|
||||
pam_result = pam_close_session(login_handle, 0);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_BUF_ERR :
|
||||
error_print(LY_ERR_PAM_BUF);
|
||||
break;
|
||||
|
||||
case PAM_SESSION_ERR :
|
||||
error_print(LY_ERR_PAM_SESSION);
|
||||
break;
|
||||
|
||||
case PAM_ABORT :
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_setcred and error handling */
|
||||
pam_result = pam_setcred(login_handle, PAM_DELETE_CRED);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
switch(pam_result)
|
||||
{
|
||||
case PAM_BUF_ERR :
|
||||
error_print(LY_ERR_PAM_BUF);
|
||||
break;
|
||||
|
||||
case PAM_CRED_ERR :
|
||||
error_print(LY_ERR_PAM_CRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_EXPIRED :
|
||||
error_print(LY_ERR_PAM_CRED_EXPIRED);
|
||||
break;
|
||||
|
||||
case PAM_CRED_UNAVAIL :
|
||||
error_print(LY_ERR_PAM_CRED_UNAVAIL);
|
||||
break;
|
||||
|
||||
case PAM_SYSTEM_ERR :
|
||||
error_print(LY_ERR_PAM_SYSTEM);
|
||||
break;
|
||||
|
||||
case PAM_USER_UNKNOWN :
|
||||
error_print(LY_ERR_PAM_USER_UNKNOWN);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_print(LY_ERR_PAM_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
pam_end(login_handle, pam_result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pam_end and error handling */
|
||||
pam_result = pam_end(login_handle, pam_result);
|
||||
|
||||
if(pam_result != PAM_SUCCESS)
|
||||
{
|
||||
error_print(LY_ERR_PAM_SYSTEM);
|
||||
refresh();
|
||||
return 1;
|
||||
}
|
||||
|
||||
error_print(LY_LANG_LOGOUT);
|
||||
refresh();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void launch_xorg(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command, const char* display_name, const char* vt,
|
||||
int xinitrc)
|
||||
{
|
||||
FILE* file;
|
||||
pid_t child;
|
||||
int status;
|
||||
char cmd[LY_LIM_CMD];
|
||||
char* argv[] = {pwd->pw_shell, "-l", "-c", cmd, NULL};
|
||||
extern char** environ;
|
||||
/* updates cookie */
|
||||
snprintf(cmd, sizeof(cmd), "exec xauth add %s . `%s`", display_name,
|
||||
LY_CMD_MCOOKIE);
|
||||
/* creates the file if it can't be found */
|
||||
file = fopen(getenv("XAUTHORITY"), "ab+");
|
||||
fclose(file);
|
||||
/* generates the cookie */
|
||||
child = fork();
|
||||
|
||||
if(child == 0)
|
||||
{
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(child, &status, 0);
|
||||
reset_terminal(pwd);
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"exec xinit %s %s%s -- %s %s %s -auth %s",
|
||||
LY_CMD_XSETUP,
|
||||
xinitrc ? "" : "/usr/bin/",
|
||||
de_command, LY_CMD_X,
|
||||
display_name, vt, getenv("XAUTHORITY"));
|
||||
execve(pwd->pw_shell, argv, environ);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void launch_wayland(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command)
|
||||
{
|
||||
char cmd[32];
|
||||
extern char** environ;
|
||||
char* argv[] = {pwd->pw_shell, "-l", "-c", cmd, NULL};
|
||||
snprintf(cmd, 32, "exec %s", de_command);
|
||||
reset_terminal(pwd);
|
||||
execve(pwd->pw_shell, argv, environ);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void launch_shell(struct passwd* pwd, pam_handle_t* pam_handle)
|
||||
{
|
||||
char* pos;
|
||||
char args[PATH_MAX + 2];
|
||||
reset_terminal(pwd);
|
||||
args[0] = '-';
|
||||
strncpy(args + 1, ((pos = strrchr(pwd->pw_shell,
|
||||
'/')) ? pos + 1 : pwd->pw_shell), sizeof(args) - 1);
|
||||
execl(pwd->pw_shell, args, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void destroy_env(void)
|
||||
{
|
||||
/* our environment */
|
||||
extern char** environ;
|
||||
/* completely destroys environment */
|
||||
environ = malloc(sizeof(char*));
|
||||
memset(environ, 0, sizeof(char*));
|
||||
}
|
||||
|
||||
void init_xdg(const char* tty_id, const char* display_name,
|
||||
enum deserv_t display_server)
|
||||
{
|
||||
setenv("XDG_SESSION_CLASS", "user", 0);
|
||||
setenv("XDG_SEAT", "seat0", 0);
|
||||
setenv("XDG_VTNR", tty_id, 0);
|
||||
setenv("DISPLAY", display_name, 1);
|
||||
|
||||
switch(display_server)
|
||||
{
|
||||
case shell:
|
||||
setenv("XDG_SESSION_TYPE", "tty", 0);
|
||||
|
||||
case wayland:
|
||||
setenv("XDG_SESSION_TYPE", "wayland", 0);
|
||||
break;
|
||||
|
||||
case xorg:
|
||||
default :
|
||||
setenv("XDG_SESSION_TYPE", "x11", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int init_env(pam_handle_t* pam_handle, struct passwd* pw)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
/* buffers */
|
||||
char tmp[PATH_MAX];
|
||||
char* buf;
|
||||
char** env;
|
||||
char* termenv = getenv("TERM");
|
||||
setenv("HOME", pw->pw_dir, 0);
|
||||
setenv("USER", pw->pw_name, 1);
|
||||
setenv("SHELL", pw->pw_shell, 1);
|
||||
setenv("LOGNAME", pw->pw_name, 1);
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", pw->pw_dir, LY_XAUTHORITY);
|
||||
setenv("XAUTHORITY", tmp, 0);
|
||||
buf = termenv ? strdup(termenv) : NULL;
|
||||
setenv("TERM", buf ? buf : "linux", 1);
|
||||
free(buf);
|
||||
len = snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pw->pw_name);
|
||||
|
||||
if((len > 0) && ((size_t) len < sizeof(tmp)))
|
||||
{
|
||||
setenv("MAIL", tmp, 0);
|
||||
}
|
||||
|
||||
if(setenv("PATH", LY_PATH, 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
env = pam_getenvlist(pam_handle);
|
||||
|
||||
for(i = 0; env && env[i]; i++)
|
||||
{
|
||||
putenv(env[i]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void reset_terminal(struct passwd* pwd)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
pid = fork();
|
||||
char cmd[LY_LIM_CMD];
|
||||
strncpy(cmd, "exec tput reset", sizeof(cmd));
|
||||
|
||||
if(pid == 0)
|
||||
{
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
|
||||
int get_free_display(void)
|
||||
{
|
||||
int i;
|
||||
char xlock[LY_LIM_PATH];
|
||||
|
||||
for(i = 0; i < 200; ++i)
|
||||
{
|
||||
snprintf(xlock, sizeof(xlock), "/tmp/.X%d-lock", i);
|
||||
|
||||
if(access(xlock, F_OK) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef _LOGIN_H_
|
||||
#define _LOGIN_H_
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <pwd.h>
|
||||
#include "desktop.h"
|
||||
|
||||
int login_conv(int num_msg, const struct pam_message** msg,
|
||||
struct pam_response** resp, void* appdata_ptr);
|
||||
int start_env(const char* username, const char* password,
|
||||
const char* de_command, enum deserv_t display_server);
|
||||
void launch_xorg(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command, const char* display_name, const char* vt,
|
||||
int xinitrc);
|
||||
void launch_wayland(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command);
|
||||
void launch_shell(struct passwd* pwd, pam_handle_t* pam_handle);
|
||||
void destroy_env(void);
|
||||
void init_xdg(const char* tty_id, const char* display_name,
|
||||
enum deserv_t display_server);
|
||||
int init_env(pam_handle_t* pam_handle, struct passwd* pw);
|
||||
void reset_terminal(struct passwd* pwd);
|
||||
int get_free_display(void);
|
||||
|
||||
#endif /* _LOGIN_H_ */
|
@ -1,226 +0,0 @@
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
/* stdlib */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
/* linux */
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vt.h>
|
||||
#include <unistd.h>
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
/* pam */
|
||||
#include <security/pam_appl.h>
|
||||
/* ly */
|
||||
#include "lang.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "login.h"
|
||||
#include "desktop.h"
|
||||
#include "ncui.h"
|
||||
|
||||
#define KEY_TAB_ASCII 8
|
||||
#define KEY_ENTER_ASCII 10
|
||||
#define KEY_BACKSPACE_ASCII 127
|
||||
|
||||
int main(void)
|
||||
{
|
||||
FILE* console;
|
||||
/* user interface components */
|
||||
struct ncform form;
|
||||
struct ncwin win;
|
||||
/* desktop environments list */
|
||||
enum deserv_t type;
|
||||
struct delist_t* de_list;
|
||||
struct deprops_t* de_props;
|
||||
char** de_names;
|
||||
int de_count;
|
||||
int de_id;
|
||||
/* user input */
|
||||
int input_key;
|
||||
/* processing buffers */
|
||||
int fail;
|
||||
int auth_fails;
|
||||
char* username;
|
||||
char* password;
|
||||
char* cmd;
|
||||
/* gets desktop entries */
|
||||
de_list = list_de();
|
||||
|
||||
if(de_list == NULL) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
de_props = de_list->props;
|
||||
de_names = de_list->names;
|
||||
de_count = de_list->count;
|
||||
de_id = 0;
|
||||
auth_fails = 0;
|
||||
/* verifies if we can access the console with enough privileges */
|
||||
console = fopen(LY_CONSOLE_DEV, "w");
|
||||
|
||||
if(!console)
|
||||
{
|
||||
fprintf(stderr, "%s\n", LY_ERR_FD_CONSOLE);
|
||||
fprintf(stderr, "%s\n", LY_ERR_FD_CONSOLE_ADVICE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* create LY_CFG_SAVE if it doesn't exist yet */
|
||||
FILE* cfg_save = fopen(LY_CFG_SAVE, "ab+");
|
||||
if (!cfg_save)
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", LY_ERR_FD_CFG_SAVE, LY_CFG_SAVE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fclose(cfg_save);
|
||||
|
||||
kernel_log(0);
|
||||
/* initializes ncurses UI */
|
||||
init_ncurses(console);
|
||||
init_form(&form, de_names, de_count, &de_id);
|
||||
init_win(&win, &form);
|
||||
init_scene(&win, &form);
|
||||
init_draw(&win, &form);
|
||||
close(fileno(console));
|
||||
/* enables insertion mode */
|
||||
form_driver(form.form, REQ_INS_MODE);
|
||||
/* makes the password field active by default */
|
||||
set_current_field(form.form, form.fields[6]);
|
||||
form_driver(form.form, REQ_END_LINE);
|
||||
|
||||
while((input_key = wgetch(win.win)) != ERR)
|
||||
{
|
||||
form.active = current_field(form.form);
|
||||
|
||||
switch(input_key)
|
||||
{
|
||||
case KEY_ENTER_ASCII:
|
||||
if(form.active == form.fields[6])
|
||||
{
|
||||
/* checks for buffer errors */
|
||||
if(form_driver(form.form, REQ_VALIDATION) != E_OK)
|
||||
{
|
||||
error_print(LY_ERR_NC_BUFFER);
|
||||
break;
|
||||
}
|
||||
|
||||
/* stores the user inputs in processing buffers */
|
||||
username = trim(field_buffer(form.fields[4], 0));
|
||||
password = trim(field_buffer(form.fields[6], 0));
|
||||
cmd = de_props[de_id].cmd;
|
||||
type = de_props[de_id].type;
|
||||
|
||||
/* saves the username and DE if enabled */
|
||||
if(LY_CFG_WRITE_SAVE)
|
||||
{
|
||||
FILE* file = fopen(LY_CFG_SAVE, "wb");
|
||||
fprintf(file, "%s\n%d", username, de_id);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* logs in and suspends ncurses mode if successful */
|
||||
fail = start_env(username, password, cmd, type);
|
||||
/* clears the password */
|
||||
set_field_buffer(form.fields[6], 0, "");
|
||||
|
||||
if(fail)
|
||||
{
|
||||
++auth_fails;
|
||||
|
||||
if(auth_fails > (LY_CFG_AUTH_TRIG - 1))
|
||||
{
|
||||
cascade();
|
||||
}
|
||||
}
|
||||
else if(LY_CFG_CLR_USR)
|
||||
{
|
||||
/* clears the username */
|
||||
set_field_buffer(form.fields[4], 0, "");
|
||||
/* sets cursor to the login field */
|
||||
set_current_field(form.form, form.fields[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* sets cursor to the password field */
|
||||
set_current_field(form.form, form.fields[6]);
|
||||
break;
|
||||
}
|
||||
|
||||
case KEY_TAB_ASCII:
|
||||
case KEY_DOWN:
|
||||
form_driver(form.form, REQ_NEXT_FIELD);
|
||||
form_driver(form.form, REQ_END_LINE);
|
||||
break;
|
||||
|
||||
case KEY_BTAB:
|
||||
case KEY_UP:
|
||||
form_driver(form.form, REQ_PREV_FIELD);
|
||||
form_driver(form.form, REQ_END_LINE);
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
if(form.active == form.fields[1])
|
||||
{
|
||||
de_id = ((de_id + 1) == de_count) ? 0 : de_id + 1;
|
||||
form_driver(form.form, REQ_NEXT_CHOICE);
|
||||
}
|
||||
else
|
||||
{
|
||||
form_driver(form.form, REQ_NEXT_CHAR);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KEY_LEFT:
|
||||
if(form.active == form.fields[1])
|
||||
{
|
||||
de_id = (de_id == 0) ? (de_count - 1) : de_id - 1;
|
||||
form_driver(form.form, REQ_PREV_CHOICE);
|
||||
}
|
||||
else
|
||||
{
|
||||
form_driver(form.form, REQ_PREV_CHAR);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case KEY_BACKSPACE_ASCII:
|
||||
case KEY_BACKSPACE:
|
||||
form_driver(form.form, REQ_DEL_PREV);
|
||||
form_driver(form.form, REQ_END_LINE);
|
||||
break;
|
||||
|
||||
case KEY_DC:
|
||||
form_driver(form.form, REQ_DEL_CHAR);
|
||||
break;
|
||||
|
||||
case KEY_F(1):
|
||||
end_form(&form);
|
||||
endwin();
|
||||
free_list(de_list);
|
||||
execl(LY_CMD_HALT, LY_CMD_HALT, "-h", "now", NULL);
|
||||
break;
|
||||
|
||||
case KEY_F(2):
|
||||
end_form(&form);
|
||||
endwin();
|
||||
free_list(de_list);
|
||||
execl(LY_CMD_HALT, LY_CMD_HALT, "-r", "now", NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
form_driver(form.form, input_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_log(1);
|
||||
fclose(console);
|
||||
free_list(de_list);
|
||||
end_form(&form);
|
||||
endwin();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include "ncui.h"
|
||||
|
||||
/* stdlib */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
/* linux */
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vt.h>
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
/* ly */
|
||||
#include "lang.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
size_t max(size_t a, size_t b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
void init_ncurses(FILE* desc)
|
||||
{
|
||||
int filedesc = fileno(desc);
|
||||
/* required for ncurses */
|
||||
putenv(LY_CONSOLE_TERM);
|
||||
/* switches tty */
|
||||
ioctl(filedesc, VT_ACTIVATE, LY_CONSOLE_TTY);
|
||||
ioctl(filedesc, VT_WAITACTIVE, LY_CONSOLE_TTY);
|
||||
/* ncurses startup */
|
||||
initscr();
|
||||
raw();
|
||||
noecho();
|
||||
}
|
||||
|
||||
void init_form(struct ncform* form, char** list, int max_de, int* de_id)
|
||||
{
|
||||
FILE* file;
|
||||
char line[LY_LIM_LINE_FILE];
|
||||
char user[LY_LIM_LINE_FILE];
|
||||
char* arrow_left;
|
||||
char arrow_right[3] = " >";
|
||||
int de;
|
||||
int i;
|
||||
|
||||
/* opens the file */
|
||||
file = fopen(LY_CFG_SAVE, "rb");
|
||||
memset(user, '\0', LY_LIM_LINE_FILE);
|
||||
de = max_de;
|
||||
|
||||
/* reads the username and DE from the save file if enabled */
|
||||
if(LY_CFG_READ_SAVE)
|
||||
{
|
||||
if(fgets(line, sizeof(line), file))
|
||||
{
|
||||
strcpy(user, line);
|
||||
}
|
||||
|
||||
if(fgets(line, sizeof(line), file))
|
||||
{
|
||||
de = (unsigned int) strtol(line, NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
/* computes input padding from labels text */
|
||||
form->label_pad = max(strlen(LY_LANG_LOGIN), strlen(LY_LANG_PASSWORD));
|
||||
arrow_left = malloc((form->label_pad + 1) * (sizeof (char)));
|
||||
/* adds the left arrow */
|
||||
i = 0;
|
||||
form->fields[i] = new_field(1, form->label_pad, 0, 0, 0, 0);
|
||||
memset(arrow_left, ' ', form->label_pad);
|
||||
arrow_left[form->label_pad - 2] = '<';
|
||||
arrow_left[form->label_pad] = '\0';
|
||||
set_field_buffer(form->fields[i], 0, arrow_left);
|
||||
set_field_opts(form->fields[i], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
|
||||
/* DE list */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, 32, 0, form->label_pad, 0, 0);
|
||||
set_field_type(form->fields[i], TYPE_ENUM, list);
|
||||
|
||||
if(de < max_de)
|
||||
{
|
||||
set_field_buffer(form->fields[i], 0, list[de]);
|
||||
*de_id = de;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_field_buffer(form->fields[i], 0, list[0]);
|
||||
*de_id = 0;
|
||||
}
|
||||
|
||||
set_field_opts(form->fields[i],
|
||||
O_VISIBLE | O_PUBLIC | O_ACTIVE);
|
||||
/* adds the right arrow */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, 2, 0, form->label_pad + 32, 0, 0);
|
||||
set_field_buffer(form->fields[i], 0, arrow_right);
|
||||
set_field_opts(form->fields[i], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
|
||||
/* login label */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, form->label_pad, 2, 0, 0, 0);
|
||||
set_field_buffer(form->fields[i], 0, LY_LANG_LOGIN);
|
||||
set_field_opts(form->fields[i], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
|
||||
/* login field */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, 32, 2, form->label_pad, 0, 0);
|
||||
|
||||
if(*user)
|
||||
{
|
||||
set_field_buffer(form->fields[i], 0, user);
|
||||
}
|
||||
|
||||
set_field_opts(form->fields[i],
|
||||
O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
|
||||
/* password label */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, form->label_pad, 4, 0, 0, 0);
|
||||
set_field_buffer(form->fields[i], 0, LY_LANG_PASSWORD);
|
||||
set_field_opts(form->fields[i], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
|
||||
/* password field */
|
||||
++i;
|
||||
form->fields[i] = new_field(1, 32, 4, form->label_pad, 0, 0);
|
||||
set_field_opts(form->fields[i], O_VISIBLE | O_EDIT | O_ACTIVE);
|
||||
/* bound */
|
||||
++i;
|
||||
form->fields[i] = NULL;
|
||||
/* generates the form */
|
||||
form->form = new_form(form->fields);
|
||||
form_opts_off(form->form, O_BS_OVERLOAD);
|
||||
scale_form(form->form, &(form->height), &(form->width));
|
||||
}
|
||||
|
||||
void init_win(struct ncwin* win, struct ncform* form)
|
||||
{
|
||||
int rows;
|
||||
int cols;
|
||||
/* fetches screen size */
|
||||
getmaxyx(stdscr, rows, cols);
|
||||
/* adds a margin */
|
||||
win->width = LY_MARGIN_H * 2 + form->width;
|
||||
win->height = LY_MARGIN_V * 2 + form->height + 2;
|
||||
/* saves the position */
|
||||
win->y = (rows - win->height) / 2;
|
||||
win->x = (cols - win->width) / 2;
|
||||
/* generates the window */
|
||||
win->win = newwin(win->height, win->width, win->y, win->x);
|
||||
/* enables advanced input (eg. "F1" key) */
|
||||
keypad(win->win, TRUE);
|
||||
}
|
||||
|
||||
void init_scene(struct ncwin* win, struct ncform* form)
|
||||
{
|
||||
set_form_win(form->form, win->win);
|
||||
set_form_sub(form->form, derwin(win->win, form->height, form->width,
|
||||
LY_MARGIN_V + 2, LY_MARGIN_H));
|
||||
}
|
||||
|
||||
void init_draw(struct ncwin* win, struct ncform* form)
|
||||
{
|
||||
char line[LY_LIM_LINE_CONSOLE];
|
||||
char *greeting;
|
||||
/* frame */
|
||||
box(win->win, 0, 0);
|
||||
/* initializes error output and prints greeting message */
|
||||
hostname(&greeting);
|
||||
error_init(win->win, win->width, greeting);
|
||||
/* prints shutdown & reboot hints */
|
||||
snprintf(line, sizeof(line), "F1 %s F2 %s", LY_LANG_SHUTDOWN,
|
||||
LY_LANG_REBOOT);
|
||||
mvprintw(0, 0, line);
|
||||
/* dumps ncurses buffer */
|
||||
refresh();
|
||||
/* registers form */
|
||||
post_form(form->form);
|
||||
/* dumps window buffer */
|
||||
wrefresh(win->win);
|
||||
free(greeting);
|
||||
}
|
||||
|
||||
void end_form(struct ncform* form)
|
||||
{
|
||||
unpost_form(form->form);
|
||||
free_form(form->form);
|
||||
free_field(form->fields[0]);
|
||||
free_field(form->fields[1]);
|
||||
free_field(form->fields[2]);
|
||||
free_field(form->fields[3]);
|
||||
free_field(form->fields[4]);
|
||||
free_field(form->fields[5]);
|
||||
free_field(form->fields[6]);
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#ifndef _NCUI_H_
|
||||
#define _NCUI_H_
|
||||
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
|
||||
struct ncwin
|
||||
{
|
||||
WINDOW* win;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct ncform
|
||||
{
|
||||
FORM* form;
|
||||
FIELD* fields[8];
|
||||
FIELD* active;
|
||||
int height;
|
||||
int width;
|
||||
int label_pad;
|
||||
};
|
||||
|
||||
void init_ncurses(FILE* desc);
|
||||
void init_form(struct ncform* form, char** list, int max_de,
|
||||
int* de_id);
|
||||
void init_win(struct ncwin* win, struct ncform* form);
|
||||
void init_scene(struct ncwin* win, struct ncform* form);
|
||||
void init_draw(struct ncwin* win, struct ncform* form);
|
||||
void end_form(struct ncform* form);
|
||||
|
||||
#endif /* _NCUI_H_ */
|
@ -1,194 +0,0 @@
|
||||
#define _XOPEN_SOURCE 500
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
/* std lib */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/wait.h>
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
/* ly */
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
/* important stuff */
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
/* sockets */
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
void kernel_log(int mode)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
pid = fork();
|
||||
if(pid < 0) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(pid == 0)
|
||||
{
|
||||
if(mode)
|
||||
{
|
||||
execl("/bin/dmesg", "/bin/dmesg", "-E", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
execl("/bin/dmesg", "/bin/dmesg", "-D", NULL);
|
||||
}
|
||||
/* execl should not return */
|
||||
perror("execl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
if(!WIFEXITED(status) || WEXITSTATUS(status))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char* trim(char* s)
|
||||
{
|
||||
char* end = s + strlen(s) - 1;
|
||||
|
||||
while((end > s) && isspace((unsigned char) *end))
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
*(end + 1) = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void hostname(char** out) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *info;
|
||||
char hostname[1024];
|
||||
char* dot;
|
||||
int result;
|
||||
|
||||
hostname[1023] = '\0';
|
||||
gethostname(hostname, 1023);
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
result = getaddrinfo(hostname, "http", &hints, &info);
|
||||
|
||||
if(result == 0 && info != NULL)
|
||||
{
|
||||
dot = strchr(info->ai_canonname, '.');
|
||||
*out = strndup(info->ai_canonname, dot - info->ai_canonname);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = strdup("");
|
||||
}
|
||||
|
||||
freeaddrinfo(info);
|
||||
}
|
||||
|
||||
void error_init(WINDOW* win, int width, const char* s)
|
||||
{
|
||||
static WINDOW* win_stack = NULL;
|
||||
static int width_stack = 0;
|
||||
char* blank;
|
||||
int i;
|
||||
|
||||
if(win)
|
||||
{
|
||||
win_stack = win;
|
||||
width_stack = width;
|
||||
}
|
||||
|
||||
blank = malloc((width_stack - 1) * (sizeof(char)));
|
||||
|
||||
for(i = 0; i < width_stack - 2; ++i)
|
||||
{
|
||||
blank[i] = ' ';
|
||||
}
|
||||
|
||||
blank[i] = '\0';
|
||||
mvwprintw(win_stack, LY_MARGIN_V, 1, blank);
|
||||
mvwprintw(win_stack, LY_MARGIN_V, (width_stack - strlen(s)) / 2, s);
|
||||
free(blank);
|
||||
}
|
||||
|
||||
void error_print(const char* s)
|
||||
{
|
||||
error_init(NULL, 0, s);
|
||||
}
|
||||
|
||||
chtype get_curses_char(int y, int x)
|
||||
{
|
||||
return mvwinch(newscr, y, x);
|
||||
}
|
||||
|
||||
void cascade(void)
|
||||
{
|
||||
int rows;
|
||||
int cols;
|
||||
int x;
|
||||
int y;
|
||||
chtype char_cur;
|
||||
chtype char_under;
|
||||
time_t time_start;
|
||||
time_t time_end;
|
||||
time_t time_rand;
|
||||
int fps = LY_CFG_FPS;
|
||||
int frame_target = LY_CFG_FMAX;
|
||||
int frame_count;
|
||||
float time_frame;
|
||||
float time_delta = 1.0 / fps;
|
||||
getmaxyx(stdscr, rows, cols);
|
||||
time(&time_rand);
|
||||
srand((unsigned) time_rand);
|
||||
|
||||
for(frame_count = 0; frame_count < frame_target; ++frame_count)
|
||||
{
|
||||
time_start = clock();
|
||||
|
||||
for(y = 0; y < rows; ++y)
|
||||
{
|
||||
for(x = 0; x < cols; ++x)
|
||||
{
|
||||
char_cur = get_curses_char(y, x);
|
||||
|
||||
if(isspace(char_cur & A_CHARTEXT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char_under = get_curses_char(y + 1, x);
|
||||
|
||||
if(!isspace(char_under & A_CHARTEXT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(((rand() % 10) > LY_CFG_FCHANCE) && (frame_count > 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mvaddch(y, x, ' ');
|
||||
mvaddch(y + 1, x, char_cur);
|
||||
}
|
||||
}
|
||||
|
||||
refresh();
|
||||
time_end = clock();
|
||||
time_frame = (time_end - time_start) / CLOCKS_PER_SEC;
|
||||
|
||||
if(time_frame < time_delta)
|
||||
{
|
||||
usleep((time_delta - time_frame) * 1000000);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
/* ncurses */
|
||||
#include <form.h>
|
||||
|
||||
void kernel_log(int mode);
|
||||
char* trim(char* s);
|
||||
char* strdup(const char* src);
|
||||
void hostname(char** out);
|
||||
void error_init(WINDOW* win, int width, const char* s);
|
||||
void error_print(const char* s);
|
||||
chtype get_curses_char(int y, int x);
|
||||
void cascade(void);
|
||||
|
||||
#endif /* _UTILS_H_ */
|
Loading…
Reference in New Issue