Advertisement
ibragimovrinat

insecure

Feb 4th, 2012
413
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.49 KB | None | 0 0
  1. #define FUSE_USE_VERSION 26
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <fuse.h>
  6. #include <errno.h>
  7. #include <dirent.h>
  8. #include <fcntl.h>
  9.  
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <unistd.h>
  13.  
  14. #include <glib.h>
  15. #include <sqlite3.h>
  16.  
  17. struct insecure_state {
  18.     char *mount_point; // mount point path
  19.     int mount_point_len;
  20.     char *backend_point; // backend path
  21.     int backend_point_len;
  22.     sqlite3 *db;
  23.     time_t last_flush;
  24. };
  25.  
  26. static const char *sql_create_tables =
  27.     "CREATE TABLE IF NOT EXISTS fit (id INTEGER PRIMARY KEY, fname TEXT, backname TEXT, parent INTEGER); "
  28.     "CREATE UNIQUE INDEX IF NOT EXISTS fit_fname ON fit (fname); "
  29.     "INSERT OR IGNORE INTO fit (id, fname, parent, backname) VALUES (1, '/', 0, '/'); ";
  30.  
  31. #define FS_DATA ((struct insecure_state *) fuse_get_context()->private_data)
  32.  
  33. static void insecure_flush_tables () {
  34.     struct insecure_state *state = FS_DATA;
  35.     static int counter = 0;
  36.  
  37.     counter ++;
  38.     time_t current = time(NULL);
  39.     if ((counter > 4000) || (current - state->last_flush > 2)) {
  40.         sqlite3_exec (FS_DATA->db, "COMMIT; BEGIN TRANSACTION;", NULL, NULL, NULL);
  41.         counter = 0;
  42.         state->last_flush = current;
  43.     }
  44. }
  45.  
  46. /// Inserts file path to database and returns string containing backpath
  47. ///
  48. /// caller must free returned string with g_free()
  49. static gchar *insecure_insert_name_to_db (const char *path) {
  50.     struct insecure_state *state = FS_DATA;
  51.     int rc;
  52.  
  53.     insecure_flush_tables ();
  54.  
  55.     sqlite3_stmt *stmt_ins;
  56.     sqlite3_prepare_v2 (state->db,
  57.         "INSERT OR IGNORE INTO fit (fname, parent) SELECT ?, id FROM fit WHERE fname=?;",
  58.         -1,
  59.         &stmt_ins,
  60.         NULL);
  61.     sqlite3_bind_text (stmt_ins, 1, path, -1, SQLITE_TRANSIENT);
  62.     gchar *parent_path = g_path_get_dirname (path);
  63.     sqlite3_bind_text (stmt_ins, 2, parent_path, -1, SQLITE_TRANSIENT);
  64.     g_free (parent_path);
  65.  
  66.     rc = sqlite3_step (stmt_ins);
  67.     sqlite3_finalize (stmt_ins);
  68.  
  69.     sqlite3_int64 rowid = sqlite3_last_insert_rowid (state->db);
  70.     sqlite3_stmt *stmt_sel;
  71.     sqlite3_prepare_v2 (state->db,
  72.         "SELECT fit.id, p.backname FROM fit, fit as p WHERE fit.ROWID=? AND p.id=fit.parent",
  73.         -1,
  74.         &stmt_sel,
  75.         NULL);
  76.     sqlite3_bind_int64 (stmt_sel, 1, rowid);
  77.     rc = sqlite3_step (stmt_sel);
  78.     if (SQLITE_ROW != rc) {
  79.         sqlite3_finalize (stmt_sel);
  80.         return NULL;
  81.     }
  82.  
  83.     GString *backend_name = g_string_new (NULL);
  84.     g_string_printf (backend_name, "prefix_%d", sqlite3_column_int (stmt_sel, 0));
  85.  
  86.     gchar *backend_path = g_build_path ("/", (gchar *)sqlite3_column_text (stmt_sel, 1), backend_name->str, NULL);
  87.  
  88.     sqlite3_stmt *stmt_upd;
  89.     sqlite3_prepare_v2 (state->db,
  90.         "UPDATE fit SET backname = ? WHERE ROWID=?",
  91.         -1,
  92.         &stmt_upd,
  93.         NULL);
  94.     sqlite3_bind_text (stmt_upd, 1, backend_path, -1, SQLITE_TRANSIENT);
  95.     sqlite3_bind_int64 (stmt_upd, 2, rowid);
  96.     sqlite3_step (stmt_upd);
  97.     sqlite3_finalize (stmt_upd);
  98.  
  99.     gchar *full_backend_path = g_build_path ("/", state->backend_point, backend_path, NULL);
  100.  
  101.     g_free (backend_path);
  102.     g_string_free (backend_name, TRUE);
  103.  
  104.     sqlite3_finalize (stmt_sel);
  105.     return full_backend_path;
  106. }
  107.  
  108. static gchar *insecure_get_backname (const gchar *fname) {
  109.     struct insecure_state *state = FS_DATA;
  110.     sqlite3_stmt *stmt;
  111.     int rc;
  112.  
  113.     insecure_flush_tables ();
  114.  
  115.     sqlite3_prepare_v2 (state->db, "SELECT backname FROM fit WHERE fname=?", -1, &stmt, NULL);
  116.     sqlite3_bind_text (stmt, 1, fname, -1, SQLITE_TRANSIENT);
  117.  
  118.     rc = sqlite3_step (stmt);
  119.     if (SQLITE_ROW != rc) {
  120.         sqlite3_finalize (stmt);
  121.         return NULL;
  122.     }
  123.     gchar *ret = g_strdup ((gchar *)sqlite3_column_text (stmt, 0));
  124.     sqlite3_finalize (stmt);
  125.     return ret;
  126. }
  127.  
  128. int insecure_getattr (const char *path, struct stat *stbuf) {
  129.     int ret;
  130.     int rc;
  131.     struct insecure_state *state = FS_DATA;
  132.  
  133.     insecure_flush_tables ();
  134.  
  135.     printf ("stat '%s'\n", path);
  136.  
  137.     sqlite3_stmt *stmt;
  138.     rc = sqlite3_prepare_v2 (state->db, "SELECT backname FROM fit WHERE fname=?;", -1, &stmt, NULL);
  139.     // printf ("sqlite3_prepare rc = %d\n", rc);
  140.     rc = sqlite3_bind_text (stmt, 1, path, -1, SQLITE_TRANSIENT);
  141.     // printf ("sqlite3_bind_text rc = %d\n", rc);
  142.     rc = sqlite3_step (stmt);
  143.     // printf ("sqlite3_step rc = %d\n", rc);
  144.  
  145.     if (SQLITE_ROW == rc) {
  146.         printf ("+ '%s', '%s'\n", path, sqlite3_column_text (stmt, 0));
  147.  
  148.         gchar *full_path = g_build_path ("/", state->backend_point, sqlite3_column_text (stmt, 0), NULL);
  149.         ret = lstat (full_path, stbuf);
  150.         g_free (full_path);
  151.     } else {
  152.         printf ("- '%s'\n", path);
  153.         ret = -ENOENT;
  154.     }
  155.  
  156.     sqlite3_finalize (stmt);
  157.  
  158.     return ret;
  159. }
  160.  
  161. void *insecure_init (struct fuse_conn_info *conn) {
  162.     printf("init\n");
  163.  
  164.     struct insecure_state *state = FS_DATA;
  165.     int rc;
  166.  
  167.     gchar *db_name = g_build_path ("/", state->backend_point, ".filenames.db", NULL);
  168.     rc = sqlite3_open (db_name, &state->db);
  169.     printf ("db_name = %s\n", db_name);
  170.     printf ("rc = %d\n", rc);
  171.     // FIXME: error handling
  172.     rc = sqlite3_exec (state->db, sql_create_tables, NULL, 0, NULL);
  173.     printf ("rc = %d\n", rc);
  174.  
  175.     sqlite3_exec (state->db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
  176.  
  177.     return FS_DATA;
  178. }
  179.  
  180. void insecure_destroy (void *p) {
  181.     printf ("shutting down\n");
  182.     sqlite3_close (FS_DATA->db);
  183. }
  184.  
  185. int insecure_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
  186. {
  187.     printf ("readdir on %s\n", path);
  188.     struct insecure_state *state = FS_DATA;
  189.     int rc;
  190.  
  191.     insecure_flush_tables ();
  192.  
  193.     sqlite3_stmt *stmt;
  194.  
  195.     rc = sqlite3_prepare_v2 (state->db,
  196.         "SELECT fit.fname FROM fit, fit as p WHERE p.fname=? AND p.id=fit.parent",
  197.         -1,     // nByte
  198.         &stmt,
  199.         NULL    // pzTail
  200.     );
  201.  
  202.     rc = sqlite3_bind_text (stmt, 1, path, -1, SQLITE_TRANSIENT);
  203.  
  204.     filler (buf, ".", NULL, 0);
  205.     filler (buf, "..", NULL, 0);
  206.  
  207.     while (SQLITE_ROW == sqlite3_step (stmt)) {
  208.         gchar *basename = g_path_get_basename ((char *)sqlite3_column_text (stmt, 0));
  209.         rc = filler (buf, basename, NULL, 0);
  210.         g_free (basename);
  211.  
  212.         if (0 != rc) {
  213.             sqlite3_finalize (stmt);
  214.             return -ENOMEM;
  215.         }
  216.     }
  217.     sqlite3_finalize (stmt);
  218.  
  219.     return 0;
  220. }
  221.  
  222. int insecure_open (const char *path, struct fuse_file_info *fi) {
  223.     printf ("open '%s'\n", path);
  224.     insecure_flush_tables ();
  225.  
  226.     gchar *backname = insecure_get_backname (path);
  227.     gchar *full_backname = g_build_path ("/", FS_DATA->backend_point, backname, NULL);
  228.  
  229.     int fd = open (full_backname, fi->flags);
  230.  
  231.     g_free (full_backname);
  232.     g_free (backname);
  233.  
  234.     if (fd < 0) return -errno;
  235.  
  236.     fi->fh = fd;
  237.     return 0;
  238. }
  239.  
  240. int insecure_release (const char *path, struct fuse_file_info *fi) {
  241.     printf ("close '%s'\n", path);
  242.     insecure_flush_tables ();
  243.  
  244.     int ret = close (fi->fh);
  245.  
  246.     return ret;
  247. }
  248.  
  249. int insecure_mknod (const char *path, mode_t mode, dev_t dev) {
  250.     printf ("mknod %s, mode %06o\n", path, mode);
  251.     insecure_flush_tables ();
  252.     int fd;
  253.  
  254.     if (S_ISREG(mode)) {
  255.         gchar *back_path = insecure_insert_name_to_db (path);
  256.         if (NULL == back_path)
  257.             return -ENOENT;
  258.  
  259.         fd = open(back_path, O_CREAT | O_EXCL | O_WRONLY, mode);
  260.         g_free (back_path);
  261.  
  262.         if (fd < 0) return -errno;
  263.  
  264.         return close (fd);
  265.     }
  266.  
  267.     return -EACCES;
  268. }
  269.  
  270. int insecure_mkdir (const char *path, mode_t mode) {
  271.     printf ("mkdir %s, mode %06o\n", path, mode);
  272.     insecure_flush_tables ();
  273.     int ret;
  274.  
  275.     gchar *back_path = insecure_insert_name_to_db (path);
  276.     if (NULL == back_path)
  277.         return -ENOENT;
  278.  
  279.     ret = mkdir (back_path, mode);
  280.     g_free (back_path);
  281.  
  282.     return ret;
  283. }
  284.  
  285. int insecure_read (const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
  286.     printf("read of %s\n", path);
  287.     insecure_flush_tables ();
  288.     if ((off_t)-1 == lseek (fi->fh, offset, SEEK_SET)) {
  289.         return -errno;
  290.     }
  291.  
  292.     size_t bytes_read = read (fi->fh, buf, size);
  293.     if (-1 == bytes_read) return -errno;
  294.  
  295.     return bytes_read;
  296. }
  297.  
  298. int insecure_write (const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
  299.     printf("write of '%s'\n", path);
  300.     insecure_flush_tables ();
  301.     if ((off_t)-1 == lseek (fi->fh, offset, SEEK_SET)) {
  302.         return -errno;
  303.     }
  304.  
  305.     size_t bytes_written = write (fi->fh, buf, size);
  306.     if (-1 == bytes_written) return -errno;
  307.  
  308.     return bytes_written;
  309. }
  310.  
  311. int insecure_access(const char *path, int mask) {
  312.     printf ("access to '%s', mask %06o\n", path, mask);
  313.     insecure_flush_tables ();
  314.     struct insecure_state *state = FS_DATA;
  315.     sqlite3_stmt *stmt;
  316.     int rc;
  317.     int ret;
  318.  
  319.     rc = sqlite3_prepare_v2 (state->db, "SELECT backname FROM fit WHERE fname=?;", -1, &stmt, NULL);
  320.     rc = sqlite3_bind_text (stmt, 1, path, -1, SQLITE_TRANSIENT);
  321.     rc = sqlite3_step (stmt);
  322.     if (SQLITE_ROW == rc) {
  323.         gchar *full_path = g_build_path ("/", state->backend_point, sqlite3_column_text (stmt, 0), NULL);
  324.         ret = access (full_path, mask);
  325.         g_free (full_path);
  326.     } else {
  327.         ret = -ENOENT;
  328.     }
  329.  
  330.     sqlite3_finalize (stmt);
  331.  
  332.     return ret;
  333. }
  334.  
  335. int insecure_truncate (const char *path, off_t newsize) {
  336.     printf ("truncate\n");
  337.     insecure_flush_tables ();
  338.     struct insecure_state *state = FS_DATA;
  339.  
  340.     gchar *backname = insecure_get_backname (path);
  341.     gchar *full_backname = g_build_path ("/", state->backend_point, backname, NULL);
  342.  
  343.     int ret = truncate (full_backname, newsize);
  344.     g_free (full_backname);
  345.     g_free (backname);
  346.     return ret;
  347. }
  348.  
  349. int insecure_utimens (const char *path, const struct timespec tv[2]) {
  350.     insecure_flush_tables ();
  351.  
  352.     gchar *backname = insecure_get_backname (path);
  353.     gchar *full_backname = g_build_path ("/", FS_DATA->backend_point, backname, NULL);
  354.  
  355.     int fd = open (full_backname, O_RDONLY);
  356.     if (fd < 0) return -errno;
  357.     int ret = futimens (fd, tv);
  358.     close (fd);
  359.  
  360.     g_free (backname);
  361.     g_free (full_backname);
  362.  
  363.     if (ret < 0) return -errno;
  364.  
  365.     return 0;
  366. }
  367.  
  368. int insecure_unlink (const char *path) {
  369.     insecure_flush_tables ();
  370.  
  371.     gchar *backname = insecure_get_backname (path);
  372.     gchar *full_backname = g_build_path ("/", FS_DATA->backend_point, backname, NULL);
  373.     printf ("unlink '%s'\n", path);
  374.  
  375.     int ret = unlink (full_backname);
  376.     g_free (backname);
  377.     g_free (full_backname);
  378.  
  379.     sqlite3_stmt *stmt;
  380.  
  381.     sqlite3_prepare_v2 (FS_DATA->db, "DELETE FROM fit WHERE fname=?", -1, &stmt, NULL);
  382.     sqlite3_bind_text (stmt, 1, path, -1, SQLITE_TRANSIENT);
  383.     sqlite3_step (stmt);
  384.     sqlite3_finalize (stmt);
  385.     if (0 == ret) return 0;
  386.  
  387.     return -errno;
  388. }
  389.  
  390. int insecure_rmdir (const char *path) {
  391.     insecure_flush_tables ();
  392.  
  393.     gchar *backname = insecure_get_backname (path);
  394.     gchar *full_backname = g_build_path ("/", FS_DATA->backend_point, backname, NULL);
  395.     printf ("rmdir '%s'\n", path);
  396.  
  397.     int ret = rmdir (full_backname);
  398.     g_free (backname);
  399.     g_free (full_backname);
  400.  
  401.     sqlite3_stmt *stmt;
  402.  
  403.     sqlite3_prepare_v2 (FS_DATA->db, "DELETE FROM fit WHERE fname=?", -1, &stmt, NULL);
  404.     sqlite3_bind_text (stmt, 1, path, -1, SQLITE_TRANSIENT);
  405.     sqlite3_step (stmt);
  406.     sqlite3_finalize (stmt);
  407.     if (0 == ret) return 0;
  408.  
  409.     return -errno;
  410. }
  411.  
  412. int insecure_symlink (const char *path, const char *dest) {
  413.     insecure_flush_tables ();
  414.     printf ("symlink '%s' to '%s'\n", path, dest);
  415.  
  416.     gchar *full_backname = insecure_insert_name_to_db (dest);
  417.     int ret = symlink (path, full_backname);
  418.     g_free (full_backname);
  419.  
  420.     return ret;
  421. }
  422.  
  423. int insecure_readlink (const char *path, char *link, size_t size) {
  424.     insecure_flush_tables ();
  425.  
  426.     gchar *backname = insecure_get_backname (path);
  427.     gchar *full_backname = g_build_path ("/", FS_DATA->backend_point, backname, NULL);
  428.  
  429.     ssize_t ret = readlink (full_backname, link, size - 1);
  430.     if (ret < 0) return -errno;
  431.  
  432.     link[ret] = 0;
  433.     return 0;
  434. }
  435.  
  436.  
  437. struct fuse_operations insecure_op = {
  438.     .getattr = insecure_getattr,
  439.     .mknod = insecure_mknod,
  440.     .mkdir = insecure_mkdir,
  441.     .readdir = insecure_readdir,
  442.     .init = insecure_init,
  443.     .destroy = insecure_destroy,
  444.     .open = insecure_open,
  445.     .release = insecure_release,
  446.     .read = insecure_read,
  447.     .write = insecure_write,
  448.     .access = insecure_access,
  449.     .truncate = insecure_truncate,
  450.     .utimens = insecure_utimens,
  451.     .unlink = insecure_unlink,
  452.     .symlink = insecure_symlink,
  453.     .readlink = insecure_readlink,
  454.     .rmdir = insecure_rmdir,
  455. };
  456.  
  457. int main (int argc, char *argv[]) {
  458.     struct insecure_state *state;
  459.     int res;
  460.  
  461.     state = (struct insecure_state *) calloc (sizeof(struct insecure_state), 1);
  462.  
  463.     if (argc < 3) {
  464.         printf("need more arguments\n");
  465.         exit(1);
  466.     }
  467.  
  468.     state->backend_point = argv[1];
  469.     state->mount_point = argv[2];
  470.     state->mount_point_len = strlen (state->mount_point);
  471.     state->backend_point_len = strlen (state->backend_point);
  472.  
  473.     int f_argc = 6;
  474.     char *f_argv[] = {argv[0], "-f", "-s", "-o", "nonempty", state->mount_point};
  475.  
  476.     res = fuse_main (f_argc, f_argv, &insecure_op, state);
  477.     printf ("fuse_main returned %d\n", res);
  478. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement