fc00f6ab5dafa6b97b382857682d50be218679b8
[ira/wip.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) == (SMB_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) == (SMB_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) == (SMB_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 (!NT_STATUS_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 *name)
1478 {
1479         struct smb_filename *smb_fname = NULL;
1480         NTSTATUS status;
1481
1482         status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1483             &smb_fname);
1484         if (!NT_STATUS_IS_OK(status)) {
1485                 return status;
1486         }
1487
1488         status = unlink_internals(conn, NULL, 0, smb_fname, false);
1489
1490         TALLOC_FREE(smb_fname);
1491         return status;
1492 }
1493
1494 /****************************************************************************
1495   Actually delete the driver files.  Make sure that
1496   printer_driver_files_in_use() return False before calling
1497   this.
1498 ****************************************************************************/
1499
1500 bool delete_driver_files(const struct auth_session_info *session_info,
1501                          const struct spoolss_DriverInfo8 *r)
1502 {
1503         int i = 0;
1504         char *s;
1505         const char *file;
1506         connection_struct *conn;
1507         NTSTATUS nt_status;
1508         char *oldcwd;
1509         char *printdollar = NULL;
1510         int printdollar_snum;
1511         bool ret = false;
1512
1513         if (!r) {
1514                 return false;
1515         }
1516
1517         DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1518                 r->driver_name, r->version));
1519
1520         printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1521         if (!printdollar) {
1522                 return false;
1523         }
1524         if (printdollar_snum == -1) {
1525                 return false;
1526         }
1527
1528         nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1529                                        printdollar_snum,
1530                                        lp_pathname(printdollar_snum),
1531                                        session_info, &oldcwd);
1532         if (!NT_STATUS_IS_OK(nt_status)) {
1533                 DEBUG(0,("delete_driver_files: create_conn_struct "
1534                          "returned %s\n", nt_errstr(nt_status)));
1535                 return false;
1536         }
1537
1538         nt_status = set_conn_force_user_group(conn, printdollar_snum);
1539         if (!NT_STATUS_IS_OK(nt_status)) {
1540                 DEBUG(0, ("failed set force user / group\n"));
1541                 ret = false;
1542                 goto err_free_conn;
1543         }
1544
1545         if (!become_user_by_session(conn, session_info)) {
1546                 DEBUG(0, ("failed to become user\n"));
1547                 ret = false;
1548                 goto err_free_conn;
1549         }
1550
1551         if ( !CAN_WRITE(conn) ) {
1552                 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1553                 ret = false;
1554                 goto err_out;
1555         }
1556
1557         /* now delete the files; must strip the '\print$' string from
1558            fron of path                                                */
1559
1560         if (r->driver_path && r->driver_path[0]) {
1561                 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1562                         file = s;
1563                         DEBUG(10,("deleting driverfile [%s]\n", s));
1564                         driver_unlink_internals(conn, file);
1565                 }
1566         }
1567
1568         if (r->config_file && r->config_file[0]) {
1569                 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1570                         file = s;
1571                         DEBUG(10,("deleting configfile [%s]\n", s));
1572                         driver_unlink_internals(conn, file);
1573                 }
1574         }
1575
1576         if (r->data_file && r->data_file[0]) {
1577                 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1578                         file = s;
1579                         DEBUG(10,("deleting datafile [%s]\n", s));
1580                         driver_unlink_internals(conn, file);
1581                 }
1582         }
1583
1584         if (r->help_file && r->help_file[0]) {
1585                 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1586                         file = s;
1587                         DEBUG(10,("deleting helpfile [%s]\n", s));
1588                         driver_unlink_internals(conn, file);
1589                 }
1590         }
1591
1592         /* check if we are done removing files */
1593
1594         if (r->dependent_files) {
1595                 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1596                         char *p;
1597
1598                         /* bypass the "\print$" portion of the path */
1599
1600                         if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1601                                 file = p;
1602                                 DEBUG(10,("deleting dependent file [%s]\n", file));
1603                                 driver_unlink_internals(conn, file);
1604                         }
1605
1606                         i++;
1607                 }
1608         }
1609
1610         ret = true;
1611  err_out:
1612         unbecome_user();
1613  err_free_conn:
1614         if (conn != NULL) {
1615                 vfs_ChDir(conn, oldcwd);
1616                 SMB_VFS_DISCONNECT(conn);
1617                 conn_free(conn);
1618         }
1619         return ret;
1620 }
1621
1622 /* error code:
1623         0: everything OK
1624         1: level not implemented
1625         2: file doesn't exist
1626         3: can't allocate memory
1627         4: can't free memory
1628         5: non existant struct
1629 */
1630
1631 /*
1632         A printer and a printer driver are 2 different things.
1633         NT manages them separatelly, Samba does the same.
1634         Why ? Simply because it's easier and it makes sense !
1635
1636         Now explanation: You have 3 printers behind your samba server,
1637         2 of them are the same make and model (laser A and B). But laser B
1638         has an 3000 sheet feeder and laser A doesn't such an option.
1639         Your third printer is an old dot-matrix model for the accounting :-).
1640
1641         If the /usr/local/samba/lib directory (default dir), you will have
1642         5 files to describe all of this.
1643
1644         3 files for the printers (1 by printer):
1645                 NTprinter_laser A
1646                 NTprinter_laser B
1647                 NTprinter_accounting
1648         2 files for the drivers (1 for the laser and 1 for the dot matrix)
1649                 NTdriver_printer model X
1650                 NTdriver_printer model Y
1651
1652 jfm: I should use this comment for the text file to explain
1653         same thing for the forms BTW.
1654         Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1655
1656 */
1657
1658 /* Convert generic access rights to printer object specific access rights.
1659    It turns out that NT4 security descriptors use generic access rights and
1660    NT5 the object specific ones. */
1661
1662 void map_printer_permissions(struct security_descriptor *sd)
1663 {
1664         int i;
1665
1666         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1667                 se_map_generic(&sd->dacl->aces[i].access_mask,
1668                                &printer_generic_mapping);
1669         }
1670 }
1671
1672 void map_job_permissions(struct security_descriptor *sd)
1673 {
1674         int i;
1675
1676         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1677                 se_map_generic(&sd->dacl->aces[i].access_mask,
1678                                &job_generic_mapping);
1679         }
1680 }
1681
1682
1683 /****************************************************************************
1684  Check a user has permissions to perform the given operation.  We use the
1685  permission constants defined in include/rpc_spoolss.h to check the various
1686  actions we perform when checking printer access.
1687
1688    PRINTER_ACCESS_ADMINISTER:
1689        print_queue_pause, print_queue_resume, update_printer_sec,
1690        update_printer, spoolss_addprinterex_level_2,
1691        _spoolss_setprinterdata
1692
1693    PRINTER_ACCESS_USE:
1694        print_job_start
1695
1696    JOB_ACCESS_ADMINISTER:
1697        print_job_delete, print_job_pause, print_job_resume,
1698        print_queue_purge
1699
1700   Try access control in the following order (for performance reasons):
1701     1)  root and SE_PRINT_OPERATOR can do anything (easy check)
1702     2)  check security descriptor (bit comparisons in memory)
1703     3)  "printer admins" (may result in numerous calls to winbind)
1704
1705  ****************************************************************************/
1706 bool print_access_check(const struct auth_session_info *session_info,
1707                         struct messaging_context *msg_ctx, int snum,
1708                         int access_type)
1709 {
1710         struct spoolss_security_descriptor *secdesc = NULL;
1711         uint32 access_granted;
1712         size_t sd_size;
1713         NTSTATUS status;
1714         WERROR result;
1715         const char *pname;
1716         TALLOC_CTX *mem_ctx = NULL;
1717
1718         /* If user is NULL then use the current_user structure */
1719
1720         /* Always allow root or SE_PRINT_OPERATROR to do anything */
1721
1722         if (session_info->unix_token->uid == sec_initial_uid()
1723             || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1724                 return True;
1725         }
1726
1727         /* Get printer name */
1728
1729         pname = lp_printername(snum);
1730
1731         if (!pname || !*pname) {
1732                 errno = EACCES;
1733                 return False;
1734         }
1735
1736         /* Get printer security descriptor */
1737
1738         if(!(mem_ctx = talloc_init("print_access_check"))) {
1739                 errno = ENOMEM;
1740                 return False;
1741         }
1742
1743         result = winreg_get_printer_secdesc_internal(mem_ctx,
1744                                             get_session_info_system(),
1745                                             msg_ctx,
1746                                             pname,
1747                                             &secdesc);
1748         if (!W_ERROR_IS_OK(result)) {
1749                 talloc_destroy(mem_ctx);
1750                 errno = ENOMEM;
1751                 return False;
1752         }
1753
1754         if (access_type == JOB_ACCESS_ADMINISTER) {
1755                 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1756
1757                 /* Create a child security descriptor to check permissions
1758                    against.  This is because print jobs are child objects
1759                    objects of a printer. */
1760                 status = se_create_child_secdesc(mem_ctx,
1761                                                  &secdesc,
1762                                                  &sd_size,
1763                                                  parent_secdesc,
1764                                                  parent_secdesc->owner_sid,
1765                                                  parent_secdesc->group_sid,
1766                                                  false);
1767                 if (!NT_STATUS_IS_OK(status)) {
1768                         talloc_destroy(mem_ctx);
1769                         errno = map_errno_from_nt_status(status);
1770                         return False;
1771                 }
1772
1773                 map_job_permissions(secdesc);
1774         } else {
1775                 map_printer_permissions(secdesc);
1776         }
1777
1778         /* Check access */
1779         status = se_access_check(secdesc, session_info->security_token, access_type,
1780                                  &access_granted);
1781
1782         DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1783
1784         /* see if we need to try the printer admin list */
1785
1786         if (!NT_STATUS_IS_OK(status) &&
1787             (token_contains_name_in_list(uidtoname(session_info->unix_token->uid),
1788                                          session_info->info->domain_name,
1789                                          NULL, session_info->security_token,
1790                                          lp_printer_admin(snum)))) {
1791                 talloc_destroy(mem_ctx);
1792                 return True;
1793         }
1794
1795         talloc_destroy(mem_ctx);
1796
1797         if (!NT_STATUS_IS_OK(status)) {
1798                 errno = EACCES;
1799         }
1800
1801         return NT_STATUS_IS_OK(status);
1802 }
1803
1804 /****************************************************************************
1805  Check the time parameters allow a print operation.
1806 *****************************************************************************/
1807
1808 bool print_time_access_check(const struct auth_session_info *session_info,
1809                              struct messaging_context *msg_ctx,
1810                              const char *servicename)
1811 {
1812         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1813         WERROR result;
1814         bool ok = False;
1815         time_t now = time(NULL);
1816         struct tm *t;
1817         uint32 mins;
1818
1819         result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1820                                     servicename, &pinfo2);
1821         if (!W_ERROR_IS_OK(result)) {
1822                 return False;
1823         }
1824
1825         if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1826                 ok = True;
1827         }
1828
1829         t = gmtime(&now);
1830         mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1831
1832         if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1833                 ok = True;
1834         }
1835
1836         TALLOC_FREE(pinfo2);
1837
1838         if (!ok) {
1839                 errno = EACCES;
1840         }
1841
1842         return ok;
1843 }
1844
1845 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1846                         const struct auth_session_info *session_info,
1847                         struct messaging_context *msg_ctx,
1848                         const char *printer)
1849 {
1850         WERROR result;
1851
1852         result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1853                                            printer, "");
1854         if (!W_ERROR_IS_OK(result)) {
1855                 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
1856                           printer));
1857         }
1858 }