10 #include <security/pam_appl.h>
15 , _group(group.toLower())
36 QMutexLocker l(&
_lock);
38 QJsonObject d = r->
_data.object();
40 bool auth = r->
_path ==
"";
42 QString user = auth ? d[
"username"].toString(
"") : r->
_path;
43 QString pass = d[
"password"].toString(
"");
46 printf(
"user:'%s' auth:%d service:'%s'\n",qUtf8Printable(user),auth,qUtf8Printable(
_service));
50 r->
_reason =
"Username cannot be empty.";
61 struct passwd *pw = getpwnam( qUtf8Printable(user) );
67 d[
"uidnumber"] = (int) pw->pw_uid;
69 QString realname(pw->pw_gecos);
70 if (realname.isEmpty())
72 d[
"realname"] = realname;
80 r->
_data.setObject(d);
87 VFS::WARN(
"User was authenticated, but did not belong to group '"+
_group+
"'");
108 printf(
"filter group: %s\n",qUtf8Printable(
_group));
114 while((pw = getpwent()) !=
nullptr)
117 printf(
"name=%s uid=%d group=%d real=%s\n",pw->pw_name,pw->pw_uid,pw->pw_gid,pw->pw_gecos);
126 QString username(pw->pw_name);
127 int uidnumber((
int)pw->pw_uid);
128 QString realname(pw->pw_gecos);
129 if (realname.isEmpty())
132 o[username] = QJsonObject {
133 {
"username", username },
134 {
"uidnumber", uidnumber },
135 {
"realname", realname }
141 QJsonObject u = r->
_data.object();
143 r->
_data.setObject(u);
147 printf(
"USERS: %s",qUtf8Printable( r->
_data.toJson() ));
152 for (
int i=0; i<nresp; ++i)
154 if (resp[i].resp !=
nullptr)
156 memset(resp[i].resp, 0, strlen(resp[i].resp));
161 memset(resp, 0, (
unsigned long) nresp *
sizeof *resp);
168 const struct pam_message **msg,
169 struct pam_response **resp,
173 if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
176 struct pam_response *r;
177 if ((r = (pam_response *)calloc((
size_t) num_msg,
sizeof *r)) ==
nullptr)
180 QJsonObject *data = (QJsonObject *) appdata;
182 for (
int i=0; i<num_msg; i++)
185 r[i].resp_retcode = 0;
187 switch(msg[i]->msg_style)
189 case PAM_PROMPT_ECHO_ON:
190 case PAM_PROMPT_ECHO_OFF:
193 r[i].resp = strdup(qUtf8Printable((*data)[
"password"].toString()));
194 r[i].resp_retcode = PAM_SUCCESS;
199 VFS::ERROR(QString(
"%1").arg(msg[i]->msg),0,
"pam");
200 r[i].resp_retcode = PAM_SUCCESS;
205 VFS::LOG(QString(
"%1").arg(msg[i]->msg),0,
"pam");
206 r[i].resp_retcode = PAM_SUCCESS;
211 VFS::ERROR(QString(
"Unknown msg_style: %1").arg(msg[i]->msg),0,
"pam");
226 d[
"username"] = user;
227 d[
"password"] = pass;
229 pam_handle_t *pamh=
nullptr;
232 struct pam_conv pam_conversation = {
237 retval = pam_start( qUtf8Printable(
_service), qUtf8Printable(user), &pam_conversation, &pamh );
239 #ifdef HAVE_PAM_FAIL_DELAY
240 if (retval == PAM_SUCCESS)
241 retval = pam_fail_delay (pamh, 0 );
244 if (retval == PAM_SUCCESS)
245 retval = pam_authenticate(pamh, 0);
247 if (
_debug && retval == PAM_USER_UNKNOWN)
250 if (retval == PAM_SUCCESS)
251 retval = pam_acct_mgmt(pamh, 0);
253 if (retval == PAM_SUCCESS)
258 if ( pam_end(pamh,retval) != PAM_SUCCESS )
269 QJsonArray groupList;
279 static int groups[NGROUPS_MAX];
281 static gid_t groups[NGROUPS_MAX];
284 int ngroups = NGROUPS_MAX;
285 if (getgrouplist(pw->pw_name, (
int) pw->pw_gid, groups, &ngroups) > -1)
287 for (
int i = 0; i < ngroups; i++)
291 struct group* gr = getgrgid((gid_t)groups[i]);
301 printf(
"%s\n",gr->gr_name);
303 QString gname(gr->gr_name);
305 if (!gname.startsWith(
"_"))
306 groupList << gname.toLower();
int pam_conv_func(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
int pam_conv_free(pam_response *resp, int nresp)
The base class for authenticating users.
QString className()
Return the class name of a node.
QMutex _lock
A recursive mutex that is local to this node.
virtual void read(VFS_request *r)
Return the data contents of this node, or if it's a container call ls()
QJsonArray getGroups(passwd *pw)
Q_INVOKABLE VFS_pam(QString service, QString group, bool debug=false)
virtual void ls(VFS_request *r)
List the contents of this node.
bool validUserPass(QString user, QString password)
QString _service
the pam service file name
virtual QString reportDetails()
Additional details for a generated report.
QString _group
the group (or empty) a user must belong to and also the group whose members will be returned by ls()
The base class for all requests between nodes.
QString _initialPath
the target path when the request was made (relative to the responder)
QString _reason
if something (probably bad) happened, this is the reason
QString _path
the target path remnant... the remaining path element once the request has found its target
bool _success
if the request was successfully completed
QJsonDocument _data
the request payload
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.