Reorganize project structure and RPM packages
[platform/core/security/key-manager.git] / misc / ckm_db_tool / ckm_db_merge.cpp
1 /*
2  *  Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 /*
17  * @file       ckm_db_merge.cpp
18  * @author     Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version    1.0
20  */
21
22 #include <string>
23 #include <vector>
24 #include <iostream>
25 #include <sstream>
26 #include <exception>
27
28 #include <getopt.h>
29 #include <unistd.h>
30
31 #include "db-wrapper.h"
32
33 using namespace std;
34 using namespace CKM;
35
36 typedef function<bool(DB::Row &row)> RowFilter;
37 typedef vector<RowFilter> RowFilterVector;
38
39 bool printRow(const DB::Row &row) {
40         string iv(10, ' '), data(10, ' ');
41         for (std::size_t i=0; i < iv.size(); ++i) {
42                 if (row.iv.size() > i) iv[i] = row.iv[i];
43                 if (row.data.size() > i) data[i] = row.data[i];
44         }
45         cout << "Read row:";
46         cout << "\n   Name:                  " << row.name;
47         cout << "\n   Owner:                 " << row.owner;
48         cout << "\n   Exportable:            " << row.exportable;
49         cout << "\n   Alg type:              " << static_cast<int>(row.algorithmType);
50         cout << "\n   Enc schema:            " << row.encryptionScheme;
51         cout << "\n   Data size:             " << row.dataSize;
52         cout << "\n   BackendId:             " << static_cast<int>(row.backendId);
53         cout << "\n   Data(first 10 chars):  " << data;
54         cout << "\n   IV(first 10 chars):    " << iv;
55         cout << "\n";
56         return true;
57 }
58
59 void printUsage()
60 {
61         cout << "Usage: ckm_db_merge [OPTION]\n";
62         cout << "Copy data from one key-manager database into other one.\n";
63         cout << "Options:\n";
64         cout << "  -v, --verbose         print additional data on screen\n";
65         cout << "  -s, --source UID      database UID from were data will be readed - default value 0\n";
66         cout << "  -t, --target UID      database UID to were data will be writen - default value 0\n";
67         cout << "  -p, --spass PASSWORD  password for source database - default empty string\n";
68         cout << "  -r, --tpass PASSWORD  password for target database - default emtpy string\n";
69         cout << "  -o, --owner OWNER     change the owner of information in database to OWNER\n";
70         cout << "  -h, --help            print this help on screen\n";
71         cout << "Example: Copy data from db-5001 to db-0 (system database) and change object owner to /System\n";
72         cout << "  ckm_db_merge -s 5001 -t 0 -p !@#SDFCV -o \"/System\"\n";
73         cout << "Please note: This tool automatically updates databases to newest scheme!" << endl;
74 }
75
76 int mergeDatabase(
77         uid_t uid1,
78         const Password &pass1,
79         uid_t uid2,
80         const Password &pass2,
81         const RowFilterVector &filters)
82 {
83         DbWrapper source(uid1, pass1);
84         DbWrapper target(uid2, pass2);
85
86         int ret;
87
88         if (CKM_API_SUCCESS != (ret = source.unlock())) {  // this should migrate database to newest version
89                 cerr << "Unlocking source database failed: " << ret << endl;
90                 return 1;
91         }
92         if (CKM_API_SUCCESS != (ret = target.unlock())) {  // this should migrate database to newest version
93                 cerr << "Unlocking target database failed: " << ret << endl;
94                 return 1;
95         }
96
97         DB::RowVector data = source.getRows();
98
99         // apply all filters to each row
100         for (auto &e : data) {
101                 bool migrate = true;
102                 for (auto &f : filters) {
103                         migrate &= f(e);
104                 }
105                 if (migrate) {
106                         try {
107                                 target.saveRow(e);
108                         } catch (const CKM::DB::SqlConnection::Exception::Base &e) {
109                                 cerr << "Sql exception. Migration failed or object already exist in database: " << e.DumpToString() << endl;
110                         }
111                 }
112         }
113
114         source.lock();
115         target.lock();
116         return 0;
117 }
118
119 int main(int argc, char *argv[]) {
120         Password password1, password2;
121         uid_t uid1 = 0, uid2 = 0;
122         string owner;
123         RowFilterVector filters;
124         try {
125                 while (1) {
126                         int option_index = 0;
127
128                         static struct option long_options[] = {
129                                 {"verbose", no_argument,       0, 'v'},
130                                 {"source",  required_argument, 0, 's'},
131                                 {"target",  required_argument, 0, 't'},
132                                 {"spass",   required_argument, 0, 'p'},
133                                 {"tpass",   required_argument, 0, 'r'},
134                                 {"owner",   required_argument, 0, 'o'},
135                                 {"help",    no_argument,       0, 'h'},
136                                 {0,         0,                 0, 0  }
137                         };
138                         int c = getopt_long(argc, argv, "vs:t:p:r:o:h", long_options, &option_index);
139
140                         if (-1 == c)
141                                 break;
142
143                         switch (c) {
144                         case 'v':
145                                 filters.push_back(printRow);
146                                 break;
147                         case 's':
148                                 uid1 = stoi(optarg);
149                                 break;
150                         case 't':
151                                 uid2 = stoi(optarg);
152                                 break;
153                         case 'p':
154                                 password1 = optarg;
155                                 break;
156                         case 'r':
157                                 password2 = optarg;
158                                 break;
159                         case 'o':
160                                 owner = optarg; // I cannot pass optarg to lambda because it's pointer
161                                 filters.push_back([=](DB::Row &row) {row.owner = owner; return true;});
162                                 break;
163                         case 'h':
164                                 printUsage();
165                                 return 0;
166                         case '?':
167                         case ':':
168                         default:
169                                 printUsage();
170                                 return 1;
171                         }
172                 }
173
174                 if (uid1 == uid2) {
175                         cerr << "Source database and target database must be different!" << endl;
176                         return 1;
177                 }
178
179                 return mergeDatabase(uid1, password1, uid2, password2, filters);
180         } catch (const CKM::DB::SqlConnection::Exception::InvalidColumn &e) {
181                 cerr << "Invalid Column exception was catched. Probably migration failed. " << e.DumpToString() << endl;
182         } catch (const invalid_argument &e) {
183                 cerr << "Argument could not be converted" << endl;
184         } catch (const out_of_range &e) {
185                 cerr << "Out of range" << endl;
186         } catch (const exception &e) {
187                 cerr << "Unexpected error: " << e.what() << endl;
188         } catch (...) {
189                 cerr << "Unknown exception" << endl;
190         }
191
192         return 1;
193 }