Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/printing/printer_list.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Share Database of available printers.
4
   Copyright (C) Simo Sorce 2010
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 3 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, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "system/filesys.h"
22
#include "dbwrap/dbwrap.h"
23
#include "dbwrap/dbwrap_open.h"
24
#include "util_tdb.h"
25
#include "printer_list.h"
26
27
0
#define PL_KEY_PREFIX "PRINTERLIST/PRN/"
28
0
#define PL_KEY_FORMAT PL_KEY_PREFIX"%s"
29
0
#define PL_TIMESTAMP_KEY "PRINTERLIST/GLOBAL/LAST_REFRESH"
30
0
#define PL_DATA_FORMAT "ddPPP"
31
0
#define PL_TSTAMP_FORMAT "dd"
32
33
static struct db_context *printerlist_db;
34
35
static struct db_context *get_printer_list_db(void)
36
0
{
37
0
  char *db_path;
38
39
0
  if (printerlist_db != NULL) {
40
0
    return printerlist_db;
41
0
  }
42
43
0
  db_path = lock_path(talloc_tos(), "printer_list.tdb");
44
0
  if (db_path == NULL) {
45
0
    return NULL;
46
0
  }
47
48
0
  printerlist_db = db_open(NULL,
49
0
         db_path,
50
0
         0,
51
0
         TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
52
0
         O_RDWR|O_CREAT,
53
0
         0644,
54
0
         DBWRAP_LOCK_ORDER_1,
55
0
         DBWRAP_FLAG_NONE);
56
0
  TALLOC_FREE(db_path);
57
0
  if (printerlist_db == NULL) {
58
0
    DBG_ERR("Failed to open printer_list.tdb\n");
59
0
  }
60
0
  return printerlist_db;
61
0
}
62
63
NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx,
64
          const char *name,
65
          const char **comment,
66
          const char **location,
67
          time_t *last_refresh)
68
0
{
69
0
  struct db_context *db;
70
0
  char *key;
71
0
  TDB_DATA data;
72
0
  uint32_t time_h, time_l;
73
0
  char *nstr = NULL;
74
0
  char *cstr = NULL;
75
0
  char *lstr = NULL;
76
0
  NTSTATUS status;
77
0
  int ret;
78
79
0
  db = get_printer_list_db();
80
0
  if (db == NULL) {
81
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
82
0
  }
83
84
0
  key = talloc_asprintf(mem_ctx, PL_KEY_FORMAT, name);
85
0
  if (!key) {
86
0
    DEBUG(0, ("Failed to allocate key name!\n"));
87
0
    return NT_STATUS_NO_MEMORY;
88
0
  }
89
90
0
  status = dbwrap_fetch_bystring_upper(db, key, key, &data);
91
0
  if (!NT_STATUS_IS_OK(status)) {
92
0
    DEBUG(6, ("Failed to fetch record! "
93
0
        "The printer database is empty?\n"));
94
0
    goto done;
95
0
  }
96
97
0
  ret = tdb_unpack(data.dptr, data.dsize,
98
0
       PL_DATA_FORMAT,
99
0
       &time_h, &time_l, &nstr, &cstr, &lstr);
100
0
  if (ret == -1) {
101
0
    DEBUG(1, ("Failed to unpack printer data\n"));
102
0
    status = NT_STATUS_INTERNAL_DB_CORRUPTION;
103
0
    goto done;
104
0
  }
105
106
0
  if (last_refresh) {
107
0
    *last_refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
108
0
  }
109
110
0
  if (comment) {
111
0
    *comment = talloc_strdup(mem_ctx, cstr);
112
0
    if (!*comment) {
113
0
      DEBUG(1, ("Failed to strdup comment!\n"));
114
0
      status = NT_STATUS_NO_MEMORY;
115
0
      goto done;
116
0
    }
117
0
  }
118
119
0
  if (location) {
120
0
    *location = talloc_strdup(mem_ctx, lstr);
121
0
    if (*location == NULL) {
122
0
      DEBUG(1, ("Failed to strdup location!\n"));
123
0
      status = NT_STATUS_NO_MEMORY;
124
0
      goto done;
125
0
    }
126
0
  }
127
128
0
  status = NT_STATUS_OK;
129
130
0
done:
131
0
  SAFE_FREE(nstr);
132
0
  SAFE_FREE(cstr);
133
0
  SAFE_FREE(lstr);
134
0
  TALLOC_FREE(key);
135
0
  return status;
136
0
}
137
138
bool printer_list_printername_exists(const char *name)
139
0
{
140
0
  struct db_context *db = get_printer_list_db();
141
0
  char *key = NULL;
142
0
  bool ok;
143
144
0
  if (db == NULL) {
145
0
    return false;
146
0
  }
147
148
0
  key = talloc_asprintf_strupper_m(
149
0
    talloc_tos(), PL_KEY_FORMAT, name);
150
0
  if (key == NULL) {
151
0
    return false;
152
0
  }
153
154
0
  ok = dbwrap_exists(db, string_term_tdb_data(key));
155
0
  TALLOC_FREE(key);
156
0
  return ok;
157
0
}
158
159
NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx,
160
          const char *name,
161
          const char *comment,
162
          const char *location,
163
          time_t last_refresh)
164
0
{
165
0
  struct db_context *db;
166
0
  char *key;
167
0
  TDB_DATA data;
168
0
  uint64_t time_64;
169
0
  uint32_t time_h, time_l;
170
0
  NTSTATUS status;
171
0
  int len;
172
173
0
  db = get_printer_list_db();
174
0
  if (db == NULL) {
175
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
176
0
  }
177
178
0
  key = talloc_asprintf(mem_ctx, PL_KEY_FORMAT, name);
179
0
  if (!key) {
180
0
    DEBUG(0, ("Failed to allocate key name!\n"));
181
0
    return NT_STATUS_NO_MEMORY;
182
0
  }
183
184
0
  if (comment == NULL) {
185
0
    comment = "";
186
0
  }
187
188
0
  if (location == NULL) {
189
0
    location = "";
190
0
  }
191
192
0
  time_64 = last_refresh;
193
0
  time_l = time_64 & 0xFFFFFFFFL;
194
0
  time_h = time_64 >> 32;
195
196
0
  len = tdb_pack(NULL, 0,
197
0
           PL_DATA_FORMAT,
198
0
           time_h,
199
0
           time_l,
200
0
           name,
201
0
           comment,
202
0
           location);
203
204
0
  data.dptr = talloc_array(key, uint8_t, len);
205
0
  if (!data.dptr) {
206
0
    DEBUG(0, ("Failed to allocate tdb data buffer!\n"));
207
0
    status = NT_STATUS_NO_MEMORY;
208
0
    goto done;
209
0
  }
210
0
  data.dsize = len;
211
212
0
  len = tdb_pack(data.dptr, data.dsize,
213
0
           PL_DATA_FORMAT,
214
0
           time_h,
215
0
           time_l,
216
0
           name,
217
0
           comment,
218
0
           location);
219
220
0
  status = dbwrap_store_bystring_upper(db, key, data, TDB_REPLACE);
221
222
0
done:
223
0
  TALLOC_FREE(key);
224
0
  return status;
225
0
}
226
227
NTSTATUS printer_list_get_last_refresh(time_t *last_refresh)
228
0
{
229
0
  struct db_context *db;
230
0
  TDB_DATA data;
231
0
  uint32_t time_h, time_l;
232
0
  NTSTATUS status;
233
0
  int ret;
234
235
0
  db = get_printer_list_db();
236
0
  if (db == NULL) {
237
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
238
0
  }
239
240
0
  ZERO_STRUCT(data);
241
242
0
  status = dbwrap_fetch_bystring(db, talloc_tos(), PL_TIMESTAMP_KEY, &data);
243
0
  if (!NT_STATUS_IS_OK(status)) {
244
0
    DEBUG(1, ("Failed to fetch record!\n"));
245
0
    goto done;
246
0
  }
247
248
0
  ret = tdb_unpack(data.dptr, data.dsize,
249
0
       PL_TSTAMP_FORMAT, &time_h, &time_l);
250
0
  TALLOC_FREE(data.dptr);
251
0
  if (ret == -1) {
252
0
    DEBUG(1, ("Failed to unpack printer data\n"));
253
0
    status = NT_STATUS_INTERNAL_DB_CORRUPTION;
254
0
    goto done;
255
0
  }
256
257
0
  *last_refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
258
0
  status = NT_STATUS_OK;
259
260
0
done:
261
0
  return status;
262
0
}
263
264
NTSTATUS printer_list_mark_reload(void)
265
0
{
266
0
  struct db_context *db;
267
0
  TDB_DATA data;
268
0
  uint32_t time_h, time_l;
269
0
  time_t now = time_mono(NULL);
270
0
  NTSTATUS status;
271
0
  int len;
272
273
0
  db = get_printer_list_db();
274
0
  if (db == NULL) {
275
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
276
0
  }
277
278
0
  time_l = ((uint64_t)now) & 0xFFFFFFFFL;
279
0
  time_h = ((uint64_t)now) >> 32;
280
281
0
  len = tdb_pack(NULL, 0, PL_TSTAMP_FORMAT, time_h, time_l);
282
283
0
  data.dptr = talloc_array(talloc_tos(), uint8_t, len);
284
0
  if (!data.dptr) {
285
0
    DEBUG(0, ("Failed to allocate tdb data buffer!\n"));
286
0
    status = NT_STATUS_NO_MEMORY;
287
0
    goto done;
288
0
  }
289
0
  data.dsize = len;
290
291
0
  len = tdb_pack(data.dptr, data.dsize,
292
0
           PL_TSTAMP_FORMAT, time_h, time_l);
293
294
0
  status = dbwrap_store_bystring(db, PL_TIMESTAMP_KEY,
295
0
            data, TDB_REPLACE);
296
297
0
done:
298
0
  TALLOC_FREE(data.dptr);
299
0
  return status;
300
0
}
301
302
typedef int (printer_list_trv_fn_t)(struct db_record *, void *);
303
304
static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn,
305
              void *private_data,
306
              bool read_only)
307
0
{
308
0
  struct db_context *db;
309
0
  NTSTATUS status;
310
311
0
  db = get_printer_list_db();
312
0
  if (db == NULL) {
313
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
314
0
  }
315
316
0
  if (read_only) {
317
0
    status = dbwrap_traverse_read(db, fn, private_data, NULL);
318
0
  } else {
319
0
    status = dbwrap_traverse(db, fn, private_data, NULL);
320
0
  }
321
322
0
  return status;
323
0
}
324
325
struct printer_list_clean_state {
326
  time_t last_refresh;
327
  NTSTATUS status;
328
};
329
330
static int printer_list_clean_fn(struct db_record *rec, void *private_data)
331
0
{
332
0
  struct printer_list_clean_state *state =
333
0
      (struct printer_list_clean_state *)private_data;
334
0
  uint32_t time_h, time_l;
335
0
  time_t refresh;
336
0
  char *name;
337
0
  char *comment;
338
0
  char *location;
339
0
  int ret;
340
0
  TDB_DATA key;
341
0
  TDB_DATA value;
342
343
0
  key = dbwrap_record_get_key(rec);
344
345
  /* skip anything that does not contain PL_DATA_FORMAT data */
346
0
  if (strncmp((char *)key.dptr,
347
0
        PL_KEY_PREFIX, sizeof(PL_KEY_PREFIX)-1)) {
348
0
    return 0;
349
0
  }
350
351
0
  value = dbwrap_record_get_value(rec);
352
353
0
  ret = tdb_unpack(value.dptr, value.dsize,
354
0
       PL_DATA_FORMAT, &time_h, &time_l, &name, &comment,
355
0
       &location);
356
0
  if (ret == -1) {
357
0
    DEBUG(1, ("Failed to unpack printer data\n"));
358
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
359
0
    return -1;
360
0
  }
361
362
0
  SAFE_FREE(name);
363
0
  SAFE_FREE(comment);
364
0
  SAFE_FREE(location);
365
366
0
  refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
367
368
0
  if (refresh < state->last_refresh) {
369
0
    state->status = dbwrap_record_delete(rec);
370
0
    if (!NT_STATUS_IS_OK(state->status)) {
371
0
      return -1;
372
0
    }
373
0
  }
374
375
0
  return 0;
376
0
}
377
378
NTSTATUS printer_list_clean_old(void)
379
0
{
380
0
  struct printer_list_clean_state state;
381
0
  NTSTATUS status;
382
383
0
  status = printer_list_get_last_refresh(&state.last_refresh);
384
0
  if (!NT_STATUS_IS_OK(status)) {
385
0
    return status;
386
0
  }
387
388
0
  state.status = NT_STATUS_OK;
389
390
0
  status = printer_list_traverse(printer_list_clean_fn, &state, false);
391
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
392
0
      !NT_STATUS_IS_OK(state.status)) {
393
0
    status = state.status;
394
0
  }
395
396
0
  return status;
397
0
}
398
399
struct printer_list_exec_state {
400
  void (*fn)(const char *, const char *, const char *, void *);
401
  void *private_data;
402
  NTSTATUS status;
403
};
404
405
static int printer_list_exec_fn(struct db_record *rec, void *private_data)
406
0
{
407
0
  struct printer_list_exec_state *state =
408
0
      (struct printer_list_exec_state *)private_data;
409
0
  uint32_t time_h, time_l;
410
0
  char *name;
411
0
  char *comment;
412
0
  char *location;
413
0
  int ret;
414
0
  TDB_DATA key;
415
0
  TDB_DATA value;
416
417
0
  key = dbwrap_record_get_key(rec);
418
419
  /* always skip PL_TIMESTAMP_KEY key */
420
0
  if (strequal((const char *)key.dptr, PL_TIMESTAMP_KEY)) {
421
0
    return 0;
422
0
  }
423
424
0
  value = dbwrap_record_get_value(rec);
425
426
0
  ret = tdb_unpack(value.dptr, value.dsize,
427
0
       PL_DATA_FORMAT, &time_h, &time_l, &name, &comment,
428
0
       &location);
429
0
  if (ret == -1) {
430
0
    DEBUG(1, ("Failed to unpack printer data\n"));
431
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
432
0
    return -1;
433
0
  }
434
435
0
  state->fn(name, comment, location, state->private_data);
436
437
0
  SAFE_FREE(name);
438
0
  SAFE_FREE(comment);
439
0
  SAFE_FREE(location);
440
0
  return 0;
441
0
}
442
443
NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *),
444
          void *private_data)
445
0
{
446
0
  struct printer_list_exec_state state;
447
0
  NTSTATUS status;
448
449
0
  state.fn = fn;
450
0
  state.private_data = private_data;
451
0
  state.status = NT_STATUS_OK;
452
453
0
  status = printer_list_traverse(printer_list_exec_fn, &state, true);
454
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
455
0
      !NT_STATUS_IS_OK(state.status)) {
456
0
    status = state.status;
457
0
  }
458
459
0
  return status;
460
0
}