Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Guenther Deschner 2016
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "librpc/gen_ndr/ndr_spoolss.h"
22 : #include "rpc_client/init_spoolss.h"
23 : #include "libgpo/gpo_ini.h"
24 : #include "printer_driver.h"
25 :
26 : #define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \
27 : do { \
28 : *(array) = talloc_realloc(mem_ctx, (*(array)), type, (*(num))+1); \
29 : SMB_ASSERT((*(array)) != NULL); \
30 : (*(array))[*(num)] = (elem); \
31 : (*(num)) += 1; \
32 : } while (0)
33 :
34 :
35 : /* GetPrinterDriverDirectory -> drivers and dependent files */
36 : #define PRINTER_INF_DIRID_66000
37 :
38 : /* GetPrintProcessorDirectory -> print processors */
39 : #define PRINTER_INF_DIRID_66001
40 :
41 : /* GetColorDirectory -> color profiles */
42 : #define PRINTER_INF_DIRID_66003
43 :
44 0 : static const char *get_string_unquote(const char *s)
45 : {
46 : bool ok;
47 : size_t len;
48 :
49 0 : if (s == NULL) {
50 0 : return NULL;
51 : }
52 :
53 0 : len = strlen(s);
54 0 : if (len < 2) {
55 0 : return s;
56 : }
57 :
58 0 : if (s[0] == '"' && s[len-1] == '"') {
59 0 : ok = trim_string(discard_const(s), "\"", "\"");
60 0 : if (!ok) {
61 0 : return NULL;
62 : }
63 : }
64 :
65 0 : return s;
66 : }
67 :
68 : /*
69 : * '%STRING%' indicates STRING is localized in the [Strings] section
70 : */
71 :
72 0 : static const char *get_string_token(struct gp_inifile_context *ctx,
73 : const char *s)
74 : {
75 : NTSTATUS status;
76 : bool ok;
77 : char *key;
78 : const char *s2;
79 :
80 0 : if (s != NULL && s[0] != '%' && s[strlen(s)-1] != '%') {
81 0 : return s;
82 : }
83 :
84 0 : ok = trim_string(discard_const(s), "%", "%");
85 0 : if (!ok) {
86 0 : return NULL;
87 : }
88 :
89 0 : key = talloc_asprintf(ctx, "Strings:%s", s);
90 0 : if (key == NULL) {
91 0 : return NULL;
92 : }
93 :
94 0 : status = gp_inifile_getstring(ctx, key, &s2);
95 0 : talloc_free(key);
96 0 : if (!NT_STATUS_IS_OK(status)) {
97 : /* what can you do... */
98 0 : return s;
99 : }
100 :
101 0 : return s2;
102 : }
103 :
104 0 : static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
105 : const char *key,
106 : const char **ret)
107 : {
108 : NTSTATUS status;
109 : const char *s;
110 :
111 0 : status = gp_inifile_getstring(ctx, key, &s);
112 0 : if (!NT_STATUS_IS_OK(status)) {
113 0 : return status;
114 : }
115 :
116 0 : s = get_string_unquote(s);
117 0 : if (s == NULL) {
118 0 : return NT_STATUS_INTERNAL_ERROR;
119 : }
120 :
121 0 : if (s[0] == '%' && s[strlen(s)-1] == '%') {
122 0 : s = get_string_token(ctx, s);
123 : }
124 :
125 0 : s = get_string_unquote(s);
126 0 : if (s == NULL) {
127 0 : return NT_STATUS_INTERNAL_ERROR;
128 : }
129 :
130 0 : *ret = s;
131 :
132 0 : return NT_STATUS_OK;
133 : }
134 :
135 0 : static NTSTATUS find_manufacturer_name(struct gp_inifile_context *ctx,
136 : TALLOC_CTX *mem_ctx,
137 : const char *section_name,
138 : const char **manufacturer_name)
139 : {
140 : NTSTATUS status;
141 0 : size_t num_keys = 0;
142 0 : const char **keys = NULL;
143 0 : const char **values = NULL;
144 : const char *s;
145 : char *p;
146 :
147 0 : status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
148 0 : if (!NT_STATUS_IS_OK(status)) {
149 0 : return status;
150 : }
151 :
152 0 : if (num_keys < 1) {
153 0 : return NT_STATUS_INVALID_PARAMETER;
154 : }
155 :
156 0 : s = talloc_strdup(mem_ctx, keys[0]);
157 0 : if (s == NULL) {
158 0 : return NT_STATUS_NO_MEMORY;
159 : }
160 :
161 0 : p = strchr(s, ':');
162 0 : if (p == NULL) {
163 0 : return NT_STATUS_NO_MEMORY;
164 : }
165 0 : *p = '\0';
166 0 : p++;
167 :
168 0 : s = get_string_unquote(p);
169 0 : if (s == NULL) {
170 0 : return NT_STATUS_INTERNAL_ERROR;
171 : }
172 :
173 0 : s = get_string_token(ctx, s);
174 :
175 0 : s = get_string_unquote(s);
176 0 : if (s == NULL) {
177 0 : return NT_STATUS_INTERNAL_ERROR;
178 : }
179 :
180 0 : if (s != NULL) {
181 0 : *manufacturer_name = talloc_strdup(mem_ctx, s);
182 0 : if (*manufacturer_name == NULL) {
183 0 : return NT_STATUS_NO_MEMORY;
184 : }
185 : }
186 :
187 0 : talloc_free(keys);
188 0 : talloc_free(values);
189 :
190 0 : return NT_STATUS_OK;
191 : }
192 :
193 0 : static NTSTATUS find_manufacturer_url(struct gp_inifile_context *ctx,
194 : TALLOC_CTX *mem_ctx,
195 : const char *section_name,
196 : const char *manufacturer_name,
197 : const char **manufacturer_url)
198 : {
199 : NTSTATUS status;
200 0 : size_t num_keys = 0;
201 0 : const char **keys = NULL;
202 0 : const char **values = NULL;
203 : const char *s;
204 : char *p;
205 :
206 0 : status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
207 :
208 0 : if (!NT_STATUS_IS_OK(status)) {
209 0 : return status;
210 : }
211 :
212 0 : if (num_keys < 1) {
213 0 : return NT_STATUS_INVALID_PARAMETER;
214 : }
215 :
216 0 : p = strchr(keys[0], ':');
217 0 : if (p == NULL) {
218 0 : return NT_STATUS_NO_MEMORY;
219 : }
220 0 : *p = '\0';
221 0 : p++;
222 :
223 0 : s = get_string_unquote(p);
224 0 : if (s == NULL) {
225 0 : return NT_STATUS_INTERNAL_ERROR;
226 : }
227 :
228 0 : s = get_string_token(ctx, s);
229 :
230 0 : s = get_string_unquote(s);
231 0 : if (s == NULL) {
232 0 : return NT_STATUS_INTERNAL_ERROR;
233 : }
234 :
235 0 : if (strequal(s, manufacturer_name)) {
236 0 : s = get_string_unquote(values[0]);
237 0 : if (s == NULL) {
238 0 : return NT_STATUS_INTERNAL_ERROR;
239 : }
240 : }
241 :
242 0 : if (s != NULL) {
243 0 : *manufacturer_url = talloc_strdup(mem_ctx, s);
244 0 : if (*manufacturer_url == NULL) {
245 0 : return NT_STATUS_NO_MEMORY;
246 : }
247 : }
248 :
249 0 : talloc_free(keys);
250 0 : talloc_free(values);
251 :
252 0 : return NT_STATUS_OK;
253 : }
254 :
255 0 : static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
256 : const char *s,
257 : struct spoolss_StringArray **r)
258 : {
259 0 : size_t count = 2;
260 0 : struct spoolss_StringArray *a = *r;
261 : bool ok;
262 : int i;
263 :
264 0 : if (a == NULL) {
265 0 : a = talloc_zero(mem_ctx, struct spoolss_StringArray);
266 0 : if (a == NULL) {
267 0 : return NT_STATUS_NO_MEMORY;
268 : }
269 : }
270 :
271 0 : if (a->string == NULL) {
272 0 : a->string = talloc_zero_array(a, const char *, count);
273 0 : if (a->string == NULL) {
274 0 : return NT_STATUS_NO_MEMORY;
275 : }
276 : }
277 :
278 0 : for (i = 0; a->string[i] != NULL; i++) { ;; }
279 0 : count = i;
280 :
281 0 : ok = add_string_to_array(mem_ctx, s, &a->string, &count);
282 0 : if (!ok) {
283 0 : return NT_STATUS_NO_MEMORY;
284 : }
285 :
286 0 : a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
287 0 : if (a->string == NULL) {
288 0 : return NT_STATUS_NO_MEMORY;
289 : }
290 0 : a->string[count] = NULL;
291 :
292 0 : *r = a;
293 :
294 0 : return NT_STATUS_OK;
295 : }
296 :
297 0 : static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
298 : const char *file,
299 : struct spoolss_StringArray **r)
300 : {
301 : char *p;
302 :
303 0 : if (file == NULL) {
304 0 : return NT_STATUS_INVALID_PARAMETER;
305 : }
306 :
307 0 : if (file[0] == '@') {
308 0 : file++;
309 : }
310 :
311 0 : p = strchr(file, ',');
312 0 : if (p != NULL) {
313 0 : *p = '\0';
314 : }
315 :
316 0 : return add_string_to_spoolss_array(mem_ctx, file, r);
317 : }
318 :
319 : /*
320 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section
321 : *
322 : * [Manufacturer]
323 : * "Kyocera"=Kyocera,NTx86.5.1,NTx86.6.0,NTamd64.5.1,NTamd64.6.0
324 : */
325 :
326 0 : static NTSTATUS enum_devices_in_toc(struct gp_inifile_context *ctx,
327 : TALLOC_CTX *mem_ctx,
328 : size_t *pnum_devices,
329 : const char ***pdevices,
330 : const char ***pdevice_values)
331 : {
332 : NTSTATUS status;
333 0 : size_t i, num_manufacturers = 0;
334 0 : const char **manufacturers = NULL;
335 0 : const char **values = NULL;
336 : char *p;
337 : bool ok;
338 :
339 0 : status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
340 0 : if (!NT_STATUS_IS_OK(status)) {
341 0 : return status;
342 : }
343 :
344 0 : for (i = 0; i < num_manufacturers; i++) {
345 :
346 : const char *models_section_name;
347 : const char *s;
348 : char **decorations;
349 : int j;
350 :
351 0 : DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
352 :
353 0 : status = gp_inifile_getstring(ctx, manufacturers[i], &s);
354 0 : if (!NT_STATUS_IS_OK(status)) {
355 0 : return status;
356 : }
357 :
358 0 : decorations = str_list_make_v3(mem_ctx, s, ",");
359 0 : if (decorations == NULL) {
360 0 : return NT_STATUS_NO_MEMORY;
361 : }
362 :
363 0 : models_section_name = decorations[0];
364 :
365 0 : for (j = 1; decorations[j] != NULL; j++) {
366 :
367 : /*
368 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
369 : */
370 :
371 : const char *decorated_models_section_name;
372 0 : size_t d, num_devices = 0;
373 0 : const char **devices = NULL;
374 0 : const char **device_values = NULL;
375 0 : size_t c = 0;
376 :
377 0 : decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
378 : models_section_name,
379 0 : decorations[j]);
380 0 : if (decorated_models_section_name == NULL) {
381 0 : return NT_STATUS_NO_MEMORY;
382 : }
383 :
384 0 : DEBUG(11,("processing decorated models_section_name: %s\n",
385 : decorated_models_section_name));
386 :
387 0 : status = gp_inifile_enum_section(ctx, decorated_models_section_name,
388 : &num_devices, &devices,
389 : &device_values);
390 0 : for (d = 0; d < num_devices; d++) {
391 :
392 0 : DEBUG(11,("processing device: %s\n",
393 : devices[d]));
394 :
395 0 : s = talloc_strdup(mem_ctx, devices[d]);
396 0 : if (s == NULL) {
397 0 : return NT_STATUS_NO_MEMORY;
398 : }
399 :
400 0 : p = strchr(s, ':');
401 0 : if (p == NULL) {
402 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
403 : }
404 :
405 0 : *p = '\0';
406 0 : p++;
407 :
408 0 : s = get_string_unquote(p);
409 :
410 0 : ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
411 0 : if (!ok) {
412 0 : return NT_STATUS_NO_MEMORY;
413 : }
414 0 : ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
415 0 : if (!ok) {
416 0 : return NT_STATUS_NO_MEMORY;
417 : }
418 : }
419 : }
420 : }
421 :
422 0 : return NT_STATUS_OK;
423 : }
424 :
425 0 : static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
426 : TALLOC_CTX *mem_ctx,
427 : const char *device_description,
428 : const char **value)
429 : {
430 : NTSTATUS status;
431 0 : size_t d, num_devices = 0;
432 0 : const char **devices = NULL;
433 0 : const char **device_values = NULL;
434 :
435 0 : if (device_description == NULL) {
436 0 : return NT_STATUS_INVALID_PARAMETER;
437 : }
438 :
439 0 : status = enum_devices_in_toc(ctx, mem_ctx,
440 : &num_devices,
441 : &devices,
442 : &device_values);
443 0 : if (!NT_STATUS_IS_OK(status)) {
444 0 : return status;
445 : }
446 :
447 0 : for (d = 0; d < num_devices; d++) {
448 :
449 0 : if (strequal(device_description, devices[d])) {
450 :
451 0 : DEBUG(10,("found device_description: %s\n",
452 : device_description));
453 :
454 0 : *value = talloc_strdup(mem_ctx, device_values[d]);
455 0 : if (*value == NULL) {
456 0 : return NT_STATUS_NO_MEMORY;
457 : }
458 0 : DEBUGADD(10,("and returned: %s\n", *value));
459 :
460 0 : return NT_STATUS_OK;
461 : }
462 : }
463 :
464 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
465 : }
466 :
467 : /*
468 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
469 : */
470 :
471 0 : static NTSTATUS process_driver_section_copyfiles(struct gp_inifile_context *ctx,
472 : TALLOC_CTX *mem_ctx,
473 : const char *driver_section,
474 : struct spoolss_AddDriverInfo8 *r)
475 : {
476 : NTSTATUS status;
477 0 : size_t i, num_keys = 0;
478 : char *p, *key;
479 0 : const char **keys = NULL;
480 0 : const char **values = NULL;
481 : char *str;
482 : const char *s;
483 :
484 0 : key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
485 0 : if (key == NULL) {
486 0 : return NT_STATUS_NO_MEMORY;
487 : }
488 :
489 0 : DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
490 :
491 0 : status = gp_inifile_getstring(ctx, key, &s);
492 0 : if (!NT_STATUS_IS_OK(status)) {
493 0 : return NT_STATUS_OK;
494 : }
495 :
496 0 : DEBUG(10,("these are the files to copy: %s\n", s));
497 :
498 0 : while (next_token_talloc(mem_ctx, &s, &str, ",")) {
499 :
500 0 : DEBUG(10,("trying section: %s\n", str));
501 :
502 0 : if (str[0] == '@') {
503 0 : DEBUG(10,("adding dependent driver file: %s\n", str));
504 0 : status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
505 0 : if (!NT_STATUS_IS_OK(status)) {
506 0 : return status;
507 : }
508 0 : continue;
509 : }
510 :
511 0 : status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
512 0 : if (NT_STATUS_IS_OK(status)) {
513 0 : for (i = 0; i < num_keys; i++) {
514 0 : p = strchr(keys[i], ':');
515 0 : if (p == NULL) {
516 0 : return NT_STATUS_INVALID_PARAMETER;
517 : }
518 0 : *p = '\0';
519 0 : p++;
520 :
521 0 : DEBUG(10,("adding dependent driver file: %s\n", p));
522 :
523 0 : status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
524 0 : if (!NT_STATUS_IS_OK(status)) {
525 0 : return status;
526 : }
527 : }
528 0 : TALLOC_FREE(keys);
529 0 : TALLOC_FREE(values);
530 : }
531 : }
532 :
533 0 : return NT_STATUS_OK;
534 : }
535 :
536 : #define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
537 : do { \
538 : NTSTATUS _status; \
539 : const char *__key, *_s; \
540 : __key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
541 : NT_STATUS_HAVE_NO_MEMORY(__key); \
542 : _status = gp_inifile_getstring(_ctx, __key, &_s); \
543 : if (NT_STATUS_IS_OK(_status)) { \
544 : (_r)->_element = talloc_strdup(mem_ctx, _s); \
545 : NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
546 : } \
547 : } while(0);
548 :
549 0 : static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
550 : TALLOC_CTX *mem_ctx,
551 : const char *section,
552 : struct spoolss_AddDriverInfo8 *r)
553 : {
554 : NTSTATUS status;
555 : const char *key, *s;
556 :
557 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
558 0 : if (key == NULL) {
559 0 : return NT_STATUS_NO_MEMORY;
560 : }
561 :
562 0 : status = gp_inifile_getstring_ext(ctx, key, &s);
563 0 : if (NT_STATUS_IS_OK(status)) {
564 :
565 0 : status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
566 0 : if (!NT_STATUS_IS_OK(status)) {
567 0 : return status;
568 : }
569 : }
570 :
571 0 : return NT_STATUS_OK;
572 : }
573 :
574 0 : static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
575 : TALLOC_CTX *mem_ctx,
576 : const char *section,
577 : struct spoolss_AddDriverInfo8 *r)
578 : {
579 : NTSTATUS status;
580 : char *key, *p;
581 : const char *s;
582 :
583 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
584 0 : if (key == NULL) {
585 0 : return NT_STATUS_NO_MEMORY;
586 : }
587 :
588 0 : status = gp_inifile_getstring_ext(ctx, key, &s);
589 0 : if (NT_STATUS_IS_OK(status)) {
590 0 : s = get_string_unquote(s);
591 :
592 0 : p = strchr(s, ',');
593 0 : if (p == NULL) {
594 0 : return NT_STATUS_INVALID_PARAMETER;
595 : }
596 0 : *p = '\0';
597 0 : r->print_processor = talloc_strdup(mem_ctx, s);
598 0 : if (r->print_processor == NULL) {
599 0 : return NT_STATUS_NO_MEMORY;
600 : }
601 : }
602 :
603 0 : return NT_STATUS_OK;
604 : }
605 :
606 0 : static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
607 : TALLOC_CTX *mem_ctx,
608 : const char *section,
609 : struct spoolss_AddDriverInfo8 *r)
610 : {
611 : NTSTATUS status;
612 : char *key;
613 : const char *s;
614 :
615 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
616 0 : if (key == NULL) {
617 0 : return NT_STATUS_NO_MEMORY;
618 : }
619 :
620 0 : status = gp_inifile_getstring(ctx, key, &s);
621 0 : if (NT_STATUS_IS_OK(status)) {
622 0 : process_driver_section_val(ctx, mem_ctx, s, r,
623 : "DriverFile", driver_path);
624 0 : process_driver_section_val(ctx, mem_ctx, s, r,
625 : "HelpFile", help_file);
626 0 : process_driver_section_val(ctx, mem_ctx, s, r,
627 : "DataFile", data_file);
628 0 : process_driver_section_val(ctx, mem_ctx, s, r,
629 : "ConfigFile", config_file);
630 : }
631 :
632 0 : return NT_STATUS_OK;
633 : }
634 :
635 :
636 0 : static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
637 : TALLOC_CTX *mem_ctx,
638 : const char *driver_section,
639 : struct spoolss_AddDriverInfo8 *r)
640 : {
641 : NTSTATUS status;
642 0 : size_t i, num_keys = 0;
643 0 : const char **keys = NULL;
644 0 : const char **values = NULL;
645 :
646 0 : DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
647 :
648 0 : status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
649 0 : if (!NT_STATUS_IS_OK(status)) {
650 0 : return status;
651 : }
652 :
653 0 : for (i = 0; i < num_keys; i++) {
654 :
655 0 : status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
656 0 : if (!NT_STATUS_IS_OK(status)) {
657 0 : return status;
658 : }
659 :
660 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
661 : "DriverFile", driver_path);
662 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
663 : "HelpFile", help_file);
664 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
665 : "ConfigFile", config_file);
666 :
667 0 : status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
668 0 : if (!NT_STATUS_IS_OK(status)) {
669 0 : return status;
670 : }
671 : }
672 :
673 0 : talloc_free(keys);
674 0 : talloc_free(values);
675 :
676 0 : return NT_STATUS_OK;
677 : }
678 :
679 : /*
680 : * CoreDriverSections="{D20EA372-DD35-4950-9ED8-A6335AFE79F0},UNIDRV_BIDI.OEM,UNIDRV_BIDI_DATA","{D20EA372-DD35-4950-9ED8-A6335AFE79F2},PCLXL.OEM","{D20EA372-DD35-4950-9ED8-A6335AFE79F3},sRGBPROFILE.OEM"
681 : */
682 0 : static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
683 : TALLOC_CTX *mem_ctx,
684 : const char *value,
685 : struct spoolss_AddDriverInfo8 *r)
686 : {
687 : NTSTATUS status;
688 : char *p;
689 : char **list;
690 : int i;
691 :
692 0 : list = str_list_make_v3(mem_ctx, value, ",");
693 0 : if (list == NULL) {
694 0 : return NT_STATUS_NO_MEMORY;
695 : }
696 :
697 0 : for (i = 0; list[i] != NULL; i++) {
698 : char **array;
699 : int a;
700 :
701 : /* FIXME: do we have to validate the core driver guid ? */
702 :
703 0 : p = strchr(list[i], ',');
704 0 : if (p != NULL) {
705 0 : *p = '\0';
706 0 : p++;
707 : }
708 :
709 0 : DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
710 :
711 0 : array = str_list_make_v3(mem_ctx, p, ",");
712 0 : if (array == NULL) {
713 0 : return NT_STATUS_NO_MEMORY;
714 : }
715 :
716 0 : for (a = 0; array[a] != NULL; a++) {
717 :
718 0 : if (core_ctx == NULL) {
719 0 : DEBUG(0,("Need to process CoreDriverSections but "
720 : "have no Core Driver Context!\n"));
721 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
722 : }
723 :
724 0 : status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
725 0 : if (!NT_STATUS_IS_OK(status)) {
726 0 : continue;
727 : }
728 : }
729 : }
730 :
731 0 : return NT_STATUS_OK;
732 : }
733 :
734 : /*
735 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
736 : */
737 0 : static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
738 : struct gp_inifile_context *core_ctx,
739 : TALLOC_CTX *mem_ctx,
740 : const char *driver_name,
741 : struct spoolss_AddDriverInfo8 *r)
742 : {
743 : NTSTATUS status;
744 : char *key;
745 : const char *s;
746 : const char *value;
747 : char *install_section_name;
748 : bool ok;
749 : char *hw_id;
750 :
751 0 : status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
752 0 : if (!NT_STATUS_IS_OK(status)) {
753 0 : return status;
754 : }
755 :
756 0 : r->driver_name = talloc_strdup(mem_ctx, driver_name);
757 0 : if (r->driver_name == NULL) {
758 0 : return NT_STATUS_NO_MEMORY;
759 : }
760 :
761 0 : ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
762 0 : if (!ok) {
763 0 : return NT_STATUS_INVALID_PARAMETER;
764 : }
765 :
766 0 : DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
767 : driver_name, value, install_section_name));
768 :
769 : /* Hardware Id is optional */
770 0 : ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
771 0 : if (ok) {
772 0 : r->hardware_id = hw_id;
773 : }
774 :
775 0 : status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
776 0 : if (!NT_STATUS_IS_OK(status)) {
777 0 : return status;
778 : }
779 :
780 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
781 : "DriverFile", driver_path);
782 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
783 : "HelpFile", help_file);
784 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
785 : "DataFile", data_file);
786 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
787 : "ConfigFile", config_file);
788 :
789 0 : status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
790 0 : if (!NT_STATUS_IS_OK(status)) {
791 0 : return status;
792 : }
793 :
794 0 : status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
795 0 : if (!NT_STATUS_IS_OK(status)) {
796 0 : return status;
797 : }
798 :
799 0 : key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
800 0 : if (key == NULL) {
801 0 : return NT_STATUS_NO_MEMORY;
802 : }
803 :
804 0 : status = gp_inifile_getstring(ctx, key, &s);
805 0 : if (NT_STATUS_IS_OK(status)) {
806 :
807 0 : DEBUG(10,("found CoreDriverSections: %s\n", s));
808 :
809 0 : status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
810 0 : if (!NT_STATUS_IS_OK(status)) {
811 0 : return status;
812 : }
813 : }
814 :
815 0 : return NT_STATUS_OK;
816 : }
817 :
818 : struct inf_context {
819 : struct gp_inifile_context *ctx;
820 : struct gp_inifile_context *core_ctx;
821 : };
822 :
823 0 : static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
824 : const char *inf_filename,
825 : const char *core_filename,
826 : struct inf_context **_inf_ctx)
827 : {
828 : NTSTATUS status;
829 : struct gp_inifile_context *ctx;
830 0 : struct gp_inifile_context *core_ctx = NULL;
831 : struct inf_context *inf_ctx;
832 :
833 0 : inf_ctx = talloc_zero(mem_ctx, struct inf_context);
834 0 : if (inf_ctx == NULL) {
835 0 : return NT_STATUS_NO_MEMORY;
836 : }
837 :
838 0 : status = gp_inifile_init_context_direct(mem_ctx,
839 : inf_filename,
840 : &ctx);
841 0 : if (!NT_STATUS_IS_OK(status)) {
842 0 : DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
843 0 : return status;
844 : }
845 :
846 0 : if (ctx->generated_filename != NULL) {
847 0 : unlink(ctx->generated_filename);
848 : }
849 :
850 0 : if (core_filename != NULL) {
851 0 : status = gp_inifile_init_context_direct(mem_ctx,
852 : core_filename,
853 : &core_ctx);
854 0 : if (!NT_STATUS_IS_OK(status)) {
855 0 : DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
856 0 : return status;
857 : }
858 :
859 0 : if (core_ctx->generated_filename != NULL) {
860 0 : unlink(core_ctx->generated_filename);
861 : }
862 : }
863 :
864 0 : inf_ctx->ctx = ctx;
865 0 : inf_ctx->core_ctx = core_ctx;
866 :
867 0 : *_inf_ctx = inf_ctx;
868 :
869 0 : return NT_STATUS_OK;
870 : }
871 :
872 0 : static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
873 : struct spoolss_AddDriverInfo8 *r)
874 : {
875 : NTSTATUS status;
876 : const char *s;
877 : char *p;
878 : bool ok;
879 : const char *str;
880 :
881 0 : status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
882 0 : if (!NT_STATUS_IS_OK(status)) {
883 0 : return status;
884 : }
885 :
886 0 : str = talloc_strdup(ctx, s);
887 0 : if (str == NULL) {
888 0 : return NT_STATUS_NO_MEMORY;
889 : }
890 :
891 0 : p = strchr(str, ',');
892 0 : if (p) {
893 0 : *p = '\0';
894 0 : p++;
895 : }
896 :
897 0 : ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
898 0 : if (!ok) {
899 0 : return NT_STATUS_INVALID_PARAMETER;
900 : }
901 :
902 0 : ok = spoolss_driver_version_to_qword(p, &r->driver_version);
903 0 : if (!ok) {
904 0 : return NT_STATUS_INVALID_PARAMETER;
905 : }
906 :
907 0 : return NT_STATUS_OK;
908 : }
909 :
910 : /*
911 : * Parse a SourceDisksNames section,
912 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
913 : */
914 0 : static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
915 : TALLOC_CTX *mem_ctx,
916 : const char *short_environment,
917 : const char **source_disk_name)
918 : {
919 : NTSTATUS status;
920 : bool ok;
921 : const char *key;
922 0 : size_t i, num_keys = 0;
923 0 : const char **keys = NULL;
924 0 : const char **values = NULL;
925 :
926 0 : key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
927 0 : if (key == NULL) {
928 0 : return NT_STATUS_NO_MEMORY;
929 : }
930 :
931 0 : status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
932 0 : if (!NT_STATUS_IS_OK(status)) {
933 0 : return status;
934 : }
935 :
936 0 : if (keys == NULL && values == NULL) {
937 0 : key = "SourceDisksNames";
938 :
939 0 : status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
940 0 : if (!NT_STATUS_IS_OK(status)) {
941 0 : return status;
942 : }
943 : }
944 :
945 0 : for (i = 0; i < num_keys; i++) {
946 :
947 : /*
948 : * 1 = %Disk1%,,,"Amd64"
949 : * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
950 : */
951 : char *disk_description, *tag_or_cab_file, *unused, *path;
952 :
953 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
954 0 : if (!ok) {
955 0 : continue;
956 : }
957 :
958 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
959 0 : if (!ok) {
960 0 : continue;
961 : }
962 :
963 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
964 0 : if (!ok) {
965 0 : continue;
966 : }
967 :
968 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
969 0 : if (!ok) {
970 0 : continue;
971 : }
972 :
973 0 : *source_disk_name = path;
974 :
975 0 : return NT_STATUS_OK;
976 : }
977 :
978 0 : return NT_STATUS_NOT_FOUND;
979 : }
980 :
981 0 : static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
982 : struct inf_context *inf_ctx,
983 : const char *filename,
984 : const char *environment,
985 : const char *driver_name,
986 : struct spoolss_AddDriverInfo8 *r,
987 : const char **source_disk_name)
988 : {
989 : NTSTATUS status;
990 0 : struct gp_inifile_context *ctx = inf_ctx->ctx;
991 0 : struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
992 : char *key;
993 : bool ok;
994 : const char *short_environment;
995 : const char *s;
996 :
997 0 : short_environment = spoolss_get_short_filesys_environment(environment);
998 0 : if (short_environment == NULL) {
999 0 : return NT_STATUS_INVALID_PARAMETER;
1000 : }
1001 :
1002 0 : status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
1003 0 : if (!NT_STATUS_IS_OK(status)) {
1004 0 : return status;
1005 : }
1006 :
1007 0 : status = process_source_disk_name(ctx, mem_ctx,
1008 : short_environment,
1009 : source_disk_name);
1010 0 : if (!NT_STATUS_IS_OK(status)) {
1011 0 : return status;
1012 : }
1013 :
1014 0 : r->inf_path = talloc_strdup(mem_ctx, filename);
1015 0 : if (r->inf_path == NULL) {
1016 0 : return NT_STATUS_NO_MEMORY;
1017 : }
1018 :
1019 0 : r->architecture = talloc_strdup(mem_ctx, environment);
1020 0 : if (r->architecture == NULL) {
1021 0 : return NT_STATUS_NO_MEMORY;
1022 : }
1023 :
1024 0 : if (r->print_processor == NULL) {
1025 0 : r->print_processor = talloc_strdup(mem_ctx, "winprint");
1026 0 : if (r->print_processor == NULL) {
1027 0 : return NT_STATUS_NO_MEMORY;
1028 : }
1029 : }
1030 :
1031 0 : status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
1032 0 : if (NT_STATUS_IS_OK(status)) {
1033 0 : if (strequal(s, "Printer")) {
1034 0 : r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
1035 : }
1036 : }
1037 :
1038 0 : status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1039 0 : if (!NT_STATUS_IS_OK(status)) {
1040 0 : return status;
1041 : }
1042 0 : if (!strequal(s, "\"$Windows NT$\"")) {
1043 0 : return NT_STATUS_INVALID_SIGNATURE;
1044 : }
1045 :
1046 0 : r->version = SPOOLSS_DRIVER_VERSION_200X;
1047 0 : status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
1048 0 : if (NT_STATUS_IS_OK(status)) {
1049 0 : int cmp = strncasecmp_m(s, "4.0", 3);
1050 0 : if (cmp == 0) {
1051 0 : r->version = SPOOLSS_DRIVER_VERSION_2012;
1052 : }
1053 0 : if (strequal(s, "3.0")) {
1054 0 : r->version = SPOOLSS_DRIVER_VERSION_200X;
1055 : }
1056 : }
1057 :
1058 0 : status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
1059 0 : if (NT_STATUS_IS_OK(status)) {
1060 0 : if (s != NULL) {
1061 0 : r->provider = talloc_strdup(mem_ctx, s);
1062 0 : if (r->provider == NULL) {
1063 0 : return NT_STATUS_NO_MEMORY;
1064 : }
1065 : }
1066 : }
1067 :
1068 0 : status = process_driver_driverver(ctx, r);
1069 0 : if (!NT_STATUS_IS_OK(status)) {
1070 0 : return status;
1071 : }
1072 :
1073 0 : r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1074 :
1075 0 : status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
1076 0 : if (NT_STATUS_IS_OK(status)) {
1077 0 : int cmp = strncasecmp_m(s, "2", 1);
1078 0 : if (cmp == 0) {
1079 0 : r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
1080 : }
1081 0 : cmp = strncasecmp_m(s, "0", 1);
1082 0 : if (cmp == 0) {
1083 0 : r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1084 : }
1085 : }
1086 :
1087 0 : status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1088 0 : if (!NT_STATUS_IS_OK(status)) {
1089 0 : return status;
1090 : }
1091 :
1092 0 : status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
1093 0 : if (!NT_STATUS_IS_OK(status)) {
1094 : /* not critical */
1095 : }
1096 :
1097 0 : status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
1098 0 : if (NT_STATUS_IS_OK(status)) {
1099 0 : if (ok) {
1100 0 : r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1101 : }
1102 : }
1103 :
1104 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1105 : "PrinterPackageInstallation", short_environment, "PackageAware");
1106 0 : if (key == NULL) {
1107 0 : return NT_STATUS_NO_MEMORY;
1108 : }
1109 :
1110 0 : status = gp_inifile_getbool(ctx, key, &ok);
1111 0 : if (NT_STATUS_IS_OK(status)) {
1112 0 : if (ok) {
1113 0 : r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1114 : }
1115 : }
1116 :
1117 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1118 : "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1119 0 : if (key == NULL) {
1120 0 : return NT_STATUS_NO_MEMORY;
1121 : }
1122 :
1123 0 : status = gp_inifile_getstring(ctx, key, &s);
1124 0 : if (NT_STATUS_IS_OK(status)) {
1125 : char **list;
1126 0 : r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
1127 0 : if (r->core_driver_dependencies == NULL) {
1128 0 : return NT_STATUS_NO_MEMORY;
1129 : }
1130 :
1131 0 : list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1132 0 : if (list == NULL) {
1133 0 : return NT_STATUS_NO_MEMORY;
1134 : }
1135 0 : r->core_driver_dependencies->string = const_str_list(list);
1136 : }
1137 :
1138 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1139 : "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1140 0 : if (key == NULL) {
1141 0 : return NT_STATUS_NO_MEMORY;
1142 : }
1143 :
1144 0 : status = gp_inifile_getstring(ctx, key, &s);
1145 0 : if (NT_STATUS_IS_OK(status)) {
1146 0 : if (strequal(s, "UseDriverVer")) {
1147 0 : r->min_inbox_driver_ver_date = r->driver_date;
1148 0 : r->min_inbox_driver_ver_version = r->driver_version;
1149 : }
1150 : }
1151 :
1152 0 : return NT_STATUS_OK;
1153 : }
1154 :
1155 : /****************************************************************
1156 : parse the a printer inf file
1157 : ****************************************************************/
1158 :
1159 0 : NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
1160 : const char *core_driver_inf,
1161 : const char *filename,
1162 : const char *environment,
1163 : const char *driver_name,
1164 : struct spoolss_AddDriverInfo8 *r,
1165 : const char **source_disk_name)
1166 : {
1167 : NTSTATUS status;
1168 : struct inf_context *inf_ctx;
1169 :
1170 0 : if (!filename || !environment) {
1171 0 : return NT_STATUS_INVALID_PARAMETER;
1172 : }
1173 :
1174 0 : status = init_inf_context(mem_ctx,
1175 : filename,
1176 : core_driver_inf,
1177 : &inf_ctx);
1178 0 : if (!NT_STATUS_IS_OK(status)) {
1179 0 : return status;
1180 : }
1181 :
1182 0 : status = setup_driver_by_name(mem_ctx, inf_ctx,
1183 : filename,
1184 : environment,
1185 : driver_name,
1186 : r,
1187 : source_disk_name);
1188 0 : if (!NT_STATUS_IS_OK(status)) {
1189 0 : return status;
1190 : }
1191 :
1192 0 : return NT_STATUS_OK;
1193 : }
1194 :
1195 0 : NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
1196 : const char *core_driver_inf,
1197 : const char *filename,
1198 : const char *environment,
1199 : uint32_t *count,
1200 : struct spoolss_AddDriverInfo8 **_r)
1201 : {
1202 : NTSTATUS status;
1203 : const char *short_environment;
1204 0 : size_t d, num_devices = 0;
1205 0 : const char **devices = NULL;
1206 0 : const char **device_values = NULL;
1207 : struct inf_context *inf_ctx;
1208 :
1209 0 : if (!filename || !environment) {
1210 0 : return NT_STATUS_INVALID_PARAMETER;
1211 : }
1212 :
1213 0 : short_environment = spoolss_get_short_filesys_environment(environment);
1214 0 : if (short_environment == NULL) {
1215 0 : return NT_STATUS_INVALID_PARAMETER;
1216 : }
1217 :
1218 0 : status = init_inf_context(mem_ctx,
1219 : filename,
1220 : core_driver_inf,
1221 : &inf_ctx);
1222 0 : if (!NT_STATUS_IS_OK(status)) {
1223 0 : return status;
1224 : }
1225 :
1226 0 : status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
1227 : &num_devices,
1228 : &devices,
1229 : &device_values);
1230 0 : if (!NT_STATUS_IS_OK(status)) {
1231 0 : return status;
1232 : }
1233 :
1234 0 : for (d = 0; d < num_devices; d++) {
1235 :
1236 : struct spoolss_AddDriverInfo8 r;
1237 : const char *source_disk_name;
1238 :
1239 0 : ZERO_STRUCT(r);
1240 :
1241 0 : status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
1242 0 : environment, devices[d], &r,
1243 : &source_disk_name);
1244 0 : if (!NT_STATUS_IS_OK(status)) {
1245 0 : return status;
1246 : }
1247 :
1248 0 : ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1249 : }
1250 :
1251 0 : return NT_STATUS_OK;
1252 : }
|