vfs: restore stat fields in vfs_stat_fsp()
[Samba.git] / lib / printer_driver / printer_driver.c
blob2176d4ae94815c4e4570dd863c2d22d547236d29
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 num_manufacturers = 0;
334 const char **manufacturers = NULL;
335 const char **values = NULL;
336 char *p;
337 int i;
338 bool ok;
340 status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
341 if (!NT_STATUS_IS_OK(status)) {
342 return status;
345 for (i = 0; i < num_manufacturers; i++) {
347 const char *models_section_name;
348 const char *s;
349 char **decorations;
350 int j;
352 DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
354 status = gp_inifile_getstring(ctx, manufacturers[i], &s);
355 if (!NT_STATUS_IS_OK(status)) {
356 return status;
359 decorations = str_list_make_v3(mem_ctx, s, ",");
360 if (decorations == NULL) {
361 return NT_STATUS_NO_MEMORY;
364 models_section_name = decorations[0];
366 for (j = 1; decorations[j] != NULL; j++) {
369 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
372 const char *decorated_models_section_name;
373 size_t num_devices = 0;
374 const char **devices = NULL;
375 const char **device_values = NULL;
376 int d;
377 size_t c = 0;
379 decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
380 models_section_name,
381 decorations[j]);
382 if (decorated_models_section_name == NULL) {
383 return NT_STATUS_NO_MEMORY;
386 DEBUG(11,("processing decorated models_section_name: %s\n",
387 decorated_models_section_name));
389 status = gp_inifile_enum_section(ctx, decorated_models_section_name,
390 &num_devices, &devices,
391 &device_values);
392 for (d = 0; d < num_devices; d++) {
394 DEBUG(11,("processing device: %s\n",
395 devices[d]));
397 s = talloc_strdup(mem_ctx, devices[d]);
398 if (s == NULL) {
399 return NT_STATUS_NO_MEMORY;
402 p = strchr(s, ':');
403 if (p == NULL) {
404 return NT_STATUS_DRIVER_INTERNAL_ERROR;
407 *p = '\0';
408 p++;
410 s = get_string_unquote(p);
412 ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
413 if (!ok) {
414 return NT_STATUS_NO_MEMORY;
416 ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
417 if (!ok) {
418 return NT_STATUS_NO_MEMORY;
424 return NT_STATUS_OK;
427 static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
428 TALLOC_CTX *mem_ctx,
429 const char *device_description,
430 const char **value)
432 NTSTATUS status;
433 size_t num_devices = 0;
434 const char **devices = NULL;
435 const char **device_values = NULL;
436 int d;
438 if (device_description == NULL) {
439 return NT_STATUS_INVALID_PARAMETER;
442 status = enum_devices_in_toc(ctx, mem_ctx,
443 &num_devices,
444 &devices,
445 &device_values);
446 if (!NT_STATUS_IS_OK(status)) {
447 return status;
450 for (d = 0; d < num_devices; d++) {
452 if (strequal(device_description, devices[d])) {
454 DEBUG(10,("found device_description: %s\n",
455 device_description));
457 *value = talloc_strdup(mem_ctx, device_values[d]);
458 if (*value == NULL) {
459 return NT_STATUS_NO_MEMORY;
461 DEBUGADD(10,("and returned: %s\n", *value));
463 return NT_STATUS_OK;
467 return NT_STATUS_DRIVER_INTERNAL_ERROR;
471 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
474 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)
479 NTSTATUS status;
480 size_t num_keys = 0;
481 char *p, *key;
482 const char **keys = NULL;
483 const char **values = NULL;
484 int i;
485 char *str;
486 const char *s;
488 key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
489 if (key == NULL) {
490 return NT_STATUS_NO_MEMORY;
493 DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
495 status = gp_inifile_getstring(ctx, key, &s);
496 if (!NT_STATUS_IS_OK(status)) {
497 return NT_STATUS_OK;
500 DEBUG(10,("these are the files to copy: %s\n", s));
502 while (next_token_talloc(mem_ctx, &s, &str, ",")) {
504 DEBUG(10,("trying section: %s\n", str));
506 if (str[0] == '@') {
507 DEBUG(10,("adding dependent driver file: %s\n", str));
508 status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
509 if (!NT_STATUS_IS_OK(status)) {
510 return status;
512 continue;
515 status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
516 if (NT_STATUS_IS_OK(status)) {
517 for (i = 0; i < num_keys; i++) {
518 p = strchr(keys[i], ':');
519 if (p == NULL) {
520 return NT_STATUS_INVALID_PARAMETER;
522 *p = '\0';
523 p++;
525 DEBUG(10,("adding dependent driver file: %s\n", p));
527 status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
528 if (!NT_STATUS_IS_OK(status)) {
529 return status;
532 TALLOC_FREE(keys);
533 TALLOC_FREE(values);
537 return NT_STATUS_OK;
540 #define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
541 do { \
542 NTSTATUS _status; \
543 const char *__key, *_s; \
544 __key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
545 NT_STATUS_HAVE_NO_MEMORY(__key); \
546 _status = gp_inifile_getstring(_ctx, __key, &_s); \
547 if (NT_STATUS_IS_OK(_status)) { \
548 (_r)->_element = talloc_strdup(mem_ctx, _s); \
549 NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
551 } while(0);
553 static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
554 TALLOC_CTX *mem_ctx,
555 const char *section,
556 struct spoolss_AddDriverInfo8 *r)
558 NTSTATUS status;
559 const char *key, *s;
561 key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
562 if (key == NULL) {
563 return NT_STATUS_NO_MEMORY;
566 status = gp_inifile_getstring_ext(ctx, key, &s);
567 if (NT_STATUS_IS_OK(status)) {
569 status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
570 if (!NT_STATUS_IS_OK(status)) {
571 return status;
575 return NT_STATUS_OK;
578 static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
579 TALLOC_CTX *mem_ctx,
580 const char *section,
581 struct spoolss_AddDriverInfo8 *r)
583 NTSTATUS status;
584 char *key, *p;
585 const char *s;
587 key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
588 if (key == NULL) {
589 return NT_STATUS_NO_MEMORY;
592 status = gp_inifile_getstring_ext(ctx, key, &s);
593 if (NT_STATUS_IS_OK(status)) {
594 s = get_string_unquote(s);
596 p = strchr(s, ',');
597 if (p == NULL) {
598 return NT_STATUS_INVALID_PARAMETER;
600 *p = '\0';
601 r->print_processor = talloc_strdup(mem_ctx, s);
602 if (r->print_processor == NULL) {
603 return NT_STATUS_NO_MEMORY;
607 return NT_STATUS_OK;
610 static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
611 TALLOC_CTX *mem_ctx,
612 const char *section,
613 struct spoolss_AddDriverInfo8 *r)
615 NTSTATUS status;
616 char *key;
617 const char *s;
619 key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
620 if (key == NULL) {
621 return NT_STATUS_NO_MEMORY;
624 status = gp_inifile_getstring(ctx, key, &s);
625 if (NT_STATUS_IS_OK(status)) {
626 process_driver_section_val(ctx, mem_ctx, s, r,
627 "DriverFile", driver_path);
628 process_driver_section_val(ctx, mem_ctx, s, r,
629 "HelpFile", help_file);
630 process_driver_section_val(ctx, mem_ctx, s, r,
631 "DataFile", data_file);
632 process_driver_section_val(ctx, mem_ctx, s, r,
633 "ConfigFile", config_file);
636 return NT_STATUS_OK;
640 static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
641 TALLOC_CTX *mem_ctx,
642 const char *driver_section,
643 struct spoolss_AddDriverInfo8 *r)
645 NTSTATUS status;
646 size_t num_keys = 0;
647 const char **keys = NULL;
648 const char **values = NULL;
649 int i;
651 DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
653 status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
654 if (!NT_STATUS_IS_OK(status)) {
655 return status;
658 for (i = 0; i < num_keys; i++) {
660 status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
661 if (!NT_STATUS_IS_OK(status)) {
662 return status;
665 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
666 "DriverFile", driver_path);
667 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
668 "HelpFile", help_file);
669 process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
670 "ConfigFile", config_file);
672 status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
673 if (!NT_STATUS_IS_OK(status)) {
674 return status;
678 talloc_free(keys);
679 talloc_free(values);
681 return NT_STATUS_OK;
685 * 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"
687 static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
688 TALLOC_CTX *mem_ctx,
689 const char *value,
690 struct spoolss_AddDriverInfo8 *r)
692 NTSTATUS status;
693 char *p;
694 char **list;
695 int i;
697 list = str_list_make_v3(mem_ctx, value, ",");
698 if (list == NULL) {
699 return NT_STATUS_NO_MEMORY;
702 for (i = 0; list[i] != NULL; i++) {
703 char **array;
704 int a;
706 /* FIXME: do we have to validate the core driver guid ? */
708 p = strchr(list[i], ',');
709 if (p != NULL) {
710 *p = '\0';
711 p++;
714 DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
716 array = str_list_make_v3(mem_ctx, p, ",");
717 if (array == NULL) {
718 return NT_STATUS_NO_MEMORY;
721 for (a = 0; array[a] != NULL; a++) {
723 if (core_ctx == NULL) {
724 DEBUG(0,("Need to process CoreDriverSections but "
725 "have no Core Driver Context!\n"));
726 return NT_STATUS_DRIVER_INTERNAL_ERROR;
729 status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
730 if (!NT_STATUS_IS_OK(status)) {
731 continue;
736 return NT_STATUS_OK;
740 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
742 static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
743 struct gp_inifile_context *core_ctx,
744 TALLOC_CTX *mem_ctx,
745 const char *driver_name,
746 struct spoolss_AddDriverInfo8 *r)
748 NTSTATUS status;
749 char *key;
750 const char *s;
751 const char *value;
752 char *install_section_name;
753 bool ok;
754 char *hw_id;
756 status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
757 if (!NT_STATUS_IS_OK(status)) {
758 return status;
761 r->driver_name = talloc_strdup(mem_ctx, driver_name);
762 if (r->driver_name == NULL) {
763 return NT_STATUS_NO_MEMORY;
766 ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
767 if (!ok) {
768 return NT_STATUS_INVALID_PARAMETER;
771 DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
772 driver_name, value, install_section_name));
774 /* Hardware Id is optional */
775 ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
776 if (ok) {
777 r->hardware_id = hw_id;
780 status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
781 if (!NT_STATUS_IS_OK(status)) {
782 return status;
785 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
786 "DriverFile", driver_path);
787 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
788 "HelpFile", help_file);
789 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
790 "DataFile", data_file);
791 process_driver_section_val(ctx, mem_ctx, install_section_name, r,
792 "ConfigFile", config_file);
794 status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
795 if (!NT_STATUS_IS_OK(status)) {
796 return status;
799 status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
800 if (!NT_STATUS_IS_OK(status)) {
801 return status;
804 key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
805 if (key == NULL) {
806 return NT_STATUS_NO_MEMORY;
809 status = gp_inifile_getstring(ctx, key, &s);
810 if (NT_STATUS_IS_OK(status)) {
812 DEBUG(10,("found CoreDriverSections: %s\n", s));
814 status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
815 if (!NT_STATUS_IS_OK(status)) {
816 return status;
820 return NT_STATUS_OK;
823 struct inf_context {
824 struct gp_inifile_context *ctx;
825 struct gp_inifile_context *core_ctx;
828 static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
829 const char *inf_filename,
830 const char *core_filename,
831 struct inf_context **_inf_ctx)
833 NTSTATUS status;
834 struct gp_inifile_context *ctx;
835 struct gp_inifile_context *core_ctx = NULL;
836 struct inf_context *inf_ctx;
838 inf_ctx = talloc_zero(mem_ctx, struct inf_context);
839 if (inf_ctx == NULL) {
840 return NT_STATUS_NO_MEMORY;
843 status = gp_inifile_init_context_direct(mem_ctx,
844 inf_filename,
845 &ctx);
846 if (!NT_STATUS_IS_OK(status)) {
847 DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
848 return status;
851 if (ctx->generated_filename != NULL) {
852 unlink(ctx->generated_filename);
855 if (core_filename != NULL) {
856 status = gp_inifile_init_context_direct(mem_ctx,
857 core_filename,
858 &core_ctx);
859 if (!NT_STATUS_IS_OK(status)) {
860 DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
861 return status;
864 if (core_ctx->generated_filename != NULL) {
865 unlink(core_ctx->generated_filename);
869 inf_ctx->ctx = ctx;
870 inf_ctx->core_ctx = core_ctx;
872 *_inf_ctx = inf_ctx;
874 return NT_STATUS_OK;
877 static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
878 struct spoolss_AddDriverInfo8 *r)
880 NTSTATUS status;
881 const char *s;
882 char *p;
883 bool ok;
884 const char *str;
886 status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
887 if (!NT_STATUS_IS_OK(status)) {
888 return status;
891 str = talloc_strdup(ctx, s);
892 if (str == NULL) {
893 return NT_STATUS_NO_MEMORY;
896 p = strchr(str, ',');
897 if (p) {
898 *p = '\0';
899 p++;
902 ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
903 if (!ok) {
904 return NT_STATUS_INVALID_PARAMETER;
907 ok = spoolss_driver_version_to_qword(p, &r->driver_version);
908 if (!ok) {
909 return NT_STATUS_INVALID_PARAMETER;
912 return NT_STATUS_OK;
916 * Parse a SourceDisksNames section,
917 * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
919 static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
920 TALLOC_CTX *mem_ctx,
921 const char *short_environment,
922 const char **source_disk_name)
924 NTSTATUS status;
925 bool ok;
926 const char *key;
927 size_t num_keys = 0;
928 const char **keys = NULL;
929 const char **values = NULL;
930 int i;
932 key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
933 if (key == NULL) {
934 return NT_STATUS_NO_MEMORY;
937 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
938 if (!NT_STATUS_IS_OK(status)) {
939 return status;
942 if (keys == NULL && values == NULL) {
943 key = "SourceDisksNames";
945 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
946 if (!NT_STATUS_IS_OK(status)) {
947 return status;
951 for (i = 0; i < num_keys; i++) {
954 * 1 = %Disk1%,,,"Amd64"
955 * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
957 char *disk_description, *tag_or_cab_file, *unused, *path;
959 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
960 if (!ok) {
961 continue;
964 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
965 if (!ok) {
966 continue;
969 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
970 if (!ok) {
971 continue;
974 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
975 if (!ok) {
976 continue;
979 *source_disk_name = path;
981 return NT_STATUS_OK;
984 return NT_STATUS_NOT_FOUND;
987 static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
988 struct inf_context *inf_ctx,
989 const char *filename,
990 const char *environment,
991 const char *driver_name,
992 struct spoolss_AddDriverInfo8 *r,
993 const char **source_disk_name)
995 NTSTATUS status;
996 struct gp_inifile_context *ctx = inf_ctx->ctx;
997 struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
998 char *key;
999 bool ok;
1000 const char *short_environment;
1001 const char *s;
1003 short_environment = spoolss_get_short_filesys_environment(environment);
1004 if (short_environment == NULL) {
1005 return NT_STATUS_INVALID_PARAMETER;
1008 status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 return status;
1013 status = process_source_disk_name(ctx, mem_ctx,
1014 short_environment,
1015 source_disk_name);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 return status;
1020 r->inf_path = talloc_strdup(mem_ctx, filename);
1021 if (r->inf_path == NULL) {
1022 return NT_STATUS_NO_MEMORY;
1025 r->architecture = talloc_strdup(mem_ctx, environment);
1026 if (r->architecture == NULL) {
1027 return NT_STATUS_NO_MEMORY;
1030 if (r->print_processor == NULL) {
1031 r->print_processor = talloc_strdup(mem_ctx, "winprint");
1032 if (r->print_processor == NULL) {
1033 return NT_STATUS_NO_MEMORY;
1037 status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
1038 if (NT_STATUS_IS_OK(status)) {
1039 if (strequal(s, "Printer")) {
1040 r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
1044 status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 return status;
1048 if (!strequal(s, "\"$Windows NT$\"")) {
1049 return NT_STATUS_INVALID_SIGNATURE;
1052 r->version = SPOOLSS_DRIVER_VERSION_200X;
1053 status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
1054 if (NT_STATUS_IS_OK(status)) {
1055 int cmp = strncasecmp_m(s, "4.0", 3);
1056 if (cmp == 0) {
1057 r->version = SPOOLSS_DRIVER_VERSION_2012;
1059 if (strequal(s, "3.0")) {
1060 r->version = SPOOLSS_DRIVER_VERSION_200X;
1064 status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
1065 if (NT_STATUS_IS_OK(status)) {
1066 if (s != NULL) {
1067 r->provider = talloc_strdup(mem_ctx, s);
1068 if (r->provider == NULL) {
1069 return NT_STATUS_NO_MEMORY;
1074 status = process_driver_driverver(ctx, r);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 return status;
1079 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1081 status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
1082 if (NT_STATUS_IS_OK(status)) {
1083 int cmp = strncasecmp_m(s, "2", 1);
1084 if (cmp == 0) {
1085 r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
1087 cmp = strncasecmp_m(s, "0", 1);
1088 if (cmp == 0) {
1089 r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1093 status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1094 if (!NT_STATUS_IS_OK(status)) {
1095 return status;
1098 status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
1099 if (!NT_STATUS_IS_OK(status)) {
1100 /* not critical */
1103 status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
1104 if (NT_STATUS_IS_OK(status)) {
1105 if (ok) {
1106 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1110 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1111 "PrinterPackageInstallation", short_environment, "PackageAware");
1112 if (key == NULL) {
1113 return NT_STATUS_NO_MEMORY;
1116 status = gp_inifile_getbool(ctx, key, &ok);
1117 if (NT_STATUS_IS_OK(status)) {
1118 if (ok) {
1119 r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
1123 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1124 "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1125 if (key == NULL) {
1126 return NT_STATUS_NO_MEMORY;
1129 status = gp_inifile_getstring(ctx, key, &s);
1130 if (NT_STATUS_IS_OK(status)) {
1131 char **list;
1132 r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
1133 if (r->core_driver_dependencies == NULL) {
1134 return NT_STATUS_NO_MEMORY;
1137 list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1138 if (list == NULL) {
1139 return NT_STATUS_NO_MEMORY;
1141 r->core_driver_dependencies->string = const_str_list(list);
1144 key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1145 "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1146 if (key == NULL) {
1147 return NT_STATUS_NO_MEMORY;
1150 status = gp_inifile_getstring(ctx, key, &s);
1151 if (NT_STATUS_IS_OK(status)) {
1152 if (strequal(s, "UseDriverVer")) {
1153 r->min_inbox_driver_ver_date = r->driver_date;
1154 r->min_inbox_driver_ver_version = r->driver_version;
1158 return NT_STATUS_OK;
1161 /****************************************************************
1162 parse the a printer inf file
1163 ****************************************************************/
1165 NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
1166 const char *core_driver_inf,
1167 const char *filename,
1168 const char *environment,
1169 const char *driver_name,
1170 struct spoolss_AddDriverInfo8 *r,
1171 const char **source_disk_name)
1173 NTSTATUS status;
1174 struct inf_context *inf_ctx;
1176 if (!filename || !environment) {
1177 return NT_STATUS_INVALID_PARAMETER;
1180 status = init_inf_context(mem_ctx,
1181 filename,
1182 core_driver_inf,
1183 &inf_ctx);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 return status;
1188 status = setup_driver_by_name(mem_ctx, inf_ctx,
1189 filename,
1190 environment,
1191 driver_name,
1193 source_disk_name);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 return status;
1198 return NT_STATUS_OK;
1201 NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
1202 const char *core_driver_inf,
1203 const char *filename,
1204 const char *environment,
1205 uint32_t *count,
1206 struct spoolss_AddDriverInfo8 **_r)
1208 NTSTATUS status;
1209 const char *short_environment;
1210 size_t num_devices = 0;
1211 const char **devices = NULL;
1212 const char **device_values = NULL;
1213 struct inf_context *inf_ctx;
1214 int d;
1216 if (!filename || !environment) {
1217 return NT_STATUS_INVALID_PARAMETER;
1220 short_environment = spoolss_get_short_filesys_environment(environment);
1221 if (short_environment == NULL) {
1222 return NT_STATUS_INVALID_PARAMETER;
1225 status = init_inf_context(mem_ctx,
1226 filename,
1227 core_driver_inf,
1228 &inf_ctx);
1229 if (!NT_STATUS_IS_OK(status)) {
1230 return status;
1233 status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
1234 &num_devices,
1235 &devices,
1236 &device_values);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 return status;
1241 for (d = 0; d < num_devices; d++) {
1243 struct spoolss_AddDriverInfo8 r;
1244 const char *source_disk_name;
1246 ZERO_STRUCT(r);
1248 status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
1249 environment, devices[d], &r,
1250 &source_disk_name);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 return status;
1255 ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1258 return NT_STATUS_OK;