CVE-2019-3824 ldb: Extra comments to clarify no pointer wrap in wildcard processing
[vlendec/samba-autobuild/.git] / lib / printer_driver / printer_driver.c
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 static const char *get_string_unquote(const char *s)
45 {
46         bool ok;
47         size_t len;
48
49         if (s == NULL) {
50                 return NULL;
51         }
52
53         len = strlen(s);
54         if (len < 2) {
55                 return s;
56         }
57
58         if (s[0] == '"' && s[len-1] == '"') {
59                 ok = trim_string(discard_const(s), "\"", "\"");
60                 if (!ok) {
61                         return NULL;
62                 }
63         }
64
65         return s;
66 }
67
68 /*
69  * '%STRING%' indicates STRING is localized in the [Strings] section
70  */
71
72 static const char *get_string_token(struct gp_inifile_context *ctx,
73                                     const char *s)
74 {
75         NTSTATUS status;
76         bool ok;
77         char *key;
78         const char *s2;
79
80         if (s != NULL &&  s[0] != '%' && s[strlen(s)-1] != '%') {
81                 return s;
82         }
83
84         ok = trim_string(discard_const(s), "%", "%");
85         if (!ok) {
86                 return NULL;
87         }
88
89         key = talloc_asprintf(ctx, "Strings:%s", s);
90         if (key == NULL) {
91                 return NULL;
92         }
93
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;
99         }
100
101         return s2;
102 }
103
104 static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
105                                          const char *key,
106                                          const char **ret)
107 {
108         NTSTATUS status;
109         const char *s;
110
111         status = gp_inifile_getstring(ctx, key, &s);
112         if (!NT_STATUS_IS_OK(status)) {
113                 return status;
114         }
115
116         s = get_string_unquote(s);
117         if (s == NULL) {
118                 return NT_STATUS_INTERNAL_ERROR;
119         }
120
121         if (s[0] == '%' && s[strlen(s)-1] == '%') {
122                 s = get_string_token(ctx, s);
123         }
124
125         s = get_string_unquote(s);
126         if (s == NULL) {
127                 return NT_STATUS_INTERNAL_ERROR;
128         }
129
130         *ret = s;
131
132         return NT_STATUS_OK;
133 }
134
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)
139 {
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;
146
147         status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
148         if (!NT_STATUS_IS_OK(status)) {
149                 return status;
150         }
151
152         if (num_keys < 1) {
153                 return NT_STATUS_INVALID_PARAMETER;
154         }
155
156         s = talloc_strdup(mem_ctx, keys[0]);
157         if (s == NULL) {
158                 return NT_STATUS_NO_MEMORY;
159         }
160
161         p = strchr(s, ':');
162         if (p == NULL) {
163                 return NT_STATUS_NO_MEMORY;
164         }
165         *p = '\0';
166         p++;
167
168         s = get_string_unquote(p);
169         if (s == NULL) {
170                 return NT_STATUS_INTERNAL_ERROR;
171         }
172
173         s = get_string_token(ctx, s);
174
175         s = get_string_unquote(s);
176         if (s == NULL) {
177                 return NT_STATUS_INTERNAL_ERROR;
178         }
179
180         if (s != NULL) {
181                 *manufacturer_name = talloc_strdup(mem_ctx, s);
182                 if (*manufacturer_name == NULL) {
183                         return NT_STATUS_NO_MEMORY;
184                 }
185         }
186
187         talloc_free(keys);
188         talloc_free(values);
189
190         return NT_STATUS_OK;
191 }
192
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)
198 {
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;
205
206         status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
207
208         if (!NT_STATUS_IS_OK(status)) {
209                 return status;
210         }
211
212         if (num_keys < 1) {
213                 return NT_STATUS_INVALID_PARAMETER;
214         }
215
216         p = strchr(keys[0], ':');
217         if (p == NULL) {
218                 return NT_STATUS_NO_MEMORY;
219         }
220         *p = '\0';
221         p++;
222
223         s = get_string_unquote(p);
224         if (s == NULL) {
225                 return NT_STATUS_INTERNAL_ERROR;
226         }
227
228         s = get_string_token(ctx, s);
229
230         s = get_string_unquote(s);
231         if (s == NULL) {
232                 return NT_STATUS_INTERNAL_ERROR;
233         }
234
235         if (strequal(s, manufacturer_name)) {
236                 s = get_string_unquote(values[0]);
237                 if (s == NULL) {
238                         return NT_STATUS_INTERNAL_ERROR;
239                 }
240         }
241
242         if (s != NULL) {
243                 *manufacturer_url = talloc_strdup(mem_ctx, s);
244                 if (*manufacturer_url == NULL) {
245                         return NT_STATUS_NO_MEMORY;
246                 }
247         }
248
249         talloc_free(keys);
250         talloc_free(values);
251
252         return NT_STATUS_OK;
253 }
254
255 static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
256                                             const char *s,
257                                             struct spoolss_StringArray **r)
258 {
259         size_t count = 2;
260         struct spoolss_StringArray *a = *r;
261         bool ok;
262         int i;
263
264         if (a == NULL) {
265                 a = talloc_zero(mem_ctx, struct spoolss_StringArray);
266                 if (a == NULL) {
267                         return NT_STATUS_NO_MEMORY;
268                 }
269         }
270
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;
275                 }
276         }
277
278         for (i = 0; a->string[i] != NULL; i++) { ;; }
279         count = i;
280
281         ok = add_string_to_array(mem_ctx, s, &a->string, &count);
282         if (!ok) {
283                 return NT_STATUS_NO_MEMORY;
284         }
285
286         a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
287         if (a->string == NULL) {
288                 return NT_STATUS_NO_MEMORY;
289         }
290         a->string[count] = NULL;
291
292         *r = a;
293
294         return NT_STATUS_OK;
295 }
296
297 static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
298                                           const char *file,
299                                           struct spoolss_StringArray **r)
300 {
301         char *p;
302
303         if (file == NULL) {
304                 return NT_STATUS_INVALID_PARAMETER;
305         }
306
307         if (file[0] == '@') {
308                 file++;
309         }
310
311         p = strchr(file, ',');
312         if (p != NULL) {
313                 *p = '\0';
314         }
315
316         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 static NTSTATUS enum_devices_in_toc(struct gp_inifile_context *ctx,
327                                     TALLOC_CTX *mem_ctx,
328                                     size_t *pnum_devices,
329                                     const char ***pdevices,
330                                     const char ***pdevice_values)
331 {
332         NTSTATUS status;
333         size_t num_manufacturers = 0;
334         const char **manufacturers = NULL;
335         const char **values = NULL;
336         char *p;
337         int i;
338         bool ok;
339
340         status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
341         if (!NT_STATUS_IS_OK(status)) {
342                 return status;
343         }
344
345         for (i = 0; i < num_manufacturers; i++) {
346
347                 const char *models_section_name;
348                 const char *s;
349                 char **decorations;
350                 int j;
351
352                 DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
353
354                 status = gp_inifile_getstring(ctx, manufacturers[i], &s);
355                 if (!NT_STATUS_IS_OK(status)) {
356                         return status;
357                 }
358
359                 decorations = str_list_make_v3(mem_ctx, s, ",");
360                 if (decorations == NULL) {
361                         return NT_STATUS_NO_MEMORY;
362                 }
363
364                 models_section_name = decorations[0];
365
366                 for (j = 1; decorations[j] != NULL; j++) {
367
368                         /*
369                          * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
370                          */
371
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;
378
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;
384                         }
385
386                         DEBUG(11,("processing decorated models_section_name: %s\n",
387                                 decorated_models_section_name));
388
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++) {
393
394                                 DEBUG(11,("processing device: %s\n",
395                                         devices[d]));
396
397                                 s = talloc_strdup(mem_ctx, devices[d]);
398                                 if (s == NULL) {
399                                         return NT_STATUS_NO_MEMORY;
400                                 }
401
402                                 p = strchr(s, ':');
403                                 if (p == NULL) {
404                                         return NT_STATUS_DRIVER_INTERNAL_ERROR;
405                                 }
406
407                                 *p = '\0';
408                                 p++;
409
410                                 s = get_string_unquote(p);
411
412                                 ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
413                                 if (!ok) {
414                                         return NT_STATUS_NO_MEMORY;
415                                 }
416                                 ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
417                                 if (!ok) {
418                                         return NT_STATUS_NO_MEMORY;
419                                 }
420                         }
421                 }
422         }
423
424         return NT_STATUS_OK;
425 }
426
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)
431 {
432         NTSTATUS status;
433         size_t num_devices = 0;
434         const char **devices = NULL;
435         const char **device_values = NULL;
436         int d;
437
438         if (device_description == NULL) {
439                 return NT_STATUS_INVALID_PARAMETER;
440         }
441
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;
448         }
449
450         for (d = 0; d < num_devices; d++) {
451
452                 if (strequal(device_description, devices[d])) {
453
454                         DEBUG(10,("found device_description: %s\n",
455                                 device_description));
456
457                         *value = talloc_strdup(mem_ctx, device_values[d]);
458                         if (*value == NULL) {
459                                 return NT_STATUS_NO_MEMORY;
460                         }
461                         DEBUGADD(10,("and returned: %s\n", *value));
462
463                         return NT_STATUS_OK;
464                 }
465         }
466
467         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 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         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;
487
488         key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
489         if (key == NULL) {
490                 return NT_STATUS_NO_MEMORY;
491         }
492
493         DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
494
495         status = gp_inifile_getstring(ctx, key, &s);
496         if (!NT_STATUS_IS_OK(status)) {
497                 return NT_STATUS_OK;
498         }
499
500         DEBUG(10,("these are the files to copy: %s\n", s));
501
502         while (next_token_talloc(mem_ctx, &s, &str, ",")) {
503
504                 DEBUG(10,("trying section: %s\n", str));
505
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;
511                         }
512                         continue;
513                 }
514
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;
521                                 }
522                                 *p = '\0';
523                                 p++;
524
525                                 DEBUG(10,("adding dependent driver file: %s\n", p));
526
527                                 status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
528                                 if (!NT_STATUS_IS_OK(status)) {
529                                         return status;
530                                 }
531                         }
532                         TALLOC_FREE(keys);
533                         TALLOC_FREE(values);
534                 }
535         }
536
537         return NT_STATUS_OK;
538 }
539
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); \
550         } \
551 } while(0);
552
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)
557 {
558         NTSTATUS status;
559         const char *key, *s;
560
561         key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
562         if (key == NULL) {
563                 return NT_STATUS_NO_MEMORY;
564         }
565
566         status = gp_inifile_getstring_ext(ctx, key, &s);
567         if (NT_STATUS_IS_OK(status)) {
568
569                 status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
570                 if (!NT_STATUS_IS_OK(status)) {
571                         return status;
572                 }
573         }
574
575         return NT_STATUS_OK;
576 }
577
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)
582 {
583         NTSTATUS status;
584         char *key, *p;
585         const char *s;
586
587         key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
588         if (key == NULL) {
589                 return NT_STATUS_NO_MEMORY;
590         }
591
592         status = gp_inifile_getstring_ext(ctx, key, &s);
593         if (NT_STATUS_IS_OK(status)) {
594                 s = get_string_unquote(s);
595
596                 p = strchr(s, ',');
597                 if (p == NULL) {
598                         return NT_STATUS_INVALID_PARAMETER;
599                 }
600                 *p = '\0';
601                 r->print_processor = talloc_strdup(mem_ctx, s);
602                 if (r->print_processor == NULL) {
603                         return NT_STATUS_NO_MEMORY;
604                 }
605         }
606
607         return NT_STATUS_OK;
608 }
609
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)
614 {
615         NTSTATUS status;
616         char *key;
617         const char *s;
618
619         key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
620         if (key == NULL) {
621                 return NT_STATUS_NO_MEMORY;
622         }
623
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);
634         }
635
636         return NT_STATUS_OK;
637 }
638
639
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)
644 {
645         NTSTATUS status;
646         size_t num_keys = 0;
647         const char **keys = NULL;
648         const char **values = NULL;
649         int i;
650
651         DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
652
653         status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
654         if (!NT_STATUS_IS_OK(status)) {
655                 return status;
656         }
657
658         for (i = 0; i < num_keys; i++) {
659
660                 status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
661                 if (!NT_STATUS_IS_OK(status)) {
662                         return status;
663                 }
664
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);
671
672                 status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
673                 if (!NT_STATUS_IS_OK(status)) {
674                         return status;
675                 }
676         }
677
678         talloc_free(keys);
679         talloc_free(values);
680
681         return NT_STATUS_OK;
682 }
683
684 /*
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"
686  */
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)
691 {
692         NTSTATUS status;
693         char *p;
694         char **list;
695         int i;
696
697         list = str_list_make_v3(mem_ctx, value, ",");
698         if (list == NULL) {
699                 return NT_STATUS_NO_MEMORY;
700         }
701
702         for (i = 0; list[i] != NULL; i++) {
703                 char **array;
704                 int a;
705
706                 /* FIXME: do we have to validate the core driver guid ? */
707
708                 p = strchr(list[i], ',');
709                 if (p != NULL) {
710                         *p = '\0';
711                         p++;
712                 }
713
714                 DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
715
716                 array = str_list_make_v3(mem_ctx, p, ",");
717                 if (array == NULL) {
718                         return NT_STATUS_NO_MEMORY;
719                 }
720
721                 for (a = 0; array[a] != NULL; a++) {
722
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;
727                         }
728
729                         status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
730                         if (!NT_STATUS_IS_OK(status)) {
731                                 continue;
732                         }
733                 }
734         }
735
736         return NT_STATUS_OK;
737 }
738
739 /*
740  * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
741  */
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)
747 {
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;
755
756         status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
757         if (!NT_STATUS_IS_OK(status)) {
758                 return status;
759         }
760
761         r->driver_name = talloc_strdup(mem_ctx, driver_name);
762         if (r->driver_name == NULL) {
763                 return NT_STATUS_NO_MEMORY;
764         }
765
766         ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
767         if (!ok) {
768                 return NT_STATUS_INVALID_PARAMETER;
769         }
770
771         DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
772                 driver_name, value, install_section_name));
773
774         /* Hardware Id is optional */
775         ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
776         if (ok) {
777                 r->hardware_id = hw_id;
778         }
779
780         status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
781         if (!NT_STATUS_IS_OK(status)) {
782                 return status;
783         }
784
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);
793
794         status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
795         if (!NT_STATUS_IS_OK(status)) {
796                 return status;
797         }
798
799         status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
800         if (!NT_STATUS_IS_OK(status)) {
801                 return status;
802         }
803
804         key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
805         if (key == NULL) {
806                 return NT_STATUS_NO_MEMORY;
807         }
808
809         status = gp_inifile_getstring(ctx, key, &s);
810         if (NT_STATUS_IS_OK(status)) {
811
812                 DEBUG(10,("found CoreDriverSections: %s\n", s));
813
814                 status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
815                 if (!NT_STATUS_IS_OK(status)) {
816                         return status;
817                 }
818         }
819
820         return NT_STATUS_OK;
821 }
822
823 struct inf_context {
824         struct gp_inifile_context *ctx;
825         struct gp_inifile_context *core_ctx;
826 };
827
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)
832 {
833         NTSTATUS status;
834         struct gp_inifile_context *ctx;
835         struct gp_inifile_context *core_ctx = NULL;
836         struct inf_context *inf_ctx;
837
838         inf_ctx = talloc_zero(mem_ctx, struct inf_context);
839         if (inf_ctx == NULL) {
840                 return NT_STATUS_NO_MEMORY;
841         }
842
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;
849         }
850
851         if (ctx->generated_filename != NULL) {
852                 unlink(ctx->generated_filename);
853         }
854
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;
862                 }
863
864                 if (core_ctx->generated_filename != NULL) {
865                         unlink(core_ctx->generated_filename);
866                 }
867         }
868
869         inf_ctx->ctx = ctx;
870         inf_ctx->core_ctx = core_ctx;
871
872         *_inf_ctx = inf_ctx;
873
874         return NT_STATUS_OK;
875 }
876
877 static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
878                                          struct spoolss_AddDriverInfo8 *r)
879 {
880         NTSTATUS status;
881         const char *s;
882         char *p;
883         bool ok;
884         const char *str;
885
886         status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
887         if (!NT_STATUS_IS_OK(status)) {
888                 return status;
889         }
890
891         str = talloc_strdup(ctx, s);
892         if (str == NULL) {
893                 return NT_STATUS_NO_MEMORY;
894         }
895
896         p = strchr(str, ',');
897         if (p) {
898                 *p = '\0';
899                 p++;
900         }
901
902         ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
903         if (!ok) {
904                 return NT_STATUS_INVALID_PARAMETER;
905         }
906
907         ok = spoolss_driver_version_to_qword(p, &r->driver_version);
908         if (!ok) {
909                 return NT_STATUS_INVALID_PARAMETER;
910         }
911
912         return NT_STATUS_OK;
913 }
914
915 /*
916  * Parse a SourceDisksNames section,
917  * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
918  */
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)
923 {
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;
931
932         key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
933         if (key == NULL) {
934                 return NT_STATUS_NO_MEMORY;
935         }
936
937         status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
938         if (!NT_STATUS_IS_OK(status)) {
939                 return status;
940         }
941
942         if (keys == NULL && values == NULL) {
943                 key = "SourceDisksNames";
944
945                 status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
946                 if (!NT_STATUS_IS_OK(status)) {
947                         return status;
948                 }
949         }
950
951         for (i = 0; i < num_keys; i++) {
952
953                 /*
954                  * 1   = %Disk1%,,,"Amd64"
955                  * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
956                  */
957                 char *disk_description, *tag_or_cab_file, *unused, *path;
958
959                 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
960                 if (!ok) {
961                         continue;
962                 }
963
964                 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
965                 if (!ok) {
966                         continue;
967                 }
968
969                 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
970                 if (!ok) {
971                         continue;
972                 }
973
974                 ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
975                 if (!ok) {
976                         continue;
977                 }
978
979                 *source_disk_name = path;
980
981                 return NT_STATUS_OK;
982         }
983
984         return NT_STATUS_NOT_FOUND;
985 }
986
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)
994 {
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;
1002
1003         short_environment = spoolss_get_short_filesys_environment(environment);
1004         if (short_environment == NULL) {
1005                 return NT_STATUS_INVALID_PARAMETER;
1006         }
1007
1008         status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
1009         if (!NT_STATUS_IS_OK(status)) {
1010                 return status;
1011         }
1012
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;
1018         }
1019
1020         r->inf_path = talloc_strdup(mem_ctx, filename);
1021         if (r->inf_path == NULL) {
1022                 return NT_STATUS_NO_MEMORY;
1023         }
1024
1025         r->architecture = talloc_strdup(mem_ctx, environment);
1026         if (r->architecture == NULL) {
1027                 return NT_STATUS_NO_MEMORY;
1028         }
1029
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;
1034                 }
1035         }
1036
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;
1041                 }
1042         }
1043
1044         status = gp_inifile_getstring(ctx, "Version:Signature", &s);
1045         if (!NT_STATUS_IS_OK(status)) {
1046                 return status;
1047         }
1048         if (!strequal(s, "\"$Windows NT$\"")) {
1049                 return NT_STATUS_INVALID_SIGNATURE;
1050         }
1051
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;
1058                 }
1059                 if (strequal(s, "3.0")) {
1060                         r->version = SPOOLSS_DRIVER_VERSION_200X;
1061                 }
1062         }
1063
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;
1070                         }
1071                 }
1072         }
1073
1074         status = process_driver_driverver(ctx, r);
1075         if (!NT_STATUS_IS_OK(status)) {
1076                 return status;
1077         }
1078
1079         r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1080
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;
1086                 }
1087                 cmp = strncasecmp_m(s, "0", 1);
1088                 if (cmp == 0) {
1089                         r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
1090                 }
1091         }
1092
1093         status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
1094         if (!NT_STATUS_IS_OK(status)) {
1095                 return status;
1096         }
1097
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 */
1101         }
1102
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;
1107                 }
1108         }
1109
1110         key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1111                 "PrinterPackageInstallation", short_environment, "PackageAware");
1112         if (key == NULL) {
1113                 return NT_STATUS_NO_MEMORY;
1114         }
1115
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;
1120                 }
1121         }
1122
1123         key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1124                 "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
1125         if (key == NULL) {
1126                 return NT_STATUS_NO_MEMORY;
1127         }
1128
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;
1135                 }
1136
1137                 list = str_list_make_v3(r->core_driver_dependencies, s, ",");
1138                 if (list == NULL) {
1139                         return NT_STATUS_NO_MEMORY;
1140                 }
1141                 r->core_driver_dependencies->string = const_str_list(list);
1142         }
1143
1144         key = talloc_asprintf(mem_ctx, "%s.%s:%s",
1145                 "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
1146         if (key == NULL) {
1147                 return NT_STATUS_NO_MEMORY;
1148         }
1149
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;
1155                 }
1156         }
1157
1158         return NT_STATUS_OK;
1159 }
1160
1161 /****************************************************************
1162  parse the a printer inf file
1163 ****************************************************************/
1164
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)
1172 {
1173         NTSTATUS status;
1174         struct inf_context *inf_ctx;
1175
1176         if (!filename || !environment) {
1177                 return NT_STATUS_INVALID_PARAMETER;
1178         }
1179
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;
1186         }
1187
1188         status = setup_driver_by_name(mem_ctx, inf_ctx,
1189                                       filename,
1190                                       environment,
1191                                       driver_name,
1192                                       r,
1193                                       source_disk_name);
1194         if (!NT_STATUS_IS_OK(status)) {
1195                 return status;
1196         }
1197
1198         return NT_STATUS_OK;
1199 }
1200
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)
1207 {
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;
1215
1216         if (!filename || !environment) {
1217                 return NT_STATUS_INVALID_PARAMETER;
1218         }
1219
1220         short_environment = spoolss_get_short_filesys_environment(environment);
1221         if (short_environment == NULL) {
1222                 return NT_STATUS_INVALID_PARAMETER;
1223         }
1224
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;
1231         }
1232
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;
1239         }
1240
1241         for (d = 0; d < num_devices; d++) {
1242
1243                 struct spoolss_AddDriverInfo8 r;
1244                 const char *source_disk_name;
1245
1246                 ZERO_STRUCT(r);
1247
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;
1253                 }
1254
1255                 ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
1256         }
1257
1258         return NT_STATUS_OK;
1259 }