git: f096655c794b - main - x11/lumina-core: Fix LScreensaver password check

From: Jason W. Bacon <jwb_at_FreeBSD.org>
Date: Fri, 04 Mar 2022 01:03:35 UTC
The branch main has been updated by jwb:

URL: https://cgit.FreeBSD.org/ports/commit/?id=f096655c794b3e062bf5c2eda8c71cdb798c7134

commit f096655c794b3e062bf5c2eda8c71cdb798c7134
Author:     Jason W. Bacon <jwb@FreeBSD.org>
AuthorDate: 2022-03-04 00:58:34 +0000
Commit:     Jason W. Bacon <jwb@FreeBSD.org>
CommitDate: 2022-03-04 00:58:34 +0000

    x11/lumina-core: Fix LScreensaver password check
    
    lumina-checkpass was disabled in the previous build, causing the
    screensaver to unlock on any input rather than just the correct pw.
    
    Also removed xscreensaver dep, replaced by LScreensaver.
    
    LPanel patch is a hack to redraw the panel after screen resize.  Makes
    Lumina usable, though still not pretty, in a VirtualBox guest with
    guest additions.  Still needs wallpaper redraw.
    
    PR:             262320
    Approved by:    lbartoletti
---
 x11/lumina-core/Makefile                           |   3 +-
 x11/lumina-core/files/patch-core.pro               |  13 +++
 .../patch-lumina-checkpass_lumina-checkpass.pro    |  11 ++
 .../files/patch-lumina-checkpass_main.c            | 122 +++++++++++++++++++++
 .../files/patch-lumina-desktop_LPanel.cpp          |  14 +++
 ...-lumina-desktop_src-screensaver_LLockScreen.cpp |  22 ++++
 x11/lumina-core/pkg-plist                          |   1 +
 7 files changed, 184 insertions(+), 2 deletions(-)

diff --git a/x11/lumina-core/Makefile b/x11/lumina-core/Makefile
index ad734e3c8e94..a9f77d06a1e8 100644
--- a/x11/lumina-core/Makefile
+++ b/x11/lumina-core/Makefile
@@ -3,7 +3,7 @@
 PORTNAME=	lumina-core
 DISTVERSIONPREFIX=	v
 DISTVERSION=	1.6.2
-PORTREVISION=	3
+PORTREVISION=	4
 CATEGORIES=	x11
 
 MAINTAINER=	lbartoletti@FreeBSD.org
@@ -14,7 +14,6 @@ LICENSE_FILE=	${WRKSRC}/../../LICENSE
 
 RUN_DEPENDS=	fluxbox>=0:x11-wm/fluxbox \
 		fluxbox-tenr-styles-pack>=0:x11-themes/fluxbox-tenr-styles-pack \
-		xscreensaver>=0:x11/xscreensaver \
 		xbrightness>=0:x11/xbrightness \
 		compton>=0:x11-wm/compton \
 		xrandr>=0:x11/xrandr \
diff --git a/x11/lumina-core/files/patch-core.pro b/x11/lumina-core/files/patch-core.pro
new file mode 100644
index 000000000000..8c3c237bb5bb
--- /dev/null
+++ b/x11/lumina-core/files/patch-core.pro
@@ -0,0 +1,13 @@
+--- core.pro.orig	2022-03-03 00:56:25 UTC
++++ core.pro
+@@ -10,8 +10,8 @@ SUBDIRS+= lumina-desktop \
+ 	lumina-info \
+ 	lumina-pingcursor \
+ 	$${PWD}/../../icon-theme \
+-	lumina-theme-engine 
+-#	lumina-checkpass
++	lumina-theme-engine \
++	lumina-checkpass
+ #	lumina-desktop-unified
+ 
+ #Also install any special menu scripts
diff --git a/x11/lumina-core/files/patch-lumina-checkpass_lumina-checkpass.pro b/x11/lumina-core/files/patch-lumina-checkpass_lumina-checkpass.pro
new file mode 100644
index 000000000000..e180991ba606
--- /dev/null
+++ b/x11/lumina-core/files/patch-lumina-checkpass_lumina-checkpass.pro
@@ -0,0 +1,11 @@
+--- lumina-checkpass/lumina-checkpass.pro.orig	2021-12-26 02:33:45 UTC
++++ lumina-checkpass/lumina-checkpass.pro
+@@ -13,6 +13,7 @@ LIBS     += -lpam
+ SOURCES += main.c
+ 
+ perms.path = $$DESTDIR$${PREFIX}/sbin
+-perms.extra = "chmod 4555 $$DESTDIR$${PREFIX}/sbin/lumina-checkpass"
++# FIXME: This does not work: DESTDIR is blank
++# perms.extra = "chmod 4555 $$DESTDIR$${PREFIX}/sbin/lumina-checkpass"
+ 
+ INSTALLS += target perms
diff --git a/x11/lumina-core/files/patch-lumina-checkpass_main.c b/x11/lumina-core/files/patch-lumina-checkpass_main.c
new file mode 100644
index 000000000000..b00f50f5858a
--- /dev/null
+++ b/x11/lumina-core/files/patch-lumina-checkpass_main.c
@@ -0,0 +1,122 @@
+--- lumina-checkpass/main.c.orig	2021-12-26 02:33:45 UTC
++++ lumina-checkpass/main.c
+@@ -18,11 +18,14 @@
+ #include <stdio.h> 	// Usage output
+ #include <pwd.h>  		// User DB information
+ #include <string.h>
++#include <sysexits.h>
+ 
+ //PAM/security libraries
+ #include <sys/types.h>
+ #include <security/pam_appl.h>
+ 
++#define	AUTH_FAILED	1
++
+ //Found this little snippet from SDDM - nice alternative to using the entire openpam library from FreeBSD
+ static int PAM_conv(
+ 	int num_msg,
+@@ -30,18 +33,19 @@ static int PAM_conv(
+ 	struct pam_response **resp,
+ 	void *ctx)
+ {
+-	return 0;
++	return PAM_SUCCESS;
+ }
+ //-----
+ 
+ 
+ void showUsage(){
+-    puts("lumina-checkpass: Simple user-level check for password validity (for screen unlockers and such).");
+-    puts("Usage:");
+-    //puts("  lumina-checkpass <password>");
+-    puts("  lumina-checkpass -fd <file descriptor>");
+-    puts("  lumina-checkpass -f <file path>");
+-    puts("Returns: 0 for a valid password, 1 for invalid");
++    fputs("lumina-checkpass: Simple user-level check for password validity (for screen unlockers and such).", stderr);
++    fputs("Usage:", stderr);
++    //fputs("  lumina-checkpass <password>", stderr);
++    fputs("  lumina-checkpass -fd <file descriptor>", stderr);
++    fputs("  lumina-checkpass -f <file path>", stderr);
++    fputs("Returns: 0 for a valid password, 1 for invalid", stderr);
++    exit(AUTH_FAILED);	// FIXME: Switch to EX_USAGE, or do callers depend on 1?
+ }
+ 
+ int main(int argc, char** argv){
+@@ -49,13 +53,20 @@ int main(int argc, char** argv){
+   if(argc!=3){
+     //Invalid inputs - show the help text
+     showUsage();
+-    return 1;
+   }
+-  char*pass = 0;
++  char *pass = NULL;
+   if(argc==3 && 0==strcmp(argv[1],"-fd") ){
+-    FILE *fp = fdopen(atoi(argv[2]), "r");
++    // This replaces dangerous atoi(), which does no validation
++    char *end;
++    int fd = strtol(argv[2], &end, 10);
++    if ( *end != '\0' )
++    {
++      fprintf(stderr, "Invalid file descriptor: %s\n", argv[2]);
++      showUsage();
++    }
++    FILE *fp = fdopen(fd, "r");
+     size_t len;
+-    if(fp!=0){
++    if(fp!=NULL){
+       ssize_t slen = getline(&pass, &len, fp);
+       if(pass[slen-1]=='\n'){ pass[slen-1] = '\0'; }
+     }
+@@ -63,26 +74,25 @@ int main(int argc, char** argv){
+   }else if(argc==3 && 0==strcmp(argv[1],"-f") ){
+     FILE *fp = fopen(argv[2], "r");
+     size_t len;
+-    if(fp!=0){
++    if(fp!=NULL){
+       ssize_t slen = getline(&pass, &len, fp);
+       if(pass[slen-1]=='\n'){ pass[slen-1] = '\0'; }
+     }else{
+-      puts("[ERROR] Unknown option provided");
+-      puts("----------------");
++      fputs("[ERROR] Unknown option provided", stderr);
++      fputs("----------------", stderr);
+       showUsage();
+-      return 1;
+     }
+     fclose(fp);
+   }
+-  if(pass == 0){ puts("Could not read password!!"); return 1; } //error in reading password
++  if(pass == NULL){ fputs("Could not read password!!", stderr); return AUTH_FAILED; } //error in reading password
+   //puts("Read Password:");
+   //puts(pass);
+   //Validate current user (make sure current UID matches the logged-in user,
+   char* cUser = getlogin();
+-  struct passwd *pwd = 0;
++  struct passwd *pwd = NULL;
+   pwd = getpwnam(cUser);
+-  if(pwd==0){ return 1; } //Login user could not be found in the database? (should never happen)
+-  if( getuid() != pwd->pw_uid ){ return 1; } //Current UID does not match currently logged-in user UID
++  if(pwd==NULL){ return AUTH_FAILED; } //Login user could not be found in the database? (should never happen)
++  if( getuid() != pwd->pw_uid ){ return AUTH_FAILED; } //Current UID does not match currently logged-in user UID
+   //Create the non-interactive PAM structures
+   pam_handle_t *pamh;
+   struct pam_conv pamc = { &PAM_conv, 0 };
+@@ -92,15 +102,15 @@ int main(int argc, char** argv){
+ #else
+     int ret = pam_start( "system-auth", cUser, &pamc, &pamh);
+ #endif
+-    if(ret != PAM_SUCCESS){ puts("Could not initialize PAM"); return 1; } //could not init PAM
++    if(ret != PAM_SUCCESS){ fputs("Could not initialize PAM", stderr); return AUTH_FAILED; } //could not init PAM
+     //char* cPassword = argv[1];
+     ret = pam_set_item(pamh, PAM_AUTHTOK, pass);
+-    if(ret != PAM_SUCCESS){ puts("Could not set conversation structure"); }
++    if(ret != PAM_SUCCESS){ fputs("Could not set conversation structure", stderr); }
+     //Authenticate with PAM
+     ret = pam_authenticate(pamh,0); //this can be true without verifying password if pam_self.so is used in the auth procedures (common)
+     if( ret == PAM_SUCCESS ){ ret = pam_acct_mgmt(pamh,0); } //Check for valid, unexpired account and verify access restrictions
+     //Stop the PAM instance
+     pam_end(pamh,ret);
+   //return verification result
+-  return ((ret==PAM_SUCCESS) ? 0 : 1);
++  return ret == PAM_SUCCESS ? EX_OK : AUTH_FAILED;
+ }
diff --git a/x11/lumina-core/files/patch-lumina-desktop_LPanel.cpp b/x11/lumina-core/files/patch-lumina-desktop_LPanel.cpp
new file mode 100644
index 000000000000..ee652f204370
--- /dev/null
+++ b/x11/lumina-core/files/patch-lumina-desktop_LPanel.cpp
@@ -0,0 +1,14 @@
+--- lumina-desktop/LPanel.cpp.orig	2021-12-26 02:33:45 UTC
++++ lumina-desktop/LPanel.cpp
+@@ -74,7 +74,10 @@ LPanel::LPanel(QSettings *file, QString scr, int num, 
+     //panelArea->setWindowOpacity(1.0); //fully opaque for the widget on top (apply stylesheet transparencies)
+   }
+   QTimer::singleShot(1,this, SLOT(UpdatePanel()) );
+-  //connect(screen, SIGNAL(resized(int)), this, SLOT(UpdatePanel()) ); //in case the screen resolution changes
++  // This apparently should not be necessary, but the main panel does not
++  // redraw reliably without it.  Be sure to fully test resizing a
++  // FreeBSD VirtualBox guest before replacing this.
++  connect(screen, SIGNAL(resized(int)), this, SLOT(UpdatePanel()) ); //in case the screen resolution changes
+ }
+ 
+ LPanel::~LPanel(){
diff --git a/x11/lumina-core/files/patch-lumina-desktop_src-screensaver_LLockScreen.cpp b/x11/lumina-core/files/patch-lumina-desktop_src-screensaver_LLockScreen.cpp
new file mode 100644
index 000000000000..238a58300a19
--- /dev/null
+++ b/x11/lumina-core/files/patch-lumina-desktop_src-screensaver_LLockScreen.cpp
@@ -0,0 +1,22 @@
+--- lumina-desktop/src-screensaver/LLockScreen.cpp.orig	2021-12-26 02:33:45 UTC
++++ lumina-desktop/src-screensaver/LLockScreen.cpp
+@@ -79,7 +79,9 @@ void LLockScreen::TryUnlock(){
+   this->setEnabled(false);
+   QString pass = ui->line_password->text();
+     ui->line_password->clear();
+-  //Create a temporary file for the password, then pass that file descriptor to lumina-checkpass
++  // Create a temporary file for the password, then pass that file descriptor
++  // to lumina-checkpass. Might seem wacky to shell this out, but we need
++  // SUID to authenticate the pw with PAM.
+   QTemporaryFile *TF = new QTemporaryFile(".XXXXXXXXXX");
+   TF->setAutoRemove(true);
+   bool ok = false;
+@@ -90,7 +92,7 @@ void LLockScreen::TryUnlock(){
+     if(DEBUG){ qDebug() << "Trying to unlock session:" << getlogin(); }
+     LUtils::runCommand(ok, "lumina-checkpass",QStringList() << "-f" << TF->fileName() );
+     if(DEBUG){ qDebug() << " - Success:" << ok; }
+-    ok = true; //bypass for the moment
++    // ok = true; //bypass if lumina-checkpass is not working
+   }
+   delete TF; //ensure the temporary file is removed **right now** for security purposes
+   if(ok){
diff --git a/x11/lumina-core/pkg-plist b/x11/lumina-core/pkg-plist
index 13b5ef2475b3..3f84230df157 100644
--- a/x11/lumina-core/pkg-plist
+++ b/x11/lumina-core/pkg-plist
@@ -12,6 +12,7 @@ man/man1/lumina-desktop.1.gz
 man/man1/lumina-info.1.gz
 man/man1/lumina-open.1.gz
 man/man8/start-lumina-desktop.8.gz
+@(root,wheel,4555) sbin/lumina-checkpass
 share/applications/lthemeengine.desktop
 share/applications/lumina-info.desktop
 share/applications/lumina-support.desktop