Line data Source code
1 : /*
2 : Unix SMB/Netbios implementation.
3 : Version 3.0
4 : printing backend routines
5 : Copyright (C) Andrew Tridgell 1992-2000
6 : Copyright (C) Jeremy Allison 2002
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 "includes.h"
23 : #include "system/passwd.h" /* uid_wrapper */
24 : #include "system/filesys.h"
25 : #include "printing.h"
26 : #include "util_tdb.h"
27 : #include "lib/util/string_wrappers.h"
28 :
29 : static struct tdb_print_db *print_db_head;
30 :
31 : /****************************************************************************
32 : Function to find or create the printer specific job tdb given a printername.
33 : Limits the number of tdb's open to MAX_PRINT_DBS_OPEN.
34 : ****************************************************************************/
35 :
36 44069 : struct tdb_print_db *get_print_db_byname(const char *printername)
37 : {
38 44069 : struct tdb_print_db *p = NULL, *last_entry = NULL;
39 44069 : size_t num_open = 0;
40 44069 : char *printdb_path = NULL;
41 44069 : bool done_become_root = False;
42 0 : char *print_cache_path;
43 0 : int ret;
44 :
45 44069 : SMB_ASSERT(printername != NULL);
46 :
47 44937 : for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
48 : /* Ensure the list terminates... JRA. */
49 44003 : SMB_ASSERT(p->next != print_db_head);
50 :
51 44003 : if (p->tdb && strequal(p->printer_name, printername)) {
52 43135 : DLIST_PROMOTE(print_db_head, p);
53 43135 : p->ref_count++;
54 43135 : return p;
55 : }
56 868 : num_open++;
57 868 : last_entry = p;
58 : }
59 :
60 : /* Not found. */
61 934 : if (num_open >= MAX_PRINT_DBS_OPEN) {
62 : /* Try and recycle the last entry. */
63 868 : if (print_db_head && last_entry) {
64 868 : DLIST_PROMOTE(print_db_head, last_entry);
65 : }
66 :
67 868 : for (p = print_db_head; p; p = p->next) {
68 868 : if (p->ref_count)
69 0 : continue;
70 868 : if (p->tdb) {
71 868 : if (tdb_close(p->tdb)) {
72 0 : DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
73 : p->printer_name ));
74 0 : return NULL;
75 : }
76 : }
77 868 : p->tdb = NULL;
78 868 : p->ref_count = 0;
79 868 : memset(p->printer_name, '\0', sizeof(p->printer_name));
80 868 : break;
81 : }
82 868 : if (p && print_db_head) {
83 868 : DLIST_PROMOTE(print_db_head, p);
84 868 : p = print_db_head;
85 : }
86 : }
87 :
88 934 : if (!p) {
89 : /* Create one. */
90 66 : p = SMB_MALLOC_P(struct tdb_print_db);
91 66 : if (!p) {
92 0 : DEBUG(0,("get_print_db: malloc fail !\n"));
93 0 : return NULL;
94 : }
95 66 : ZERO_STRUCTP(p);
96 66 : DLIST_ADD(print_db_head, p);
97 : }
98 :
99 934 : print_cache_path = cache_path(talloc_tos(), "printing/");
100 934 : if (print_cache_path == NULL) {
101 0 : DLIST_REMOVE(print_db_head, p);
102 0 : SAFE_FREE(p);
103 0 : return NULL;
104 : }
105 934 : ret = asprintf(&printdb_path, "%s%s.tdb",
106 : print_cache_path, printername);
107 934 : TALLOC_FREE(print_cache_path);
108 934 : if (ret < 0) {
109 0 : DLIST_REMOVE(print_db_head, p);
110 0 : SAFE_FREE(p);
111 0 : return NULL;
112 : }
113 :
114 934 : if (geteuid() != sec_initial_uid()) {
115 452 : become_root();
116 452 : done_become_root = True;
117 : }
118 :
119 934 : p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT,
120 : 0600);
121 :
122 934 : if (done_become_root)
123 452 : unbecome_root();
124 :
125 934 : if (!p->tdb) {
126 0 : DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n",
127 : printdb_path ));
128 0 : DLIST_REMOVE(print_db_head, p);
129 0 : SAFE_FREE(printdb_path);
130 0 : SAFE_FREE(p);
131 0 : return NULL;
132 : }
133 934 : SAFE_FREE(printdb_path);
134 934 : fstrcpy(p->printer_name, printername);
135 934 : p->ref_count++;
136 934 : return p;
137 : }
138 :
139 : /***************************************************************************
140 : Remove a reference count.
141 : ****************************************************************************/
142 :
143 44037 : void release_print_db( struct tdb_print_db *pdb)
144 : {
145 44037 : pdb->ref_count--;
146 44037 : SMB_ASSERT(pdb->ref_count >= 0);
147 44037 : }
148 :
149 : /***************************************************************************
150 : Close all open print db entries.
151 : ****************************************************************************/
152 :
153 28 : void close_all_print_db(void)
154 : {
155 28 : struct tdb_print_db *p = NULL, *next_p = NULL;
156 :
157 56 : for (p = print_db_head; p; p = next_p) {
158 28 : next_p = p->next;
159 :
160 28 : if (p->tdb)
161 28 : tdb_close(p->tdb);
162 28 : DLIST_REMOVE(print_db_head, p);
163 28 : ZERO_STRUCTP(p);
164 28 : SAFE_FREE(p);
165 : }
166 28 : }
167 :
168 :
169 : /****************************************************************************
170 : Fetch and clean the pid_t record list for all pids interested in notify
171 : messages. data needs freeing on exit.
172 : ****************************************************************************/
173 :
174 262 : TDB_DATA get_printer_notify_pid_list(struct tdb_context *tdb, const char *printer_name, bool cleanlist)
175 : {
176 0 : TDB_DATA data;
177 0 : size_t i;
178 :
179 262 : ZERO_STRUCT(data);
180 :
181 262 : data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY );
182 :
183 262 : if (!data.dptr) {
184 252 : ZERO_STRUCT(data);
185 252 : return data;
186 : }
187 :
188 10 : if (data.dsize % 8) {
189 0 : DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name ));
190 0 : tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY );
191 0 : SAFE_FREE(data.dptr);
192 0 : ZERO_STRUCT(data);
193 0 : return data;
194 : }
195 :
196 10 : if (!cleanlist)
197 0 : return data;
198 :
199 : /*
200 : * Weed out all dead entries.
201 : */
202 :
203 20 : for( i = 0; i < data.dsize; i += 8) {
204 10 : pid_t pid = (pid_t)IVAL(data.dptr, i);
205 :
206 10 : if (pid == getpid())
207 10 : continue;
208 :
209 : /* Entry is dead if process doesn't exist or refcount is zero. */
210 :
211 0 : while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists_by_pid(pid))) {
212 :
213 : /* Refcount == zero is a logic error and should never happen. */
214 0 : if (IVAL(data.dptr, i + 4) == 0) {
215 0 : DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n",
216 : (unsigned int)pid, printer_name ));
217 : }
218 :
219 0 : if (data.dsize - i > 8)
220 0 : memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
221 0 : data.dsize -= 8;
222 : }
223 : }
224 :
225 10 : return data;
226 : }
227 :
228 :
|