python/samba/tests/krb5: Add tests for password expiry with krb5 ENC-TS
[samba.git] / lib / dbwrap / dbwrap.c
1 /*
2    Unix SMB/CIFS implementation.
3    Database interface wrapper
4    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
5
6    Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "replace.h"
23 #include "lib/util/debug.h"
24 #include "lib/util/fault.h"
25 #include "lib/util/talloc_stack.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_private.h"
28 #include "lib/util/util_tdb.h"
29 #include "lib/util/tevent_ntstatus.h"
30
31 /*
32  * Fall back using fetch if no genuine exists operation is provided
33  */
34
35 static int dbwrap_fallback_exists(struct db_context *db, TDB_DATA key)
36 {
37         NTSTATUS status = dbwrap_parse_record(db, key, NULL, NULL);
38         return NT_STATUS_IS_OK(status) ? 1 : 0;
39 }
40
41 static int delete_record(struct db_record *rec, void *data)
42 {
43         NTSTATUS status = dbwrap_record_delete(rec);
44         return NT_STATUS_IS_OK(status) ? 0 : -1;
45 }
46
47 /*
48  * Fallback wipe implementation using traverse and delete if no genuine
49  * wipe operation is provided
50  */
51 static int dbwrap_fallback_wipe(struct db_context *db)
52 {
53         NTSTATUS status = dbwrap_trans_traverse(db, delete_record, NULL);
54         return NT_STATUS_IS_OK(status) ? 0 : -1;
55 }
56
57 static int do_nothing(struct db_record *rec, void *unused)
58 {
59         return 0;
60 }
61
62 /*
63  * Fallback check operation: just traverse.
64  */
65 static int dbwrap_fallback_check(struct db_context *db)
66 {
67         NTSTATUS status = dbwrap_traverse_read(db, do_nothing, NULL, NULL);
68         return NT_STATUS_IS_OK(status) ? 0 : -1;
69 }
70
71 /*
72  * Wrapper functions for the backend methods
73  */
74
75 TDB_DATA dbwrap_record_get_key(const struct db_record *rec)
76 {
77         return rec->key;
78 }
79
80 TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
81 {
82         SMB_ASSERT(rec->value_valid);
83         return rec->value;
84 }
85
86 NTSTATUS dbwrap_record_storev(struct db_record *rec,
87                               const TDB_DATA *dbufs, int num_dbufs, int flags)
88 {
89         NTSTATUS status;
90
91         /*
92          * Invalidate before rec->storev() is called, give
93          * rec->storev() the chance to re-validate rec->value.
94          */
95         rec->value_valid = false;
96
97         status = rec->storev(rec, dbufs, num_dbufs, flags);
98         if (!NT_STATUS_IS_OK(status)) {
99                 return status;
100         }
101         return NT_STATUS_OK;
102 }
103
104 NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
105 {
106         return dbwrap_record_storev(rec, &data, 1, flags);
107 }
108
109 NTSTATUS dbwrap_record_delete(struct db_record *rec)
110 {
111         NTSTATUS status;
112
113         status = rec->delete_rec(rec);
114         if (!NT_STATUS_IS_OK(status)) {
115                 return status;
116         }
117
118         rec->value = tdb_null;
119
120         return NT_STATUS_OK;
121 }
122
123 struct dbwrap_merge_dbs_state {
124         struct db_context *to;
125         int flags;
126 };
127
128 /* Copy a single record to the db_context passed in private_data */
129 static int dbwrap_merge_dbs_copy_record(struct db_record *rec,
130                                             void *private_data)
131 {
132         struct dbwrap_merge_dbs_state *state = private_data;
133
134         TDB_DATA data = dbwrap_record_get_value(rec);
135         TDB_DATA key = dbwrap_record_get_key(rec);
136         NTSTATUS status = dbwrap_store(state->to, key, data, state->flags);
137
138         return NT_STATUS_IS_OK(status) ? 0 : 1;
139 }
140
141 NTSTATUS
142 dbwrap_merge_dbs(struct db_context *to, struct db_context *from, int flags)
143 {
144         struct dbwrap_merge_dbs_state state = {.to = to, .flags = flags};
145
146         return dbwrap_traverse(from,
147                                dbwrap_merge_dbs_copy_record,
148                                &state,
149                                NULL);
150 }
151
152 const char *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
153
154 static void debug_lock_order(int level)
155 {
156         int i;
157         DEBUG(level, ("lock order:"));
158         for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) {
159                 DEBUGADD(level,
160                          (" %d:%s",
161                           i + 1,
162                           locked_dbs[i] ? locked_dbs[i] : "<none>"));
163         }
164         DEBUGADD(level, ("\n"));
165 }
166
167 void dbwrap_lock_order_lock(const char *db_name,
168                             enum dbwrap_lock_order lock_order)
169 {
170         int idx;
171
172         DBG_INFO("check lock order %d for %s\n",
173                  (int)lock_order,
174                  db_name);
175
176         if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
177                 DBG_ERR("Invalid lock order %d of %s\n",
178                         lock_order,
179                         db_name);
180                 smb_panic("lock order violation");
181         }
182
183         for (idx=lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) {
184                 if (locked_dbs[idx] != NULL) {
185                         DBG_ERR("Lock order violation: Trying %s at %d while "
186                                 "%s at %d is locked\n",
187                                 db_name,
188                                 (int)lock_order,
189                                 locked_dbs[idx],
190                                 idx + 1);
191                         debug_lock_order(0);
192                         smb_panic("lock order violation");
193                 }
194         }
195
196         locked_dbs[lock_order-1] = db_name;
197
198         debug_lock_order(10);
199 }
200
201 void dbwrap_lock_order_unlock(const char *db_name,
202                               enum dbwrap_lock_order lock_order)
203 {
204         DBG_INFO("release lock order %d for %s\n",
205                  (int)lock_order,
206                  db_name);
207
208         if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
209                 DBG_ERR("Invalid lock order %d of %s\n",
210                         lock_order,
211                         db_name);
212                 smb_panic("lock order violation");
213         }
214
215         if (locked_dbs[lock_order-1] == NULL) {
216                 DBG_ERR("db %s at order %d unlocked\n",
217                         db_name,
218                         (int)lock_order);
219                 smb_panic("lock order violation");
220         }
221
222         if (locked_dbs[lock_order-1] != db_name) {
223                 DBG_ERR("locked db at lock order %d is %s, expected %s\n",
224                         (int)lock_order,
225                         locked_dbs[lock_order-1],
226                         db_name);
227                 smb_panic("lock order violation");
228         }
229
230         locked_dbs[lock_order-1] = NULL;
231 }
232
233 struct dbwrap_lock_order_state {
234         struct db_context *db;
235 };
236
237 static int dbwrap_lock_order_state_destructor(
238         struct dbwrap_lock_order_state *s)
239 {
240         struct db_context *db = s->db;
241         dbwrap_lock_order_unlock(db->name, db->lock_order);
242         return 0;
243 }
244
245 static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
246         struct db_context *db, TALLOC_CTX *mem_ctx)
247 {
248         struct dbwrap_lock_order_state *state;
249
250         state = talloc(mem_ctx, struct dbwrap_lock_order_state);
251         if (state == NULL) {
252                 DBG_WARNING("talloc failed\n");
253                 return NULL;
254         }
255         state->db = db;
256
257         dbwrap_lock_order_lock(db->name, db->lock_order);
258         talloc_set_destructor(state, dbwrap_lock_order_state_destructor);
259
260         return state;
261 }
262
263 static struct db_record *dbwrap_fetch_locked_internal(
264         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key,
265         struct db_record *(*db_fn)(struct db_context *db, TALLOC_CTX *mem_ctx,
266                                    TDB_DATA key))
267 {
268         struct db_record *rec;
269         struct dbwrap_lock_order_state *lock_order = NULL;
270
271         if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
272                 lock_order = dbwrap_check_lock_order(db, mem_ctx);
273                 if (lock_order == NULL) {
274                         return NULL;
275                 }
276         }
277         rec = db_fn(db, mem_ctx, key);
278         if (rec == NULL) {
279                 TALLOC_FREE(lock_order);
280                 return NULL;
281         }
282         (void)talloc_steal(rec, lock_order);
283         rec->db = db;
284         return rec;
285 }
286
287 struct db_record *dbwrap_fetch_locked(struct db_context *db,
288                                       TALLOC_CTX *mem_ctx,
289                                       TDB_DATA key)
290 {
291         return dbwrap_fetch_locked_internal(db, mem_ctx, key,
292                                             db->fetch_locked);
293 }
294
295 struct db_context *dbwrap_record_get_db(struct db_record *rec)
296 {
297         return rec->db;
298 }
299
300 struct dbwrap_fetch_state {
301         TALLOC_CTX *mem_ctx;
302         TDB_DATA data;
303 };
304
305 static void dbwrap_fetch_parser(TDB_DATA key, TDB_DATA data,
306                                 void *private_data)
307 {
308         struct dbwrap_fetch_state *state =
309                 (struct dbwrap_fetch_state *)private_data;
310
311         state->data.dsize = data.dsize;
312         state->data.dptr = (uint8_t *)talloc_memdup(state->mem_ctx, data.dptr,
313                                                     data.dsize);
314 }
315
316 NTSTATUS dbwrap_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
317                       TDB_DATA key, TDB_DATA *value)
318 {
319         struct dbwrap_fetch_state state;
320         NTSTATUS status;
321
322         if (value == NULL) {
323                 return NT_STATUS_INVALID_PARAMETER;
324         }
325
326         state.mem_ctx = mem_ctx;
327
328         status = dbwrap_parse_record(db, key, dbwrap_fetch_parser, &state);
329         if (!NT_STATUS_IS_OK(status)) {
330                 return status;
331         }
332         if ((state.data.dsize != 0) && (state.data.dptr == NULL)) {
333                 return NT_STATUS_NO_MEMORY;
334         }
335         *value = state.data;
336         return NT_STATUS_OK;
337 }
338
339 bool dbwrap_exists(struct db_context *db, TDB_DATA key)
340 {
341         int result;
342         if (db->exists != NULL) {
343                 result = db->exists(db, key);
344         } else {
345                 result = dbwrap_fallback_exists(db,key);
346         }
347         return (result == 1);
348 }
349
350 struct dbwrap_store_state {
351         TDB_DATA data;
352         int flags;
353         NTSTATUS status;
354 };
355
356 static void dbwrap_store_fn(
357         struct db_record *rec,
358         TDB_DATA value,
359         void *private_data)
360 {
361         struct dbwrap_store_state *state = private_data;
362         state->status = dbwrap_record_store(rec, state->data, state->flags);
363 }
364
365 NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
366                       TDB_DATA data, int flags)
367 {
368         struct dbwrap_store_state state = { .data = data, .flags = flags };
369         NTSTATUS status;
370
371         status = dbwrap_do_locked(db, key, dbwrap_store_fn, &state);
372         if (!NT_STATUS_IS_OK(status)) {
373                 return status;
374         }
375
376         return state.status;
377 }
378
379 struct dbwrap_delete_state {
380         NTSTATUS status;
381 };
382
383 static void dbwrap_delete_fn(
384         struct db_record *rec,
385         TDB_DATA value,
386         void *private_data)
387 {
388         struct dbwrap_delete_state *state = private_data;
389         state->status = dbwrap_record_delete(rec);
390 }
391
392 NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key)
393 {
394         struct dbwrap_delete_state state = { .status = NT_STATUS_NOT_FOUND };
395         NTSTATUS status;
396
397         status = dbwrap_do_locked(db, key, dbwrap_delete_fn, &state);
398         if (!NT_STATUS_IS_OK(status)) {
399                 return status;
400         }
401
402         return state.status;
403 }
404
405 NTSTATUS dbwrap_traverse(struct db_context *db,
406                          int (*f)(struct db_record*, void*),
407                          void *private_data,
408                          int *count)
409 {
410         int ret = db->traverse(db, f, private_data);
411
412         if (ret < 0) {
413                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
414         }
415
416         if (count != NULL) {
417                 *count = ret;
418         }
419
420         return NT_STATUS_OK;
421 }
422
423 NTSTATUS dbwrap_traverse_read(struct db_context *db,
424                               int (*f)(struct db_record*, void*),
425                               void *private_data,
426                               int *count)
427 {
428         int ret = db->traverse_read(db, f, private_data);
429
430         if (ret < 0) {
431                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
432         }
433
434         if (count != NULL) {
435                 *count = ret;
436         }
437
438         return NT_STATUS_OK;
439 }
440
441 static void dbwrap_null_parser(TDB_DATA key, TDB_DATA val, void* data)
442 {
443         return;
444 }
445
446 NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
447                              void (*parser)(TDB_DATA key, TDB_DATA data,
448                                             void *private_data),
449                              void *private_data)
450 {
451         if (parser == NULL) {
452                 parser = dbwrap_null_parser;
453         }
454         return db->parse_record(db, key, parser, private_data);
455 }
456
457 struct dbwrap_parse_record_state {
458         struct db_context *db;
459         TDB_DATA key;
460         uint8_t _keybuf[64];
461 };
462
463 static void dbwrap_parse_record_done(struct tevent_req *subreq);
464
465 struct tevent_req *dbwrap_parse_record_send(
466         TALLOC_CTX *mem_ctx,
467         struct tevent_context *ev,
468         struct db_context *db,
469         TDB_DATA key,
470         void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
471         void *private_data,
472         enum dbwrap_req_state *req_state)
473 {
474         struct tevent_req *req = NULL;
475         struct tevent_req *subreq = NULL;
476         struct dbwrap_parse_record_state *state = NULL;
477         NTSTATUS status;
478
479         req = tevent_req_create(mem_ctx, &state, struct dbwrap_parse_record_state);
480         if (req == NULL) {
481                 *req_state = DBWRAP_REQ_ERROR;
482                 return NULL;
483         }
484
485         *state = (struct dbwrap_parse_record_state) {
486                 .db = db,
487         };
488
489         if (parser == NULL) {
490                 parser = dbwrap_null_parser;
491         }
492
493         *req_state = DBWRAP_REQ_INIT;
494
495         if (db->parse_record_send == NULL) {
496                 /*
497                  * Backend doesn't implement async version, call sync one
498                  */
499                 status = db->parse_record(db, key, parser, private_data);
500                 if (tevent_req_nterror(req, status)) {
501                         *req_state = DBWRAP_REQ_DONE;
502                         return tevent_req_post(req, ev);
503                 }
504
505                 *req_state = DBWRAP_REQ_DONE;
506                 tevent_req_done(req);
507                 return tevent_req_post(req, ev);
508         }
509
510         /*
511          * Copy the key into our state ensuring the key data buffer is always
512          * available to all the dbwrap backends over the entire lifetime of the
513          * async request. Otherwise the caller might have free'd the key buffer.
514          */
515         if (key.dsize > sizeof(state->_keybuf)) {
516                 state->key.dptr = talloc_memdup(state, key.dptr, key.dsize);
517                 if (tevent_req_nomem(state->key.dptr, req)) {
518                         return tevent_req_post(req, ev);
519                 }
520         } else {
521                 memcpy(state->_keybuf, key.dptr, key.dsize);
522                 state->key.dptr = state->_keybuf;
523         }
524         state->key.dsize = key.dsize;
525
526         subreq = db->parse_record_send(state,
527                                        ev,
528                                        db,
529                                        state->key,
530                                        parser,
531                                        private_data,
532                                        req_state);
533         if (tevent_req_nomem(subreq, req)) {
534                 *req_state = DBWRAP_REQ_ERROR;
535                 return tevent_req_post(req, ev);
536         }
537
538         tevent_req_set_callback(subreq,
539                                 dbwrap_parse_record_done,
540                                 req);
541         return req;
542 }
543
544 static void dbwrap_parse_record_done(struct tevent_req *subreq)
545 {
546         struct tevent_req *req = tevent_req_callback_data(
547                 subreq, struct tevent_req);
548         struct dbwrap_parse_record_state *state = tevent_req_data(
549                 req, struct dbwrap_parse_record_state);
550         NTSTATUS status;
551
552         status = state->db->parse_record_recv(subreq);
553         TALLOC_FREE(subreq);
554         if (!NT_STATUS_IS_OK(status)) {
555                 tevent_req_nterror(req, status);
556                 return;
557         }
558
559         tevent_req_done(req);
560 }
561
562 NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
563 {
564         return tevent_req_simple_recv_ntstatus(req);
565 }
566
567 NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
568                           void (*fn)(struct db_record *rec,
569                                      TDB_DATA value,
570                                      void *private_data),
571                           void *private_data)
572 {
573         struct db_record *rec;
574
575         if (db->do_locked != NULL) {
576                 NTSTATUS status;
577
578                 if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
579                         dbwrap_lock_order_lock(db->name, db->lock_order);
580                 }
581
582                 status = db->do_locked(db, key, fn, private_data);
583
584                 if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
585                         dbwrap_lock_order_unlock(db->name, db->lock_order);
586                 }
587
588                 return status;
589         }
590
591         rec = dbwrap_fetch_locked(db, db, key);
592         if (rec == NULL) {
593                 return NT_STATUS_NO_MEMORY;
594         }
595
596         /*
597          * Invalidate rec->value, nobody shall assume it's set from
598          * within dbwrap_do_locked().
599          */
600         rec->value_valid = false;
601
602         fn(rec, rec->value, private_data);
603
604         TALLOC_FREE(rec);
605
606         return NT_STATUS_OK;
607 }
608
609 int dbwrap_wipe(struct db_context *db)
610 {
611         if (db->wipe == NULL) {
612                 return dbwrap_fallback_wipe(db);
613         }
614         return db->wipe(db);
615 }
616
617 int dbwrap_check(struct db_context *db)
618 {
619         if (db->check == NULL) {
620                 return dbwrap_fallback_check(db);
621         }
622         return db->check(db);
623 }
624
625 int dbwrap_get_seqnum(struct db_context *db)
626 {
627         return db->get_seqnum(db);
628 }
629
630 int dbwrap_transaction_start(struct db_context *db)
631 {
632         if (!db->persistent) {
633                 /*
634                  * dbwrap_ctdb has two different data models for persistent
635                  * and non-persistent databases. Transactions are supported
636                  * only for the persistent databases. This check is here to
637                  * prevent breakages of the cluster case, autobuild at this
638                  * point only tests non-clustered Samba. Before removing this
639                  * check, please make sure that this facility has also been
640                  * added to dbwrap_ctdb.
641                  *
642                  * Thanks, vl
643                  */
644                 DEBUG(1, ("transactions not supported on non-persistent "
645                           "database %s\n", db->name));
646                 return -1;
647         }
648         return db->transaction_start(db);
649 }
650
651 NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db)
652 {
653         if (db->transaction_start_nonblock) {
654                 return db->transaction_start_nonblock(db);
655         } else {
656                 return dbwrap_transaction_start(db) == 0 ? NT_STATUS_OK
657                         : NT_STATUS_UNSUCCESSFUL;
658         }
659 }
660
661 int dbwrap_transaction_commit(struct db_context *db)
662 {
663         return db->transaction_commit(db);
664 }
665
666 int dbwrap_transaction_cancel(struct db_context *db)
667 {
668         return db->transaction_cancel(db);
669 }
670
671 size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
672 {
673         return db->id(db, id, idlen);
674 }
675
676 bool dbwrap_is_persistent(struct db_context *db)
677 {
678         return db->persistent;
679 }
680
681 const char *dbwrap_name(struct db_context *db)
682 {
683         return db->name;
684 }
685
686 static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
687                             uint8_t *buf, size_t buflen)
688 {
689         size_t needed = 0;
690         uint8_t *p = buf;
691         int i;
692
693         for (i=0; i<num_dbufs; i++) {
694                 size_t thislen = dbufs[i].dsize;
695
696                 needed += thislen;
697                 if (needed < thislen) {
698                         /* wrap */
699                         return -1;
700                 }
701
702                 if (p != NULL && (thislen != 0) && (needed <= buflen)) {
703                         memcpy(p, dbufs[i].dptr, thislen);
704                         p += thislen;
705                 }
706         }
707
708         return needed;
709 }
710
711
712 NTSTATUS dbwrap_merge_dbufs(TDB_DATA *buf, TALLOC_CTX *mem_ctx,
713                             const TDB_DATA *dbufs, int num_dbufs)
714 {
715         ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
716
717         if (len == -1) {
718                 return NT_STATUS_INVALID_PARAMETER;
719         }
720
721         if (buf->dsize != len) {
722                 uint8_t *tmp;
723
724                 tmp = talloc_realloc(mem_ctx, buf->dptr, uint8_t, len);
725                 if (tmp == NULL && len != 0) {
726                         return NT_STATUS_NO_MEMORY;
727                 }
728
729                 buf->dptr = tmp;
730                 buf->dsize = len;
731         }
732
733         tdb_data_buf(dbufs, num_dbufs, buf->dptr, buf->dsize);
734
735         return NT_STATUS_OK;
736 }