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