1 //===========================================
2 // Lumina-DE source code
3 // Copyright (c) 2015, Ken Moore
4 // Available under the 3-clause BSD license
5 // See the LICENSE file for full details
6 //===========================================
7 // This function provides the basic current-user password validation
8 // The binary may need to have an effective root UID (setuid as root: "chmod 4555")
9 // so that PAM can actually check the validity of the password.
10 //===========================================
11 // SECURITY NOTE:
12 // It is highly recomended that you have your PAM rules setup to disallow password checks for a time
13 // after a number of failed attempts to prevent a user-level script from hammering this utility
14 //===========================================
15 //Standard C libary
16 #include <unistd.h> // Standard C
17 #include <stdlib.h>
18 #include <stdio.h> // Usage output
19 #include <pwd.h> // User DB information
20 #include <string.h>
21
22 //PAM/security libraries
23 #include <sys/types.h>
24 #include <security/pam_appl.h>
25 #include <security/openpam.h>
26
showUsage()27 void showUsage(){
28 puts("lumina-checkpass: Simple user-level check for password validity (for screen unlockers and such).");
29 puts("Usage:");
30 //puts(" lumina-checkpass <password>");
31 puts(" lumina-checkpass -fd <file descriptor>");
32 puts(" lumina-checkpass -f <file path>");
33 puts("Returns: 0 for a valid password, 1 for invalid");
34 }
35
main(int argc,char ** argv)36 int main(int argc, char** argv){
37 //Check the inputs
38 if(argc!=3){
39 //Invalid inputs - show the help text
40 showUsage();
41 return 1;
42 }
43 char*pass = 0;
44 if(argc==3 && 0==strcmp(argv[1],"-fd") ){
45 FILE *fp = fdopen(atoi(argv[2]), "r");
46 size_t len;
47 if(fp!=0){
48 ssize_t slen = getline(&pass, &len, fp);
49 if(pass[slen-1]=='\n'){ pass[slen-1] = '\0'; }
50 }
51 fclose(fp);
52 }else if(argc==3 && 0==strcmp(argv[1],"-f") ){
53 FILE *fp = fopen(argv[2], "r");
54 size_t len;
55 if(fp!=0){
56 ssize_t slen = getline(&pass, &len, fp);
57 if(pass[slen-1]=='\n'){ pass[slen-1] = '\0'; }
58 }else{
59 puts("[ERROR] Unknown option provided");
60 puts("----------------");
61 showUsage();
62 return 1;
63 }
64 fclose(fp);
65 }
66 if(pass == 0){ puts("Could not read password!!"); return 1; } //error in reading password
67 //puts("Read Password:");
68 //puts(pass);
69 //Validate current user (make sure current UID matches the logged-in user,
70 char* cUser = getlogin();
71 struct passwd *pwd = 0;
72 pwd = getpwnam(cUser);
73 if(pwd==0){ return 1; } //Login user could not be found in the database? (should never happen)
74 if( getuid() != pwd->pw_uid ){ return 1; } //Current UID does not match currently logged-in user UID
75 //Create the non-interactive PAM structures
76 pam_handle_t *pamh;
77 struct pam_conv pamc = { openpam_nullconv, NULL };
78 //Place the user-supplied password into the structure
79 int ret = pam_start( "system", cUser, &pamc, &pamh);
80 if(ret != PAM_SUCCESS){ return 1; } //could not init PAM
81 //char* cPassword = argv[1];
82 ret = pam_set_item(pamh, PAM_AUTHTOK, pass);
83 //Authenticate with PAM
84 ret = pam_authenticate(pamh,0); //this can be true without verifying password if pam_self.so is used in the auth procedures (common)
85 if( ret == PAM_SUCCESS ){ ret = pam_acct_mgmt(pamh,0); } //Check for valid, unexpired account and verify access restrictions
86 //Stop the PAM instance
87 pam_end(pamh,ret);
88 //return verification result
89 return ((ret==PAM_SUCCESS) ? 0 : 1);
90 }
91