mirror of
https://github.com/samba-team/samba.git
synced 2025-02-08 05:57:51 +03:00
1321 lines
34 KiB
C
1321 lines
34 KiB
C
/*
|
|
* Unix SMB/Netbios implementation.
|
|
* Version 1.9.
|
|
* RPC Pipe client / server routines
|
|
* Copyright (C) Andrew Tridgell 1992-2000,
|
|
* Copyright (C) Jean François Micouleau 1998-2000.
|
|
*
|
|
* 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 2 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, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
extern int DEBUGLEVEL;
|
|
|
|
static TDB_CONTEXT *tdb; /* used for driver files */
|
|
|
|
#define FORMS_PREFIX "FORMS/"
|
|
#define DRIVERS_PREFIX "DRIVERS/"
|
|
#define PRINTERS_PREFIX "PRINTERS/"
|
|
|
|
#define DATABASE_VERSION 1
|
|
|
|
/****************************************************************************
|
|
open the NT printing tdb
|
|
****************************************************************************/
|
|
int nt_printing_init(void)
|
|
{
|
|
static pid_t local_pid;
|
|
|
|
if (tdb && local_pid == sys_getpid()) return True;
|
|
tdb = tdb_open(lock_path("ntdrivers.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
|
|
DEBUG(0,("Failed to open nt drivers database\n"));
|
|
|
|
local_pid = sys_getpid();
|
|
|
|
/* handle a Samba upgrade */
|
|
tdb_writelock(tdb);
|
|
if (tdb_fetch_int(tdb, "INFO/version") != DATABASE_VERSION) {
|
|
tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
|
|
tdb_store_int(tdb, "INFO/version", DATABASE_VERSION);
|
|
}
|
|
tdb_writeunlock(tdb);
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get a form struct list
|
|
****************************************************************************/
|
|
int get_ntforms(nt_forms_struct **list)
|
|
{
|
|
TDB_DATA kbuf, dbuf;
|
|
nt_forms_struct form;
|
|
int ret;
|
|
int n = 0;
|
|
|
|
for (kbuf = tdb_firstkey(tdb);
|
|
kbuf.dptr;
|
|
free(kbuf.dptr), kbuf = tdb_nextkey(tdb, kbuf)) {
|
|
if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) continue;
|
|
|
|
dbuf = tdb_fetch(tdb, kbuf);
|
|
if (!dbuf.dptr) continue;
|
|
|
|
fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
|
|
ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddddddd",
|
|
&form.flag, &form.width, &form.length, &form.left,
|
|
&form.top, &form.right, &form.bottom);
|
|
free(dbuf.dptr);
|
|
if (ret != dbuf.dsize) continue;
|
|
|
|
*list = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
|
|
(*list)[n] = form;
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
/****************************************************************************
|
|
write a form struct list
|
|
****************************************************************************/
|
|
int write_ntforms(nt_forms_struct **list, int number)
|
|
{
|
|
pstring buf, key;
|
|
int len;
|
|
TDB_DATA kbuf,dbuf;
|
|
int i;
|
|
|
|
for (i=0;i<number;i++) {
|
|
len = tdb_pack(buf, sizeof(buf), "ddddddd",
|
|
(*list)[i].flag, (*list)[i].width, (*list)[i].length,
|
|
(*list)[i].left, (*list)[i].top, (*list)[i].right,
|
|
(*list)[i].bottom);
|
|
if (len > sizeof(buf)) break;
|
|
slprintf(key, sizeof(key), "%s/%s", FORMS_PREFIX, (*list)[i].name);
|
|
kbuf.dsize = strlen(key)+1;
|
|
kbuf.dptr = key;
|
|
dbuf.dsize = len;
|
|
dbuf.dptr = buf;
|
|
if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/****************************************************************************
|
|
add a form struct at the end of the list
|
|
****************************************************************************/
|
|
BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
|
|
{
|
|
int n=0;
|
|
BOOL update;
|
|
fstring form_name;
|
|
|
|
/*
|
|
* NT tries to add forms even when
|
|
* they are already in the base
|
|
* only update the values if already present
|
|
*/
|
|
|
|
update=False;
|
|
|
|
unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
|
|
for (n=0; n<*count && update==False; n++)
|
|
{
|
|
if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
|
|
{
|
|
DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
|
|
update=True;
|
|
}
|
|
}
|
|
|
|
if (update==False)
|
|
{
|
|
if((*list=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL)
|
|
return False;
|
|
unistr2_to_ascii((*list)[n].name, &(form->name), sizeof((*list)[n].name)-1);
|
|
(*count)++;
|
|
}
|
|
|
|
(*list)[n].flag=form->flags;
|
|
(*list)[n].width=form->size_x;
|
|
(*list)[n].length=form->size_y;
|
|
(*list)[n].left=form->left;
|
|
(*list)[n].top=form->top;
|
|
(*list)[n].right=form->right;
|
|
(*list)[n].bottom=form->bottom;
|
|
|
|
return True;
|
|
}
|
|
|
|
/****************************************************************************
|
|
update a form struct
|
|
****************************************************************************/
|
|
void update_a_form(nt_forms_struct **list, const FORM *form, int count)
|
|
{
|
|
int n=0;
|
|
fstring form_name;
|
|
unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
|
|
|
|
DEBUG(106, ("[%s]\n", form_name));
|
|
for (n=0; n<count; n++)
|
|
{
|
|
DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
|
|
if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
|
|
break;
|
|
}
|
|
|
|
if (n==count) return;
|
|
|
|
(*list)[n].flag=form->flags;
|
|
(*list)[n].width=form->size_x;
|
|
(*list)[n].length=form->size_y;
|
|
(*list)[n].left=form->left;
|
|
(*list)[n].top=form->top;
|
|
(*list)[n].right=form->right;
|
|
(*list)[n].bottom=form->bottom;
|
|
}
|
|
|
|
/****************************************************************************
|
|
get the nt drivers list
|
|
|
|
traverse the database and look-up the matching names
|
|
****************************************************************************/
|
|
int get_ntdrivers(fstring **list, char *architecture)
|
|
{
|
|
int total=0;
|
|
fstring short_archi;
|
|
pstring key;
|
|
TDB_DATA kbuf;
|
|
|
|
get_short_archi(short_archi, architecture);
|
|
slprintf(key, sizeof(key), "%s/%s/", DRIVERS_PREFIX, short_archi);
|
|
|
|
for (kbuf = tdb_firstkey(tdb);
|
|
kbuf.dptr;
|
|
free(kbuf.dptr), kbuf = tdb_nextkey(tdb, kbuf)) {
|
|
if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue;
|
|
|
|
if((*list = Realloc(*list, sizeof(fstring)*(total+1))) == NULL)
|
|
return -1;
|
|
|
|
fstrcpy((*list)[total], kbuf.dptr+strlen(key));
|
|
total++;
|
|
}
|
|
|
|
return(total);
|
|
}
|
|
|
|
/****************************************************************************
|
|
function to do the mapping between the long architecture name and
|
|
the short one.
|
|
****************************************************************************/
|
|
void get_short_archi(char *short_archi, char *long_archi)
|
|
{
|
|
struct table {
|
|
char *long_archi;
|
|
char *short_archi;
|
|
};
|
|
|
|
struct table archi_table[]=
|
|
{
|
|
{"Windows 4.0", "WIN40" },
|
|
{"Windows NT x86", "W32X86" },
|
|
{"Windows NT R4000", "W32mips" },
|
|
{"Windows NT Alpha_AXP", "W32alpha" },
|
|
{"Windows NT PowerPC", "W32ppc" },
|
|
{NULL, "" }
|
|
};
|
|
|
|
int i=-1;
|
|
|
|
DEBUG(107,("Getting architecture dependant directory\n"));
|
|
do {
|
|
i++;
|
|
} while ( (archi_table[i].long_archi!=NULL ) && strncmp(long_archi, archi_table[i].long_archi, strlen(long_archi)) );
|
|
|
|
if (archi_table[i].long_archi==NULL)
|
|
{
|
|
DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
|
|
}
|
|
StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
|
|
|
|
DEBUGADD(108,("index: [%d]\n", i));
|
|
DEBUGADD(108,("long architecture: [%s]\n", long_archi));
|
|
DEBUGADD(108,("short architecture: [%s]\n", short_archi));
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
|
|
{
|
|
int len, buflen;
|
|
fstring architecture;
|
|
pstring key;
|
|
char *buf;
|
|
int i, ret;
|
|
TDB_DATA kbuf, dbuf;
|
|
|
|
get_short_archi(architecture, driver->environment);
|
|
slprintf(key, sizeof(key), "%s/%s/%s", DRIVERS_PREFIX, architecture, driver->name);
|
|
|
|
/*
|
|
* cversion must be 2.
|
|
* when adding a printer ON the SERVER
|
|
* rpcAddPrinterDriver defines it to zero
|
|
* which is wrong !!!
|
|
*
|
|
* JFM, 4/14/99
|
|
*/
|
|
driver->cversion=2;
|
|
|
|
buf = NULL;
|
|
len = buflen = 0;
|
|
|
|
again:
|
|
len = 0;
|
|
len += tdb_pack(buf+len, buflen-len, "dffffffff",
|
|
driver->cversion,
|
|
driver->name,
|
|
driver->environment,
|
|
driver->driverpath,
|
|
driver->datafile,
|
|
driver->configfile,
|
|
driver->helpfile,
|
|
driver->monitorname,
|
|
driver->defaultdatatype);
|
|
|
|
if (driver->dependentfiles) {
|
|
for (i=0; *driver->dependentfiles[i]; i++) {
|
|
len += tdb_pack(buf+len, buflen-len, "f",
|
|
driver->dependentfiles[i]);
|
|
}
|
|
}
|
|
|
|
if (len != buflen) {
|
|
buf = (char *)Realloc(buf, len);
|
|
buflen = len;
|
|
goto again;
|
|
}
|
|
|
|
|
|
kbuf.dptr = key;
|
|
kbuf.dsize = strlen(key)+1;
|
|
dbuf.dptr = buf;
|
|
dbuf.dsize = len;
|
|
|
|
ret = tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
|
|
|
|
free(buf);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
|
|
{
|
|
NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
|
|
|
|
info3.cversion = driver->version;
|
|
fstrcpy(info3.environment,driver->environment);
|
|
fstrcpy(info3.driverpath,driver->driverpath);
|
|
fstrcpy(info3.datafile,driver->datafile);
|
|
fstrcpy(info3.configfile,driver->configfile);
|
|
fstrcpy(info3.helpfile,driver->helpfile);
|
|
fstrcpy(info3.monitorname,driver->monitorname);
|
|
fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
|
|
info3.dependentfiles = driver->dependentfiles;
|
|
|
|
return add_a_printer_driver_3(&info3);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring in_prt, fstring in_arch)
|
|
{
|
|
NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
|
|
int snum;
|
|
|
|
ZERO_STRUCT(info);
|
|
|
|
snum = lp_servicenumber(in_prt);
|
|
|
|
fstrcpy(info.name, lp_printerdriver(snum));
|
|
fstrcpy(info.defaultdatatype, "RAW");
|
|
|
|
info.dependentfiles=(fstring *)malloc(sizeof(fstring));
|
|
fstrcpy(info.dependentfiles[0], "");
|
|
|
|
*info_ptr = memdup(&info, sizeof(info));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring in_prt, fstring in_arch)
|
|
{
|
|
NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
|
|
TDB_DATA kbuf, dbuf;
|
|
fstring architecture;
|
|
int len = 0;
|
|
int i;
|
|
pstring key;
|
|
|
|
ZERO_STRUCT(driver);
|
|
|
|
get_short_archi(architecture, in_arch);
|
|
slprintf(key, sizeof(key), "%s/%s/%s", DRIVERS_PREFIX, architecture, in_prt);
|
|
|
|
kbuf.dptr = key;
|
|
kbuf.dsize = strlen(key)+1;
|
|
|
|
dbuf = tdb_fetch(tdb, kbuf);
|
|
if (!dbuf.dptr) return get_a_printer_driver_3_default(info_ptr, in_prt, in_arch);
|
|
|
|
len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
|
|
&driver.cversion,
|
|
driver.name,
|
|
driver.environment,
|
|
driver.driverpath,
|
|
driver.datafile,
|
|
driver.configfile,
|
|
driver.helpfile,
|
|
driver.monitorname,
|
|
driver.defaultdatatype);
|
|
|
|
i=0;
|
|
while (len < dbuf.dsize) {
|
|
driver.dependentfiles = (fstring *)Realloc(driver.dependentfiles,
|
|
sizeof(fstring)*(i+2));
|
|
len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
|
|
driver.dependentfiles[i]);
|
|
i++;
|
|
}
|
|
fstrcpy(driver.dependentfiles[i], "");
|
|
|
|
free(dbuf.dptr);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
debugging function, dump at level 6 the struct in the logs
|
|
****************************************************************************/
|
|
static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
|
|
{
|
|
uint32 success;
|
|
NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
|
|
int i;
|
|
|
|
DEBUG(106,("Dumping printer driver at level [%d]\n", level));
|
|
|
|
switch (level)
|
|
{
|
|
case 3:
|
|
{
|
|
if (driver.info_3 == NULL)
|
|
success=5;
|
|
else {
|
|
info3=driver.info_3;
|
|
|
|
DEBUGADD(106,("version:[%d]\n", info3->cversion));
|
|
DEBUGADD(106,("name:[%s]\n", info3->name));
|
|
DEBUGADD(106,("environment:[%s]\n", info3->environment));
|
|
DEBUGADD(106,("driverpath:[%s]\n", info3->driverpath));
|
|
DEBUGADD(106,("datafile:[%s]\n", info3->datafile));
|
|
DEBUGADD(106,("configfile:[%s]\n", info3->configfile));
|
|
DEBUGADD(106,("helpfile:[%s]\n", info3->helpfile));
|
|
DEBUGADD(106,("monitorname:[%s]\n", info3->monitorname));
|
|
DEBUGADD(106,("defaultdatatype:[%s]\n", info3->defaultdatatype));
|
|
|
|
for (i=0; *info3->dependentfiles[i]; i++) {
|
|
DEBUGADD(106,("dependentfile:[%s]\n",
|
|
info3->dependentfiles[i]));
|
|
}
|
|
success=0;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DEBUGADD(1,("Level not implemented\n"));
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
|
|
{
|
|
int len = 0;
|
|
|
|
len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
|
|
|
|
if (!nt_devmode) return len;
|
|
|
|
len += tdb_pack(buf+len, buflen-len, "fddddddddddddddddddddddp",
|
|
nt_devmode->formname,
|
|
nt_devmode->specversion,
|
|
nt_devmode->driverversion,
|
|
nt_devmode->size,
|
|
nt_devmode->driverextra,
|
|
nt_devmode->fields,
|
|
nt_devmode->orientation,
|
|
nt_devmode->papersize,
|
|
nt_devmode->paperlength,
|
|
nt_devmode->paperwidth,
|
|
nt_devmode->scale,
|
|
nt_devmode->copies,
|
|
nt_devmode->defaultsource,
|
|
nt_devmode->printquality,
|
|
nt_devmode->color,
|
|
nt_devmode->duplex,
|
|
nt_devmode->yresolution,
|
|
nt_devmode->ttoption,
|
|
nt_devmode->collate,
|
|
nt_devmode->icmmethod,
|
|
nt_devmode->icmintent,
|
|
nt_devmode->mediatype,
|
|
nt_devmode->dithertype,
|
|
nt_devmode->private);
|
|
|
|
if (nt_devmode->private) {
|
|
len += tdb_pack(buf+len, buflen-len, "B",
|
|
nt_devmode->driverextra,
|
|
nt_devmode->private);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen)
|
|
{
|
|
int len = 0;
|
|
|
|
while (param != NULL) {
|
|
len += tdb_pack(buf+len, buflen-len, "pfdB",
|
|
param,
|
|
param->value,
|
|
param->type,
|
|
param->data_len,
|
|
param->data);
|
|
param=param->next;
|
|
}
|
|
|
|
len += tdb_pack(buf+len, buflen-len, "p", param);
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
delete a printer - this just deletes the printer info file, any open
|
|
handles are not affected
|
|
****************************************************************************/
|
|
uint32 del_a_printer(char *portname)
|
|
{
|
|
pstring key;
|
|
TDB_DATA kbuf;
|
|
|
|
slprintf(key, sizeof(key), "%s/%s",
|
|
PRINTERS_PREFIX, portname);
|
|
|
|
kbuf.dptr=key;
|
|
kbuf.dsize=strlen(key)+1;
|
|
|
|
tdb_delete(tdb, kbuf);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
|
|
{
|
|
pstring key;
|
|
char *buf;
|
|
int buflen, len, ret;
|
|
TDB_DATA kbuf, dbuf;
|
|
|
|
/*
|
|
* in addprinter: no servername and the printer is the name
|
|
* in setprinter: servername is \\server
|
|
* and printer is \\server\\printer
|
|
*
|
|
* Samba manages only local printers.
|
|
* we currently don't support things like path=\\other_server\printer
|
|
*/
|
|
if (info->servername[0]!='\0')
|
|
{
|
|
trim_string(info->printername, info->servername, NULL);
|
|
trim_string(info->printername, "\\", NULL);
|
|
info->servername[0]='\0';
|
|
}
|
|
|
|
/*
|
|
* JFM: one day I'll forget.
|
|
* below that's info->portname because that's the SAMBA sharename
|
|
* and I made NT 'thinks' it's the portname
|
|
* the info->sharename is the thing you can name when you add a printer
|
|
* that's the short-name when you create shared printer for 95/98
|
|
* So I've made a limitation in SAMBA: you can only have 1 printer model
|
|
* behind a SAMBA share.
|
|
*/
|
|
|
|
|
|
buf = NULL;
|
|
buflen = 0;
|
|
|
|
again:
|
|
len = 0;
|
|
len += tdb_pack(buf+len, buflen-len, "dddddddddddffffffffff",
|
|
info->attributes,
|
|
info->priority,
|
|
info->default_priority,
|
|
info->starttime,
|
|
info->untiltime,
|
|
info->status,
|
|
info->cjobs,
|
|
info->averageppm,
|
|
info->changeid,
|
|
info->c_setprinter,
|
|
info->setuptime,
|
|
info->servername,
|
|
info->printername,
|
|
info->sharename,
|
|
info->portname,
|
|
info->drivername,
|
|
info->location,
|
|
info->sepfile,
|
|
info->printprocessor,
|
|
info->datatype,
|
|
info->parameters);
|
|
|
|
len += pack_devicemode(info->devmode, buf+len, buflen-len);
|
|
len += pack_specifics(info->specific, buf+len, buflen-len);
|
|
|
|
if (buflen != len) {
|
|
buf = (char *)Realloc(buf, len);
|
|
buflen = len;
|
|
goto again;
|
|
}
|
|
|
|
|
|
slprintf(key, sizeof(key), "%s/%s",
|
|
PRINTERS_PREFIX, info->portname);
|
|
|
|
kbuf.dptr = key;
|
|
kbuf.dsize = strlen(key)+1;
|
|
dbuf.dptr = buf;
|
|
dbuf.dsize = len;
|
|
|
|
ret = tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
|
|
|
|
free(buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
BOOL add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
|
|
{
|
|
NT_PRINTER_PARAM *current;
|
|
|
|
DEBUG(108,("add_a_specific_param\n"));
|
|
|
|
param->next=NULL;
|
|
|
|
if (info_2->specific == NULL)
|
|
{
|
|
info_2->specific=param;
|
|
}
|
|
else
|
|
{
|
|
current=info_2->specific;
|
|
while (current->next != NULL) {
|
|
current=current->next;
|
|
}
|
|
current->next=param;
|
|
}
|
|
return (True);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param)
|
|
{
|
|
NT_PRINTER_PARAM *current;
|
|
NT_PRINTER_PARAM *previous;
|
|
|
|
current=info_2->specific;
|
|
previous=current;
|
|
|
|
if (current==NULL) return (False);
|
|
|
|
if ( !strcmp(current->value, param->value) &&
|
|
(strlen(current->value)==strlen(param->value)) )
|
|
{
|
|
DEBUG(109,("deleting first value\n"));
|
|
info_2->specific=current->next;
|
|
safe_free(current->data);
|
|
free(current);
|
|
DEBUG(109,("deleted first value\n"));
|
|
return (True);
|
|
}
|
|
|
|
current=previous->next;
|
|
|
|
while ( current!=NULL )
|
|
{
|
|
if (!strcmp(current->value, param->value) &&
|
|
strlen(current->value)==strlen(param->value) )
|
|
{
|
|
DEBUG(109,("deleting current value\n"));
|
|
previous->next=current->next;
|
|
free(current);
|
|
DEBUG(109,("deleted current value\n"));
|
|
return(True);
|
|
}
|
|
|
|
previous=previous->next;
|
|
current=current->next;
|
|
}
|
|
return (False);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Clean up and deallocate a (maybe partially) allocated NT_PRINTER_PARAM.
|
|
****************************************************************************/
|
|
static void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr)
|
|
{
|
|
NT_PRINTER_PARAM *param = *param_ptr;
|
|
|
|
if(param == NULL)
|
|
return;
|
|
|
|
DEBUG(106,("free_nt_printer_param: deleting param [%s]\n", param->value));
|
|
|
|
if(param->data)
|
|
free(param->data);
|
|
|
|
free(param);
|
|
*param_ptr = NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
|
|
****************************************************************************/
|
|
static void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
|
|
{
|
|
NT_DEVICEMODE *nt_devmode = *devmode_ptr;
|
|
|
|
if(nt_devmode == NULL)
|
|
return;
|
|
|
|
DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
|
|
|
|
if(nt_devmode->private)
|
|
free(nt_devmode->private);
|
|
|
|
free(nt_devmode);
|
|
*devmode_ptr = NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
|
|
****************************************************************************/
|
|
static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
|
|
{
|
|
NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
|
|
NT_PRINTER_PARAM *param_ptr;
|
|
|
|
if(info == NULL)
|
|
return;
|
|
|
|
DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
|
|
|
|
free_nt_devicemode(&info->devmode);
|
|
free_sec_desc_buf(&info->secdesc);
|
|
|
|
for(param_ptr = info->specific; param_ptr; ) {
|
|
NT_PRINTER_PARAM *tofree = param_ptr;
|
|
|
|
param_ptr = param_ptr->next;
|
|
free_nt_printer_param(&tofree);
|
|
}
|
|
|
|
free(info);
|
|
*info_ptr = NULL;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
|
|
{
|
|
int len = 0;
|
|
NT_DEVICEMODE devmode;
|
|
|
|
ZERO_STRUCT(devmode);
|
|
|
|
len += tdb_unpack(buf+len, buflen-len, "p", *nt_devmode);
|
|
|
|
if (!*nt_devmode) return len;
|
|
|
|
len += tdb_unpack(buf+len, buflen-len, "fddddddddddddddddddddddp",
|
|
devmode.formname,
|
|
&devmode.specversion,
|
|
&devmode.driverversion,
|
|
&devmode.size,
|
|
&devmode.driverextra,
|
|
&devmode.fields,
|
|
&devmode.orientation,
|
|
&devmode.papersize,
|
|
&devmode.paperlength,
|
|
&devmode.paperwidth,
|
|
&devmode.scale,
|
|
&devmode.copies,
|
|
&devmode.defaultsource,
|
|
&devmode.printquality,
|
|
&devmode.color,
|
|
&devmode.duplex,
|
|
&devmode.yresolution,
|
|
&devmode.ttoption,
|
|
&devmode.collate,
|
|
&devmode.icmmethod,
|
|
&devmode.icmintent,
|
|
&devmode.mediatype,
|
|
&devmode.dithertype,
|
|
&devmode.private);
|
|
|
|
if (devmode.private) {
|
|
devmode.private = (uint8 *)malloc(devmode.driverextra);
|
|
if (!devmode.private) return 2;
|
|
len += tdb_unpack(buf+len, buflen-len, "B",
|
|
devmode.driverextra,
|
|
devmode.private);
|
|
}
|
|
|
|
*nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
|
|
|
|
return len;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen)
|
|
{
|
|
int len = 0;
|
|
NT_PRINTER_PARAM param, *p;
|
|
|
|
*list = NULL;
|
|
|
|
while (1) {
|
|
len += tdb_unpack(buf+len, buflen-len, "p", p);
|
|
if (!p) break;
|
|
|
|
len += tdb_unpack(buf+len, buflen-len, "fdB",
|
|
param.value,
|
|
¶m.type,
|
|
¶m.data_len,
|
|
¶m.data);
|
|
param.next = *list;
|
|
*list = memdup(¶m, sizeof(param));
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
get a default printer info 2 struct
|
|
****************************************************************************/
|
|
static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
|
|
{
|
|
extern pstring global_myname;
|
|
int snum;
|
|
NT_PRINTER_INFO_LEVEL_2 info;
|
|
NT_DEVICEMODE devmode;
|
|
|
|
ZERO_STRUCT(info);
|
|
ZERO_STRUCT(devmode);
|
|
|
|
init_devicemode(&devmode);
|
|
|
|
snum = lp_servicenumber(sharename);
|
|
|
|
fstrcpy(info.servername, global_myname);
|
|
fstrcpy(info.printername, sharename);
|
|
fstrcpy(info.portname, sharename);
|
|
fstrcpy(info.drivername, lp_printerdriver(snum));
|
|
fstrcpy(info.printprocessor, "winprint");
|
|
fstrcpy(info.datatype, "RAW");
|
|
|
|
info.devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
|
|
|
|
*info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
|
|
if (! *info_ptr) return 2;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
|
|
{
|
|
pstring key;
|
|
NT_PRINTER_INFO_LEVEL_2 info;
|
|
int len = 0;
|
|
TDB_DATA kbuf, dbuf;
|
|
|
|
ZERO_STRUCT(info);
|
|
|
|
slprintf(key, sizeof(key), "%s/%s",
|
|
PRINTERS_PREFIX, sharename);
|
|
|
|
kbuf.dptr = key;
|
|
kbuf.dsize = strlen(key)+1;
|
|
|
|
dbuf = tdb_fetch(tdb, kbuf);
|
|
if (!dbuf.dptr) return get_a_printer_2_default(info_ptr, sharename);
|
|
|
|
len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddffffffffff",
|
|
&info.attributes,
|
|
&info.priority,
|
|
&info.default_priority,
|
|
&info.starttime,
|
|
&info.untiltime,
|
|
&info.status,
|
|
&info.cjobs,
|
|
&info.averageppm,
|
|
&info.changeid,
|
|
&info.c_setprinter,
|
|
&info.setuptime,
|
|
info.servername,
|
|
info.printername,
|
|
info.sharename,
|
|
info.portname,
|
|
info.drivername,
|
|
info.location,
|
|
info.sepfile,
|
|
info.printprocessor,
|
|
info.datatype,
|
|
info.parameters);
|
|
|
|
len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
|
|
len += unpack_specifics(&info.specific,dbuf.dptr+len, dbuf.dsize-len);
|
|
|
|
*info_ptr=memdup(&info, sizeof(info));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
debugging function, dump at level 6 the struct in the logs
|
|
****************************************************************************/
|
|
static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
|
|
{
|
|
uint32 success;
|
|
NT_PRINTER_INFO_LEVEL_2 *info2;
|
|
|
|
DEBUG(106,("Dumping printer at level [%d]\n", level));
|
|
|
|
switch (level)
|
|
{
|
|
case 2:
|
|
{
|
|
if (printer.info_2 == NULL)
|
|
success=5;
|
|
else
|
|
{
|
|
info2=printer.info_2;
|
|
|
|
DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
|
|
DEBUGADD(106,("priority:[%d]\n", info2->priority));
|
|
DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
|
|
DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
|
|
DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
|
|
DEBUGADD(106,("status:[%d]\n", info2->status));
|
|
DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
|
|
DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
|
|
DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
|
|
DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
|
|
DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
|
|
|
|
DEBUGADD(106,("servername:[%s]\n", info2->servername));
|
|
DEBUGADD(106,("printername:[%s]\n", info2->printername));
|
|
DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
|
|
DEBUGADD(106,("portname:[%s]\n", info2->portname));
|
|
DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
|
|
DEBUGADD(106,("location:[%s]\n", info2->location));
|
|
DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
|
|
DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
|
|
DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
|
|
DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
|
|
success=0;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DEBUGADD(1,("Level not implemented\n"));
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
/*
|
|
* The function below are the high level ones.
|
|
* only those ones must be called from the spoolss code.
|
|
* JFM.
|
|
*/
|
|
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
|
|
{
|
|
uint32 success;
|
|
|
|
dump_a_printer(printer, level);
|
|
|
|
switch (level)
|
|
{
|
|
case 2:
|
|
{
|
|
success=add_a_printer_2(printer.info_2);
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 get_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level, fstring sharename)
|
|
{
|
|
uint32 success;
|
|
|
|
DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
|
|
|
|
switch (level)
|
|
{
|
|
case 2:
|
|
{
|
|
printer->info_2=NULL;
|
|
success=get_a_printer_2(&(printer->info_2), sharename);
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
dump_a_printer(*printer, level);
|
|
|
|
DEBUG(10,("get_a_printer: [%s] level %u returning %u\n", sharename, (unsigned int)level, (unsigned int)success));
|
|
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 free_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
|
|
{
|
|
uint32 success;
|
|
DEBUG(104,("freeing a printer at level [%d]\n", level));
|
|
|
|
switch (level)
|
|
{
|
|
case 2:
|
|
{
|
|
if (printer.info_2 != NULL)
|
|
{
|
|
free_nt_printer_info_level_2(&printer.info_2);
|
|
success=0;
|
|
}
|
|
else
|
|
{
|
|
success=4;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
|
|
{
|
|
uint32 success;
|
|
DEBUG(104,("adding a printer at level [%d]\n", level));
|
|
dump_a_printer_driver(driver, level);
|
|
|
|
switch (level)
|
|
{
|
|
case 3:
|
|
{
|
|
success=add_a_printer_driver_3(driver.info_3);
|
|
break;
|
|
}
|
|
|
|
case 6:
|
|
{
|
|
success=add_a_printer_driver_6(driver.info_6);
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
|
|
fstring printername, fstring architecture)
|
|
{
|
|
uint32 success;
|
|
|
|
switch (level)
|
|
{
|
|
case 3:
|
|
{
|
|
success=get_a_printer_driver_3(&(driver->info_3),
|
|
printername,
|
|
architecture);
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
|
|
if (success == 0) dump_a_printer_driver(*driver, level);
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
|
|
{
|
|
uint32 success;
|
|
NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
|
|
|
|
switch (level)
|
|
{
|
|
case 3:
|
|
{
|
|
if (driver.info_3 != NULL)
|
|
{
|
|
info3=driver.info_3;
|
|
if (info3->dependentfiles)
|
|
free(info3->dependentfiles);
|
|
free(info3);
|
|
ZERO_STRUCTP(info3);
|
|
success=0;
|
|
}
|
|
else
|
|
{
|
|
success=4;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
success=1;
|
|
break;
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
|
|
fstring value, uint8 **data, uint32 *type, uint32 *len)
|
|
{
|
|
/* right now that's enough ! */
|
|
NT_PRINTER_PARAM *param;
|
|
int i=0;
|
|
|
|
param=printer.info_2->specific;
|
|
|
|
while (param != NULL && i <= param_index)
|
|
{
|
|
param=param->next;
|
|
i++;
|
|
}
|
|
|
|
if (param == NULL)
|
|
return False;
|
|
|
|
/* exited because it exist */
|
|
*type=param->type;
|
|
StrnCpy(value, param->value, sizeof(fstring)-1);
|
|
*data=(uint8 *)malloc(param->data_len*sizeof(uint8));
|
|
if(*data == NULL)
|
|
return False;
|
|
memcpy(*data, param->data, param->data_len);
|
|
*len=param->data_len;
|
|
return True;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
|
|
fstring value, uint8 **data, uint32 *type, uint32 *len)
|
|
{
|
|
/* right now that's enough ! */
|
|
NT_PRINTER_PARAM *param;
|
|
|
|
DEBUG(105, ("get_specific_param\n"));
|
|
|
|
param=printer.info_2->specific;
|
|
|
|
while (param != NULL)
|
|
{
|
|
if ( !strcmp(value, param->value)
|
|
&& strlen(value)==strlen(param->value))
|
|
break;
|
|
|
|
param=param->next;
|
|
}
|
|
|
|
DEBUG(106, ("found one param\n"));
|
|
if (param != NULL)
|
|
{
|
|
/* exited because it exist */
|
|
*type=param->type;
|
|
|
|
*data=(uint8 *)malloc(param->data_len*sizeof(uint8));
|
|
if(*data == NULL)
|
|
return False;
|
|
memcpy(*data, param->data, param->data_len);
|
|
*len=param->data_len;
|
|
|
|
DEBUG(106, ("exit of get_specific_param:true\n"));
|
|
return (True);
|
|
}
|
|
DEBUG(106, ("exit of get_specific_param:false\n"));
|
|
return (False);
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
void init_devicemode(NT_DEVICEMODE *nt_devmode)
|
|
{
|
|
/*
|
|
* should I init this ones ???
|
|
nt_devmode->devicename
|
|
*/
|
|
fstrcpy(nt_devmode->formname, "A4");
|
|
|
|
nt_devmode->specversion = 0x0401;
|
|
nt_devmode->driverversion = 0x0400;
|
|
nt_devmode->size = 0x00DC;
|
|
nt_devmode->driverextra = 0x0000;
|
|
nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
|
|
DEFAULTSOURCE | COPIES | SCALE |
|
|
PAPERSIZE | ORIENTATION;
|
|
nt_devmode->orientation = 1;
|
|
nt_devmode->papersize = PAPER_A4;
|
|
nt_devmode->paperlength = 0;
|
|
nt_devmode->paperwidth = 0;
|
|
nt_devmode->scale = 0x64;
|
|
nt_devmode->copies = 01;
|
|
nt_devmode->defaultsource = BIN_FORMSOURCE;
|
|
nt_devmode->printquality = 0x0258;
|
|
nt_devmode->color = COLOR_MONOCHROME;
|
|
nt_devmode->duplex = DUP_SIMPLEX;
|
|
nt_devmode->yresolution = 0;
|
|
nt_devmode->ttoption = TT_SUBDEV;
|
|
nt_devmode->collate = COLLATE_FALSE;
|
|
nt_devmode->icmmethod = 0;
|
|
nt_devmode->icmintent = 0;
|
|
nt_devmode->mediatype = 0;
|
|
nt_devmode->dithertype = 0;
|
|
|
|
/* non utilisés par un driver d'imprimante */
|
|
nt_devmode->logpixels = 0;
|
|
nt_devmode->bitsperpel = 0;
|
|
nt_devmode->pelswidth = 0;
|
|
nt_devmode->pelsheight = 0;
|
|
nt_devmode->displayflags = 0;
|
|
nt_devmode->displayfrequency = 0;
|
|
nt_devmode->reserved1 = 0;
|
|
nt_devmode->reserved2 = 0;
|
|
nt_devmode->panningwidth = 0;
|
|
nt_devmode->panningheight = 0;
|
|
|
|
nt_devmode->private=NULL;
|
|
}
|
|
|
|
|
|
/* error code:
|
|
0: everything OK
|
|
1: level not implemented
|
|
2: file doesn't exist
|
|
3: can't allocate memory
|
|
4: can't free memory
|
|
5: non existant struct
|
|
*/
|
|
|
|
/*
|
|
A printer and a printer driver are 2 different things.
|
|
NT manages them separatelly, Samba does the same.
|
|
Why ? Simply because it's easier and it makes sense !
|
|
|
|
Now explanation: You have 3 printers behind your samba server,
|
|
2 of them are the same make and model (laser A and B). But laser B
|
|
has an 3000 sheet feeder and laser A doesn't such an option.
|
|
Your third printer is an old dot-matrix model for the accounting :-).
|
|
|
|
If the /usr/local/samba/lib directory (default dir), you will have
|
|
5 files to describe all of this.
|
|
|
|
3 files for the printers (1 by printer):
|
|
NTprinter_laser A
|
|
NTprinter_laser B
|
|
NTprinter_accounting
|
|
2 files for the drivers (1 for the laser and 1 for the dot matrix)
|
|
NTdriver_printer model X
|
|
NTdriver_printer model Y
|
|
|
|
jfm: I should use this comment for the text file to explain
|
|
same thing for the forms BTW.
|
|
Je devrais mettre mes commentaires en francais, ca serait mieux :-)
|
|
|
|
*/
|
|
|
|
|