secrets: fix replacemend random seed generator (security issue).
[ira/wip.git] / source3 / lib / dbwrap_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Utility functions for the dbwrap API
4    Copyright (C) Volker Lendecke 2007
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
24 {
25         TDB_DATA dbuf;
26         int32 ret;
27
28         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
29                 return -1;
30         }
31
32         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
33                 TALLOC_FREE(dbuf.dptr);
34                 return -1;
35         }
36
37         ret = IVAL(dbuf.dptr, 0);
38         TALLOC_FREE(dbuf.dptr);
39         return ret;
40 }
41
42 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
43 {
44         struct db_record *rec;
45         int32 v_store;
46         NTSTATUS status;
47
48         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
49         if (rec == NULL) {
50                 return -1;
51         }
52
53         SIVAL(&v_store, 0, v);
54
55         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
56                                                sizeof(v_store)),
57                             TDB_REPLACE);
58         TALLOC_FREE(rec);
59         return NT_STATUS_IS_OK(status) ? 0 : -1;
60 }
61
62 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
63                          uint32_t *val)
64 {
65         TDB_DATA dbuf;
66
67         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
68                 return false;
69         }
70
71         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
72                 TALLOC_FREE(dbuf.dptr);
73                 return false;
74         }
75
76         *val = IVAL(dbuf.dptr, 0);
77         TALLOC_FREE(dbuf.dptr);
78         return true;
79 }
80
81 bool dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
82 {
83         struct db_record *rec;
84         uint32 v_store;
85         NTSTATUS status;
86
87         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
88         if (rec == NULL) {
89                 return false;
90         }
91
92         SIVAL(&v_store, 0, v);
93
94         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
95                                                sizeof(v_store)),
96                             TDB_REPLACE);
97         TALLOC_FREE(rec);
98         return NT_STATUS_IS_OK(status) ? 0 : -1;
99 }
100
101 /**
102  * Atomic unsigned integer change (addition):
103  *
104  * if value does not exist yet in the db, use *oldval as initial old value.
105  * return old value in *oldval.
106  * store *oldval + change_val to db.
107  */
108 uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
109                                      uint32_t *oldval, uint32_t change_val)
110 {
111         struct db_record *rec;
112         uint32 val = -1;
113         TDB_DATA data;
114
115         if (!(rec = db->fetch_locked(db, NULL,
116                                      string_term_tdb_data(keystr)))) {
117                 return -1;
118         }
119
120         if (rec->value.dptr == NULL) {
121                 val = *oldval;
122         } else if (rec->value.dsize == sizeof(val)) {
123                 val = IVAL(rec->value.dptr, 0);
124                 *oldval = val;
125         } else {
126                 return -1;
127         }
128
129         val += change_val;
130
131         data.dsize = sizeof(val);
132         data.dptr = (uint8 *)&val;
133
134         rec->store(rec, data, TDB_REPLACE);
135
136         TALLOC_FREE(rec);
137
138         return 0;
139 }
140
141 int32 dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
142                                  int32 *oldval, int32 change_val)
143 {
144         struct db_record *rec;
145         int32 val = -1;
146         TDB_DATA data;
147
148         if (!(rec = db->fetch_locked(db, NULL,
149                                      string_term_tdb_data(keystr)))) {
150                 return -1;
151         }
152
153         if (rec->value.dptr == NULL) {
154                 val = *oldval;
155         } else if (rec->value.dsize == sizeof(val)) {
156                 val = IVAL(rec->value.dptr, 0);
157                 *oldval = val;
158         } else {
159                 return -1;
160         }
161
162         val += change_val;
163
164         data.dsize = sizeof(val);
165         data.dptr = (uint8 *)&val;
166
167         rec->store(rec, data, TDB_REPLACE);
168
169         TALLOC_FREE(rec);
170
171         return 0;
172 }
173
174 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
175                             int flag)
176 {
177         int res;
178         struct db_record *rec = NULL;
179         NTSTATUS status;
180
181         res = db->transaction_start(db);
182         if (res != 0) {
183                 DEBUG(5, ("transaction_start failed\n"));
184                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
185         }
186
187         rec = db->fetch_locked(db, talloc_tos(), key);
188         if (rec == NULL) {
189                 DEBUG(5, ("fetch_locked failed\n"));
190                 status = NT_STATUS_NO_MEMORY;
191                 goto cancel;
192         }
193
194         status = rec->store(rec, dbuf, flag);
195         if (!NT_STATUS_IS_OK(status)) {
196                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
197                 goto cancel;
198         }
199
200         TALLOC_FREE(rec);
201
202         res = db->transaction_commit(db);
203         if (res != 0) {
204                 DEBUG(5, ("tdb_transaction_commit failed\n"));
205                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
206                 goto cancel;
207         }
208
209         return NT_STATUS_OK;
210
211  cancel:
212         TALLOC_FREE(rec);
213
214         if (db->transaction_cancel(db) != 0) {
215                 smb_panic("Cancelling transaction failed");
216         }
217         return status;
218 }
219
220 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
221 {
222         int res;
223         struct db_record *rec = NULL;
224         NTSTATUS status;
225
226         res = db->transaction_start(db);
227         if (res != 0) {
228                 DEBUG(5, ("transaction_start failed\n"));
229                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
230         }
231
232         rec = db->fetch_locked(db, talloc_tos(), key);
233         if (rec == NULL) {
234                 DEBUG(5, ("fetch_locked failed\n"));
235                 status = NT_STATUS_NO_MEMORY;
236                 goto cancel;
237         }
238
239         status = rec->delete_rec(rec);
240         if (!NT_STATUS_IS_OK(status)) {
241                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
242                 goto cancel;
243         }
244
245         TALLOC_FREE(rec);
246
247         res = db->transaction_commit(db);
248         if (res != 0) {
249                 DEBUG(5, ("tdb_transaction_commit failed\n"));
250                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
251                 goto cancel;
252         }
253
254         return NT_STATUS_OK;
255
256  cancel:
257         TALLOC_FREE(rec);
258
259         if (db->transaction_cancel(db) != 0) {
260                 smb_panic("Cancelling transaction failed");
261         }
262         return status;
263 }
264
265 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
266                                   int32_t v)
267 {
268         int32 v_store;
269
270         SIVAL(&v_store, 0, v);
271
272         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
273                                   make_tdb_data((const uint8 *)&v_store,
274                                                 sizeof(v_store)),
275                                   TDB_REPLACE);
276 }
277
278 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
279                                    uint32_t v)
280 {
281         uint32 v_store;
282
283         SIVAL(&v_store, 0, v);
284
285         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
286                                   make_tdb_data((const uint8 *)&v_store,
287                                                 sizeof(v_store)),
288                                   TDB_REPLACE);
289 }
290
291 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
292                                      TDB_DATA data, int flags)
293 {
294         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
295 }
296
297 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
298 {
299         return dbwrap_trans_delete(db, string_term_tdb_data(key));
300 }