net: Avoid tallocs
[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                 TALLOC_FREE(user_sids);
460                 d_printf("sid_array_from_info3 failed for %s\n", sid_str);
461                 return -1;
462         }
463
464         for (i = 0; i < num_user_sids; i++) {
465                 char buf[DOM_SID_STR_BUFLEN];
466                 dom_sid_string_buf(&user_sids[i], buf, sizeof(buf));
467                 d_printf("SID %2" PRIu32 ": %s\n", i, buf);
468         }
469
470         TALLOC_FREE(user_sids);
471
472         return 0;
473 }
474
475 static int net_cache_samlogon_ndrdump(struct net_context *c,
476                                       int argc,
477                                       const char **argv)
478 {
479         const char *sid_str = NULL;
480         struct dom_sid sid;
481         struct netr_SamInfo3 *info3 = NULL;
482         struct ndr_print *ndr_print = NULL;
483         bool ok;
484
485         if (argc != 1 || c->display_usage) {
486                 d_printf(  "%s\n"
487                            "net cache samlogon ndrdump SID\n"
488                            "    %s\n",
489                            _("Usage:"),
490                            _("Show samlogon cache entry for SID."));
491                 return 0;
492         }
493
494         sid_str = argv[0];
495
496         ok = string_to_sid(&sid, sid_str);
497         if (!ok) {
498                 d_printf("String to SID failed for %s\n", sid_str);
499                 return -1;
500         }
501
502         info3 = netsamlogon_cache_get(c, &sid);
503         if (info3 == NULL) {
504                 d_printf("SID %s not found in samlogon cache\n", sid_str);
505                 return -1;
506         }
507
508         ndr_print = talloc_zero(c, struct ndr_print);
509         if (ndr_print == NULL) {
510                 d_printf("Could not allocate memory.\n");
511                 return -1;
512         }
513
514         ndr_print->print = ndr_print_printf_helper;
515         ndr_print->depth = 1;
516         ndr_print_netr_SamInfo3(ndr_print, "netr_SamInfo3", info3);
517         TALLOC_FREE(ndr_print);
518
519         return 0;
520 }
521
522 static int net_cache_samlogon_delete(struct net_context *c,
523                                      int argc,
524                                      const char **argv)
525 {
526         const char *sid_str = argv[0];
527         struct dom_sid sid;
528         bool ok;
529
530         if (argc != 1 || c->display_usage) {
531                 d_printf(  "%s\n"
532                            "net cache samlogon delete SID\n"
533                            "    %s\n",
534                          _("Usage:"),
535                          _("Delete samlogon cache entry for SID."));
536                 return 0;
537         }
538
539         ok = string_to_sid(&sid, sid_str);
540         if (!ok) {
541                 d_printf("String to SID failed for %s\n", sid_str);
542                 return -1;
543         }
544
545         netsamlogon_clear_cached_user(&sid);
546
547         return 0;
548 }
549
550 static int net_cache_samlogon(struct net_context *c, int argc, const char **argv)
551 {
552         struct functable func[] = {
553                 {
554                         "list",
555                         net_cache_samlogon_list,
556                         NET_TRANSPORT_LOCAL,
557                         N_("List samlogon cache"),
558                         N_("net cache samlogon list\n"
559                            "    List samlogon cachen\n")
560                 },
561                 {
562                         "show",
563                         net_cache_samlogon_show,
564                         NET_TRANSPORT_LOCAL,
565                         N_("Show samlogon cache entry"),
566                         N_("net cache samlogon show SID\n"
567                            "    Show samlogon cache entry\n")
568                 },
569                 {
570                         "ndrdump",
571                         net_cache_samlogon_ndrdump,
572                         NET_TRANSPORT_LOCAL,
573                         N_("Dump the samlogon cache entry NDR blob"),
574                         N_("net cache samlogon ndrdump SID\n"
575                            "    Dump the samlogon cache entry NDR blob\n")
576                 },
577                 {
578                         "delete",
579                         net_cache_samlogon_delete,
580                         NET_TRANSPORT_LOCAL,
581                         N_("Delete samlogon cache entry"),
582                         N_("net cache samlogon delete SID\n"
583                            "    Delete samlogon cache entry\n")
584                 },
585                 {NULL, NULL, 0, NULL, NULL}
586         };
587
588         return net_run_function(c, argc, argv, "net cache samlogon", func);
589 }
590
591 /**
592  * Entry point to 'net cache' subfunctionality
593  *
594  * @param c     A net_context structure
595  * @param argv arguments passed to further called functions
596  * @return whatever further functions return
597  **/
598 int net_cache(struct net_context *c, int argc, const char **argv)
599 {
600         struct functable func[] = {
601                 {
602                         "add",
603                         net_cache_add,
604                         NET_TRANSPORT_LOCAL,
605                         N_("Add new cache entry"),
606                         N_("net cache add <key string> <data string> <timeout>\n"
607                            "  Add new cache entry.\n"
608                            "    key string\tKey string to add cache data under.\n"
609                            "    data string\tData to store under given key.\n"
610                            "    timeout\tTimeout for cache data.")
611                 },
612                 {
613                         "del",
614                         net_cache_del,
615                         NET_TRANSPORT_LOCAL,
616                         N_("Delete existing cache entry by key"),
617                         N_("net cache del <key string>\n"
618                            "  Delete existing cache entry by key.\n"
619                            "    key string\tKey string to delete.")
620                 },
621                 {
622                         "get",
623                         net_cache_get,
624                         NET_TRANSPORT_LOCAL,
625                         N_("Get cache entry by key"),
626                         N_("net cache get <key string>\n"
627                            "  Get cache entry by key.\n"
628                            "    key string\tKey string to look up cache entry for.")
629
630                 },
631                 {
632                         "search",
633                         net_cache_search,
634                         NET_TRANSPORT_LOCAL,
635                         N_("Search entry by pattern"),
636                         N_("net cache search <pattern>\n"
637                            "  Search entry by pattern.\n"
638                            "    pattern\tPattern to search for in cache.")
639                 },
640                 {
641                         "list",
642                         net_cache_list,
643                         NET_TRANSPORT_LOCAL,
644                         N_("List all cache entries"),
645                         N_("net cache list\n"
646                            "  List all cache entries")
647                 },
648                 {
649                         "flush",
650                         net_cache_flush,
651                         NET_TRANSPORT_LOCAL,
652                         N_("Delete all cache entries"),
653                         N_("net cache flush\n"
654                            "  Delete all cache entries")
655                 },
656                 {
657                         "stabilize",
658                         net_cache_stabilize,
659                         NET_TRANSPORT_LOCAL,
660                         N_("Move transient cache content to stable storage"),
661                         N_("net cache stabilize\n"
662                            "  Move transient cache content to stable storage")
663                 },
664                 {
665                         "samlogon",
666                         net_cache_samlogon,
667                         NET_TRANSPORT_LOCAL,
668                         N_("List contents of the samlogon cache"),
669                         N_("net cache samlogon\n"
670                            "  List contents of the samlogon cache")
671                 },
672                 {NULL, NULL, 0, NULL, NULL}
673         };
674
675         return net_run_function(c, argc, argv, "net cache", func);
676 }