forest_update: behave more like a Windows 2022 server
[Samba.git] / lib / printer_driver / printer_driver.c
blob35260c2907573dcc190a5ca08e51327367a1ce23
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Guenther Deschner 2016
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.
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.
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/>.
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"
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)
35 /* GetPrinterDriverDirectory -> drivers and dependent files */
36 #define PRINTER_INF_DIRID_66000
38 /* GetPrintProcessorDirectory -> print processors */
39 #define PRINTER_INF_DIRID_66001
41 /* GetColorDirectory -> color profiles */
42 #define PRINTER_INF_DIRID_66003
44 static const char *get_string_unquote(const char *s)
46 bool ok;
47 size_t len;
49 if (s == NULL) {
50 return NULL;
53 len = strlen(s);
54 if (len < 2) {
55 return s;
58 if (s[0] == '"' && s[len-1] == '"') {
59 ok = trim_string(discard_const(s), "\"", "\"");
60 if (!ok) {
61 return NULL;
65 return s;
69 * '%STRING%' indicates STRING is localized in the [Strings] section
72 static const char *get_string_token(struct gp_inifile_context *ctx,
73 const char *s)
75 NTSTATUS status;
76 bool ok;
77 char *key;
78 const char *s2;
80 if (s != NULL && s[0] != '%' && s[strlen(s)-1] != '%') {
81 return s;
84 ok = trim_string(discard_const(s), "%", "%");
85 if (!ok) {
86 return NULL;
89 key = talloc_asprintf(ctx, "Strings:%s", s);
90 if (key == NULL) {
91 return NULL;
94 status = gp_inifile_getstring(ctx, key, &s2);
95 talloc_free(key);
96 if (!NT_STATUS_IS_OK(status)) {
97 /* what can you do... */
98 return s;
101 return s2;
104 static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
105 const char *key,
106 const char **ret)
108 NTSTATUS status;
109 const char *s;
111 status = gp_inifile_getstring(ctx, key, &s);
112 if (!NT_STATUS_IS_OK(status)) {
113 return status;
116 s = get_string_unquote(s);
117 if (s == NULL) {
118 return NT_STATUS_INTERNAL_ERROR;
121 if (s[0] == '%' && s[strlen(s)-1] == '%') {
122 s = get_string_token(ctx, s);
125 s = get_string_unquote(s);
126 if (s == NULL) {
127 return NT_STATUS_INTERNAL_ERROR;
130 *ret = s;
132 return NT_STATUS_OK;
135 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)
140 NTSTATUS status;
141 size_t num_keys = 0;
142 const char **keys = NULL;
143 const char **values = NULL;
144 const char *s;
145 char *p;
147 status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
148 if (!NT_STATUS_IS_OK(status)) {
149 return status;
152 if (num_keys < 1) {
153 return NT_STATUS_INVALID_PARAMETER;
156 s = talloc_strdup(mem_ctx, keys[0]);
157 if (s == NULL) {
158 return NT_STATUS_NO_MEMORY;
161 p = strchr(s, ':');
162 if (p == NULL) {
163 return NT_STATUS_NO_MEMORY;
165 *p = '\0';
166 p++;
168 s = get_string_unquote(p);
169 if (s == NULL) {
170 return NT_STATUS_INTERNAL_ERROR;
173 s = get_string_token(ctx, s);
175 s = get_string_unquote(s);
176 if (s == NULL) {
177 return NT_STATUS_INTERNAL_ERROR;
180 if (s != NULL) {
181 *manufacturer_name = talloc_strdup(mem_ctx, s);
182 if (*manufacturer_name == NULL) {
183 return NT_STATUS_NO_MEMORY;
187 talloc_free(keys);
188 talloc_free(values);
190 return NT_STATUS_OK;
193 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)
199 NTSTATUS status;
200 size_t num_keys = 0;
201 const char **keys = NULL;
202 const char **values = NULL;
203 const char *s;
204 char *p;
206 status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
208 if (!NT_STATUS_IS_OK(status)) {
209 return status;
212 if (num_keys < 1) {
213 return NT_STATUS_INVALID_PARAMETER;
216 p = strchr(keys[0], ':');
217 if (p == NULL) {
218 return NT_STATUS_NO_MEMORY;
220 *p = '\0';
221 p++;
223 s = get_string_unquote(p);
224 if (s == NULL) {
225 return NT_STATUS_INTERNAL_ERROR;
228 s = get_string_token(ctx, s);
230 s = get_string_unquote(s);
231 if (s == NULL) {
232 return NT_STATUS_INTERNAL_ERROR;
235 if (strequal(s, manufacturer_name)) {
236 s = get_string_unquote(values[0]);
237 if (s == NULL) {
238 return NT_STATUS_INTERNAL_ERROR;
242 if (s != NULL) {
243 *manufacturer_url = talloc_strdup(mem_ctx, s);
244 if (*manufacturer_url == NULL) {
245 return NT_STATUS_NO_MEMORY;
249 talloc_free(keys);
250 talloc_free(values);
252 return NT_STATUS_OK;
255 static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
256 const char *s,
257 struct spoolss_StringArray **r)
259 size_t count = 2;
260 struct spoolss_StringArray *a = *r;
261 bool ok;
262 int i;
264 if (a == NULL) {
265 a = talloc_zero(mem_ctx, struct spoolss_StringArray);
266 if (a == NULL) {
267 return NT_STATUS_NO_MEMORY;
271 if (a->string == NULL) {
272 a->string = talloc_zero_array(a, const char *, count);
273 if (a->string == NULL) {
274 return NT_STATUS_NO_MEMORY;
278 for (i = 0; a->string[i] != NULL; i++) { ;; }
279 count = i;
281 ok = add_string_to_array(mem_ctx, s, &a->string, &count);
282 if (!ok) {
283 return NT_STATUS_NO_MEMORY;
286 a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
287 if (a->string == NULL) {
288 return NT_STATUS_NO_MEMORY;
290 a->string[count] = NULL;
292 *r = a;
294 return NT_STATUS_OK;
297 static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
298 const char *file,
299 struct spoolss_StringArray **r)
301 char *p;
303 if (file == NULL) {
304 return NT_STATUS_INVALID_PARAMETER;
307 if (file[0] == '@') {
308 file++;
311 p = strchr(file, ',');
312 if (p != NULL) {
313 *p = '\0';
316 return add_string_to_spoolss_array(mem_ctx, file, r);
320 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section
322 * [Manufacturer]
323 * "Kyocera"=Kyocera,NTx86.5.1,NTx86.6.0,NTamd64.5.1,NTamd64.6.0
326 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)
332 NTSTATUS status;
333 size_t i, num_manufacturers = 0;
334 const char **manufacturers = NULL;
335 const char **values = NULL;
336 char *p;
337 bool ok;
339 status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
340 if (!NT_STATUS_IS_OK(status)) {
341 return status;
344 for (i = 0; i < num_manufacturers; i++) {
346 const char *models_section_name;
347 const char *s;
348 char **decorations;
349 int j;
351 DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
353 status = gp_inifile_getstring(ctx, manufacturers[i], &s);
354 if (!NT_STATUS_IS_OK(status)) {
355 return status;
358 decorations = str_list_make_v3(mem_ctx, s, ",");
359 if (decorations == NULL) {
360 return NT_STATUS_NO_MEMORY;
363 models_section_name = decorations[0];
365 for (j = 1; decorations[j] != NULL; j++) {
368 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
371 const char *decorated_models_section_name;
372 size_t d, num_devices = 0;
373 const char **devices = NULL;
374 const char **device_values = NULL;
375 size_t c = 0;
377 decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
378 models_section_name,
379 decorations[j]);
380 if (decorated_models_section_name == NULL) {
381 return NT_STATUS_NO_MEMORY;
384 DEBUG(11,("processing decorated models_section_name: %s\n",
385 decorated_models_section_name));
387 status = gp_inifile_enum_section(ctx, decorated_models_section_name,
388 &num_devices, &devices,
389 &device_values);
390 for (d = 0; d < num_devices; d++) {
392 DEBUG(11,("processing device: %s\n",
393 devices[d]));
395 s = talloc_strdup(mem_ctx, devices[d]);
396 if (s == NULL) {
397 return NT_STATUS_NO_MEMORY;
400 p = strchr(s, ':');
401 if (p == NULL) {
402 return NT_STATUS_DRIVER_INTERNAL_ERROR;
405 *p = '\0';
406 p++;
408 s = get_string_unquote(p);
410 ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
411 if (!ok) {
412 return NT_STATUS_NO_MEMORY;
414 ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
415 if (!ok) {
416 return NT_STATUS_NO_MEMORY;
422 return NT_STATUS_OK;
425 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)
430 NTSTATUS status;
431 size_t d, num_devices = 0;
432 const char **devices = NULL;
433 const char **device_values = NULL;
435 if (device_description == NULL) {
436 return NT_STATUS_INVALID_PARAMETER;
439 status = enum_devices_in_toc(ctx, mem_ctx,
440 &num_devices,
441 &devices,
442 &device_values);
443 if (!NT_STATUS_IS_OK(status)) {
444 return status;
447 for (d = 0; d < num_devices; d++) {
449 if (strequal(device_description, devices[d])) {
451 DEBUG(10,("found device_description: %s\n",
452 device_description));
454 *value = talloc_strdup(mem_ctx, device_values[d]);
455 if (*value == NULL) {
456 return NT_STATUS_NO_MEMORY;
458 DEBUGADD(10,("and returned: %s\n", *value));
460 return NT_STATUS_OK;
464 return NT_STATUS_DRIVER_INTERNAL_ERROR;
468 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
471 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)
476 NTSTATUS status;
477 size_t i, num_keys = 0;
478 char *p, *key;
479 const char **keys = NULL;
480 const char **values = NULL;
481 char *str;
482 const char *s;
484 key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
485 if (key == NULL) {
486 return NT_STATUS_NO_MEMORY;
489 DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
491 status = gp_inifile_getstring(ctx, key, &s);
492 if (!NT_STATUS_IS_OK(status)) {
493 return NT_STATUS_OK;
496 DEBUG(10,("these are the files to copy: %s\n", s));
498 while (next_token_talloc(mem_ctx, &s, &str, ",")) {
500 DEBUG(10,("trying section: %s\n", str));
502 if (str[0] == '@') {
503 DEBUG(10,("adding dependent driver file: %s\n", str));
504 status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
505 if (!NT_STATUS_IS_OK(status)) {
506 return status;
508 continue;
511 status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
512 if (NT_STATUS_IS_OK(status)) {
513 for (i = 0; i < num_keys; i++) {
514 p = strchr(keys[i], ':');
515 if (p == NULL) {
516 return NT_STATUS_INVALID_PARAMETER;
518 *p = '\0';
519 p++;
521 DEBUG(10,("adding dependent driver file: %s\n", p));
523 status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
524 if (!NT_STATUS_IS_OK(status)) {
525 return status;
528 TALLOC_FREE(keys);
529 TALLOC_FREE(values);
533 return NT_STATUS_OK;
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); \
547 } while(0);
549 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)
554 NTSTATUS status;
555 const char *key, *s;
557 key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
558 if (key == NULL) {
559 return NT_STATUS_NO_MEMORY;
562 status = gp_inifile_getstring_ext(ctx, key, &s);
563 if (NT_STATUS_IS_OK(status)) {
565 status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
566 if (!NT_STATUS_IS_OK(status)) {
567 return status;
571 return NT_STATUS_OK;
574 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)
579 NTSTATUS status;
580 char *key, *p;
581 const char *s;
583 key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
584 if (key == NULL) {
585 return NT_STATUS_NO_MEMORY;
588 status = gp_inifile_getstring_ext(ctx, key, &s);
589 if (NT_STATUS_IS_OK(status)) {
590 s = get_string_unquote(s);
592 p = strchr(s, ',');
593 if (p == NULL) {
594 return NT_STATUS_INVALID_PARAMETER;
596 *p = '\0';
597 r->print_processor = talloc_strdup(mem_ctx, s);
598 if (r->print_processor == NULL) {
599 return NT_STATUS_NO_MEMORY;
603 return NT_STATUS_OK;
606 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)
611 NTSTATUS status;
612 char *key;
613 const char *s;
615 key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
616 if (key == NULL) {
617 return NT_STATUS_NO_MEMORY;
620 status = gp_inifile_getstring(ctx, key, &s);
621 if (NT_STATUS_IS_OK(status)) {
622 process_driver_section_val(ctx, mem_ctx, s, r,
623 "DriverFile", driver_path);
624 process_driver_section_val(ctx, mem_ctx, s, r,
625 "HelpFile", help_file);
626 process_driver_section_val(ctx, mem_ctx, s, r,
627 "DataFile", data_file);
628 process_driver_section_val(ctx, mem_ctx, s, r,
629 "ConfigFile", config_file);
632 return NT_STATUS_OK;
636 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)
641 NTSTATUS status;
642 size_t i, num_keys = 0;
643 const char **keys = NULL;
644 const char **values = NULL;
646 DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
648 status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
649 if (!NT_STATUS_IS_OK(status)) {
650 return status;
653 for (i = 0; i < num_keys; i++) {
655 status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
656 if (!NT_STATUS_IS_OK(status)) {
657 return status;
660 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
661 "DriverFile", driver_path);
662 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
663 "HelpFile", help_file);
664 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
665 "ConfigFile", config_file);
667 status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
668 if (!NT_STATUS_IS_OK(status)) {
669 return status;
673 talloc_free(keys);
674 talloc_free(values);
676 return NT_STATUS_OK;
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"
682 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)
687 NTSTATUS status;
688 char *p;
689 char **list;
690 int i;
692 list = str_list_make_v3(mem_ctx, value, ",");
693 if (list == NULL) {
694 return NT_STATUS_NO_MEMORY;
697 for (i = 0; list[i] != NULL; i++) {
698 char **array;
699 int a;
701 /* FIXME: do we have to validate the core driver guid ? */
703 p = strchr(list[i], ',');
704 if (p != NULL) {
705 *p = '\0';
706 p++;
709 DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
711 array = str_list_make_v3(mem_ctx, p, ",");
712 if (array == NULL) {
713 return NT_STATUS_NO_MEMORY;
716 for (a = 0; array[a] != NULL; a++) {
718 if (core_ctx == NULL) {
719 DEBUG(0,("Need to process CoreDriverSections but "
720 "have no Core Driver Context!\n"));
721 return NT_STATUS_DRIVER_INTERNAL_ERROR;
724 status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
725 if (!NT_STATUS_IS_OK(status)) {
726 continue;
731 return NT_STATUS_OK;
735 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
737 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)
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;
751 status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
752 if (!NT_STATUS_IS_OK(status)) {
753 return status;
756 r->driver_name = talloc_strdup(mem_ctx, driver_name);
757 if (r->driver_name == NULL) {
758 return NT_STATUS_NO_MEMORY;
761 ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
762 if (!ok) {
763 return NT_STATUS_INVALID_PARAMETER;
766 DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
767 driver_name, value, install_section_name));
769 /* Hardware Id is optional */
770 ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
771 if (ok) {
772 r->hardware_id = hw_id;
775 status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
776 if (!NT_STATUS_IS_OK(status)) {
777 return status;
780 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
781 "DriverFile", driver_path);
782 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
783 "HelpFile", help_file);
784 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
785 "DataFile", data_file);
786 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
787 "ConfigFile", config_file);
789 status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
790 if (!NT_STATUS_IS_OK(status)) {
791 return status;
794 status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
795 if (!NT_STATUS_IS_OK(status)) {
796 return status;
799 key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
800 if (key == NULL) {
801 return NT_STATUS_NO_MEMORY;
804 status = gp_inifile_getstring(ctx, key, &s);
805 if (NT_STATUS_IS_OK(status)) {
807 DEBUG(10,("found CoreDriverSections: %s\n", s));
809 status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
810 if (!NT_STATUS_IS_OK(status)) {
811 return status;
815 return NT_STATUS_OK;
818 struct inf_context {
819 struct gp_inifile_context *ctx;
820 struct gp_inifile_context *core_ctx;
823 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)
828 NTSTATUS status;
829 struct gp_inifile_context *ctx;
830 struct gp_inifile_context *core_ctx = NULL;
831 struct inf_context *inf_ctx;
833 inf_ctx = talloc_zero(mem_ctx, struct inf_context);
834 if (inf_ctx == NULL) {
835 return NT_STATUS_NO_MEMORY;
838 status = gp_inifile_init_context_direct(mem_ctx,
839 inf_filename,
840 &ctx);
841 if (!NT_STATUS_IS_OK(status)) {
842 DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
843 return status;
846 if (ctx->generated_filename != NULL) {
847 unlink(ctx->generated_filename);
850 if (core_filename != NULL) {
851 status = gp_inifile_init_context_direct(mem_ctx,
852 core_filename,
853 &core_ctx);
854 if (!NT_STATUS_IS_OK(status)) {
855 DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
856 return status;
859 if (core_ctx->generated_filename != NULL) {
860 unlink(core_ctx->generated_filename);
864 inf_ctx->ctx = ctx;
865 inf_ctx->core_ctx = core_ctx;
867 *_inf_ctx = inf_ctx;
869 return NT_STATUS_OK;
872 static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
873 struct spoolss_AddDriverInfo8 *r)
875 NTSTATUS status;
876 const char *s;
877 char *p;
878 bool ok;
879 const char *str;
881 status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
882 if (!NT_STATUS_IS_OK(status)) {
883 return status;
886 str = talloc_strdup(ctx, s);
887 if (str == NULL) {
888 return NT_STATUS_NO_MEMORY;
891 p = strchr(str, ',');
892 if (p) {
893 *p = '\0';
894 p++;
897 ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
898 if (!ok) {
899 return NT_STATUS_INVALID_PARAMETER;
902 ok = spoolss_driver_version_to_qword(p, &r->driver_version);
903 if (!ok) {
904 return NT_STATUS_INVALID_PARAMETER;
907 return NT_STATUS_OK;
911 * Parse a SourceDisksNames section,
912 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
914 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)
919 NTSTATUS status;
920 bool ok;
921 const char *key;
922 size_t i, num_keys = 0;
923 const char **keys = NULL;
924 const char **values = NULL;
926 key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
927 if (key == NULL) {
928 return NT_STATUS_NO_MEMORY;
931 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
932 if (!NT_STATUS_IS_OK(status)) {
933 return status;
936 if (keys == NULL && values == NULL) {
937 key = "SourceDisksNames";
939 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
940 if (!NT_STATUS_IS_OK(status)) {
941 return status;
945 for (i = 0; i < num_keys; i++) {
948 * 1 = %Disk1%,,,"Amd64"
949 * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
951 char *disk_description, *tag_or_cab_file, *unused, *path;
953 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
954 if (!ok) {
955 continue;
958 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
959 if (!ok) {
960 continue;
963 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
964 if (!ok) {
965 continue;
968 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
969 if (!ok) {
970 continue;
973 *source_disk_name = path;
975 return NT_STATUS_OK;
978 return NT_STATUS_NOT_FOUND;
981 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)
989 NTSTATUS status;
990 struct gp_inifile_context *ctx = inf_ctx->ctx;
991 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;
997 short_environment = spoolss_get_short_filesys_environment(environment);
998 if (short_environment == NULL) {
999 return NT_STATUS_INVALID_PARAMETER;
1002 status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
1003 if (!NT_STATUS_IS_OK(status)) {
1004 return status;
1007 status = process_source_disk_name(ctx, mem_ctx,
1008 short_environment,
1009 source_disk_name);
1010 if (!NT_STATUS_IS_OK(status)) {
1011 return status;
1014 r->inf_path = talloc_strdup(mem_ctx, filename);
1015 if (r->inf_path == NULL) {
1016 return NT_STATUS_NO_MEMORY;
1019 r->architecture = talloc_strdup(mem_ctx, environment);
1020 if (r->architecture == NULL) {
1021 return NT_STATUS_NO_MEMORY;
1024 if (r->print_processor == NULL) {
1025 r->print_processor = talloc_strdup(mem_ctx, "winprint");
1026 if (r->print_processor == NULL) {
1027 return NT_STATUS_NO_MEMORY;
1031 status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
1032 if (NT_STATUS_IS_OK(status)) {
1033 if (strequal(s, "Printer")) {
1034 r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
1038 status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 return status;
1042 if (!strequal(s, "\"$Windows NT$\"")) {
1043 return NT_STATUS_INVALID_SIGNATURE;
1046 r->version = SPOOLSS_DRIVER_VERSION_200X;
1047 status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
1048 if (NT_STATUS_IS_OK(status)) {
1049 int cmp = strncasecmp_m(s, "4.0", 3);
1050 if (cmp == 0) {
1051 r->version = SPOOLSS_DRIVER_VERSION_2012;
1053 if (strequal(s, "3.0")) {
1054 r->version = SPOOLSS_DRIVER_VERSION_200X;
1058 status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
1059 if (NT_STATUS_IS_OK(status)) {
1060 if (s != NULL) {
1061 r->provider = talloc_strdup(mem_ctx, s);
1062 if (r->provider == NULL) {
1063 return NT_STATUS_NO_MEMORY;
1068 status = process_driver_driverver(ctx, r);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 return status;
1073 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1075 status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
1076 if (NT_STATUS_IS_OK(status)) {
1077 int cmp = strncasecmp_m(s, "2", 1);
1078 if (cmp == 0) {
1079 r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
1081 cmp = strncasecmp_m(s, "0", 1);
1082 if (cmp == 0) {
1083 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1087 status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 return status;
1092 status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 /* not critical */
1097 status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
1098 if (NT_STATUS_IS_OK(status)) {
1099 if (ok) {
1100 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1104 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1105 "PrinterPackageInstallation", short_environment, "PackageAware");
1106 if (key == NULL) {
1107 return NT_STATUS_NO_MEMORY;
1110 status = gp_inifile_getbool(ctx, key, &ok);
1111 if (NT_STATUS_IS_OK(status)) {
1112 if (ok) {
1113 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1117 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1118 "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1119 if (key == NULL) {
1120 return NT_STATUS_NO_MEMORY;
1123 status = gp_inifile_getstring(ctx, key, &s);
1124 if (NT_STATUS_IS_OK(status)) {
1125 char **list;
1126 r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
1127 if (r->core_driver_dependencies == NULL) {
1128 return NT_STATUS_NO_MEMORY;
1131 list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1132 if (list == NULL) {
1133 return NT_STATUS_NO_MEMORY;
1135 r->core_driver_dependencies->string = const_str_list(list);
1138 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1139 "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1140 if (key == NULL) {
1141 return NT_STATUS_NO_MEMORY;
1144 status = gp_inifile_getstring(ctx, key, &s);
1145 if (NT_STATUS_IS_OK(status)) {
1146 if (strequal(s, "UseDriverVer")) {
1147 r->min_inbox_driver_ver_date = r->driver_date;
1148 r->min_inbox_driver_ver_version = r->driver_version;
1152 return NT_STATUS_OK;
1155 /****************************************************************
1156 parse the a printer inf file
1157 ****************************************************************/
1159 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)
1167 NTSTATUS status;
1168 struct inf_context *inf_ctx;
1170 if (!filename || !environment) {
1171 return NT_STATUS_INVALID_PARAMETER;
1174 status = init_inf_context(mem_ctx,
1175 filename,
1176 core_driver_inf,
1177 &inf_ctx);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 return status;
1182 status = setup_driver_by_name(mem_ctx, inf_ctx,
1183 filename,
1184 environment,
1185 driver_name,
1187 source_disk_name);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 return status;
1192 return NT_STATUS_OK;
1195 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)
1202 NTSTATUS status;
1203 const char *short_environment;
1204 size_t d, num_devices = 0;
1205 const char **devices = NULL;
1206 const char **device_values = NULL;
1207 struct inf_context *inf_ctx;
1209 if (!filename || !environment) {
1210 return NT_STATUS_INVALID_PARAMETER;
1213 short_environment = spoolss_get_short_filesys_environment(environment);
1214 if (short_environment == NULL) {
1215 return NT_STATUS_INVALID_PARAMETER;
1218 status = init_inf_context(mem_ctx,
1219 filename,
1220 core_driver_inf,
1221 &inf_ctx);
1222 if (!NT_STATUS_IS_OK(status)) {
1223 return status;
1226 status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
1227 &num_devices,
1228 &devices,
1229 &device_values);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 return status;
1234 for (d = 0; d < num_devices; d++) {
1236 struct spoolss_AddDriverInfo8 r;
1237 const char *source_disk_name;
1239 ZERO_STRUCT(r);
1241 status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
1242 environment, devices[d], &r,
1243 &source_disk_name);
1244 if (!NT_STATUS_IS_OK(status)) {
1245 return status;
1248 ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1251 return NT_STATUS_OK;