source: src-qt4/PCDM/src/pcdm-xprocess.cpp @ 1620346

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since 1620346 was 1620346, checked in by Kris Moore <kris@…>, 18 months ago

Initial import of PC-BSD /current/ SVN repo

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/* PCDM Login Manager:
2*  Written by Ken Moore (ken@pcbsd.org) 2012/2013
3*  Copyright(c) 2013 by the PC-BSD Project
4*  Available under the 3-clause BSD license
5*/
6
7/*
8Sub-classed QProcess for starting an XSession Process
9*/
10
11#include "pcdm-xprocess.h"
12
13XProcess::XProcess() : QProcess(0) {
14  //initialize the variables
15  xuser.clear();
16  xcmd.clear();
17  xhome.clear();
18  xpwd.clear();
19  pam_started = FALSE;
20  pam_session_open = FALSE;
21  //Setup the finished signal/slot
22  connect( this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotCleanup(int, QProcess::ExitStatus)) );
23}
24
25XProcess::~XProcess(){
26  if( isRunning() ){
27    this->terminate();
28  }
29  this->close();
30}
31
32void XProcess::loginToXSession(QString username, QString password, QString homedir, QString cmd){
33  //Setup the variables
34  xuser = username;
35  xpwd = password;
36  xhome = homedir;
37  xcmd = cmd;
38  //Now start the login process
39  startXSession();
40}
41
42bool XProcess::isRunning(){
43  if(this->state() != QProcess::NotRunning){ return TRUE; }
44  else{ return FALSE; }
45}
46
47void XProcess::waitForSessionClosed(){
48  // CAUTION!!
49  // This function will pause the calling program to wait for the session to end!
50  if( isRunning() ){
51    this->waitForFinished(-1);
52  }
53}
54
55/*
56 ========== SESSION STARTUP ==========
57*/
58
59bool XProcess::startXSession(){
60  //Check that the necessary info to start the session is available
61  if( xuser.isEmpty() || xcmd.isEmpty() || xhome.isEmpty() ){
62    emit InvalidLogin();  //Make sure the GUI knows that it was a failure
63    return FALSE;
64  }
65  //Backend::log("Starting up Desktop environment ("+xcmd+") as user ("+xuser+")");
66 
67  //Check for PAM username/password validity
68  if( !pam_checkPW() ){ emit InvalidLogin(); pam_shutdown(); return FALSE; }
69  //Startup the PAM session
70  if( !pam_startSession() ){ pam_shutdown(); return FALSE; }
71  pam_session_open = TRUE; //flag that pam has an open session
72 
73  // Configure the DE startup command
74  QString cmd = "su "+xuser+" -c \""; //switch user command to start process properly
75  //  - Setup to run the user's <home-dir>/.xprofile startup script
76  if(QFile::exists(xhome+"/.xprofile")){
77    cmd.append("(/bin/sh "+xhome+"/.xprofile) &; ");  //make sure to start it in parallel
78  }
79  //  - Add the DE startup command to the end
80  cmd.append(xcmd);
81  //  - Finish up the command formatting
82  cmd.append("\"");
83 
84  //Backend::log("Startup command: "+cmd);
85  // Get the current locale code
86  QLocale mylocale;
87  QString langCode = mylocale.name();
88  // Setup the process environment
89  QProcessEnvironment environ = QProcessEnvironment::systemEnvironment(); //current environment
90
91  // Setup any specialized environment variables
92  // USER, HOME, and SHELL are set by the "su" login
93  environ.insert("LOGNAME",xuser); //Login name
94  environ.insert("USERNAME",xuser); // Username
95  environ.insert("PATH",environ.value("PATH")+":"+xhome+"/bin"); // Append the user's home dir to the path
96  if( langCode.toLower() == "c" ){} // do nothing extra to it
97  else if(!environ.value("MM_CHARSET").isEmpty() ){ langCode.append( "."+environ.value("MM_CHARSET") ); }
98  else{ langCode.append(".UTF-8"); }
99  environ.insert("LANG",langCode); //Set the proper localized language
100  environ.insert("MAIL","/var/mail/"+xuser); //Set the mail variable
101  environ.insert("GROUP",xuser); //Set the proper group id
102  environ.insert("SHLVL","1"); //Set the proper shell level
103  this->setProcessEnvironment(environ);
104  this->setWorkingDirectory(xhome); //set the current directory to the user's home directory
105  //Log the DE startup outputs as well
106  this->setStandardOutputFile(xhome+"/.pcdm-startup.log",QIODevice::Truncate);
107  // Startup the process
108  this->start(cmd);
109  return TRUE;
110}
111
112void XProcess::slotCleanup(int exitCode, QProcess::ExitStatus status){
113  pam_shutdown(); //make sure that PAM shuts down properly     
114}
115
116/*
117 ========== PAM FUNCTIONS ==========
118*/
119static struct pam_conv pamc = { openpam_nullconv, NULL };
120
121bool XProcess::pam_checkPW(){
122 //Requires internal "xuser" and "xpwd" variables to be set
123       
124//Convert the inputs to C character arrays for use in PAM
125  QByteArray tmp = xuser.toUtf8();
126  char* cUser = tmp.data();
127  QByteArray tmp2 = xpwd.toUtf8();
128  char* cPassword = tmp2.data();
129  //initialize variables
130  bool result = FALSE;
131  int ret;
132  //Initialize PAM
133  ret = pam_start("login", cUser, &pamc, &pamh);
134  if( ret == PAM_SUCCESS ){
135    pam_started = TRUE; //flag that pam is started
136    //Place the user-supplied password into the structure
137    ret = pam_set_item(pamh, PAM_AUTHTOK, cPassword);
138    //Set the TTY
139    //ret = pam_set_item(pamh, PAM_TTY, "pcdm-terminal");
140    //Authenticate with PAM
141    ret = pam_authenticate(pamh,0);
142    if( ret == PAM_SUCCESS ){
143      //Check for valid, unexpired account and verify access restrictions
144      ret = pam_acct_mgmt(pamh,0);
145      if( ret == PAM_SUCCESS ){ result = TRUE; }
146   
147    }else{
148      pam_logFailure(ret);
149    }
150  }
151  //return verification result
152  return result;       
153}
154
155bool XProcess::pam_startSession(){
156  //This should only be run if pam_checkPW was successful
157  int ret = pam_open_session(pamh,0);
158  bool ok = FALSE;
159  if(ret == PAM_SUCCESS){ ok = TRUE; }
160  else{ pam_logFailure(ret); }
161 
162  return ok;
163}
164
165bool XProcess::pam_stopSession(){
166  //This should only be run if pam_startSession was successful
167  int ret = pam_close_session(pamh,0);
168  bool ok = FALSE;
169  if(ret == PAM_SUCCESS){ ok = TRUE; }
170  else{ pam_logFailure(ret); }
171 
172  return ok;
173}
174
175void XProcess::pam_logFailure(int ret){
176  //Interpret a PAM error message and log it
177  Backend::log("PAM Error: " + QString::number(ret));
178  switch( ret ){
179  case PAM_ABORT:
180    Backend::log(" - PAM abort error");
181    break;
182  case PAM_AUTHINFO_UNAVAIL:
183    Backend::log(" - Authentication info unavailable");
184    break;
185  case PAM_AUTH_ERR:
186    Backend::log(" - Authentication error");
187    break;
188  case PAM_BUF_ERR:
189    Backend::log(" - Buffer error");
190    break;
191  case PAM_CONV_ERR:
192    Backend::log(" - Conversion error");
193    break;
194  case PAM_CRED_INSUFFICIENT:
195    Backend::log(" - Credentials insufficient");
196    break;
197  case PAM_MAXTRIES:
198    Backend::log(" - Maximum number of tries exceeded");
199    break;
200  case PAM_PERM_DENIED:
201    Backend::log(" - Permission denied");
202    break;
203  case PAM_SERVICE_ERR:
204    Backend::log(" - Service error");
205    break;
206  case PAM_SYMBOL_ERR:
207    Backend::log(" - Symbol error");
208    break;
209  case PAM_SYSTEM_ERR:
210    Backend::log(" - System error");
211    break;
212  case PAM_USER_UNKNOWN:
213    Backend::log(" - Unknown user");
214    break;
215  default:
216    Backend::log(" - Unrecognized authentication error");
217  }
218       
219}
220
221void XProcess::pam_shutdown(){
222  if(pam_session_open){
223    pam_stopSession();
224    pam_session_open = FALSE;
225  }
226  if(pam_started){
227    pam_end(pamh,0);
228    pam_started = FALSE;
229  }
230}
Note: See TracBrowser for help on using the repository browser.