s3:passdb: fix a type Domain Users has RID -513
[amitay/samba.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    Copyright (C) Michael Adam 2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
25 {
26         TDB_DATA dbuf;
27         int32 ret;
28
29         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
30                 return -1;
31         }
32
33         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
34                 TALLOC_FREE(dbuf.dptr);
35                 return -1;
36         }
37
38         ret = IVAL(dbuf.dptr, 0);
39         TALLOC_FREE(dbuf.dptr);
40         return ret;
41 }
42
43 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
44 {
45         struct db_record *rec;
46         int32 v_store;
47         NTSTATUS status;
48
49         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
50         if (rec == NULL) {
51                 return -1;
52         }
53
54         SIVAL(&v_store, 0, v);
55
56         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
57                                                sizeof(v_store)),
58                             TDB_REPLACE);
59         TALLOC_FREE(rec);
60         return NT_STATUS_IS_OK(status) ? 0 : -1;
61 }
62
63 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
64                          uint32_t *val)
65 {
66         TDB_DATA dbuf;
67
68         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
69                 return false;
70         }
71
72         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
73                 TALLOC_FREE(dbuf.dptr);
74                 return false;
75         }
76
77         *val = IVAL(dbuf.dptr, 0);
78         TALLOC_FREE(dbuf.dptr);
79         return true;
80 }
81
82 int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
83 {
84         struct db_record *rec;
85         uint32 v_store;
86         NTSTATUS status;
87
88         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
89         if (rec == NULL) {
90                 return -1;
91         }
92
93         SIVAL(&v_store, 0, v);
94
95         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
96                                                sizeof(v_store)),
97                             TDB_REPLACE);
98         TALLOC_FREE(rec);
99         return NT_STATUS_IS_OK(status) ? 0 : -1;
100 }
101
102 /**
103  * Atomic unsigned integer change (addition):
104  *
105  * if value does not exist yet in the db, use *oldval as initial old value.
106  * return old value in *oldval.
107  * store *oldval + change_val to db.
108  */
109
110 struct dbwrap_change_uint32_atomic_context {
111         const char *keystr;
112         uint32_t *oldval;
113         uint32_t change_val;
114 };
115
116 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
117                                                    void *private_data)
118 {
119         struct db_record *rec;
120         uint32 val = -1;
121         uint32_t v_store;
122         NTSTATUS ret;
123         struct dbwrap_change_uint32_atomic_context *state;
124
125         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
126
127         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
128         if (!rec) {
129                 return NT_STATUS_UNSUCCESSFUL;
130         }
131
132         if (rec->value.dptr == NULL) {
133                 val = *(state->oldval);
134         } else if (rec->value.dsize == sizeof(val)) {
135                 val = IVAL(rec->value.dptr, 0);
136                 *(state->oldval) = val;
137         } else {
138                 ret = NT_STATUS_UNSUCCESSFUL;
139                 goto done;
140         }
141
142         val += state->change_val;
143
144         SIVAL(&v_store, 0, val);
145
146         ret = rec->store(rec,
147                          make_tdb_data((const uint8 *)&v_store,
148                                        sizeof(v_store)),
149                          TDB_REPLACE);
150
151 done:
152         TALLOC_FREE(rec);
153         return ret;
154 }
155
156 NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
157                                      uint32_t *oldval, uint32_t change_val)
158 {
159         NTSTATUS ret;
160         struct dbwrap_change_uint32_atomic_context state;
161
162         state.keystr = keystr;
163         state.oldval = oldval;
164         state.change_val = change_val;
165
166         ret = dbwrap_change_uint32_atomic_action(db, &state);
167
168         return ret;
169 }
170
171 NTSTATUS dbwrap_trans_change_uint32_atomic(struct db_context *db,
172                                            const char *keystr,
173                                            uint32_t *oldval,
174                                            uint32_t change_val)
175 {
176         NTSTATUS ret;
177         struct dbwrap_change_uint32_atomic_context state;
178
179         state.keystr = keystr;
180         state.oldval = oldval;
181         state.change_val = change_val;
182
183         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
184
185         return ret;
186 }
187
188 /**
189  * Atomic integer change (addition):
190  *
191  * if value does not exist yet in the db, use *oldval as initial old value.
192  * return old value in *oldval.
193  * store *oldval + change_val to db.
194  */
195
196 struct dbwrap_change_int32_atomic_context {
197         const char *keystr;
198         int32_t *oldval;
199         int32_t change_val;
200 };
201
202 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
203                                                   void *private_data)
204 {
205         struct db_record *rec;
206         int32_t val = -1;
207         int32_t v_store;
208         NTSTATUS ret;
209         struct dbwrap_change_int32_atomic_context *state;
210
211         state = (struct dbwrap_change_int32_atomic_context *)private_data;
212
213         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
214         if (!rec) {
215                 return NT_STATUS_UNSUCCESSFUL;
216         }
217
218         if (rec->value.dptr == NULL) {
219                 val = *(state->oldval);
220         } else if (rec->value.dsize == sizeof(val)) {
221                 val = IVAL(rec->value.dptr, 0);
222                 *(state->oldval) = val;
223         } else {
224                 ret = NT_STATUS_UNSUCCESSFUL;
225                 goto done;
226         }
227
228         val += state->change_val;
229
230         SIVAL(&v_store, 0, val);
231
232         ret = rec->store(rec,
233                          make_tdb_data((const uint8_t *)&v_store,
234                                        sizeof(v_store)),
235                          TDB_REPLACE);
236
237 done:
238         TALLOC_FREE(rec);
239         return ret;
240 }
241
242 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
243                                     int32_t *oldval, int32_t change_val)
244 {
245         NTSTATUS ret;
246         struct dbwrap_change_int32_atomic_context state;
247
248         state.keystr = keystr;
249         state.oldval = oldval;
250         state.change_val = change_val;
251
252         ret = dbwrap_change_int32_atomic_action(db, &state);
253
254         return ret;
255 }
256
257 NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db,
258                                           const char *keystr,
259                                           int32_t *oldval,
260                                           int32_t change_val)
261 {
262         NTSTATUS ret;
263         struct dbwrap_change_int32_atomic_context state;
264
265         state.keystr = keystr;
266         state.oldval = oldval;
267         state.change_val = change_val;
268
269         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
270
271         return ret;
272 }
273
274 struct dbwrap_store_context {
275         TDB_DATA *key;
276         TDB_DATA *dbuf;
277         int flag;
278 };
279
280 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
281 {
282         struct db_record *rec = NULL;
283         NTSTATUS status;
284         struct dbwrap_store_context *store_ctx;
285
286         store_ctx = (struct dbwrap_store_context *)private_data;
287
288         rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
289         if (rec == NULL) {
290                 DEBUG(5, ("fetch_locked failed\n"));
291                 return NT_STATUS_NO_MEMORY;
292         }
293
294         status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
295         if (!NT_STATUS_IS_OK(status)) {
296                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
297         }
298
299         TALLOC_FREE(rec);
300         return status;
301 }
302
303 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
304                             int flag)
305 {
306         NTSTATUS status;
307         struct dbwrap_store_context store_ctx;
308
309         store_ctx.key = &key;
310         store_ctx.dbuf = &dbuf;
311         store_ctx.flag = flag;
312
313         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
314
315         return status;
316 }
317
318 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
319 {
320         NTSTATUS status;
321         struct db_record *rec;
322         TDB_DATA *key = (TDB_DATA *)private_data;
323
324         rec = db->fetch_locked(db, talloc_tos(), *key);
325         if (rec == NULL) {
326                 DEBUG(5, ("fetch_locked failed\n"));
327                 return NT_STATUS_NO_MEMORY;
328         }
329
330         status = rec->delete_rec(rec);
331         if (!NT_STATUS_IS_OK(status)) {
332                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
333         }
334
335         talloc_free(rec);
336         return  status;
337 }
338
339 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
340 {
341         NTSTATUS status;
342
343         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
344
345         return status;
346 }
347
348 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
349                                   int32_t v)
350 {
351         int32 v_store;
352
353         SIVAL(&v_store, 0, v);
354
355         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
356                                   make_tdb_data((const uint8 *)&v_store,
357                                                 sizeof(v_store)),
358                                   TDB_REPLACE);
359 }
360
361 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
362                                    uint32_t v)
363 {
364         uint32 v_store;
365
366         SIVAL(&v_store, 0, v);
367
368         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
369                                   make_tdb_data((const uint8 *)&v_store,
370                                                 sizeof(v_store)),
371                                   TDB_REPLACE);
372 }
373
374 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
375                                      TDB_DATA data, int flags)
376 {
377         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
378 }
379
380 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
381 {
382         return dbwrap_trans_delete(db, string_term_tdb_data(key));
383 }
384
385 /**
386  * Wrap db action(s) into a transaction.
387  */
388 NTSTATUS dbwrap_trans_do(struct db_context *db,
389                          NTSTATUS (*action)(struct db_context *, void *),
390                          void *private_data)
391 {
392         int res;
393         NTSTATUS status;
394
395         res = db->transaction_start(db);
396         if (res != 0) {
397                 DEBUG(5, ("transaction_start failed\n"));
398                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
399         }
400
401         status = action(db, private_data);
402         if (!NT_STATUS_IS_OK(status)) {
403                 if (db->transaction_cancel(db) != 0) {
404                         smb_panic("Cancelling transaction failed");
405                 }
406                 return status;
407         }
408
409         res = db->transaction_commit(db);
410         if (res == 0) {
411                 return NT_STATUS_OK;
412         }
413
414         DEBUG(2, ("transaction_commit failed\n"));
415         return NT_STATUS_INTERNAL_DB_CORRUPTION;
416 }
417
418 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
419 {
420         char *key_upper;
421         NTSTATUS status;
422
423         key_upper = talloc_strdup_upper(talloc_tos(), key);
424         if (key_upper == NULL) {
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         status = dbwrap_delete_bystring(db, key_upper);
429
430         talloc_free(key_upper);
431         return status;
432 }
433
434 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
435                                      TDB_DATA data, int flags)
436 {
437         char *key_upper;
438         NTSTATUS status;
439
440         key_upper = talloc_strdup_upper(talloc_tos(), key);
441         if (key_upper == NULL) {
442                 return NT_STATUS_NO_MEMORY;
443         }
444
445         status = dbwrap_store_bystring(db, key_upper, data, flags);
446
447         talloc_free(key_upper);
448         return status;
449 }
450
451 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
452                                      const char *key)
453 {
454         char *key_upper;
455         TDB_DATA result;
456
457         key_upper = talloc_strdup_upper(talloc_tos(), key);
458         if (key_upper == NULL) {
459                 return make_tdb_data(NULL, 0);
460         }
461
462         result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
463
464         talloc_free(key_upper);
465         return result;
466 }