| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "database/rrd.h" |
| 4 | #include "registry_internals.h" |
| 5 | |
| 6 | struct registry registry; |
| 7 | |
| 8 | // ---------------------------------------------------------------------------- |
| 9 | // common functions |
| 10 | |
| 11 | // parse a GUID and re-generated to be always lower case |
| 12 | // this is used as a protection against the variations of GUIDs |
| 13 | int regenerate_guid(const char *guid, char *result) { |
| 14 | nd_uuid_t uuid; |
| 15 | if(unlikely(uuid_parse(guid, uuid) == -1)) { |
| 16 | netdata_log_info("Registry: GUID '%s' is not a valid GUID.", guid); |
| 17 | return -1; |
| 18 | } |
| 19 | else { |
| 20 | uuid_unparse_lower(uuid, result); |
| 21 | |
| 22 | #ifdef NETDATA_INTERNAL_CHECKS |
| 23 | if(strcmp(guid, result) != 0) |
| 24 | netdata_log_info("GUID '%s' and re-generated GUID '%s' differ!", guid, result); |
| 25 | #endif /* NETDATA_INTERNAL_CHECKS */ |
| 26 | } |
| 27 | |
| 28 | return 0; |
| 29 | } |
| 30 | |
| 31 | // make sure the names of the machines / URLs do not contain any tabs |
| 32 | // (which are used as our separator in the database files) |
| 33 | // and are properly trimmed (before and after) |
| 34 | static inline char *registry_fix_machine_name(char *name, size_t *len) { |
| 35 | char *s = name?name:""; |
| 36 | |
| 37 | // skip leading spaces |
| 38 | while(*s && isspace((uint8_t)*s)) s++; |
| 39 | |
| 40 | // make sure all spaces are a SPACE |
| 41 | char *t = s; |
| 42 | while(*t) { |
| 43 | if(unlikely(isspace((uint8_t)*t))) |
| 44 | *t = ' '; |
| 45 | |
| 46 | t++; |
| 47 | } |
| 48 | |
| 49 | // remove trailing spaces |
| 50 | while(--t >= s) { |
| 51 | if(*t == ' ') |
| 52 | *t = '\0'; |
| 53 | else |
| 54 | break; |
| 55 | } |
| 56 | t++; |
| 57 | |
| 58 | if(likely(len)) |
| 59 | *len = (t - s); |
| 60 | |
| 61 | return s; |
| 62 | } |
| 63 | |
| 64 | static inline char *registry_fix_url(char *url, size_t *len) { |
| 65 | size_t l = 0; |
| 66 | char *s = registry_fix_machine_name(url, &l); |
| 67 | |
| 68 | // protection from too big URLs |
| 69 | if(l > registry.max_url_length) { |
| 70 | l = registry.max_url_length; |
| 71 | s[l] = '\0'; |
| 72 | } |
| 73 | |
| 74 | if(len) *len = l; |
| 75 | return s; |
| 76 | } |
| 77 | |
| 78 | |
| 79 | // ---------------------------------------------------------------------------- |
| 80 | // HELPERS |
| 81 | |
| 82 | // verify the person, the machine and the URL exist in our DB |
| 83 | REGISTRY_PERSON_URL *registry_verify_request(const char *person_guid, char *machine_guid, char *url, REGISTRY_PERSON **pp, REGISTRY_MACHINE **mm) { |
| 84 | char pbuf[GUID_LEN + 1], mbuf[GUID_LEN + 1]; |
| 85 | |
| 86 | if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) { |
| 87 | netdata_log_info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET"); |
| 88 | return NULL; |
| 89 | } |
| 90 | |
| 91 | // normalize the url |
| 92 | url = registry_fix_url(url, NULL); |
| 93 | |
| 94 | // make sure the person GUID is valid |
| 95 | if(regenerate_guid(person_guid, pbuf) == -1) { |
| 96 | netdata_log_info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); |
| 97 | return NULL; |
| 98 | } |
| 99 | person_guid = pbuf; |
| 100 | |
| 101 | // make sure the machine GUID is valid |
| 102 | if(regenerate_guid(machine_guid, mbuf) == -1) { |
| 103 | netdata_log_info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); |
| 104 | return NULL; |
| 105 | } |
| 106 | machine_guid = mbuf; |
| 107 | |
| 108 | // make sure the machine exists |
| 109 | REGISTRY_MACHINE *m = registry_machine_find(machine_guid); |
| 110 | if(!m) { |
| 111 | netdata_log_info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); |
| 112 | return NULL; |
| 113 | } |
| 114 | if(mm) *mm = m; |
| 115 | |
| 116 | // make sure the person exist |
| 117 | REGISTRY_PERSON *p = registry_person_find(person_guid); |
| 118 | if(!p) { |
| 119 | netdata_log_info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); |
| 120 | return NULL; |
| 121 | } |
| 122 | if(pp) *pp = p; |
| 123 | |
| 124 | STRING *u = string_strdupz(url); |
| 125 | REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u); |
| 126 | string_freez(u); |
| 127 | |
| 128 | if(!pu) { |
| 129 | netdata_log_info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url); |
| 130 | return NULL; |
| 131 | } |
| 132 | //else if (pu->machine != m) { |
| 133 | // netdata_log_info("Registry Request Verification: Machine mismatch: person: '%s', machine requested='%s' <> loaded='%s', url '%s'", person_guid, machine_guid, pu->machine->guid, url); |
| 134 | // return NULL; |
| 135 | //} |
| 136 | |
| 137 | return pu; |
| 138 | } |
| 139 | |
| 140 | |
| 141 | // ---------------------------------------------------------------------------- |
| 142 | // REGISTRY REQUESTS |
| 143 | |
| 144 | REGISTRY_PERSON *registry_request_access(const char *person_guid, char *machine_guid, char *url, char *name, time_t when) { |
| 145 | netdata_log_debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url); |
| 146 | |
| 147 | bool is_dummy = is_dummy_person(person_guid); |
| 148 | |
| 149 | REGISTRY_MACHINE *m = registry_machine_find_or_create(machine_guid, when, is_dummy); |
| 150 | if(!m) return NULL; |
| 151 | |
| 152 | REGISTRY_PERSON *p = registry_person_find_or_create(person_guid, when, is_dummy); |
| 153 | |
| 154 | // make sure the name is valid |
| 155 | size_t name_len; |
| 156 | name = registry_fix_machine_name(name, &name_len); |
| 157 | |
| 158 | size_t url_len; |
| 159 | url = registry_fix_url(url, &url_len); |
| 160 | |
| 161 | STRING *u = string_strdupz(url); |
| 162 | |
| 163 | if(!is_dummy) |
| 164 | registry_person_link_to_url(p, m, u, name, name_len, when); |
| 165 | |
| 166 | registry_machine_link_to_url(m, u, when); |
| 167 | |
| 168 | registry_log('A', p, m, u, name); |
| 169 | |
| 170 | registry.usages_count++; |
| 171 | |
| 172 | return p; |
| 173 | } |
| 174 | |
| 175 | REGISTRY_PERSON *registry_request_delete(const char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) { |
| 176 | (void) when; |
| 177 | |
| 178 | REGISTRY_PERSON *p = NULL; |
| 179 | REGISTRY_MACHINE *m = NULL; |
| 180 | REGISTRY_PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m); |
| 181 | if(!pu || !p || !m) return NULL; |
| 182 | |
| 183 | // normalize the url |
| 184 | delete_url = registry_fix_url(delete_url, NULL); |
| 185 | |
| 186 | // make sure the user is not deleting the url it uses |
| 187 | /* |
| 188 | if(!strcmp(delete_url, pu->url->url)) { |
| 189 | netdata_log_info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'" |
| 190 | , p->guid, m->guid, pu->url->url, delete_url); |
| 191 | return NULL; |
| 192 | } |
| 193 | */ |
| 194 | |
| 195 | STRING *d_url = string_strdupz(delete_url); |
| 196 | REGISTRY_PERSON_URL *dpu = registry_person_url_index_find(p, d_url); |
| 197 | string_freez(d_url); |
| 198 | |
| 199 | if(!dpu) { |
| 200 | netdata_log_info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid |
| 201 | , m->guid, string2str(pu->url), delete_url); |
| 202 | return NULL; |
| 203 | } |
| 204 | |
| 205 | registry_log('D', p, m, pu->url, string2str(dpu->url)); |
| 206 | registry_person_unlink_from_url(p, dpu); |
| 207 | |
| 208 | return p; |
| 209 | } |
| 210 | |
| 211 | |
| 212 | REGISTRY_MACHINE *registry_request_machine(const char *person_guid, char *request_machine, STRING **hostname) { |
| 213 | char pbuf[GUID_LEN + 1]; |
| 214 | char mbuf[GUID_LEN + 1]; |
| 215 | |
| 216 | // make sure the person GUID is valid |
| 217 | if(regenerate_guid(person_guid, pbuf) == -1) { |
| 218 | netdata_log_info("REGISTRY: %s(): invalid person GUID '%s'", __FUNCTION__ , person_guid); |
| 219 | return NULL; |
| 220 | } |
| 221 | person_guid = pbuf; |
| 222 | |
| 223 | // make sure the person GUID is valid |
| 224 | if(regenerate_guid(request_machine, mbuf) == -1) { |
| 225 | netdata_log_info("REGISTRY: %s(): invalid search machine GUID '%s'", __FUNCTION__ , request_machine); |
| 226 | return NULL; |
| 227 | } |
| 228 | request_machine = mbuf; |
| 229 | |
| 230 | REGISTRY_PERSON *p = registry_person_find(person_guid); |
| 231 | if(!p) return NULL; |
| 232 | |
| 233 | REGISTRY_MACHINE *m = registry_machine_find(request_machine); |
| 234 | if(!m) return NULL; |
| 235 | |
| 236 | // Verify the user has in the past accessed this machine |
| 237 | // We will walk through the PERSON_URLs to find the machine |
| 238 | // linking to our machine |
| 239 | |
| 240 | // make sure the user has access |
| 241 | for(REGISTRY_PERSON_URL *pu = p->person_urls; pu ;pu = pu->next) |
| 242 | if(pu->machine == m) { |
| 243 | *hostname = string_dup(pu->machine_name); |
| 244 | return m; |
| 245 | } |
| 246 | |
| 247 | return NULL; |
| 248 | } |
| 249 | |
| 250 | |
| 251 | // ---------------------------------------------------------------------------- |
| 252 | |
| 253 | const char *registry_get_this_machine_hostname(void) { |
| 254 | return registry.hostname; |
| 255 | } |