1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00
samba-mirror/lib/printer_driver/printer_driver.c
Joseph Sutton fe86989fcc lib:printer_driver: Check return value of gp_inifile_enum_section() (CID 1444835)
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-10-13 02:18:30 +00:00

1256 lines
29 KiB
C

/*
Unix SMB/CIFS implementation.
Copyright (C) Guenther Deschner 2016
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "librpc/gen_ndr/ndr_spoolss.h"
#include "rpc_client/init_spoolss.h"
#include "libgpo/gpo_ini.h"
#include "printer_driver.h"
#define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \
do { \
*(array) = talloc_realloc(mem_ctx, (*(array)), type, (*(num))+1); \
SMB_ASSERT((*(array)) != NULL); \
(*(array))[*(num)] = (elem); \
(*(num)) += 1; \
} while (0)
/* GetPrinterDriverDirectory -> drivers and dependent files */
#define PRINTER_INF_DIRID_66000
/* GetPrintProcessorDirectory -> print processors */
#define PRINTER_INF_DIRID_66001
/* GetColorDirectory -> color profiles */
#define PRINTER_INF_DIRID_66003
static const char *get_string_unquote(const char *s)
{
bool ok;
size_t len;
if (s == NULL) {
return NULL;
}
len = strlen(s);
if (len < 2) {
return s;
}
if (s[0] == '"' && s[len-1] == '"') {
ok = trim_string(discard_const(s), "\"", "\"");
if (!ok) {
return NULL;
}
}
return s;
}
/*
* '%STRING%' indicates STRING is localized in the [Strings] section
*/
static const char *get_string_token(struct gp_inifile_context *ctx,
const char *s)
{
NTSTATUS status;
bool ok;
char *key;
const char *s2;
if (s != NULL && s[0] != '%' && s[strlen(s)-1] != '%') {
return s;
}
ok = trim_string(discard_const(s), "%", "%");
if (!ok) {
return NULL;
}
key = talloc_asprintf(ctx, "Strings:%s", s);
if (key == NULL) {
return NULL;
}
status = gp_inifile_getstring(ctx, key, &s2);
talloc_free(key);
if (!NT_STATUS_IS_OK(status)) {
/* what can you do... */
return s;
}
return s2;
}
static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
const char *key,
const char **ret)
{
NTSTATUS status;
const char *s;
status = gp_inifile_getstring(ctx, key, &s);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
s = get_string_unquote(s);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
if (s[0] == '%' && s[strlen(s)-1] == '%') {
s = get_string_token(ctx, s);
}
s = get_string_unquote(s);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
*ret = s;
return NT_STATUS_OK;
}
static NTSTATUS find_manufacturer_name(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *section_name,
const char **manufacturer_name)
{
NTSTATUS status;
size_t num_keys = 0;
const char **keys = NULL;
const char **values = NULL;
const char *s;
char *p;
status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (num_keys < 1) {
return NT_STATUS_INVALID_PARAMETER;
}
s = talloc_strdup(mem_ctx, keys[0]);
if (s == NULL) {
return NT_STATUS_NO_MEMORY;
}
p = strchr(s, ':');
if (p == NULL) {
return NT_STATUS_NO_MEMORY;
}
*p = '\0';
p++;
s = get_string_unquote(p);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
s = get_string_token(ctx, s);
s = get_string_unquote(s);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
if (s != NULL) {
*manufacturer_name = talloc_strdup(mem_ctx, s);
if (*manufacturer_name == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
talloc_free(keys);
talloc_free(values);
return NT_STATUS_OK;
}
static NTSTATUS find_manufacturer_url(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *section_name,
const char *manufacturer_name,
const char **manufacturer_url)
{
NTSTATUS status;
size_t num_keys = 0;
const char **keys = NULL;
const char **values = NULL;
const char *s;
char *p;
status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (num_keys < 1) {
return NT_STATUS_INVALID_PARAMETER;
}
p = strchr(keys[0], ':');
if (p == NULL) {
return NT_STATUS_NO_MEMORY;
}
*p = '\0';
p++;
s = get_string_unquote(p);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
s = get_string_token(ctx, s);
s = get_string_unquote(s);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
if (strequal(s, manufacturer_name)) {
s = get_string_unquote(values[0]);
if (s == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
}
if (s != NULL) {
*manufacturer_url = talloc_strdup(mem_ctx, s);
if (*manufacturer_url == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
talloc_free(keys);
talloc_free(values);
return NT_STATUS_OK;
}
static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
const char *s,
struct spoolss_StringArray **r)
{
size_t count = 2;
struct spoolss_StringArray *a = *r;
bool ok;
int i;
if (a == NULL) {
a = talloc_zero(mem_ctx, struct spoolss_StringArray);
if (a == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
if (a->string == NULL) {
a->string = talloc_zero_array(a, const char *, count);
if (a->string == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
for (i = 0; a->string[i] != NULL; i++) { ;; }
count = i;
ok = add_string_to_array(mem_ctx, s, &a->string, &count);
if (!ok) {
return NT_STATUS_NO_MEMORY;
}
a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
if (a->string == NULL) {
return NT_STATUS_NO_MEMORY;
}
a->string[count] = NULL;
*r = a;
return NT_STATUS_OK;
}
static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
const char *file,
struct spoolss_StringArray **r)
{
char *p;
if (file == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
if (file[0] == '@') {
file++;
}
p = strchr(file, ',');
if (p != NULL) {
*p = '\0';
}
return add_string_to_spoolss_array(mem_ctx, file, r);
}
/*
* https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section
*
* [Manufacturer]
* "Kyocera"=Kyocera,NTx86.5.1,NTx86.6.0,NTamd64.5.1,NTamd64.6.0
*/
static NTSTATUS enum_devices_in_toc(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
size_t *pnum_devices,
const char ***pdevices,
const char ***pdevice_values)
{
NTSTATUS status;
size_t i, num_manufacturers = 0;
const char **manufacturers = NULL;
const char **values = NULL;
char *p;
bool ok;
status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
for (i = 0; i < num_manufacturers; i++) {
const char *models_section_name;
const char *s;
char **decorations;
int j;
DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
status = gp_inifile_getstring(ctx, manufacturers[i], &s);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
decorations = str_list_make_v3(mem_ctx, s, ",");
if (decorations == NULL) {
return NT_STATUS_NO_MEMORY;
}
models_section_name = decorations[0];
for (j = 1; decorations[j] != NULL; j++) {
/*
* https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
*/
const char *decorated_models_section_name;
size_t d, num_devices = 0;
const char **devices = NULL;
const char **device_values = NULL;
size_t c = 0;
decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
models_section_name,
decorations[j]);
if (decorated_models_section_name == NULL) {
return NT_STATUS_NO_MEMORY;
}
DEBUG(11,("processing decorated models_section_name: %s\n",
decorated_models_section_name));
status = gp_inifile_enum_section(ctx, decorated_models_section_name,
&num_devices, &devices,
&device_values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
for (d = 0; d < num_devices; d++) {
DEBUG(11,("processing device: %s\n",
devices[d]));
s = talloc_strdup(mem_ctx, devices[d]);
if (s == NULL) {
return NT_STATUS_NO_MEMORY;
}
p = strchr(s, ':');
if (p == NULL) {
return NT_STATUS_DRIVER_INTERNAL_ERROR;
}
*p = '\0';
p++;
s = get_string_unquote(p);
ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
if (!ok) {
return NT_STATUS_NO_MEMORY;
}
ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
if (!ok) {
return NT_STATUS_NO_MEMORY;
}
}
}
}
return NT_STATUS_OK;
}
static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *device_description,
const char **value)
{
NTSTATUS status;
size_t d, num_devices = 0;
const char **devices = NULL;
const char **device_values = NULL;
if (device_description == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
status = enum_devices_in_toc(ctx, mem_ctx,
&num_devices,
&devices,
&device_values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
for (d = 0; d < num_devices; d++) {
if (strequal(device_description, devices[d])) {
DEBUG(10,("found device_description: %s\n",
device_description));
*value = talloc_strdup(mem_ctx, device_values[d]);
if (*value == NULL) {
return NT_STATUS_NO_MEMORY;
}
DEBUGADD(10,("and returned: %s\n", *value));
return NT_STATUS_OK;
}
}
return NT_STATUS_DRIVER_INTERNAL_ERROR;
}
/*
* https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
*/
static NTSTATUS process_driver_section_copyfiles(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *driver_section,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
size_t i, num_keys = 0;
char *p, *key;
const char **keys = NULL;
const char **values = NULL;
char *str;
const char *s;
key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
status = gp_inifile_getstring(ctx, key, &s);
if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_OK;
}
DEBUG(10,("these are the files to copy: %s\n", s));
while (next_token_talloc(mem_ctx, &s, &str, ",")) {
DEBUG(10,("trying section: %s\n", str));
if (str[0] == '@') {
DEBUG(10,("adding dependent driver file: %s\n", str));
status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
continue;
}
status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
if (NT_STATUS_IS_OK(status)) {
for (i = 0; i < num_keys; i++) {
p = strchr(keys[i], ':');
if (p == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
*p = '\0';
p++;
DEBUG(10,("adding dependent driver file: %s\n", p));
status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
TALLOC_FREE(keys);
TALLOC_FREE(values);
}
}
return NT_STATUS_OK;
}
#define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
do { \
NTSTATUS _status; \
const char *__key, *_s; \
__key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
NT_STATUS_HAVE_NO_MEMORY(__key); \
_status = gp_inifile_getstring(_ctx, __key, &_s); \
if (NT_STATUS_IS_OK(_status)) { \
(_r)->_element = talloc_strdup(mem_ctx, _s); \
NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
} \
} while(0);
static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *section,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
const char *key, *s;
key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring_ext(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
return NT_STATUS_OK;
}
static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *section,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
char *key, *p;
const char *s;
key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring_ext(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
s = get_string_unquote(s);
p = strchr(s, ',');
if (p == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
*p = '\0';
r->print_processor = talloc_strdup(mem_ctx, s);
if (r->print_processor == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
return NT_STATUS_OK;
}
static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *section,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
char *key;
const char *s;
key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
process_driver_section_val(ctx, mem_ctx, s, r,
"DriverFile", driver_path);
process_driver_section_val(ctx, mem_ctx, s, r,
"HelpFile", help_file);
process_driver_section_val(ctx, mem_ctx, s, r,
"DataFile", data_file);
process_driver_section_val(ctx, mem_ctx, s, r,
"ConfigFile", config_file);
}
return NT_STATUS_OK;
}
static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
TALLOC_CTX *mem_ctx,
const char *driver_section,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
size_t i, num_keys = 0;
const char **keys = NULL;
const char **values = NULL;
DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
for (i = 0; i < num_keys; i++) {
status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
"DriverFile", driver_path);
process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
"HelpFile", help_file);
process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
"ConfigFile", config_file);
status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
talloc_free(keys);
talloc_free(values);
return NT_STATUS_OK;
}
/*
* 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"
*/
static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
TALLOC_CTX *mem_ctx,
const char *value,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
char *p;
char **list;
int i;
list = str_list_make_v3(mem_ctx, value, ",");
if (list == NULL) {
return NT_STATUS_NO_MEMORY;
}
for (i = 0; list[i] != NULL; i++) {
char **array;
int a;
/* FIXME: do we have to validate the core driver guid ? */
p = strchr(list[i], ',');
if (p != NULL) {
*p = '\0';
p++;
}
DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
array = str_list_make_v3(mem_ctx, p, ",");
if (array == NULL) {
return NT_STATUS_NO_MEMORY;
}
for (a = 0; array[a] != NULL; a++) {
if (core_ctx == NULL) {
DEBUG(0,("Need to process CoreDriverSections but "
"have no Core Driver Context!\n"));
return NT_STATUS_DRIVER_INTERNAL_ERROR;
}
status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
if (!NT_STATUS_IS_OK(status)) {
continue;
}
}
}
return NT_STATUS_OK;
}
/*
* https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
*/
static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
struct gp_inifile_context *core_ctx,
TALLOC_CTX *mem_ctx,
const char *driver_name,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
char *key;
const char *s;
const char *value;
char *install_section_name;
bool ok;
char *hw_id;
status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r->driver_name = talloc_strdup(mem_ctx, driver_name);
if (r->driver_name == NULL) {
return NT_STATUS_NO_MEMORY;
}
ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
if (!ok) {
return NT_STATUS_INVALID_PARAMETER;
}
DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
driver_name, value, install_section_name));
/* Hardware Id is optional */
ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
if (ok) {
r->hardware_id = hw_id;
}
status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
process_driver_section_val(ctx, mem_ctx, install_section_name, r,
"DriverFile", driver_path);
process_driver_section_val(ctx, mem_ctx, install_section_name, r,
"HelpFile", help_file);
process_driver_section_val(ctx, mem_ctx, install_section_name, r,
"DataFile", data_file);
process_driver_section_val(ctx, mem_ctx, install_section_name, r,
"ConfigFile", config_file);
status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
DEBUG(10,("found CoreDriverSections: %s\n", s));
status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
return NT_STATUS_OK;
}
struct inf_context {
struct gp_inifile_context *ctx;
struct gp_inifile_context *core_ctx;
};
static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
const char *inf_filename,
const char *core_filename,
struct inf_context **_inf_ctx)
{
NTSTATUS status;
struct gp_inifile_context *ctx;
struct gp_inifile_context *core_ctx = NULL;
struct inf_context *inf_ctx;
inf_ctx = talloc_zero(mem_ctx, struct inf_context);
if (inf_ctx == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_init_context_direct(mem_ctx,
inf_filename,
&ctx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
return status;
}
if (ctx->generated_filename != NULL) {
unlink(ctx->generated_filename);
}
if (core_filename != NULL) {
status = gp_inifile_init_context_direct(mem_ctx,
core_filename,
&core_ctx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
return status;
}
if (core_ctx->generated_filename != NULL) {
unlink(core_ctx->generated_filename);
}
}
inf_ctx->ctx = ctx;
inf_ctx->core_ctx = core_ctx;
*_inf_ctx = inf_ctx;
return NT_STATUS_OK;
}
static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
struct spoolss_AddDriverInfo8 *r)
{
NTSTATUS status;
const char *s;
char *p;
bool ok;
const char *str;
status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
str = talloc_strdup(ctx, s);
if (str == NULL) {
return NT_STATUS_NO_MEMORY;
}
p = strchr(str, ',');
if (p) {
*p = '\0';
p++;
}
ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
if (!ok) {
return NT_STATUS_INVALID_PARAMETER;
}
ok = spoolss_driver_version_to_qword(p, &r->driver_version);
if (!ok) {
return NT_STATUS_INVALID_PARAMETER;
}
return NT_STATUS_OK;
}
/*
* Parse a SourceDisksNames section,
* https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
*/
static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
TALLOC_CTX *mem_ctx,
const char *short_environment,
const char **source_disk_name)
{
NTSTATUS status;
bool ok;
const char *key;
size_t i, num_keys = 0;
const char **keys = NULL;
const char **values = NULL;
key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (keys == NULL && values == NULL) {
key = "SourceDisksNames";
status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
for (i = 0; i < num_keys; i++) {
/*
* 1 = %Disk1%,,,"Amd64"
* diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
*/
char *disk_description, *tag_or_cab_file, *unused, *path;
ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
if (!ok) {
continue;
}
ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
if (!ok) {
continue;
}
ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
if (!ok) {
continue;
}
ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
if (!ok) {
continue;
}
*source_disk_name = path;
return NT_STATUS_OK;
}
return NT_STATUS_NOT_FOUND;
}
static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
struct inf_context *inf_ctx,
const char *filename,
const char *environment,
const char *driver_name,
struct spoolss_AddDriverInfo8 *r,
const char **source_disk_name)
{
NTSTATUS status;
struct gp_inifile_context *ctx = inf_ctx->ctx;
struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
char *key;
bool ok;
const char *short_environment;
const char *s;
short_environment = spoolss_get_short_filesys_environment(environment);
if (short_environment == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = process_source_disk_name(ctx, mem_ctx,
short_environment,
source_disk_name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r->inf_path = talloc_strdup(mem_ctx, filename);
if (r->inf_path == NULL) {
return NT_STATUS_NO_MEMORY;
}
r->architecture = talloc_strdup(mem_ctx, environment);
if (r->architecture == NULL) {
return NT_STATUS_NO_MEMORY;
}
if (r->print_processor == NULL) {
r->print_processor = talloc_strdup(mem_ctx, "winprint");
if (r->print_processor == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
if (NT_STATUS_IS_OK(status)) {
if (strequal(s, "Printer")) {
r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
}
}
status = gp_inifile_getstring(ctx, "Version:Signature", &s);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (!strequal(s, "\"$Windows NT$\"")) {
return NT_STATUS_INVALID_SIGNATURE;
}
r->version = SPOOLSS_DRIVER_VERSION_200X;
status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
if (NT_STATUS_IS_OK(status)) {
int cmp = strncasecmp_m(s, "4.0", 3);
if (cmp == 0) {
r->version = SPOOLSS_DRIVER_VERSION_2012;
}
if (strequal(s, "3.0")) {
r->version = SPOOLSS_DRIVER_VERSION_200X;
}
}
status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
if (NT_STATUS_IS_OK(status)) {
if (s != NULL) {
r->provider = talloc_strdup(mem_ctx, s);
if (r->provider == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
}
status = process_driver_driverver(ctx, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
if (NT_STATUS_IS_OK(status)) {
int cmp = strncasecmp_m(s, "2", 1);
if (cmp == 0) {
r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
}
cmp = strncasecmp_m(s, "0", 1);
if (cmp == 0) {
r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
}
}
status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
if (!NT_STATUS_IS_OK(status)) {
/* not critical */
}
status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
if (NT_STATUS_IS_OK(status)) {
if (ok) {
r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
}
}
key = talloc_asprintf(mem_ctx, "%s.%s:%s",
"PrinterPackageInstallation", short_environment, "PackageAware");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getbool(ctx, key, &ok);
if (NT_STATUS_IS_OK(status)) {
if (ok) {
r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
}
}
key = talloc_asprintf(mem_ctx, "%s.%s:%s",
"PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
char **list;
r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
if (r->core_driver_dependencies == NULL) {
return NT_STATUS_NO_MEMORY;
}
list = str_list_make_v3(r->core_driver_dependencies, s, ",");
if (list == NULL) {
return NT_STATUS_NO_MEMORY;
}
r->core_driver_dependencies->string = const_str_list(list);
}
key = talloc_asprintf(mem_ctx, "%s.%s:%s",
"PrinterPackageInstallation", short_environment, "InboxVersionRequired");
if (key == NULL) {
return NT_STATUS_NO_MEMORY;
}
status = gp_inifile_getstring(ctx, key, &s);
if (NT_STATUS_IS_OK(status)) {
if (strequal(s, "UseDriverVer")) {
r->min_inbox_driver_ver_date = r->driver_date;
r->min_inbox_driver_ver_version = r->driver_version;
}
}
return NT_STATUS_OK;
}
/****************************************************************
parse a printer inf file
****************************************************************/
NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
const char *core_driver_inf,
const char *filename,
const char *environment,
const char *driver_name,
struct spoolss_AddDriverInfo8 *r,
const char **source_disk_name)
{
NTSTATUS status;
struct inf_context *inf_ctx;
if (!filename || !environment) {
return NT_STATUS_INVALID_PARAMETER;
}
status = init_inf_context(mem_ctx,
filename,
core_driver_inf,
&inf_ctx);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = setup_driver_by_name(mem_ctx, inf_ctx,
filename,
environment,
driver_name,
r,
source_disk_name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}
NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
const char *core_driver_inf,
const char *filename,
const char *environment,
uint32_t *count,
struct spoolss_AddDriverInfo8 **_r)
{
NTSTATUS status;
const char *short_environment;
size_t d, num_devices = 0;
const char **devices = NULL;
const char **device_values = NULL;
struct inf_context *inf_ctx;
if (!filename || !environment) {
return NT_STATUS_INVALID_PARAMETER;
}
short_environment = spoolss_get_short_filesys_environment(environment);
if (short_environment == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
status = init_inf_context(mem_ctx,
filename,
core_driver_inf,
&inf_ctx);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
&num_devices,
&devices,
&device_values);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
for (d = 0; d < num_devices; d++) {
struct spoolss_AddDriverInfo8 r;
const char *source_disk_name;
ZERO_STRUCT(r);
status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
environment, devices[d], &r,
&source_disk_name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
}
return NT_STATUS_OK;
}