int seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, const char *repo_id, const char *user, const char *passwd, GError **error) { SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); DecryptKey *crypt_key; GString *hash_key; if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo"); return -1; } if (!repo->encrypted) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Repo is not encrypted"); return -1; } if (repo->enc_version != 1 && repo->enc_version != 2) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Unsupported encryption version"); return -1; } if (seafile_verify_repo_passwd (repo->id, passwd, repo->magic, repo->enc_version) < 0) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return -1; } crypt_key = g_new0 (DecryptKey, 1); if (!crypt_key) { g_warning ("Failed to alloc crypt key struct.\n"); seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal server error"); return -1; } if (seafile_decrypt_repo_enc_key (repo->enc_version, passwd, repo->random_key, crypt_key->key, crypt_key->iv) < 0) { seaf_repo_unref (repo); g_free (crypt_key); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return -1; } crypt_key->expire_time = (guint64)time(NULL) + REAP_THRESHOLD; crypt_key->enc_version = repo->enc_version; hash_key = g_string_new (NULL); g_string_printf (hash_key, "%s.%s", repo_id, user); /* g_debug ("[passwd mgr] Set passwd for %s\n", hash_key->str); */ g_hash_table_insert (mgr->priv->decrypt_keys, g_string_free (hash_key, FALSE), crypt_key); seaf_repo_unref (repo); return 0; }
char * seaf_clone_manager_add_download_task (SeafCloneManager *mgr, const char *repo_id, int repo_version, const char *peer_id, const char *repo_name, const char *token, const char *passwd, const char *magic, int enc_version, const char *random_key, const char *wt_parent, const char *peer_addr, const char *peer_port, const char *email, const char *more_info, GError **error) { SeafRepo *repo; char *wt_tmp, *worktree; char *ret; if (!seaf->started) { seaf_message ("System not started, skip adding clone task.\n"); return NULL; } #ifdef USE_GPL_CRYPTO if (repo_version == 0 || (passwd && enc_version < 2)) { seaf_warning ("Don't support syncing old version libraries.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Don't support syncing old version libraries"); return NULL; } #endif if (passwd && !check_encryption_args (magic, enc_version, random_key, error)) return NULL; /* After a repo was unsynced, the sync task may still be blocked in the * network, so the repo is not actually deleted yet. * In this case just return an error to the user. */ SyncInfo *sync_info = seaf_sync_manager_get_sync_info (seaf->sync_mgr, repo_id); if (sync_info && sync_info->in_sync) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Repo already exists"); return NULL; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (repo != NULL && repo->head != NULL) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Repo already exists"); return NULL; } if (is_duplicate_task (mgr, repo_id)) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Task is already in progress"); return NULL; } if (passwd && seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return NULL; } IgnoreReason reason; if (should_ignore_on_checkout (repo_name, &reason)) { if (reason == IGNORE_REASON_END_SPACE_PERIOD) g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Library name ends with space or period character"); else g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Library name contains invalid characters such as ':', '*', '|', '?'"); return NULL; } wt_tmp = g_build_filename (wt_parent, repo_name, NULL); worktree = make_worktree_for_download (mgr, wt_tmp, error); if (!worktree) { g_free (wt_tmp); return NULL; } /* If a repo was unsynced and then downloaded again, there may be * a garbage record for this repo. We don't want the downloaded blocks * be removed by GC. */ if (repo_version > 0) seaf_repo_manager_remove_garbage_repo (seaf->repo_mgr, repo_id); /* Delete orphan information in the db in case the repo was corrupt. */ if (!repo) seaf_repo_manager_remove_repo_ondisk (seaf->repo_mgr, repo_id, FALSE); ret = add_task_common (mgr, repo_id, repo_version, peer_id, repo_name, token, passwd, enc_version, random_key, worktree, peer_addr, peer_port, email, more_info, TRUE, error); g_free (worktree); g_free (wt_tmp); return ret; }
char * seaf_repo_manager_create_virtual_repo (SeafRepoManager *mgr, const char *origin_repo_id, const char *path, const char *repo_name, const char *repo_desc, const char *owner, const char *passwd, GError **error) { SeafRepo *origin_repo = NULL; SeafCommit *origin_head = NULL; char *repo_id = NULL; char *dir_id = NULL; char *orig_owner = NULL; if (seaf_repo_manager_is_virtual_repo (mgr, origin_repo_id)) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Cannot create sub-library from a sub-library"); return NULL; } repo_id = get_existing_virtual_repo (mgr, origin_repo_id, path); if (repo_id) { return repo_id; } origin_repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); if (!origin_repo) { seaf_warning ("Failed to get origin repo %.10s\n", origin_repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Origin library not exists"); return NULL; } if (origin_repo->encrypted) { if (origin_repo->enc_version < 2) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Library encryption version must be higher than 2"); seaf_repo_unref (origin_repo); return NULL; } if (!passwd || passwd[0] == 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Password is not set"); seaf_repo_unref (origin_repo); return NULL; } if (seafile_verify_repo_passwd (origin_repo_id, passwd, origin_repo->magic, origin_repo->enc_version) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); seaf_repo_unref (origin_repo); return NULL; } } origin_head = seaf_commit_manager_get_commit (seaf->commit_mgr, origin_repo->id, origin_repo->version, origin_repo->head->commit_id); if (!origin_head) { seaf_warning ("Failed to get head commit %.8s of repo %s.\n", origin_repo->head->commit_id, origin_repo->id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Bad origin repo head"); goto error; } dir_id = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, origin_repo->store_id, origin_repo->version, origin_head->root_id, path, NULL); if (!dir_id) { seaf_warning ("Path %s doesn't exist or is not a dir in repo %.10s.\n", path, origin_repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad path"); goto error; } repo_id = gen_uuid(); /* Save virtual repo info before actually create the repo. */ if (save_virtual_repo_info (mgr, repo_id, origin_repo_id, path, origin_head->commit_id) < 0) { seaf_warning ("Failed to save virtual repo info for %.10s:%s", origin_repo_id, path); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Internal error"); goto error; } orig_owner = seaf_repo_manager_get_repo_owner (mgr, origin_repo_id); if (do_create_virtual_repo (mgr, origin_repo, repo_id, repo_name, repo_desc, dir_id, orig_owner, passwd, error) < 0) goto error; if (seaf_repo_manager_set_repo_owner (mgr, repo_id, orig_owner) < 0) { seaf_warning ("Failed to set repo owner for %.10s.\n", repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to set repo owner."); goto error; } /* The size of virtual repo is non-zero at the beginning. */ update_repo_size (repo_id); seaf_repo_unref (origin_repo); seaf_commit_unref (origin_head); g_free (dir_id); g_free (orig_owner); return repo_id; error: seaf_repo_unref (origin_repo); seaf_commit_unref (origin_head); g_free (repo_id); g_free (dir_id); g_free (orig_owner); return NULL; }
char * seaf_clone_manager_add_task (SeafCloneManager *mgr, const char *repo_id, int repo_version, const char *peer_id, const char *repo_name, const char *token, const char *passwd, const char *magic, int enc_version, const char *random_key, const char *worktree_in, const char *peer_addr, const char *peer_port, const char *email, const char *more_info, GError **error) { SeafRepo *repo; char *worktree; char *ret; gboolean sync_wt_name = FALSE; if (!seaf->started) { seaf_message ("System not started, skip adding clone task.\n"); return NULL; } #ifdef USE_GPL_CRYPTO if (repo_version == 0 || (passwd && enc_version < 2)) { seaf_warning ("Don't support syncing old version libraries.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Don't support syncing old version libraries"); return NULL; } #endif if (passwd && !check_encryption_args (magic, enc_version, random_key, error)) return NULL; /* After a repo was unsynced, the sync task may still be blocked in the * network, so the repo is not actually deleted yet. * In this case just return an error to the user. */ SyncInfo *sync_info = seaf_sync_manager_get_sync_info (seaf->sync_mgr, repo_id); if (sync_info && sync_info->in_sync) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Repo already exists"); return NULL; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (repo != NULL && repo->head != NULL) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Repo already exists"); return NULL; } if (is_duplicate_task (mgr, repo_id)) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Task is already in progress"); return NULL; } if (passwd && seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return NULL; } if (!seaf_clone_manager_check_worktree_path (mgr, worktree_in, error)) return NULL; /* Return error if worktree_in conflicts with another repo or * is not a directory. */ worktree = make_worktree (mgr, worktree_in, FALSE, error); if (!worktree) { return NULL; } /* Don't sync worktree folder name with library name later if they're not the same * at the beginning. */ sync_wt_name = is_wt_repo_name_same (worktree, repo_name); /* If a repo was unsynced and then downloaded again, there may be * a garbage record for this repo. We don't want the downloaded blocks * be removed by GC. */ if (repo_version > 0) seaf_repo_manager_remove_garbage_repo (seaf->repo_mgr, repo_id); /* Delete orphan information in the db in case the repo was corrupt. */ if (!repo) seaf_repo_manager_remove_repo_ondisk (seaf->repo_mgr, repo_id, FALSE); ret = add_task_common (mgr, repo_id, repo_version, peer_id, repo_name, token, passwd, enc_version, random_key, worktree, peer_addr, peer_port, email, more_info, sync_wt_name, error); g_free (worktree); return ret; }