master
c 201 lines 5.97 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../../libnetdata.h"
4
5 #if defined(OS_WINDOWS)
6 #include "cached-sid-username.h"
7
8 typedef struct {
9 size_t len;
10 uint8_t sid[];
11 } SID_KEY;
12
13 typedef struct {
14 // IMPORTANT:
15 // This is malloc'd ! You have to manually set fields to zero.
16
17 STRING *account;
18 STRING *domain;
19 STRING *full;
20 STRING *sid_str;
21
22 // this needs to be last, because of its variable size
23 SID_KEY key;
24 } SID_VALUE;
25
26 #define SIMPLE_HASHTABLE_NAME _SID
27 #define SIMPLE_HASHTABLE_VALUE_TYPE SID_VALUE *
28 #define SIMPLE_HASHTABLE_KEY_TYPE SID_KEY
29 #define SIMPLE_HASHTABLE_VALUE2KEY_FUNCTION sid_value_to_key
30 #define SIMPLE_HASHTABLE_COMPARE_KEYS_FUNCTION sid_cache_compar
31 #define SIMPLE_HASHTABLE_SAMPLE_IMPLEMENTATION 1
32 #include "libnetdata/simple_hashtable/simple_hashtable.h"
33
34 static struct {
35 SPINLOCK spinlock;
36 struct simple_hashtable_SID hashtable;
37 } sid_globals = {
38 .spinlock = SPINLOCK_INITIALIZER,
39 .hashtable = { 0 },
40 };
41
42 static inline SID_KEY *sid_value_to_key(SID_VALUE *s) {
43 return &s->key;
44 }
45
46 static inline bool sid_cache_compar(SID_KEY *a, SID_KEY *b) {
47 return a->len == b->len && memcmp(&a->sid, &b->sid, a->len) == 0;
48 }
49
50 void cached_sid_username_init(void) {
51 simple_hashtable_init_SID(&sid_globals.hashtable, 100);
52 }
53
54 static char *account2utf8(const wchar_t *user) {
55 static __thread char buffer[256];
56 if(utf16_to_utf8(buffer, sizeof(buffer), user, -1, NULL) == 0)
57 buffer[0] = '\0';
58 return buffer;
59 }
60
61 static char *domain2utf8(const wchar_t *domain) {
62 static __thread char buffer[256];
63 if(utf16_to_utf8(buffer, sizeof(buffer), domain, -1, NULL) == 0)
64 buffer[0] = '\0';
65 return buffer;
66 }
67
68 static void lookup_user_in_system(SID_VALUE *sv) {
69 static __thread wchar_t account_unicode[256];
70 static __thread wchar_t domain_unicode[256];
71 static __thread char tmp[512 + 2];
72
73 DWORD account_name_size = sizeof(account_unicode) / sizeof(account_unicode[0]);
74 DWORD domain_name_size = sizeof(domain_unicode) / sizeof(domain_unicode[0]);
75 SID_NAME_USE sid_type;
76
77 if (LookupAccountSidW(NULL, sv->key.sid, account_unicode, &account_name_size, domain_unicode, &domain_name_size, &sid_type)) {
78 const char *account = account2utf8(account_unicode);
79 const char *domain = domain2utf8(domain_unicode);
80 snprintfz(tmp, sizeof(tmp), "%s\\%s", domain, account);
81 sv->domain = string_strdupz(domain);
82 sv->account = string_strdupz(account);
83 sv->full = string_strdupz(tmp);
84 }
85 else {
86 sv->domain = NULL;
87 sv->account = NULL;
88 sv->full = NULL;
89 }
90
91 wchar_t *sid_string = NULL;
92 if (ConvertSidToStringSidW(sv->key.sid, &sid_string))
93 sv->sid_str = string_strdupz(account2utf8(sid_string));
94 else
95 sv->sid_str = NULL;
96 }
97
98 static SID_VALUE *lookup_or_convert_user_id_to_name_lookup(PSID sid) {
99 if(!sid || !IsValidSid(sid))
100 return NULL;
101
102 size_t size = GetLengthSid(sid);
103
104 size_t tmp_size = sizeof(SID_VALUE) + size;
105 size_t tmp_key_size = sizeof(SID_KEY) + size;
106 SID_VALUE *tmp = mallocz(tmp_size);
107 memcpy(&tmp->key.sid, sid, size);
108 tmp->key.len = size;
109
110 spinlock_lock(&sid_globals.spinlock);
111 SID_VALUE *found = simple_hashtable_get_SID(&sid_globals.hashtable, &tmp->key, tmp_key_size);
112 spinlock_unlock(&sid_globals.spinlock);
113 if(found) {
114 freez(tmp);
115 return found;
116 }
117
118 // allocate the SID_VALUE
119 found = tmp;
120
121 lookup_user_in_system(found);
122
123 // add it to the cache
124 spinlock_lock(&sid_globals.spinlock);
125 simple_hashtable_set_SID(&sid_globals.hashtable, &found->key, tmp_key_size, found);
126 spinlock_unlock(&sid_globals.spinlock);
127
128 return found;
129 }
130
131 bool cached_sid_to_account_domain_sidstr(PSID sid, TXT_UTF8 *dst_account, TXT_UTF8 *dst_domain, TXT_UTF8 *dst_sid_str) {
132 SID_VALUE *found = lookup_or_convert_user_id_to_name_lookup(sid);
133
134 if(found) {
135 if (found->account) {
136 txt_utf8_resize(dst_account, string_strlen(found->account) + 1, false);
137 memcpy(dst_account->data, string2str(found->account), string_strlen(found->account) + 1);
138 dst_account->used = string_strlen(found->account) + 1;
139 }
140 else
141 txt_utf8_empty(dst_account);
142
143 if (found->domain) {
144 txt_utf8_resize(dst_domain, string_strlen(found->domain) + 1, false);
145 memcpy(dst_domain->data, string2str(found->domain), string_strlen(found->domain) + 1);
146 dst_domain->used = string_strlen(found->domain) + 1;
147 }
148 else
149 txt_utf8_empty(dst_domain);
150
151 if (found->sid_str) {
152 txt_utf8_resize(dst_sid_str, string_strlen(found->sid_str) + 1, false);
153 memcpy(dst_sid_str->data, string2str(found->sid_str), string_strlen(found->sid_str) + 1);
154 dst_sid_str->used = string_strlen(found->sid_str) + 1;
155 }
156 else
157 txt_utf8_empty(dst_sid_str);
158
159 return true;
160 }
161
162 txt_utf8_empty(dst_account);
163 txt_utf8_empty(dst_domain);
164 txt_utf8_empty(dst_sid_str);
165 return false;
166 }
167
168 bool cached_sid_to_buffer_append(PSID sid, BUFFER *dst, const char *prefix) {
169 SID_VALUE *found = lookup_or_convert_user_id_to_name_lookup(sid);
170 size_t added = 0;
171
172 if(found) {
173 if (found->full) {
174 if (prefix && *prefix)
175 buffer_strcat(dst, prefix);
176
177 buffer_fast_strcat(dst, string2str(found->full), string_strlen(found->full));
178 added++;
179 }
180 if (found->sid_str) {
181 if (prefix && *prefix)
182 buffer_strcat(dst, prefix);
183
184 buffer_fast_strcat(dst, string2str(found->sid_str), string_strlen(found->sid_str));
185 added++;
186 }
187 }
188
189 return added > 0;
190 }
191
192 STRING *cached_sid_fullname_or_sid_str(PSID sid) {
193 SID_VALUE *found = lookup_or_convert_user_id_to_name_lookup(sid);
194 if(found) {
195 if(found->full) return string_dup(found->full);
196 return string_dup(found->sid_str);
197 }
198 return NULL;
199 }
200
201 #endif