1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Written by Kern Sibbald, July 2007 to replace idcache.c
21 *
22 * Program to convert uid and gid into names, and cache the results
23 * for preformance reasons.
24 *
25 */
26
27 #include "bacula.h"
28
29 #ifndef WIN32
30 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
31 #endif
32
33 struct guitem {
34 dlink link;
35 char *name;
36 union {
37 uid_t uid;
38 gid_t gid;
39 };
40 };
41
42
new_guid_list()43 guid_list *new_guid_list()
44 {
45 guid_list *list;
46 guitem *item = NULL;
47 list = (guid_list *)malloc(sizeof(guid_list));
48 list->uid_list = New(dlist(item, &item->link));
49 list->gid_list = New(dlist(item, &item->link));
50 return list;
51 }
52
free_guid_list(guid_list * list)53 void free_guid_list(guid_list *list)
54 {
55 guitem *item;
56 foreach_dlist(item, list->uid_list) {
57 free(item->name);
58 }
59 foreach_dlist(item, list->gid_list) {
60 free(item->name);
61 }
62 delete list->uid_list;
63 delete list->gid_list;
64 free(list);
65 }
66
uid_compare(void * item1,void * item2)67 static int uid_compare(void *item1, void *item2)
68 {
69 guitem *i1 = (guitem *)item1;
70 guitem *i2 = (guitem *)item2;
71 if (i1->uid < i2->uid) {
72 return -1;
73 } else if (i1->uid > i2->uid) {
74 return 1;
75 } else {
76 return 0;
77 }
78 }
79
gid_compare(void * item1,void * item2)80 static int gid_compare(void *item1, void *item2)
81 {
82 guitem *i1 = (guitem *)item1;
83 guitem *i2 = (guitem *)item2;
84 if (i1->gid < i2->gid) {
85 return -1;
86 } else if (i1->gid > i2->gid) {
87 return 1;
88 } else {
89 return 0;
90 }
91 }
92
93
get_uidname(uid_t uid,guitem * item)94 static void get_uidname(uid_t uid, guitem *item)
95 {
96 #ifndef HAVE_WIN32
97 struct passwd *pwbuf;
98 P(mutex);
99 pwbuf = getpwuid(uid);
100 if (pwbuf != NULL && strcmp(pwbuf->pw_name, "????????") != 0) {
101 item->name = bstrdup(pwbuf->pw_name);
102 }
103 V(mutex);
104 #endif
105 }
106
get_gidname(gid_t gid,guitem * item)107 static void get_gidname(gid_t gid, guitem *item)
108 {
109 #ifndef HAVE_WIN32
110 struct group *grbuf;
111 P(mutex);
112 grbuf = getgrgid(gid);
113 if (grbuf != NULL && strcmp(grbuf->gr_name, "????????") != 0) {
114 item->name = bstrdup(grbuf->gr_name);
115 }
116 V(mutex);
117 #endif
118 }
119
120
uid_to_name(uid_t uid,char * name,int maxlen)121 char *guid_list::uid_to_name(uid_t uid, char *name, int maxlen)
122 {
123 guitem sitem, *item, *fitem;
124 sitem.uid = uid;
125 char buf[50];
126
127 item = (guitem *)uid_list->binary_search(&sitem, uid_compare);
128 Dmsg2(900, "uid=%d item=%p\n", uid, item);
129 if (!item) {
130 item = (guitem *)malloc(sizeof(guitem));
131 item->uid = uid;
132 item->name = NULL;
133 get_uidname(uid, item);
134 if (!item->name) {
135 item->name = bstrdup(edit_int64(uid, buf));
136 Dmsg2(900, "set uid=%d name=%s\n", uid, item->name);
137 }
138 fitem = (guitem *)uid_list->binary_insert(item, uid_compare);
139 if (fitem != item) { /* item already there this shouldn't happen */
140 free(item->name);
141 free(item);
142 item = fitem;
143 }
144 }
145 bstrncpy(name, item->name, maxlen);
146 return name;
147 }
148
gid_to_name(gid_t gid,char * name,int maxlen)149 char *guid_list::gid_to_name(gid_t gid, char *name, int maxlen)
150 {
151 guitem sitem, *item, *fitem;
152 sitem.gid = gid;
153 char buf[50];
154
155 item = (guitem *)gid_list->binary_search(&sitem, gid_compare);
156 if (!item) {
157 item = (guitem *)malloc(sizeof(guitem));
158 item->gid = gid;
159 item->name = NULL;
160 get_gidname(gid, item);
161 if (!item->name) {
162 item->name = bstrdup(edit_int64(gid, buf));
163 }
164 fitem = (guitem *)gid_list->binary_insert(item, gid_compare);
165 if (fitem != item) { /* item already there this shouldn't happen */
166 free(item->name);
167 free(item);
168 item = fitem;
169 }
170 }
171
172 bstrncpy(name, item->name, maxlen);
173 return name;
174 }
175
176 #ifdef TEST_PROGRAM
177
main()178 int main()
179 {
180 int i;
181 guid_list *list;
182 char ed1[50], ed2[50];
183 list = new_guid_list();
184 for (i=0; i<1001; i++) {
185 printf("uid=%d name=%s gid=%d name=%s\n", i, list->uid_to_name(i, ed1, sizeof(ed1)),
186 i, list->gid_to_name(i, ed2, sizeof(ed2)));
187 printf("uid=%d name=%s gid=%d name=%s\n", i, list->uid_to_name(i, ed1, sizeof(ed1)),
188 i, list->gid_to_name(i, ed2, sizeof(ed2)));
189 }
190
191 free_guid_list(list);
192 sm_dump(false); /* unit test */
193
194 return 0;
195 }
196
197 #endif
198