build: Remove SMB_OFF_T, replace with off_t
[kai/samba.git] / source3 / printing / nt_printing.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean François Micouleau      1998-2000.
6  *  Copyright (C) Gerald Carter                2002-2005.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
37
38 /* Map generic permissions to printer object specific permissions */
39
40 const struct generic_mapping printer_generic_mapping = {
41         PRINTER_READ,
42         PRINTER_WRITE,
43         PRINTER_EXECUTE,
44         PRINTER_ALL_ACCESS
45 };
46
47 /* Map generic permissions to print server object specific permissions */
48
49 const struct generic_mapping printserver_generic_mapping = {
50         SERVER_READ,
51         SERVER_WRITE,
52         SERVER_EXECUTE,
53         SERVER_ALL_ACCESS
54 };
55
56 /* Map generic permissions to job object specific permissions */
57
58 const struct generic_mapping job_generic_mapping = {
59         JOB_READ,
60         JOB_WRITE,
61         JOB_EXECUTE,
62         JOB_ALL_ACCESS
63 };
64
65 static const struct print_architecture_table_node archi_table[]= {
66
67         {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
68         {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
69         {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
70         {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
71         {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
72         {"Windows IA64",         SPL_ARCH_IA64,         3 },
73         {"Windows x64",          SPL_ARCH_X64,          3 },
74         {NULL,                   "",            -1 }
75 };
76
77 /****************************************************************************
78  Open the NT printing tdbs. Done once before fork().
79 ****************************************************************************/
80
81 bool nt_printing_init(struct messaging_context *msg_ctx)
82 {
83         WERROR win_rc;
84
85         if (!nt_printing_tdb_upgrade()) {
86                 return false;
87         }
88
89         /*
90          * register callback to handle updating printers as new
91          * drivers are installed
92          */
93         messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
94                            do_drv_upgrade_printer);
95
96         /* of course, none of the message callbacks matter if you don't
97            tell messages.c that you interested in receiving PRINT_GENERAL
98            msgs.  This is done in serverid_register() */
99
100         if ( lp_security() == SEC_ADS ) {
101                 win_rc = check_published_printers(msg_ctx);
102                 if (!W_ERROR_IS_OK(win_rc))
103                         DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
104         }
105
106         return true;
107 }
108
109 /*******************************************************************
110  Function to allow filename parsing "the old way".
111 ********************************************************************/
112
113 static NTSTATUS driver_unix_convert(connection_struct *conn,
114                                     const char *old_name,
115                                     struct smb_filename **smb_fname)
116 {
117         NTSTATUS status;
118         TALLOC_CTX *ctx = talloc_tos();
119         char *name = talloc_strdup(ctx, old_name);
120
121         if (!name) {
122                 return NT_STATUS_NO_MEMORY;
123         }
124         unix_format(name);
125         name = unix_clean_name(ctx, name);
126         if (!name) {
127                 return NT_STATUS_NO_MEMORY;
128         }
129         trim_string(name,"/","/");
130
131         status = unix_convert(ctx, conn, name, smb_fname, 0);
132         if (!NT_STATUS_IS_OK(status)) {
133                 return NT_STATUS_NO_MEMORY;
134         }
135
136         return NT_STATUS_OK;
137 }
138
139 /****************************************************************************
140  Function to do the mapping between the long architecture name and
141  the short one.
142 ****************************************************************************/
143
144 const char *get_short_archi(const char *long_archi)
145 {
146         int i=-1;
147
148         DEBUG(107,("Getting architecture dependent directory\n"));
149         do {
150                 i++;
151         } while ( (archi_table[i].long_archi!=NULL ) &&
152                   strcasecmp_m(long_archi, archi_table[i].long_archi) );
153
154         if (archi_table[i].long_archi==NULL) {
155                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
156                 return NULL;
157         }
158
159         /* this might be client code - but shouldn't this be an fstrcpy etc? */
160
161         DEBUGADD(108,("index: [%d]\n", i));
162         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
163         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
164
165         return archi_table[i].short_archi;
166 }
167
168 /****************************************************************************
169  Version information in Microsoft files is held in a VS_VERSION_INFO structure.
170  There are two case to be covered here: PE (Portable Executable) and NE (New
171  Executable) files. Both files support the same INFO structure, but PE files
172  store the signature in unicode, and NE files store it as !unicode.
173  returns -1 on error, 1 on version info found, and 0 on no version info found.
174 ****************************************************************************/
175
176 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
177 {
178         int     i;
179         char    *buf = NULL;
180         ssize_t byte_count;
181
182         if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
183                 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
184                                 fname, DOS_HEADER_SIZE));
185                 goto error_exit;
186         }
187
188         if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
189                 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
190                          fname, (unsigned long)byte_count));
191                 goto no_version_info;
192         }
193
194         /* Is this really a DOS header? */
195         if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
196                 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
197                                 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
198                 goto no_version_info;
199         }
200
201         /* Skip OEM header (if any) and the DOS stub to start of Windows header */
202         if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
203                 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
204                                 fname, errno));
205                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
206                 goto no_version_info;
207         }
208
209         /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
210         if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
211                 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
212                          fname, (unsigned long)byte_count));
213                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
214                 goto no_version_info;
215         }
216
217         /* The header may be a PE (Portable Executable) or an NE (New Executable) */
218         if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
219                 unsigned int num_sections;
220                 unsigned int section_table_bytes;
221
222                 /* Just skip over optional header to get to section table */
223                 if (SMB_VFS_LSEEK(fsp,
224                                 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
225                                 SEEK_CUR) == (off_t)-1) {
226                         DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
227                                 fname, errno));
228                         goto error_exit;
229                 }
230
231                 /* get the section table */
232                 num_sections        = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
233                 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
234                 if (section_table_bytes == 0)
235                         goto error_exit;
236
237                 SAFE_FREE(buf);
238                 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
239                         DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
240                                         fname, section_table_bytes));
241                         goto error_exit;
242                 }
243
244                 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
245                         DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
246                                  fname, (unsigned long)byte_count));
247                         goto error_exit;
248                 }
249
250                 /* Iterate the section table looking for the resource section ".rsrc" */
251                 for (i = 0; i < num_sections; i++) {
252                         int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
253
254                         if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
255                                 unsigned int section_pos   = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
256                                 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
257
258                                 if (section_bytes == 0)
259                                         goto error_exit;
260
261                                 SAFE_FREE(buf);
262                                 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
263                                         DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
264                                                         fname, section_bytes));
265                                         goto error_exit;
266                                 }
267
268                                 /* Seek to the start of the .rsrc section info */
269                                 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
270                                         DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
271                                                         fname, errno));
272                                         goto error_exit;
273                                 }
274
275                                 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
276                                         DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
277                                                  fname, (unsigned long)byte_count));
278                                         goto error_exit;
279                                 }
280
281                                 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
282                                         goto error_exit;
283
284                                 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
285                                         /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
286                                         if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
287                                                 /* Align to next long address */
288                                                 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
289
290                                                 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
291                                                         *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
292                                                         *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
293
294                                                         DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
295                                                                           fname, *major, *minor,
296                                                                           (*major>>16)&0xffff, *major&0xffff,
297                                                                           (*minor>>16)&0xffff, *minor&0xffff));
298                                                         SAFE_FREE(buf);
299                                                         return 1;
300                                                 }
301                                         }
302                                 }
303                         }
304                 }
305
306                 /* Version info not found, fall back to origin date/time */
307                 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
308                 SAFE_FREE(buf);
309                 return 0;
310
311         } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
312                 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
313                         DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
314                                         fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
315                         /* At this point, we assume the file is in error. It still could be somthing
316                          * else besides a NE file, but it unlikely at this point. */
317                         goto error_exit;
318                 }
319
320                 /* Allocate a bit more space to speed up things */
321                 SAFE_FREE(buf);
322                 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
323                         DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
324                                         fname, PE_HEADER_SIZE));
325                         goto error_exit;
326                 }
327
328                 /* This is a HACK! I got tired of trying to sort through the messy
329                  * 'NE' file format. If anyone wants to clean this up please have at
330                  * it, but this works. 'NE' files will eventually fade away. JRR */
331                 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
332                         /* Cover case that should not occur in a well formed 'NE' .dll file */
333                         if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
334
335                         for(i=0; i<byte_count; i++) {
336                                 /* Fast skip past data that can't possibly match */
337                                 if (buf[i] != 'V') continue;
338
339                                 /* Potential match data crosses buf boundry, move it to beginning
340                                  * of buf, and fill the buf with as much as it will hold. */
341                                 if (i>byte_count-VS_VERSION_INFO_SIZE) {
342                                         int bc;
343
344                                         memcpy(buf, &buf[i], byte_count-i);
345                                         if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
346                                                                    (byte_count-i))) < 0) {
347
348                                                 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
349                                                                  fname, errno));
350                                                 goto error_exit;
351                                         }
352
353                                         byte_count = bc + (byte_count - i);
354                                         if (byte_count<VS_VERSION_INFO_SIZE) break;
355
356                                         i = 0;
357                                 }
358
359                                 /* Check that the full signature string and the magic number that
360                                  * follows exist (not a perfect solution, but the chances that this
361                                  * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
362                                  * twice, as it is simpler to read the code. */
363                                 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
364                                         /* Compute skip alignment to next long address */
365                                         int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
366                                                                  sizeof(VS_SIGNATURE)) & 3;
367                                         if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
368
369                                         *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
370                                         *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
371                                         DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
372                                                           fname, *major, *minor,
373                                                           (*major>>16)&0xffff, *major&0xffff,
374                                                           (*minor>>16)&0xffff, *minor&0xffff));
375                                         SAFE_FREE(buf);
376                                         return 1;
377                                 }
378                         }
379                 }
380
381                 /* Version info not found, fall back to origin date/time */
382                 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
383                 SAFE_FREE(buf);
384                 return 0;
385
386         } else
387                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
388                 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
389                                 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
390
391         no_version_info:
392                 SAFE_FREE(buf);
393                 return 0;
394
395         error_exit:
396                 SAFE_FREE(buf);
397                 return -1;
398 }
399
400 /****************************************************************************
401 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
402 share one or more files. During the MS installation process files are checked
403 to insure that only a newer version of a shared file is installed over an
404 older version. There are several possibilities for this comparison. If there
405 is no previous version, the new one is newer (obviously). If either file is
406 missing the version info structure, compare the creation date (on Unix use
407 the modification date). Otherwise chose the numerically larger version number.
408 ****************************************************************************/
409
410 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
411 {
412         bool use_version = true;
413
414         uint32 new_major;
415         uint32 new_minor;
416         time_t new_create_time;
417
418         uint32 old_major;
419         uint32 old_minor;
420         time_t old_create_time;
421
422         struct smb_filename *smb_fname = NULL;
423         files_struct    *fsp = NULL;
424         SMB_STRUCT_STAT st;
425
426         NTSTATUS status;
427         int ret;
428
429         SET_STAT_INVALID(st);
430         new_create_time = (time_t)0;
431         old_create_time = (time_t)0;
432
433         /* Get file version info (if available) for previous file (if it exists) */
434         status = driver_unix_convert(conn, old_file, &smb_fname);
435         if (!NT_STATUS_IS_OK(status)) {
436                 goto error_exit;
437         }
438
439         status = SMB_VFS_CREATE_FILE(
440                 conn,                                   /* conn */
441                 NULL,                                   /* req */
442                 0,                                      /* root_dir_fid */
443                 smb_fname,                              /* fname */
444                 FILE_GENERIC_READ,                      /* access_mask */
445                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
446                 FILE_OPEN,                              /* create_disposition*/
447                 0,                                      /* create_options */
448                 FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
449                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
450                 0,                                      /* allocation_size */
451                 0,                                      /* private_flags */
452                 NULL,                                   /* sd */
453                 NULL,                                   /* ea_list */
454                 &fsp,                                   /* result */
455                 NULL);                                  /* pinfo */
456
457         if (!NT_STATUS_IS_OK(status)) {
458                 /* Old file not found, so by definition new file is in fact newer */
459                 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
460                           "errno = %d\n", smb_fname_str_dbg(smb_fname),
461                           errno));
462                 ret = 1;
463                 goto done;
464
465         } else {
466                 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
467                 if (ret == -1) {
468                         goto error_exit;
469                 }
470
471                 if (!ret) {
472                         DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
473                                          old_file));
474                         use_version = false;
475                         if (SMB_VFS_FSTAT(fsp, &st) == -1) {
476                                  goto error_exit;
477                         }
478                         old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
479                         DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
480                                 (long)old_create_time));
481                 }
482         }
483         close_file(NULL, fsp, NORMAL_CLOSE);
484         fsp = NULL;
485
486         /* Get file version info (if available) for new file */
487         status = driver_unix_convert(conn, new_file, &smb_fname);
488         if (!NT_STATUS_IS_OK(status)) {
489                 goto error_exit;
490         }
491
492         status = SMB_VFS_CREATE_FILE(
493                 conn,                                   /* conn */
494                 NULL,                                   /* req */
495                 0,                                      /* root_dir_fid */
496                 smb_fname,                              /* fname */
497                 FILE_GENERIC_READ,                      /* access_mask */
498                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
499                 FILE_OPEN,                              /* create_disposition*/
500                 0,                                      /* create_options */
501                 FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
502                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
503                 0,                                      /* allocation_size */
504                 0,                                      /* private_flags */
505                 NULL,                                   /* sd */
506                 NULL,                                   /* ea_list */
507                 &fsp,                                   /* result */
508                 NULL);                                  /* pinfo */
509
510         if (!NT_STATUS_IS_OK(status)) {
511                 /* New file not found, this shouldn't occur if the caller did its job */
512                 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
513                          "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
514                 goto error_exit;
515
516         } else {
517                 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
518                 if (ret == -1) {
519                         goto error_exit;
520                 }
521
522                 if (!ret) {
523                         DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
524                                          new_file));
525                         use_version = false;
526                         if (SMB_VFS_FSTAT(fsp, &st) == -1) {
527                                 goto error_exit;
528                         }
529                         new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
530                         DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
531                                 (long)new_create_time));
532                 }
533         }
534         close_file(NULL, fsp, NORMAL_CLOSE);
535         fsp = NULL;
536
537         if (use_version && (new_major != old_major || new_minor != old_minor)) {
538                 /* Compare versions and choose the larger version number */
539                 if (new_major > old_major ||
540                         (new_major == old_major && new_minor > old_minor)) {
541
542                         DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
543                         ret = 1;
544                         goto done;
545                 }
546                 else {
547                         DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
548                         ret = 0;
549                         goto done;
550                 }
551
552         } else {
553                 /* Compare modification time/dates and choose the newest time/date */
554                 if (new_create_time > old_create_time) {
555                         DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
556                         ret = 1;
557                         goto done;
558                 }
559                 else {
560                         DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
561                         ret = 0;
562                         goto done;
563                 }
564         }
565
566  error_exit:
567         if(fsp)
568                 close_file(NULL, fsp, NORMAL_CLOSE);
569         ret = -1;
570  done:
571         TALLOC_FREE(smb_fname);
572         return ret;
573 }
574
575 /****************************************************************************
576 Determine the correct cVersion associated with an architecture and driver
577 ****************************************************************************/
578 static uint32 get_correct_cversion(struct auth_session_info *session_info,
579                                    const char *architecture,
580                                    const char *driverpath_in,
581                                    WERROR *perr)
582 {
583         int cversion = -1;
584         NTSTATUS          nt_status;
585         struct smb_filename *smb_fname = NULL;
586         char *driverpath = NULL;
587         files_struct      *fsp = NULL;
588         connection_struct *conn = NULL;
589         char *oldcwd;
590         char *printdollar = NULL;
591         int printdollar_snum;
592
593         *perr = WERR_INVALID_PARAM;
594
595         /* If architecture is Windows 95/98/ME, the version is always 0. */
596         if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
597                 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
598                 *perr = WERR_OK;
599                 return 0;
600         }
601
602         /* If architecture is Windows x64, the version is always 3. */
603         if (strcmp(architecture, SPL_ARCH_X64) == 0) {
604                 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
605                 *perr = WERR_OK;
606                 return 3;
607         }
608
609         printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
610         if (!printdollar) {
611                 *perr = WERR_NOMEM;
612                 return -1;
613         }
614         if (printdollar_snum == -1) {
615                 *perr = WERR_NO_SUCH_SHARE;
616                 return -1;
617         }
618
619         nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
620                                        printdollar_snum,
621                                        lp_pathname(printdollar_snum),
622                                        session_info, &oldcwd);
623         if (!NT_STATUS_IS_OK(nt_status)) {
624                 DEBUG(0,("get_correct_cversion: create_conn_struct "
625                          "returned %s\n", nt_errstr(nt_status)));
626                 *perr = ntstatus_to_werror(nt_status);
627                 return -1;
628         }
629
630         nt_status = set_conn_force_user_group(conn, printdollar_snum);
631         if (!NT_STATUS_IS_OK(nt_status)) {
632                 DEBUG(0, ("failed set force user / group\n"));
633                 *perr = ntstatus_to_werror(nt_status);
634                 goto error_free_conn;
635         }
636
637         if (!become_user_by_session(conn, session_info)) {
638                 DEBUG(0, ("failed to become user\n"));
639                 *perr = WERR_ACCESS_DENIED;
640                 goto error_free_conn;
641         }
642
643         /* Open the driver file (Portable Executable format) and determine the
644          * deriver the cversion. */
645         driverpath = talloc_asprintf(talloc_tos(),
646                                         "%s/%s",
647                                         architecture,
648                                         driverpath_in);
649         if (!driverpath) {
650                 *perr = WERR_NOMEM;
651                 goto error_exit;
652         }
653
654         nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
655         if (!NT_STATUS_IS_OK(nt_status)) {
656                 *perr = ntstatus_to_werror(nt_status);
657                 goto error_exit;
658         }
659
660         nt_status = vfs_file_exist(conn, smb_fname);
661         if (!NT_STATUS_IS_OK(nt_status)) {
662                 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
663                 *perr = WERR_BADFILE;
664                 goto error_exit;
665         }
666
667         nt_status = SMB_VFS_CREATE_FILE(
668                 conn,                                   /* conn */
669                 NULL,                                   /* req */
670                 0,                                      /* root_dir_fid */
671                 smb_fname,                              /* fname */
672                 FILE_GENERIC_READ,                      /* access_mask */
673                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
674                 FILE_OPEN,                              /* create_disposition*/
675                 0,                                      /* create_options */
676                 FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
677                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
678                 0,                                      /* private_flags */
679                 0,                                      /* allocation_size */
680                 NULL,                                   /* sd */
681                 NULL,                                   /* ea_list */
682                 &fsp,                                   /* result */
683                 NULL);                                  /* pinfo */
684
685         if (!NT_STATUS_IS_OK(nt_status)) {
686                 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
687                          "%d\n", smb_fname_str_dbg(smb_fname), errno));
688                 *perr = WERR_ACCESS_DENIED;
689                 goto error_exit;
690         } else {
691                 uint32 major;
692                 uint32 minor;
693                 int    ret;
694
695                 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
696                 if (ret == -1) {
697                         *perr = WERR_INVALID_PARAM;
698                         goto error_exit;
699                 } else if (!ret) {
700                         DEBUG(6,("get_correct_cversion: Version info not "
701                                  "found [%s]\n",
702                                  smb_fname_str_dbg(smb_fname)));
703                         *perr = WERR_INVALID_PARAM;
704                         goto error_exit;
705                 }
706
707                 /*
708                  * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
709                  * for more details. Version in this case is not just the version of the
710                  * file, but the version in the sense of kernal mode (2) vs. user mode
711                  * (3) drivers. Other bits of the version fields are the version info.
712                  * JRR 010716
713                 */
714                 cversion = major & 0x0000ffff;
715                 switch (cversion) {
716                         case 2: /* WinNT drivers */
717                         case 3: /* Win2K drivers */
718                                 break;
719
720                         default:
721                                 DEBUG(6,("get_correct_cversion: cversion "
722                                          "invalid [%s]  cversion = %d\n",
723                                          smb_fname_str_dbg(smb_fname),
724                                          cversion));
725                                 goto error_exit;
726                 }
727
728                 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
729                           " = 0x%x  minor = 0x%x\n",
730                           smb_fname_str_dbg(smb_fname), major, minor));
731         }
732
733         DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
734                   smb_fname_str_dbg(smb_fname), cversion));
735         *perr = WERR_OK;
736
737  error_exit:
738         unbecome_user();
739  error_free_conn:
740         TALLOC_FREE(smb_fname);
741         if (fsp != NULL) {
742                 close_file(NULL, fsp, NORMAL_CLOSE);
743         }
744         if (conn != NULL) {
745                 vfs_ChDir(conn, oldcwd);
746                 SMB_VFS_DISCONNECT(conn);
747                 conn_free(conn);
748         }
749         if (!W_ERROR_IS_OK(*perr)) {
750                 cversion = -1;
751         }
752
753         return cversion;
754 }
755
756 /****************************************************************************
757 ****************************************************************************/
758
759 #define strip_driver_path(_mem_ctx, _element) do { \
760         if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
761                 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
762                 W_ERROR_HAVE_NO_MEMORY((_element)); \
763         } \
764 } while (0);
765
766 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
767                                            struct auth_session_info *session_info,
768                                            const char *architecture,
769                                            const char **driver_path,
770                                            const char **data_file,
771                                            const char **config_file,
772                                            const char **help_file,
773                                            struct spoolss_StringArray *dependent_files,
774                                            enum spoolss_DriverOSVersion *version)
775 {
776         const char *short_architecture;
777         int i;
778         WERROR err;
779         char *_p;
780
781         if (!*driver_path || !*data_file) {
782                 return WERR_INVALID_PARAM;
783         }
784
785         if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
786                 return WERR_INVALID_PARAM;
787         }
788
789         /* clean up the driver name.
790          * we can get .\driver.dll
791          * or worse c:\windows\system\driver.dll !
792          */
793         /* using an intermediate string to not have overlaping memcpy()'s */
794
795         strip_driver_path(mem_ctx, *driver_path);
796         strip_driver_path(mem_ctx, *data_file);
797         if (*config_file) {
798                 strip_driver_path(mem_ctx, *config_file);
799         }
800         if (help_file) {
801                 strip_driver_path(mem_ctx, *help_file);
802         }
803
804         if (dependent_files && dependent_files->string) {
805                 for (i=0; dependent_files->string[i]; i++) {
806                         strip_driver_path(mem_ctx, dependent_files->string[i]);
807                 }
808         }
809
810         short_architecture = get_short_archi(architecture);
811         if (!short_architecture) {
812                 return WERR_UNKNOWN_PRINTER_DRIVER;
813         }
814
815         /* jfm:7/16/2000 the client always sends the cversion=0.
816          * The server should check which version the driver is by reading
817          * the PE header of driver->driverpath.
818          *
819          * For Windows 95/98 the version is 0 (so the value sent is correct)
820          * For Windows NT (the architecture doesn't matter)
821          *      NT 3.1: cversion=0
822          *      NT 3.5/3.51: cversion=1
823          *      NT 4: cversion=2
824          *      NT2K: cversion=3
825          */
826
827         *version = get_correct_cversion(session_info, short_architecture,
828                                         *driver_path, &err);
829         if (*version == -1) {
830                 return err;
831         }
832
833         return WERR_OK;
834 }
835
836 /****************************************************************************
837 ****************************************************************************/
838
839 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
840                               struct auth_session_info *session_info,
841                               struct spoolss_AddDriverInfoCtr *r)
842 {
843         switch (r->level) {
844         case 3:
845                 return clean_up_driver_struct_level(mem_ctx, session_info,
846                                                     r->info.info3->architecture,
847                                                     &r->info.info3->driver_path,
848                                                     &r->info.info3->data_file,
849                                                     &r->info.info3->config_file,
850                                                     &r->info.info3->help_file,
851                                                     r->info.info3->dependent_files,
852                                                     &r->info.info3->version);
853         case 6:
854                 return clean_up_driver_struct_level(mem_ctx, session_info,
855                                                     r->info.info6->architecture,
856                                                     &r->info.info6->driver_path,
857                                                     &r->info.info6->data_file,
858                                                     &r->info.info6->config_file,
859                                                     &r->info.info6->help_file,
860                                                     r->info.info6->dependent_files,
861                                                     &r->info.info6->version);
862         default:
863                 return WERR_NOT_SUPPORTED;
864         }
865 }
866
867 /****************************************************************************
868  This function sucks and should be replaced. JRA.
869 ****************************************************************************/
870
871 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
872                                       const struct spoolss_AddDriverInfo6 *src)
873 {
874         dst->version            = src->version;
875
876         dst->driver_name        = src->driver_name;
877         dst->architecture       = src->architecture;
878         dst->driver_path        = src->driver_path;
879         dst->data_file          = src->data_file;
880         dst->config_file        = src->config_file;
881         dst->help_file          = src->help_file;
882         dst->monitor_name       = src->monitor_name;
883         dst->default_datatype   = src->default_datatype;
884         dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
885         dst->dependent_files    = src->dependent_files;
886 }
887
888 /****************************************************************************
889 ****************************************************************************/
890
891 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
892                                                 connection_struct *conn,
893                                                 const char *driver_file,
894                                                 const char *short_architecture,
895                                                 uint32_t driver_version,
896                                                 uint32_t version)
897 {
898         struct smb_filename *smb_fname_old = NULL;
899         struct smb_filename *smb_fname_new = NULL;
900         char *old_name = NULL;
901         char *new_name = NULL;
902         NTSTATUS status;
903         WERROR ret;
904
905         old_name = talloc_asprintf(mem_ctx, "%s/%s",
906                                    short_architecture, driver_file);
907         W_ERROR_HAVE_NO_MEMORY(old_name);
908
909         new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
910                                    short_architecture, driver_version, driver_file);
911         if (new_name == NULL) {
912                 TALLOC_FREE(old_name);
913                 return WERR_NOMEM;
914         }
915
916         if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
917
918                 status = driver_unix_convert(conn, old_name, &smb_fname_old);
919                 if (!NT_STATUS_IS_OK(status)) {
920                         ret = WERR_NOMEM;
921                         goto out;
922                 }
923
924                 /* Setup a synthetic smb_filename struct */
925                 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
926                 if (!smb_fname_new) {
927                         ret = WERR_NOMEM;
928                         goto out;
929                 }
930
931                 smb_fname_new->base_name = new_name;
932
933                 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
934                           "'%s'\n", smb_fname_old->base_name,
935                           smb_fname_new->base_name));
936
937                 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
938                                    OPENX_FILE_EXISTS_TRUNCATE |
939                                    OPENX_FILE_CREATE_IF_NOT_EXIST,
940                                    0, false);
941
942                 if (!NT_STATUS_IS_OK(status)) {
943                         DEBUG(0,("move_driver_file_to_download_area: Unable "
944                                  "to rename [%s] to [%s]: %s\n",
945                                  smb_fname_old->base_name, new_name,
946                                  nt_errstr(status)));
947                         ret = WERR_ACCESS_DENIED;
948                         goto out;
949                 }
950         }
951
952         ret = WERR_OK;
953  out:
954         TALLOC_FREE(smb_fname_old);
955         TALLOC_FREE(smb_fname_new);
956         return ret;
957 }
958
959 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
960                                     struct spoolss_AddDriverInfoCtr *r)
961 {
962         struct spoolss_AddDriverInfo3 *driver;
963         struct spoolss_AddDriverInfo3 converted_driver;
964         const char *short_architecture;
965         struct smb_filename *smb_dname = NULL;
966         char *new_dir = NULL;
967         connection_struct *conn = NULL;
968         NTSTATUS nt_status;
969         int i;
970         TALLOC_CTX *ctx = talloc_tos();
971         int ver = 0;
972         char *oldcwd;
973         char *printdollar = NULL;
974         int printdollar_snum;
975         WERROR err = WERR_OK;
976
977         switch (r->level) {
978         case 3:
979                 driver = r->info.info3;
980                 break;
981         case 6:
982                 convert_level_6_to_level3(&converted_driver, r->info.info6);
983                 driver = &converted_driver;
984                 break;
985         default:
986                 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
987                 return WERR_UNKNOWN_LEVEL;
988         }
989
990         short_architecture = get_short_archi(driver->architecture);
991         if (!short_architecture) {
992                 return WERR_UNKNOWN_PRINTER_DRIVER;
993         }
994
995         printdollar_snum = find_service(ctx, "print$", &printdollar);
996         if (!printdollar) {
997                 return WERR_NOMEM;
998         }
999         if (printdollar_snum == -1) {
1000                 return WERR_NO_SUCH_SHARE;
1001         }
1002
1003         nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1004                                        printdollar_snum,
1005                                        lp_pathname(printdollar_snum),
1006                                        session_info, &oldcwd);
1007         if (!NT_STATUS_IS_OK(nt_status)) {
1008                 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1009                          "returned %s\n", nt_errstr(nt_status)));
1010                 err = ntstatus_to_werror(nt_status);
1011                 return err;
1012         }
1013
1014         nt_status = set_conn_force_user_group(conn, printdollar_snum);
1015         if (!NT_STATUS_IS_OK(nt_status)) {
1016                 DEBUG(0, ("failed set force user / group\n"));
1017                 err = ntstatus_to_werror(nt_status);
1018                 goto err_free_conn;
1019         }
1020
1021         if (!become_user_by_session(conn, session_info)) {
1022                 DEBUG(0, ("failed to become user\n"));
1023                 err = WERR_ACCESS_DENIED;
1024                 goto err_free_conn;
1025         }
1026
1027         new_dir = talloc_asprintf(ctx,
1028                                 "%s/%d",
1029                                 short_architecture,
1030                                 driver->version);
1031         if (!new_dir) {
1032                 err = WERR_NOMEM;
1033                 goto err_exit;
1034         }
1035         nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1036         if (!NT_STATUS_IS_OK(nt_status)) {
1037                 err = WERR_NOMEM;
1038                 goto err_exit;
1039         }
1040
1041         DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1042
1043         nt_status = create_directory(conn, NULL, smb_dname);
1044         if (!NT_STATUS_IS_OK(nt_status)
1045          && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1046                 DEBUG(0, ("failed to create driver destination directory: %s\n",
1047                           nt_errstr(nt_status)));
1048                 err = ntstatus_to_werror(nt_status);
1049                 goto err_exit;
1050         }
1051
1052         /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1053          * listed for this driver which has already been moved, skip it (note:
1054          * drivers may list the same file name several times. Then check if the
1055          * file already exists in archi\version\, if so, check that the version
1056          * info (or time stamps if version info is unavailable) is newer (or the
1057          * date is later). If it is, move it to archi\version\filexxx.yyy.
1058          * Otherwise, delete the file.
1059          *
1060          * If a file is not moved to archi\version\ because of an error, all the
1061          * rest of the 'unmoved' driver files are removed from archi\. If one or
1062          * more of the driver's files was already moved to archi\version\, it
1063          * potentially leaves the driver in a partially updated state. Version
1064          * trauma will most likely occur if an client attempts to use any printer
1065          * bound to the driver. Perhaps a rewrite to make sure the moves can be
1066          * done is appropriate... later JRR
1067          */
1068
1069         DEBUG(5,("Moving files now !\n"));
1070
1071         if (driver->driver_path && strlen(driver->driver_path)) {
1072
1073                 err = move_driver_file_to_download_area(ctx,
1074                                                         conn,
1075                                                         driver->driver_path,
1076                                                         short_architecture,
1077                                                         driver->version,
1078                                                         ver);
1079                 if (!W_ERROR_IS_OK(err)) {
1080                         goto err_exit;
1081                 }
1082         }
1083
1084         if (driver->data_file && strlen(driver->data_file)) {
1085                 if (!strequal(driver->data_file, driver->driver_path)) {
1086
1087                         err = move_driver_file_to_download_area(ctx,
1088                                                                 conn,
1089                                                                 driver->data_file,
1090                                                                 short_architecture,
1091                                                                 driver->version,
1092                                                                 ver);
1093                         if (!W_ERROR_IS_OK(err)) {
1094                                 goto err_exit;
1095                         }
1096                 }
1097         }
1098
1099         if (driver->config_file && strlen(driver->config_file)) {
1100                 if (!strequal(driver->config_file, driver->driver_path) &&
1101                     !strequal(driver->config_file, driver->data_file)) {
1102
1103                         err = move_driver_file_to_download_area(ctx,
1104                                                                 conn,
1105                                                                 driver->config_file,
1106                                                                 short_architecture,
1107                                                                 driver->version,
1108                                                                 ver);
1109                         if (!W_ERROR_IS_OK(err)) {
1110                                 goto err_exit;
1111                         }
1112                 }
1113         }
1114
1115         if (driver->help_file && strlen(driver->help_file)) {
1116                 if (!strequal(driver->help_file, driver->driver_path) &&
1117                     !strequal(driver->help_file, driver->data_file) &&
1118                     !strequal(driver->help_file, driver->config_file)) {
1119
1120                         err = move_driver_file_to_download_area(ctx,
1121                                                                 conn,
1122                                                                 driver->help_file,
1123                                                                 short_architecture,
1124                                                                 driver->version,
1125                                                                 ver);
1126                         if (!W_ERROR_IS_OK(err)) {
1127                                 goto err_exit;
1128                         }
1129                 }
1130         }
1131
1132         if (driver->dependent_files && driver->dependent_files->string) {
1133                 for (i=0; driver->dependent_files->string[i]; i++) {
1134                         if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1135                             !strequal(driver->dependent_files->string[i], driver->data_file) &&
1136                             !strequal(driver->dependent_files->string[i], driver->config_file) &&
1137                             !strequal(driver->dependent_files->string[i], driver->help_file)) {
1138                                 int j;
1139                                 for (j=0; j < i; j++) {
1140                                         if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1141                                                 goto NextDriver;
1142                                         }
1143                                 }
1144
1145                                 err = move_driver_file_to_download_area(ctx,
1146                                                                         conn,
1147                                                                         driver->dependent_files->string[i],
1148                                                                         short_architecture,
1149                                                                         driver->version,
1150                                                                         ver);
1151                                 if (!W_ERROR_IS_OK(err)) {
1152                                         goto err_exit;
1153                                 }
1154                         }
1155                 NextDriver: ;
1156                 }
1157         }
1158
1159         err = WERR_OK;
1160  err_exit:
1161         unbecome_user();
1162  err_free_conn:
1163         TALLOC_FREE(smb_dname);
1164
1165         if (conn != NULL) {
1166                 vfs_ChDir(conn, oldcwd);
1167                 SMB_VFS_DISCONNECT(conn);
1168                 conn_free(conn);
1169         }
1170
1171         return err;
1172 }
1173
1174 /****************************************************************************
1175   Determine whether or not a particular driver is currently assigned
1176   to a printer
1177 ****************************************************************************/
1178
1179 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1180                            struct dcerpc_binding_handle *b,
1181                            const struct spoolss_DriverInfo8 *r)
1182 {
1183         int snum;
1184         int n_services = lp_numservices();
1185         bool in_use = False;
1186         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1187         WERROR result;
1188
1189         if (!r) {
1190                 return false;
1191         }
1192
1193         DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1194
1195         /* loop through the printers.tdb and check for the drivername */
1196
1197         for (snum=0; snum<n_services && !in_use; snum++) {
1198                 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1199                         continue;
1200                 }
1201
1202                 result = winreg_get_printer(mem_ctx, b,
1203                                             lp_servicename(snum),
1204                                             &pinfo2);
1205                 if (!W_ERROR_IS_OK(result)) {
1206                         continue; /* skip */
1207                 }
1208
1209                 if (strequal(r->driver_name, pinfo2->drivername)) {
1210                         in_use = True;
1211                 }
1212
1213                 TALLOC_FREE(pinfo2);
1214         }
1215
1216         DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1217
1218         if ( in_use ) {
1219                 struct spoolss_DriverInfo8 *driver;
1220                 WERROR werr;
1221
1222                 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1223
1224                 /* we can still remove the driver if there is one of
1225                    "Windows NT x86" version 2 or 3 left */
1226
1227                 if (!strequal("Windows NT x86", r->architecture)) {
1228                         werr = winreg_get_driver(mem_ctx, b,
1229                                                  "Windows NT x86",
1230                                                  r->driver_name,
1231                                                  DRIVER_ANY_VERSION,
1232                                                  &driver);
1233                 } else if (r->version == 2) {
1234                         werr = winreg_get_driver(mem_ctx, b,
1235                                                  "Windows NT x86",
1236                                                  r->driver_name,
1237                                                  3, &driver);
1238                 } else if (r->version == 3) {
1239                         werr = winreg_get_driver(mem_ctx, b,
1240                                                  "Windows NT x86",
1241                                                  r->driver_name,
1242                                                  2, &driver);
1243                 } else {
1244                         DEBUG(0, ("printer_driver_in_use: ERROR!"
1245                                   " unknown driver version (%d)\n",
1246                                   r->version));
1247                         werr = WERR_UNKNOWN_PRINTER_DRIVER;
1248                 }
1249
1250                 /* now check the error code */
1251
1252                 if ( W_ERROR_IS_OK(werr) ) {
1253                         /* it's ok to remove the driver, we have other architctures left */
1254                         in_use = False;
1255                         talloc_free(driver);
1256                 }
1257         }
1258
1259         /* report that the driver is not in use by default */
1260
1261         return in_use;
1262 }
1263
1264
1265 /**********************************************************************
1266  Check to see if a ogiven file is in use by *info
1267  *********************************************************************/
1268
1269 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1270 {
1271         int i = 0;
1272
1273         if ( !info )
1274                 return False;
1275
1276         /* mz: skip files that are in the list but already deleted */
1277         if (!file || !file[0]) {
1278                 return false;
1279         }
1280
1281         if (strequal(file, info->driver_path))
1282                 return True;
1283
1284         if (strequal(file, info->data_file))
1285                 return True;
1286
1287         if (strequal(file, info->config_file))
1288                 return True;
1289
1290         if (strequal(file, info->help_file))
1291                 return True;
1292
1293         /* see of there are any dependent files to examine */
1294
1295         if (!info->dependent_files)
1296                 return False;
1297
1298         while (info->dependent_files[i] && *info->dependent_files[i]) {
1299                 if (strequal(file, info->dependent_files[i]))
1300                         return True;
1301                 i++;
1302         }
1303
1304         return False;
1305
1306 }
1307
1308 /**********************************************************************
1309  Utility function to remove the dependent file pointed to by the
1310  input parameter from the list
1311  *********************************************************************/
1312
1313 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1314 {
1315
1316         /* bump everything down a slot */
1317
1318         while (files && files[idx+1]) {
1319                 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1320                 idx++;
1321         }
1322
1323         files[idx] = NULL;
1324
1325         return;
1326 }
1327
1328 /**********************************************************************
1329  Check if any of the files used by src are also used by drv
1330  *********************************************************************/
1331
1332 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1333                                    struct spoolss_DriverInfo8 *src,
1334                                    const struct spoolss_DriverInfo8 *drv)
1335 {
1336         bool    in_use = False;
1337         int     i = 0;
1338
1339         if ( !src || !drv )
1340                 return False;
1341
1342         /* check each file.  Remove it from the src structure if it overlaps */
1343
1344         if (drv_file_in_use(src->driver_path, drv)) {
1345                 in_use = True;
1346                 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1347                 src->driver_path = talloc_strdup(mem_ctx, "");
1348                 if (!src->driver_path) { return false; }
1349         }
1350
1351         if (drv_file_in_use(src->data_file, drv)) {
1352                 in_use = True;
1353                 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1354                 src->data_file = talloc_strdup(mem_ctx, "");
1355                 if (!src->data_file) { return false; }
1356         }
1357
1358         if (drv_file_in_use(src->config_file, drv)) {
1359                 in_use = True;
1360                 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1361                 src->config_file = talloc_strdup(mem_ctx, "");
1362                 if (!src->config_file) { return false; }
1363         }
1364
1365         if (drv_file_in_use(src->help_file, drv)) {
1366                 in_use = True;
1367                 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1368                 src->help_file = talloc_strdup(mem_ctx, "");
1369                 if (!src->help_file) { return false; }
1370         }
1371
1372         /* are there any dependentfiles to examine? */
1373
1374         if (!src->dependent_files)
1375                 return in_use;
1376
1377         while (src->dependent_files[i] && *src->dependent_files[i]) {
1378                 if (drv_file_in_use(src->dependent_files[i], drv)) {
1379                         in_use = True;
1380                         DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1381                         trim_dependent_file(mem_ctx, src->dependent_files, i);
1382                 } else
1383                         i++;
1384         }
1385
1386         return in_use;
1387 }
1388
1389 /****************************************************************************
1390   Determine whether or not a particular driver files are currently being
1391   used by any other driver.
1392
1393   Return value is True if any files were in use by other drivers
1394   and False otherwise.
1395
1396   Upon return, *info has been modified to only contain the driver files
1397   which are not in use
1398
1399   Fix from mz:
1400
1401   This needs to check all drivers to ensure that all files in use
1402   have been removed from *info, not just the ones in the first
1403   match.
1404 ****************************************************************************/
1405
1406 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1407                                  struct dcerpc_binding_handle *b,
1408                                  struct spoolss_DriverInfo8 *info)
1409 {
1410         int                             i;
1411         uint32                          version;
1412         struct spoolss_DriverInfo8      *driver;
1413         bool in_use = false;
1414         uint32_t num_drivers;
1415         const char **drivers;
1416         WERROR result;
1417
1418         if ( !info )
1419                 return False;
1420
1421         version = info->version;
1422
1423         /* loop over all driver versions */
1424
1425         DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1426
1427         /* get the list of drivers */
1428
1429         result = winreg_get_driver_list(mem_ctx, b,
1430                                         info->architecture, version,
1431                                         &num_drivers, &drivers);
1432         if (!W_ERROR_IS_OK(result)) {
1433                 return true;
1434         }
1435
1436         DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1437                      num_drivers, info->architecture, version));
1438
1439         /* check each driver for overlap in files */
1440
1441         for (i = 0; i < num_drivers; i++) {
1442                 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1443
1444                 driver = NULL;
1445
1446                 result = winreg_get_driver(mem_ctx, b,
1447                                            info->architecture, drivers[i],
1448                                            version, &driver);
1449                 if (!W_ERROR_IS_OK(result)) {
1450                         talloc_free(drivers);
1451                         return True;
1452                 }
1453
1454                 /* check if d2 uses any files from d1 */
1455                 /* only if this is a different driver than the one being deleted */
1456
1457                 if (!strequal(info->driver_name, driver->driver_name)) {
1458                         if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1459                                 /* mz: Do not instantly return -
1460                                  * we need to ensure this file isn't
1461                                  * also in use by other drivers. */
1462                                 in_use = true;
1463                         }
1464                 }
1465
1466                 talloc_free(driver);
1467         }
1468
1469         talloc_free(drivers);
1470
1471         DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1472
1473         return in_use;
1474 }
1475
1476 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1477                                         const char *short_arch,
1478                                         int vers,
1479                                         const char *fname)
1480 {
1481         TALLOC_CTX *tmp_ctx = talloc_new(conn);
1482         struct smb_filename *smb_fname = NULL;
1483         char *print_dlr_path;
1484         NTSTATUS status = NT_STATUS_NO_MEMORY;
1485
1486         print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1487                                          short_arch, vers, fname);
1488         if (print_dlr_path == NULL) {
1489                 goto err_out;
1490         }
1491
1492         status = create_synthetic_smb_fname(tmp_ctx, print_dlr_path,
1493                                             NULL, NULL, &smb_fname);
1494         if (!NT_STATUS_IS_OK(status)) {
1495                 goto err_out;
1496         }
1497
1498         status = unlink_internals(conn, NULL, 0, smb_fname, false);
1499 err_out:
1500         talloc_free(tmp_ctx);
1501         return status;
1502 }
1503
1504 /****************************************************************************
1505   Actually delete the driver files.  Make sure that
1506   printer_driver_files_in_use() return False before calling
1507   this.
1508 ****************************************************************************/
1509
1510 bool delete_driver_files(const struct auth_session_info *session_info,
1511                          const struct spoolss_DriverInfo8 *r)
1512 {
1513         const char *short_arch;
1514         connection_struct *conn;
1515         NTSTATUS nt_status;
1516         char *oldcwd;
1517         char *printdollar = NULL;
1518         int printdollar_snum;
1519         bool ret = false;
1520
1521         if (!r) {
1522                 return false;
1523         }
1524
1525         DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1526                 r->driver_name, r->version));
1527
1528         printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1529         if (!printdollar) {
1530                 return false;
1531         }
1532         if (printdollar_snum == -1) {
1533                 return false;
1534         }
1535
1536         nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1537                                        printdollar_snum,
1538                                        lp_pathname(printdollar_snum),
1539                                        session_info, &oldcwd);
1540         if (!NT_STATUS_IS_OK(nt_status)) {
1541                 DEBUG(0,("delete_driver_files: create_conn_struct "
1542                          "returned %s\n", nt_errstr(nt_status)));
1543                 return false;
1544         }
1545
1546         nt_status = set_conn_force_user_group(conn, printdollar_snum);
1547         if (!NT_STATUS_IS_OK(nt_status)) {
1548                 DEBUG(0, ("failed set force user / group\n"));
1549                 ret = false;
1550                 goto err_free_conn;
1551         }
1552
1553         if (!become_user_by_session(conn, session_info)) {
1554                 DEBUG(0, ("failed to become user\n"));
1555                 ret = false;
1556                 goto err_free_conn;
1557         }
1558
1559         if ( !CAN_WRITE(conn) ) {
1560                 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1561                 ret = false;
1562                 goto err_out;
1563         }
1564
1565         short_arch = get_short_archi(r->architecture);
1566         if (short_arch == NULL) {
1567                 DEBUG(0, ("bad architecture %s\n", r->architecture));
1568                 ret = false;
1569                 goto err_out;
1570         }
1571
1572         /* now delete the files */
1573
1574         if (r->driver_path && r->driver_path[0]) {
1575                 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1576                 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1577         }
1578
1579         if (r->config_file && r->config_file[0]) {
1580                 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1581                 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1582         }
1583
1584         if (r->data_file && r->data_file[0]) {
1585                 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1586                 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1587         }
1588
1589         if (r->help_file && r->help_file[0]) {
1590                 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1591                 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1592         }
1593
1594         if (r->dependent_files) {
1595                 int i = 0;
1596                 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1597                         DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1598                         driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1599                         i++;
1600                 }
1601         }
1602
1603         ret = true;
1604  err_out:
1605         unbecome_user();
1606  err_free_conn:
1607         if (conn != NULL) {
1608                 vfs_ChDir(conn, oldcwd);
1609                 SMB_VFS_DISCONNECT(conn);
1610                 conn_free(conn);
1611         }
1612         return ret;
1613 }
1614
1615 /* error code:
1616         0: everything OK
1617         1: level not implemented
1618         2: file doesn't exist
1619         3: can't allocate memory
1620         4: can't free memory
1621         5: non existant struct
1622 */
1623
1624 /*
1625         A printer and a printer driver are 2 different things.
1626         NT manages them separatelly, Samba does the same.
1627         Why ? Simply because it's easier and it makes sense !
1628
1629         Now explanation: You have 3 printers behind your samba server,
1630         2 of them are the same make and model (laser A and B). But laser B
1631         has an 3000 sheet feeder and laser A doesn't such an option.
1632         Your third printer is an old dot-matrix model for the accounting :-).
1633
1634         If the /usr/local/samba/lib directory (default dir), you will have
1635         5 files to describe all of this.
1636
1637         3 files for the printers (1 by printer):
1638                 NTprinter_laser A
1639                 NTprinter_laser B
1640                 NTprinter_accounting
1641         2 files for the drivers (1 for the laser and 1 for the dot matrix)
1642                 NTdriver_printer model X
1643                 NTdriver_printer model Y
1644
1645 jfm: I should use this comment for the text file to explain
1646         same thing for the forms BTW.
1647         Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1648
1649 */
1650
1651 /* Convert generic access rights to printer object specific access rights.
1652    It turns out that NT4 security descriptors use generic access rights and
1653    NT5 the object specific ones. */
1654
1655 void map_printer_permissions(struct security_descriptor *sd)
1656 {
1657         int i;
1658
1659         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1660                 se_map_generic(&sd->dacl->aces[i].access_mask,
1661                                &printer_generic_mapping);
1662         }
1663 }
1664
1665 void map_job_permissions(struct security_descriptor *sd)
1666 {
1667         int i;
1668
1669         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1670                 se_map_generic(&sd->dacl->aces[i].access_mask,
1671                                &job_generic_mapping);
1672         }
1673 }
1674
1675
1676 /****************************************************************************
1677  Check a user has permissions to perform the given operation.  We use the
1678  permission constants defined in include/rpc_spoolss.h to check the various
1679  actions we perform when checking printer access.
1680
1681    PRINTER_ACCESS_ADMINISTER:
1682        print_queue_pause, print_queue_resume, update_printer_sec,
1683        update_printer, spoolss_addprinterex_level_2,
1684        _spoolss_setprinterdata
1685
1686    PRINTER_ACCESS_USE:
1687        print_job_start
1688
1689    JOB_ACCESS_ADMINISTER:
1690        print_job_delete, print_job_pause, print_job_resume,
1691        print_queue_purge
1692
1693   Try access control in the following order (for performance reasons):
1694     1)  root and SE_PRINT_OPERATOR can do anything (easy check)
1695     2)  check security descriptor (bit comparisons in memory)
1696     3)  "printer admins" (may result in numerous calls to winbind)
1697
1698  ****************************************************************************/
1699 bool print_access_check(const struct auth_session_info *session_info,
1700                         struct messaging_context *msg_ctx, int snum,
1701                         int access_type)
1702 {
1703         struct spoolss_security_descriptor *secdesc = NULL;
1704         uint32 access_granted;
1705         size_t sd_size;
1706         NTSTATUS status;
1707         WERROR result;
1708         const char *pname;
1709         TALLOC_CTX *mem_ctx = NULL;
1710
1711         /* If user is NULL then use the current_user structure */
1712
1713         /* Always allow root or SE_PRINT_OPERATROR to do anything */
1714
1715         if (session_info->unix_token->uid == sec_initial_uid()
1716             || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1717                 return True;
1718         }
1719
1720         /* Get printer name */
1721
1722         pname = lp_printername(snum);
1723
1724         if (!pname || !*pname) {
1725                 errno = EACCES;
1726                 return False;
1727         }
1728
1729         /* Get printer security descriptor */
1730
1731         if(!(mem_ctx = talloc_init("print_access_check"))) {
1732                 errno = ENOMEM;
1733                 return False;
1734         }
1735
1736         result = winreg_get_printer_secdesc_internal(mem_ctx,
1737                                             get_session_info_system(),
1738                                             msg_ctx,
1739                                             pname,
1740                                             &secdesc);
1741         if (!W_ERROR_IS_OK(result)) {
1742                 talloc_destroy(mem_ctx);
1743                 errno = ENOMEM;
1744                 return False;
1745         }
1746
1747         if (access_type == JOB_ACCESS_ADMINISTER) {
1748                 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1749
1750                 /* Create a child security descriptor to check permissions
1751                    against.  This is because print jobs are child objects
1752                    objects of a printer. */
1753                 status = se_create_child_secdesc(mem_ctx,
1754                                                  &secdesc,
1755                                                  &sd_size,
1756                                                  parent_secdesc,
1757                                                  parent_secdesc->owner_sid,
1758                                                  parent_secdesc->group_sid,
1759                                                  false);
1760                 if (!NT_STATUS_IS_OK(status)) {
1761                         talloc_destroy(mem_ctx);
1762                         errno = map_errno_from_nt_status(status);
1763                         return False;
1764                 }
1765
1766                 map_job_permissions(secdesc);
1767         } else {
1768                 map_printer_permissions(secdesc);
1769         }
1770
1771         /* Check access */
1772         status = se_access_check(secdesc, session_info->security_token, access_type,
1773                                  &access_granted);
1774
1775         DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1776
1777         /* see if we need to try the printer admin list */
1778
1779         if (!NT_STATUS_IS_OK(status) &&
1780             (token_contains_name_in_list(uidtoname(session_info->unix_token->uid),
1781                                          session_info->info->domain_name,
1782                                          NULL, session_info->security_token,
1783                                          lp_printer_admin(snum)))) {
1784                 talloc_destroy(mem_ctx);
1785                 return True;
1786         }
1787
1788         talloc_destroy(mem_ctx);
1789
1790         if (!NT_STATUS_IS_OK(status)) {
1791                 errno = EACCES;
1792         }
1793
1794         return NT_STATUS_IS_OK(status);
1795 }
1796
1797 /****************************************************************************
1798  Check the time parameters allow a print operation.
1799 *****************************************************************************/
1800
1801 bool print_time_access_check(const struct auth_session_info *session_info,
1802                              struct messaging_context *msg_ctx,
1803                              const char *servicename)
1804 {
1805         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1806         WERROR result;
1807         bool ok = False;
1808         time_t now = time(NULL);
1809         struct tm *t;
1810         uint32 mins;
1811
1812         result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1813                                     servicename, &pinfo2);
1814         if (!W_ERROR_IS_OK(result)) {
1815                 return False;
1816         }
1817
1818         if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1819                 ok = True;
1820         }
1821
1822         t = gmtime(&now);
1823         mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1824
1825         if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1826                 ok = True;
1827         }
1828
1829         TALLOC_FREE(pinfo2);
1830
1831         if (!ok) {
1832                 errno = EACCES;
1833         }
1834
1835         return ok;
1836 }
1837
1838 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1839                         const struct auth_session_info *session_info,
1840                         struct messaging_context *msg_ctx,
1841                         const char *printer)
1842 {
1843         WERROR result;
1844
1845         result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1846                                            printer, "");
1847         if (!W_ERROR_IS_OK(result)) {
1848                 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1849                 "%s\n", printer, win_errstr(result)));
1850         }
1851 }
1852
1853 void nt_printer_add(TALLOC_CTX *mem_ctx,
1854                     const struct auth_session_info *session_info,
1855                     struct messaging_context *msg_ctx,
1856                     const char *printer)
1857 {
1858         WERROR result;
1859
1860         result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1861                                                 printer);
1862         if (!W_ERROR_IS_OK(result)) {
1863                 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1864                           printer, win_errstr(result)));
1865         }
1866 }