s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / lib / printer_driver / printer_driver.c
blobf04952eba64da3f256e0f2a8fbd23988ed62fa81
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"
25 #include "source3/include/smb_macros.h"
27 /* GetPrinterDriverDirectory -> drivers and dependent files */
28 #define PRINTER_INF_DIRID_66000
30 /* GetPrintProcessorDirectory -> print processors */
31 #define PRINTER_INF_DIRID_66001
33 /* GetColorDirectory -> color profiles */
34 #define PRINTER_INF_DIRID_66003
36 static const char *get_string_unquote(const char *s)
38 bool ok;
39 size_t len;
41 if (s == NULL) {
42 return NULL;
45 len = strlen(s);
46 if (len < 2) {
47 return s;
50 if (s[0] == '"' && s[len-1] == '"') {
51 ok = trim_string(discard_const(s), "\"", "\"");
52 if (!ok) {
53 return NULL;
57 return s;
61 * '%STRING%' indicates STRING is localized in the [Strings] section
64 static const char *get_string_token(struct gp_inifile_context *ctx,
65 const char *s)
67 NTSTATUS status;
68 bool ok;
69 char *key;
70 const char *s2;
72 if (s != NULL && s[0] != '%' && s[strlen(s)-1] != '%') {
73 return s;
76 ok = trim_string(discard_const(s), "%", "%");
77 if (!ok) {
78 return NULL;
81 key = talloc_asprintf(ctx, "Strings:%s", s);
82 if (key == NULL) {
83 return NULL;
86 status = gp_inifile_getstring(ctx, key, &s2);
87 talloc_free(key);
88 if (!NT_STATUS_IS_OK(status)) {
89 /* what can you do... */
90 return s;
93 return s2;
96 static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
97 const char *key,
98 const char **ret)
100 NTSTATUS status;
101 const char *s;
103 status = gp_inifile_getstring(ctx, key, &s);
104 if (!NT_STATUS_IS_OK(status)) {
105 return status;
108 s = get_string_unquote(s);
109 if (s == NULL) {
110 return NT_STATUS_INTERNAL_ERROR;
113 if (s[0] == '%' && s[strlen(s)-1] == '%') {
114 s = get_string_token(ctx, s);
117 s = get_string_unquote(s);
118 if (s == NULL) {
119 return NT_STATUS_INTERNAL_ERROR;
122 *ret = s;
124 return NT_STATUS_OK;
127 static NTSTATUS find_manufacturer_name(struct gp_inifile_context *ctx,
128 TALLOC_CTX *mem_ctx,
129 const char *section_name,
130 const char **manufacturer_name)
132 NTSTATUS status;
133 size_t num_keys = 0;
134 const char **keys = NULL;
135 const char **values = NULL;
136 const char *s;
137 char *p;
139 status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
140 if (!NT_STATUS_IS_OK(status)) {
141 return status;
144 if (num_keys < 1) {
145 return NT_STATUS_INVALID_PARAMETER;
148 s = talloc_strdup(mem_ctx, keys[0]);
149 if (s == NULL) {
150 return NT_STATUS_NO_MEMORY;
153 p = strchr(s, ':');
154 if (p == NULL) {
155 return NT_STATUS_NO_MEMORY;
157 *p = '\0';
158 p++;
160 s = get_string_unquote(p);
161 if (s == NULL) {
162 return NT_STATUS_INTERNAL_ERROR;
165 s = get_string_token(ctx, s);
167 s = get_string_unquote(s);
168 if (s == NULL) {
169 return NT_STATUS_INTERNAL_ERROR;
172 if (s != NULL) {
173 *manufacturer_name = talloc_strdup(mem_ctx, s);
174 if (*manufacturer_name == NULL) {
175 return NT_STATUS_NO_MEMORY;
179 talloc_free(keys);
180 talloc_free(values);
182 return NT_STATUS_OK;
185 static NTSTATUS find_manufacturer_url(struct gp_inifile_context *ctx,
186 TALLOC_CTX *mem_ctx,
187 const char *section_name,
188 const char *manufacturer_name,
189 const char **manufacturer_url)
191 NTSTATUS status;
192 size_t num_keys = 0;
193 const char **keys = NULL;
194 const char **values = NULL;
195 const char *s;
196 char *p;
198 status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
200 if (!NT_STATUS_IS_OK(status)) {
201 return status;
204 if (num_keys < 1) {
205 return NT_STATUS_INVALID_PARAMETER;
208 p = strchr(keys[0], ':');
209 if (p == NULL) {
210 return NT_STATUS_NO_MEMORY;
212 *p = '\0';
213 p++;
215 s = get_string_unquote(p);
216 if (s == NULL) {
217 return NT_STATUS_INTERNAL_ERROR;
220 s = get_string_token(ctx, s);
222 s = get_string_unquote(s);
223 if (s == NULL) {
224 return NT_STATUS_INTERNAL_ERROR;
227 if (strequal(s, manufacturer_name)) {
228 s = get_string_unquote(values[0]);
229 if (s == NULL) {
230 return NT_STATUS_INTERNAL_ERROR;
234 if (s != NULL) {
235 *manufacturer_url = talloc_strdup(mem_ctx, s);
236 if (*manufacturer_url == NULL) {
237 return NT_STATUS_NO_MEMORY;
241 talloc_free(keys);
242 talloc_free(values);
244 return NT_STATUS_OK;
247 static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
248 const char *s,
249 struct spoolss_StringArray **r)
251 size_t count = 2;
252 struct spoolss_StringArray *a = *r;
253 bool ok;
254 int i;
256 if (a == NULL) {
257 a = talloc_zero(mem_ctx, struct spoolss_StringArray);
258 if (a == NULL) {
259 return NT_STATUS_NO_MEMORY;
263 if (a->string == NULL) {
264 a->string = talloc_zero_array(a, const char *, count);
265 if (a->string == NULL) {
266 return NT_STATUS_NO_MEMORY;
270 for (i = 0; a->string[i] != NULL; i++) { ;; }
271 count = i;
273 ok = add_string_to_array(mem_ctx, s, &a->string, &count);
274 if (!ok) {
275 return NT_STATUS_NO_MEMORY;
278 a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
279 if (a->string == NULL) {
280 return NT_STATUS_NO_MEMORY;
282 a->string[count] = NULL;
284 *r = a;
286 return NT_STATUS_OK;
289 static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
290 const char *file,
291 struct spoolss_StringArray **r)
293 char *p;
295 if (file == NULL) {
296 return NT_STATUS_INVALID_PARAMETER;
299 if (file[0] == '@') {
300 file++;
303 p = strchr(file, ',');
304 if (p != NULL) {
305 *p = '\0';
308 return add_string_to_spoolss_array(mem_ctx, file, r);
312 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section
314 * [Manufacturer]
315 * "Kyocera"=Kyocera,NTx86.5.1,NTx86.6.0,NTamd64.5.1,NTamd64.6.0
318 static NTSTATUS enum_devices_in_toc(struct gp_inifile_context *ctx,
319 TALLOC_CTX *mem_ctx,
320 size_t *pnum_devices,
321 const char ***pdevices,
322 const char ***pdevice_values)
324 NTSTATUS status;
325 size_t i, num_manufacturers = 0;
326 const char **manufacturers = NULL;
327 const char **values = NULL;
328 char *p;
329 bool ok;
331 status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
332 if (!NT_STATUS_IS_OK(status)) {
333 return status;
336 for (i = 0; i < num_manufacturers; i++) {
338 const char *models_section_name;
339 const char *s;
340 char **decorations;
341 int j;
343 DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
345 status = gp_inifile_getstring(ctx, manufacturers[i], &s);
346 if (!NT_STATUS_IS_OK(status)) {
347 return status;
350 decorations = str_list_make_v3(mem_ctx, s, ",");
351 if (decorations == NULL) {
352 return NT_STATUS_NO_MEMORY;
355 models_section_name = decorations[0];
357 for (j = 1; decorations[j] != NULL; j++) {
360 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
363 const char *decorated_models_section_name;
364 size_t d, num_devices = 0;
365 const char **devices = NULL;
366 const char **device_values = NULL;
367 size_t c = 0;
369 decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
370 models_section_name,
371 decorations[j]);
372 if (decorated_models_section_name == NULL) {
373 return NT_STATUS_NO_MEMORY;
376 DEBUG(11,("processing decorated models_section_name: %s\n",
377 decorated_models_section_name));
379 status = gp_inifile_enum_section(ctx, decorated_models_section_name,
380 &num_devices, &devices,
381 &device_values);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
385 for (d = 0; d < num_devices; d++) {
387 DEBUG(11,("processing device: %s\n",
388 devices[d]));
390 s = talloc_strdup(mem_ctx, devices[d]);
391 if (s == NULL) {
392 return NT_STATUS_NO_MEMORY;
395 p = strchr(s, ':');
396 if (p == NULL) {
397 return NT_STATUS_DRIVER_INTERNAL_ERROR;
400 *p = '\0';
401 p++;
403 s = get_string_unquote(p);
405 ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
406 if (!ok) {
407 return NT_STATUS_NO_MEMORY;
409 ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
410 if (!ok) {
411 return NT_STATUS_NO_MEMORY;
417 return NT_STATUS_OK;
420 static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
421 TALLOC_CTX *mem_ctx,
422 const char *device_description,
423 const char **value)
425 NTSTATUS status;
426 size_t d, num_devices = 0;
427 const char **devices = NULL;
428 const char **device_values = NULL;
430 if (device_description == NULL) {
431 return NT_STATUS_INVALID_PARAMETER;
434 status = enum_devices_in_toc(ctx, mem_ctx,
435 &num_devices,
436 &devices,
437 &device_values);
438 if (!NT_STATUS_IS_OK(status)) {
439 return status;
442 for (d = 0; d < num_devices; d++) {
444 if (strequal(device_description, devices[d])) {
446 DEBUG(10,("found device_description: %s\n",
447 device_description));
449 *value = talloc_strdup(mem_ctx, device_values[d]);
450 if (*value == NULL) {
451 return NT_STATUS_NO_MEMORY;
453 DEBUGADD(10,("and returned: %s\n", *value));
455 return NT_STATUS_OK;
459 return NT_STATUS_DRIVER_INTERNAL_ERROR;
463 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
466 static NTSTATUS process_driver_section_copyfiles(struct gp_inifile_context *ctx,
467 TALLOC_CTX *mem_ctx,
468 const char *driver_section,
469 struct spoolss_AddDriverInfo8 *r)
471 NTSTATUS status;
472 size_t i, num_keys = 0;
473 char *p, *key;
474 const char **keys = NULL;
475 const char **values = NULL;
476 char *str;
477 const char *s;
479 key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
480 if (key == NULL) {
481 return NT_STATUS_NO_MEMORY;
484 DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
486 status = gp_inifile_getstring(ctx, key, &s);
487 if (!NT_STATUS_IS_OK(status)) {
488 return NT_STATUS_OK;
491 DEBUG(10,("these are the files to copy: %s\n", s));
493 while (next_token_talloc(mem_ctx, &s, &str, ",")) {
495 DEBUG(10,("trying section: %s\n", str));
497 if (str[0] == '@') {
498 DEBUG(10,("adding dependent driver file: %s\n", str));
499 status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
500 if (!NT_STATUS_IS_OK(status)) {
501 return status;
503 continue;
506 status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
507 if (NT_STATUS_IS_OK(status)) {
508 for (i = 0; i < num_keys; i++) {
509 p = strchr(keys[i], ':');
510 if (p == NULL) {
511 return NT_STATUS_INVALID_PARAMETER;
513 *p = '\0';
514 p++;
516 DEBUG(10,("adding dependent driver file: %s\n", p));
518 status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
519 if (!NT_STATUS_IS_OK(status)) {
520 return status;
523 TALLOC_FREE(keys);
524 TALLOC_FREE(values);
528 return NT_STATUS_OK;
531 #define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
532 do { \
533 NTSTATUS _status; \
534 const char *__key, *_s; \
535 __key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
536 NT_STATUS_HAVE_NO_MEMORY(__key); \
537 _status = gp_inifile_getstring(_ctx, __key, &_s); \
538 if (NT_STATUS_IS_OK(_status)) { \
539 (_r)->_element = talloc_strdup(mem_ctx, _s); \
540 NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
542 } while(0);
544 static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
545 TALLOC_CTX *mem_ctx,
546 const char *section,
547 struct spoolss_AddDriverInfo8 *r)
549 NTSTATUS status;
550 const char *key, *s;
552 key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
553 if (key == NULL) {
554 return NT_STATUS_NO_MEMORY;
557 status = gp_inifile_getstring_ext(ctx, key, &s);
558 if (NT_STATUS_IS_OK(status)) {
560 status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
561 if (!NT_STATUS_IS_OK(status)) {
562 return status;
566 return NT_STATUS_OK;
569 static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
570 TALLOC_CTX *mem_ctx,
571 const char *section,
572 struct spoolss_AddDriverInfo8 *r)
574 NTSTATUS status;
575 char *key, *p;
576 const char *s;
578 key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
579 if (key == NULL) {
580 return NT_STATUS_NO_MEMORY;
583 status = gp_inifile_getstring_ext(ctx, key, &s);
584 if (NT_STATUS_IS_OK(status)) {
585 s = get_string_unquote(s);
587 p = strchr(s, ',');
588 if (p == NULL) {
589 return NT_STATUS_INVALID_PARAMETER;
591 *p = '\0';
592 r->print_processor = talloc_strdup(mem_ctx, s);
593 if (r->print_processor == NULL) {
594 return NT_STATUS_NO_MEMORY;
598 return NT_STATUS_OK;
601 static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
602 TALLOC_CTX *mem_ctx,
603 const char *section,
604 struct spoolss_AddDriverInfo8 *r)
606 NTSTATUS status;
607 char *key;
608 const char *s;
610 key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
611 if (key == NULL) {
612 return NT_STATUS_NO_MEMORY;
615 status = gp_inifile_getstring(ctx, key, &s);
616 if (NT_STATUS_IS_OK(status)) {
617 process_driver_section_val(ctx, mem_ctx, s, r,
618 "DriverFile", driver_path);
619 process_driver_section_val(ctx, mem_ctx, s, r,
620 "HelpFile", help_file);
621 process_driver_section_val(ctx, mem_ctx, s, r,
622 "DataFile", data_file);
623 process_driver_section_val(ctx, mem_ctx, s, r,
624 "ConfigFile", config_file);
627 return NT_STATUS_OK;
631 static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
632 TALLOC_CTX *mem_ctx,
633 const char *driver_section,
634 struct spoolss_AddDriverInfo8 *r)
636 NTSTATUS status;
637 size_t i, num_keys = 0;
638 const char **keys = NULL;
639 const char **values = NULL;
641 DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
643 status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
644 if (!NT_STATUS_IS_OK(status)) {
645 return status;
648 for (i = 0; i < num_keys; i++) {
650 status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
651 if (!NT_STATUS_IS_OK(status)) {
652 return status;
655 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
656 "DriverFile", driver_path);
657 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
658 "HelpFile", help_file);
659 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
660 "ConfigFile", config_file);
662 status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
663 if (!NT_STATUS_IS_OK(status)) {
664 return status;
668 talloc_free(keys);
669 talloc_free(values);
671 return NT_STATUS_OK;
675 * 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"
677 static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
678 TALLOC_CTX *mem_ctx,
679 const char *value,
680 struct spoolss_AddDriverInfo8 *r)
682 NTSTATUS status;
683 char *p;
684 char **list;
685 int i;
687 list = str_list_make_v3(mem_ctx, value, ",");
688 if (list == NULL) {
689 return NT_STATUS_NO_MEMORY;
692 for (i = 0; list[i] != NULL; i++) {
693 char **array;
694 int a;
696 /* FIXME: do we have to validate the core driver guid ? */
698 p = strchr(list[i], ',');
699 if (p != NULL) {
700 *p = '\0';
701 p++;
704 DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
706 array = str_list_make_v3(mem_ctx, p, ",");
707 if (array == NULL) {
708 return NT_STATUS_NO_MEMORY;
711 for (a = 0; array[a] != NULL; a++) {
713 if (core_ctx == NULL) {
714 DEBUG(0,("Need to process CoreDriverSections but "
715 "have no Core Driver Context!\n"));
716 return NT_STATUS_DRIVER_INTERNAL_ERROR;
719 status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
720 if (!NT_STATUS_IS_OK(status)) {
721 continue;
726 return NT_STATUS_OK;
730 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
732 static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
733 struct gp_inifile_context *core_ctx,
734 TALLOC_CTX *mem_ctx,
735 const char *driver_name,
736 struct spoolss_AddDriverInfo8 *r)
738 NTSTATUS status;
739 char *key;
740 const char *s;
741 const char *value;
742 char *install_section_name;
743 bool ok;
744 char *hw_id;
746 status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
747 if (!NT_STATUS_IS_OK(status)) {
748 return status;
751 r->driver_name = talloc_strdup(mem_ctx, driver_name);
752 if (r->driver_name == NULL) {
753 return NT_STATUS_NO_MEMORY;
756 ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
757 if (!ok) {
758 return NT_STATUS_INVALID_PARAMETER;
761 DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
762 driver_name, value, install_section_name));
764 /* Hardware Id is optional */
765 ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
766 if (ok) {
767 r->hardware_id = hw_id;
770 status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
771 if (!NT_STATUS_IS_OK(status)) {
772 return status;
775 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
776 "DriverFile", driver_path);
777 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
778 "HelpFile", help_file);
779 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
780 "DataFile", data_file);
781 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
782 "ConfigFile", config_file);
784 status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
785 if (!NT_STATUS_IS_OK(status)) {
786 return status;
789 status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
790 if (!NT_STATUS_IS_OK(status)) {
791 return status;
794 key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
795 if (key == NULL) {
796 return NT_STATUS_NO_MEMORY;
799 status = gp_inifile_getstring(ctx, key, &s);
800 if (NT_STATUS_IS_OK(status)) {
802 DEBUG(10,("found CoreDriverSections: %s\n", s));
804 status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
805 if (!NT_STATUS_IS_OK(status)) {
806 return status;
810 return NT_STATUS_OK;
813 struct inf_context {
814 struct gp_inifile_context *ctx;
815 struct gp_inifile_context *core_ctx;
818 static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
819 const char *inf_filename,
820 const char *core_filename,
821 struct inf_context **_inf_ctx)
823 NTSTATUS status;
824 struct gp_inifile_context *ctx;
825 struct gp_inifile_context *core_ctx = NULL;
826 struct inf_context *inf_ctx;
828 inf_ctx = talloc_zero(mem_ctx, struct inf_context);
829 if (inf_ctx == NULL) {
830 return NT_STATUS_NO_MEMORY;
833 status = gp_inifile_init_context_direct(mem_ctx,
834 inf_filename,
835 &ctx);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
838 return status;
841 if (ctx->generated_filename != NULL) {
842 unlink(ctx->generated_filename);
845 if (core_filename != NULL) {
846 status = gp_inifile_init_context_direct(mem_ctx,
847 core_filename,
848 &core_ctx);
849 if (!NT_STATUS_IS_OK(status)) {
850 DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
851 return status;
854 if (core_ctx->generated_filename != NULL) {
855 unlink(core_ctx->generated_filename);
859 inf_ctx->ctx = ctx;
860 inf_ctx->core_ctx = core_ctx;
862 *_inf_ctx = inf_ctx;
864 return NT_STATUS_OK;
867 static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
868 struct spoolss_AddDriverInfo8 *r)
870 NTSTATUS status;
871 const char *s;
872 char *p;
873 bool ok;
874 const char *str;
876 status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
877 if (!NT_STATUS_IS_OK(status)) {
878 return status;
881 str = talloc_strdup(ctx, s);
882 if (str == NULL) {
883 return NT_STATUS_NO_MEMORY;
886 p = strchr(str, ',');
887 if (p) {
888 *p = '\0';
889 p++;
892 ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
893 if (!ok) {
894 return NT_STATUS_INVALID_PARAMETER;
897 ok = spoolss_driver_version_to_qword(p, &r->driver_version);
898 if (!ok) {
899 return NT_STATUS_INVALID_PARAMETER;
902 return NT_STATUS_OK;
906 * Parse a SourceDisksNames section,
907 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
909 static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
910 TALLOC_CTX *mem_ctx,
911 const char *short_environment,
912 const char **source_disk_name)
914 NTSTATUS status;
915 bool ok;
916 const char *key;
917 size_t i, num_keys = 0;
918 const char **keys = NULL;
919 const char **values = NULL;
921 key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
922 if (key == NULL) {
923 return NT_STATUS_NO_MEMORY;
926 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
927 if (!NT_STATUS_IS_OK(status)) {
928 return status;
931 if (keys == NULL && values == NULL) {
932 key = "SourceDisksNames";
934 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
935 if (!NT_STATUS_IS_OK(status)) {
936 return status;
940 for (i = 0; i < num_keys; i++) {
943 * 1 = %Disk1%,,,"Amd64"
944 * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
946 char *disk_description, *tag_or_cab_file, *unused, *path;
948 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
949 if (!ok) {
950 continue;
953 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
954 if (!ok) {
955 continue;
958 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
959 if (!ok) {
960 continue;
963 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
964 if (!ok) {
965 continue;
968 *source_disk_name = path;
970 return NT_STATUS_OK;
973 return NT_STATUS_NOT_FOUND;
976 static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
977 struct inf_context *inf_ctx,
978 const char *filename,
979 const char *environment,
980 const char *driver_name,
981 struct spoolss_AddDriverInfo8 *r,
982 const char **source_disk_name)
984 NTSTATUS status;
985 struct gp_inifile_context *ctx = inf_ctx->ctx;
986 struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
987 char *key;
988 bool ok;
989 const char *short_environment;
990 const char *s;
992 short_environment = spoolss_get_short_filesys_environment(environment);
993 if (short_environment == NULL) {
994 return NT_STATUS_INVALID_PARAMETER;
997 status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
998 if (!NT_STATUS_IS_OK(status)) {
999 return status;
1002 status = process_source_disk_name(ctx, mem_ctx,
1003 short_environment,
1004 source_disk_name);
1005 if (!NT_STATUS_IS_OK(status)) {
1006 return status;
1009 r->inf_path = talloc_strdup(mem_ctx, filename);
1010 if (r->inf_path == NULL) {
1011 return NT_STATUS_NO_MEMORY;
1014 r->architecture = talloc_strdup(mem_ctx, environment);
1015 if (r->architecture == NULL) {
1016 return NT_STATUS_NO_MEMORY;
1019 if (r->print_processor == NULL) {
1020 r->print_processor = talloc_strdup(mem_ctx, "winprint");
1021 if (r->print_processor == NULL) {
1022 return NT_STATUS_NO_MEMORY;
1026 status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
1027 if (NT_STATUS_IS_OK(status)) {
1028 if (strequal(s, "Printer")) {
1029 r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
1033 status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 return status;
1037 if (!strequal(s, "\"$Windows NT$\"")) {
1038 return NT_STATUS_INVALID_SIGNATURE;
1041 r->version = SPOOLSS_DRIVER_VERSION_200X;
1042 status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
1043 if (NT_STATUS_IS_OK(status)) {
1044 int cmp = strncasecmp_m(s, "4.0", 3);
1045 if (cmp == 0) {
1046 r->version = SPOOLSS_DRIVER_VERSION_2012;
1048 if (strequal(s, "3.0")) {
1049 r->version = SPOOLSS_DRIVER_VERSION_200X;
1053 status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
1054 if (NT_STATUS_IS_OK(status)) {
1055 if (s != NULL) {
1056 r->provider = talloc_strdup(mem_ctx, s);
1057 if (r->provider == NULL) {
1058 return NT_STATUS_NO_MEMORY;
1063 status = process_driver_driverver(ctx, r);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 return status;
1068 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1070 status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
1071 if (NT_STATUS_IS_OK(status)) {
1072 int cmp = strncasecmp_m(s, "2", 1);
1073 if (cmp == 0) {
1074 r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
1076 cmp = strncasecmp_m(s, "0", 1);
1077 if (cmp == 0) {
1078 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1082 status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 return status;
1087 status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 /* not critical */
1092 status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
1093 if (NT_STATUS_IS_OK(status)) {
1094 if (ok) {
1095 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1099 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1100 "PrinterPackageInstallation", short_environment, "PackageAware");
1101 if (key == NULL) {
1102 return NT_STATUS_NO_MEMORY;
1105 status = gp_inifile_getbool(ctx, key, &ok);
1106 if (NT_STATUS_IS_OK(status)) {
1107 if (ok) {
1108 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1112 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1113 "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1114 if (key == NULL) {
1115 return NT_STATUS_NO_MEMORY;
1118 status = gp_inifile_getstring(ctx, key, &s);
1119 if (NT_STATUS_IS_OK(status)) {
1120 char **list;
1121 r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
1122 if (r->core_driver_dependencies == NULL) {
1123 return NT_STATUS_NO_MEMORY;
1126 list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1127 if (list == NULL) {
1128 return NT_STATUS_NO_MEMORY;
1130 r->core_driver_dependencies->string = const_str_list(list);
1133 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1134 "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1135 if (key == NULL) {
1136 return NT_STATUS_NO_MEMORY;
1139 status = gp_inifile_getstring(ctx, key, &s);
1140 if (NT_STATUS_IS_OK(status)) {
1141 if (strequal(s, "UseDriverVer")) {
1142 r->min_inbox_driver_ver_date = r->driver_date;
1143 r->min_inbox_driver_ver_version = r->driver_version;
1147 return NT_STATUS_OK;
1150 /****************************************************************
1151 parse a printer inf file
1152 ****************************************************************/
1154 NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
1155 const char *core_driver_inf,
1156 const char *filename,
1157 const char *environment,
1158 const char *driver_name,
1159 struct spoolss_AddDriverInfo8 *r,
1160 const char **source_disk_name)
1162 NTSTATUS status;
1163 struct inf_context *inf_ctx;
1165 if (!filename || !environment) {
1166 return NT_STATUS_INVALID_PARAMETER;
1169 status = init_inf_context(mem_ctx,
1170 filename,
1171 core_driver_inf,
1172 &inf_ctx);
1173 if (!NT_STATUS_IS_OK(status)) {
1174 return status;
1177 status = setup_driver_by_name(mem_ctx, inf_ctx,
1178 filename,
1179 environment,
1180 driver_name,
1182 source_disk_name);
1183 if (!NT_STATUS_IS_OK(status)) {
1184 return status;
1187 return NT_STATUS_OK;
1190 NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
1191 const char *core_driver_inf,
1192 const char *filename,
1193 const char *environment,
1194 uint32_t *count,
1195 struct spoolss_AddDriverInfo8 **_r)
1197 NTSTATUS status;
1198 const char *short_environment;
1199 size_t d, num_devices = 0;
1200 const char **devices = NULL;
1201 const char **device_values = NULL;
1202 struct inf_context *inf_ctx;
1204 if (!filename || !environment) {
1205 return NT_STATUS_INVALID_PARAMETER;
1208 short_environment = spoolss_get_short_filesys_environment(environment);
1209 if (short_environment == NULL) {
1210 return NT_STATUS_INVALID_PARAMETER;
1213 status = init_inf_context(mem_ctx,
1214 filename,
1215 core_driver_inf,
1216 &inf_ctx);
1217 if (!NT_STATUS_IS_OK(status)) {
1218 return status;
1221 status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
1222 &num_devices,
1223 &devices,
1224 &device_values);
1225 if (!NT_STATUS_IS_OK(status)) {
1226 return status;
1229 for (d = 0; d < num_devices; d++) {
1231 struct spoolss_AddDriverInfo8 r;
1232 const char *source_disk_name;
1234 ZERO_STRUCT(r);
1236 status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
1237 environment, devices[d], &r,
1238 &source_disk_name);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 return status;
1243 ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1246 return NT_STATUS_OK;