ページの作成:「== 概要 == <br><br> == Linuxのグループの取得 == 以下の例では、現在のユーザが所属しているグループ名を取得している。<br> <br> 標準C++とPOSIX APIのみを使用している。<br> ただし、この実装はUNIX系システム (Linux、MacOS) 向けであるため、Windowsでは動作しないことに注意すること。<br> Windowsで同様の機能を実装する場合は、Windows APIを使用する必要がある。…」 |
|||
| (同じ利用者による、間の1版が非表示) | |||
| 1行目: | 1行目: | ||
== 概要 == | == 概要 == | ||
LinuxをはじめとするUNIX系オペレーティングシステムでは、ユーザとグループの概念がシステムのセキュリティとアクセス制御の基盤となっている。<br> | |||
<br> | |||
各ユーザには一意のユーザID (UID) が割り当てられ、各グループには一意のグループID (GID) が割り当てられる。<br> | |||
ユーザは1つ以上のグループに所属することができ、これによってファイルシステムのパーミッションやリソースアクセスが制御される。<br> | |||
<br> | |||
C++プログラムからこれらのユーザおよびグループ情報にアクセスする必要がある場合、POSIX標準で定義されているシステムコールとライブラリ関数を使用する。<br> | |||
以下に示すような用途でこれらのAPIが使用される。<br> | |||
* システム管理ツールの開発 | |||
* ファイルアクセス制御の実装 | |||
* プロセス権限の確認と管理 | |||
* セキュリティ監査ログの記録 | |||
* マルチユーザ環境でのリソース管理 | |||
<br> | |||
<u>※注意</u><br> | |||
<u>UNIX系システム (Linux、BSD等) 専用であり、Windowsでは動作しない。</u><br> | |||
<u>Windows環境では、Windows APIを使用した別の実装が必要となる。</u><br> | |||
<br> | |||
参考文献を以下に示す。<br> | |||
* [https://pubs.opengroup.org/onlinepubs/9699919799/ POSIX.1-2017 Standard] | |||
* Linux Man Pages: | |||
** [https://man7.org/linux/man-pages/man3/getpwuid.3.html getpwuid(3)] | |||
** [https://man7.org/linux/man-pages/man3/getgrgid.3.html getgrgid(3)] | |||
** [https://man7.org/linux/man-pages/man3/getgrouplist.3.html getgrouplist(3)] | |||
<br><br> | |||
== 使用する主なPOSIX API関数 == | |||
ユーザとグループの情報を取得するため、POSIX API関数が使用される。<br> | |||
<br> | |||
==== ユーザ情報取得関数 ==== | |||
* getuid() | |||
*: 現在のプロセスの実行ユーザID (UID) を取得する。 | |||
*: 戻り値は、<code>uid_t</code> 型である。 | |||
*: <br> | |||
* getpwuid(uid_t uid) | |||
*: 指定されたUIDに対応するユーザ情報を取得する。 | |||
*: <code>struct passwd</code> へのポインタを返す。 | |||
*: <br> | |||
* getpwnam(const char *name) | |||
: 指定されたユーザ名に対応するユーザ情報を取得する。 | |||
*: <code>struct passwd</code> へのポインタを返す。 | |||
<br> | |||
==== グループ情報取得関数 ==== | |||
* getgid() | |||
*: 現在のプロセスの実行グループID (GID) を取得する。 | |||
*: 戻り値は、<code>gid_t</code> 型である。 | |||
*: <br> | |||
* getgrgid(gid_t gid) | |||
*: 指定されたGIDに対応するグループ情報を取得する。 | |||
*: <code>struct group</code> へのポインタを返す。 | |||
*: <br> | |||
* getgrnam(const char *name) | |||
*: 指定されたグループ名に対応するグループ情報を取得する。 | |||
*: <code>struct group</code> へのポインタを返す。 | |||
*: <br> | |||
* getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) | |||
*: 指定されたユーザが所属する全てのグループのリストを取得する。 | |||
<br><br> | |||
== 主要なデータ構造 == | |||
==== struct passwd ==== | |||
ユーザ情報を格納する構造体である。<br> | |||
<code><pwd.h></code> で定義されている。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
struct passwd { | |||
char *pw_name; // ユーザ名 | |||
char *pw_passwd; // 暗号化されたパスワード (通常は使用されない) | |||
uid_t pw_uid; // ユーザID | |||
gid_t pw_gid; // プライマリグループID | |||
char *pw_gecos; // ユーザ情報 (フルネーム等) | |||
char *pw_dir; // ホームディレクトリ | |||
char *pw_shell; // デフォルトシェル | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== struct group ==== | |||
グループ情報を格納する構造体である。<br> | |||
<code><grp.h></code> で定義されている。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
struct group { | |||
char *gr_name; // グループ名 | |||
char *gr_passwd; // 暗号化されたパスワード (通常は使用されない) | |||
gid_t gr_gid; // グループID | |||
char **gr_mem; // グループメンバーのユーザ名リスト (NULL終端) | |||
}; | |||
</syntaxhighlight> | |||
<br><br> | |||
== 現在のユーザ情報の取得 == | |||
以下の例では、現在のユーザの詳細情報を取得している。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <iostream> | |||
#include <string> | |||
#include <pwd.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
struct UserInfo { | |||
std::string username; | |||
uid_t uid; | |||
gid_t gid; | |||
std::string homeDirectory; | |||
std::string shell; | |||
std::string fullName; | |||
}; | |||
bool getCurrentUserInfo(UserInfo& userInfo, std::string& errorMessage) | |||
{ | |||
errorMessage.clear(); | |||
// 現在のユーザのUIDを取得 | |||
uid_t uid = getuid(); | |||
// UIDからユーザ情報を取得 | |||
struct passwd *pw = getpwuid(uid); | |||
if (!pw) { | |||
errorMessage = "Failed to get user information for UID " + std::to_string(uid); | |||
return false; | |||
} | |||
// 構造体に情報をコピー | |||
userInfo.username = pw->pw_name; | |||
userInfo.uid = pw->pw_uid; | |||
userInfo.gid = pw->pw_gid; | |||
userInfo.homeDirectory = pw->pw_dir; | |||
userInfo.shell = pw->pw_shell; | |||
userInfo.fullName = pw->pw_gecos; | |||
return true; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
int main() | |||
{ | |||
UserInfo userInfo; | |||
std::string errorMessage; | |||
if (getCurrentUserInfo(userInfo, errorMessage)) { | |||
std::cout << "=== Current User Information ===" << std::endl; | |||
std::cout << "Username: " << userInfo.username << std::endl; | |||
std::cout << "UID: " << userInfo.uid << std::endl; | |||
std::cout << "GID: " << userInfo.gid << std::endl; | |||
std::cout << "Home Directory: " << userInfo.homeDirectory << std::endl; | |||
std::cout << "Shell: " << userInfo.shell << std::endl; | |||
std::cout << "Full Name: " << userInfo.fullName << std::endl; | |||
} | |||
else { | |||
std::cerr << "Error: " << errorMessage << std::endl; | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
| 6行目: | 165行目: | ||
<br> | <br> | ||
標準C++とPOSIX APIのみを使用している。<br> | 標準C++とPOSIX APIのみを使用している。<br> | ||
<br> | |||
ただし、これはUNIX系システム (Linux、BSD等) 向けであるため、Windowsでは動作しないことに注意する。<br> | |||
Windowsで同様の機能を実装する場合は、Windows APIを使用する必要がある。<br> | Windowsで同様の機能を実装する場合は、Windows APIを使用する必要がある。<br> | ||
<br> | <br> | ||
以下に示す手順で動作する。<br> | |||
# まず、現在のユーザのUIDを取得する。 | # まず、現在のユーザのUIDを取得する。 | ||
# UIDを使用してユーザ情報を取得する。 | # UIDを使用してユーザ情報を取得する。 | ||
# | # getgrouplist関数 (UNIX系システム専用) を使用して、ユーザが所属するグループの数とIDを取得する。 | ||
# 各グループIDに対して、getgrgid関数を使用してグループ名を取得する。 | # 各グループIDに対して、getgrgid関数を使用してグループ名を取得する。 | ||
# | # 取得したグループ名を std::vector< std::string> クラスに追加する。 | ||
<br> | <br> | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
| 32行目: | 192行目: | ||
errorMessage.clear(); | errorMessage.clear(); | ||
// 現在のユーザのUIDを取得 | |||
uid_t uid = getuid(); | uid_t uid = getuid(); | ||
// UIDからユーザ情報を取得 | |||
struct passwd *pw = getpwuid(uid); | struct passwd *pw = getpwuid(uid); | ||
if (!pw) { | if (!pw) { | ||
| 40行目: | 202行目: | ||
} | } | ||
// まずグループ数を取得 (最初の呼び出しで必要なバッファサイズを取得) | |||
int ngroups = 0; | int ngroups = 0; | ||
if (getgrouplist(pw->pw_name, pw->pw_gid, nullptr, &ngroups) == -1) { | if (getgrouplist(pw->pw_name, pw->pw_gid, nullptr, &ngroups) == -1) { | ||
errorMessage = "Failed to get group list size"; | // この失敗は期待される動作(サイズ取得のため) | ||
if (ngroups <= 0) { | |||
errorMessage = "Failed to get group list size"; | |||
return groups; | |||
} | |||
} | } | ||
// グループIDを格納するバッファを確保 | |||
if (ngroups > 0) { | if (ngroups > 0) { | ||
std::vector<gid_t> gids(ngroups); | std::vector<gid_t> gids(ngroups); | ||
// 実際のグループリストを取得 | |||
if (getgrouplist(pw->pw_name, pw->pw_gid, gids.data(), &ngroups) == -1) { | if (getgrouplist(pw->pw_name, pw->pw_gid, gids.data(), &ngroups) == -1) { | ||
errorMessage = "Failed to get group list"; | errorMessage = "Failed to get group list"; | ||
| 53行目: | 222行目: | ||
} | } | ||
// 各グループIDからグループ名を取得 | |||
for (int i = 0; i < ngroups; i++) { | for (int i = 0; i < ngroups; i++) { | ||
errno = 0; | errno = 0; | ||
| 60行目: | 230行目: | ||
} | } | ||
else { | else { | ||
std::cerr << "Failed to get group name for gid " << gids[i] << ": " << strerror(errno) << std::endl; | // エラーを記録するが、処理は継続 | ||
std::cerr << "Failed to get group name for gid " << gids[i] | |||
<< ": " << strerror(errno) << std::endl; | |||
} | } | ||
} | } | ||
| 74行目: | 246行目: | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// 使用例 | // 使用例 | ||
int main() | int main() | ||
{ | { | ||
| 81行目: | 254行目: | ||
if (!errorMessage.empty()) { | if (!errorMessage.empty()) { | ||
std::cerr << "Error occurred: " << errorMessage << std::endl; | std::cerr << "Error occurred: " << errorMessage << std::endl; | ||
return 1; | |||
} | } | ||
if (userGroups.empty()) { | |||
std::cout << "User is not a member of any groups" << std::endl; | std::cout << "User is not a member of any groups" << std::endl; | ||
} | } | ||
else { | else { | ||
std::cout << "User groups:" << std::endl; | std::cout << "User groups (" << userGroups.size() << " total):" << std::endl; | ||
for (const auto& group : userGroups) { | for (const auto& group : userGroups) { | ||
std::cout << " " << group << std::endl; | std::cout << " " << group << std::endl; | ||
| 97行目: | 272行目: | ||
<br><br> | <br><br> | ||
== 特定グループのメンバー取得 == | |||
以下の例では、指定されたグループ名に所属する全メンバーのユーザ名を取得している。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <iostream> | |||
#include <vector> | |||
#include <string> | |||
#include <cstring> | |||
#include <grp.h> | |||
#include <errno.h> | |||
std::vector<std::string> getGroupMembers(const std::string& groupName, std::string& errorMessage) | |||
{ | |||
std::vector<std::string> members; | |||
errorMessage.clear(); | |||
// グループ名からグループ情報を取得 | |||
errno = 0; | |||
struct group *gr = getgrnam(groupName.c_str()); | |||
if (!gr) { | |||
if (errno != 0) { | |||
errorMessage = "Failed to get group '" + groupName + "': " + std::string(strerror(errno)); | |||
} | |||
else { | |||
errorMessage = "Group '" + groupName + "' not found"; | |||
} | |||
return members; | |||
} | |||
// メンバーリストをstd::vectorにコピー | |||
// gr_memはNULL終端の文字列ポインタ配列 | |||
char **member = gr->gr_mem; | |||
while (*member != nullptr) { | |||
members.push_back(std::string(*member)); | |||
member++; | |||
} | |||
return members; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
int main() | |||
{ | |||
std::string groupName = "sudo"; // 例:sudoグループ | |||
std::string errorMessage; | |||
std::vector<std::string> members = getGroupMembers(groupName, errorMessage); | |||
if (!errorMessage.empty()) { | |||
std::cerr << "Error: " << errorMessage << std::endl; | |||
return 1; | |||
} | |||
std::cout << "Members of group '" << groupName << "' (" << members.size() << " total):" << std::endl; | |||
if (members.empty()) { | |||
std::cout << " (No members)" << std::endl; | |||
} | |||
else { | |||
for (const auto& member : members) { | |||
std::cout << " " << member << std::endl; | |||
} | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 特定ユーザの詳細情報取得 == | |||
以下の例では、ユーザ名を指定して、そのユーザの詳細情報を取得している。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <iostream> | |||
#include <string> | |||
#include <vector> | |||
#include <pwd.h> | |||
#include <grp.h> | |||
#include <errno.h> | |||
#include <cstring> | |||
struct DetailedUserInfo { | |||
std::string username; | |||
uid_t uid; | |||
gid_t primaryGid; | |||
std::string primaryGroupName; | |||
std::string homeDirectory; | |||
std::string shell; | |||
std::string fullName; | |||
std::vector<std::string> groups; | |||
}; | |||
bool getUserInfo(const std::string& username, DetailedUserInfo& info, std::string& errorMessage) | |||
{ | |||
errorMessage.clear(); | |||
// ユーザ名からユーザ情報を取得 | |||
errno = 0; | |||
struct passwd *pw = getpwnam(username.c_str()); | |||
if (!pw) { | |||
if (errno != 0) { | |||
errorMessage = "Failed to get user '" + username + "': " + std::string(strerror(errno)); | |||
} | |||
else { | |||
errorMessage = "User '" + username + "' not found"; | |||
} | |||
return false; | |||
} | |||
// 基本情報を設定 | |||
info.username = pw->pw_name; | |||
info.uid = pw->pw_uid; | |||
info.primaryGid = pw->pw_gid; | |||
info.homeDirectory = pw->pw_dir; | |||
info.shell = pw->pw_shell; | |||
info.fullName = pw->pw_gecos; | |||
// プライマリグループ名を取得 | |||
struct group *gr = getgrgid(pw->pw_gid); | |||
if (gr) { | |||
info.primaryGroupName = gr->gr_name; | |||
} | |||
// ユーザが所属する全グループを取得 | |||
int ngroups = 0; | |||
if (getgrouplist(pw->pw_name, pw->pw_gid, nullptr, &ngroups) == -1) { | |||
if (ngroups > 0) { | |||
std::vector<gid_t> gids(ngroups); | |||
if (getgrouplist(pw->pw_name, pw->pw_gid, gids.data(), &ngroups) != -1) { | |||
for (int i = 0; i < ngroups; i++) { | |||
struct group *g = getgrgid(gids[i]); | |||
if (g) { | |||
info.groups.push_back(std::string(g->gr_name)); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
int main() | |||
{ | |||
std::string username = "root"; // 例:rootユーザ | |||
DetailedUserInfo info; | |||
std::string errorMessage; | |||
if (getUserInfo(username, info, errorMessage)) { | |||
std::cout << "=== User Information for '" << username << "' ===" << std::endl; | |||
std::cout << "Username: " << info.username << std::endl; | |||
std::cout << "UID: " << info.uid << std::endl; | |||
std::cout << "Primary GID: " << info.primaryGid << std::endl; | |||
std::cout << "Primary Group: " << info.primaryGroupName << std::endl; | |||
std::cout << "Home Directory: " << info.homeDirectory << std::endl; | |||
std::cout << "Shell: " << info.shell << std::endl; | |||
std::cout << "Full Name: " << info.fullName << std::endl; | |||
std::cout << "\nGroup Memberships (" << info.groups.size() << "):" << std::endl; | |||
for (const auto& group : info.groups) { | |||
std::cout << " " << group << std::endl; | |||
} | |||
} | |||
else { | |||
std::cerr << "Error: " << errorMessage << std::endl; | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== エラーハンドリング == | |||
==== errnoの適切な使用 ==== | |||
多くのPOSIX関数は、エラー発生時に <code>errno</code> グローバル変数にエラーコードを設定する。<br> | |||
ただし、成功時には <code>errno</code> をクリアしないため、使用前に必ず0に初期化すること。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
errno = 0; // 使用前にクリア | |||
struct passwd *pw = getpwuid(uid); | |||
if (!pw) { | |||
if (errno != 0) { | |||
std::cerr << "Error: " << strerror(errno) << std::endl; | |||
} | |||
else { | |||
std::cerr << "User not found" << std::endl; | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== スレッドセーフ関数の使用 ==== | |||
マルチスレッド環境では、再入可能 (リエントラント) な関数を使用すること。<br> | |||
POSIX標準では、多くの関数に対して <code>_r</code> サフィックスを持つスレッドセーフ版が提供されている。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// スレッドセーフ版の例 | |||
struct passwd pwd; | |||
struct passwd *result; | |||
char buffer[16384]; // 十分なバッファサイズを確保 | |||
int ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result); | |||
if (ret != 0) { | |||
std::cerr << "Error: " << strerror(ret) << std::endl; | |||
} | |||
else if (result == nullptr) { | |||
std::cerr << "User not found" << std::endl; | |||
} | |||
else { | |||
std::cout << "Username: " << result->pw_name << std::endl; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== セキュリティの考慮 == | |||
==== 権限の確認 ==== | |||
ユーザやグループ情報の読み取りには特別な権限は不要だが、一部の機密情報 (暗号化されたパスワード等) へのアクセスは制限されている可能性がある。<br> | |||
<br> | |||
==== Time-of-check to time-of-use (TOCTOU) 攻撃への対策 ==== | |||
ユーザ情報の確認から実際の使用までの間に、システムの状態が変化する可能性がある。<br> | |||
セキュリティクリティカルな操作では、この事柄に注意すること。<br> | |||
<br> | |||
==== 入力の検証 ==== | |||
外部から受け取ったユーザ名やグループ名を使用する場合は、必ず検証を行うこと。<br> | |||
特殊文字や異常な長さの入力によるセキュリティ問題を防ぐため、サニタイズ処理を行うこと。<br> | |||
<br><br> | |||
{{#seo: | |||
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki | |||
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 | |||
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux | |||
|image=/resources/assets/MochiuLogo_Single_Blue.png | |||
}} | |||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:C++]] | [[カテゴリ:C++]] | ||