Enable -Wshadow and fix warnings
[platform/core/security/key-manager.git] / misc / ckm_db_tool / ckm_db_merge.cpp
1 /*
2  *  Copyright (c) 2000 - 2020 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 #include "ui.h"
33
34 using namespace std;
35 using namespace CKM;
36
37 typedef function<bool(DB::Row &row)> RowFilter;
38 typedef vector<RowFilter> RowFilterVector;
39
40 bool printRow(const DB::Row &row) {
41         string iv(10, ' '), data(10, ' ');
42         for (std::size_t i=0; i < iv.size(); ++i) {
43                 if (row.iv.size() > i) iv[i] = row.iv[i];
44                 if (row.data.size() > i) data[i] = row.data[i];
45         }
46         cout << "Read row:";
47         cout << "\n   Name:                  " << row.name;
48         cout << "\n   Owner:                 " << row.owner;
49         cout << "\n   Exportable:            " << row.exportable;
50         cout << "\n   Alg type:              " << static_cast<int>(row.algorithmType);
51         cout << "\n   Enc schema:            " << row.encryptionScheme;
52         cout << "\n   Data size:             " << row.dataSize;
53         cout << "\n   BackendId:             " << static_cast<int>(row.backendId);
54         cout << "\n   Data(first 10 chars):  " << data;
55         cout << "\n   IV(first 10 chars):    " << iv;
56         cout << "\n";
57         return true;
58 }
59
60 void printUsage()
61 {
62         cout << "Usage: ckm_db_merge [OPTION]\n";
63         cout << "Copy data from one key-manager database into other one.\n";
64         cout << "Options:\n";
65         cout << "  -v, --verbose         print additional data on screen\n";
66         cout << "  -s, --source UID      database UID from were data will be readed - default value 0\n";
67         cout << "  -t, --target UID      database UID to were data will be writen - default value 0\n";
68         cout << "  -p, --spass PASSWORD  password for source database - default empty string\n";
69         cout << "  -r, --tpass PASSWORD  password for target database - default emtpy string\n";
70         cout << "  -o, --owner OWNER     change the owner of information in database to OWNER\n";
71         cout << "  -h, --help            print this help on screen\n";
72         cout << "Example: Copy data from db-5001 to db-0 (system database) and change object owner to /System\n";
73         cout << "  ckm_db_merge -s 5001 -t 0 -p !@#SDFCV -o \"/System\"\n";
74         cout << "Please note: This tool automatically updates databases to newest scheme!" << endl;
75 }
76
77 int mergeDatabase(
78         uid_t uid1,
79         const Password &pass1,
80         uid_t uid2,
81         const Password &pass2,
82         const RowFilterVector &filters)
83 {
84         DbWrapper source(uid1, pass1);
85         DbWrapper target(uid2, pass2);
86
87         int ret;
88
89         if (CKM_API_SUCCESS != (ret = source.unlock())) {  // this should migrate database to newest version
90                 UI::error() << "unlocking source database failed: " << APICodeToString(ret) << endl;
91                 return 1;
92         }
93         if (CKM_API_SUCCESS != (ret = target.unlock())) {  // this should migrate database to newest version
94                 UI::error() << "unlocking target database failed: " << APICodeToString(ret) << endl;
95                 return 1;
96         }
97
98         DB::RowVector data = source.getRows();
99
100         // apply all filters to each row
101         for (auto &e : data) {
102                 bool migrate = true;
103                 for (auto &f : filters) {
104                         migrate &= f(e);
105                 }
106                 if (migrate) {
107                         try {
108                                 target.saveRow(e);
109                         } catch (const CKM::DB::SqlConnection::Exception::Base &exc) {
110                                 UI::error()
111                                         << "sql exception, migration failed or object already exists in the database: "
112                                         << exc.DumpToString() << endl;
113                         }
114                 }
115         }
116
117         source.lock();
118         target.lock();
119         return 0;
120 }
121
122 int main(int argc, char *argv[]) {
123         Password password1, password2;
124         uid_t uid1 = 0, uid2 = 0;
125         string owner;
126         RowFilterVector filters;
127         try {
128                 while (1) {
129                         int option_index = 0;
130
131                         static struct option long_options[] = {
132                                 {"verbose", no_argument,       0, 'v'},
133                                 {"source",  required_argument, 0, 's'},
134                                 {"target",  required_argument, 0, 't'},
135                                 {"spass",   required_argument, 0, 'p'},
136                                 {"tpass",   required_argument, 0, 'r'},
137                                 {"owner",   required_argument, 0, 'o'},
138                                 {"help",    no_argument,       0, 'h'},
139                                 {0,         0,                 0, 0  }
140                         };
141                         int c = getopt_long(argc, argv, "vs:t:p:r:o:h", long_options, &option_index);
142
143                         if (-1 == c)
144                                 break;
145
146                         switch (c) {
147                         case 'v':
148                                 filters.push_back(printRow);
149                                 break;
150                         case 's':
151                                 uid1 = stoi(optarg);
152                                 break;
153                         case 't':
154                                 uid2 = stoi(optarg);
155                                 break;
156                         case 'p':
157                                 password1 = optarg;
158                                 break;
159                         case 'r':
160                                 password2 = optarg;
161                                 break;
162                         case 'o':
163                                 owner = optarg; // I cannot pass optarg to lambda because it's pointer
164                                 filters.push_back([=](DB::Row &row) {row.owner = owner; return true;});
165                                 break;
166                         case 'h':
167                                 printUsage();
168                                 return 0;
169                         case '?':
170                         case ':':
171                         default:
172                                 printUsage();
173                                 return 1;
174                         }
175                 }
176
177                 if (uid1 == uid2) {
178                         UI::error() << "source and target databases must be different" << endl;
179                         return 1;
180                 }
181
182                 return mergeDatabase(uid1, password1, uid2, password2, filters);
183         } catch (const CKM::DB::SqlConnection::Exception::InvalidColumn &e) {
184                 UI::error() << "invalid column exception, probably a failed migration: " << e.DumpToString()
185                         << endl;
186         } catch (const invalid_argument &e) {
187                 UI::error() << "argument could not be converted: " << e.what() << endl;
188         } catch (const out_of_range &e) {
189                 UI::error() << "argument out of range: " << e.what() << endl;
190         } catch (const exception &e) {
191                 UI::error() << "unexpected exception: " << e.what() << endl;
192         } catch (...) {
193                 UI::error() << "unknown exception" << endl;
194         }
195
196         return 1;
197 }