Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * RPC Pipe client / server routines
4 : * Copyright (C) Andrew Tridgell 1992-2000,
5 : * Copyright (C) Jean François Micouleau 1998-2000.
6 : * Copyright (C) Gerald Carter 2002-2005.
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 "printing/nt_printing_tdb.h"
24 : #include "printing/queue_process.h"
25 : #include "../librpc/gen_ndr/ndr_spoolss.h"
26 : #include "rpc_server/spoolss/srv_spoolss_util.h"
27 : #include "nt_printing.h"
28 : #include "secrets.h"
29 : #include "../librpc/gen_ndr/netlogon.h"
30 : #include "../libcli/security/security.h"
31 : #include "passdb/machine_sid.h"
32 : #include "smbd/smbd.h"
33 : #include "auth.h"
34 : #include "messages.h"
35 : #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 : #include "rpc_client/cli_winreg_spoolss.h"
37 : #include "lib/util/string_wrappers.h"
38 : #include "lib/global_contexts.h"
39 :
40 : /* Map generic permissions to printer object specific permissions */
41 :
42 : const struct generic_mapping printer_generic_mapping = {
43 : PRINTER_READ,
44 : PRINTER_WRITE,
45 : PRINTER_EXECUTE,
46 : PRINTER_ALL_ACCESS
47 : };
48 :
49 : /* Map generic permissions to print server object specific permissions */
50 :
51 : const struct generic_mapping printserver_generic_mapping = {
52 : SERVER_READ,
53 : SERVER_WRITE,
54 : SERVER_EXECUTE,
55 : SERVER_ALL_ACCESS
56 : };
57 :
58 : /* Map generic permissions to job object specific permissions */
59 :
60 : const struct generic_mapping job_generic_mapping = {
61 : JOB_READ,
62 : JOB_WRITE,
63 : JOB_EXECUTE,
64 : JOB_ALL_ACCESS
65 : };
66 :
67 28 : static bool print_driver_directories_init(void)
68 : {
69 0 : int service;
70 0 : size_t i;
71 0 : char *driver_path;
72 0 : bool ok;
73 28 : TALLOC_CTX *mem_ctx = talloc_stackframe();
74 0 : const struct loadparm_substitution *lp_sub =
75 28 : loadparm_s3_global_substitution();
76 :
77 28 : const char *dir_list[] = {
78 : "W32X86/PCC",
79 : "x64/PCC",
80 : "ARM64",
81 : "color"
82 : };
83 :
84 28 : service = lp_servicenumber("print$");
85 28 : if (service < 0) {
86 : /* We don't have a print$ share */
87 0 : DEBUG(5, ("No print$ share has been configured.\n"));
88 0 : talloc_free(mem_ctx);
89 0 : return true;
90 : }
91 :
92 28 : driver_path = lp_path(mem_ctx, lp_sub, service);
93 28 : if (driver_path == NULL) {
94 0 : talloc_free(mem_ctx);
95 0 : return false;
96 : }
97 :
98 28 : ok = directory_create_or_exist(driver_path, 0755);
99 28 : if (!ok) {
100 0 : DEBUG(1, ("Failed to create printer driver directory %s\n",
101 : driver_path));
102 0 : talloc_free(mem_ctx);
103 0 : return false;
104 : }
105 :
106 280 : for (i = 0; archi_table[i].long_archi != NULL; i++) {
107 0 : const char *arch_path;
108 :
109 252 : arch_path = talloc_asprintf(mem_ctx,
110 : "%s/%s",
111 : driver_path,
112 252 : archi_table[i].short_archi);
113 252 : if (arch_path == NULL) {
114 0 : talloc_free(mem_ctx);
115 0 : return false;
116 : }
117 :
118 252 : ok = directory_create_or_exist(arch_path, 0755);
119 252 : if (!ok) {
120 0 : DEBUG(1, ("Failed to create printer driver "
121 : "architecture directory %s\n",
122 : arch_path));
123 0 : talloc_free(mem_ctx);
124 0 : return false;
125 : }
126 : }
127 :
128 140 : for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
129 0 : const char *path;
130 :
131 112 : path = talloc_asprintf(mem_ctx,
132 : "%s/%s",
133 : driver_path,
134 : dir_list[i]);
135 112 : if (path == NULL) {
136 0 : talloc_free(mem_ctx);
137 0 : return false;
138 : }
139 :
140 112 : ok = directory_create_or_exist(path, 0755);
141 112 : if (!ok) {
142 0 : DEBUG(1, ("Failed to create printer driver "
143 : "architecture directory %s\n",
144 : path));
145 0 : talloc_free(mem_ctx);
146 0 : return false;
147 : }
148 : }
149 :
150 28 : driver_path = state_path(talloc_tos(), "DriverStore");
151 28 : if (driver_path == NULL) {
152 0 : talloc_free(mem_ctx);
153 0 : return false;
154 : }
155 :
156 28 : ok = directory_create_or_exist(driver_path, 0755);
157 28 : if (!ok) {
158 0 : DEBUG(1,("failed to create path %s\n", driver_path));
159 0 : talloc_free(mem_ctx);
160 0 : return false;
161 : }
162 :
163 28 : driver_path = state_path(talloc_tos(), "DriverStore/FileRepository");
164 28 : if (driver_path == NULL) {
165 0 : talloc_free(mem_ctx);
166 0 : return false;
167 : }
168 :
169 28 : ok = directory_create_or_exist(driver_path, 0755);
170 28 : if (!ok) {
171 0 : DEBUG(1,("failed to create path %s\n", driver_path));
172 0 : talloc_free(mem_ctx);
173 0 : return false;
174 : }
175 :
176 28 : driver_path = state_path(talloc_tos(), "DriverStore/Temp");
177 28 : if (driver_path == NULL) {
178 0 : talloc_free(mem_ctx);
179 0 : return false;
180 : }
181 :
182 28 : ok = directory_create_or_exist(driver_path, 0755);
183 28 : if (!ok) {
184 0 : DEBUG(1,("failed to create path %s\n", driver_path));
185 0 : talloc_free(mem_ctx);
186 0 : return false;
187 : }
188 :
189 28 : talloc_free(mem_ctx);
190 28 : return true;
191 : }
192 :
193 : /****************************************************************************
194 : Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
195 : background lpq updater.
196 : ****************************************************************************/
197 :
198 0 : static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
199 : void *private_data,
200 : uint32_t msg_type,
201 : struct server_id server_id,
202 : DATA_BLOB *data)
203 : {
204 0 : send_to_bgqd(msg, msg_type, data->data, data->length);
205 0 : }
206 :
207 : /****************************************************************************
208 : Open the NT printing tdbs. Done once before fork().
209 : ****************************************************************************/
210 :
211 28 : bool nt_printing_init(struct messaging_context *msg_ctx)
212 : {
213 0 : WERROR win_rc;
214 :
215 28 : if (!print_driver_directories_init()) {
216 0 : return false;
217 : }
218 :
219 28 : if (!nt_printing_tdb_upgrade()) {
220 0 : return false;
221 : }
222 :
223 : /*
224 : * register callback to handle updating printers as new
225 : * drivers are installed. Forwards to background lpq updater.
226 : */
227 28 : messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
228 : forward_drv_upgrade_printer_msg);
229 :
230 28 : if ( lp_security() == SEC_ADS ) {
231 2 : win_rc = check_published_printers(msg_ctx);
232 2 : if (!W_ERROR_IS_OK(win_rc))
233 0 : DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
234 : }
235 :
236 28 : return true;
237 : }
238 :
239 : /*******************************************************************
240 : Function to allow filename parsing "the old way".
241 : ********************************************************************/
242 :
243 0 : static NTSTATUS driver_unix_convert(connection_struct *conn,
244 : const char *old_name,
245 : struct files_struct **pdirfsp,
246 : struct smb_filename **psmb_fname)
247 : {
248 0 : NTSTATUS status;
249 0 : TALLOC_CTX *ctx = talloc_tos();
250 0 : char *name = talloc_strdup(ctx, old_name);
251 :
252 0 : if (!name) {
253 0 : return NT_STATUS_NO_MEMORY;
254 : }
255 0 : unix_format(name);
256 0 : name = unix_clean_name(ctx, name);
257 0 : if (!name) {
258 0 : return NT_STATUS_NO_MEMORY;
259 : }
260 0 : trim_string(name,"/","/");
261 :
262 0 : status = filename_convert_dirfsp(ctx,
263 : conn,
264 : name,
265 : 0, /* ucf_flags */
266 : 0, /* twrp */
267 : pdirfsp,
268 : psmb_fname);
269 0 : if (!NT_STATUS_IS_OK(status)) {
270 0 : return status;
271 : }
272 :
273 0 : return NT_STATUS_OK;
274 : }
275 :
276 : /****************************************************************************
277 : Function to do the mapping between the long architecture name and
278 : the short one.
279 : ****************************************************************************/
280 :
281 256 : const char *get_short_archi(const char *long_archi)
282 : {
283 256 : int i=-1;
284 :
285 256 : DEBUG(107,("Getting architecture dependent directory\n"));
286 0 : do {
287 1656 : i++;
288 1908 : } while ( (archi_table[i].long_archi!=NULL ) &&
289 1652 : strcasecmp_m(long_archi, archi_table[i].long_archi) );
290 :
291 256 : if (archi_table[i].long_archi==NULL) {
292 4 : DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
293 4 : return NULL;
294 : }
295 :
296 : /* this might be client code - but shouldn't this be an fstrcpy etc? */
297 :
298 252 : DEBUGADD(108,("index: [%d]\n", i));
299 252 : DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
300 252 : DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
301 :
302 252 : return archi_table[i].short_archi;
303 : }
304 :
305 : /****************************************************************************
306 : Read data from fsp on the vfs.
307 : ****************************************************************************/
308 :
309 0 : static ssize_t printing_pread_data(files_struct *fsp,
310 : char *buf,
311 : off_t *poff,
312 : size_t byte_count)
313 : {
314 0 : size_t total=0;
315 0 : off_t in_pos = *poff;
316 :
317 : /* Don't allow integer wrap on read. */
318 0 : if (in_pos + byte_count < in_pos) {
319 0 : return -1;
320 : }
321 :
322 0 : while (total < byte_count) {
323 0 : ssize_t ret = read_file(fsp,
324 : buf + total,
325 : in_pos,
326 : byte_count - total);
327 :
328 0 : if (ret == 0) {
329 0 : *poff = in_pos;
330 0 : return total;
331 : }
332 0 : if (ret == -1) {
333 0 : if (errno == EINTR) {
334 0 : continue;
335 : } else {
336 0 : return -1;
337 : }
338 : }
339 0 : in_pos += ret;
340 0 : total += ret;
341 : }
342 0 : *poff = in_pos;
343 0 : return (ssize_t)total;
344 : }
345 :
346 : /****************************************************************************
347 : Detect the major and minor version of a PE file.
348 : Returns:
349 :
350 : 1 if file is a PE file and we got version numbers,
351 : 0 if this file is a PE file and we couldn't get the version numbers,
352 : -1 on error.
353 :
354 : NB. buf is passed into and freed inside this function. This is a
355 : bad API design, but fixing this is a task for another day.
356 : ****************************************************************************/
357 :
358 0 : static int handle_pe_file(files_struct *fsp,
359 : off_t in_pos,
360 : char *fname,
361 : char *buf,
362 : uint32_t *major,
363 : uint32_t *minor)
364 : {
365 0 : unsigned int i;
366 0 : unsigned int num_sections;
367 0 : unsigned int section_table_bytes;
368 0 : ssize_t byte_count;
369 0 : off_t rel_pos;
370 0 : int ret = -1;
371 :
372 : /* Just skip over optional header to get to section table */
373 0 : rel_pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-
374 : (NE_HEADER_SIZE-PE_HEADER_SIZE);
375 :
376 0 : if (in_pos + rel_pos < in_pos) {
377 : /* Integer wrap. */
378 0 : goto out;
379 : }
380 0 : in_pos = rel_pos + in_pos;
381 :
382 : /* get the section table */
383 0 : num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
384 :
385 0 : if (num_sections >= (UINT_MAX / PE_HEADER_SECT_HEADER_SIZE)) {
386 : /* Integer wrap. */
387 0 : goto out;
388 : }
389 :
390 0 : section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
391 0 : if (section_table_bytes == 0) {
392 0 : goto out;
393 : }
394 :
395 0 : SAFE_FREE(buf);
396 0 : buf = (char *)SMB_MALLOC(section_table_bytes);
397 0 : if (buf == NULL) {
398 0 : DBG_ERR("PE file [%s] section table malloc "
399 : "failed bytes = %d\n",
400 : fname,
401 : section_table_bytes);
402 0 : goto out;
403 : }
404 :
405 0 : byte_count = printing_pread_data(fsp, buf, &in_pos, section_table_bytes);
406 0 : if (byte_count < section_table_bytes) {
407 0 : DBG_NOTICE("PE file [%s] Section header too short, "
408 : "bytes read = %lu\n",
409 : fname,
410 : (unsigned long)byte_count);
411 0 : goto out;
412 : }
413 :
414 : /*
415 : * Iterate the section table looking for
416 : * the resource section ".rsrc"
417 : */
418 0 : for (i = 0; i < num_sections; i++) {
419 0 : int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
420 :
421 0 : if (strcmp(".rsrc",
422 0 : &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) {
423 0 : unsigned int section_pos = IVAL(buf,
424 : sec_offset+
425 : PE_HEADER_SECT_PTR_DATA_OFFSET);
426 0 : unsigned int section_bytes = IVAL(buf,
427 : sec_offset+
428 : PE_HEADER_SECT_SIZE_DATA_OFFSET);
429 :
430 0 : if (section_bytes == 0) {
431 0 : goto out;
432 : }
433 :
434 0 : SAFE_FREE(buf);
435 0 : buf=(char *)SMB_MALLOC(section_bytes);
436 0 : if (buf == NULL) {
437 0 : DBG_ERR("PE file [%s] version malloc "
438 : "failed bytes = %d\n",
439 : fname,
440 : section_bytes);
441 0 : goto out;
442 : }
443 :
444 : /*
445 : * Read from the start of the .rsrc
446 : * section info
447 : */
448 0 : in_pos = section_pos;
449 :
450 0 : byte_count = printing_pread_data(fsp,
451 : buf,
452 : &in_pos,
453 : section_bytes);
454 0 : if (byte_count < section_bytes) {
455 0 : DBG_NOTICE("PE file "
456 : "[%s] .rsrc section too short, "
457 : "bytes read = %lu\n",
458 : fname,
459 : (unsigned long)byte_count);
460 0 : goto out;
461 : }
462 :
463 0 : if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) {
464 0 : goto out;
465 : }
466 :
467 0 : for (i=0;
468 0 : i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE;
469 0 : i++) {
470 : /*
471 : * Scan for 1st 3 unicoded bytes
472 : * followed by word aligned magic
473 : * value.
474 : */
475 0 : int mpos;
476 0 : bool magic_match = false;
477 :
478 0 : if (buf[i] == 'V' &&
479 0 : buf[i+1] == '\0' &&
480 0 : buf[i+2] == 'S') {
481 0 : magic_match = true;
482 : }
483 :
484 0 : if (magic_match == false) {
485 0 : continue;
486 : }
487 :
488 : /* Align to next long address */
489 0 : mpos = (i + sizeof(VS_SIGNATURE)*2 +
490 0 : 3) & 0xfffffffc;
491 :
492 0 : if (IVAL(buf,mpos) == VS_MAGIC_VALUE) {
493 0 : *major = IVAL(buf,
494 : mpos+ VS_MAJOR_OFFSET);
495 0 : *minor = IVAL(buf,
496 : mpos+ VS_MINOR_OFFSET);
497 :
498 0 : DBG_INFO("PE file [%s] Version = "
499 : "%08x:%08x (%d.%d.%d.%d)\n",
500 : fname,
501 : *major,
502 : *minor,
503 : (*major>>16)&0xffff,
504 : *major&0xffff,
505 : (*minor>>16)&0xffff,
506 : *minor&0xffff);
507 0 : ret = 1;
508 0 : goto out;
509 : }
510 : }
511 : }
512 : }
513 :
514 : /* Version info not found, fall back to origin date/time */
515 0 : DBG_DEBUG("PE file [%s] has no version info\n", fname);
516 0 : ret = 0;
517 :
518 0 : out:
519 :
520 0 : SAFE_FREE(buf);
521 0 : return ret;
522 : }
523 :
524 : /****************************************************************************
525 : Detect the major and minor version of an NE file.
526 : Returns:
527 :
528 : 1 if file is an NE file and we got version numbers,
529 : 0 if this file is an NE file and we couldn't get the version numbers,
530 : -1 on error.
531 :
532 : NB. buf is passed into and freed inside this function. This is a
533 : bad API design, but fixing this is a task for another day.
534 : ****************************************************************************/
535 :
536 0 : static int handle_ne_file(files_struct *fsp,
537 : off_t in_pos,
538 : char *fname,
539 : char *buf,
540 : uint32_t *major,
541 : uint32_t *minor)
542 : {
543 0 : unsigned int i;
544 0 : ssize_t byte_count;
545 0 : int ret = -1;
546 :
547 0 : if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
548 0 : DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n",
549 : fname,
550 : CVAL(buf,NE_HEADER_TARGET_OS_OFFSET));
551 : /*
552 : * At this point, we assume the file is in error.
553 : * It still could be something else besides a NE file,
554 : * but it unlikely at this point.
555 : */
556 0 : goto out;
557 : }
558 :
559 : /* Allocate a bit more space to speed up things */
560 0 : SAFE_FREE(buf);
561 0 : buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE);
562 0 : if (buf == NULL) {
563 0 : DBG_ERR("NE file [%s] malloc failed bytes = %d\n",
564 : fname,
565 : PE_HEADER_SIZE);
566 0 : goto out;
567 : }
568 :
569 : /*
570 : * This is a HACK! I got tired of trying to sort through the
571 : * messy 'NE' file format. If anyone wants to clean this up
572 : * please have at it, but this works. 'NE' files will
573 : * eventually fade away. JRR
574 : */
575 0 : byte_count = printing_pread_data(fsp, buf, &in_pos, VS_NE_BUF_SIZE);
576 0 : while (byte_count > 0) {
577 : /*
578 : * Cover case that should not occur in a well
579 : * formed 'NE' .dll file
580 : */
581 0 : if (byte_count-VS_VERSION_INFO_SIZE <= 0) {
582 0 : break;
583 : }
584 :
585 0 : for(i=0; i<byte_count; i++) {
586 : /*
587 : * Fast skip past data that can't
588 : * possibly match
589 : */
590 0 : if (buf[i] != 'V') {
591 0 : byte_count = printing_pread_data(fsp,
592 : buf,
593 : &in_pos,
594 : VS_NE_BUF_SIZE);
595 0 : continue;
596 : }
597 :
598 : /*
599 : * Potential match data crosses buf boundary,
600 : * move it to beginning of buf, and fill the
601 : * buf with as much as it will hold.
602 : */
603 0 : if (i>byte_count-VS_VERSION_INFO_SIZE) {
604 0 : ssize_t amount_read;
605 0 : ssize_t amount_unused = byte_count-i;
606 :
607 0 : memmove(buf, &buf[i], amount_unused);
608 0 : amount_read = printing_pread_data(fsp,
609 : &buf[amount_unused],
610 : &in_pos,
611 0 : VS_NE_BUF_SIZE- amount_unused);
612 0 : if (amount_read < 0) {
613 0 : DBG_ERR("NE file [%s] Read "
614 : "error, errno=%d\n",
615 : fname,
616 : errno);
617 0 : goto out;
618 : }
619 :
620 0 : if (amount_read + amount_unused <
621 : amount_read) {
622 : /* Check for integer wrap. */
623 0 : break;
624 : }
625 :
626 0 : byte_count = amount_read +
627 : amount_unused;
628 0 : if (byte_count < VS_VERSION_INFO_SIZE) {
629 0 : break;
630 : }
631 :
632 0 : i = 0;
633 : }
634 :
635 : /*
636 : * Check that the full signature string and
637 : * the magic number that follows exist (not
638 : * a perfect solution, but the chances that this
639 : * occurs in code is, well, remote. Yes I know
640 : * I'm comparing the 'V' twice, as it is
641 : * simpler to read the code.
642 : */
643 0 : if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
644 : /*
645 : * Compute skip alignment to next
646 : * long address.
647 : */
648 0 : off_t cpos = in_pos;
649 0 : int skip = -(cpos - (byte_count - i) +
650 0 : sizeof(VS_SIGNATURE)) & 3;
651 0 : if (IVAL(buf,
652 : i+sizeof(VS_SIGNATURE)+skip)
653 : != 0xfeef04bd) {
654 0 : byte_count = printing_pread_data(fsp,
655 : buf,
656 : &in_pos,
657 : VS_NE_BUF_SIZE);
658 0 : continue;
659 : }
660 :
661 0 : *major = IVAL(buf,
662 : i+sizeof(VS_SIGNATURE)+
663 : skip+VS_MAJOR_OFFSET);
664 0 : *minor = IVAL(buf,
665 : i+sizeof(VS_SIGNATURE)+
666 : skip+VS_MINOR_OFFSET);
667 0 : DBG_INFO("NE file [%s] Version "
668 : "= %08x:%08x (%d.%d.%d.%d)\n",
669 : fname,
670 : *major,
671 : *minor,
672 : (*major>>16)&0xffff,
673 : *major&0xffff,
674 : (*minor>>16)&0xffff,
675 : *minor&0xffff);
676 0 : ret = 1;
677 0 : goto out;
678 : }
679 : }
680 : }
681 :
682 : /* Version info not found, fall back to origin date/time */
683 0 : DBG_ERR("NE file [%s] Version info not found\n", fname);
684 0 : ret = 0;
685 :
686 0 : out:
687 :
688 0 : SAFE_FREE(buf);
689 0 : return ret;
690 : }
691 :
692 : /****************************************************************************
693 : Version information in Microsoft files is held in a VS_VERSION_INFO structure.
694 : There are two case to be covered here: PE (Portable Executable) and NE (New
695 : Executable) files. Both files support the same INFO structure, but PE files
696 : store the signature in unicode, and NE files store it as !unicode.
697 : returns -1 on error, 1 on version info found, and 0 on no version info found.
698 : ****************************************************************************/
699 :
700 0 : static int get_file_version(files_struct *fsp,
701 : char *fname,
702 : uint32_t *major,
703 : uint32_t *minor)
704 : {
705 0 : char *buf = NULL;
706 0 : ssize_t byte_count;
707 0 : off_t in_pos = fh_get_pos(fsp->fh);
708 :
709 0 : buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE);
710 0 : if (buf == NULL) {
711 0 : DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n",
712 : fname,
713 : DOS_HEADER_SIZE);
714 0 : goto error_exit;
715 : }
716 :
717 0 : byte_count = printing_pread_data(fsp, buf, &in_pos, DOS_HEADER_SIZE);
718 0 : if (byte_count < DOS_HEADER_SIZE) {
719 0 : DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n",
720 : fname,
721 : (unsigned long)byte_count);
722 0 : goto no_version_info;
723 : }
724 :
725 : /* Is this really a DOS header? */
726 0 : if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
727 0 : DBG_INFO("File [%s] bad DOS magic = 0x%x\n",
728 : fname,
729 : SVAL(buf,DOS_HEADER_MAGIC_OFFSET));
730 0 : goto no_version_info;
731 : }
732 :
733 : /*
734 : * Skip OEM header (if any) and the
735 : * DOS stub to start of Windows header.
736 : */
737 0 : in_pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET);
738 :
739 : /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
740 0 : byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE);
741 0 : if (byte_count < NE_HEADER_SIZE) {
742 0 : DBG_NOTICE("File [%s] Windows header too short, "
743 : "bytes read = %lu\n",
744 : fname,
745 : (unsigned long)byte_count);
746 : /*
747 : * Assume this isn't an error...
748 : * the file just looks sort of like a PE/NE file
749 : */
750 0 : goto no_version_info;
751 : }
752 :
753 : /*
754 : * The header may be a PE (Portable Executable)
755 : * or an NE (New Executable).
756 : */
757 0 : if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
758 0 : return handle_pe_file(fsp,
759 : in_pos,
760 : fname,
761 : buf,
762 : major,
763 : minor);
764 0 : } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) ==
765 : NE_HEADER_SIGNATURE) {
766 0 : return handle_ne_file(fsp,
767 : in_pos,
768 : fname,
769 : buf,
770 : major,
771 : minor);
772 : } else {
773 : /*
774 : * Assume this isn't an error... the file just
775 : * looks sort of like a PE/NE file.
776 : */
777 0 : DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n",
778 : fname,
779 : IVAL(buf,PE_HEADER_SIGNATURE_OFFSET));
780 : /* Fallthrough into no_version_info: */
781 : }
782 :
783 0 : no_version_info:
784 0 : SAFE_FREE(buf);
785 0 : return 0;
786 :
787 0 : error_exit:
788 0 : SAFE_FREE(buf);
789 0 : return -1;
790 : }
791 :
792 : /****************************************************************************
793 : Drivers for Microsoft systems contain multiple files. Often, multiple drivers
794 : share one or more files. During the MS installation process files are checked
795 : to insure that only a newer version of a shared file is installed over an
796 : older version. There are several possibilities for this comparison. If there
797 : is no previous version, the new one is newer (obviously). If either file is
798 : missing the version info structure, compare the creation date (on Unix use
799 : the modification date). Otherwise chose the numerically larger version number.
800 : ****************************************************************************/
801 :
802 0 : static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
803 : {
804 0 : bool use_version = true;
805 :
806 0 : uint32_t new_major;
807 0 : uint32_t new_minor;
808 0 : time_t new_create_time;
809 :
810 0 : uint32_t old_major;
811 0 : uint32_t old_minor;
812 0 : time_t old_create_time;
813 :
814 0 : struct smb_filename *smb_fname = NULL;
815 0 : files_struct *fsp = NULL;
816 0 : struct files_struct *dirfsp = NULL;
817 0 : SMB_STRUCT_STAT st;
818 :
819 0 : NTSTATUS status;
820 0 : int ret;
821 :
822 0 : SET_STAT_INVALID(st);
823 0 : new_create_time = (time_t)0;
824 0 : old_create_time = (time_t)0;
825 :
826 : /* Get file version info (if available) for previous file (if it exists) */
827 0 : status = driver_unix_convert(conn, old_file, &dirfsp, &smb_fname);
828 0 : if (!NT_STATUS_IS_OK(status)) {
829 0 : goto error_exit;
830 : }
831 :
832 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
833 0 : if (!NT_STATUS_IS_OK(status)) {
834 0 : ret = 1;
835 0 : goto done;
836 : }
837 :
838 0 : status = SMB_VFS_CREATE_FILE(
839 : conn, /* conn */
840 : NULL, /* req */
841 : dirfsp, /* dirfsp */
842 : smb_fname, /* fname */
843 : FILE_GENERIC_READ, /* access_mask */
844 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
845 : FILE_OPEN, /* create_disposition*/
846 : 0, /* create_options */
847 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
848 : INTERNAL_OPEN_ONLY, /* oplock_request */
849 : NULL, /* lease */
850 : 0, /* allocation_size */
851 : 0, /* private_flags */
852 : NULL, /* sd */
853 : NULL, /* ea_list */
854 : &fsp, /* result */
855 : NULL, /* pinfo */
856 : NULL, NULL); /* create context */
857 :
858 0 : if (!NT_STATUS_IS_OK(status)) {
859 : /* Old file not found, so by definition new file is in fact newer */
860 0 : DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
861 : "errno = %d\n", smb_fname_str_dbg(smb_fname),
862 : errno));
863 0 : ret = 1;
864 0 : goto done;
865 :
866 : }
867 :
868 0 : ret = get_file_version(fsp, old_file, &old_major, &old_minor);
869 0 : if (ret == -1) {
870 0 : goto error_exit;
871 : }
872 :
873 0 : if (!ret) {
874 0 : DEBUG(6,("file_version_is_newer: Version info not found [%s], "
875 : "use mod time\n",
876 : old_file));
877 0 : use_version = false;
878 0 : if (SMB_VFS_FSTAT(fsp, &st) == -1) {
879 0 : goto error_exit;
880 : }
881 0 : old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
882 0 : DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
883 : (long)old_create_time));
884 : }
885 :
886 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
887 :
888 : /* Get file version info (if available) for new file */
889 0 : status = driver_unix_convert(conn, new_file, &dirfsp, &smb_fname);
890 0 : if (!NT_STATUS_IS_OK(status)) {
891 0 : goto error_exit;
892 : }
893 :
894 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
895 0 : if (!NT_STATUS_IS_OK(status)) {
896 0 : DBG_NOTICE("Can't open new file [%s], errno = %d\n",
897 : smb_fname_str_dbg(smb_fname), errno);
898 0 : goto error_exit;
899 : }
900 :
901 0 : status = SMB_VFS_CREATE_FILE(
902 : conn, /* conn */
903 : NULL, /* req */
904 : dirfsp, /* dirfsp */
905 : smb_fname, /* fname */
906 : FILE_GENERIC_READ, /* access_mask */
907 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
908 : FILE_OPEN, /* create_disposition*/
909 : 0, /* create_options */
910 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
911 : INTERNAL_OPEN_ONLY, /* oplock_request */
912 : NULL, /* lease */
913 : 0, /* allocation_size */
914 : 0, /* private_flags */
915 : NULL, /* sd */
916 : NULL, /* ea_list */
917 : &fsp, /* result */
918 : NULL, /* pinfo */
919 : NULL, NULL); /* create context */
920 :
921 0 : if (!NT_STATUS_IS_OK(status)) {
922 : /* New file not found, this shouldn't occur if the caller did its job */
923 0 : DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
924 : "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
925 0 : goto error_exit;
926 :
927 : }
928 :
929 0 : ret = get_file_version(fsp, new_file, &new_major, &new_minor);
930 0 : if (ret == -1) {
931 0 : goto error_exit;
932 : }
933 :
934 0 : if (!ret) {
935 0 : DEBUG(6,("file_version_is_newer: Version info not found [%s], "
936 : "use mod time\n",
937 : new_file));
938 0 : use_version = false;
939 0 : if (SMB_VFS_FSTAT(fsp, &st) == -1) {
940 0 : goto error_exit;
941 : }
942 0 : new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
943 0 : DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
944 : (long)new_create_time));
945 : }
946 :
947 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
948 :
949 0 : if (use_version && (new_major != old_major || new_minor != old_minor)) {
950 : /* Compare versions and choose the larger version number */
951 0 : if (new_major > old_major ||
952 0 : (new_major == old_major && new_minor > old_minor)) {
953 :
954 0 : DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
955 0 : ret = 1;
956 0 : goto done;
957 : }
958 : else {
959 0 : DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
960 0 : ret = 0;
961 0 : goto done;
962 : }
963 :
964 : } else {
965 : /* Compare modification time/dates and choose the newest time/date */
966 0 : if (new_create_time > old_create_time) {
967 0 : DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
968 0 : ret = 1;
969 0 : goto done;
970 : }
971 : else {
972 0 : DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
973 0 : ret = 0;
974 0 : goto done;
975 : }
976 : }
977 :
978 0 : error_exit:
979 0 : if(fsp)
980 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
981 0 : ret = -1;
982 0 : done:
983 0 : TALLOC_FREE(smb_fname);
984 0 : return ret;
985 : }
986 :
987 : /****************************************************************************
988 : Determine the correct cVersion associated with an architecture and driver
989 : ****************************************************************************/
990 0 : static uint32_t get_correct_cversion(const struct auth_session_info *session_info,
991 : const char *architecture,
992 : const char *driverpath_in,
993 : const char *driver_directory,
994 : WERROR *perr)
995 : {
996 0 : TALLOC_CTX *frame = talloc_stackframe();
997 0 : const struct loadparm_substitution *lp_sub =
998 0 : loadparm_s3_global_substitution();
999 0 : int cversion = -1;
1000 0 : NTSTATUS nt_status;
1001 0 : struct smb_filename *smb_fname = NULL;
1002 0 : files_struct *fsp = NULL;
1003 0 : struct files_struct *dirfsp = NULL;
1004 0 : struct conn_struct_tos *c = NULL;
1005 0 : connection_struct *conn = NULL;
1006 0 : char *printdollar = NULL;
1007 0 : char *printdollar_path = NULL;
1008 0 : char *working_dir = NULL;
1009 0 : int printdollar_snum;
1010 0 : uint32_t major, minor;
1011 0 : int ret;
1012 :
1013 0 : *perr = WERR_INVALID_PARAMETER;
1014 :
1015 : /* If architecture is Windows 95/98/ME, the version is always 0. */
1016 0 : if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
1017 0 : DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1018 0 : *perr = WERR_OK;
1019 0 : TALLOC_FREE(frame);
1020 0 : return 0;
1021 : }
1022 :
1023 : /* If architecture is Windows x64, the version is always 3. */
1024 0 : if (strcmp(architecture, SPL_ARCH_X64) == 0 ||
1025 0 : strcmp(architecture, SPL_ARCH_ARM64) == 0) {
1026 0 : DBG_DEBUG("get_correct_cversion: this architecture must be, cversion = 3\n");
1027 0 : *perr = WERR_OK;
1028 0 : TALLOC_FREE(frame);
1029 0 : return 3;
1030 : }
1031 :
1032 0 : printdollar_snum = find_service(frame, "print$", &printdollar);
1033 0 : if (!printdollar) {
1034 0 : *perr = WERR_NOT_ENOUGH_MEMORY;
1035 0 : TALLOC_FREE(frame);
1036 0 : return -1;
1037 : }
1038 0 : if (printdollar_snum == -1) {
1039 0 : *perr = WERR_BAD_NET_NAME;
1040 0 : TALLOC_FREE(frame);
1041 0 : return -1;
1042 : }
1043 :
1044 0 : printdollar_path = lp_path(frame, lp_sub, printdollar_snum);
1045 0 : if (printdollar_path == NULL) {
1046 0 : *perr = WERR_NOT_ENOUGH_MEMORY;
1047 0 : TALLOC_FREE(frame);
1048 0 : return -1;
1049 : }
1050 :
1051 0 : working_dir = talloc_asprintf(frame,
1052 : "%s/%s",
1053 : printdollar_path,
1054 : architecture);
1055 : /*
1056 : * If the driver has been uploaded into a temorpary driver
1057 : * directory, switch to the driver directory.
1058 : */
1059 0 : if (driver_directory != NULL) {
1060 0 : working_dir = talloc_asprintf(frame, "%s/%s/%s",
1061 : printdollar_path,
1062 : architecture,
1063 : driver_directory);
1064 : }
1065 :
1066 0 : nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1067 : printdollar_snum,
1068 : working_dir,
1069 : session_info,
1070 : &c);
1071 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1072 0 : DEBUG(0,("get_correct_cversion: create_conn_struct "
1073 : "returned %s\n", nt_errstr(nt_status)));
1074 0 : *perr = ntstatus_to_werror(nt_status);
1075 0 : TALLOC_FREE(frame);
1076 0 : return -1;
1077 : }
1078 0 : conn = c->conn;
1079 :
1080 0 : nt_status = set_conn_force_user_group(conn, printdollar_snum);
1081 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1082 0 : DEBUG(0, ("failed set force user / group\n"));
1083 0 : *perr = ntstatus_to_werror(nt_status);
1084 0 : goto error_free_conn;
1085 : }
1086 :
1087 0 : if (!become_user_without_service_by_session(conn, session_info)) {
1088 0 : DEBUG(0, ("failed to become user\n"));
1089 0 : *perr = WERR_ACCESS_DENIED;
1090 0 : goto error_free_conn;
1091 : }
1092 :
1093 : /*
1094 : * We switch to the directory where the driver files are located,
1095 : * so only work on the file names
1096 : */
1097 0 : nt_status = driver_unix_convert(conn,
1098 : driverpath_in,
1099 : &dirfsp,
1100 : &smb_fname);
1101 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1102 0 : *perr = ntstatus_to_werror(nt_status);
1103 0 : goto error_exit;
1104 : }
1105 :
1106 0 : nt_status = vfs_file_exist(conn, smb_fname);
1107 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1108 0 : DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
1109 0 : *perr = WERR_FILE_NOT_FOUND;
1110 0 : goto error_exit;
1111 : }
1112 :
1113 0 : nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
1114 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1115 0 : DBG_NOTICE("Can't open file [%s]: %s\n",
1116 : smb_fname_str_dbg(smb_fname),
1117 : nt_errstr(nt_status));
1118 0 : *perr = WERR_ACCESS_DENIED;
1119 0 : goto error_exit;
1120 : }
1121 :
1122 0 : nt_status = SMB_VFS_CREATE_FILE(
1123 : conn, /* conn */
1124 : NULL, /* req */
1125 : dirfsp, /* dirfsp */
1126 : smb_fname, /* fname */
1127 : FILE_GENERIC_READ, /* access_mask */
1128 : FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1129 : FILE_OPEN, /* create_disposition*/
1130 : 0, /* create_options */
1131 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1132 : INTERNAL_OPEN_ONLY, /* oplock_request */
1133 : NULL, /* lease */
1134 : 0, /* private_flags */
1135 : 0, /* allocation_size */
1136 : NULL, /* sd */
1137 : NULL, /* ea_list */
1138 : &fsp, /* result */
1139 : NULL, /* pinfo */
1140 : NULL, NULL); /* create context */
1141 :
1142 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1143 0 : DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
1144 : "%d\n", smb_fname_str_dbg(smb_fname), errno));
1145 0 : *perr = WERR_ACCESS_DENIED;
1146 0 : goto error_exit;
1147 : }
1148 :
1149 0 : ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
1150 0 : if (ret == -1) {
1151 0 : *perr = WERR_INVALID_PARAMETER;
1152 0 : goto error_exit;
1153 0 : } else if (!ret) {
1154 0 : DEBUG(6,("get_correct_cversion: Version info not "
1155 : "found [%s]\n",
1156 : smb_fname_str_dbg(smb_fname)));
1157 0 : *perr = WERR_INVALID_PARAMETER;
1158 0 : goto error_exit;
1159 : }
1160 :
1161 : /*
1162 : * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1163 : * for more details. Version in this case is not just the version of the
1164 : * file, but the version in the sense of kernel mode (2) vs. user mode
1165 : * (3) drivers. Other bits of the version fields are the version info.
1166 : * JRR 010716
1167 : */
1168 0 : cversion = major & 0x0000ffff;
1169 0 : switch (cversion) {
1170 0 : case 2: /* WinNT drivers */
1171 : case 3: /* Win2K drivers */
1172 0 : break;
1173 :
1174 0 : default:
1175 0 : DEBUG(6,("get_correct_cversion: cversion "
1176 : "invalid [%s] cversion = %d\n",
1177 : smb_fname_str_dbg(smb_fname),
1178 : cversion));
1179 0 : goto error_exit;
1180 : }
1181 :
1182 0 : DEBUG(10,("get_correct_cversion: Version info found [%s] major"
1183 : " = 0x%x minor = 0x%x\n",
1184 : smb_fname_str_dbg(smb_fname), major, minor));
1185 :
1186 0 : DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1187 : smb_fname_str_dbg(smb_fname), cversion));
1188 0 : *perr = WERR_OK;
1189 :
1190 0 : error_exit:
1191 0 : unbecome_user_without_service();
1192 0 : error_free_conn:
1193 0 : if (fsp != NULL) {
1194 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1195 : }
1196 0 : if (!W_ERROR_IS_OK(*perr)) {
1197 0 : cversion = -1;
1198 : }
1199 :
1200 0 : TALLOC_FREE(frame);
1201 0 : return cversion;
1202 : }
1203 :
1204 : /****************************************************************************
1205 : ****************************************************************************/
1206 :
1207 : #define strip_driver_path(_mem_ctx, _element) do { \
1208 : if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
1209 : (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
1210 : W_ERROR_HAVE_NO_MEMORY((_element)); \
1211 : } \
1212 : } while (0);
1213 :
1214 0 : static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
1215 : const struct auth_session_info *session_info,
1216 : const char *architecture,
1217 : const char **driver_path,
1218 : const char **data_file,
1219 : const char **config_file,
1220 : const char **help_file,
1221 : struct spoolss_StringArray *dependent_files,
1222 : enum spoolss_DriverOSVersion *version,
1223 : uint32_t flags,
1224 : const char **driver_directory)
1225 : {
1226 0 : const char *short_architecture;
1227 0 : int i;
1228 0 : WERROR err;
1229 0 : char *_p;
1230 :
1231 0 : if (!*driver_path || !*data_file) {
1232 0 : return WERR_INVALID_PARAMETER;
1233 : }
1234 :
1235 0 : if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
1236 0 : return WERR_INVALID_PARAMETER;
1237 : }
1238 :
1239 0 : if (flags & APD_COPY_FROM_DIRECTORY) {
1240 0 : char *path;
1241 0 : char *q;
1242 :
1243 : /*
1244 : * driver_path is set to:
1245 : *
1246 : * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
1247 : */
1248 0 : path = talloc_strdup(mem_ctx, *driver_path);
1249 0 : if (path == NULL) {
1250 0 : return WERR_NOT_ENOUGH_MEMORY;
1251 : }
1252 :
1253 : /* Remove pscript5.dll */
1254 0 : q = strrchr_m(path, '\\');
1255 0 : if (q == NULL) {
1256 0 : return WERR_INVALID_PARAMETER;
1257 : }
1258 0 : *q = '\0';
1259 :
1260 : /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
1261 0 : q = strrchr_m(path, '\\');
1262 0 : if (q == NULL) {
1263 0 : return WERR_INVALID_PARAMETER;
1264 : }
1265 :
1266 : /*
1267 : * Set driver_directory to:
1268 : *
1269 : * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1270 : *
1271 : * This is the directory where all the files have been uploaded
1272 : */
1273 0 : *driver_directory = q + 1;
1274 : }
1275 :
1276 : /* clean up the driver name.
1277 : * we can get .\driver.dll
1278 : * or worse c:\windows\system\driver.dll !
1279 : */
1280 : /* using an intermediate string to not have overlapping memcpy()'s */
1281 :
1282 0 : strip_driver_path(mem_ctx, *driver_path);
1283 0 : strip_driver_path(mem_ctx, *data_file);
1284 0 : if (*config_file) {
1285 0 : strip_driver_path(mem_ctx, *config_file);
1286 : }
1287 0 : if (help_file) {
1288 0 : strip_driver_path(mem_ctx, *help_file);
1289 : }
1290 :
1291 0 : if (dependent_files && dependent_files->string) {
1292 0 : for (i=0; dependent_files->string[i]; i++) {
1293 0 : strip_driver_path(mem_ctx, dependent_files->string[i]);
1294 : }
1295 : }
1296 :
1297 0 : short_architecture = get_short_archi(architecture);
1298 0 : if (!short_architecture) {
1299 0 : return WERR_UNKNOWN_PRINTER_DRIVER;
1300 : }
1301 :
1302 : /* jfm:7/16/2000 the client always sends the cversion=0.
1303 : * The server should check which version the driver is by reading
1304 : * the PE header of driver->driverpath.
1305 : *
1306 : * For Windows 95/98 the version is 0 (so the value sent is correct)
1307 : * For Windows NT (the architecture doesn't matter)
1308 : * NT 3.1: cversion=0
1309 : * NT 3.5/3.51: cversion=1
1310 : * NT 4: cversion=2
1311 : * NT2K: cversion=3
1312 : */
1313 :
1314 0 : *version = get_correct_cversion(session_info,
1315 : short_architecture,
1316 : *driver_path,
1317 : *driver_directory,
1318 : &err);
1319 0 : if (*version == -1) {
1320 0 : return err;
1321 : }
1322 :
1323 0 : return WERR_OK;
1324 : }
1325 :
1326 : /****************************************************************************
1327 : ****************************************************************************/
1328 :
1329 0 : WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1330 : const struct auth_session_info *session_info,
1331 : const struct spoolss_AddDriverInfoCtr *r,
1332 : uint32_t flags,
1333 : const char **driver_directory)
1334 : {
1335 0 : switch (r->level) {
1336 0 : case 3:
1337 0 : return clean_up_driver_struct_level(mem_ctx, session_info,
1338 0 : r->info.info3->architecture,
1339 0 : &r->info.info3->driver_path,
1340 0 : &r->info.info3->data_file,
1341 0 : &r->info.info3->config_file,
1342 0 : &r->info.info3->help_file,
1343 0 : r->info.info3->dependent_files,
1344 0 : &r->info.info3->version,
1345 : flags,
1346 : driver_directory);
1347 0 : case 6:
1348 0 : return clean_up_driver_struct_level(mem_ctx, session_info,
1349 0 : r->info.info6->architecture,
1350 0 : &r->info.info6->driver_path,
1351 0 : &r->info.info6->data_file,
1352 0 : &r->info.info6->config_file,
1353 0 : &r->info.info6->help_file,
1354 0 : r->info.info6->dependent_files,
1355 0 : &r->info.info6->version,
1356 : flags,
1357 : driver_directory);
1358 0 : case 8:
1359 0 : return clean_up_driver_struct_level(mem_ctx, session_info,
1360 0 : r->info.info8->architecture,
1361 0 : &r->info.info8->driver_path,
1362 0 : &r->info.info8->data_file,
1363 0 : &r->info.info8->config_file,
1364 0 : &r->info.info8->help_file,
1365 0 : r->info.info8->dependent_files,
1366 0 : &r->info.info8->version,
1367 : flags,
1368 : driver_directory);
1369 0 : default:
1370 0 : return WERR_NOT_SUPPORTED;
1371 : }
1372 : }
1373 :
1374 : /****************************************************************************
1375 : This function sucks and should be replaced. JRA.
1376 : ****************************************************************************/
1377 :
1378 0 : static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1379 : const struct spoolss_AddDriverInfo6 *src)
1380 : {
1381 0 : dst->version = src->version;
1382 :
1383 0 : dst->driver_name = src->driver_name;
1384 0 : dst->architecture = src->architecture;
1385 0 : dst->driver_path = src->driver_path;
1386 0 : dst->data_file = src->data_file;
1387 0 : dst->config_file = src->config_file;
1388 0 : dst->help_file = src->help_file;
1389 0 : dst->monitor_name = src->monitor_name;
1390 0 : dst->default_datatype = src->default_datatype;
1391 0 : dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1392 0 : dst->dependent_files = src->dependent_files;
1393 0 : }
1394 :
1395 0 : static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1396 : const struct spoolss_AddDriverInfo8 *src)
1397 : {
1398 0 : dst->version = src->version;
1399 :
1400 0 : dst->driver_name = src->driver_name;
1401 0 : dst->architecture = src->architecture;
1402 0 : dst->driver_path = src->driver_path;
1403 0 : dst->data_file = src->data_file;
1404 0 : dst->config_file = src->config_file;
1405 0 : dst->help_file = src->help_file;
1406 0 : dst->monitor_name = src->monitor_name;
1407 0 : dst->default_datatype = src->default_datatype;
1408 0 : dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1409 0 : dst->dependent_files = src->dependent_files;
1410 0 : }
1411 :
1412 : /****************************************************************************
1413 : ****************************************************************************/
1414 :
1415 0 : static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1416 : connection_struct *conn,
1417 : const char *driver_file,
1418 : const char *short_architecture,
1419 : uint32_t driver_version,
1420 : uint32_t version,
1421 : const char *driver_directory)
1422 : {
1423 0 : struct smb_filename *smb_fname_old = NULL;
1424 0 : struct smb_filename *smb_fname_new = NULL;
1425 0 : char *old_name = NULL;
1426 0 : char *new_name = NULL;
1427 0 : NTSTATUS status;
1428 0 : WERROR ret;
1429 :
1430 0 : if (driver_directory != NULL) {
1431 0 : old_name = talloc_asprintf(mem_ctx,
1432 : "%s/%s/%s",
1433 : short_architecture,
1434 : driver_directory,
1435 : driver_file);
1436 : } else {
1437 0 : old_name = talloc_asprintf(mem_ctx,
1438 : "%s/%s",
1439 : short_architecture,
1440 : driver_file);
1441 : }
1442 0 : if (old_name == NULL) {
1443 0 : return WERR_NOT_ENOUGH_MEMORY;
1444 : }
1445 :
1446 0 : new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1447 : short_architecture, driver_version, driver_file);
1448 0 : if (new_name == NULL) {
1449 0 : TALLOC_FREE(old_name);
1450 0 : return WERR_NOT_ENOUGH_MEMORY;
1451 : }
1452 :
1453 0 : if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1454 0 : struct files_struct *dirfsp = NULL;
1455 :
1456 0 : status = driver_unix_convert(conn,
1457 : old_name,
1458 : &dirfsp,
1459 : &smb_fname_old);
1460 0 : if (!NT_STATUS_IS_OK(status)) {
1461 0 : ret = WERR_NOT_ENOUGH_MEMORY;
1462 0 : goto out;
1463 : }
1464 :
1465 : /* Setup a synthetic smb_filename struct */
1466 0 : smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1467 0 : if (!smb_fname_new) {
1468 0 : ret = WERR_NOT_ENOUGH_MEMORY;
1469 0 : goto out;
1470 : }
1471 :
1472 0 : smb_fname_new->base_name = new_name;
1473 :
1474 0 : DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1475 : "'%s'\n", smb_fname_old->base_name,
1476 : smb_fname_new->base_name));
1477 :
1478 0 : status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1479 : FILE_OVERWRITE_IF);
1480 :
1481 0 : if (!NT_STATUS_IS_OK(status)) {
1482 0 : DEBUG(0,("move_driver_file_to_download_area: Unable "
1483 : "to rename [%s] to [%s]: %s\n",
1484 : smb_fname_old->base_name, new_name,
1485 : nt_errstr(status)));
1486 0 : ret = WERR_APP_INIT_FAILURE;
1487 0 : goto out;
1488 : }
1489 : }
1490 :
1491 0 : ret = WERR_OK;
1492 0 : out:
1493 0 : TALLOC_FREE(smb_fname_old);
1494 0 : TALLOC_FREE(smb_fname_new);
1495 0 : return ret;
1496 : }
1497 :
1498 0 : WERROR move_driver_to_download_area(const struct auth_session_info *session_info,
1499 : const struct spoolss_AddDriverInfoCtr *r,
1500 : const char *driver_directory)
1501 : {
1502 0 : TALLOC_CTX *frame = talloc_stackframe();
1503 0 : const struct loadparm_substitution *lp_sub =
1504 0 : loadparm_s3_global_substitution();
1505 0 : struct spoolss_AddDriverInfo3 *driver;
1506 0 : struct spoolss_AddDriverInfo3 converted_driver;
1507 0 : const char *short_architecture;
1508 0 : struct files_struct *dirfsp = NULL;
1509 0 : struct smb_filename *smb_dname = NULL;
1510 0 : char *new_dir = NULL;
1511 0 : struct conn_struct_tos *c = NULL;
1512 0 : connection_struct *conn = NULL;
1513 0 : NTSTATUS nt_status;
1514 0 : int i;
1515 0 : int ver = 0;
1516 0 : char *printdollar = NULL;
1517 0 : int printdollar_snum;
1518 0 : WERROR err = WERR_OK;
1519 :
1520 0 : switch (r->level) {
1521 0 : case 3:
1522 0 : driver = r->info.info3;
1523 0 : break;
1524 0 : case 6:
1525 0 : convert_level_6_to_level3(&converted_driver, r->info.info6);
1526 0 : driver = &converted_driver;
1527 0 : break;
1528 0 : case 8:
1529 0 : convert_level_8_to_level3(&converted_driver, r->info.info8);
1530 0 : driver = &converted_driver;
1531 0 : break;
1532 0 : default:
1533 0 : DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1534 0 : TALLOC_FREE(frame);
1535 0 : return WERR_INVALID_LEVEL;
1536 : }
1537 :
1538 0 : short_architecture = get_short_archi(driver->architecture);
1539 0 : if (!short_architecture) {
1540 0 : TALLOC_FREE(frame);
1541 0 : return WERR_UNKNOWN_PRINTER_DRIVER;
1542 : }
1543 :
1544 0 : printdollar_snum = find_service(frame, "print$", &printdollar);
1545 0 : if (!printdollar) {
1546 0 : TALLOC_FREE(frame);
1547 0 : return WERR_NOT_ENOUGH_MEMORY;
1548 : }
1549 0 : if (printdollar_snum == -1) {
1550 0 : TALLOC_FREE(frame);
1551 0 : return WERR_BAD_NET_NAME;
1552 : }
1553 :
1554 0 : nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1555 : printdollar_snum,
1556 0 : lp_path(frame, lp_sub, printdollar_snum),
1557 : session_info,
1558 : &c);
1559 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1560 0 : DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1561 : "returned %s\n", nt_errstr(nt_status)));
1562 0 : err = ntstatus_to_werror(nt_status);
1563 0 : TALLOC_FREE(frame);
1564 0 : return err;
1565 : }
1566 0 : conn = c->conn;
1567 :
1568 0 : nt_status = set_conn_force_user_group(conn, printdollar_snum);
1569 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1570 0 : DEBUG(0, ("failed set force user / group\n"));
1571 0 : err = ntstatus_to_werror(nt_status);
1572 0 : goto err_free_conn;
1573 : }
1574 :
1575 0 : if (!become_user_without_service_by_session(conn, session_info)) {
1576 0 : DEBUG(0, ("failed to become user\n"));
1577 0 : err = WERR_ACCESS_DENIED;
1578 0 : goto err_free_conn;
1579 : }
1580 :
1581 0 : new_dir = talloc_asprintf(frame,
1582 : "%s/%d",
1583 : short_architecture,
1584 0 : driver->version);
1585 0 : if (!new_dir) {
1586 0 : err = WERR_NOT_ENOUGH_MEMORY;
1587 0 : goto err_exit;
1588 : }
1589 0 : nt_status = driver_unix_convert(conn, new_dir, &dirfsp, &smb_dname);
1590 0 : if (!NT_STATUS_IS_OK(nt_status)) {
1591 0 : err = WERR_NOT_ENOUGH_MEMORY;
1592 0 : goto err_exit;
1593 : }
1594 :
1595 0 : DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1596 :
1597 0 : nt_status = create_directory(conn, NULL, dirfsp, smb_dname);
1598 0 : if (!NT_STATUS_IS_OK(nt_status)
1599 0 : && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1600 0 : DEBUG(0, ("failed to create driver destination directory: %s\n",
1601 : nt_errstr(nt_status)));
1602 0 : err = ntstatus_to_werror(nt_status);
1603 0 : goto err_exit;
1604 : }
1605 :
1606 : /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1607 : * listed for this driver which has already been moved, skip it (note:
1608 : * drivers may list the same file name several times. Then check if the
1609 : * file already exists in archi\version\, if so, check that the version
1610 : * info (or time stamps if version info is unavailable) is newer (or the
1611 : * date is later). If it is, move it to archi\version\filexxx.yyy.
1612 : * Otherwise, delete the file.
1613 : *
1614 : * If a file is not moved to archi\version\ because of an error, all the
1615 : * rest of the 'unmoved' driver files are removed from archi\. If one or
1616 : * more of the driver's files was already moved to archi\version\, it
1617 : * potentially leaves the driver in a partially updated state. Version
1618 : * trauma will most likely occur if an client attempts to use any printer
1619 : * bound to the driver. Perhaps a rewrite to make sure the moves can be
1620 : * done is appropriate... later JRR
1621 : */
1622 :
1623 0 : DEBUG(5,("Moving files now !\n"));
1624 :
1625 0 : if (driver->driver_path && strlen(driver->driver_path)) {
1626 :
1627 0 : err = move_driver_file_to_download_area(frame,
1628 : conn,
1629 : driver->driver_path,
1630 : short_architecture,
1631 0 : driver->version,
1632 : ver,
1633 : driver_directory);
1634 0 : if (!W_ERROR_IS_OK(err)) {
1635 0 : goto err_exit;
1636 : }
1637 : }
1638 :
1639 0 : if (driver->data_file && strlen(driver->data_file)) {
1640 0 : if (!strequal(driver->data_file, driver->driver_path)) {
1641 :
1642 0 : err = move_driver_file_to_download_area(frame,
1643 : conn,
1644 : driver->data_file,
1645 : short_architecture,
1646 0 : driver->version,
1647 : ver,
1648 : driver_directory);
1649 0 : if (!W_ERROR_IS_OK(err)) {
1650 0 : goto err_exit;
1651 : }
1652 : }
1653 : }
1654 :
1655 0 : if (driver->config_file && strlen(driver->config_file)) {
1656 0 : if (!strequal(driver->config_file, driver->driver_path) &&
1657 0 : !strequal(driver->config_file, driver->data_file)) {
1658 :
1659 0 : err = move_driver_file_to_download_area(frame,
1660 : conn,
1661 : driver->config_file,
1662 : short_architecture,
1663 0 : driver->version,
1664 : ver,
1665 : driver_directory);
1666 0 : if (!W_ERROR_IS_OK(err)) {
1667 0 : goto err_exit;
1668 : }
1669 : }
1670 : }
1671 :
1672 0 : if (driver->help_file && strlen(driver->help_file)) {
1673 0 : if (!strequal(driver->help_file, driver->driver_path) &&
1674 0 : !strequal(driver->help_file, driver->data_file) &&
1675 0 : !strequal(driver->help_file, driver->config_file)) {
1676 :
1677 0 : err = move_driver_file_to_download_area(frame,
1678 : conn,
1679 : driver->help_file,
1680 : short_architecture,
1681 0 : driver->version,
1682 : ver,
1683 : driver_directory);
1684 0 : if (!W_ERROR_IS_OK(err)) {
1685 0 : goto err_exit;
1686 : }
1687 : }
1688 : }
1689 :
1690 0 : if (driver->dependent_files && driver->dependent_files->string) {
1691 0 : for (i=0; driver->dependent_files->string[i]; i++) {
1692 0 : if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1693 0 : !strequal(driver->dependent_files->string[i], driver->data_file) &&
1694 0 : !strequal(driver->dependent_files->string[i], driver->config_file) &&
1695 0 : !strequal(driver->dependent_files->string[i], driver->help_file)) {
1696 : int j;
1697 0 : for (j=0; j < i; j++) {
1698 0 : if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1699 0 : goto NextDriver;
1700 : }
1701 : }
1702 :
1703 0 : err = move_driver_file_to_download_area(frame,
1704 : conn,
1705 0 : driver->dependent_files->string[i],
1706 : short_architecture,
1707 0 : driver->version,
1708 : ver,
1709 : driver_directory);
1710 0 : if (!W_ERROR_IS_OK(err)) {
1711 0 : goto err_exit;
1712 : }
1713 : }
1714 0 : NextDriver: ;
1715 : }
1716 : }
1717 :
1718 0 : err = WERR_OK;
1719 0 : err_exit:
1720 0 : unbecome_user_without_service();
1721 0 : err_free_conn:
1722 0 : TALLOC_FREE(frame);
1723 0 : return err;
1724 : }
1725 :
1726 : /****************************************************************************
1727 : Determine whether or not a particular driver is currently assigned
1728 : to a printer
1729 : ****************************************************************************/
1730 :
1731 0 : bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1732 : struct dcerpc_binding_handle *b,
1733 : const struct spoolss_DriverInfo8 *r)
1734 : {
1735 0 : const struct loadparm_substitution *lp_sub =
1736 0 : loadparm_s3_global_substitution();
1737 0 : int snum;
1738 0 : int n_services = lp_numservices();
1739 0 : bool in_use = false;
1740 0 : struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1741 0 : WERROR result;
1742 :
1743 0 : if (!r) {
1744 0 : return false;
1745 : }
1746 :
1747 0 : DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1748 :
1749 : /* loop through the printers.tdb and check for the drivername */
1750 :
1751 0 : for (snum=0; snum<n_services && !in_use; snum++) {
1752 0 : if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1753 0 : continue;
1754 : }
1755 :
1756 0 : result = winreg_get_printer(mem_ctx, b,
1757 0 : lp_servicename(talloc_tos(), lp_sub, snum),
1758 : &pinfo2);
1759 0 : if (!W_ERROR_IS_OK(result)) {
1760 0 : continue; /* skip */
1761 : }
1762 :
1763 0 : if (strequal(r->driver_name, pinfo2->drivername)) {
1764 0 : in_use = true;
1765 : }
1766 :
1767 0 : TALLOC_FREE(pinfo2);
1768 : }
1769 :
1770 0 : DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1771 :
1772 0 : if ( in_use ) {
1773 0 : struct spoolss_DriverInfo8 *driver = NULL;
1774 0 : WERROR werr;
1775 :
1776 0 : DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1777 :
1778 : /* we can still remove the driver if there is one of
1779 : "Windows NT x86" version 2 or 3 left */
1780 :
1781 0 : if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1782 0 : if (r->version == 2) {
1783 0 : werr = winreg_get_driver(mem_ctx, b,
1784 0 : r->architecture,
1785 0 : r->driver_name,
1786 : 3, &driver);
1787 0 : } else if (r->version == 3) {
1788 0 : werr = winreg_get_driver(mem_ctx, b,
1789 0 : r->architecture,
1790 0 : r->driver_name,
1791 : 2, &driver);
1792 : } else {
1793 0 : DBG_ERR("Unknown driver version (%d)\n",
1794 : r->version);
1795 0 : werr = WERR_UNKNOWN_PRINTER_DRIVER;
1796 : }
1797 0 : } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1798 0 : werr = winreg_get_driver(mem_ctx, b,
1799 : SPOOLSS_ARCHITECTURE_NT_X86,
1800 0 : r->driver_name,
1801 : DRIVER_ANY_VERSION,
1802 : &driver);
1803 : } else {
1804 0 : DBG_ERR("Unknown driver architecture: %s\n",
1805 : r->architecture);
1806 0 : werr = WERR_UNKNOWN_PRINTER_DRIVER;
1807 : }
1808 :
1809 : /* now check the error code */
1810 :
1811 0 : if ( W_ERROR_IS_OK(werr) ) {
1812 : /* it's ok to remove the driver, we have other architectures left */
1813 0 : in_use = false;
1814 0 : talloc_free(driver);
1815 : }
1816 : }
1817 :
1818 : /* report that the driver is not in use by default */
1819 :
1820 0 : return in_use;
1821 : }
1822 :
1823 :
1824 : /**********************************************************************
1825 : Check to see if a ogiven file is in use by *info
1826 : *********************************************************************/
1827 :
1828 0 : static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1829 : {
1830 0 : int i = 0;
1831 :
1832 0 : if ( !info )
1833 0 : return False;
1834 :
1835 : /* mz: skip files that are in the list but already deleted */
1836 0 : if (!file || !file[0]) {
1837 0 : return false;
1838 : }
1839 :
1840 0 : if (strequal(file, info->driver_path))
1841 0 : return True;
1842 :
1843 0 : if (strequal(file, info->data_file))
1844 0 : return True;
1845 :
1846 0 : if (strequal(file, info->config_file))
1847 0 : return True;
1848 :
1849 0 : if (strequal(file, info->help_file))
1850 0 : return True;
1851 :
1852 : /* see of there are any dependent files to examine */
1853 :
1854 0 : if (!info->dependent_files)
1855 0 : return False;
1856 :
1857 0 : while (info->dependent_files[i] && *info->dependent_files[i]) {
1858 0 : if (strequal(file, info->dependent_files[i]))
1859 0 : return True;
1860 0 : i++;
1861 : }
1862 :
1863 0 : return False;
1864 :
1865 : }
1866 :
1867 : /**********************************************************************
1868 : Utility function to remove the dependent file pointed to by the
1869 : input parameter from the list
1870 : *********************************************************************/
1871 :
1872 0 : static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1873 : {
1874 :
1875 : /* bump everything down a slot */
1876 :
1877 0 : while (files && files[idx+1]) {
1878 0 : files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1879 0 : idx++;
1880 : }
1881 :
1882 0 : files[idx] = NULL;
1883 :
1884 0 : return;
1885 : }
1886 :
1887 : /**********************************************************************
1888 : Check if any of the files used by src are also used by drv
1889 : *********************************************************************/
1890 :
1891 0 : static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1892 : struct spoolss_DriverInfo8 *src,
1893 : const struct spoolss_DriverInfo8 *drv)
1894 : {
1895 0 : bool in_use = False;
1896 0 : int i = 0;
1897 :
1898 0 : if ( !src || !drv )
1899 0 : return False;
1900 :
1901 : /* check each file. Remove it from the src structure if it overlaps */
1902 :
1903 0 : if (drv_file_in_use(src->driver_path, drv)) {
1904 0 : in_use = True;
1905 0 : DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1906 0 : src->driver_path = talloc_strdup(mem_ctx, "");
1907 0 : if (!src->driver_path) { return false; }
1908 : }
1909 :
1910 0 : if (drv_file_in_use(src->data_file, drv)) {
1911 0 : in_use = True;
1912 0 : DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1913 0 : src->data_file = talloc_strdup(mem_ctx, "");
1914 0 : if (!src->data_file) { return false; }
1915 : }
1916 :
1917 0 : if (drv_file_in_use(src->config_file, drv)) {
1918 0 : in_use = True;
1919 0 : DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1920 0 : src->config_file = talloc_strdup(mem_ctx, "");
1921 0 : if (!src->config_file) { return false; }
1922 : }
1923 :
1924 0 : if (drv_file_in_use(src->help_file, drv)) {
1925 0 : in_use = True;
1926 0 : DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1927 0 : src->help_file = talloc_strdup(mem_ctx, "");
1928 0 : if (!src->help_file) { return false; }
1929 : }
1930 :
1931 : /* are there any dependentfiles to examine? */
1932 :
1933 0 : if (!src->dependent_files)
1934 0 : return in_use;
1935 :
1936 0 : while (src->dependent_files[i] && *src->dependent_files[i]) {
1937 0 : if (drv_file_in_use(src->dependent_files[i], drv)) {
1938 0 : in_use = True;
1939 0 : DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1940 0 : trim_dependent_file(mem_ctx, src->dependent_files, i);
1941 : } else
1942 0 : i++;
1943 : }
1944 :
1945 0 : return in_use;
1946 : }
1947 :
1948 : /****************************************************************************
1949 : Determine whether or not a particular driver files are currently being
1950 : used by any other driver.
1951 :
1952 : Return value is True if any files were in use by other drivers
1953 : and False otherwise.
1954 :
1955 : Upon return, *info has been modified to only contain the driver files
1956 : which are not in use
1957 :
1958 : Fix from mz:
1959 :
1960 : This needs to check all drivers to ensure that all files in use
1961 : have been removed from *info, not just the ones in the first
1962 : match.
1963 : ****************************************************************************/
1964 :
1965 0 : bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1966 : struct dcerpc_binding_handle *b,
1967 : struct spoolss_DriverInfo8 *info)
1968 : {
1969 0 : uint32_t version;
1970 0 : struct spoolss_DriverInfo8 *driver;
1971 0 : bool in_use = false;
1972 0 : uint32_t i, num_drivers;
1973 0 : const char **drivers;
1974 0 : WERROR result;
1975 :
1976 0 : if ( !info )
1977 0 : return False;
1978 :
1979 0 : version = info->version;
1980 :
1981 : /* loop over all driver versions */
1982 :
1983 0 : DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1984 :
1985 : /* get the list of drivers */
1986 :
1987 0 : result = winreg_get_driver_list(mem_ctx, b,
1988 : info->architecture, version,
1989 : &num_drivers, &drivers);
1990 0 : if (!W_ERROR_IS_OK(result)) {
1991 0 : return true;
1992 : }
1993 :
1994 0 : DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1995 : num_drivers, info->architecture, version));
1996 :
1997 : /* check each driver for overlap in files */
1998 :
1999 0 : for (i = 0; i < num_drivers; i++) {
2000 0 : DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
2001 :
2002 0 : driver = NULL;
2003 :
2004 0 : result = winreg_get_driver(mem_ctx, b,
2005 0 : info->architecture, drivers[i],
2006 : version, &driver);
2007 0 : if (!W_ERROR_IS_OK(result)) {
2008 0 : talloc_free(drivers);
2009 0 : return True;
2010 : }
2011 :
2012 : /* check if d2 uses any files from d1 */
2013 : /* only if this is a different driver than the one being deleted */
2014 :
2015 0 : if (!strequal(info->driver_name, driver->driver_name)) {
2016 0 : if (trim_overlap_drv_files(mem_ctx, info, driver)) {
2017 : /* mz: Do not instantly return -
2018 : * we need to ensure this file isn't
2019 : * also in use by other drivers. */
2020 0 : in_use = true;
2021 : }
2022 : }
2023 :
2024 0 : talloc_free(driver);
2025 : }
2026 :
2027 0 : talloc_free(drivers);
2028 :
2029 0 : DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2030 :
2031 0 : return in_use;
2032 : }
2033 :
2034 0 : static NTSTATUS driver_unlink_internals(connection_struct *conn,
2035 : const char *short_arch,
2036 : int vers,
2037 : const char *fname)
2038 : {
2039 0 : TALLOC_CTX *tmp_ctx = talloc_new(conn);
2040 0 : struct smb_filename *smb_fname = NULL;
2041 0 : char *print_dlr_path;
2042 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
2043 :
2044 0 : print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
2045 : short_arch, vers, fname);
2046 0 : if (print_dlr_path == NULL) {
2047 0 : goto err_out;
2048 : }
2049 :
2050 0 : status = synthetic_pathref(tmp_ctx,
2051 : conn->cwd_fsp,
2052 : print_dlr_path,
2053 : NULL,
2054 : NULL,
2055 : 0,
2056 : 0,
2057 : &smb_fname);
2058 0 : if (!NT_STATUS_IS_OK(status)) {
2059 0 : goto err_out;
2060 : }
2061 :
2062 0 : status = unlink_internals(conn, NULL, 0, NULL, smb_fname);
2063 0 : err_out:
2064 0 : talloc_free(tmp_ctx);
2065 0 : return status;
2066 : }
2067 :
2068 : /****************************************************************************
2069 : Actually delete the driver files. Make sure that
2070 : printer_driver_files_in_use() return False before calling
2071 : this.
2072 : ****************************************************************************/
2073 :
2074 0 : bool delete_driver_files(const struct auth_session_info *session_info,
2075 : const struct spoolss_DriverInfo8 *r)
2076 : {
2077 0 : TALLOC_CTX *frame = talloc_stackframe();
2078 0 : const struct loadparm_substitution *lp_sub =
2079 0 : loadparm_s3_global_substitution();
2080 0 : const char *short_arch;
2081 0 : struct conn_struct_tos *c = NULL;
2082 0 : connection_struct *conn = NULL;
2083 0 : NTSTATUS nt_status;
2084 0 : char *printdollar = NULL;
2085 0 : int printdollar_snum;
2086 0 : bool ret = false;
2087 :
2088 0 : if (!r) {
2089 0 : TALLOC_FREE(frame);
2090 0 : return false;
2091 : }
2092 :
2093 0 : DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2094 : r->driver_name, r->version));
2095 :
2096 0 : printdollar_snum = find_service(frame, "print$", &printdollar);
2097 0 : if (!printdollar) {
2098 0 : TALLOC_FREE(frame);
2099 0 : return false;
2100 : }
2101 0 : if (printdollar_snum == -1) {
2102 0 : TALLOC_FREE(frame);
2103 0 : return false;
2104 : }
2105 :
2106 0 : nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
2107 : printdollar_snum,
2108 0 : lp_path(frame, lp_sub, printdollar_snum),
2109 : session_info,
2110 : &c);
2111 0 : if (!NT_STATUS_IS_OK(nt_status)) {
2112 0 : DEBUG(0,("delete_driver_files: create_conn_struct "
2113 : "returned %s\n", nt_errstr(nt_status)));
2114 0 : TALLOC_FREE(frame);
2115 0 : return false;
2116 : }
2117 0 : conn = c->conn;
2118 :
2119 0 : nt_status = set_conn_force_user_group(conn, printdollar_snum);
2120 0 : if (!NT_STATUS_IS_OK(nt_status)) {
2121 0 : DEBUG(0, ("failed set force user / group\n"));
2122 0 : ret = false;
2123 0 : goto err_free_conn;
2124 : }
2125 :
2126 0 : if (!become_user_without_service_by_session(conn, session_info)) {
2127 0 : DEBUG(0, ("failed to become user\n"));
2128 0 : ret = false;
2129 0 : goto err_free_conn;
2130 : }
2131 :
2132 0 : if ( !CAN_WRITE(conn) ) {
2133 0 : DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2134 0 : ret = false;
2135 0 : goto err_out;
2136 : }
2137 :
2138 0 : short_arch = get_short_archi(r->architecture);
2139 0 : if (short_arch == NULL) {
2140 0 : DEBUG(0, ("bad architecture %s\n", r->architecture));
2141 0 : ret = false;
2142 0 : goto err_out;
2143 : }
2144 :
2145 : /* now delete the files */
2146 :
2147 0 : if (r->driver_path && r->driver_path[0]) {
2148 0 : DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
2149 0 : driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
2150 : }
2151 :
2152 0 : if (r->config_file && r->config_file[0]) {
2153 0 : DEBUG(10,("deleting configfile [%s]\n", r->config_file));
2154 0 : driver_unlink_internals(conn, short_arch, r->version, r->config_file);
2155 : }
2156 :
2157 0 : if (r->data_file && r->data_file[0]) {
2158 0 : DEBUG(10,("deleting datafile [%s]\n", r->data_file));
2159 0 : driver_unlink_internals(conn, short_arch, r->version, r->data_file);
2160 : }
2161 :
2162 0 : if (r->help_file && r->help_file[0]) {
2163 0 : DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
2164 0 : driver_unlink_internals(conn, short_arch, r->version, r->help_file);
2165 : }
2166 :
2167 0 : if (r->dependent_files) {
2168 0 : int i = 0;
2169 0 : while (r->dependent_files[i] && r->dependent_files[i][0]) {
2170 0 : DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
2171 0 : driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
2172 0 : i++;
2173 : }
2174 : }
2175 :
2176 0 : ret = true;
2177 0 : err_out:
2178 0 : unbecome_user_without_service();
2179 0 : err_free_conn:
2180 0 : TALLOC_FREE(frame);
2181 0 : return ret;
2182 : }
2183 :
2184 : /* error code:
2185 : 0: everything OK
2186 : 1: level not implemented
2187 : 2: file doesn't exist
2188 : 3: can't allocate memory
2189 : 4: can't free memory
2190 : 5: non existent struct
2191 : */
2192 :
2193 : /*
2194 : A printer and a printer driver are 2 different things.
2195 : NT manages them separately, Samba does the same.
2196 : Why ? Simply because it's easier and it makes sense !
2197 :
2198 : Now explanation: You have 3 printers behind your samba server,
2199 : 2 of them are the same make and model (laser A and B). But laser B
2200 : has an 3000 sheet feeder and laser A doesn't such an option.
2201 : Your third printer is an old dot-matrix model for the accounting :-).
2202 :
2203 : If the /usr/local/samba/lib directory (default dir), you will have
2204 : 5 files to describe all of this.
2205 :
2206 : 3 files for the printers (1 by printer):
2207 : NTprinter_laser A
2208 : NTprinter_laser B
2209 : NTprinter_accounting
2210 : 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2211 : NTdriver_printer model X
2212 : NTdriver_printer model Y
2213 :
2214 : jfm: I should use this comment for the text file to explain
2215 : same thing for the forms BTW.
2216 : Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2217 :
2218 : */
2219 :
2220 : /* Convert generic access rights to printer object specific access rights.
2221 : It turns out that NT4 security descriptors use generic access rights and
2222 : NT5 the object specific ones. */
2223 :
2224 4 : void map_printer_permissions(struct security_descriptor *sd)
2225 : {
2226 0 : uint32_t i;
2227 :
2228 32 : for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2229 28 : se_map_generic(&sd->dacl->aces[i].access_mask,
2230 : &printer_generic_mapping);
2231 : }
2232 4 : }
2233 :
2234 0 : void map_job_permissions(struct security_descriptor *sd)
2235 : {
2236 0 : uint32_t i;
2237 :
2238 0 : for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2239 0 : se_map_generic(&sd->dacl->aces[i].access_mask,
2240 : &job_generic_mapping);
2241 : }
2242 0 : }
2243 :
2244 :
2245 : /****************************************************************************
2246 : Check a user has permissions to perform the given operation. We use the
2247 : permission constants defined in include/rpc_spoolss.h to check the various
2248 : actions we perform when checking printer access.
2249 :
2250 : PRINTER_ACCESS_ADMINISTER:
2251 : print_queue_pause, print_queue_resume, update_printer_sec,
2252 : update_printer, spoolss_addprinterex_level_2,
2253 : _spoolss_setprinterdata
2254 :
2255 : PRINTER_ACCESS_USE:
2256 : print_job_start
2257 :
2258 : JOB_ACCESS_ADMINISTER:
2259 : print_job_delete, print_job_pause, print_job_resume,
2260 : print_queue_purge
2261 :
2262 : Try access control in the following order (for performance reasons):
2263 : 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2264 : 2) check security descriptor (bit comparisons in memory)
2265 : 3) "printer admins" (may result in numerous calls to winbind)
2266 :
2267 : ****************************************************************************/
2268 1294 : WERROR print_access_check(const struct auth_session_info *session_info,
2269 : struct messaging_context *msg_ctx, int snum,
2270 : int access_type)
2271 : {
2272 1294 : struct spoolss_security_descriptor *secdesc = NULL;
2273 0 : const struct loadparm_substitution *lp_sub =
2274 1294 : loadparm_s3_global_substitution();
2275 0 : uint32_t access_granted;
2276 0 : size_t sd_size;
2277 0 : NTSTATUS status;
2278 0 : WERROR result;
2279 0 : const char *pname;
2280 1294 : TALLOC_CTX *mem_ctx = NULL;
2281 :
2282 : /* If user is NULL then use the current_user structure */
2283 :
2284 : /* Always allow root or SE_PRINT_OPERATROR to do anything */
2285 :
2286 1294 : if ((session_info->unix_token->uid == sec_initial_uid())
2287 4 : || security_token_has_privilege(session_info->security_token,
2288 : SEC_PRIV_PRINT_OPERATOR)) {
2289 1290 : return WERR_OK;
2290 : }
2291 :
2292 : /* Get printer name */
2293 :
2294 4 : pname = lp_printername(talloc_tos(), lp_sub, snum);
2295 :
2296 4 : if (!pname || !*pname) {
2297 0 : return WERR_ACCESS_DENIED;
2298 : }
2299 :
2300 : /* Get printer security descriptor */
2301 :
2302 4 : if(!(mem_ctx = talloc_init("print_access_check"))) {
2303 0 : return WERR_NOT_ENOUGH_MEMORY;
2304 : }
2305 :
2306 4 : result = winreg_get_printer_secdesc_internal(mem_ctx,
2307 : get_session_info_system(),
2308 : msg_ctx,
2309 : pname,
2310 : &secdesc);
2311 4 : if (!W_ERROR_IS_OK(result)) {
2312 0 : talloc_destroy(mem_ctx);
2313 0 : return WERR_NOT_ENOUGH_MEMORY;
2314 : }
2315 :
2316 4 : if (access_type == JOB_ACCESS_ADMINISTER) {
2317 0 : struct spoolss_security_descriptor *parent_secdesc = secdesc;
2318 :
2319 : /* Create a child security descriptor to check permissions
2320 : against. This is because print jobs are child objects
2321 : objects of a printer. */
2322 0 : status = se_create_child_secdesc(mem_ctx,
2323 : &secdesc,
2324 : &sd_size,
2325 : parent_secdesc,
2326 0 : parent_secdesc->owner_sid,
2327 0 : parent_secdesc->group_sid,
2328 : false);
2329 0 : if (!NT_STATUS_IS_OK(status)) {
2330 0 : talloc_destroy(mem_ctx);
2331 0 : return ntstatus_to_werror(status);
2332 : }
2333 :
2334 0 : map_job_permissions(secdesc);
2335 : } else {
2336 4 : map_printer_permissions(secdesc);
2337 : }
2338 :
2339 : /* Check access */
2340 4 : status = se_access_check(secdesc, session_info->security_token, access_type,
2341 : &access_granted);
2342 :
2343 4 : DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2344 :
2345 4 : talloc_destroy(mem_ctx);
2346 :
2347 4 : return ntstatus_to_werror(status);
2348 : }
2349 :
2350 : /****************************************************************************
2351 : Check the time parameters allow a print operation.
2352 : *****************************************************************************/
2353 :
2354 668 : bool print_time_access_check(const struct auth_session_info *session_info,
2355 : struct messaging_context *msg_ctx,
2356 : const char *servicename)
2357 : {
2358 668 : struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2359 0 : WERROR result;
2360 668 : bool ok = False;
2361 668 : time_t now = time(NULL);
2362 0 : struct tm *t;
2363 0 : uint32_t mins;
2364 :
2365 668 : result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2366 : servicename, &pinfo2);
2367 668 : if (!W_ERROR_IS_OK(result)) {
2368 0 : return False;
2369 : }
2370 :
2371 668 : if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2372 668 : ok = True;
2373 : }
2374 :
2375 668 : t = gmtime(&now);
2376 668 : mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2377 :
2378 668 : if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2379 0 : ok = True;
2380 : }
2381 :
2382 668 : TALLOC_FREE(pinfo2);
2383 :
2384 668 : if (!ok) {
2385 0 : errno = EACCES;
2386 : }
2387 :
2388 668 : return ok;
2389 : }
2390 :
2391 0 : void nt_printer_remove(TALLOC_CTX *mem_ctx,
2392 : const struct auth_session_info *session_info,
2393 : struct messaging_context *msg_ctx,
2394 : const char *printer)
2395 : {
2396 0 : WERROR result;
2397 :
2398 0 : result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2399 : printer, "");
2400 0 : if (!W_ERROR_IS_OK(result)) {
2401 0 : DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2402 : "%s\n", printer, win_errstr(result)));
2403 : }
2404 0 : }
2405 :
2406 0 : void nt_printer_add(TALLOC_CTX *mem_ctx,
2407 : const struct auth_session_info *session_info,
2408 : struct messaging_context *msg_ctx,
2409 : const char *printer)
2410 : {
2411 0 : WERROR result;
2412 :
2413 0 : result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2414 : printer);
2415 0 : if (!W_ERROR_IS_OK(result)) {
2416 0 : DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2417 : printer, win_errstr(result)));
2418 : }
2419 0 : }
|