s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
[samba.git] / source3 / modules / onefs_shadow_copy.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * OneFS shadow copy implementation that utilizes the file system's native
5  * snapshot support. This file does all of the heavy lifting.
6  *
7  * Copyright (C) Dave Richards, 2007
8  * Copyright (C) Tim Prouty, 2009
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "smbd/smbd.h"
25 #include <ifs/ifs_syscalls.h>
26 #include <sys/types.h>
27 #include <sys/isi_enc.h>
28 #include <sys/module.h>
29 #include <sys/stat.h>
30 #include <sys/syscall.h>
31 #include <sys/time.h>
32 #include <dirent.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <search.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include "onefs_shadow_copy.h"
43
44 /* Copied from ../include/proto.h */
45 void become_root(void);
46 void unbecome_root(void);
47
48 #define SNAPSHOT_DIRECTORY      ".snapshot"
49
50 #define MAX_VERSIONS            64
51
52 /**
53  * A snapshot object.
54  *
55  * During snapshot enumeration, snapshots are represented by snapshot objects
56  * and are stored in a snapshot set.  The snapshot object represents one
57  * snapshot within the set.  An important thing to note about the set is that
58  * the key of the snapshot object is the tv_sec component of the is_time
59  * member.  What this means is that we only store one snapshot for each
60  * second.  If multiple snapshots were created within the same second, we'll
61  * keep the earliest one and ignore the rest.  Thus, not all snapshots are
62  * necessarily retained.
63  */
64 struct osc_snapshot {
65         char *                  is_name;
66         struct timespec         is_time;
67         struct osc_snapshot *   is_next;
68 };
69
70 /**
71  * A snapshot context object.
72  *
73  * Snapshot contexts are used to pass information throughout the snapshot
74  * enumeration routines.  As a result, snapshot contexts are stored on the
75  * stack and are both created and destroyed within a single API function.
76  */
77 struct osc_snapshot_ctx {
78         void *          osc_set;
79         struct timespec osc_mtime;
80 };
81
82 /**
83  * A directory context.
84  *
85  * Directory contexts are the underlying data structured used to enumerate
86  * snapshot versions.  An opendir()-, readdir()- and closedir()-like interface
87  * is provided that utilizes directory contexts.  At the API level, directory
88  * contexts are passed around as void pointers.  Directory contexts are
89  * allocated on the heap and their lifetime is dictated by the calling
90  * routine.
91  */
92 struct osc_directory_ctx {
93         size_t          idc_pos;
94         size_t          idc_len;
95         size_t          idc_size;
96         char **         idc_version;
97 };
98
99 /**
100  * Return a file descriptor to the STF names directory.
101  *
102  * Opens the STF names directory and returns a file descriptor to it.
103  * Subsequent calls return the same value (avoiding the need to re-open the
104  * directory repeatedly).  Caveat caller: don't close the file descriptor or
105  * you will be shot!
106  */
107 static int
108 osc_get_names_directory_fd(void)
109 {
110         static int fd = -1;
111
112         if (fd == -1) {
113                 become_root();
114                 fd = pctl2_lin_open(STF_NAMES_LIN, HEAD_SNAPID, O_RDONLY);
115                 unbecome_root();
116         }
117
118         return fd;
119 }
120
121 /**
122  * Compare two time values.
123  *
124  * Accepts two struct timespecs and compares the tv_sec components of these
125  * values.  It returns -1 if the first value preceeds the second, 0 if they
126  * are equal and +1 if the first values succeeds the second.
127  */
128 static int
129 osc_time_compare(const struct timespec *tsp1, const struct timespec *tsp2)
130 {
131         return (tsp1->tv_sec < tsp2->tv_sec) ? -1 :
132                (tsp1->tv_sec > tsp2->tv_sec) ? +1 : 0;
133 }
134
135 /**
136  * Compare two timespec values.
137  *
138  * Compares two timespec values.  It returns -1 if the first value preceeds
139  * the second, 0 if they are equal and +1 if the first values succeeds the
140  * second.
141  */
142 static int
143 osc_timespec_compare(const struct timespec *tsp1, const struct timespec *tsp2)
144 {
145         return (tsp1->tv_sec  < tsp2->tv_sec)  ? -1 :
146                (tsp1->tv_sec  > tsp2->tv_sec)  ? +1 :
147                (tsp1->tv_nsec < tsp2->tv_nsec) ? -1 :
148                (tsp1->tv_nsec > tsp2->tv_nsec) ? +1 : 0;
149 }
150
151 /**
152  * Determine whether a timespec value is zero.
153  *
154  * Return 1 if the struct timespec provided is zero and 0 otherwise.
155  */
156 static int
157 osc_timespec_is_zero(const struct timespec *tsp)
158 {
159         return (tsp->tv_sec  == 0) &&
160                (tsp->tv_nsec == 0);
161 }
162
163 /**
164  * Create a snapshot object.
165  *
166  * Allocates and initializes a new snapshot object.  In addition to allocating
167  * space for the snapshot object itself, space is allocated for the snapshot
168  * name.  Both the name and time are then copied to the new object.
169  */
170 static struct osc_snapshot *
171 osc_snapshot_create(const char *name, const struct timespec *tsp)
172 {
173         struct osc_snapshot *isp;
174
175         isp = malloc(sizeof *isp);
176         if (isp == NULL)
177                 goto out;
178
179         isp->is_name = malloc(strlen(name) + 1);
180         if (isp->is_name == NULL) {
181                 free(isp);
182                 isp = NULL;
183                 goto out;
184         }
185
186         strcpy(isp->is_name, name);
187         isp->is_time = *tsp;
188         isp->is_next = NULL;
189
190  out:
191         return isp;
192 }
193
194 /**
195  * Destroy a snapshot object.
196  *
197  * Frees both the name and the snapshot object itself.  Appropriate NULL
198  * checking is performed because counting on free to do so is immoral.
199  */
200 static void
201 osc_snapshot_destroy(struct osc_snapshot *isp)
202 {
203         if (isp != NULL) {
204                 if (isp->is_name != NULL)
205                         free(isp->is_name);
206                 free(isp);
207         }
208 }
209
210 /**
211  * Destroy all snapshots in the snapshot list.
212  *
213  * Calls osc_snapshot_destroy() on each snapshot in the list.
214  */
215 static void
216 osc_snapshot_destroy_list(struct osc_snapshot *isp)
217 {
218         struct osc_snapshot *tmp;
219
220         while (isp != NULL) {
221                 tmp = isp;
222                 isp = isp->is_next;
223                 osc_snapshot_destroy(tmp);
224         }
225 }
226
227 /**
228  * Compare two snapshot objects.
229  *
230  * Compare two snapshot objects.  It is really just a wrapper for
231  * osc_time_compare(), which compare the time value of the two snapshots.
232  * N.B. time value in this context refers only to the tv_sec component.
233  */
234 static int
235 osc_snapshot_compare(const void *vp1, const void *vp2)
236 {
237         const struct osc_snapshot *isp1 = vp1;
238         const struct osc_snapshot *isp2 = vp2;
239
240         return -osc_time_compare(&isp1->is_time, &isp2->is_time);
241 }
242
243 /**
244  * Insert a snapshot into the snapshot set.
245  *
246  * Inserts a new snapshot into the snapshot set.  The key for snapshots is
247  * their creation time (it's actually the seconds portion of the creation
248  * time).  If a duplicate snapshot is found in the set, the new snapshot is
249  * added to a linked list of snapshots for that second.
250  */
251 static void
252 osc_snapshot_insert(struct osc_snapshot_ctx *oscp, const char *name,
253     const struct timespec *tsp, int *errorp)
254 {
255         struct osc_snapshot *isp1;
256         struct osc_snapshot **ispp;
257
258         isp1 = osc_snapshot_create(name, tsp);
259         if (isp1 == NULL) {
260                 *errorp = 1;
261                 return;
262         }
263
264         ispp = tsearch(isp1, &oscp->osc_set, osc_snapshot_compare);
265         if (ispp != NULL) {
266                 struct osc_snapshot *isp2 = *ispp;
267
268                 /* If this is the only snapshot for this second, we're done. */
269                 if (isp2 == isp1)
270                         return;
271
272                 /* Collision: add the new snapshot to the list. */
273                 isp1->is_next = isp2->is_next;
274                 isp2->is_next = isp1;
275
276         } else
277                 *errorp = 1;
278
279 }
280
281 /**
282  * Process the next snapshot.
283  *
284  * Called for (almost) every entry in a .snapshot directory, ("." and ".." are
285  * ignored in osc_process_snapshot_directory()).  All other entries are passed
286  * to osc_process_snapshot(), however.  These entries can fall into one of two
287  * categories: snapshot names and snapshot aliases.  We only care about
288  * snapshot names (as aliases are just redundant entries).  Once it verifies
289  * that name represents a valid snapshot name, it calls fstat() to get the
290  * creation time of the snapshot and then calls osc_snapshot_insert() to add
291  * this entry to the snapshot set.
292  */
293 static void
294 osc_process_snapshot(struct osc_snapshot_ctx *oscp, const char *name,
295     int *errorp)
296 {
297         int fd;
298         struct stf_stat stf_stat;
299         struct stat stbuf;
300
301         fd = osc_get_names_directory_fd();
302         if (fd == -1)
303                 goto out;
304
305         fd = enc_openat(fd, name, ENC_DEFAULT, O_RDONLY);
306         if (fd == -1)
307                 goto out;
308
309         memset(&stf_stat, 0, sizeof stf_stat);
310         if (ifs_snap_stat(fd, &stf_stat) == -1)
311                 goto out;
312
313         if (stf_stat.sf_type != SF_STF)
314                 goto out;
315
316         if (fstat(fd, &stbuf) == -1)
317                 goto out;
318
319         osc_snapshot_insert(oscp, name, &stbuf.st_birthtimespec, errorp);
320
321  out:
322         if (fd != -1)
323                 close(fd);
324 }
325
326 /**
327  * Process a snapshot directory.
328  *
329  * Opens the snapshot directory and calls osc_process_snapshot() for each
330  * entry.  (Well ok, "." and ".."  are ignored.)  The goal here is to add all
331  * snapshots in the directory to the snapshot set.
332  */
333 static void
334 osc_process_snapshot_directory(struct osc_snapshot_ctx *oscp, int *errorp)
335 {
336         int fd;
337         struct stat stbuf;
338         DIR *dirp;
339         struct dirent *dp;
340
341         fd = osc_get_names_directory_fd();
342         if (fd == -1)
343                 goto out;
344
345         if (fstat(fd, &stbuf) == -1)
346                 goto out;
347
348         dirp = opendir(SNAPSHOT_DIRECTORY);
349         if (dirp == NULL)
350                 goto out;
351
352         for (;;) {
353                 dp = readdir(dirp);
354                 if (dp == NULL)
355                         break;
356
357                 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
358                     (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
359                         continue;
360
361                 osc_process_snapshot(oscp, dp->d_name, errorp);
362                 if (*errorp)
363                         break;
364         }
365
366         closedir(dirp);
367
368         if (!*errorp)
369                 oscp->osc_mtime = stbuf.st_mtimespec;
370
371  out:
372         return;
373 }
374
375 /**
376  * Initialize a snapshot context object.
377  *
378  * Clears all members of the context object.
379  */
380 static void
381 osc_snapshot_ctx_init(struct osc_snapshot_ctx *oscp)
382 {
383         memset(oscp, 0, sizeof *oscp);
384 }
385
386 /**
387  * Desoy a snapshot context object.
388  *
389  * Frees all snapshots associated with the snapshot context and then calls
390  * osc_snapshot_ctx_init() to re-initialize the context object.
391  */
392 static void
393 osc_snapshot_ctx_clean(struct osc_snapshot_ctx *oscp)
394 {
395         struct osc_snapshot *tmp;
396
397         while (oscp->osc_set != NULL) {
398                 tmp = *(void **)oscp->osc_set;
399                 tdelete(tmp, &oscp->osc_set, osc_snapshot_compare);
400                 osc_snapshot_destroy_list(tmp);
401         }
402
403         osc_snapshot_ctx_init(oscp);
404 }
405
406 /**
407  * Return the "global" snapshot context.
408  *
409  * We maintain a single open snapshot context.  Return a pointer to it.
410  */
411 static struct osc_snapshot_ctx *
412 osc_get_snapshot_ctx(void)
413 {
414         static struct osc_snapshot_ctx osc = { 0, { 0, 0 } };
415
416         return &osc;
417 }
418
419 /**
420  * Determine whether a snapshot context is still valid.
421  *
422  * "Valid" in this context means "reusable".  We can re-use a previous
423  * snapshot context iff we successfully built a previous snapshot context
424  * and no snapshots have been created or deleted since we did so.
425  * A "names" directory exists within our snapshot
426  * implementation in which all snapshot names are entered.  Each time a
427  * snapshot is created or deleted, an entry must be added or removed.
428  * When this happens the modification time on the "names" directory
429  * changes.  Therefore, a snapshot context is valid iff the context
430  * pointer is non-NULL, the cached modification time is non-zero
431  * (zero means uninitialized), and the modification time of the "names"
432  * directory matches the cached value.
433  */
434 static int
435 osc_snapshot_ctx_is_valid(struct osc_snapshot_ctx *oscp)
436 {
437         int fd;
438         struct stat stbuf;
439
440         if (oscp == NULL)
441                 return 0;
442
443         if (osc_timespec_is_zero(&oscp->osc_mtime))
444                 return 0;
445
446         fd = osc_get_names_directory_fd();
447         if (fd == -1)
448                 return 0;
449
450         if (fstat(fd, &stbuf) == -1)
451                 return 0;
452
453         if (osc_timespec_compare(&oscp->osc_mtime, &stbuf.st_mtimespec) != 0)
454                 return 0;
455
456         return 1;
457 }
458
459 /**
460  * Create and initialize a directory context.
461  *
462  * Allocates a directory context from the heap and initializes it.
463  */
464 static struct osc_directory_ctx *
465 osc_directory_ctx_create(void)
466 {
467         struct osc_directory_ctx *idcp;
468
469         idcp = malloc(sizeof *idcp);
470         if (idcp != NULL)
471                 memset(idcp, 0, sizeof *idcp);
472
473         return idcp;
474 }
475
476 /**
477  * Destroy a directory context.
478  *
479  * Frees any versions associated with the directory context and then frees the
480  * context itself.
481  */
482 static void
483 osc_directory_ctx_destroy(struct osc_directory_ctx *idcp)
484 {
485         int i;
486
487         if (idcp == NULL)
488                 return;
489
490         for (i = 0; i < idcp->idc_len; i++)
491                 free(idcp->idc_version[i]);
492
493         free(idcp);
494 }
495
496 /**
497  * Expand the size of a directory context's version list.
498  *
499  * If osc_directory_ctx_append_version() detects that the version list is too
500  * small to accomodate a new version string, it called
501  * osc_directory_ctx_expand_version_list() to expand the version list.
502  */
503 static void
504 osc_directory_ctx_expand_version_list(struct osc_snapshot_ctx *oscp,
505     struct osc_directory_ctx *idcp, int *errorp)
506 {
507         size_t size;
508         char **cpp;
509
510         size = idcp->idc_size * 2 ?: 1;
511
512         cpp = realloc(idcp->idc_version, size * sizeof (char *));
513         if (cpp == NULL) {
514                 *errorp = 1;
515                 return;
516         }
517
518         idcp->idc_size = size;
519         idcp->idc_version = cpp;
520 }
521
522 /**
523  * Append a new version to a directory context.
524  *
525  * Appends a snapshot version to the
526  * directory context's version list.
527  */
528 static void
529 osc_directory_ctx_append_version(struct osc_snapshot_ctx *oscp,
530     struct osc_directory_ctx *idcp, const struct timespec *tsp, int *errorp)
531 {
532         char *cp;
533         struct tm *tmp;
534         char text[64];
535
536         if (idcp->idc_len >= MAX_VERSIONS)
537                 return;
538
539         if (idcp->idc_len >= idcp->idc_size) {
540                 osc_directory_ctx_expand_version_list(oscp, idcp, errorp);
541                 if (*errorp)
542                         return;
543         }
544
545         tmp = gmtime(&tsp->tv_sec);
546         if (tmp == NULL) {
547                 *errorp = 1;
548                 return;
549         }
550
551         snprintf(text, sizeof text,
552             "@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
553             tmp->tm_year + 1900,
554             tmp->tm_mon + 1,
555             tmp->tm_mday,
556             tmp->tm_hour,
557             tmp->tm_min,
558             tmp->tm_sec);
559
560         cp = malloc(strlen(text) + 1);
561         if (cp == NULL) {
562                 *errorp = 1;
563                 return;
564         }
565
566         strcpy(cp, text);
567
568         idcp->idc_version[idcp->idc_len++] = cp;
569 }
570
571 /**
572  * Make a directory context from a snapshot context.
573  *
574  * Once a snapshot context has been completely filled-in,
575  * osc_make_directory_ctx() is used to build a directory context from it.  The
576  * idea here is to create version for each snapshot in the snapshot set.
577  */
578 static void
579 osc_make_directory_ctx(struct osc_snapshot_ctx *oscp,
580     struct osc_directory_ctx *idcp, int *errorp)
581 {
582         static void
583         walk(const void *vp, VISIT v, int level)
584         {
585                 const struct osc_snapshot *isp;
586
587                 if ((v != postorder && v != leaf) || *errorp)
588                         return;
589
590                 isp = *(const struct osc_snapshot **)(u_long)vp;
591
592                 osc_directory_ctx_append_version(oscp, idcp, &isp->is_time,
593                     errorp);
594         }
595
596         twalk(oscp->osc_set, walk);
597 }
598
599 /**
600  * Open a version directory.
601  *
602  * Opens a version directory.  What this really means is that
603  * osc_version_opendir() returns a handle to a directory context, which can be
604  * used to retrieve version strings.
605  */
606 void *
607 osc_version_opendir(void)
608 {
609         int error = 0;
610         struct osc_directory_ctx *idcp;
611         struct osc_snapshot_ctx *oscp;
612
613         idcp = osc_directory_ctx_create();
614         if (idcp == NULL)
615                 goto error_out;
616
617         oscp = osc_get_snapshot_ctx();
618
619         if (!osc_snapshot_ctx_is_valid(oscp)) {
620                 osc_snapshot_ctx_clean(oscp);
621                 osc_process_snapshot_directory(oscp, &error);
622                 if (error)
623                         goto error_out;
624         }
625
626         osc_make_directory_ctx(oscp, idcp, &error);
627         if (error)
628                 goto error_out;
629
630         goto out;
631
632  error_out:
633         if (idcp != NULL) {
634                 osc_directory_ctx_destroy(idcp);
635                 idcp = NULL;
636         }
637
638  out:
639         return (void *)idcp;
640 }
641
642 /**
643  * Read the next version directory entry.
644  *
645  * Returns the name of the next version in the version directory, or NULL if
646  * we're at the end of the directory.  What this really does is return the
647  * next version from the version list stored in the directory context.
648  */
649 char *
650 osc_version_readdir(void *vp)
651 {
652         struct osc_directory_ctx *idcp = vp;
653
654         if (idcp == NULL)
655                 return NULL;
656
657         if (idcp->idc_pos >= idcp->idc_len)
658                 return NULL;
659
660         return idcp->idc_version[idcp->idc_pos++];
661 }
662
663 /**
664  * Close the version directory.
665  *
666  * Destroys the underlying directory context.
667  */
668 void
669 osc_version_closedir(void *vp)
670 {
671         struct osc_directory_ctx *idcp = vp;
672
673         if (idcp != NULL)
674                 osc_directory_ctx_destroy(idcp);
675 }
676
677 /**
678  * Canonicalize a path.
679  *
680  * Converts paths of the form @GMT-.. to paths of the form ../.snapshot/..
681  * It's not the prettiest routine I've ever written, but what the heck?
682  */
683 char *
684 osc_canonicalize_path(const char *path, char *snap_component)
685 {
686         int error = 0;
687         struct osc_snapshot_ctx *oscp;
688         struct tm tm;
689         int n;
690         struct osc_snapshot is;
691         struct osc_snapshot **ispp;
692         struct osc_snapshot *isp;
693         char *cpath = NULL;
694         char *cpath2 = NULL;
695         const char *snap_component_orig = snap_component;
696         struct stat sb;
697
698         oscp = osc_get_snapshot_ctx();
699
700         if (!osc_snapshot_ctx_is_valid(oscp)) {
701                 osc_snapshot_ctx_clean(oscp);
702                 osc_process_snapshot_directory(oscp, &error);
703                 if (error)
704                         goto out;
705         }
706
707         memset(&tm, 0, sizeof tm);
708         n = sscanf(snap_component,
709             "@GMT-%4u.%2u.%2u-%2u.%2u.%2u",
710             &tm.tm_year,
711             &tm.tm_mon,
712             &tm.tm_mday,
713             &tm.tm_hour,
714             &tm.tm_min,
715             &tm.tm_sec);
716         if (n != 6)
717                 goto out;
718
719         tm.tm_year -= 1900;
720         tm.tm_mon -= 1;
721
722         is.is_name = NULL;
723         is.is_time.tv_sec = timegm(&tm);
724         is.is_time.tv_nsec = 0;
725
726         ispp = tfind(&is, &oscp->osc_set, osc_snapshot_compare);
727         if (ispp == NULL)
728                 goto out;
729         isp = *ispp;
730
731         /* Determine the path after "@GMT-..." */
732         while (*snap_component != '/' && *snap_component != '\0')
733                 snap_component++;
734
735         while (*snap_component == '/')
736                 snap_component++;
737
738         cpath = malloc(strlen(SNAPSHOT_DIRECTORY) + strlen(isp->is_name) +
739             strlen(path) + 3);
740
741         if (cpath == NULL)
742                 goto out;
743
744         /*
745          * Use the first snapshot that has a successful stat for the requested
746          * path.
747          */
748         while (true) {
749
750                 sprintf(cpath, "%s/%s", SNAPSHOT_DIRECTORY, isp->is_name);
751
752                 /* Append path before "@GMT-..." */
753                 if (snap_component_orig != path) {
754                         strcat(cpath, "/");
755                         strncat(cpath, path, snap_component_orig - path);
756                 }
757
758                 /* Append path after "@GMT-..." */
759                 if (*snap_component != '\0') {
760                         strcat(cpath, "/");
761                         strcat(cpath, snap_component);
762                 }
763
764                 /* If there is a valid snapshot for this file, we're done. */
765                 if (stat(cpath, &sb) == 0)
766                         break;
767
768                 /* Try the next snapshot. If this was the last one, give up. */
769                 isp = isp->is_next;
770                 if (isp == NULL)
771                         break;
772
773                 /* If the realloc fails, give up. */
774                 cpath2 = realloc(cpath, strlen(SNAPSHOT_DIRECTORY) +
775                     strlen(isp->is_name) + strlen(path) + 3);
776                 if (cpath2 == NULL)
777                         break;
778                 cpath = cpath2;
779         }
780
781  out:
782         return cpath;
783 }