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 0 : bool ok;
47 0 : 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 0 : NTSTATUS status;
76 0 : bool ok;
77 0 : char *key;
78 0 : 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 0 : NTSTATUS status;
109 0 : 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 0 : NTSTATUS status;
141 0 : size_t num_keys = 0;
142 0 : const char **keys = NULL;
143 0 : const char **values = NULL;
144 0 : const char *s;
145 0 : 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 0 : NTSTATUS status;
200 0 : size_t num_keys = 0;
201 0 : const char **keys = NULL;
202 0 : const char **values = NULL;
203 0 : const char *s;
204 0 : 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 0 : bool ok;
262 0 : 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 0 : 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 0 : NTSTATUS status;
333 0 : size_t i, num_manufacturers = 0;
334 0 : const char **manufacturers = NULL;
335 0 : const char **values = NULL;
336 0 : char *p;
337 0 : 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 0 : const char *models_section_name;
347 0 : const char *s;
348 0 : char **decorations;
349 0 : 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 0 : 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 : if (!NT_STATUS_IS_OK(status)) {
391 0 : return status;
392 : }
393 0 : for (d = 0; d < num_devices; d++) {
394 :
395 0 : DEBUG(11,("processing device: %s\n",
396 : devices[d]));
397 :
398 0 : s = talloc_strdup(mem_ctx, devices[d]);
399 0 : if (s == NULL) {
400 0 : return NT_STATUS_NO_MEMORY;
401 : }
402 :
403 0 : p = strchr(s, ':');
404 0 : if (p == NULL) {
405 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
406 : }
407 :
408 0 : *p = '\0';
409 0 : p++;
410 :
411 0 : s = get_string_unquote(p);
412 :
413 0 : ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
414 0 : if (!ok) {
415 0 : return NT_STATUS_NO_MEMORY;
416 : }
417 0 : ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
418 0 : if (!ok) {
419 0 : return NT_STATUS_NO_MEMORY;
420 : }
421 : }
422 : }
423 : }
424 :
425 0 : return NT_STATUS_OK;
426 : }
427 :
428 0 : static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
429 : TALLOC_CTX *mem_ctx,
430 : const char *device_description,
431 : const char **value)
432 : {
433 0 : NTSTATUS status;
434 0 : size_t d, num_devices = 0;
435 0 : const char **devices = NULL;
436 0 : const char **device_values = NULL;
437 :
438 0 : if (device_description == NULL) {
439 0 : return NT_STATUS_INVALID_PARAMETER;
440 : }
441 :
442 0 : status = enum_devices_in_toc(ctx, mem_ctx,
443 : &num_devices,
444 : &devices,
445 : &device_values);
446 0 : if (!NT_STATUS_IS_OK(status)) {
447 0 : return status;
448 : }
449 :
450 0 : for (d = 0; d < num_devices; d++) {
451 :
452 0 : if (strequal(device_description, devices[d])) {
453 :
454 0 : DEBUG(10,("found device_description: %s\n",
455 : device_description));
456 :
457 0 : *value = talloc_strdup(mem_ctx, device_values[d]);
458 0 : if (*value == NULL) {
459 0 : return NT_STATUS_NO_MEMORY;
460 : }
461 0 : DEBUGADD(10,("and returned: %s\n", *value));
462 :
463 0 : return NT_STATUS_OK;
464 : }
465 : }
466 :
467 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
468 : }
469 :
470 : /*
471 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
472 : */
473 :
474 0 : static NTSTATUS process_driver_section_copyfiles(struct gp_inifile_context *ctx,
475 : TALLOC_CTX *mem_ctx,
476 : const char *driver_section,
477 : struct spoolss_AddDriverInfo8 *r)
478 : {
479 0 : NTSTATUS status;
480 0 : size_t i, num_keys = 0;
481 0 : char *p, *key;
482 0 : const char **keys = NULL;
483 0 : const char **values = NULL;
484 0 : char *str;
485 0 : const char *s;
486 :
487 0 : key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
488 0 : if (key == NULL) {
489 0 : return NT_STATUS_NO_MEMORY;
490 : }
491 :
492 0 : DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
493 :
494 0 : status = gp_inifile_getstring(ctx, key, &s);
495 0 : if (!NT_STATUS_IS_OK(status)) {
496 0 : return NT_STATUS_OK;
497 : }
498 :
499 0 : DEBUG(10,("these are the files to copy: %s\n", s));
500 :
501 0 : while (next_token_talloc(mem_ctx, &s, &str, ",")) {
502 :
503 0 : DEBUG(10,("trying section: %s\n", str));
504 :
505 0 : if (str[0] == '@') {
506 0 : DEBUG(10,("adding dependent driver file: %s\n", str));
507 0 : status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
508 0 : if (!NT_STATUS_IS_OK(status)) {
509 0 : return status;
510 : }
511 0 : continue;
512 : }
513 :
514 0 : status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
515 0 : if (NT_STATUS_IS_OK(status)) {
516 0 : for (i = 0; i < num_keys; i++) {
517 0 : p = strchr(keys[i], ':');
518 0 : if (p == NULL) {
519 0 : return NT_STATUS_INVALID_PARAMETER;
520 : }
521 0 : *p = '\0';
522 0 : p++;
523 :
524 0 : DEBUG(10,("adding dependent driver file: %s\n", p));
525 :
526 0 : status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
527 0 : if (!NT_STATUS_IS_OK(status)) {
528 0 : return status;
529 : }
530 : }
531 0 : TALLOC_FREE(keys);
532 0 : TALLOC_FREE(values);
533 : }
534 : }
535 :
536 0 : return NT_STATUS_OK;
537 : }
538 :
539 : #define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
540 : do { \
541 : NTSTATUS _status; \
542 : const char *__key, *_s; \
543 : __key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
544 : NT_STATUS_HAVE_NO_MEMORY(__key); \
545 : _status = gp_inifile_getstring(_ctx, __key, &_s); \
546 : if (NT_STATUS_IS_OK(_status)) { \
547 : (_r)->_element = talloc_strdup(mem_ctx, _s); \
548 : NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
549 : } \
550 : } while(0);
551 :
552 0 : static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
553 : TALLOC_CTX *mem_ctx,
554 : const char *section,
555 : struct spoolss_AddDriverInfo8 *r)
556 : {
557 0 : NTSTATUS status;
558 0 : const char *key, *s;
559 :
560 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
561 0 : if (key == NULL) {
562 0 : return NT_STATUS_NO_MEMORY;
563 : }
564 :
565 0 : status = gp_inifile_getstring_ext(ctx, key, &s);
566 0 : if (NT_STATUS_IS_OK(status)) {
567 :
568 0 : status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
569 0 : if (!NT_STATUS_IS_OK(status)) {
570 0 : return status;
571 : }
572 : }
573 :
574 0 : return NT_STATUS_OK;
575 : }
576 :
577 0 : static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
578 : TALLOC_CTX *mem_ctx,
579 : const char *section,
580 : struct spoolss_AddDriverInfo8 *r)
581 : {
582 0 : NTSTATUS status;
583 0 : char *key, *p;
584 0 : const char *s;
585 :
586 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
587 0 : if (key == NULL) {
588 0 : return NT_STATUS_NO_MEMORY;
589 : }
590 :
591 0 : status = gp_inifile_getstring_ext(ctx, key, &s);
592 0 : if (NT_STATUS_IS_OK(status)) {
593 0 : s = get_string_unquote(s);
594 :
595 0 : p = strchr(s, ',');
596 0 : if (p == NULL) {
597 0 : return NT_STATUS_INVALID_PARAMETER;
598 : }
599 0 : *p = '\0';
600 0 : r->print_processor = talloc_strdup(mem_ctx, s);
601 0 : if (r->print_processor == NULL) {
602 0 : return NT_STATUS_NO_MEMORY;
603 : }
604 : }
605 :
606 0 : return NT_STATUS_OK;
607 : }
608 :
609 0 : static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
610 : TALLOC_CTX *mem_ctx,
611 : const char *section,
612 : struct spoolss_AddDriverInfo8 *r)
613 : {
614 0 : NTSTATUS status;
615 0 : char *key;
616 0 : const char *s;
617 :
618 0 : key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
619 0 : if (key == NULL) {
620 0 : return NT_STATUS_NO_MEMORY;
621 : }
622 :
623 0 : status = gp_inifile_getstring(ctx, key, &s);
624 0 : if (NT_STATUS_IS_OK(status)) {
625 0 : process_driver_section_val(ctx, mem_ctx, s, r,
626 0 : "DriverFile", driver_path);
627 0 : process_driver_section_val(ctx, mem_ctx, s, r,
628 0 : "HelpFile", help_file);
629 0 : process_driver_section_val(ctx, mem_ctx, s, r,
630 0 : "DataFile", data_file);
631 0 : process_driver_section_val(ctx, mem_ctx, s, r,
632 0 : "ConfigFile", config_file);
633 : }
634 :
635 0 : return NT_STATUS_OK;
636 : }
637 :
638 :
639 0 : static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
640 : TALLOC_CTX *mem_ctx,
641 : const char *driver_section,
642 : struct spoolss_AddDriverInfo8 *r)
643 : {
644 0 : NTSTATUS status;
645 0 : size_t i, num_keys = 0;
646 0 : const char **keys = NULL;
647 0 : const char **values = NULL;
648 :
649 0 : DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
650 :
651 0 : status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
652 0 : if (!NT_STATUS_IS_OK(status)) {
653 0 : return status;
654 : }
655 :
656 0 : for (i = 0; i < num_keys; i++) {
657 :
658 0 : status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
659 0 : if (!NT_STATUS_IS_OK(status)) {
660 0 : return status;
661 : }
662 :
663 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
664 0 : "DriverFile", driver_path);
665 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
666 0 : "HelpFile", help_file);
667 0 : process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
668 0 : "ConfigFile", config_file);
669 :
670 0 : status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
671 0 : if (!NT_STATUS_IS_OK(status)) {
672 0 : return status;
673 : }
674 : }
675 :
676 0 : talloc_free(keys);
677 0 : talloc_free(values);
678 :
679 0 : return NT_STATUS_OK;
680 : }
681 :
682 : /*
683 : * 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"
684 : */
685 0 : static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
686 : TALLOC_CTX *mem_ctx,
687 : const char *value,
688 : struct spoolss_AddDriverInfo8 *r)
689 : {
690 0 : NTSTATUS status;
691 0 : char *p;
692 0 : char **list;
693 0 : int i;
694 :
695 0 : list = str_list_make_v3(mem_ctx, value, ",");
696 0 : if (list == NULL) {
697 0 : return NT_STATUS_NO_MEMORY;
698 : }
699 :
700 0 : for (i = 0; list[i] != NULL; i++) {
701 0 : char **array;
702 0 : int a;
703 :
704 : /* FIXME: do we have to validate the core driver guid ? */
705 :
706 0 : p = strchr(list[i], ',');
707 0 : if (p != NULL) {
708 0 : *p = '\0';
709 0 : p++;
710 : }
711 :
712 0 : DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
713 :
714 0 : array = str_list_make_v3(mem_ctx, p, ",");
715 0 : if (array == NULL) {
716 0 : return NT_STATUS_NO_MEMORY;
717 : }
718 :
719 0 : for (a = 0; array[a] != NULL; a++) {
720 :
721 0 : if (core_ctx == NULL) {
722 0 : DEBUG(0,("Need to process CoreDriverSections but "
723 : "have no Core Driver Context!\n"));
724 0 : return NT_STATUS_DRIVER_INTERNAL_ERROR;
725 : }
726 :
727 0 : status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
728 0 : if (!NT_STATUS_IS_OK(status)) {
729 0 : continue;
730 : }
731 : }
732 : }
733 :
734 0 : return NT_STATUS_OK;
735 : }
736 :
737 : /*
738 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
739 : */
740 0 : static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
741 : struct gp_inifile_context *core_ctx,
742 : TALLOC_CTX *mem_ctx,
743 : const char *driver_name,
744 : struct spoolss_AddDriverInfo8 *r)
745 : {
746 0 : NTSTATUS status;
747 0 : char *key;
748 0 : const char *s;
749 0 : const char *value;
750 0 : char *install_section_name;
751 0 : bool ok;
752 0 : char *hw_id;
753 :
754 0 : status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
755 0 : if (!NT_STATUS_IS_OK(status)) {
756 0 : return status;
757 : }
758 :
759 0 : r->driver_name = talloc_strdup(mem_ctx, driver_name);
760 0 : if (r->driver_name == NULL) {
761 0 : return NT_STATUS_NO_MEMORY;
762 : }
763 :
764 0 : ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
765 0 : if (!ok) {
766 0 : return NT_STATUS_INVALID_PARAMETER;
767 : }
768 :
769 0 : DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
770 : driver_name, value, install_section_name));
771 :
772 : /* Hardware Id is optional */
773 0 : ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
774 0 : if (ok) {
775 0 : r->hardware_id = hw_id;
776 : }
777 :
778 0 : status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
779 0 : if (!NT_STATUS_IS_OK(status)) {
780 0 : return status;
781 : }
782 :
783 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
784 0 : "DriverFile", driver_path);
785 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
786 0 : "HelpFile", help_file);
787 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
788 0 : "DataFile", data_file);
789 0 : process_driver_section_val(ctx, mem_ctx, install_section_name, r,
790 0 : "ConfigFile", config_file);
791 :
792 0 : status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
793 0 : if (!NT_STATUS_IS_OK(status)) {
794 0 : return status;
795 : }
796 :
797 0 : status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
798 0 : if (!NT_STATUS_IS_OK(status)) {
799 0 : return status;
800 : }
801 :
802 0 : key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
803 0 : if (key == NULL) {
804 0 : return NT_STATUS_NO_MEMORY;
805 : }
806 :
807 0 : status = gp_inifile_getstring(ctx, key, &s);
808 0 : if (NT_STATUS_IS_OK(status)) {
809 :
810 0 : DEBUG(10,("found CoreDriverSections: %s\n", s));
811 :
812 0 : status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
813 0 : if (!NT_STATUS_IS_OK(status)) {
814 0 : return status;
815 : }
816 : }
817 :
818 0 : return NT_STATUS_OK;
819 : }
820 :
821 : struct inf_context {
822 : struct gp_inifile_context *ctx;
823 : struct gp_inifile_context *core_ctx;
824 : };
825 :
826 0 : static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
827 : const char *inf_filename,
828 : const char *core_filename,
829 : struct inf_context **_inf_ctx)
830 : {
831 0 : NTSTATUS status;
832 0 : struct gp_inifile_context *ctx;
833 0 : struct gp_inifile_context *core_ctx = NULL;
834 0 : struct inf_context *inf_ctx;
835 :
836 0 : inf_ctx = talloc_zero(mem_ctx, struct inf_context);
837 0 : if (inf_ctx == NULL) {
838 0 : return NT_STATUS_NO_MEMORY;
839 : }
840 :
841 0 : status = gp_inifile_init_context_direct(mem_ctx,
842 : inf_filename,
843 : &ctx);
844 0 : if (!NT_STATUS_IS_OK(status)) {
845 0 : DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
846 0 : return status;
847 : }
848 :
849 0 : if (ctx->generated_filename != NULL) {
850 0 : unlink(ctx->generated_filename);
851 : }
852 :
853 0 : if (core_filename != NULL) {
854 0 : status = gp_inifile_init_context_direct(mem_ctx,
855 : core_filename,
856 : &core_ctx);
857 0 : if (!NT_STATUS_IS_OK(status)) {
858 0 : DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
859 0 : return status;
860 : }
861 :
862 0 : if (core_ctx->generated_filename != NULL) {
863 0 : unlink(core_ctx->generated_filename);
864 : }
865 : }
866 :
867 0 : inf_ctx->ctx = ctx;
868 0 : inf_ctx->core_ctx = core_ctx;
869 :
870 0 : *_inf_ctx = inf_ctx;
871 :
872 0 : return NT_STATUS_OK;
873 : }
874 :
875 0 : static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
876 : struct spoolss_AddDriverInfo8 *r)
877 : {
878 0 : NTSTATUS status;
879 0 : const char *s;
880 0 : char *p;
881 0 : bool ok;
882 0 : const char *str;
883 :
884 0 : status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
885 0 : if (!NT_STATUS_IS_OK(status)) {
886 0 : return status;
887 : }
888 :
889 0 : str = talloc_strdup(ctx, s);
890 0 : if (str == NULL) {
891 0 : return NT_STATUS_NO_MEMORY;
892 : }
893 :
894 0 : p = strchr(str, ',');
895 0 : if (p) {
896 0 : *p = '\0';
897 0 : p++;
898 : }
899 :
900 0 : ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
901 0 : if (!ok) {
902 0 : return NT_STATUS_INVALID_PARAMETER;
903 : }
904 :
905 0 : ok = spoolss_driver_version_to_qword(p, &r->driver_version);
906 0 : if (!ok) {
907 0 : return NT_STATUS_INVALID_PARAMETER;
908 : }
909 :
910 0 : return NT_STATUS_OK;
911 : }
912 :
913 : /*
914 : * Parse a SourceDisksNames section,
915 : * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
916 : */
917 0 : static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
918 : TALLOC_CTX *mem_ctx,
919 : const char *short_environment,
920 : const char **source_disk_name)
921 : {
922 0 : NTSTATUS status;
923 0 : bool ok;
924 0 : const char *key;
925 0 : size_t i, num_keys = 0;
926 0 : const char **keys = NULL;
927 0 : const char **values = NULL;
928 :
929 0 : key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
930 0 : if (key == NULL) {
931 0 : return NT_STATUS_NO_MEMORY;
932 : }
933 :
934 0 : status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
935 0 : if (!NT_STATUS_IS_OK(status)) {
936 0 : return status;
937 : }
938 :
939 0 : if (keys == NULL && values == NULL) {
940 0 : key = "SourceDisksNames";
941 :
942 0 : status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
943 0 : if (!NT_STATUS_IS_OK(status)) {
944 0 : return status;
945 : }
946 : }
947 :
948 0 : for (i = 0; i < num_keys; i++) {
949 :
950 : /*
951 : * 1 = %Disk1%,,,"Amd64"
952 : * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
953 : */
954 0 : char *disk_description, *tag_or_cab_file, *unused, *path;
955 :
956 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
957 0 : if (!ok) {
958 0 : continue;
959 : }
960 :
961 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
962 0 : if (!ok) {
963 0 : continue;
964 : }
965 :
966 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
967 0 : if (!ok) {
968 0 : continue;
969 : }
970 :
971 0 : ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
972 0 : if (!ok) {
973 0 : continue;
974 : }
975 :
976 0 : *source_disk_name = path;
977 :
978 0 : return NT_STATUS_OK;
979 : }
980 :
981 0 : return NT_STATUS_NOT_FOUND;
982 : }
983 :
984 0 : static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
985 : struct inf_context *inf_ctx,
986 : const char *filename,
987 : const char *environment,
988 : const char *driver_name,
989 : struct spoolss_AddDriverInfo8 *r,
990 : const char **source_disk_name)
991 : {
992 0 : NTSTATUS status;
993 0 : struct gp_inifile_context *ctx = inf_ctx->ctx;
994 0 : struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
995 0 : char *key;
996 0 : bool ok;
997 0 : const char *short_environment;
998 0 : const char *s;
999 :
1000 0 : short_environment = spoolss_get_short_filesys_environment(environment);
1001 0 : if (short_environment == NULL) {
1002 0 : return NT_STATUS_INVALID_PARAMETER;
1003 : }
1004 :
1005 0 : status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
1006 0 : if (!NT_STATUS_IS_OK(status)) {
1007 0 : return status;
1008 : }
1009 :
1010 0 : status = process_source_disk_name(ctx, mem_ctx,
1011 : short_environment,
1012 : source_disk_name);
1013 0 : if (!NT_STATUS_IS_OK(status)) {
1014 0 : return status;
1015 : }
1016 :
1017 0 : r->inf_path = talloc_strdup(mem_ctx, filename);
1018 0 : if (r->inf_path == NULL) {
1019 0 : return NT_STATUS_NO_MEMORY;
1020 : }
1021 :
1022 0 : r->architecture = talloc_strdup(mem_ctx, environment);
1023 0 : if (r->architecture == NULL) {
1024 0 : return NT_STATUS_NO_MEMORY;
1025 : }
1026 :
1027 0 : if (r->print_processor == NULL) {
1028 0 : r->print_processor = talloc_strdup(mem_ctx, "winprint");
1029 0 : if (r->print_processor == NULL) {
1030 0 : return NT_STATUS_NO_MEMORY;
1031 : }
1032 : }
1033 :
1034 0 : status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
1035 0 : if (NT_STATUS_IS_OK(status)) {
1036 0 : if (strequal(s, "Printer")) {
1037 0 : r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
1038 : }
1039 : }
1040 :
1041 0 : status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1042 0 : if (!NT_STATUS_IS_OK(status)) {
1043 0 : return status;
1044 : }
1045 0 : if (!strequal(s, "\"$Windows NT$\"")) {
1046 0 : return NT_STATUS_INVALID_SIGNATURE;
1047 : }
1048 :
1049 0 : r->version = SPOOLSS_DRIVER_VERSION_200X;
1050 0 : status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
1051 0 : if (NT_STATUS_IS_OK(status)) {
1052 0 : int cmp = strncasecmp_m(s, "4.0", 3);
1053 0 : if (cmp == 0) {
1054 0 : r->version = SPOOLSS_DRIVER_VERSION_2012;
1055 : }
1056 0 : if (strequal(s, "3.0")) {
1057 0 : r->version = SPOOLSS_DRIVER_VERSION_200X;
1058 : }
1059 : }
1060 :
1061 0 : status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
1062 0 : if (NT_STATUS_IS_OK(status)) {
1063 0 : if (s != NULL) {
1064 0 : r->provider = talloc_strdup(mem_ctx, s);
1065 0 : if (r->provider == NULL) {
1066 0 : return NT_STATUS_NO_MEMORY;
1067 : }
1068 : }
1069 : }
1070 :
1071 0 : status = process_driver_driverver(ctx, r);
1072 0 : if (!NT_STATUS_IS_OK(status)) {
1073 0 : return status;
1074 : }
1075 :
1076 0 : r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1077 :
1078 0 : status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
1079 0 : if (NT_STATUS_IS_OK(status)) {
1080 0 : int cmp = strncasecmp_m(s, "2", 1);
1081 0 : if (cmp == 0) {
1082 0 : r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
1083 : }
1084 0 : cmp = strncasecmp_m(s, "0", 1);
1085 0 : if (cmp == 0) {
1086 0 : r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1087 : }
1088 : }
1089 :
1090 0 : status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1091 0 : if (!NT_STATUS_IS_OK(status)) {
1092 0 : return status;
1093 : }
1094 :
1095 0 : status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
1096 0 : if (!NT_STATUS_IS_OK(status)) {
1097 : /* not critical */
1098 0 : }
1099 :
1100 0 : status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
1101 0 : if (NT_STATUS_IS_OK(status)) {
1102 0 : if (ok) {
1103 0 : r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1104 : }
1105 : }
1106 :
1107 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1108 : "PrinterPackageInstallation", short_environment, "PackageAware");
1109 0 : if (key == NULL) {
1110 0 : return NT_STATUS_NO_MEMORY;
1111 : }
1112 :
1113 0 : status = gp_inifile_getbool(ctx, key, &ok);
1114 0 : if (NT_STATUS_IS_OK(status)) {
1115 0 : if (ok) {
1116 0 : r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1117 : }
1118 : }
1119 :
1120 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1121 : "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1122 0 : if (key == NULL) {
1123 0 : return NT_STATUS_NO_MEMORY;
1124 : }
1125 :
1126 0 : status = gp_inifile_getstring(ctx, key, &s);
1127 0 : if (NT_STATUS_IS_OK(status)) {
1128 0 : char **list;
1129 0 : r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
1130 0 : if (r->core_driver_dependencies == NULL) {
1131 0 : return NT_STATUS_NO_MEMORY;
1132 : }
1133 :
1134 0 : list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1135 0 : if (list == NULL) {
1136 0 : return NT_STATUS_NO_MEMORY;
1137 : }
1138 0 : r->core_driver_dependencies->string = const_str_list(list);
1139 : }
1140 :
1141 0 : key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1142 : "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1143 0 : if (key == NULL) {
1144 0 : return NT_STATUS_NO_MEMORY;
1145 : }
1146 :
1147 0 : status = gp_inifile_getstring(ctx, key, &s);
1148 0 : if (NT_STATUS_IS_OK(status)) {
1149 0 : if (strequal(s, "UseDriverVer")) {
1150 0 : r->min_inbox_driver_ver_date = r->driver_date;
1151 0 : r->min_inbox_driver_ver_version = r->driver_version;
1152 : }
1153 : }
1154 :
1155 0 : return NT_STATUS_OK;
1156 : }
1157 :
1158 : /****************************************************************
1159 : parse a printer inf file
1160 : ****************************************************************/
1161 :
1162 0 : NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
1163 : const char *core_driver_inf,
1164 : const char *filename,
1165 : const char *environment,
1166 : const char *driver_name,
1167 : struct spoolss_AddDriverInfo8 *r,
1168 : const char **source_disk_name)
1169 : {
1170 0 : NTSTATUS status;
1171 0 : struct inf_context *inf_ctx;
1172 :
1173 0 : if (!filename || !environment) {
1174 0 : return NT_STATUS_INVALID_PARAMETER;
1175 : }
1176 :
1177 0 : status = init_inf_context(mem_ctx,
1178 : filename,
1179 : core_driver_inf,
1180 : &inf_ctx);
1181 0 : if (!NT_STATUS_IS_OK(status)) {
1182 0 : return status;
1183 : }
1184 :
1185 0 : status = setup_driver_by_name(mem_ctx, inf_ctx,
1186 : filename,
1187 : environment,
1188 : driver_name,
1189 : r,
1190 : source_disk_name);
1191 0 : if (!NT_STATUS_IS_OK(status)) {
1192 0 : return status;
1193 : }
1194 :
1195 0 : return NT_STATUS_OK;
1196 : }
1197 :
1198 0 : NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
1199 : const char *core_driver_inf,
1200 : const char *filename,
1201 : const char *environment,
1202 : uint32_t *count,
1203 : struct spoolss_AddDriverInfo8 **_r)
1204 : {
1205 0 : NTSTATUS status;
1206 0 : const char *short_environment;
1207 0 : size_t d, num_devices = 0;
1208 0 : const char **devices = NULL;
1209 0 : const char **device_values = NULL;
1210 0 : struct inf_context *inf_ctx;
1211 :
1212 0 : if (!filename || !environment) {
1213 0 : return NT_STATUS_INVALID_PARAMETER;
1214 : }
1215 :
1216 0 : short_environment = spoolss_get_short_filesys_environment(environment);
1217 0 : if (short_environment == NULL) {
1218 0 : return NT_STATUS_INVALID_PARAMETER;
1219 : }
1220 :
1221 0 : status = init_inf_context(mem_ctx,
1222 : filename,
1223 : core_driver_inf,
1224 : &inf_ctx);
1225 0 : if (!NT_STATUS_IS_OK(status)) {
1226 0 : return status;
1227 : }
1228 :
1229 0 : status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
1230 : &num_devices,
1231 : &devices,
1232 : &device_values);
1233 0 : if (!NT_STATUS_IS_OK(status)) {
1234 0 : return status;
1235 : }
1236 :
1237 0 : for (d = 0; d < num_devices; d++) {
1238 :
1239 0 : struct spoolss_AddDriverInfo8 r;
1240 0 : const char *source_disk_name;
1241 :
1242 0 : ZERO_STRUCT(r);
1243 :
1244 0 : status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
1245 0 : environment, devices[d], &r,
1246 : &source_disk_name);
1247 0 : if (!NT_STATUS_IS_OK(status)) {
1248 0 : return status;
1249 : }
1250 :
1251 0 : ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1252 : }
1253 :
1254 0 : return NT_STATUS_OK;
1255 : }
|