PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/source3/printing/printer_list.c

https://gitlab.com/miztake/samba
C | 471 lines | 365 code | 81 blank | 25 comment | 53 complexity | 7e9560a44f21ade8b7a76f1c73355559 MD5 | raw file
  1. /*
  2. Unix SMB/CIFS implementation.
  3. Share Database of available printers.
  4. Copyright (C) Simo Sorce 2010
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "includes.h"
  17. #include "system/filesys.h"
  18. #include "dbwrap/dbwrap.h"
  19. #include "dbwrap/dbwrap_open.h"
  20. #include "util_tdb.h"
  21. #include "printer_list.h"
  22. #define PL_KEY_PREFIX "PRINTERLIST/PRN/"
  23. #define PL_KEY_FORMAT PL_KEY_PREFIX"%s"
  24. #define PL_TIMESTAMP_KEY "PRINTERLIST/GLOBAL/LAST_REFRESH"
  25. #define PL_DATA_FORMAT "ddPPP"
  26. #define PL_TSTAMP_FORMAT "dd"
  27. static struct db_context *get_printer_list_db(void)
  28. {
  29. static struct db_context *db;
  30. char *db_path;
  31. if (db != NULL) {
  32. return db;
  33. }
  34. db_path = lock_path(talloc_tos(), "printer_list.tdb");
  35. if (db_path == NULL) {
  36. return NULL;
  37. }
  38. db = db_open(NULL, db_path, 0,
  39. TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
  40. O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_1,
  41. DBWRAP_FLAG_NONE);
  42. TALLOC_FREE(db_path);
  43. return db;
  44. }
  45. bool printer_list_parent_init(void)
  46. {
  47. struct db_context *db;
  48. /*
  49. * Open the tdb in the parent process (smbd) so that our
  50. * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
  51. * work.
  52. */
  53. db = get_printer_list_db();
  54. if (db == NULL) {
  55. DEBUG(1, ("could not open Printer List Database: %s\n",
  56. strerror(errno)));
  57. return false;
  58. }
  59. return true;
  60. }
  61. NTSTATUS printer_list_get_printer(TALLOC_CTX *mem_ctx,
  62. const char *name,
  63. const char **comment,
  64. const char **location,
  65. time_t *last_refresh)
  66. {
  67. struct db_context *db;
  68. char *key;
  69. TDB_DATA data;
  70. uint32_t time_h, time_l;
  71. char *nstr = NULL;
  72. char *cstr = NULL;
  73. char *lstr = NULL;
  74. NTSTATUS status;
  75. int ret;
  76. db = get_printer_list_db();
  77. if (db == NULL) {
  78. return NT_STATUS_INTERNAL_DB_CORRUPTION;
  79. }
  80. key = talloc_asprintf(mem_ctx, PL_KEY_FORMAT, name);
  81. if (!key) {
  82. DEBUG(0, ("Failed to allocate key name!\n"));
  83. return NT_STATUS_NO_MEMORY;
  84. }
  85. status = dbwrap_fetch_bystring_upper(db, key, key, &data);
  86. if (!NT_STATUS_IS_OK(status)) {
  87. DEBUG(6, ("Failed to fetch record! "
  88. "The printer database is empty?\n"));
  89. goto done;
  90. }
  91. ret = tdb_unpack(data.dptr, data.dsize,
  92. PL_DATA_FORMAT,
  93. &time_h, &time_l, &nstr, &cstr, &lstr);
  94. if (ret == -1) {
  95. DEBUG(1, ("Failed to un pack printer data"));
  96. status = NT_STATUS_INTERNAL_DB_CORRUPTION;
  97. goto done;
  98. }
  99. if (last_refresh) {
  100. *last_refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
  101. }
  102. if (comment) {
  103. *comment = talloc_strdup(mem_ctx, cstr);
  104. if (!*comment) {
  105. DEBUG(1, ("Failed to strdup comment!\n"));
  106. status = NT_STATUS_NO_MEMORY;
  107. goto done;
  108. }
  109. }
  110. if (location) {
  111. *location = talloc_strdup(mem_ctx, lstr);
  112. if (*location == NULL) {
  113. DEBUG(1, ("Failed to strdup location!\n"));
  114. status = NT_STATUS_NO_MEMORY;
  115. goto done;
  116. }
  117. }
  118. status = NT_STATUS_OK;
  119. done:
  120. SAFE_FREE(nstr);
  121. SAFE_FREE(cstr);
  122. SAFE_FREE(lstr);
  123. TALLOC_FREE(key);
  124. return status;
  125. }
  126. bool printer_list_printername_exists(const char *name)
  127. {
  128. struct db_context *db = get_printer_list_db();
  129. char *key = NULL;
  130. bool ok;
  131. if (db == NULL) {
  132. return false;
  133. }
  134. key = talloc_asprintf_strupper_m(
  135. talloc_tos(), PL_KEY_FORMAT, name);
  136. if (key == NULL) {
  137. return false;
  138. }
  139. ok = dbwrap_exists(db, string_term_tdb_data(key));
  140. TALLOC_FREE(key);
  141. return ok;
  142. }
  143. NTSTATUS printer_list_set_printer(TALLOC_CTX *mem_ctx,
  144. const char *name,
  145. const char *comment,
  146. const char *location,
  147. time_t last_refresh)
  148. {
  149. struct db_context *db;
  150. char *key;
  151. TDB_DATA data;
  152. uint64_t time_64;
  153. uint32_t time_h, time_l;
  154. NTSTATUS status;
  155. int len;
  156. db = get_printer_list_db();
  157. if (db == NULL) {
  158. return NT_STATUS_INTERNAL_DB_CORRUPTION;
  159. }
  160. key = talloc_asprintf(mem_ctx, PL_KEY_FORMAT, name);
  161. if (!key) {
  162. DEBUG(0, ("Failed to allocate key name!\n"));
  163. return NT_STATUS_NO_MEMORY;
  164. }
  165. if (comment == NULL) {
  166. comment = "";
  167. }
  168. if (location == NULL) {
  169. location = "";
  170. }
  171. time_64 = last_refresh;
  172. time_l = time_64 & 0xFFFFFFFFL;
  173. time_h = time_64 >> 32;
  174. len = tdb_pack(NULL, 0,
  175. PL_DATA_FORMAT,
  176. time_h,
  177. time_l,
  178. name,
  179. comment,
  180. location);
  181. data.dptr = talloc_array(key, uint8_t, len);
  182. if (!data.dptr) {
  183. DEBUG(0, ("Failed to allocate tdb data buffer!\n"));
  184. status = NT_STATUS_NO_MEMORY;
  185. goto done;
  186. }
  187. data.dsize = len;
  188. len = tdb_pack(data.dptr, data.dsize,
  189. PL_DATA_FORMAT,
  190. time_h,
  191. time_l,
  192. name,
  193. comment,
  194. location);
  195. status = dbwrap_store_bystring_upper(db, key, data, TDB_REPLACE);
  196. done:
  197. TALLOC_FREE(key);
  198. return status;
  199. }
  200. NTSTATUS printer_list_get_last_refresh(time_t *last_refresh)
  201. {
  202. struct db_context *db;
  203. TDB_DATA data;
  204. uint32_t time_h, time_l;
  205. NTSTATUS status;
  206. int ret;
  207. db = get_printer_list_db();
  208. if (db == NULL) {
  209. return NT_STATUS_INTERNAL_DB_CORRUPTION;
  210. }
  211. ZERO_STRUCT(data);
  212. status = dbwrap_fetch_bystring(db, talloc_tos(), PL_TIMESTAMP_KEY, &data);
  213. if (!NT_STATUS_IS_OK(status)) {
  214. DEBUG(1, ("Failed to fetch record!\n"));
  215. goto done;
  216. }
  217. ret = tdb_unpack(data.dptr, data.dsize,
  218. PL_TSTAMP_FORMAT, &time_h, &time_l);
  219. TALLOC_FREE(data.dptr);
  220. if (ret == -1) {
  221. DEBUG(1, ("Failed to un pack printer data"));
  222. status = NT_STATUS_INTERNAL_DB_CORRUPTION;
  223. goto done;
  224. }
  225. *last_refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
  226. status = NT_STATUS_OK;
  227. done:
  228. return status;
  229. }
  230. NTSTATUS printer_list_mark_reload(void)
  231. {
  232. struct db_context *db;
  233. TDB_DATA data;
  234. uint32_t time_h, time_l;
  235. time_t now = time_mono(NULL);
  236. NTSTATUS status;
  237. int len;
  238. db = get_printer_list_db();
  239. if (db == NULL) {
  240. return NT_STATUS_INTERNAL_DB_CORRUPTION;
  241. }
  242. time_l = ((uint64_t)now) & 0xFFFFFFFFL;
  243. time_h = ((uint64_t)now) >> 32;
  244. len = tdb_pack(NULL, 0, PL_TSTAMP_FORMAT, time_h, time_l);
  245. data.dptr = talloc_array(talloc_tos(), uint8_t, len);
  246. if (!data.dptr) {
  247. DEBUG(0, ("Failed to allocate tdb data buffer!\n"));
  248. status = NT_STATUS_NO_MEMORY;
  249. goto done;
  250. }
  251. data.dsize = len;
  252. len = tdb_pack(data.dptr, data.dsize,
  253. PL_TSTAMP_FORMAT, time_h, time_l);
  254. status = dbwrap_store_bystring(db, PL_TIMESTAMP_KEY,
  255. data, TDB_REPLACE);
  256. done:
  257. TALLOC_FREE(data.dptr);
  258. return status;
  259. }
  260. typedef int (printer_list_trv_fn_t)(struct db_record *, void *);
  261. static NTSTATUS printer_list_traverse(printer_list_trv_fn_t *fn,
  262. void *private_data,
  263. bool read_only)
  264. {
  265. struct db_context *db;
  266. NTSTATUS status;
  267. db = get_printer_list_db();
  268. if (db == NULL) {
  269. return NT_STATUS_INTERNAL_DB_CORRUPTION;
  270. }
  271. if (read_only) {
  272. status = dbwrap_traverse_read(db, fn, private_data, NULL);
  273. } else {
  274. status = dbwrap_traverse(db, fn, private_data, NULL);
  275. }
  276. return status;
  277. }
  278. struct printer_list_clean_state {
  279. time_t last_refresh;
  280. NTSTATUS status;
  281. };
  282. static int printer_list_clean_fn(struct db_record *rec, void *private_data)
  283. {
  284. struct printer_list_clean_state *state =
  285. (struct printer_list_clean_state *)private_data;
  286. uint32_t time_h, time_l;
  287. time_t refresh;
  288. char *name;
  289. char *comment;
  290. char *location;
  291. int ret;
  292. TDB_DATA key;
  293. TDB_DATA value;
  294. key = dbwrap_record_get_key(rec);
  295. /* skip anything that does not contain PL_DATA_FORMAT data */
  296. if (strncmp((char *)key.dptr,
  297. PL_KEY_PREFIX, sizeof(PL_KEY_PREFIX)-1)) {
  298. return 0;
  299. }
  300. value = dbwrap_record_get_value(rec);
  301. ret = tdb_unpack(value.dptr, value.dsize,
  302. PL_DATA_FORMAT, &time_h, &time_l, &name, &comment,
  303. &location);
  304. if (ret == -1) {
  305. DEBUG(1, ("Failed to un pack printer data"));
  306. state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
  307. return -1;
  308. }
  309. SAFE_FREE(name);
  310. SAFE_FREE(comment);
  311. SAFE_FREE(location);
  312. refresh = (time_t)(((uint64_t)time_h << 32) + time_l);
  313. if (refresh < state->last_refresh) {
  314. state->status = dbwrap_record_delete(rec);
  315. if (!NT_STATUS_IS_OK(state->status)) {
  316. return -1;
  317. }
  318. }
  319. return 0;
  320. }
  321. NTSTATUS printer_list_clean_old(void)
  322. {
  323. struct printer_list_clean_state state;
  324. NTSTATUS status;
  325. status = printer_list_get_last_refresh(&state.last_refresh);
  326. if (!NT_STATUS_IS_OK(status)) {
  327. return status;
  328. }
  329. state.status = NT_STATUS_OK;
  330. status = printer_list_traverse(printer_list_clean_fn, &state, false);
  331. if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
  332. !NT_STATUS_IS_OK(state.status)) {
  333. status = state.status;
  334. }
  335. return status;
  336. }
  337. struct printer_list_exec_state {
  338. void (*fn)(const char *, const char *, const char *, void *);
  339. void *private_data;
  340. NTSTATUS status;
  341. };
  342. static int printer_list_exec_fn(struct db_record *rec, void *private_data)
  343. {
  344. struct printer_list_exec_state *state =
  345. (struct printer_list_exec_state *)private_data;
  346. uint32_t time_h, time_l;
  347. char *name;
  348. char *comment;
  349. char *location;
  350. int ret;
  351. TDB_DATA key;
  352. TDB_DATA value;
  353. key = dbwrap_record_get_key(rec);
  354. /* always skip PL_TIMESTAMP_KEY key */
  355. if (strequal((const char *)key.dptr, PL_TIMESTAMP_KEY)) {
  356. return 0;
  357. }
  358. value = dbwrap_record_get_value(rec);
  359. ret = tdb_unpack(value.dptr, value.dsize,
  360. PL_DATA_FORMAT, &time_h, &time_l, &name, &comment,
  361. &location);
  362. if (ret == -1) {
  363. DEBUG(1, ("Failed to un pack printer data"));
  364. state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
  365. return -1;
  366. }
  367. state->fn(name, comment, location, state->private_data);
  368. SAFE_FREE(name);
  369. SAFE_FREE(comment);
  370. SAFE_FREE(location);
  371. return 0;
  372. }
  373. NTSTATUS printer_list_read_run_fn(void (*fn)(const char *, const char *, const char *, void *),
  374. void *private_data)
  375. {
  376. struct printer_list_exec_state state;
  377. NTSTATUS status;
  378. state.fn = fn;
  379. state.private_data = private_data;
  380. state.status = NT_STATUS_OK;
  381. status = printer_list_traverse(printer_list_exec_fn, &state, true);
  382. if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) &&
  383. !NT_STATUS_IS_OK(state.status)) {
  384. status = state.status;
  385. }
  386. return status;
  387. }