source: vendor/3.6.24/source3/printing/printing.c

Last change on this file was 860, checked in by Silvan Scherrer, 11 years ago

Samba 3.6: updated vendor to latest version

File size: 94.0 KB
Line 
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/syslog.h"
24#include "system/filesys.h"
25#include "printing.h"
26#include "../librpc/gen_ndr/ndr_spoolss.h"
27#include "nt_printing.h"
28#include "../librpc/gen_ndr/netlogon.h"
29#include "printing/notify.h"
30#include "printing/pcap.h"
31#include "serverid.h"
32#include "smbd/smbd.h"
33#include "auth.h"
34#include "messages.h"
35#include "util_tdb.h"
36
37extern struct current_user current_user;
38extern userdom_struct current_user_info;
39
40/* Current printer interface */
41static bool remove_from_jobs_added(const char* sharename, uint32 jobid);
42
43/*
44 the printing backend revolves around a tdb database that stores the
45 SMB view of the print queue
46
47 The key for this database is a jobid - a internally generated number that
48 uniquely identifies a print job
49
50 reading the print queue involves two steps:
51 - possibly running lpq and updating the internal database from that
52 - reading entries from the database
53
54 jobids are assigned when a job starts spooling.
55*/
56
57static TDB_CONTEXT *rap_tdb;
58static uint16 next_rap_jobid;
59struct rap_jobid_key {
60 fstring sharename;
61 uint32 jobid;
62};
63
64/***************************************************************************
65 Nightmare. LANMAN jobid's are 16 bit numbers..... We must map them to 32
66 bit RPC jobids.... JRA.
67***************************************************************************/
68
69uint16 pjobid_to_rap(const char* sharename, uint32 jobid)
70{
71 uint16 rap_jobid;
72 TDB_DATA data, key;
73 struct rap_jobid_key jinfo;
74 uint8 buf[2];
75
76 DEBUG(10,("pjobid_to_rap: called.\n"));
77
78 if (!rap_tdb) {
79 /* Create the in-memory tdb. */
80 rap_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, (O_RDWR|O_CREAT), 0644);
81 if (!rap_tdb)
82 return 0;
83 }
84
85 ZERO_STRUCT( jinfo );
86 fstrcpy( jinfo.sharename, sharename );
87 jinfo.jobid = jobid;
88 key.dptr = (uint8 *)&jinfo;
89 key.dsize = sizeof(jinfo);
90
91 data = tdb_fetch(rap_tdb, key);
92 if (data.dptr && data.dsize == sizeof(uint16)) {
93 rap_jobid = SVAL(data.dptr, 0);
94 SAFE_FREE(data.dptr);
95 DEBUG(10,("pjobid_to_rap: jobid %u maps to RAP jobid %u\n",
96 (unsigned int)jobid, (unsigned int)rap_jobid));
97 return rap_jobid;
98 }
99 SAFE_FREE(data.dptr);
100 /* Not found - create and store mapping. */
101 rap_jobid = ++next_rap_jobid;
102 if (rap_jobid == 0)
103 rap_jobid = ++next_rap_jobid;
104 SSVAL(buf,0,rap_jobid);
105 data.dptr = buf;
106 data.dsize = sizeof(rap_jobid);
107 tdb_store(rap_tdb, key, data, TDB_REPLACE);
108 tdb_store(rap_tdb, data, key, TDB_REPLACE);
109
110 DEBUG(10,("pjobid_to_rap: created jobid %u maps to RAP jobid %u\n",
111 (unsigned int)jobid, (unsigned int)rap_jobid));
112 return rap_jobid;
113}
114
115bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
116{
117 TDB_DATA data, key;
118 uint8 buf[2];
119
120 DEBUG(10,("rap_to_pjobid called.\n"));
121
122 if (!rap_tdb)
123 return False;
124
125 SSVAL(buf,0,rap_jobid);
126 key.dptr = buf;
127 key.dsize = sizeof(rap_jobid);
128 data = tdb_fetch(rap_tdb, key);
129 if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
130 {
131 struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
132 if (sharename != NULL) {
133 fstrcpy( sharename, jinfo->sharename );
134 }
135 *pjobid = jinfo->jobid;
136 DEBUG(10,("rap_to_pjobid: jobid %u maps to RAP jobid %u\n",
137 (unsigned int)*pjobid, (unsigned int)rap_jobid));
138 SAFE_FREE(data.dptr);
139 return True;
140 }
141
142 DEBUG(10,("rap_to_pjobid: Failed to lookup RAP jobid %u\n",
143 (unsigned int)rap_jobid));
144 SAFE_FREE(data.dptr);
145 return False;
146}
147
148void rap_jobid_delete(const char* sharename, uint32 jobid)
149{
150 TDB_DATA key, data;
151 uint16 rap_jobid;
152 struct rap_jobid_key jinfo;
153 uint8 buf[2];
154
155 DEBUG(10,("rap_jobid_delete: called.\n"));
156
157 if (!rap_tdb)
158 return;
159
160 ZERO_STRUCT( jinfo );
161 fstrcpy( jinfo.sharename, sharename );
162 jinfo.jobid = jobid;
163 key.dptr = (uint8 *)&jinfo;
164 key.dsize = sizeof(jinfo);
165
166 data = tdb_fetch(rap_tdb, key);
167 if (!data.dptr || (data.dsize != sizeof(uint16))) {
168 DEBUG(10,("rap_jobid_delete: cannot find jobid %u\n",
169 (unsigned int)jobid ));
170 SAFE_FREE(data.dptr);
171 return;
172 }
173
174 DEBUG(10,("rap_jobid_delete: deleting jobid %u\n",
175 (unsigned int)jobid ));
176
177 rap_jobid = SVAL(data.dptr, 0);
178 SAFE_FREE(data.dptr);
179 SSVAL(buf,0,rap_jobid);
180 data.dptr = buf;
181 data.dsize = sizeof(rap_jobid);
182 tdb_delete(rap_tdb, key);
183 tdb_delete(rap_tdb, data);
184}
185
186static int get_queue_status(const char* sharename, print_status_struct *);
187
188/****************************************************************************
189 Initialise the printing backend. Called once at startup before the fork().
190****************************************************************************/
191
192bool print_backend_init(struct messaging_context *msg_ctx)
193{
194 const char *sversion = "INFO/version";
195 int services = lp_numservices();
196 int snum;
197
198 unlink(cache_path("printing.tdb"));
199 mkdir(cache_path("printing"),0755);
200
201 /* handle a Samba upgrade */
202
203 for (snum = 0; snum < services; snum++) {
204 struct tdb_print_db *pdb;
205 if (!lp_print_ok(snum))
206 continue;
207
208 pdb = get_print_db_byname(lp_const_servicename(snum));
209 if (!pdb)
210 continue;
211 if (tdb_lock_bystring(pdb->tdb, sversion) == -1) {
212 DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) ));
213 release_print_db(pdb);
214 return False;
215 }
216 if (tdb_fetch_int32(pdb->tdb, sversion) != PRINT_DATABASE_VERSION) {
217 tdb_wipe_all(pdb->tdb);
218 tdb_store_int32(pdb->tdb, sversion, PRINT_DATABASE_VERSION);
219 }
220 tdb_unlock_bystring(pdb->tdb, sversion);
221 release_print_db(pdb);
222 }
223
224 close_all_print_db(); /* Don't leave any open. */
225
226 /* do NT print initialization... */
227 return nt_printing_init(msg_ctx);
228}
229
230/****************************************************************************
231 Shut down printing backend. Called once at shutdown to close the tdb.
232****************************************************************************/
233
234void printing_end(void)
235{
236 close_all_print_db(); /* Don't leave any open. */
237}
238
239/****************************************************************************
240 Retrieve the set of printing functions for a given service. This allows
241 us to set the printer function table based on the value of the 'printing'
242 service parameter.
243
244 Use the generic interface as the default and only use cups interface only
245 when asked for (and only when supported)
246****************************************************************************/
247
248static struct printif *get_printer_fns_from_type( enum printing_types type )
249{
250 struct printif *printer_fns = &generic_printif;
251
252#ifdef HAVE_CUPS
253 if ( type == PRINT_CUPS ) {
254 printer_fns = &cups_printif;
255 }
256#endif /* HAVE_CUPS */
257
258#ifdef HAVE_IPRINT
259 if ( type == PRINT_IPRINT ) {
260 printer_fns = &iprint_printif;
261 }
262#endif /* HAVE_IPRINT */
263
264 printer_fns->type = type;
265
266 return printer_fns;
267}
268
269static struct printif *get_printer_fns( int snum )
270{
271 return get_printer_fns_from_type( (enum printing_types)lp_printing(snum) );
272}
273
274
275/****************************************************************************
276 Useful function to generate a tdb key.
277****************************************************************************/
278
279static TDB_DATA print_key(uint32 jobid, uint32 *tmp)
280{
281 TDB_DATA ret;
282
283 SIVAL(tmp, 0, jobid);
284 ret.dptr = (uint8 *)tmp;
285 ret.dsize = sizeof(*tmp);
286 return ret;
287}
288
289/****************************************************************************
290 Pack the devicemode to store it in a tdb.
291****************************************************************************/
292static int pack_devicemode(struct spoolss_DeviceMode *devmode, uint8 *buf, int buflen)
293{
294 enum ndr_err_code ndr_err;
295 DATA_BLOB blob;
296 int len = 0;
297
298 if (devmode) {
299 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(),
300 devmode,
301 (ndr_push_flags_fn_t)
302 ndr_push_spoolss_DeviceMode);
303 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
304 DEBUG(10, ("pack_devicemode: "
305 "error encoding spoolss_DeviceMode\n"));
306 goto done;
307 }
308 } else {
309 ZERO_STRUCT(blob);
310 }
311
312 len = tdb_pack(buf, buflen, "B", blob.length, blob.data);
313
314 if (devmode) {
315 DEBUG(8, ("Packed devicemode [%s]\n", devmode->formname));
316 }
317
318done:
319 return len;
320}
321
322/****************************************************************************
323 Unpack the devicemode to store it in a tdb.
324****************************************************************************/
325static int unpack_devicemode(TALLOC_CTX *mem_ctx,
326 const uint8 *buf, int buflen,
327 struct spoolss_DeviceMode **devmode)
328{
329 struct spoolss_DeviceMode *dm;
330 enum ndr_err_code ndr_err;
331 char *data = NULL;
332 int data_len = 0;
333 DATA_BLOB blob;
334 int len = 0;
335
336 *devmode = NULL;
337
338 len = tdb_unpack(buf, buflen, "B", &data_len, &data);
339 if (!data) {
340 return len;
341 }
342
343 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
344 if (!dm) {
345 goto done;
346 }
347
348 blob = data_blob_const(data, data_len);
349
350 ndr_err = ndr_pull_struct_blob(&blob, dm, dm,
351 (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);
352 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
353 DEBUG(10, ("unpack_devicemode: "
354 "error parsing spoolss_DeviceMode\n"));
355 goto done;
356 }
357
358 DEBUG(8, ("Unpacked devicemode [%s](%s)\n",
359 dm->devicename, dm->formname));
360 if (dm->driverextra_data.data) {
361 DEBUG(8, ("with a private section of %d bytes\n",
362 dm->__driverextra_length));
363 }
364
365 *devmode = dm;
366
367done:
368 SAFE_FREE(data);
369 return len;
370}
371
372/***********************************************************************
373 unpack a pjob from a tdb buffer
374***********************************************************************/
375
376static int unpack_pjob(TALLOC_CTX *mem_ctx, uint8 *buf, int buflen,
377 struct printjob *pjob)
378{
379 int len = 0;
380 int used;
381 uint32 pjpid, pjjobid, pjsysjob, pjfd, pjstarttime, pjstatus;
382 uint32 pjsize, pjpage_count, pjspooled, pjsmbjob;
383
384 if (!buf || !pjob) {
385 return -1;
386 }
387
388 len += tdb_unpack(buf+len, buflen-len, "ddddddddddfffff",
389 &pjpid,
390 &pjjobid,
391 &pjsysjob,
392 &pjfd,
393 &pjstarttime,
394 &pjstatus,
395 &pjsize,
396 &pjpage_count,
397 &pjspooled,
398 &pjsmbjob,
399 pjob->filename,
400 pjob->jobname,
401 pjob->user,
402 pjob->clientmachine,
403 pjob->queuename);
404
405 if (len == -1) {
406 return -1;
407 }
408
409 used = unpack_devicemode(mem_ctx, buf+len, buflen-len, &pjob->devmode);
410 if (used == -1) {
411 return -1;
412 }
413
414 len += used;
415
416 pjob->pid = pjpid;
417 pjob->jobid = pjjobid;
418 pjob->sysjob = pjsysjob;
419 pjob->fd = pjfd;
420 pjob->starttime = pjstarttime;
421 pjob->status = pjstatus;
422 pjob->size = pjsize;
423 pjob->page_count = pjpage_count;
424 pjob->spooled = pjspooled;
425 pjob->smbjob = pjsmbjob;
426
427 return len;
428
429}
430
431/****************************************************************************
432 Useful function to find a print job in the database.
433****************************************************************************/
434
435static struct printjob *print_job_find(TALLOC_CTX *mem_ctx,
436 const char *sharename,
437 uint32 jobid)
438{
439 struct printjob *pjob;
440 uint32_t tmp;
441 TDB_DATA ret;
442 struct tdb_print_db *pdb = get_print_db_byname(sharename);
443
444 DEBUG(10,("print_job_find: looking up job %u for share %s\n",
445 (unsigned int)jobid, sharename ));
446
447 if (!pdb) {
448 return NULL;
449 }
450
451 ret = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
452 release_print_db(pdb);
453
454 if (!ret.dptr) {
455 DEBUG(10, ("print_job_find: failed to find jobid %u.\n",
456 jobid));
457 return NULL;
458 }
459
460 pjob = talloc_zero(mem_ctx, struct printjob);
461 if (pjob == NULL) {
462 goto err_out;
463 }
464
465 if (unpack_pjob(mem_ctx, ret.dptr, ret.dsize, pjob) == -1) {
466 DEBUG(10, ("failed to unpack jobid %u.\n", jobid));
467 talloc_free(pjob);
468 pjob = NULL;
469 goto err_out;
470 }
471
472 DEBUG(10,("print_job_find: returning system job %d for jobid %u.\n",
473 pjob->sysjob, jobid));
474 SMB_ASSERT(pjob->jobid == jobid);
475
476err_out:
477 SAFE_FREE(ret.dptr);
478 return pjob;
479}
480
481/* Convert a unix jobid to a smb jobid */
482
483struct unixjob_traverse_state {
484 int sysjob;
485 uint32 sysjob_to_jobid_value;
486};
487
488static int unixjob_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key,
489 TDB_DATA data, void *private_data)
490{
491 struct printjob *pjob;
492 struct unixjob_traverse_state *state =
493 (struct unixjob_traverse_state *)private_data;
494
495 if (!data.dptr || data.dsize == 0)
496 return 0;
497
498 pjob = (struct printjob *)data.dptr;
499 if (key.dsize != sizeof(uint32))
500 return 0;
501
502 if (state->sysjob == pjob->sysjob) {
503 state->sysjob_to_jobid_value = pjob->jobid;
504 return 1;
505 }
506
507 return 0;
508}
509
510static uint32 sysjob_to_jobid_pdb(struct tdb_print_db *pdb, int sysjob)
511{
512 struct unixjob_traverse_state state;
513
514 state.sysjob = sysjob;
515 state.sysjob_to_jobid_value = (uint32)-1;
516
517 tdb_traverse(pdb->tdb, unixjob_traverse_fn, &state);
518
519 return state.sysjob_to_jobid_value;
520}
521
522/****************************************************************************
523 This is a *horribly expensive call as we have to iterate through all the
524 current printer tdb's. Don't do this often ! JRA.
525****************************************************************************/
526
527uint32 sysjob_to_jobid(int unix_jobid)
528{
529 int services = lp_numservices();
530 int snum;
531 struct unixjob_traverse_state state;
532
533 state.sysjob = unix_jobid;
534 state.sysjob_to_jobid_value = (uint32)-1;
535
536 for (snum = 0; snum < services; snum++) {
537 struct tdb_print_db *pdb;
538 if (!lp_print_ok(snum))
539 continue;
540 pdb = get_print_db_byname(lp_const_servicename(snum));
541 if (!pdb) {
542 continue;
543 }
544 tdb_traverse(pdb->tdb, unixjob_traverse_fn, &state);
545 release_print_db(pdb);
546 if (state.sysjob_to_jobid_value != (uint32)-1)
547 return state.sysjob_to_jobid_value;
548 }
549 return (uint32)-1;
550}
551
552/****************************************************************************
553 Send notifications based on what has changed after a pjob_store.
554****************************************************************************/
555
556static const struct {
557 uint32_t lpq_status;
558 uint32_t spoolss_status;
559} lpq_to_spoolss_status_map[] = {
560 { LPQ_QUEUED, JOB_STATUS_QUEUED },
561 { LPQ_PAUSED, JOB_STATUS_PAUSED },
562 { LPQ_SPOOLING, JOB_STATUS_SPOOLING },
563 { LPQ_PRINTING, JOB_STATUS_PRINTING },
564 { LPQ_DELETING, JOB_STATUS_DELETING },
565 { LPQ_OFFLINE, JOB_STATUS_OFFLINE },
566 { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
567 { LPQ_PRINTED, JOB_STATUS_PRINTED },
568 { LPQ_DELETED, JOB_STATUS_DELETED },
569 { LPQ_BLOCKED, JOB_STATUS_BLOCKED_DEVQ },
570 { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
571 { (uint32_t)-1, 0 }
572};
573
574/* Convert a lpq status value stored in printing.tdb into the
575 appropriate win32 API constant. */
576
577static uint32 map_to_spoolss_status(uint32 lpq_status)
578{
579 int i = 0;
580
581 while (lpq_to_spoolss_status_map[i].lpq_status != -1) {
582 if (lpq_to_spoolss_status_map[i].lpq_status == lpq_status)
583 return lpq_to_spoolss_status_map[i].spoolss_status;
584 i++;
585 }
586
587 return 0;
588}
589
590/***************************************************************************
591 Append a jobid to the 'jobs changed' list.
592***************************************************************************/
593
594static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32_t jobid)
595{
596 TDB_DATA data;
597 uint32_t store_jobid;
598
599 SIVAL(&store_jobid, 0, jobid);
600 data.dptr = (uint8 *) &store_jobid;
601 data.dsize = 4;
602
603 DEBUG(10,("add_to_jobs_added: Added jobid %u\n", (unsigned int)jobid ));
604
605 return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_changed"),
606 data) == 0);
607}
608
609/***************************************************************************
610 Remove a jobid from the 'jobs changed' list.
611***************************************************************************/
612
613static bool remove_from_jobs_changed(const char* sharename, uint32_t jobid)
614{
615 struct tdb_print_db *pdb = get_print_db_byname(sharename);
616 TDB_DATA data, key;
617 size_t job_count, i;
618 bool ret = False;
619 bool gotlock = False;
620
621 if (!pdb) {
622 return False;
623 }
624
625 ZERO_STRUCT(data);
626
627 key = string_tdb_data("INFO/jobs_changed");
628
629 if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
630 goto out;
631
632 gotlock = True;
633
634 data = tdb_fetch(pdb->tdb, key);
635
636 if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
637 goto out;
638
639 job_count = data.dsize / 4;
640 for (i = 0; i < job_count; i++) {
641 uint32 ch_jobid;
642
643 ch_jobid = IVAL(data.dptr, i*4);
644 if (ch_jobid == jobid) {
645 if (i < job_count -1 )
646 memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
647 data.dsize -= 4;
648 if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) == -1)
649 goto out;
650 break;
651 }
652 }
653
654 ret = True;
655 out:
656
657 if (gotlock)
658 tdb_chainunlock(pdb->tdb, key);
659 SAFE_FREE(data.dptr);
660 release_print_db(pdb);
661 if (ret)
662 DEBUG(10,("remove_from_jobs_changed: removed jobid %u\n", (unsigned int)jobid ));
663 else
664 DEBUG(10,("remove_from_jobs_changed: Failed to remove jobid %u\n", (unsigned int)jobid ));
665 return ret;
666}
667
668static void pjob_store_notify(struct tevent_context *ev,
669 struct messaging_context *msg_ctx,
670 const char* sharename, uint32 jobid,
671 struct printjob *old_data,
672 struct printjob *new_data,
673 bool *pchanged)
674{
675 bool new_job = false;
676 bool changed = false;
677
678 if (old_data == NULL) {
679 new_job = true;
680 }
681
682 /* ACHTUNG! Due to a bug in Samba's spoolss parsing of the
683 NOTIFY_INFO_DATA buffer, we *have* to send the job submission
684 time first or else we'll end up with potential alignment
685 errors. I don't think the systemtime should be spooled as
686 a string, but this gets us around that error.
687 --jerry (i'll feel dirty for this) */
688
689 if (new_job) {
690 notify_job_submitted(ev, msg_ctx,
691 sharename, jobid, new_data->starttime);
692 notify_job_username(ev, msg_ctx,
693 sharename, jobid, new_data->user);
694 notify_job_name(ev, msg_ctx,
695 sharename, jobid, new_data->jobname);
696 notify_job_status(ev, msg_ctx,
697 sharename, jobid, map_to_spoolss_status(new_data->status));
698 notify_job_total_bytes(ev, msg_ctx,
699 sharename, jobid, new_data->size);
700 notify_job_total_pages(ev, msg_ctx,
701 sharename, jobid, new_data->page_count);
702 } else {
703 if (!strequal(old_data->jobname, new_data->jobname)) {
704 notify_job_name(ev, msg_ctx, sharename,
705 jobid, new_data->jobname);
706 changed = true;
707 }
708
709 if (old_data->status != new_data->status) {
710 notify_job_status(ev, msg_ctx,
711 sharename, jobid,
712 map_to_spoolss_status(new_data->status));
713 }
714
715 if (old_data->size != new_data->size) {
716 notify_job_total_bytes(ev, msg_ctx,
717 sharename, jobid, new_data->size);
718 }
719
720 if (old_data->page_count != new_data->page_count) {
721 notify_job_total_pages(ev, msg_ctx,
722 sharename, jobid,
723 new_data->page_count);
724 }
725 }
726
727 *pchanged = changed;
728}
729
730/****************************************************************************
731 Store a job structure back to the database.
732****************************************************************************/
733
734static bool pjob_store(struct tevent_context *ev,
735 struct messaging_context *msg_ctx,
736 const char* sharename, uint32 jobid,
737 struct printjob *pjob)
738{
739 uint32_t tmp;
740 TDB_DATA old_data, new_data;
741 bool ret = False;
742 struct tdb_print_db *pdb = get_print_db_byname(sharename);
743 uint8 *buf = NULL;
744 int len, newlen, buflen;
745
746
747 if (!pdb)
748 return False;
749
750 /* Get old data */
751
752 old_data = tdb_fetch(pdb->tdb, print_key(jobid, &tmp));
753
754 /* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */
755
756 newlen = 0;
757
758 do {
759 len = 0;
760 buflen = newlen;
761 len += tdb_pack(buf+len, buflen-len, "ddddddddddfffff",
762 (uint32)pjob->pid,
763 (uint32)pjob->jobid,
764 (uint32)pjob->sysjob,
765 (uint32)pjob->fd,
766 (uint32)pjob->starttime,
767 (uint32)pjob->status,
768 (uint32)pjob->size,
769 (uint32)pjob->page_count,
770 (uint32)pjob->spooled,
771 (uint32)pjob->smbjob,
772 pjob->filename,
773 pjob->jobname,
774 pjob->user,
775 pjob->clientmachine,
776 pjob->queuename);
777
778 len += pack_devicemode(pjob->devmode, buf+len, buflen-len);
779
780 if (buflen != len) {
781 buf = (uint8 *)SMB_REALLOC(buf, len);
782 if (!buf) {
783 DEBUG(0,("pjob_store: failed to enlarge buffer!\n"));
784 goto done;
785 }
786 newlen = len;
787 }
788 } while ( buflen != len );
789
790
791 /* Store new data */
792
793 new_data.dptr = buf;
794 new_data.dsize = len;
795 ret = (tdb_store(pdb->tdb, print_key(jobid, &tmp), new_data,
796 TDB_REPLACE) == 0);
797
798 /* Send notify updates for what has changed */
799
800 if (ret) {
801 bool changed = false;
802 struct printjob old_pjob;
803
804 if (old_data.dsize) {
805 TALLOC_CTX *tmp_ctx = talloc_new(ev);
806 if (tmp_ctx == NULL)
807 goto done;
808
809 len = unpack_pjob(tmp_ctx, old_data.dptr,
810 old_data.dsize, &old_pjob);
811 if (len != -1 ) {
812 pjob_store_notify(ev,
813 msg_ctx,
814 sharename, jobid, &old_pjob,
815 pjob,
816 &changed);
817 if (changed) {
818 add_to_jobs_changed(pdb, jobid);
819 }
820 }
821 talloc_free(tmp_ctx);
822
823 } else {
824 /* new job */
825 pjob_store_notify(ev, msg_ctx,
826 sharename, jobid, NULL, pjob,
827 &changed);
828 }
829 }
830
831done:
832 release_print_db(pdb);
833 SAFE_FREE( old_data.dptr );
834 SAFE_FREE( buf );
835
836 return ret;
837}
838
839/****************************************************************************
840 Remove a job structure from the database.
841****************************************************************************/
842
843static void pjob_delete(struct tevent_context *ev,
844 struct messaging_context *msg_ctx,
845 const char* sharename, uint32 jobid)
846{
847 uint32_t tmp;
848 struct printjob *pjob;
849 uint32 job_status = 0;
850 struct tdb_print_db *pdb;
851 TALLOC_CTX *tmp_ctx = talloc_new(ev);
852 if (tmp_ctx == NULL) {
853 return;
854 }
855
856 pdb = get_print_db_byname(sharename);
857 if (!pdb) {
858 goto err_out;
859 }
860
861 pjob = print_job_find(tmp_ctx, sharename, jobid);
862 if (!pjob) {
863 DEBUG(5, ("we were asked to delete nonexistent job %u\n",
864 jobid));
865 goto err_release;
866 }
867
868 /* We must cycle through JOB_STATUS_DELETING and
869 JOB_STATUS_DELETED for the port monitor to delete the job
870 properly. */
871
872 job_status = JOB_STATUS_DELETING|JOB_STATUS_DELETED;
873 notify_job_status(ev, msg_ctx, sharename, jobid, job_status);
874
875 /* Remove from printing.tdb */
876
877 tdb_delete(pdb->tdb, print_key(jobid, &tmp));
878 remove_from_jobs_added(sharename, jobid);
879 rap_jobid_delete(sharename, jobid);
880err_release:
881 release_print_db(pdb);
882err_out:
883 talloc_free(tmp_ctx);
884}
885
886/****************************************************************************
887 List a unix job in the print database.
888****************************************************************************/
889
890static void print_unix_job(struct tevent_context *ev,
891 struct messaging_context *msg_ctx,
892 const char *sharename, print_queue_struct *q,
893 uint32 jobid)
894{
895 struct printjob pj, *old_pj;
896 TALLOC_CTX *tmp_ctx = talloc_new(ev);
897 if (tmp_ctx == NULL) {
898 return;
899 }
900
901 if (jobid == (uint32)-1) {
902 jobid = q->sysjob + UNIX_JOB_START;
903 }
904
905 /* Preserve the timestamp on an existing unix print job */
906
907 old_pj = print_job_find(tmp_ctx, sharename, jobid);
908
909 ZERO_STRUCT(pj);
910
911 pj.pid = (pid_t)-1;
912 pj.jobid = jobid;
913 pj.sysjob = q->sysjob;
914 pj.fd = -1;
915 pj.starttime = old_pj ? old_pj->starttime : q->time;
916 pj.status = q->status;
917 pj.size = q->size;
918 pj.spooled = True;
919 fstrcpy(pj.filename, old_pj ? old_pj->filename : "");
920 if (jobid < UNIX_JOB_START) {
921 pj.smbjob = True;
922 fstrcpy(pj.jobname, old_pj ? old_pj->jobname : "Remote Downlevel Document");
923 } else {
924 pj.smbjob = False;
925 fstrcpy(pj.jobname, old_pj ? old_pj->jobname : q->fs_file);
926 }
927 fstrcpy(pj.user, old_pj ? old_pj->user : q->fs_user);
928 fstrcpy(pj.queuename, old_pj ? old_pj->queuename : sharename );
929
930 pjob_store(ev, msg_ctx, sharename, jobid, &pj);
931 talloc_free(tmp_ctx);
932}
933
934
935struct traverse_struct {
936 print_queue_struct *queue;
937 int qcount, snum, maxcount, total_jobs;
938 const char *sharename;
939 time_t lpq_time;
940 const char *lprm_command;
941 struct printif *print_if;
942 struct tevent_context *ev;
943 struct messaging_context *msg_ctx;
944 TALLOC_CTX *mem_ctx;
945};
946
947/****************************************************************************
948 Utility fn to delete any jobs that are no longer active.
949****************************************************************************/
950
951static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
952{
953 struct traverse_struct *ts = (struct traverse_struct *)state;
954 struct printjob pjob;
955 uint32 jobid;
956 int i = 0;
957
958 if ( key.dsize != sizeof(jobid) )
959 return 0;
960
961 if (unpack_pjob(ts->mem_ctx, data.dptr, data.dsize, &pjob) == -1)
962 return 0;
963 talloc_free(pjob.devmode);
964 jobid = pjob.jobid;
965
966 if (!pjob.smbjob) {
967 /* remove a unix job if it isn't in the system queue any more */
968 for (i=0;i<ts->qcount;i++) {
969 if (ts->queue[i].sysjob == pjob.sysjob) {
970 break;
971 }
972 }
973 if (i == ts->qcount) {
974 DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !smbjob\n",
975 (unsigned int)jobid ));
976 pjob_delete(ts->ev, ts->msg_ctx,
977 ts->sharename, jobid);
978 return 0;
979 }
980
981 /* need to continue the the bottom of the function to
982 save the correct attributes */
983 }
984
985 /* maybe it hasn't been spooled yet */
986 if (!pjob.spooled) {
987 /* if a job is not spooled and the process doesn't
988 exist then kill it. This cleans up after smbd
989 deaths */
990 if (!process_exists_by_pid(pjob.pid)) {
991 DEBUG(10,("traverse_fn_delete: pjob %u deleted due to !process_exists (%u)\n",
992 (unsigned int)jobid, (unsigned int)pjob.pid ));
993 pjob_delete(ts->ev, ts->msg_ctx,
994 ts->sharename, jobid);
995 } else
996 ts->total_jobs++;
997 return 0;
998 }
999
1000 /* this check only makes sense for jobs submitted from Windows clients */
1001
1002 if (pjob.smbjob) {
1003 for (i=0;i<ts->qcount;i++) {
1004 if ( pjob.status == LPQ_DELETED )
1005 continue;
1006
1007 if (ts->queue[i].sysjob == pjob.sysjob) {
1008
1009 /* try to clean up any jobs that need to be deleted */
1010
1011 if ( pjob.status == LPQ_DELETING ) {
1012 int result;
1013
1014 result = (*(ts->print_if->job_delete))(
1015 ts->sharename, ts->lprm_command, &pjob );
1016
1017 if ( result != 0 ) {
1018 /* if we can't delete, then reset the job status */
1019 pjob.status = LPQ_QUEUED;
1020 pjob_store(ts->ev, ts->msg_ctx,
1021 ts->sharename, jobid, &pjob);
1022 }
1023 else {
1024 /* if we deleted the job, the remove the tdb record */
1025 pjob_delete(ts->ev,
1026 ts->msg_ctx,
1027 ts->sharename, jobid);
1028 pjob.status = LPQ_DELETED;
1029 }
1030
1031 }
1032
1033 break;
1034 }
1035 }
1036 }
1037
1038 /* The job isn't in the system queue - we have to assume it has
1039 completed, so delete the database entry. */
1040
1041 if (i == ts->qcount) {
1042
1043 /* A race can occur between the time a job is spooled and
1044 when it appears in the lpq output. This happens when
1045 the job is added to printing.tdb when another smbd
1046 running print_queue_update() has completed a lpq and
1047 is currently traversing the printing tdb and deleting jobs.
1048 Don't delete the job if it was submitted after the lpq_time. */
1049
1050 if (pjob.starttime < ts->lpq_time) {
1051 DEBUG(10,("traverse_fn_delete: pjob %u deleted due to pjob.starttime (%u) < ts->lpq_time (%u)\n",
1052 (unsigned int)jobid,
1053 (unsigned int)pjob.starttime,
1054 (unsigned int)ts->lpq_time ));
1055 pjob_delete(ts->ev, ts->msg_ctx,
1056 ts->sharename, jobid);
1057 } else
1058 ts->total_jobs++;
1059 return 0;
1060 }
1061
1062 /* Save the pjob attributes we will store. */
1063 ts->queue[i].sysjob = pjob.sysjob;
1064 ts->queue[i].size = pjob.size;
1065 ts->queue[i].page_count = pjob.page_count;
1066 ts->queue[i].status = pjob.status;
1067 ts->queue[i].priority = 1;
1068 ts->queue[i].time = pjob.starttime;
1069 fstrcpy(ts->queue[i].fs_user, pjob.user);
1070 fstrcpy(ts->queue[i].fs_file, pjob.jobname);
1071
1072 ts->total_jobs++;
1073
1074 return 0;
1075}
1076
1077/****************************************************************************
1078 Check if the print queue has been updated recently enough.
1079****************************************************************************/
1080
1081static void print_cache_flush(const char *sharename)
1082{
1083 fstring key;
1084 struct tdb_print_db *pdb = get_print_db_byname(sharename);
1085
1086 if (!pdb)
1087 return;
1088 slprintf(key, sizeof(key)-1, "CACHE/%s", sharename);
1089 tdb_store_int32(pdb->tdb, key, -1);
1090 release_print_db(pdb);
1091}
1092
1093/****************************************************************************
1094 Check if someone already thinks they are doing the update.
1095****************************************************************************/
1096
1097static pid_t get_updating_pid(const char *sharename)
1098{
1099 fstring keystr;
1100 TDB_DATA data, key;
1101 pid_t updating_pid;
1102 struct tdb_print_db *pdb = get_print_db_byname(sharename);
1103
1104 if (!pdb)
1105 return (pid_t)-1;
1106 slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
1107 key = string_tdb_data(keystr);
1108
1109 data = tdb_fetch(pdb->tdb, key);
1110 release_print_db(pdb);
1111 if (!data.dptr || data.dsize != sizeof(pid_t)) {
1112 SAFE_FREE(data.dptr);
1113 return (pid_t)-1;
1114 }
1115
1116 updating_pid = IVAL(data.dptr, 0);
1117 SAFE_FREE(data.dptr);
1118
1119 if (process_exists_by_pid(updating_pid))
1120 return updating_pid;
1121
1122 return (pid_t)-1;
1123}
1124
1125/****************************************************************************
1126 Set the fact that we're doing the update, or have finished doing the update
1127 in the tdb.
1128****************************************************************************/
1129
1130static void set_updating_pid(const fstring sharename, bool updating)
1131{
1132 fstring keystr;
1133 TDB_DATA key;
1134 TDB_DATA data;
1135 pid_t updating_pid = sys_getpid();
1136 uint8 buffer[4];
1137
1138 struct tdb_print_db *pdb = get_print_db_byname(sharename);
1139
1140 if (!pdb)
1141 return;
1142
1143 slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
1144 key = string_tdb_data(keystr);
1145
1146 DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n",
1147 updating ? "" : "not ",
1148 sharename ));
1149
1150 if ( !updating ) {
1151 tdb_delete(pdb->tdb, key);
1152 release_print_db(pdb);
1153 return;
1154 }
1155
1156 SIVAL( buffer, 0, updating_pid);
1157 data.dptr = buffer;
1158 data.dsize = 4; /* we always assume this is a 4 byte value */
1159
1160 tdb_store(pdb->tdb, key, data, TDB_REPLACE);
1161 release_print_db(pdb);
1162}
1163
1164/****************************************************************************
1165 Sort print jobs by submittal time.
1166****************************************************************************/
1167
1168static int printjob_comp(print_queue_struct *j1, print_queue_struct *j2)
1169{
1170 /* Silly cases */
1171
1172 if (!j1 && !j2)
1173 return 0;
1174 if (!j1)
1175 return -1;
1176 if (!j2)
1177 return 1;
1178
1179 /* Sort on job start time */
1180
1181 if (j1->time == j2->time)
1182 return 0;
1183 return (j1->time > j2->time) ? 1 : -1;
1184}
1185
1186/****************************************************************************
1187 Store the sorted queue representation for later portmon retrieval.
1188 Skip deleted jobs
1189****************************************************************************/
1190
1191static void store_queue_struct(struct tdb_print_db *pdb, struct traverse_struct *pts)
1192{
1193 TDB_DATA data;
1194 int max_reported_jobs = lp_max_reported_jobs(pts->snum);
1195 print_queue_struct *queue = pts->queue;
1196 size_t len;
1197 size_t i;
1198 unsigned int qcount;
1199
1200 if (max_reported_jobs && (max_reported_jobs < pts->qcount))
1201 pts->qcount = max_reported_jobs;
1202 qcount = 0;
1203
1204 /* Work out the size. */
1205 data.dsize = 0;
1206 data.dsize += tdb_pack(NULL, 0, "d", qcount);
1207
1208 for (i = 0; i < pts->qcount; i++) {
1209 if ( queue[i].status == LPQ_DELETED )
1210 continue;
1211
1212 qcount++;
1213 data.dsize += tdb_pack(NULL, 0, "ddddddff",
1214 (uint32)queue[i].sysjob,
1215 (uint32)queue[i].size,
1216 (uint32)queue[i].page_count,
1217 (uint32)queue[i].status,
1218 (uint32)queue[i].priority,
1219 (uint32)queue[i].time,
1220 queue[i].fs_user,
1221 queue[i].fs_file);
1222 }
1223
1224 if ((data.dptr = (uint8 *)SMB_MALLOC(data.dsize)) == NULL)
1225 return;
1226
1227 len = 0;
1228 len += tdb_pack(data.dptr + len, data.dsize - len, "d", qcount);
1229 for (i = 0; i < pts->qcount; i++) {
1230 if ( queue[i].status == LPQ_DELETED )
1231 continue;
1232
1233 len += tdb_pack(data.dptr + len, data.dsize - len, "ddddddff",
1234 (uint32)queue[i].sysjob,
1235 (uint32)queue[i].size,
1236 (uint32)queue[i].page_count,
1237 (uint32)queue[i].status,
1238 (uint32)queue[i].priority,
1239 (uint32)queue[i].time,
1240 queue[i].fs_user,
1241 queue[i].fs_file);
1242 }
1243
1244 tdb_store(pdb->tdb, string_tdb_data("INFO/linear_queue_array"), data,
1245 TDB_REPLACE);
1246 SAFE_FREE(data.dptr);
1247 return;
1248}
1249
1250static TDB_DATA get_jobs_added_data(struct tdb_print_db *pdb)
1251{
1252 TDB_DATA data;
1253
1254 ZERO_STRUCT(data);
1255
1256 data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_added"));
1257 if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0)) {
1258 SAFE_FREE(data.dptr);
1259 ZERO_STRUCT(data);
1260 }
1261
1262 return data;
1263}
1264
1265static void check_job_added(const char *sharename, TDB_DATA data, uint32 jobid)
1266{
1267 unsigned int i;
1268 unsigned int job_count = data.dsize / 4;
1269
1270 for (i = 0; i < job_count; i++) {
1271 uint32 ch_jobid;
1272
1273 ch_jobid = IVAL(data.dptr, i*4);
1274 if (ch_jobid == jobid)
1275 remove_from_jobs_added(sharename, jobid);
1276 }
1277}
1278
1279/****************************************************************************
1280 Check if the print queue has been updated recently enough.
1281****************************************************************************/
1282
1283static bool print_cache_expired(const char *sharename, bool check_pending)
1284{
1285 fstring key;
1286 time_t last_qscan_time, time_now = time(NULL);
1287 struct tdb_print_db *pdb = get_print_db_byname(sharename);
1288 bool result = False;
1289
1290 if (!pdb)
1291 return False;
1292
1293 snprintf(key, sizeof(key), "CACHE/%s", sharename);
1294 last_qscan_time = (time_t)tdb_fetch_int32(pdb->tdb, key);
1295
1296 /*
1297 * Invalidate the queue for 3 reasons.
1298 * (1). last queue scan time == -1.
1299 * (2). Current time - last queue scan time > allowed cache time.
1300 * (3). last queue scan time > current time + MAX_CACHE_VALID_TIME (1 hour by default).
1301 * This last test picks up machines for which the clock has been moved
1302 * forward, an lpq scan done and then the clock moved back. Otherwise
1303 * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
1304 */
1305
1306 if (last_qscan_time == ((time_t)-1)
1307 || (time_now - last_qscan_time) >= lp_lpqcachetime()
1308 || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME))
1309 {
1310 uint32 u;
1311 time_t msg_pending_time;
1312
1313 DEBUG(4, ("print_cache_expired: cache expired for queue %s "
1314 "(last_qscan_time = %d, time now = %d, qcachetime = %d)\n",
1315 sharename, (int)last_qscan_time, (int)time_now,
1316 (int)lp_lpqcachetime() ));
1317
1318 /* check if another smbd has already sent a message to update the
1319 queue. Give the pending message one minute to clear and
1320 then send another message anyways. Make sure to check for
1321 clocks that have been run forward and then back again. */
1322
1323 snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
1324
1325 if ( check_pending
1326 && tdb_fetch_uint32( pdb->tdb, key, &u )
1327 && (msg_pending_time=u) > 0
1328 && msg_pending_time <= time_now
1329 && (time_now - msg_pending_time) < 60 )
1330 {
1331 DEBUG(4,("print_cache_expired: message already pending for %s. Accepting cache\n",
1332 sharename));
1333 goto done;
1334 }
1335
1336 result = True;
1337 }
1338
1339done:
1340 release_print_db(pdb);
1341 return result;
1342}
1343
1344/****************************************************************************
1345 main work for updating the lpq cache for a printer queue
1346****************************************************************************/
1347
1348static void print_queue_update_internal(struct tevent_context *ev,
1349 struct messaging_context *msg_ctx,
1350 const char *sharename,
1351 struct printif *current_printif,
1352 char *lpq_command, char *lprm_command)
1353{
1354 int i, qcount;
1355 print_queue_struct *queue = NULL;
1356 print_status_struct status;
1357 print_status_struct old_status;
1358 struct printjob *pjob;
1359 struct traverse_struct tstruct;
1360 TDB_DATA data, key;
1361 TDB_DATA jcdata;
1362 fstring keystr, cachestr;
1363 struct tdb_print_db *pdb = get_print_db_byname(sharename);
1364 TALLOC_CTX *tmp_ctx = talloc_new(ev);
1365
1366 if ((pdb == NULL) || (tmp_ctx == NULL)) {
1367 return;
1368 }
1369
1370 DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
1371 sharename, current_printif->type, lpq_command));
1372
1373 /*
1374 * Update the cache time FIRST ! Stops others even
1375 * attempting to get the lock and doing this
1376 * if the lpq takes a long time.
1377 */
1378
1379 slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", sharename);
1380 tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL));
1381
1382 /* get the current queue using the appropriate interface */
1383 ZERO_STRUCT(status);
1384
1385 qcount = (*(current_printif->queue_get))(sharename,
1386 current_printif->type,
1387 lpq_command, &queue, &status);
1388
1389 DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n",
1390 qcount, (qcount != 1) ? "s" : "", sharename));
1391
1392 /* Sort the queue by submission time otherwise they are displayed
1393 in hash order. */
1394
1395 TYPESAFE_QSORT(queue, qcount, printjob_comp);
1396
1397 /*
1398 any job in the internal database that is marked as spooled
1399 and doesn't exist in the system queue is considered finished
1400 and removed from the database
1401
1402 any job in the system database but not in the internal database
1403 is added as a unix job
1404
1405 fill in any system job numbers as we go
1406 */
1407 jcdata = get_jobs_added_data(pdb);
1408
1409 for (i=0; i<qcount; i++) {
1410 uint32 jobid = sysjob_to_jobid_pdb(pdb, queue[i].sysjob);
1411 if (jobid == (uint32)-1) {
1412 /* assume its a unix print job */
1413 print_unix_job(ev, msg_ctx,
1414 sharename, &queue[i], jobid);
1415 continue;
1416 }
1417
1418 /* we have an active SMB print job - update its status */
1419 pjob = print_job_find(tmp_ctx, sharename, jobid);
1420 if (!pjob) {
1421 /* err, somethings wrong. Probably smbd was restarted
1422 with jobs in the queue. All we can do is treat them
1423 like unix jobs. Pity. */
1424 DEBUG(1, ("queued print job %d not found in jobs list, "
1425 "assuming unix job\n", jobid));
1426 print_unix_job(ev, msg_ctx,
1427 sharename, &queue[i], jobid);
1428 continue;
1429 }
1430
1431 /* don't reset the status on jobs to be deleted */
1432
1433 if ( pjob->status != LPQ_DELETING )
1434 pjob->status = queue[i].status;
1435
1436 pjob_store(ev, msg_ctx, sharename, jobid, pjob);
1437
1438 check_job_added(sharename, jcdata, jobid);
1439 }
1440
1441 SAFE_FREE(jcdata.dptr);
1442
1443 /* now delete any queued entries that don't appear in the
1444 system queue */
1445 tstruct.queue = queue;
1446 tstruct.qcount = qcount;
1447 tstruct.snum = -1;
1448 tstruct.total_jobs = 0;
1449 tstruct.lpq_time = time(NULL);
1450 tstruct.sharename = sharename;
1451 tstruct.lprm_command = lprm_command;
1452 tstruct.print_if = current_printif;
1453 tstruct.ev = ev;
1454 tstruct.msg_ctx = msg_ctx;
1455 tstruct.mem_ctx = tmp_ctx;
1456
1457 tdb_traverse(pdb->tdb, traverse_fn_delete, (void *)&tstruct);
1458
1459 /* Store the linearised queue, max jobs only. */
1460 store_queue_struct(pdb, &tstruct);
1461
1462 SAFE_FREE(tstruct.queue);
1463 talloc_free(tmp_ctx);
1464
1465 DEBUG(10,("print_queue_update_internal: printer %s INFO/total_jobs = %d\n",
1466 sharename, tstruct.total_jobs ));
1467
1468 tdb_store_int32(pdb->tdb, "INFO/total_jobs", tstruct.total_jobs);
1469
1470 get_queue_status(sharename, &old_status);
1471 if (old_status.qcount != qcount)
1472 DEBUG(10,("print_queue_update_internal: queue status change %d jobs -> %d jobs for printer %s\n",
1473 old_status.qcount, qcount, sharename));
1474
1475 /* store the new queue status structure */
1476 slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
1477 key = string_tdb_data(keystr);
1478
1479 status.qcount = qcount;
1480 data.dptr = (uint8 *)&status;
1481 data.dsize = sizeof(status);
1482 tdb_store(pdb->tdb, key, data, TDB_REPLACE);
1483
1484 /*
1485 * Update the cache time again. We want to do this call
1486 * as little as possible...
1487 */
1488
1489 slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", sharename);
1490 tdb_store_int32(pdb->tdb, keystr, (int32)time(NULL));
1491
1492 /* clear the msg pending record for this queue */
1493
1494 snprintf(keystr, sizeof(keystr), "MSG_PENDING/%s", sharename);
1495
1496 if ( !tdb_store_uint32( pdb->tdb, keystr, 0 ) ) {
1497 /* log a message but continue on */
1498
1499 DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
1500 sharename));
1501 }
1502
1503 release_print_db( pdb );
1504
1505 return;
1506}
1507
1508/****************************************************************************
1509 Update the internal database from the system print queue for a queue.
1510 obtain a lock on the print queue before proceeding (needed when mutiple
1511 smbd processes maytry to update the lpq cache concurrently).
1512****************************************************************************/
1513
1514static void print_queue_update_with_lock( struct tevent_context *ev,
1515 struct messaging_context *msg_ctx,
1516 const char *sharename,
1517 struct printif *current_printif,
1518 char *lpq_command, char *lprm_command )
1519{
1520 fstring keystr;
1521 struct tdb_print_db *pdb;
1522
1523 DEBUG(5,("print_queue_update_with_lock: printer share = %s\n", sharename));
1524 pdb = get_print_db_byname(sharename);
1525 if (!pdb)
1526 return;
1527
1528 if ( !print_cache_expired(sharename, False) ) {
1529 DEBUG(5,("print_queue_update_with_lock: print cache for %s is still ok\n", sharename));
1530 release_print_db(pdb);
1531 return;
1532 }
1533
1534 /*
1535 * Check to see if someone else is doing this update.
1536 * This is essentially a mutex on the update.
1537 */
1538
1539 if (get_updating_pid(sharename) != -1) {
1540 release_print_db(pdb);
1541 return;
1542 }
1543
1544 /* Lock the queue for the database update */
1545
1546 slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", sharename);
1547 /* Only wait 10 seconds for this. */
1548 if (tdb_lock_bystring_with_timeout(pdb->tdb, keystr, 10) == -1) {
1549 DEBUG(0,("print_queue_update_with_lock: Failed to lock printer %s database\n", sharename));
1550 release_print_db(pdb);
1551 return;
1552 }
1553
1554 /*
1555 * Ensure that no one else got in here.
1556 * If the updating pid is still -1 then we are
1557 * the winner.
1558 */
1559
1560 if (get_updating_pid(sharename) != -1) {
1561 /*
1562 * Someone else is doing the update, exit.
1563 */
1564 tdb_unlock_bystring(pdb->tdb, keystr);
1565 release_print_db(pdb);
1566 return;
1567 }
1568
1569 /*
1570 * We're going to do the update ourselves.
1571 */
1572
1573 /* Tell others we're doing the update. */
1574 set_updating_pid(sharename, True);
1575
1576 /*
1577 * Allow others to enter and notice we're doing
1578 * the update.
1579 */
1580
1581 tdb_unlock_bystring(pdb->tdb, keystr);
1582
1583 /* do the main work now */
1584
1585 print_queue_update_internal(ev, msg_ctx,
1586 sharename, current_printif,
1587 lpq_command, lprm_command);
1588
1589 /* Delete our pid from the db. */
1590 set_updating_pid(sharename, False);
1591 release_print_db(pdb);
1592}
1593
1594/****************************************************************************
1595this is the receive function of the background lpq updater
1596****************************************************************************/
1597void print_queue_receive(struct messaging_context *msg,
1598 void *private_data,
1599 uint32_t msg_type,
1600 struct server_id server_id,
1601 DATA_BLOB *data)
1602{
1603 fstring sharename;
1604 char *lpqcommand = NULL, *lprmcommand = NULL;
1605 int printing_type;
1606 size_t len;
1607
1608 len = tdb_unpack( (uint8 *)data->data, data->length, "fdPP",
1609 sharename,
1610 &printing_type,
1611 &lpqcommand,
1612 &lprmcommand );
1613
1614 if ( len == -1 ) {
1615 SAFE_FREE(lpqcommand);
1616 SAFE_FREE(lprmcommand);
1617 DEBUG(0,("print_queue_receive: Got invalid print queue update message\n"));
1618 return;
1619 }
1620
1621 print_queue_update_with_lock(server_event_context(), msg, sharename,
1622 get_printer_fns_from_type((enum printing_types)printing_type),
1623 lpqcommand, lprmcommand );
1624
1625 SAFE_FREE(lpqcommand);
1626 SAFE_FREE(lprmcommand);
1627 return;
1628}
1629
1630static void printing_pause_fd_handler(struct tevent_context *ev,
1631 struct tevent_fd *fde,
1632 uint16_t flags,
1633 void *private_data)
1634{
1635 /*
1636 * If pause_pipe[1] is closed it means the parent smbd
1637 * and children exited or aborted.
1638 */
1639 exit_server_cleanly(NULL);
1640}
1641
1642extern struct child_pid *children;
1643extern int num_children;
1644
1645static void add_child_pid(pid_t pid)
1646{
1647 struct child_pid *child;
1648
1649 child = SMB_MALLOC_P(struct child_pid);
1650 if (child == NULL) {
1651 DEBUG(0, ("Could not add child struct -- malloc failed\n"));
1652 return;
1653 }
1654 child->pid = pid;
1655 DLIST_ADD(children, child);
1656 num_children += 1;
1657}
1658
1659/****************************************************************************
1660 Notify smbds of new printcap data
1661**************************************************************************/
1662static void reload_pcap_change_notify(struct tevent_context *ev,
1663 struct messaging_context *msg_ctx)
1664{
1665 /*
1666 * Reload the printers first in the background process so that
1667 * newly added printers get default values created in the registry.
1668 *
1669 * This will block the process for some time (~1 sec per printer), but
1670 * it doesn't block smbd's servering clients.
1671 */
1672 reload_printers_full(ev, msg_ctx);
1673
1674 message_send_all(msg_ctx, MSG_PRINTER_PCAP, NULL, 0, NULL);
1675}
1676
1677static bool printer_housekeeping_fn(const struct timeval *now,
1678 void *private_data)
1679{
1680 static time_t last_pcap_reload_time = 0;
1681 time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
1682 time_t t = time_mono(NULL);
1683
1684 DEBUG(5, ("printer housekeeping\n"));
1685
1686 /* if periodic printcap rescan is enabled, see if it's time to reload */
1687 if ((printcap_cache_time != 0)
1688 && (t >= (last_pcap_reload_time + printcap_cache_time))) {
1689 DEBUG( 3,( "Printcap cache time expired.\n"));
1690 pcap_cache_reload(server_event_context(),
1691 smbd_messaging_context(),
1692 &reload_pcap_change_notify);
1693 last_pcap_reload_time = t;
1694 }
1695
1696 return true;
1697}
1698
1699static void printing_sig_term_handler(struct tevent_context *ev,
1700 struct tevent_signal *se,
1701 int signum,
1702 int count,
1703 void *siginfo,
1704 void *private_data)
1705{
1706 exit_server_cleanly("termination signal");
1707}
1708
1709static void printing_sig_hup_handler(struct tevent_context *ev,
1710 struct tevent_signal *se,
1711 int signum,
1712 int count,
1713 void *siginfo,
1714 void *private_data)
1715{
1716 struct messaging_context *msg_ctx = talloc_get_type_abort(
1717 private_data, struct messaging_context);
1718
1719 DEBUG(1,("Reloading printers after SIGHUP\n"));
1720 pcap_cache_reload(ev, msg_ctx,
1721 &reload_pcap_change_notify);
1722}
1723
1724static void printing_conf_updated(struct messaging_context *msg,
1725 void *private_data,
1726 uint32_t msg_type,
1727 struct server_id server_id,
1728 DATA_BLOB *data)
1729{
1730 DEBUG(5,("Reloading printers after conf change\n"));
1731 pcap_cache_reload(messaging_event_context(msg), msg,
1732 &reload_pcap_change_notify);
1733}
1734
1735
1736static pid_t background_lpq_updater_pid = -1;
1737
1738/****************************************************************************
1739main thread of the background lpq updater
1740****************************************************************************/
1741void start_background_queue(struct tevent_context *ev,
1742 struct messaging_context *msg_ctx)
1743{
1744 /* Use local variables for this as we don't
1745 * need to save the parent side of this, just
1746 * ensure it closes when the process exits.
1747 */
1748 int pause_pipe[2];
1749
1750 DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
1751
1752 if (pipe(pause_pipe) == -1) {
1753 DEBUG(5,("start_background_queue: cannot create pipe. %s\n", strerror(errno) ));
1754 exit(1);
1755 }
1756
1757 background_lpq_updater_pid = sys_fork();
1758
1759 if (background_lpq_updater_pid == -1) {
1760 DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
1761 exit(1);
1762 }
1763
1764 /* Track the printing pid along with other smbd children */
1765 add_child_pid(background_lpq_updater_pid);
1766
1767 if(background_lpq_updater_pid == 0) {
1768 struct tevent_fd *fde;
1769 int ret;
1770 NTSTATUS status;
1771 struct tevent_signal *se;
1772
1773 /* Child. */
1774 DEBUG(5,("start_background_queue: background LPQ thread started\n"));
1775
1776 close(pause_pipe[0]);
1777 pause_pipe[0] = -1;
1778
1779 status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
1780
1781 if (!NT_STATUS_IS_OK(status)) {
1782 DEBUG(0,("reinit_after_fork() failed\n"));
1783 smb_panic("reinit_after_fork() failed");
1784 }
1785
1786 se = tevent_add_signal(ev, ev, SIGTERM, 0,
1787 printing_sig_term_handler,
1788 NULL);
1789 if (se == NULL) {
1790 smb_panic("failed to setup SIGTERM handler");
1791 }
1792 se = tevent_add_signal(ev, ev, SIGHUP, 0,
1793 printing_sig_hup_handler,
1794 msg_ctx);
1795 if (se == NULL) {
1796 smb_panic("failed to setup SIGHUP handler");
1797 }
1798
1799 if (!serverid_register(procid_self(),
1800 FLAG_MSG_GENERAL|FLAG_MSG_SMBD
1801 |FLAG_MSG_PRINT_GENERAL)) {
1802 exit(1);
1803 }
1804
1805 if (!locking_init()) {
1806 exit(1);
1807 }
1808
1809 messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
1810 print_queue_receive);
1811 messaging_register(msg_ctx, NULL, MSG_SMB_CONF_UPDATED,
1812 printing_conf_updated);
1813
1814 fde = tevent_add_fd(ev, ev, pause_pipe[1], TEVENT_FD_READ,
1815 printing_pause_fd_handler,
1816 NULL);
1817 if (!fde) {
1818 DEBUG(0,("tevent_add_fd() failed for pause_pipe\n"));
1819 smb_panic("tevent_add_fd() failed for pause_pipe");
1820 }
1821
1822 /* reload on startup to ensure parent smbd is refreshed */
1823 pcap_cache_reload(server_event_context(),
1824 smbd_messaging_context(),
1825 &reload_pcap_change_notify);
1826
1827 if (!(event_add_idle(ev, NULL,
1828 timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
1829 "printer_housekeeping",
1830 printer_housekeeping_fn,
1831 NULL))) {
1832 DEBUG(0, ("Could not add printing housekeeping event\n"));
1833 exit(1);
1834 }
1835
1836 DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
1837 ret = tevent_loop_wait(ev);
1838 /* should not be reached */
1839 DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
1840 ret, (ret == 0) ? "out of events" : strerror(errno)));
1841 exit(1);
1842 }
1843
1844 close(pause_pipe[1]);
1845}
1846
1847/****************************************************************************
1848update the internal database from the system print queue for a queue
1849****************************************************************************/
1850
1851static void print_queue_update(struct messaging_context *msg_ctx,
1852 int snum, bool force)
1853{
1854 fstring key;
1855 fstring sharename;
1856 char *lpqcommand = NULL;
1857 char *lprmcommand = NULL;
1858 uint8 *buffer = NULL;
1859 size_t len = 0;
1860 size_t newlen;
1861 struct tdb_print_db *pdb;
1862 int type;
1863 struct printif *current_printif;
1864 TALLOC_CTX *ctx = talloc_tos();
1865
1866 fstrcpy( sharename, lp_const_servicename(snum));
1867
1868 /* don't strip out characters like '$' from the printername */
1869
1870 lpqcommand = talloc_string_sub2(ctx,
1871 lp_lpqcommand(snum),
1872 "%p",
1873 lp_printername(snum),
1874 false, false, false);
1875 if (!lpqcommand) {
1876 return;
1877 }
1878 lpqcommand = talloc_sub_advanced(ctx,
1879 lp_servicename(snum),
1880 current_user_info.unix_name,
1881 "",
1882 current_user.ut.gid,
1883 get_current_username(),
1884 current_user_info.domain,
1885 lpqcommand);
1886 if (!lpqcommand) {
1887 return;
1888 }
1889
1890 lprmcommand = talloc_string_sub2(ctx,
1891 lp_lprmcommand(snum),
1892 "%p",
1893 lp_printername(snum),
1894 false, false, false);
1895 if (!lprmcommand) {
1896 return;
1897 }
1898 lprmcommand = talloc_sub_advanced(ctx,
1899 lp_servicename(snum),
1900 current_user_info.unix_name,
1901 "",
1902 current_user.ut.gid,
1903 get_current_username(),
1904 current_user_info.domain,
1905 lprmcommand);
1906 if (!lprmcommand) {
1907 return;
1908 }
1909
1910 /*
1911 * Make sure that the background queue process exists.
1912 * Otherwise just do the update ourselves
1913 */
1914
1915 if ( force || background_lpq_updater_pid == -1 ) {
1916 DEBUG(4,("print_queue_update: updating queue [%s] myself\n", sharename));
1917 current_printif = get_printer_fns( snum );
1918 print_queue_update_with_lock(server_event_context(), msg_ctx,
1919 sharename, current_printif,
1920 lpqcommand, lprmcommand);
1921
1922 return;
1923 }
1924
1925 type = lp_printing(snum);
1926
1927 /* get the length */
1928
1929 len = tdb_pack( NULL, 0, "fdPP",
1930 sharename,
1931 type,
1932 lpqcommand,
1933 lprmcommand );
1934
1935 buffer = SMB_XMALLOC_ARRAY( uint8, len );
1936
1937 /* now pack the buffer */
1938 newlen = tdb_pack( buffer, len, "fdPP",
1939 sharename,
1940 type,
1941 lpqcommand,
1942 lprmcommand );
1943
1944 SMB_ASSERT( newlen == len );
1945
1946 DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
1947 "type = %d, lpq command = [%s] lprm command = [%s]\n",
1948 sharename, type, lpqcommand, lprmcommand ));
1949
1950 /* here we set a msg pending record for other smbd processes
1951 to throttle the number of duplicate print_queue_update msgs
1952 sent. */
1953
1954 pdb = get_print_db_byname(sharename);
1955 if (!pdb) {
1956 SAFE_FREE(buffer);
1957 return;
1958 }
1959
1960 snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
1961
1962 if ( !tdb_store_uint32( pdb->tdb, key, time(NULL) ) ) {
1963 /* log a message but continue on */
1964
1965 DEBUG(0,("print_queue_update: failed to store MSG_PENDING flag for [%s]!\n",
1966 sharename));
1967 }
1968
1969 release_print_db( pdb );
1970
1971 /* finally send the message */
1972
1973 messaging_send_buf(msg_ctx, pid_to_procid(background_lpq_updater_pid),
1974 MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
1975
1976 SAFE_FREE( buffer );
1977
1978 return;
1979}
1980
1981/****************************************************************************
1982 Create/Update an entry in the print tdb that will allow us to send notify
1983 updates only to interested smbd's.
1984****************************************************************************/
1985
1986bool print_notify_register_pid(int snum)
1987{
1988 TDB_DATA data;
1989 struct tdb_print_db *pdb = NULL;
1990 TDB_CONTEXT *tdb = NULL;
1991 const char *printername;
1992 uint32 mypid = (uint32)sys_getpid();
1993 bool ret = False;
1994 size_t i;
1995
1996 /* if (snum == -1), then the change notify request was
1997 on a print server handle and we need to register on
1998 all print queus */
1999
2000 if (snum == -1)
2001 {
2002 int num_services = lp_numservices();
2003 int idx;
2004
2005 for ( idx=0; idx<num_services; idx++ ) {
2006 if (lp_snum_ok(idx) && lp_print_ok(idx) )
2007 print_notify_register_pid(idx);
2008 }
2009
2010 return True;
2011 }
2012 else /* register for a specific printer */
2013 {
2014 printername = lp_const_servicename(snum);
2015 pdb = get_print_db_byname(printername);
2016 if (!pdb)
2017 return False;
2018 tdb = pdb->tdb;
2019 }
2020
2021 if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
2022 DEBUG(0,("print_notify_register_pid: Failed to lock printer %s\n",
2023 printername));
2024 if (pdb)
2025 release_print_db(pdb);
2026 return False;
2027 }
2028
2029 data = get_printer_notify_pid_list( tdb, printername, True );
2030
2031 /* Add ourselves and increase the refcount. */
2032
2033 for (i = 0; i < data.dsize; i += 8) {
2034 if (IVAL(data.dptr,i) == mypid) {
2035 uint32 new_refcount = IVAL(data.dptr, i+4) + 1;
2036 SIVAL(data.dptr, i+4, new_refcount);
2037 break;
2038 }
2039 }
2040
2041 if (i == data.dsize) {
2042 /* We weren't in the list. Realloc. */
2043 data.dptr = (uint8 *)SMB_REALLOC(data.dptr, data.dsize + 8);
2044 if (!data.dptr) {
2045 DEBUG(0,("print_notify_register_pid: Relloc fail for printer %s\n",
2046 printername));
2047 goto done;
2048 }
2049 data.dsize += 8;
2050 SIVAL(data.dptr,data.dsize - 8,mypid);
2051 SIVAL(data.dptr,data.dsize - 4,1); /* Refcount. */
2052 }
2053
2054 /* Store back the record. */
2055 if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
2056 DEBUG(0,("print_notify_register_pid: Failed to update pid \
2057list for printer %s\n", printername));
2058 goto done;
2059 }
2060
2061 ret = True;
2062
2063 done:
2064
2065 tdb_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
2066 if (pdb)
2067 release_print_db(pdb);
2068 SAFE_FREE(data.dptr);
2069 return ret;
2070}
2071
2072/****************************************************************************
2073 Update an entry in the print tdb that will allow us to send notify
2074 updates only to interested smbd's.
2075****************************************************************************/
2076
2077bool print_notify_deregister_pid(int snum)
2078{
2079 TDB_DATA data;
2080 struct tdb_print_db *pdb = NULL;
2081 TDB_CONTEXT *tdb = NULL;
2082 const char *printername;
2083 uint32 mypid = (uint32)sys_getpid();
2084 size_t i;
2085 bool ret = False;
2086
2087 /* if ( snum == -1 ), we are deregister a print server handle
2088 which means to deregister on all print queues */
2089
2090 if (snum == -1)
2091 {
2092 int num_services = lp_numservices();
2093 int idx;
2094
2095 for ( idx=0; idx<num_services; idx++ ) {
2096 if ( lp_snum_ok(idx) && lp_print_ok(idx) )
2097 print_notify_deregister_pid(idx);
2098 }
2099
2100 return True;
2101 }
2102 else /* deregister a specific printer */
2103 {
2104 printername = lp_const_servicename(snum);
2105 pdb = get_print_db_byname(printername);
2106 if (!pdb)
2107 return False;
2108 tdb = pdb->tdb;
2109 }
2110
2111 if (tdb_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
2112 DEBUG(0,("print_notify_register_pid: Failed to lock \
2113printer %s database\n", printername));
2114 if (pdb)
2115 release_print_db(pdb);
2116 return False;
2117 }
2118
2119 data = get_printer_notify_pid_list( tdb, printername, True );
2120
2121 /* Reduce refcount. Remove ourselves if zero. */
2122
2123 for (i = 0; i < data.dsize; ) {
2124 if (IVAL(data.dptr,i) == mypid) {
2125 uint32 refcount = IVAL(data.dptr, i+4);
2126
2127 refcount--;
2128
2129 if (refcount == 0) {
2130 if (data.dsize - i > 8)
2131 memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
2132 data.dsize -= 8;
2133 continue;
2134 }
2135 SIVAL(data.dptr, i+4, refcount);
2136 }
2137
2138 i += 8;
2139 }
2140
2141 if (data.dsize == 0)
2142 SAFE_FREE(data.dptr);
2143
2144 /* Store back the record. */
2145 if (tdb_store_bystring(tdb, NOTIFY_PID_LIST_KEY, data, TDB_REPLACE) == -1) {
2146 DEBUG(0,("print_notify_register_pid: Failed to update pid \
2147list for printer %s\n", printername));
2148 goto done;
2149 }
2150
2151 ret = True;
2152
2153 done:
2154
2155 tdb_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
2156 if (pdb)
2157 release_print_db(pdb);
2158 SAFE_FREE(data.dptr);
2159 return ret;
2160}
2161
2162/****************************************************************************
2163 Check if a jobid is valid. It is valid if it exists in the database.
2164****************************************************************************/
2165
2166bool print_job_exists(const char* sharename, uint32 jobid)
2167{
2168 struct tdb_print_db *pdb = get_print_db_byname(sharename);
2169 bool ret;
2170 uint32_t tmp;
2171
2172 if (!pdb)
2173 return False;
2174 ret = tdb_exists(pdb->tdb, print_key(jobid, &tmp));
2175 release_print_db(pdb);
2176 return ret;
2177}
2178
2179/****************************************************************************
2180 Return the device mode asigned to a specific print job.
2181 Only valid for the process doing the spooling and when the job
2182 has not been spooled.
2183****************************************************************************/
2184
2185struct spoolss_DeviceMode *print_job_devmode(TALLOC_CTX *mem_ctx,
2186 const char *sharename,
2187 uint32 jobid)
2188{
2189 struct printjob *pjob = print_job_find(mem_ctx, sharename, jobid);
2190 if (pjob == NULL) {
2191 return NULL;
2192 }
2193
2194 return pjob->devmode;
2195}
2196
2197/****************************************************************************
2198 Set the name of a job. Only possible for owner.
2199****************************************************************************/
2200
2201bool print_job_set_name(struct tevent_context *ev,
2202 struct messaging_context *msg_ctx,
2203 const char *sharename, uint32 jobid, const char *name)
2204{
2205 struct printjob *pjob;
2206 bool ret;
2207 TALLOC_CTX *tmp_ctx = talloc_new(ev);
2208 if (tmp_ctx == NULL) {
2209 return false;
2210 }
2211
2212 pjob = print_job_find(tmp_ctx, sharename, jobid);
2213 if (!pjob || pjob->pid != sys_getpid()) {
2214 ret = false;
2215 goto err_out;
2216 }
2217
2218 fstrcpy(pjob->jobname, name);
2219 ret = pjob_store(ev, msg_ctx, sharename, jobid, pjob);
2220err_out:
2221 talloc_free(tmp_ctx);
2222 return ret;
2223}
2224
2225/****************************************************************************
2226 Get the name of a job. Only possible for owner.
2227****************************************************************************/
2228
2229bool print_job_get_name(TALLOC_CTX *mem_ctx, const char *sharename, uint32_t jobid, char **name)
2230{
2231 struct printjob *pjob;
2232
2233 pjob = print_job_find(mem_ctx, sharename, jobid);
2234 if (!pjob || pjob->pid != sys_getpid()) {
2235 return false;
2236 }
2237
2238 *name = pjob->jobname;
2239 return true;
2240}
2241
2242
2243/***************************************************************************
2244 Remove a jobid from the 'jobs added' list.
2245***************************************************************************/
2246
2247static bool remove_from_jobs_added(const char* sharename, uint32 jobid)
2248{
2249 struct tdb_print_db *pdb = get_print_db_byname(sharename);
2250 TDB_DATA data, key;
2251 size_t job_count, i;
2252 bool ret = False;
2253 bool gotlock = False;
2254
2255 if (!pdb) {
2256 return False;
2257 }
2258
2259 ZERO_STRUCT(data);
2260
2261 key = string_tdb_data("INFO/jobs_added");
2262
2263 if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
2264 goto out;
2265
2266 gotlock = True;
2267
2268 data = tdb_fetch(pdb->tdb, key);
2269
2270 if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
2271 goto out;
2272
2273 job_count = data.dsize / 4;
2274 for (i = 0; i < job_count; i++) {
2275 uint32 ch_jobid;
2276
2277 ch_jobid = IVAL(data.dptr, i*4);
2278 if (ch_jobid == jobid) {
2279 if (i < job_count -1 )
2280 memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
2281 data.dsize -= 4;
2282 if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) == -1)
2283 goto out;
2284 break;
2285 }
2286 }
2287
2288 ret = True;
2289 out:
2290
2291 if (gotlock)
2292 tdb_chainunlock(pdb->tdb, key);
2293 SAFE_FREE(data.dptr);
2294 release_print_db(pdb);
2295 if (ret)
2296 DEBUG(10,("remove_from_jobs_added: removed jobid %u\n", (unsigned int)jobid ));
2297 else
2298 DEBUG(10,("remove_from_jobs_added: Failed to remove jobid %u\n", (unsigned int)jobid ));
2299 return ret;
2300}
2301
2302/****************************************************************************
2303 Delete a print job - don't update queue.
2304****************************************************************************/
2305
2306static bool print_job_delete1(struct tevent_context *ev,
2307 struct messaging_context *msg_ctx,
2308 int snum, uint32 jobid)
2309{
2310 const char* sharename = lp_const_servicename(snum);
2311 struct printjob *pjob;
2312 int result = 0;
2313 struct printif *current_printif = get_printer_fns( snum );
2314 bool ret;
2315 TALLOC_CTX *tmp_ctx = talloc_new(ev);
2316 if (tmp_ctx == NULL) {
2317 return false;
2318 }
2319
2320 pjob = print_job_find(tmp_ctx, sharename, jobid);
2321 if (!pjob) {
2322 ret = false;
2323 goto err_out;
2324 }
2325
2326 /*
2327 * If already deleting just return.
2328 */
2329
2330 if (pjob->status == LPQ_DELETING) {
2331 ret = true;
2332 goto err_out;
2333 }
2334
2335 /* Hrm - we need to be able to cope with deleting a job before it
2336 has reached the spooler. Just mark it as LPQ_DELETING and
2337 let the print_queue_update() code rmeove the record */
2338
2339
2340 if (pjob->sysjob == -1) {
2341 DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid));
2342 }
2343
2344 /* Set the tdb entry to be deleting. */
2345
2346 pjob->status = LPQ_DELETING;
2347 pjob_store(ev, msg_ctx, sharename, jobid, pjob);
2348
2349 if (pjob->spooled && pjob->sysjob != -1)
2350 {
2351 result = (*(current_printif->job_delete))(
2352 lp_printername(snum),
2353 lp_lprmcommand(snum),
2354 pjob);
2355
2356 /* Delete the tdb entry if the delete succeeded or the job hasn't
2357 been spooled. */
2358
2359 if (result == 0) {
2360 struct tdb_print_db *pdb = get_print_db_byname(sharename);
2361 int njobs = 1;
2362
2363 if (!pdb) {
2364 ret = false;
2365 goto err_out;
2366 }
2367 pjob_delete(ev, msg_ctx, sharename, jobid);
2368 /* Ensure we keep a rough count of the number of total jobs... */
2369 tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, -1);
2370 release_print_db(pdb);
2371 }
2372 }
2373
2374 remove_from_jobs_added( sharename, jobid );
2375
2376 ret = (result == 0);
2377err_out:
2378 talloc_free(tmp_ctx);
2379 return ret;
2380}
2381
2382/****************************************************************************
2383 Return true if the current user owns the print job.
2384****************************************************************************/
2385
2386static bool is_owner(const struct auth_serversupplied_info *server_info,
2387 const char *servicename,
2388 uint32 jobid)
2389{
2390 struct printjob *pjob;
2391 bool ret;
2392 TALLOC_CTX *tmp_ctx = talloc_new(server_info);
2393 if (tmp_ctx == NULL) {
2394 return false;
2395 }
2396
2397 pjob = print_job_find(tmp_ctx, servicename, jobid);
2398 if (!pjob || !server_info) {
2399 ret = false;
2400 goto err_out;
2401 }
2402
2403 ret = strequal(pjob->user, server_info->sanitized_username);
2404err_out:
2405 talloc_free(tmp_ctx);
2406 return ret;
2407}
2408
2409/****************************************************************************
2410 Delete a print job.
2411****************************************************************************/
2412
2413WERROR print_job_delete(const struct auth_serversupplied_info *server_info,
2414 struct messaging_context *msg_ctx,
2415 int snum, uint32_t jobid)
2416{
2417 const char* sharename = lp_const_servicename(snum);
2418 struct printjob *pjob;
2419 bool owner;
2420 WERROR werr;
2421 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
2422 if (tmp_ctx == NULL) {
2423 return WERR_NOT_ENOUGH_MEMORY;
2424 }
2425
2426 owner = is_owner(server_info, lp_const_servicename(snum), jobid);
2427
2428 /* Check access against security descriptor or whether the user
2429 owns their job. */
2430
2431 if (!owner &&
2432 !print_access_check(server_info, msg_ctx, snum,
2433 JOB_ACCESS_ADMINISTER)) {
2434 DEBUG(3, ("delete denied by security descriptor\n"));
2435
2436 /* BEGIN_ADMIN_LOG */
2437 sys_adminlog( LOG_ERR,
2438 "Permission denied-- user not allowed to delete, \
2439pause, or resume print job. User name: %s. Printer name: %s.",
2440 uidtoname(server_info->utok.uid),
2441 lp_printername(snum) );
2442 /* END_ADMIN_LOG */
2443
2444 werr = WERR_ACCESS_DENIED;
2445 goto err_out;
2446 }
2447
2448 /*
2449 * get the spooled filename of the print job
2450 * if this works, then the file has not been spooled
2451 * to the underlying print system. Just delete the
2452 * spool file & return.
2453 */
2454
2455 pjob = print_job_find(tmp_ctx, sharename, jobid);
2456 if (!pjob || pjob->spooled || pjob->pid != getpid()) {
2457 DEBUG(10, ("Skipping spool file removal for job %u\n", jobid));
2458 } else {
2459 DEBUG(10, ("Removing spool file [%s]\n", pjob->filename));
2460 if (unlink(pjob->filename) == -1) {
2461 werr = map_werror_from_unix(errno);
2462 goto err_out;
2463 }
2464 }
2465
2466 if (!print_job_delete1(server_event_context(), msg_ctx, snum, jobid)) {
2467 werr = WERR_ACCESS_DENIED;
2468 goto err_out;
2469 }
2470
2471 /* force update the database and say the delete failed if the
2472 job still exists */
2473
2474 print_queue_update(msg_ctx, snum, True);
2475
2476 pjob = print_job_find(tmp_ctx, sharename, jobid);
2477 if (pjob && (pjob->status != LPQ_DELETING)) {
2478 werr = WERR_ACCESS_DENIED;
2479 goto err_out;
2480 }
2481 werr = WERR_PRINTER_HAS_JOBS_QUEUED;
2482
2483err_out:
2484 talloc_free(tmp_ctx);
2485 return werr;
2486}
2487
2488/****************************************************************************
2489 Pause a job.
2490****************************************************************************/
2491
2492WERROR print_job_pause(const struct auth_serversupplied_info *server_info,
2493 struct messaging_context *msg_ctx,
2494 int snum, uint32 jobid)
2495{
2496 const char* sharename = lp_const_servicename(snum);
2497 struct printjob *pjob;
2498 int ret = -1;
2499 struct printif *current_printif = get_printer_fns( snum );
2500 WERROR werr;
2501 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
2502 if (tmp_ctx == NULL) {
2503 return WERR_NOT_ENOUGH_MEMORY;
2504 }
2505
2506 pjob = print_job_find(tmp_ctx, sharename, jobid);
2507 if (!pjob || !server_info) {
2508 DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
2509 (unsigned int)jobid ));
2510 werr = WERR_INVALID_PARAM;
2511 goto err_out;
2512 }
2513
2514 if (!pjob->spooled || pjob->sysjob == -1) {
2515 DEBUG(10, ("print_job_pause: not spooled or bad sysjob = %d for jobid %u\n",
2516 (int)pjob->sysjob, (unsigned int)jobid ));
2517 werr = WERR_INVALID_PARAM;
2518 goto err_out;
2519 }
2520
2521 if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
2522 !print_access_check(server_info, msg_ctx, snum,
2523 JOB_ACCESS_ADMINISTER)) {
2524 DEBUG(3, ("pause denied by security descriptor\n"));
2525
2526 /* BEGIN_ADMIN_LOG */
2527 sys_adminlog( LOG_ERR,
2528 "Permission denied-- user not allowed to delete, \
2529pause, or resume print job. User name: %s. Printer name: %s.",
2530 uidtoname(server_info->utok.uid),
2531 lp_printername(snum) );
2532 /* END_ADMIN_LOG */
2533
2534 werr = WERR_ACCESS_DENIED;
2535 goto err_out;
2536 }
2537
2538 /* need to pause the spooled entry */
2539 ret = (*(current_printif->job_pause))(snum, pjob);
2540
2541 if (ret != 0) {
2542 werr = WERR_INVALID_PARAM;
2543 goto err_out;
2544 }
2545
2546 /* force update the database */
2547 print_cache_flush(lp_const_servicename(snum));
2548
2549 /* Send a printer notify message */
2550
2551 notify_job_status(server_event_context(), msg_ctx, sharename, jobid,
2552 JOB_STATUS_PAUSED);
2553
2554 /* how do we tell if this succeeded? */
2555 werr = WERR_OK;
2556err_out:
2557 talloc_free(tmp_ctx);
2558 return werr;
2559}
2560
2561/****************************************************************************
2562 Resume a job.
2563****************************************************************************/
2564
2565WERROR print_job_resume(const struct auth_serversupplied_info *server_info,
2566 struct messaging_context *msg_ctx,
2567 int snum, uint32 jobid)
2568{
2569 const char *sharename = lp_const_servicename(snum);
2570 struct printjob *pjob;
2571 int ret;
2572 struct printif *current_printif = get_printer_fns( snum );
2573 WERROR werr;
2574 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
2575 if (tmp_ctx == NULL)
2576 return WERR_NOT_ENOUGH_MEMORY;
2577
2578 pjob = print_job_find(tmp_ctx, sharename, jobid);
2579 if (!pjob || !server_info) {
2580 DEBUG(10, ("print_job_resume: no pjob or user for jobid %u\n",
2581 (unsigned int)jobid ));
2582 werr = WERR_INVALID_PARAM;
2583 goto err_out;
2584 }
2585
2586 if (!pjob->spooled || pjob->sysjob == -1) {
2587 DEBUG(10, ("print_job_resume: not spooled or bad sysjob = %d for jobid %u\n",
2588 (int)pjob->sysjob, (unsigned int)jobid ));
2589 werr = WERR_INVALID_PARAM;
2590 goto err_out;
2591 }
2592
2593 if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
2594 !print_access_check(server_info, msg_ctx, snum,
2595 JOB_ACCESS_ADMINISTER)) {
2596 DEBUG(3, ("resume denied by security descriptor\n"));
2597
2598 /* BEGIN_ADMIN_LOG */
2599 sys_adminlog( LOG_ERR,
2600 "Permission denied-- user not allowed to delete, \
2601pause, or resume print job. User name: %s. Printer name: %s.",
2602 uidtoname(server_info->utok.uid),
2603 lp_printername(snum) );
2604 /* END_ADMIN_LOG */
2605 werr = WERR_ACCESS_DENIED;
2606 goto err_out;
2607 }
2608
2609 ret = (*(current_printif->job_resume))(snum, pjob);
2610
2611 if (ret != 0) {
2612 werr = WERR_INVALID_PARAM;
2613 goto err_out;
2614 }
2615
2616 /* force update the database */
2617 print_cache_flush(lp_const_servicename(snum));
2618
2619 /* Send a printer notify message */
2620
2621 notify_job_status(server_event_context(), msg_ctx, sharename, jobid,
2622 JOB_STATUS_QUEUED);
2623
2624 werr = WERR_OK;
2625err_out:
2626 talloc_free(tmp_ctx);
2627 return werr;
2628}
2629
2630/****************************************************************************
2631 Write to a print file.
2632****************************************************************************/
2633
2634ssize_t print_job_write(struct tevent_context *ev,
2635 struct messaging_context *msg_ctx,
2636 int snum, uint32 jobid, const char *buf, size_t size)
2637{
2638 const char* sharename = lp_const_servicename(snum);
2639 ssize_t return_code;
2640 struct printjob *pjob;
2641 TALLOC_CTX *tmp_ctx = talloc_new(ev);
2642 if (tmp_ctx == NULL) {
2643 return -1;
2644 }
2645
2646 pjob = print_job_find(tmp_ctx, sharename, jobid);
2647 if (!pjob) {
2648 return_code = -1;
2649 goto err_out;
2650 }
2651
2652 /* don't allow another process to get this info - it is meaningless */
2653 if (pjob->pid != sys_getpid()) {
2654 return_code = -1;
2655 goto err_out;
2656 }
2657
2658 /* if SMBD is spooling this can't be allowed */
2659 if (pjob->status == PJOB_SMBD_SPOOLING) {
2660 return_code = -1;
2661 goto err_out;
2662 }
2663
2664 return_code = write_data(pjob->fd, buf, size);
2665 if (return_code > 0) {
2666 pjob->size += size;
2667 pjob_store(ev, msg_ctx, sharename, jobid, pjob);
2668 }
2669err_out:
2670 talloc_free(tmp_ctx);
2671 return return_code;
2672}
2673
2674/****************************************************************************
2675 Get the queue status - do not update if db is out of date.
2676****************************************************************************/
2677
2678static int get_queue_status(const char* sharename, print_status_struct *status)
2679{
2680 fstring keystr;
2681 TDB_DATA data;
2682 struct tdb_print_db *pdb = get_print_db_byname(sharename);
2683 int len;
2684
2685 if (status) {
2686 ZERO_STRUCTP(status);
2687 }
2688
2689 if (!pdb)
2690 return 0;
2691
2692 if (status) {
2693 fstr_sprintf(keystr, "STATUS/%s", sharename);
2694 data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
2695 if (data.dptr) {
2696 if (data.dsize == sizeof(print_status_struct))
2697 /* this memcpy is ok since the status struct was
2698 not packed before storing it in the tdb */
2699 memcpy(status, data.dptr, sizeof(print_status_struct));
2700 SAFE_FREE(data.dptr);
2701 }
2702 }
2703 len = tdb_fetch_int32(pdb->tdb, "INFO/total_jobs");
2704 release_print_db(pdb);
2705 return (len == -1 ? 0 : len);
2706}
2707
2708/****************************************************************************
2709 Determine the number of jobs in a queue.
2710****************************************************************************/
2711
2712int print_queue_length(struct messaging_context *msg_ctx, int snum,
2713 print_status_struct *pstatus)
2714{
2715 const char* sharename = lp_const_servicename( snum );
2716 print_status_struct status;
2717 int len;
2718
2719 ZERO_STRUCT( status );
2720
2721 /* make sure the database is up to date */
2722 if (print_cache_expired(lp_const_servicename(snum), True))
2723 print_queue_update(msg_ctx, snum, False);
2724
2725 /* also fetch the queue status */
2726 memset(&status, 0, sizeof(status));
2727 len = get_queue_status(sharename, &status);
2728
2729 if (pstatus)
2730 *pstatus = status;
2731
2732 return len;
2733}
2734
2735/***************************************************************************
2736 Allocate a jobid. Hold the lock for as short a time as possible.
2737***************************************************************************/
2738
2739static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
2740 const char *sharename, uint32 *pjobid)
2741{
2742 int i;
2743 uint32 jobid;
2744 enum TDB_ERROR terr;
2745 int ret;
2746
2747 *pjobid = (uint32)-1;
2748
2749 for (i = 0; i < 3; i++) {
2750 /* Lock the database - only wait 20 seconds. */
2751 ret = tdb_lock_bystring_with_timeout(pdb->tdb,
2752 "INFO/nextjob", 20);
2753 if (ret == -1) {
2754 DEBUG(0, ("allocate_print_jobid: "
2755 "Failed to lock printing database %s\n",
2756 sharename));
2757 terr = tdb_error(pdb->tdb);
2758 return ntstatus_to_werror(map_nt_error_from_tdb(terr));
2759 }
2760
2761 if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
2762 terr = tdb_error(pdb->tdb);
2763 if (terr != TDB_ERR_NOEXIST) {
2764 DEBUG(0, ("allocate_print_jobid: "
2765 "Failed to fetch INFO/nextjob "
2766 "for print queue %s\n", sharename));
2767 tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
2768 return ntstatus_to_werror(map_nt_error_from_tdb(terr));
2769 }
2770 DEBUG(10, ("allocate_print_jobid: "
2771 "No existing jobid in %s\n", sharename));
2772 jobid = 0;
2773 }
2774
2775 DEBUG(10, ("allocate_print_jobid: "
2776 "Read jobid %u from %s\n", jobid, sharename));
2777
2778 jobid = NEXT_JOBID(jobid);
2779
2780 ret = tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid);
2781 if (ret == -1) {
2782 terr = tdb_error(pdb->tdb);
2783 DEBUG(3, ("allocate_print_jobid: "
2784 "Failed to store INFO/nextjob.\n"));
2785 tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
2786 return ntstatus_to_werror(map_nt_error_from_tdb(terr));
2787 }
2788
2789 /* We've finished with the INFO/nextjob lock. */
2790 tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
2791
2792 if (!print_job_exists(sharename, jobid)) {
2793 break;
2794 }
2795 DEBUG(10, ("allocate_print_jobid: "
2796 "Found jobid %u in %s\n", jobid, sharename));
2797 }
2798
2799 if (i > 2) {
2800 DEBUG(0, ("allocate_print_jobid: "
2801 "Failed to allocate a print job for queue %s\n",
2802 sharename));
2803 /* Probably full... */
2804 return WERR_NO_SPOOL_SPACE;
2805 }
2806
2807 /* Store a dummy placeholder. */
2808 {
2809 uint32_t tmp;
2810 TDB_DATA dum;
2811 dum.dptr = NULL;
2812 dum.dsize = 0;
2813 if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
2814 TDB_INSERT) == -1) {
2815 DEBUG(3, ("allocate_print_jobid: "
2816 "jobid (%d) failed to store placeholder.\n",
2817 jobid ));
2818 terr = tdb_error(pdb->tdb);
2819 return ntstatus_to_werror(map_nt_error_from_tdb(terr));
2820 }
2821 }
2822
2823 *pjobid = jobid;
2824 return WERR_OK;
2825}
2826
2827/***************************************************************************
2828 Append a jobid to the 'jobs added' list.
2829***************************************************************************/
2830
2831static bool add_to_jobs_added(struct tdb_print_db *pdb, uint32 jobid)
2832{
2833 TDB_DATA data;
2834 uint32 store_jobid;
2835
2836 SIVAL(&store_jobid, 0, jobid);
2837 data.dptr = (uint8 *)&store_jobid;
2838 data.dsize = 4;
2839
2840 DEBUG(10,("add_to_jobs_added: Added jobid %u\n", (unsigned int)jobid ));
2841
2842 return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_added"),
2843 data) == 0);
2844}
2845
2846
2847/***************************************************************************
2848 Do all checks needed to determine if we can start a job.
2849***************************************************************************/
2850
2851static WERROR print_job_checks(const struct auth_serversupplied_info *server_info,
2852 struct messaging_context *msg_ctx,
2853 int snum, int *njobs)
2854{
2855 const char *sharename = lp_const_servicename(snum);
2856 uint64_t dspace, dsize;
2857 uint64_t minspace;
2858 int ret;
2859
2860 if (!print_access_check(server_info, msg_ctx, snum,
2861 PRINTER_ACCESS_USE)) {
2862 DEBUG(3, ("print_job_checks: "
2863 "job start denied by security descriptor\n"));
2864 return WERR_ACCESS_DENIED;
2865 }
2866
2867 if (!print_time_access_check(server_info, msg_ctx, sharename)) {
2868 DEBUG(3, ("print_job_checks: "
2869 "job start denied by time check\n"));
2870 return WERR_ACCESS_DENIED;
2871 }
2872
2873 /* see if we have sufficient disk space */
2874 if (lp_minprintspace(snum)) {
2875 minspace = lp_minprintspace(snum);
2876 ret = sys_fsusage(lp_pathname(snum), &dspace, &dsize);
2877 if (ret == 0 && dspace < 2*minspace) {
2878 DEBUG(3, ("print_job_checks: "
2879 "disk space check failed.\n"));
2880 return WERR_NO_SPOOL_SPACE;
2881 }
2882 }
2883
2884 /* for autoloaded printers, check that the printcap entry still exists */
2885 if (lp_autoloaded(snum) && !pcap_printername_ok(sharename)) {
2886 DEBUG(3, ("print_job_checks: printer name %s check failed.\n",
2887 sharename));
2888 return WERR_ACCESS_DENIED;
2889 }
2890
2891 /* Insure the maximum queue size is not violated */
2892 *njobs = print_queue_length(msg_ctx, snum, NULL);
2893 if (*njobs > lp_maxprintjobs(snum)) {
2894 DEBUG(3, ("print_job_checks: Queue %s number of jobs (%d) "
2895 "larger than max printjobs per queue (%d).\n",
2896 sharename, *njobs, lp_maxprintjobs(snum)));
2897 return WERR_NO_SPOOL_SPACE;
2898 }
2899
2900 return WERR_OK;
2901}
2902
2903/***************************************************************************
2904 Create a job file.
2905***************************************************************************/
2906
2907static WERROR print_job_spool_file(int snum, uint32_t jobid,
2908 const char *output_file,
2909 struct printjob *pjob)
2910{
2911 WERROR werr;
2912 SMB_STRUCT_STAT st;
2913 const char *path;
2914 int len;
2915
2916 /* if this file is within the printer path, it means that smbd
2917 * is spooling it and will pass us control when it is finished.
2918 * Verify that the file name is ok, within path, and it is
2919 * already already there */
2920 if (output_file) {
2921 path = lp_pathname(snum);
2922 len = strlen(path);
2923 if (strncmp(output_file, path, len) == 0 &&
2924 (output_file[len - 1] == '/' || output_file[len] == '/')) {
2925
2926 /* verify path is not too long */
2927 if (strlen(output_file) >= sizeof(pjob->filename)) {
2928 return WERR_INVALID_NAME;
2929 }
2930
2931 /* verify that the file exists */
2932 if (sys_stat(output_file, &st, false) != 0) {
2933 return WERR_INVALID_NAME;
2934 }
2935
2936 fstrcpy(pjob->filename, output_file);
2937
2938 DEBUG(3, ("print_job_spool_file:"
2939 "External spooling activated"));
2940
2941 /* we do not open the file until spooling is done */
2942 pjob->fd = -1;
2943 pjob->status = PJOB_SMBD_SPOOLING;
2944
2945 return WERR_OK;
2946 }
2947 }
2948
2949 slprintf(pjob->filename, sizeof(pjob->filename)-1,
2950 "%s/%sXXXXXX", lp_pathname(snum), PRINT_SPOOL_PREFIX);
2951 pjob->fd = mkstemp(pjob->filename);
2952
2953 if (pjob->fd == -1) {
2954 werr = map_werror_from_unix(errno);
2955 if (W_ERROR_EQUAL(werr, WERR_ACCESS_DENIED)) {
2956 /* Common setup error, force a report. */
2957 DEBUG(0, ("print_job_spool_file: "
2958 "insufficient permissions to open spool "
2959 "file %s.\n", pjob->filename));
2960 } else {
2961 /* Normal case, report at level 3 and above. */
2962 DEBUG(3, ("print_job_spool_file: "
2963 "can't open spool file %s\n",
2964 pjob->filename));
2965 }
2966 return werr;
2967 }
2968
2969 return WERR_OK;
2970}
2971
2972/***************************************************************************
2973 Start spooling a job - return the jobid.
2974***************************************************************************/
2975
2976WERROR print_job_start(const struct auth_serversupplied_info *server_info,
2977 struct messaging_context *msg_ctx,
2978 const char *clientmachine,
2979 int snum, const char *docname, const char *filename,
2980 struct spoolss_DeviceMode *devmode, uint32_t *_jobid)
2981{
2982 uint32_t jobid;
2983 char *path;
2984 struct printjob pjob;
2985 const char *sharename = lp_const_servicename(snum);
2986 struct tdb_print_db *pdb = get_print_db_byname(sharename);
2987 int njobs;
2988 WERROR werr;
2989
2990 if (!pdb) {
2991 return WERR_INTERNAL_DB_CORRUPTION;
2992 }
2993
2994 path = lp_pathname(snum);
2995
2996 werr = print_job_checks(server_info, msg_ctx, snum, &njobs);
2997 if (!W_ERROR_IS_OK(werr)) {
2998 release_print_db(pdb);
2999 return werr;
3000 }
3001
3002 DEBUG(10, ("print_job_start: "
3003 "Queue %s number of jobs (%d), max printjobs = %d\n",
3004 sharename, njobs, lp_maxprintjobs(snum)));
3005
3006 werr = allocate_print_jobid(pdb, snum, sharename, &jobid);
3007 if (!W_ERROR_IS_OK(werr)) {
3008 goto fail;
3009 }
3010
3011 /* create the database entry */
3012
3013 ZERO_STRUCT(pjob);
3014
3015 pjob.pid = sys_getpid();
3016 pjob.jobid = jobid;
3017 pjob.sysjob = -1;
3018 pjob.fd = -1;
3019 pjob.starttime = time(NULL);
3020 pjob.status = LPQ_SPOOLING;
3021 pjob.size = 0;
3022 pjob.spooled = False;
3023 pjob.smbjob = True;
3024 pjob.devmode = devmode;
3025
3026 fstrcpy(pjob.jobname, docname);
3027
3028 fstrcpy(pjob.clientmachine, clientmachine);
3029
3030 fstrcpy(pjob.user, lp_printjob_username(snum));
3031 standard_sub_advanced(sharename, server_info->sanitized_username,
3032 path, server_info->utok.gid,
3033 server_info->sanitized_username,
3034 server_info->info3->base.domain.string,
3035 pjob.user, sizeof(pjob.user)-1);
3036 /* ensure NULL termination */
3037 pjob.user[sizeof(pjob.user)-1] = '\0';
3038
3039 fstrcpy(pjob.queuename, lp_const_servicename(snum));
3040
3041 /* we have a job entry - now create the spool file */
3042 werr = print_job_spool_file(snum, jobid, filename, &pjob);
3043 if (!W_ERROR_IS_OK(werr)) {
3044 goto fail;
3045 }
3046
3047 pjob_store(server_event_context(), msg_ctx, sharename, jobid, &pjob);
3048
3049 /* Update the 'jobs added' entry used by print_queue_status. */
3050 add_to_jobs_added(pdb, jobid);
3051
3052 /* Ensure we keep a rough count of the number of total jobs... */
3053 tdb_change_int32_atomic(pdb->tdb, "INFO/total_jobs", &njobs, 1);
3054
3055 release_print_db(pdb);
3056
3057 *_jobid = jobid;
3058 return WERR_OK;
3059
3060fail:
3061 if (jobid != -1) {
3062 pjob_delete(server_event_context(), msg_ctx, sharename, jobid);
3063 }
3064
3065 release_print_db(pdb);
3066
3067 DEBUG(3, ("print_job_start: returning fail. "
3068 "Error = %s\n", win_errstr(werr)));
3069 return werr;
3070}
3071
3072/****************************************************************************
3073 Update the number of pages spooled to jobid
3074****************************************************************************/
3075
3076void print_job_endpage(struct messaging_context *msg_ctx,
3077 int snum, uint32 jobid)
3078{
3079 const char* sharename = lp_const_servicename(snum);
3080 struct printjob *pjob;
3081 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
3082 if (tmp_ctx == NULL) {
3083 return;
3084 }
3085
3086 pjob = print_job_find(tmp_ctx, sharename, jobid);
3087 if (!pjob) {
3088 goto err_out;
3089 }
3090 /* don't allow another process to get this info - it is meaningless */
3091 if (pjob->pid != sys_getpid()) {
3092 goto err_out;
3093 }
3094
3095 pjob->page_count++;
3096 pjob_store(server_event_context(), msg_ctx, sharename, jobid, pjob);
3097err_out:
3098 talloc_free(tmp_ctx);
3099}
3100
3101/****************************************************************************
3102 Print a file - called on closing the file. This spools the job.
3103 If normal close is false then we're tearing down the jobs - treat as an
3104 error.
3105****************************************************************************/
3106
3107NTSTATUS print_job_end(struct messaging_context *msg_ctx, int snum,
3108 uint32 jobid, enum file_close_type close_type)
3109{
3110 const char* sharename = lp_const_servicename(snum);
3111 struct printjob *pjob;
3112 int ret;
3113 SMB_STRUCT_STAT sbuf;
3114 struct printif *current_printif = get_printer_fns(snum);
3115 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3116 char *lpq_cmd;
3117 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
3118 if (tmp_ctx == NULL) {
3119 return NT_STATUS_NO_MEMORY;
3120 }
3121
3122 pjob = print_job_find(tmp_ctx, sharename, jobid);
3123 if (!pjob) {
3124 status = NT_STATUS_PRINT_CANCELLED;
3125 goto err_out;
3126 }
3127
3128 if (pjob->spooled || pjob->pid != sys_getpid()) {
3129 status = NT_STATUS_ACCESS_DENIED;
3130 goto err_out;
3131 }
3132
3133 if (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) {
3134 if (pjob->status == PJOB_SMBD_SPOOLING) {
3135 /* take over the file now, smbd is done */
3136 if (sys_stat(pjob->filename, &sbuf, false) != 0) {
3137 status = map_nt_error_from_unix(errno);
3138 DEBUG(3, ("print_job_end: "
3139 "stat file failed for jobid %d\n",
3140 jobid));
3141 goto fail;
3142 }
3143
3144 pjob->status = LPQ_SPOOLING;
3145
3146 } else {
3147
3148 if ((sys_fstat(pjob->fd, &sbuf, false) != 0)) {
3149 status = map_nt_error_from_unix(errno);
3150 close(pjob->fd);
3151 DEBUG(3, ("print_job_end: "
3152 "stat file failed for jobid %d\n",
3153 jobid));
3154 goto fail;
3155 }
3156
3157 close(pjob->fd);
3158 }
3159
3160 pjob->size = sbuf.st_ex_size;
3161 } else {
3162
3163 /*
3164 * Not a normal close, something has gone wrong. Cleanup.
3165 */
3166 if (pjob->fd != -1) {
3167 close(pjob->fd);
3168 }
3169 goto fail;
3170 }
3171
3172 /* Technically, this is not quite right. If the printer has a separator
3173 * page turned on, the NT spooler prints the separator page even if the
3174 * print job is 0 bytes. 010215 JRR */
3175 if (pjob->size == 0 || pjob->status == LPQ_DELETING) {
3176 /* don't bother spooling empty files or something being deleted. */
3177 DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
3178 pjob->filename, pjob->size ? "deleted" : "zero length" ));
3179 unlink(pjob->filename);
3180 pjob_delete(server_event_context(), msg_ctx, sharename, jobid);
3181 return NT_STATUS_OK;
3182 }
3183
3184 /* don't strip out characters like '$' from the printername */
3185 lpq_cmd = talloc_string_sub2(tmp_ctx,
3186 lp_lpqcommand(snum),
3187 "%p",
3188 lp_printername(snum),
3189 false, false, false);
3190 if (lpq_cmd == NULL) {
3191 status = NT_STATUS_PRINT_CANCELLED;
3192 goto fail;
3193 }
3194 lpq_cmd = talloc_sub_advanced(tmp_ctx,
3195 lp_servicename(snum),
3196 current_user_info.unix_name,
3197 "",
3198 current_user.ut.gid,
3199 get_current_username(),
3200 current_user_info.domain,
3201 lpq_cmd);
3202 if (lpq_cmd == NULL) {
3203 status = NT_STATUS_PRINT_CANCELLED;
3204 goto fail;
3205 }
3206
3207 ret = (*(current_printif->job_submit))(snum, pjob,
3208 current_printif->type, lpq_cmd);
3209 if (ret) {
3210 status = NT_STATUS_PRINT_CANCELLED;
3211 goto fail;
3212 }
3213
3214 /* The print job has been successfully handed over to the back-end */
3215
3216 pjob->spooled = True;
3217 pjob->status = LPQ_QUEUED;
3218 pjob_store(server_event_context(), msg_ctx, sharename, jobid, pjob);
3219
3220 /* make sure the database is up to date */
3221 if (print_cache_expired(lp_const_servicename(snum), True))
3222 print_queue_update(msg_ctx, snum, False);
3223
3224 return NT_STATUS_OK;
3225
3226fail:
3227
3228 /* The print job was not successfully started. Cleanup */
3229 /* Still need to add proper error return propagation! 010122:JRR */
3230 pjob->fd = -1;
3231 unlink(pjob->filename);
3232 pjob_delete(server_event_context(), msg_ctx, sharename, jobid);
3233err_out:
3234 talloc_free(tmp_ctx);
3235 return status;
3236}
3237
3238/****************************************************************************
3239 Get a snapshot of jobs in the system without traversing.
3240****************************************************************************/
3241
3242static bool get_stored_queue_info(struct messaging_context *msg_ctx,
3243 struct tdb_print_db *pdb, int snum,
3244 int *pcount, print_queue_struct **ppqueue)
3245{
3246 TDB_DATA data, cgdata, jcdata;
3247 print_queue_struct *queue = NULL;
3248 uint32 qcount = 0;
3249 uint32 extra_count = 0;
3250 uint32_t changed_count = 0;
3251 int total_count = 0;
3252 size_t len = 0;
3253 uint32 i;
3254 int max_reported_jobs = lp_max_reported_jobs(snum);
3255 bool ret = False;
3256 const char* sharename = lp_servicename(snum);
3257 TALLOC_CTX *tmp_ctx = talloc_new(msg_ctx);
3258 if (tmp_ctx == NULL) {
3259 return false;
3260 }
3261
3262 /* make sure the database is up to date */
3263 if (print_cache_expired(lp_const_servicename(snum), True))
3264 print_queue_update(msg_ctx, snum, False);
3265
3266 *pcount = 0;
3267 *ppqueue = NULL;
3268
3269 ZERO_STRUCT(data);
3270 ZERO_STRUCT(cgdata);
3271
3272 /* Get the stored queue data. */
3273 data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
3274
3275 if (data.dptr && data.dsize >= sizeof(qcount))
3276 len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
3277
3278 /* Get the added jobs list. */
3279 cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_added"));
3280 if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
3281 extra_count = cgdata.dsize/4;
3282
3283 /* Get the changed jobs list. */
3284 jcdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
3285 if (jcdata.dptr != NULL && (jcdata.dsize % 4 == 0))
3286 changed_count = jcdata.dsize / 4;
3287
3288 DEBUG(5,("get_stored_queue_info: qcount = %u, extra_count = %u\n", (unsigned int)qcount, (unsigned int)extra_count));
3289
3290 /* Allocate the queue size. */
3291 if (qcount == 0 && extra_count == 0)
3292 goto out;
3293
3294 if ((queue = SMB_MALLOC_ARRAY(print_queue_struct, qcount + extra_count)) == NULL)
3295 goto out;
3296
3297 /* Retrieve the linearised queue data. */
3298
3299 for( i = 0; i < qcount; i++) {
3300 uint32 qjob, qsize, qpage_count, qstatus, qpriority, qtime;
3301 len += tdb_unpack(data.dptr + len, data.dsize - len, "ddddddff",
3302 &qjob,
3303 &qsize,
3304 &qpage_count,
3305 &qstatus,
3306 &qpriority,
3307 &qtime,
3308 queue[i].fs_user,
3309 queue[i].fs_file);
3310 queue[i].sysjob = qjob;
3311 queue[i].size = qsize;
3312 queue[i].page_count = qpage_count;
3313 queue[i].status = qstatus;
3314 queue[i].priority = qpriority;
3315 queue[i].time = qtime;
3316 }
3317
3318 total_count = qcount;
3319
3320 /* Add new jobids to the queue. */
3321 for( i = 0; i < extra_count; i++) {
3322 uint32 jobid;
3323 struct printjob *pjob;
3324
3325 jobid = IVAL(cgdata.dptr, i*4);
3326 DEBUG(5,("get_stored_queue_info: added job = %u\n", (unsigned int)jobid));
3327 pjob = print_job_find(tmp_ctx, lp_const_servicename(snum), jobid);
3328 if (!pjob) {
3329 DEBUG(5,("get_stored_queue_info: failed to find added job = %u\n", (unsigned int)jobid));
3330 remove_from_jobs_added(sharename, jobid);
3331 continue;
3332 }
3333
3334 queue[total_count].sysjob = jobid;
3335 queue[total_count].size = pjob->size;
3336 queue[total_count].page_count = pjob->page_count;
3337 queue[total_count].status = pjob->status;
3338 queue[total_count].priority = 1;
3339 queue[total_count].time = pjob->starttime;
3340 fstrcpy(queue[total_count].fs_user, pjob->user);
3341 fstrcpy(queue[total_count].fs_file, pjob->jobname);
3342 total_count++;
3343 talloc_free(pjob);
3344 }
3345
3346 /* Update the changed jobids. */
3347 for (i = 0; i < changed_count; i++) {
3348 uint32_t jobid = IVAL(jcdata.dptr, i * 4);
3349 uint32_t j;
3350 bool found = false;
3351
3352 for (j = 0; j < total_count; j++) {
3353 if (queue[j].sysjob == jobid) {
3354 found = true;
3355 break;
3356 }
3357 }
3358
3359 if (found) {
3360 struct printjob *pjob;
3361
3362 DEBUG(5,("get_stored_queue_info: changed job: %u\n",
3363 (unsigned int) jobid));
3364
3365 pjob = print_job_find(tmp_ctx, sharename, jobid);
3366 if (pjob == NULL) {
3367 DEBUG(5,("get_stored_queue_info: failed to find "
3368 "changed job = %u\n",
3369 (unsigned int) jobid));
3370 remove_from_jobs_changed(sharename, jobid);
3371 continue;
3372 }
3373
3374 queue[j].sysjob = jobid;
3375 queue[j].size = pjob->size;
3376 queue[j].page_count = pjob->page_count;
3377 queue[j].status = pjob->status;
3378 queue[j].priority = 1;
3379 queue[j].time = pjob->starttime;
3380 fstrcpy(queue[j].fs_user, pjob->user);
3381 fstrcpy(queue[j].fs_file, pjob->jobname);
3382 talloc_free(pjob);
3383
3384 DEBUG(5,("get_stored_queue_info: updated queue[%u], jobid: %u, jobname: %s\n",
3385 (unsigned int) j, (unsigned int) jobid, pjob->jobname));
3386 }
3387
3388 remove_from_jobs_changed(sharename, jobid);
3389 }
3390
3391 /* Sort the queue by submission time otherwise they are displayed
3392 in hash order. */
3393
3394 TYPESAFE_QSORT(queue, total_count, printjob_comp);
3395
3396 DEBUG(5,("get_stored_queue_info: total_count = %u\n", (unsigned int)total_count));
3397
3398 if (max_reported_jobs && total_count > max_reported_jobs)
3399 total_count = max_reported_jobs;
3400
3401 *ppqueue = queue;
3402 *pcount = total_count;
3403
3404 ret = True;
3405
3406 out:
3407
3408 SAFE_FREE(data.dptr);
3409 SAFE_FREE(cgdata.dptr);
3410 talloc_free(tmp_ctx);
3411 return ret;
3412}
3413
3414/****************************************************************************
3415 Get a printer queue listing.
3416 set queue = NULL and status = NULL if you just want to update the cache
3417****************************************************************************/
3418
3419int print_queue_status(struct messaging_context *msg_ctx, int snum,
3420 print_queue_struct **ppqueue,
3421 print_status_struct *status)
3422{
3423 fstring keystr;
3424 TDB_DATA data, key;
3425 const char *sharename;
3426 struct tdb_print_db *pdb;
3427 int count = 0;
3428
3429 /* make sure the database is up to date */
3430
3431 if (print_cache_expired(lp_const_servicename(snum), True))
3432 print_queue_update(msg_ctx, snum, False);
3433
3434 /* return if we are done */
3435 if ( !ppqueue || !status )
3436 return 0;
3437
3438 *ppqueue = NULL;
3439 sharename = lp_const_servicename(snum);
3440 pdb = get_print_db_byname(sharename);
3441
3442 if (!pdb)
3443 return 0;
3444
3445 /*
3446 * Fetch the queue status. We must do this first, as there may
3447 * be no jobs in the queue.
3448 */
3449
3450 ZERO_STRUCTP(status);
3451 slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", sharename);
3452 key = string_tdb_data(keystr);
3453
3454 data = tdb_fetch(pdb->tdb, key);
3455 if (data.dptr) {
3456 if (data.dsize == sizeof(*status)) {
3457 /* this memcpy is ok since the status struct was
3458 not packed before storing it in the tdb */
3459 memcpy(status, data.dptr, sizeof(*status));
3460 }
3461 SAFE_FREE(data.dptr);
3462 }
3463
3464 /*
3465 * Now, fetch the print queue information. We first count the number
3466 * of entries, and then only retrieve the queue if necessary.
3467 */
3468
3469 if (!get_stored_queue_info(msg_ctx, pdb, snum, &count, ppqueue)) {
3470 release_print_db(pdb);
3471 return 0;
3472 }
3473
3474 release_print_db(pdb);
3475 return count;
3476}
3477
3478/****************************************************************************
3479 Pause a queue.
3480****************************************************************************/
3481
3482WERROR print_queue_pause(const struct auth_serversupplied_info *server_info,
3483 struct messaging_context *msg_ctx, int snum)
3484{
3485 int ret;
3486 struct printif *current_printif = get_printer_fns( snum );
3487
3488 if (!print_access_check(server_info, msg_ctx, snum,
3489 PRINTER_ACCESS_ADMINISTER)) {
3490 return WERR_ACCESS_DENIED;
3491 }
3492
3493
3494 become_root();
3495
3496 ret = (*(current_printif->queue_pause))(snum);
3497
3498 unbecome_root();
3499
3500 if (ret != 0) {
3501 return WERR_INVALID_PARAM;
3502 }
3503
3504 /* force update the database */
3505 print_cache_flush(lp_const_servicename(snum));
3506
3507 /* Send a printer notify message */
3508
3509 notify_printer_status(server_event_context(), msg_ctx, snum,
3510 PRINTER_STATUS_PAUSED);
3511
3512 return WERR_OK;
3513}
3514
3515/****************************************************************************
3516 Resume a queue.
3517****************************************************************************/
3518
3519WERROR print_queue_resume(const struct auth_serversupplied_info *server_info,
3520 struct messaging_context *msg_ctx, int snum)
3521{
3522 int ret;
3523 struct printif *current_printif = get_printer_fns( snum );
3524
3525 if (!print_access_check(server_info, msg_ctx, snum,
3526 PRINTER_ACCESS_ADMINISTER)) {
3527 return WERR_ACCESS_DENIED;
3528 }
3529
3530 become_root();
3531
3532 ret = (*(current_printif->queue_resume))(snum);
3533
3534 unbecome_root();
3535
3536 if (ret != 0) {
3537 return WERR_INVALID_PARAM;
3538 }
3539
3540 /* make sure the database is up to date */
3541 if (print_cache_expired(lp_const_servicename(snum), True))
3542 print_queue_update(msg_ctx, snum, True);
3543
3544 /* Send a printer notify message */
3545
3546 notify_printer_status(server_event_context(), msg_ctx, snum,
3547 PRINTER_STATUS_OK);
3548
3549 return WERR_OK;
3550}
3551
3552/****************************************************************************
3553 Purge a queue - implemented by deleting all jobs that we can delete.
3554****************************************************************************/
3555
3556WERROR print_queue_purge(const struct auth_serversupplied_info *server_info,
3557 struct messaging_context *msg_ctx, int snum)
3558{
3559 print_queue_struct *queue;
3560 print_status_struct status;
3561 int njobs, i;
3562 bool can_job_admin;
3563
3564 /* Force and update so the count is accurate (i.e. not a cached count) */
3565 print_queue_update(msg_ctx, snum, True);
3566
3567 can_job_admin = print_access_check(server_info,
3568 msg_ctx,
3569 snum,
3570 JOB_ACCESS_ADMINISTER);
3571 njobs = print_queue_status(msg_ctx, snum, &queue, &status);
3572
3573 if ( can_job_admin )
3574 become_root();
3575
3576 for (i=0;i<njobs;i++) {
3577 bool owner = is_owner(server_info, lp_const_servicename(snum),
3578 queue[i].sysjob);
3579
3580 if (owner || can_job_admin) {
3581 print_job_delete1(server_event_context(), msg_ctx,
3582 snum, queue[i].sysjob);
3583 }
3584 }
3585
3586 if ( can_job_admin )
3587 unbecome_root();
3588
3589 /* update the cache */
3590 print_queue_update(msg_ctx, snum, True);
3591
3592 SAFE_FREE(queue);
3593
3594 return WERR_OK;
3595}
Note: See TracBrowser for help on using the repository browser.