Line data Source code
1 : /*
2 : Samba Unix/Linux SMB client library
3 : Distributed SMB/CIFS Server Management Utility
4 : Copyright (C) Rafal Szczesniak 2002
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "net.h"
22 : #include "libsmb/samlogon_cache.h"
23 : #include "../librpc/gen_ndr/netlogon.h"
24 : #include "../librpc/gen_ndr/ndr_netlogon.h"
25 : #include "libcli/security/dom_sid.h"
26 : #include "lib/util/strv.h"
27 : #include "lib/gencache.h"
28 :
29 : /**
30 : * @file net_cache.c
31 : * @brief This is part of the net tool which is basically command
32 : * line wrapper for gencache.c functions (mainly for testing)
33 : *
34 : **/
35 :
36 :
37 : /*
38 : * These routines are used via gencache_iterate() to display the cache's contents
39 : * (print_cache_entry) and to flush it (delete_cache_entry).
40 : * Both of them are defined by first arg of gencache_iterate() routine.
41 : */
42 0 : static void print_cache_entry(const char* keystr, DATA_BLOB value,
43 : const time_t timeout, void* dptr)
44 : {
45 0 : char *timeout_str;
46 0 : char *alloc_str = NULL;
47 0 : const char *datastr;
48 0 : char *datastr_free = NULL;
49 0 : time_t now_t = time(NULL);
50 0 : struct tm timeout_tm, now_tm;
51 0 : struct tm *ptimeout_tm, *pnow_tm;
52 :
53 0 : ptimeout_tm = localtime_r(&timeout, &timeout_tm);
54 0 : if (ptimeout_tm == NULL) {
55 0 : return;
56 : }
57 0 : pnow_tm = localtime_r(&now_t, &now_tm);
58 0 : if (pnow_tm == NULL) {
59 0 : return;
60 : }
61 :
62 : /* form up timeout string depending whether it's today's date or not */
63 0 : if (timeout_tm.tm_year != now_tm.tm_year ||
64 0 : timeout_tm.tm_mon != now_tm.tm_mon ||
65 0 : timeout_tm.tm_mday != now_tm.tm_mday) {
66 :
67 0 : timeout_str = asctime(&timeout_tm);
68 0 : if (!timeout_str) {
69 0 : return;
70 : }
71 0 : timeout_str[strlen(timeout_str) - 1] = '\0'; /* remove tailing CR */
72 : } else {
73 0 : if (asprintf(&alloc_str, "%.2d:%.2d:%.2d", timeout_tm.tm_hour,
74 : timeout_tm.tm_min, timeout_tm.tm_sec) == -1) {
75 0 : return;
76 : }
77 0 : timeout_str = alloc_str;
78 : }
79 :
80 0 : datastr = (char *)value.data;
81 :
82 0 : if (strnequal(keystr, "NAME2SID/", strlen("NAME2SID/"))) {
83 0 : const char *strv = (char *)value.data;
84 0 : size_t strv_len = value.length;
85 0 : const char *sid = strv_len_next(strv, strv_len, NULL);
86 0 : const char *type = strv_len_next(strv, strv_len, sid);
87 0 : datastr = talloc_asprintf(talloc_tos(), "%s (%s)", sid, type);
88 : }
89 :
90 0 : if (strnequal(keystr, "SID2NAME/", strlen("SID2NAME/"))) {
91 0 : const char *strv = (char *)value.data;
92 0 : size_t strv_len = value.length;
93 0 : const char *domain = strv_len_next(strv, strv_len, NULL);
94 0 : const char *name = strv_len_next(strv, strv_len, domain);
95 0 : const char *type = strv_len_next(strv, strv_len, name);
96 0 : datastr = talloc_asprintf(talloc_tos(), "%s\\%s (%s)",
97 : domain, name, type);
98 : }
99 :
100 0 : if ((value.length > 0) && (value.data[value.length-1] != '\0')) {
101 0 : datastr_free = talloc_asprintf(
102 0 : talloc_tos(), "<binary length %d>",
103 0 : (int)value.length);
104 0 : datastr = datastr_free;
105 0 : if (datastr == NULL) {
106 0 : datastr = "<binary>";
107 : }
108 : }
109 :
110 0 : d_printf(_("Key: %s\t Timeout: %s\t Value: %s %s\n"), keystr,
111 0 : timeout_str, datastr, timeout > now_t ? "": _("(expired)"));
112 :
113 0 : SAFE_FREE(alloc_str);
114 : }
115 :
116 501 : static void delete_cache_entry(const char* keystr, const char* datastr,
117 : const time_t timeout, void* dptr)
118 : {
119 501 : if (!gencache_del(keystr))
120 0 : d_fprintf(stderr, _("Couldn't delete entry! key = %s\n"),
121 : keystr);
122 501 : }
123 :
124 :
125 : /**
126 : * Parse text representation of timeout value
127 : *
128 : * @param timeout_str string containing text representation of the timeout
129 : * @return numeric timeout of time_t type
130 : **/
131 0 : static time_t parse_timeout(const char* timeout_str)
132 : {
133 0 : char sign = '\0', *number = NULL, unit = '\0';
134 0 : int len, number_begin, number_end;
135 0 : time_t timeout;
136 :
137 : /* sign detection */
138 0 : if (timeout_str[0] == '!' || timeout_str[0] == '+') {
139 0 : sign = timeout_str[0];
140 0 : number_begin = 1;
141 : } else {
142 0 : number_begin = 0;
143 : }
144 :
145 : /* unit detection */
146 0 : len = strlen(timeout_str);
147 0 : switch (timeout_str[len - 1]) {
148 0 : case 's':
149 : case 'm':
150 : case 'h':
151 : case 'd':
152 0 : case 'w': unit = timeout_str[len - 1];
153 : }
154 :
155 : /* number detection */
156 0 : len = (sign) ? strlen(&timeout_str[number_begin]) : len;
157 0 : number_end = (unit) ? len - 1 : len;
158 0 : number = SMB_STRNDUP(&timeout_str[number_begin], number_end);
159 :
160 : /* calculate actual timeout value */
161 0 : timeout = (time_t)atoi(number);
162 :
163 0 : switch (unit) {
164 0 : case 'm': timeout *= 60; break;
165 0 : case 'h': timeout *= 60*60; break;
166 0 : case 'd': timeout *= 60*60*24; break;
167 0 : case 'w': timeout *= 60*60*24*7; break; /* that's fair enough, I think :) */
168 : }
169 :
170 0 : switch (sign) {
171 0 : case '!': timeout = time(NULL) - timeout; break;
172 0 : case '+':
173 0 : default: timeout += time(NULL); break;
174 : }
175 :
176 0 : if (number) SAFE_FREE(number);
177 0 : return timeout;
178 : }
179 :
180 :
181 : /**
182 : * Add an entry to the cache. If it does exist, then set it.
183 : *
184 : * @param c A net_context structure
185 : * @param argv key, value and timeout are passed in command line
186 : * @return 0 on success, otherwise failure
187 : **/
188 0 : static int net_cache_add(struct net_context *c, int argc, const char **argv)
189 : {
190 0 : const char *keystr, *datastr, *timeout_str;
191 0 : time_t timeout;
192 :
193 0 : if (argc < 3 || c->display_usage) {
194 0 : d_printf("%s\n%s",
195 : _("Usage:"),
196 : _("net cache add <key string> <data string> "
197 : "<timeout>\n"));
198 0 : return -1;
199 : }
200 :
201 0 : keystr = argv[0];
202 0 : datastr = argv[1];
203 0 : timeout_str = argv[2];
204 :
205 : /* parse timeout given in command line */
206 0 : timeout = parse_timeout(timeout_str);
207 0 : if (!timeout) {
208 0 : d_fprintf(stderr, _("Invalid timeout argument.\n"));
209 0 : return -1;
210 : }
211 :
212 0 : if (gencache_set(keystr, datastr, timeout)) {
213 0 : d_printf(_("New cache entry stored successfully.\n"));
214 0 : return 0;
215 : }
216 :
217 0 : d_fprintf(stderr, _("Entry couldn't be added. Perhaps there's already such a key.\n"));
218 0 : return -1;
219 : }
220 :
221 : /**
222 : * Delete an entry in the cache
223 : *
224 : * @param c A net_context structure
225 : * @param argv key to delete an entry of
226 : * @return 0 on success, otherwise failure
227 : **/
228 740 : static int net_cache_del(struct net_context *c, int argc, const char **argv)
229 : {
230 740 : const char *keystr = argv[0];
231 :
232 740 : if (argc < 1 || c->display_usage) {
233 0 : d_printf("%s\n%s",
234 : _("Usage:"),
235 : _(" net cache del <key string>\n"));
236 0 : return -1;
237 : }
238 :
239 740 : if(gencache_del(keystr)) {
240 526 : d_printf(_("Entry deleted.\n"));
241 526 : return 0;
242 : }
243 :
244 214 : d_fprintf(stderr, _("Couldn't delete specified entry\n"));
245 214 : return -1;
246 : }
247 :
248 :
249 : /**
250 : * Get and display an entry from the cache
251 : *
252 : * @param c A net_context structure
253 : * @param argv key to search an entry of
254 : * @return 0 on success, otherwise failure
255 : **/
256 0 : static int net_cache_get(struct net_context *c, int argc, const char **argv)
257 : {
258 0 : const char* keystr = argv[0];
259 0 : DATA_BLOB value;
260 0 : time_t timeout;
261 :
262 0 : if (argc < 1 || c->display_usage) {
263 0 : d_printf("%s\n%s",
264 : _("Usage:"),
265 : _(" net cache get <key>\n"));
266 0 : return -1;
267 : }
268 :
269 0 : if (gencache_get_data_blob(keystr, NULL, &value, &timeout, NULL)) {
270 0 : print_cache_entry(keystr, value, timeout, NULL);
271 0 : data_blob_free(&value);
272 0 : return 0;
273 : }
274 :
275 0 : d_fprintf(stderr, _("Failed to find entry\n"));
276 0 : return -1;
277 : }
278 :
279 :
280 : /**
281 : * Search an entry/entries in the cache
282 : *
283 : * @param c A net_context structure
284 : * @param argv key pattern to match the entries to
285 : * @return 0 on success, otherwise failure
286 : **/
287 0 : static int net_cache_search(struct net_context *c, int argc, const char **argv)
288 : {
289 0 : const char* pattern;
290 :
291 0 : if (argc < 1 || c->display_usage) {
292 0 : d_printf("%s\n%s",
293 : _("Usage:"),
294 : _(" net cache search <pattern>\n"));
295 0 : return -1;
296 : }
297 :
298 0 : pattern = argv[0];
299 0 : gencache_iterate_blobs(print_cache_entry, NULL, pattern);
300 0 : return 0;
301 : }
302 :
303 :
304 : /**
305 : * List the contents of the cache
306 : *
307 : * @param c A net_context structure
308 : * @param argv ignored in this functionality
309 : * @return always returns 0
310 : **/
311 0 : static int net_cache_list(struct net_context *c, int argc, const char **argv)
312 : {
313 0 : const char* pattern = "*";
314 :
315 0 : if (c->display_usage) {
316 0 : d_printf( "%s\n"
317 : "net cache list\n"
318 : " %s\n",
319 : _("Usage:"),
320 : _("List all cache entries."));
321 0 : return 0;
322 : }
323 0 : gencache_iterate_blobs(print_cache_entry, NULL, pattern);
324 0 : return 0;
325 : }
326 :
327 :
328 : /**
329 : * Flush the whole cache
330 : *
331 : * @param c A net_context structure
332 : * @param argv ignored in this functionality
333 : * @return always returns 0
334 : **/
335 10 : static int net_cache_flush(struct net_context *c, int argc, const char **argv)
336 : {
337 10 : const char* pattern = "*";
338 10 : if (c->display_usage) {
339 0 : d_printf( "%s\n"
340 : "net cache flush\n"
341 : " %s",
342 : _("Usage:"),
343 : _("Delete all cache entries."));
344 0 : return 0;
345 : }
346 10 : gencache_iterate(delete_cache_entry, NULL, pattern);
347 10 : return 0;
348 : }
349 :
350 72 : static int netsamlog_cache_for_all_cb(const char *sid_str,
351 : time_t when_cached,
352 : struct netr_SamInfo3 *info3,
353 : void *private_data)
354 : {
355 72 : struct net_context *c = (struct net_context *)private_data;
356 72 : char *name = NULL;
357 :
358 72 : name = talloc_asprintf(c, "%s\\%s",
359 : info3->base.logon_domain.string,
360 : info3->base.account_name.string);
361 72 : if (name == NULL) {
362 0 : return -1;
363 : }
364 :
365 72 : d_printf("%-50s %-40s %s\n",
366 : sid_str,
367 : name,
368 : timestring(c, when_cached));
369 :
370 72 : return 0;
371 : }
372 :
373 6 : static int net_cache_samlogon_list(struct net_context *c,
374 : int argc,
375 : const char **argv)
376 : {
377 0 : int ret;
378 :
379 6 : d_printf("%-50s %-40s When cached\n", "SID", "Name");
380 6 : d_printf("------------------------------------------------------------"
381 : "------------------------------------------------------------"
382 : "----\n");
383 :
384 6 : ret = netsamlog_cache_for_all(netsamlog_cache_for_all_cb, c);
385 6 : if (ret == -1) {
386 0 : return -1;
387 : }
388 :
389 6 : return 0;
390 : }
391 :
392 4 : static int net_cache_samlogon_show(struct net_context *c,
393 : int argc,
394 : const char **argv)
395 : {
396 4 : const char *sid_str = argv[0];
397 0 : struct dom_sid sid;
398 4 : struct dom_sid *user_sids = NULL;
399 0 : uint32_t num_user_sids;
400 4 : struct netr_SamInfo3 *info3 = NULL;
401 4 : char *name = NULL;
402 0 : uint32_t i;
403 0 : NTSTATUS status;
404 0 : bool ok;
405 :
406 4 : if (argc != 1 || c->display_usage) {
407 0 : d_printf("%s\n"
408 : "net cache samlogon show SID\n"
409 : " %s\n",
410 : _("Usage:"),
411 : _("Show samlogon cache entry for SID."));
412 0 : return 0;
413 : }
414 :
415 4 : ok = string_to_sid(&sid, sid_str);
416 4 : if (!ok) {
417 0 : d_printf("String to SID failed for %s\n", sid_str);
418 0 : return -1;
419 : }
420 :
421 4 : info3 = netsamlogon_cache_get(c, &sid);
422 4 : if (info3 == NULL) {
423 0 : d_printf("SID %s not found in samlogon cache\n", sid_str);
424 0 : return -1;
425 : }
426 :
427 4 : name = talloc_asprintf(c, "%s\\%s",
428 : info3->base.logon_domain.string,
429 : info3->base.account_name.string);
430 4 : if (name == NULL) {
431 0 : return -1;
432 : }
433 :
434 4 : d_printf("Name: %s\n", name);
435 :
436 4 : status = sid_array_from_info3(c,
437 : info3,
438 : &user_sids,
439 : &num_user_sids,
440 : true);
441 4 : if (!NT_STATUS_IS_OK(status)) {
442 0 : TALLOC_FREE(user_sids);
443 0 : d_printf("sid_array_from_info3 failed for %s\n", sid_str);
444 0 : return -1;
445 : }
446 :
447 18 : for (i = 0; i < num_user_sids; i++) {
448 0 : struct dom_sid_buf buf;
449 14 : d_printf("SID %2" PRIu32 ": %s\n",
450 : i,
451 14 : dom_sid_str_buf(&user_sids[i], &buf));
452 : }
453 :
454 4 : TALLOC_FREE(user_sids);
455 :
456 4 : return 0;
457 : }
458 :
459 4 : static int net_cache_samlogon_ndrdump(struct net_context *c,
460 : int argc,
461 : const char **argv)
462 : {
463 4 : const char *sid_str = NULL;
464 0 : struct dom_sid sid;
465 4 : struct netr_SamInfo3 *info3 = NULL;
466 4 : struct ndr_print *ndr_print = NULL;
467 0 : bool ok;
468 :
469 4 : if (argc != 1 || c->display_usage) {
470 0 : d_printf( "%s\n"
471 : "net cache samlogon ndrdump SID\n"
472 : " %s\n",
473 : _("Usage:"),
474 : _("Show samlogon cache entry for SID."));
475 0 : return 0;
476 : }
477 :
478 4 : sid_str = argv[0];
479 :
480 4 : ok = string_to_sid(&sid, sid_str);
481 4 : if (!ok) {
482 0 : d_printf("String to SID failed for %s\n", sid_str);
483 0 : return -1;
484 : }
485 :
486 4 : info3 = netsamlogon_cache_get(c, &sid);
487 4 : if (info3 == NULL) {
488 0 : d_printf("SID %s not found in samlogon cache\n", sid_str);
489 0 : return -1;
490 : }
491 :
492 4 : ndr_print = talloc_zero(c, struct ndr_print);
493 4 : if (ndr_print == NULL) {
494 0 : d_printf("Could not allocate memory.\n");
495 0 : return -1;
496 : }
497 :
498 4 : ndr_print->print = ndr_print_printf_helper;
499 4 : ndr_print->depth = 1;
500 4 : ndr_print_netr_SamInfo3(ndr_print, "netr_SamInfo3", info3);
501 4 : TALLOC_FREE(ndr_print);
502 :
503 4 : return 0;
504 : }
505 :
506 4 : static int net_cache_samlogon_delete(struct net_context *c,
507 : int argc,
508 : const char **argv)
509 : {
510 4 : const char *sid_str = argv[0];
511 0 : struct dom_sid sid;
512 0 : bool ok;
513 :
514 4 : if (argc != 1 || c->display_usage) {
515 0 : d_printf( "%s\n"
516 : "net cache samlogon delete SID\n"
517 : " %s\n",
518 : _("Usage:"),
519 : _("Delete samlogon cache entry for SID."));
520 0 : return 0;
521 : }
522 :
523 4 : ok = string_to_sid(&sid, sid_str);
524 4 : if (!ok) {
525 0 : d_printf("String to SID failed for %s\n", sid_str);
526 0 : return -1;
527 : }
528 :
529 4 : netsamlogon_clear_cached_user(&sid);
530 :
531 4 : return 0;
532 : }
533 :
534 18 : static int net_cache_samlogon(struct net_context *c, int argc, const char **argv)
535 : {
536 18 : struct functable func[] = {
537 : {
538 : "list",
539 : net_cache_samlogon_list,
540 : NET_TRANSPORT_LOCAL,
541 : N_("List samlogon cache"),
542 : N_("net cache samlogon list\n"
543 : " List samlogon cachen\n")
544 : },
545 : {
546 : "show",
547 : net_cache_samlogon_show,
548 : NET_TRANSPORT_LOCAL,
549 : N_("Show samlogon cache entry"),
550 : N_("net cache samlogon show SID\n"
551 : " Show samlogon cache entry\n")
552 : },
553 : {
554 : "ndrdump",
555 : net_cache_samlogon_ndrdump,
556 : NET_TRANSPORT_LOCAL,
557 : N_("Dump the samlogon cache entry NDR blob"),
558 : N_("net cache samlogon ndrdump SID\n"
559 : " Dump the samlogon cache entry NDR blob\n")
560 : },
561 : {
562 : "delete",
563 : net_cache_samlogon_delete,
564 : NET_TRANSPORT_LOCAL,
565 : N_("Delete samlogon cache entry"),
566 : N_("net cache samlogon delete SID\n"
567 : " Delete samlogon cache entry\n")
568 : },
569 : {NULL, NULL, 0, NULL, NULL}
570 : };
571 :
572 18 : return net_run_function(c, argc, argv, "net cache samlogon", func);
573 : }
574 :
575 : /**
576 : * Entry point to 'net cache' subfunctionality
577 : *
578 : * @param c A net_context structure
579 : * @param argv arguments passed to further called functions
580 : * @return whatever further functions return
581 : **/
582 768 : int net_cache(struct net_context *c, int argc, const char **argv)
583 : {
584 768 : struct functable func[] = {
585 : {
586 : "add",
587 : net_cache_add,
588 : NET_TRANSPORT_LOCAL,
589 : N_("Add new cache entry"),
590 : N_("net cache add <key string> <data string> <timeout>\n"
591 : " Add new cache entry.\n"
592 : " key string\tKey string to add cache data under.\n"
593 : " data string\tData to store under given key.\n"
594 : " timeout\tTimeout for cache data.")
595 : },
596 : {
597 : "del",
598 : net_cache_del,
599 : NET_TRANSPORT_LOCAL,
600 : N_("Delete existing cache entry by key"),
601 : N_("net cache del <key string>\n"
602 : " Delete existing cache entry by key.\n"
603 : " key string\tKey string to delete.")
604 : },
605 : {
606 : "get",
607 : net_cache_get,
608 : NET_TRANSPORT_LOCAL,
609 : N_("Get cache entry by key"),
610 : N_("net cache get <key string>\n"
611 : " Get cache entry by key.\n"
612 : " key string\tKey string to look up cache entry for.")
613 :
614 : },
615 : {
616 : "search",
617 : net_cache_search,
618 : NET_TRANSPORT_LOCAL,
619 : N_("Search entry by pattern"),
620 : N_("net cache search <pattern>\n"
621 : " Search entry by pattern.\n"
622 : " pattern\tPattern to search for in cache.")
623 : },
624 : {
625 : "list",
626 : net_cache_list,
627 : NET_TRANSPORT_LOCAL,
628 : N_("List all cache entries"),
629 : N_("net cache list\n"
630 : " List all cache entries")
631 : },
632 : {
633 : "flush",
634 : net_cache_flush,
635 : NET_TRANSPORT_LOCAL,
636 : N_("Delete all cache entries"),
637 : N_("net cache flush\n"
638 : " Delete all cache entries")
639 : },
640 : {
641 : "samlogon",
642 : net_cache_samlogon,
643 : NET_TRANSPORT_LOCAL,
644 : N_("List contents of the samlogon cache"),
645 : N_("net cache samlogon\n"
646 : " List contents of the samlogon cache")
647 : },
648 : {NULL, NULL, 0, NULL, NULL}
649 : };
650 :
651 768 : return net_run_function(c, argc, argv, "net cache", func);
652 : }
|