Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <LibCore/ArgsParser.h>
28#include <alloca.h>
29#include <grp.h>
30#include <pwd.h>
31#include <stdio.h>
32#include <unistd.h>
33
34static int print_id_objects();
35
36static bool flag_print_uid = false;
37static bool flag_print_gid = false;
38static bool flag_print_name = false;
39static bool flag_print_gid_all = false;
40
41int main(int argc, char** argv)
42{
43 if (unveil("/etc/passwd", "r") < 0) {
44 perror("unveil");
45 return 1;
46 }
47
48 if (unveil("/etc/group", "r") < 0) {
49 perror("unveil");
50 return 1;
51 }
52
53 if (unveil(nullptr, nullptr) < 0) {
54 perror("unveil");
55 return 1;
56 }
57
58 if (pledge("stdio rpath", nullptr) < 0) {
59 perror("pledge");
60 return 1;
61 }
62
63 Core::ArgsParser args_parser;
64 args_parser.add_option(flag_print_uid, "Print UID", nullptr, 'u');
65 args_parser.add_option(flag_print_gid, "Print GID", nullptr, 'g');
66 args_parser.add_option(flag_print_gid_all, "Print all GIDs", nullptr, 'G');
67 args_parser.add_option(flag_print_name, "Print name", nullptr, 'n');
68 args_parser.parse(argc, argv);
69
70 if (flag_print_name && !(flag_print_uid || flag_print_gid || flag_print_gid_all)) {
71 fprintf(stderr, "cannot print only names or real IDs in default format\n");
72 return 1;
73 }
74
75 if (flag_print_uid + flag_print_gid + flag_print_gid_all > 1) {
76 fprintf(stderr, "cannot print \"only\" of more than one choice\n");
77 return 1;
78 }
79
80 int status = print_id_objects();
81 return status;
82}
83
84bool print_uid_object(uid_t uid)
85{
86 if (flag_print_name) {
87 struct passwd* pw = getpwuid(uid);
88 printf("%s", pw ? pw->pw_name : "n/a");
89 } else
90 printf("%u", uid);
91
92 return true;
93}
94
95bool print_gid_object(gid_t gid)
96{
97 if (flag_print_name) {
98 struct group* gr = getgrgid(gid);
99 printf("%s", gr ? gr->gr_name : "n/a");
100 } else
101 printf("%u", gid);
102 return true;
103}
104
105bool print_gid_list()
106{
107 int extra_gid_count = getgroups(0, nullptr);
108 if (extra_gid_count) {
109 auto* extra_gids = (gid_t*)alloca(extra_gid_count * sizeof(gid_t));
110 int rc = getgroups(extra_gid_count, extra_gids);
111
112 if (rc < 0) {
113 perror("\ngetgroups");
114 return false;
115 }
116
117 for (int g = 0; g < extra_gid_count; ++g) {
118 auto* gr = getgrgid(extra_gids[g]);
119 if (flag_print_name && gr)
120 printf("%s", gr->gr_name);
121 else
122 printf("%u", extra_gids[g]);
123 if (g != extra_gid_count - 1)
124 printf(" ");
125 }
126 }
127 return true;
128}
129
130bool print_full_id_list()
131{
132
133 uid_t uid = getuid();
134 gid_t gid = getgid();
135 struct passwd* pw = getpwuid(uid);
136 struct group* gr = getgrgid(gid);
137
138 printf("uid=%u(%s) gid=%u(%s)", uid, pw ? pw->pw_name : "n/a", gid, gr ? gr->gr_name : "n/a");
139
140 int extra_gid_count = getgroups(0, nullptr);
141 if (extra_gid_count) {
142 auto* extra_gids = (gid_t*)alloca(extra_gid_count * sizeof(gid_t));
143 int rc = getgroups(extra_gid_count, extra_gids);
144 if (rc < 0) {
145 perror("\ngetgroups");
146 return false;
147 }
148 printf(" groups=");
149 for (int g = 0; g < extra_gid_count; ++g) {
150 auto* gr = getgrgid(extra_gids[g]);
151 if (gr)
152 printf("%u(%s)", extra_gids[g], gr->gr_name);
153 else
154 printf("%u", extra_gids[g]);
155 if (g != extra_gid_count - 1)
156 printf(",");
157 }
158 }
159 return true;
160}
161
162int print_id_objects()
163{
164 if (flag_print_uid) {
165 if (!print_uid_object(getuid()))
166 return 1;
167 } else if (flag_print_gid) {
168 if (!print_gid_object(getgid()))
169 return 1;
170 } else if (flag_print_gid_all) {
171 if (!print_gid_list())
172 return 1;
173 } else {
174 if (!print_full_id_list())
175 return 1;
176 }
177
178 printf("\n");
179 return 0;
180}