10#include "config-util.h"
11#include "kcoreaddons_debug.h"
25#if defined(__BIONIC__) && __ANDROID_API__ < 26
26static inline struct passwd *getpwent()
33static inline void setgrent()
36static inline struct group *getgrent()
43static inline void endgrent()
49#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
50static int os_pw_size()
52 const int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
61#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID) && (__ANDROID_API__ >= 24))
62static int os_gr_size()
64 const int size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
75 uid_t uid = uid_t(-1);
76 gid_t gid = gid_t(-1);
84 KUserPrivate(
const char *name)
89 struct passwd *pw =
nullptr;
90#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
91 static const int bufsize = os_pw_size();
94 getpwnam_r(name, &entry, buf.data(), buf.size(), &pw);
101 KUserPrivate(K_UID uid)
103 struct passwd *pw =
nullptr;
104#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
105 static const int bufsize = os_pw_size();
108 getpwuid_r(uid, &entry, buf.data(), buf.size(), &pw);
114 KUserPrivate(
const passwd *p)
119 void fillPasswd(
const passwd *p)
129 while (gecosList.
size() < 4) {
140 if (uid == ::getuid() && uid == ::geteuid()) {
153 uid_t _uid = ::getuid();
156 d =
new KUserPrivate(_euid);
158 d =
new KUserPrivate(qgetenv(
"LOGNAME").constData());
159 if (d->uid != _uid) {
160 d =
new KUserPrivate(qgetenv(
"USER").constData());
161 if (d->uid != _uid) {
162 d =
new KUserPrivate(_uid);
169 : d(new KUserPrivate(_uid))
174 : d(new KUserPrivate(_uid.nativeId()))
179 : d(new KUserPrivate(name.toLocal8Bit().data()))
184 : d(new KUserPrivate(name))
189 : d(new KUserPrivate(p))
206 return isValid() && (d->uid == user.d->uid);
211 return d->uid != uid_t(-1);
242 if (!d->loginName.isEmpty()) {
243 pathToFaceIcon = QStringLiteral(ACCOUNTS_SERVICE_ICON_DIR) +
QLatin1Char(
'/') + d->loginName;
247 return pathToFaceIcon;
252 if (
QFileInfo(pathToFaceIcon).isReadable()) {
253 return pathToFaceIcon;
265static void listGroupsForUser(
const char *name, gid_t gid, uint maxCount, Func handleNextGroup)
267 if (Q_UNLIKELY(maxCount == 0)) {
274 int numGroups = gid_buffer.
size();
275 int result = getgrouplist(name, gid, gid_buffer.
data(), &numGroups);
276 if (result < 0 && uint(numGroups) < maxCount) {
278 qCDebug(KCOREADDONS_DEBUG) <<
"Buffer was too small: " << gid_buffer.
size() <<
", need" << numGroups;
279 gid_buffer.
resize(numGroups);
280 numGroups = gid_buffer.
size();
281 getgrouplist(name, gid, gid_buffer.
data(), &numGroups);
283 for (
int i = 0; i < numGroups && found < maxCount; ++i) {
284 struct group *g = getgrgid(gid_buffer[i]);
295 struct group *g = getgrgid(gid);
299 if (found >= maxCount) {
304 static const auto groupContainsUser = [](
struct group *g,
const char *
name) ->
bool {
305 for (
char **user = g->gr_mem; *user; user++) {
306 if (strcmp(name, *user) == 0) {
314 while ((g = getgrent())) {
316 if (g->gr_gid != gid && groupContainsUser(g, name)) {
319 if (found >= maxCount) {
331 listGroupsForUser(d->loginName.toLocal8Bit().constData(), d->gid, maxCount, [&](
const group *g) {
332 result.append(KUserGroup(g));
340 listGroupsForUser(d->loginName.toLocal8Bit().constData(), d->gid, maxCount, [&](
const group *g) {
341 result.append(QString::fromLocal8Bit(g->gr_name));
348 return d->properties.value(which);
358 for (uint i = 0; i < maxCount && (p = getpwent()); ++i) {
374 for (uint i = 0; i < maxCount && (p = getpwent()); ++i) {
389 gid_t gid = gid_t(-1);
395 KUserGroupPrivate(
const char *_name)
397 fillGroup(_name ? ::getgrnam(_name) :
nullptr);
399 KUserGroupPrivate(K_GID gid)
401 struct group *gr =
nullptr;
402#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID) && (__ANDROID_API__ >= 24))
403 static const int bufsize = os_gr_size();
408 for (
int size = bufsize; size < 256000; size += size) {
411 if (!getgrgid_r(gid, &entry, buf.data(), buf.size(), &gr) || errno != ERANGE) {
420 KUserGroupPrivate(const ::group *p)
425 void fillGroup(const ::group *p)
435 : d(new KUserGroupPrivate(
KUser(mode).groupId().nativeId()))
440 : d(new KUserGroupPrivate(_gid))
445 : d(new KUserGroupPrivate(_gid.nativeId()))
450 : d(new KUserGroupPrivate(_name.toLocal8Bit().data()))
455 : d(new KUserGroupPrivate(_name))
460 : d(new KUserGroupPrivate(g))
477 return isValid() && (d->gid == group.d->gid);
482 return d->gid != gid_t(-1);
495static void listGroupMembers(gid_t gid, uint maxCount, std::function<
void(passwd *)> handleNextGroupUser)
500 struct group *g = getgrgid(gid);
506 struct passwd *p =
nullptr;
507 for (
char **user = g->gr_mem; *user; user++) {
508 if ((p = getpwnam(*user))) {
509 addedUsers.
append(p->pw_uid);
510 handleNextGroupUser(p);
512 if (found >= maxCount) {
520 while ((p = getpwent()) && found < maxCount) {
521 if (p->pw_gid != gid) {
525 if (std::find(addedUsers.
cbegin(), addedUsers.
cend(), p->pw_uid) == addedUsers.
cend()) {
526 handleNextGroupUser(p);
536 listGroupMembers(d->gid, maxCount, [&](
const passwd *p) {
537 result.append(KUser(p));
545 listGroupMembers(d->gid, maxCount, [&](
const passwd *p) {
546 result.append(QString::fromLocal8Bit(p->pw_name));
558 for (uint i = 0; i < maxCount && (g = getgrent()); ++i) {
574 for (uint i = 0; i < maxCount && (g = getgrent()); ++i) {
593 struct passwd *p = ::getpwnam(name8Bit.
constData());
595 qCWarning(KCOREADDONS_DEBUG,
"Failed to lookup user %s: %s", name8Bit.
constData(), strerror(errno));
607 struct group *g = ::getgrnam(name8Bit.
constData());
609 qCWarning(KCOREADDONS_DEBUG,
"Failed to lookup group %s: %s", name8Bit.
constData(), strerror(errno));
Represents a group on your system.
QStringList userNames(uint maxCount=KCOREADDONS_UINT_MAX) const
static QList< KUserGroup > allGroups(uint maxCount=KCOREADDONS_UINT_MAX)
QString name() const
The name of the group.
KUserGroup(const QString &name)
Create an object from a group name.
bool isValid() const
Returns whether the group is valid.
QList< KUser > users(uint maxCount=KCOREADDONS_UINT_MAX) const
bool operator==(const KUserGroup &group) const
Two KUserGroup objects are equal if their gid()s are identical.
static QStringList allGroupNames(uint maxCount=KCOREADDONS_UINT_MAX)
KUserGroup & operator=(const KUserGroup &group)
Copies a group.
Represents a user on your system.
QString faceIconPath() const
The path to the user's face file.
KUser(UIDMode mode=UseEffectiveUID)
Creates an object that contains information about the current user.
QString homeDir() const
The path to the user's home directory.
QVariant property(UserProperty which) const
Returns an extended property.
QList< KUserGroup > groups(uint maxCount=KCOREADDONS_UINT_MAX) const
QString shell() const
The path to the user's login shell.
bool operator==(const KUser &user) const
Two KUser objects are equal if the userId() are identical.
QStringList groupNames(uint maxCount=KCOREADDONS_UINT_MAX) const
QString loginName() const
The login name of the user.
bool isValid() const
Returns true if the user is valid.
static QList< KUser > allUsers(uint maxCount=KCOREADDONS_UINT_MAX)
bool isSuperUser() const
Checks whether the user is the super user (root).
KUser & operator=(const KUser &user)
Copies a user.
static QStringList allUserNames(uint maxCount=KCOREADDONS_UINT_MAX)
@ UseEffectiveUID
Use the effective user id.
QString name(StandardAction id)
const char * constData() const const
QString decodeName(const QByteArray &localFileName)
bool exists() const const
void append(QList< T > &&value)
qsizetype size() const const
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toLocal8Bit() const const
const_iterator cbegin() const const
const_iterator cend() const const
void resize(qsizetype size)
qsizetype size() const const
A platform independent group ID.
static KGroupId fromName(const QString &name)
KGroupId()
Creates an invalid KGroupId.
static KGroupId currentGroupId()
static KGroupId currentEffectiveGroupId()
A platform independent user ID.
static KUserId currentUserId()
KUserId()
Creates an invalid KUserId.
static KUserId fromName(const QString &name)
static KUserId currentEffectiveUserId()