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