smbd: Split create_conn_struct into a fn that does not change the working dir
[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_cwd(talloc_tos(),
620                                        server_event_context(),
621                                        server_messaging_context(),
622                                        &conn,
623                                        printdollar_snum,
624                                        lp_pathname(talloc_tos(), printdollar_snum),
625                                        session_info, &oldcwd);
626         if (!NT_STATUS_IS_OK(nt_status)) {
627                 DEBUG(0,("get_correct_cversion: create_conn_struct "
628                          "returned %s\n", nt_errstr(nt_status)));
629                 *perr = ntstatus_to_werror(nt_status);
630                 return -1;
631         }
632
633         nt_status = set_conn_force_user_group(conn, printdollar_snum);
634         if (!NT_STATUS_IS_OK(nt_status)) {
635                 DEBUG(0, ("failed set force user / group\n"));
636                 *perr = ntstatus_to_werror(nt_status);
637                 goto error_free_conn;
638         }
639
640         if (!become_user_by_session(conn, session_info)) {
641                 DEBUG(0, ("failed to become user\n"));
642                 *perr = WERR_ACCESS_DENIED;
643                 goto error_free_conn;
644         }
645
646         /* Open the driver file (Portable Executable format) and determine the
647          * deriver the cversion. */
648         driverpath = talloc_asprintf(talloc_tos(),
649                                         "%s/%s",
650                                         architecture,
651                                         driverpath_in);
652         if (!driverpath) {
653                 *perr = WERR_NOMEM;
654                 goto error_exit;
655         }
656
657         nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
658         if (!NT_STATUS_IS_OK(nt_status)) {
659                 *perr = ntstatus_to_werror(nt_status);
660                 goto error_exit;
661         }
662
663         nt_status = vfs_file_exist(conn, smb_fname);
664         if (!NT_STATUS_IS_OK(nt_status)) {
665                 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
666                 *perr = WERR_BADFILE;
667                 goto error_exit;
668         }
669
670         nt_status = SMB_VFS_CREATE_FILE(
671                 conn,                                   /* conn */
672                 NULL,                                   /* req */
673                 0,                                      /* root_dir_fid */
674                 smb_fname,                              /* fname */
675                 FILE_GENERIC_READ,                      /* access_mask */
676                 FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
677                 FILE_OPEN,                              /* create_disposition*/
678                 0,                                      /* create_options */
679                 FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
680                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
681                 0,                                      /* private_flags */
682                 0,                                      /* allocation_size */
683                 NULL,                                   /* sd */
684                 NULL,                                   /* ea_list */
685                 &fsp,                                   /* result */
686                 NULL);                                  /* pinfo */
687
688         if (!NT_STATUS_IS_OK(nt_status)) {
689                 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
690                          "%d\n", smb_fname_str_dbg(smb_fname), errno));
691                 *perr = WERR_ACCESS_DENIED;
692                 goto error_exit;
693         } else {
694                 uint32 major;
695                 uint32 minor;
696                 int    ret;
697
698                 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
699                 if (ret == -1) {
700                         *perr = WERR_INVALID_PARAM;
701                         goto error_exit;
702                 } else if (!ret) {
703                         DEBUG(6,("get_correct_cversion: Version info not "
704                                  "found [%s]\n",
705                                  smb_fname_str_dbg(smb_fname)));
706                         *perr = WERR_INVALID_PARAM;
707                         goto error_exit;
708                 }
709
710                 /*
711                  * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
712                  * for more details. Version in this case is not just the version of the
713                  * file, but the version in the sense of kernal mode (2) vs. user mode
714                  * (3) drivers. Other bits of the version fields are the version info.
715                  * JRR 010716
716                 */
717                 cversion = major & 0x0000ffff;
718                 switch (cversion) {
719                         case 2: /* WinNT drivers */
720                         case 3: /* Win2K drivers */
721                                 break;
722
723                         default:
724                                 DEBUG(6,("get_correct_cversion: cversion "
725                                          "invalid [%s]  cversion = %d\n",
726                                          smb_fname_str_dbg(smb_fname),
727                                          cversion));
728                                 goto error_exit;
729                 }
730
731                 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
732                           " = 0x%x  minor = 0x%x\n",
733                           smb_fname_str_dbg(smb_fname), major, minor));
734         }
735
736         DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
737                   smb_fname_str_dbg(smb_fname), cversion));
738         *perr = WERR_OK;
739
740  error_exit:
741         unbecome_user();
742  error_free_conn:
743         TALLOC_FREE(smb_fname);
744         if (fsp != NULL) {
745                 close_file(NULL, fsp, NORMAL_CLOSE);
746         }
747         if (conn != NULL) {
748                 vfs_ChDir(conn, oldcwd);
749                 SMB_VFS_DISCONNECT(conn);
750                 conn_free(conn);
751         }
752         if (!W_ERROR_IS_OK(*perr)) {
753                 cversion = -1;
754         }
755
756         return cversion;
757 }
758
759 /****************************************************************************
760 ****************************************************************************/
761
762 #define strip_driver_path(_mem_ctx, _element) do { \
763         if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
764                 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
765                 W_ERROR_HAVE_NO_MEMORY((_element)); \
766         } \
767 } while (0);
768
769 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
770                                            struct auth_session_info *session_info,
771                                            const char *architecture,
772                                            const char **driver_path,
773                                            const char **data_file,
774                                            const char **config_file,
775                                            const char **help_file,
776                                            struct spoolss_StringArray *dependent_files,
777                                            enum spoolss_DriverOSVersion *version)
778 {
779         const char *short_architecture;
780         int i;
781         WERROR err;
782         char *_p;
783
784         if (!*driver_path || !*data_file) {
785                 return WERR_INVALID_PARAM;
786         }
787
788         if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
789                 return WERR_INVALID_PARAM;
790         }
791
792         /* clean up the driver name.
793          * we can get .\driver.dll
794          * or worse c:\windows\system\driver.dll !
795          */
796         /* using an intermediate string to not have overlaping memcpy()'s */
797
798         strip_driver_path(mem_ctx, *driver_path);
799         strip_driver_path(mem_ctx, *data_file);
800         if (*config_file) {
801                 strip_driver_path(mem_ctx, *config_file);
802         }
803         if (help_file) {
804                 strip_driver_path(mem_ctx, *help_file);
805         }
806
807         if (dependent_files && dependent_files->string) {
808                 for (i=0; dependent_files->string[i]; i++) {
809                         strip_driver_path(mem_ctx, dependent_files->string[i]);
810                 }
811         }
812
813         short_architecture = get_short_archi(architecture);
814         if (!short_architecture) {
815                 return WERR_UNKNOWN_PRINTER_DRIVER;
816         }
817
818         /* jfm:7/16/2000 the client always sends the cversion=0.
819          * The server should check which version the driver is by reading
820          * the PE header of driver->driverpath.
821          *
822          * For Windows 95/98 the version is 0 (so the value sent is correct)
823          * For Windows NT (the architecture doesn't matter)
824          *      NT 3.1: cversion=0
825          *      NT 3.5/3.51: cversion=1
826          *      NT 4: cversion=2
827          *      NT2K: cversion=3
828          */
829
830         *version = get_correct_cversion(session_info, short_architecture,
831                                         *driver_path, &err);
832         if (*version == -1) {
833                 return err;
834         }
835
836         return WERR_OK;
837 }
838
839 /****************************************************************************
840 ****************************************************************************/
841
842 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
843                               struct auth_session_info *session_info,
844                               struct spoolss_AddDriverInfoCtr *r)
845 {
846         switch (r->level) {
847         case 3:
848                 return clean_up_driver_struct_level(mem_ctx, session_info,
849                                                     r->info.info3->architecture,
850                                                     &r->info.info3->driver_path,
851                                                     &r->info.info3->data_file,
852                                                     &r->info.info3->config_file,
853                                                     &r->info.info3->help_file,
854                                                     r->info.info3->dependent_files,
855                                                     &r->info.info3->version);
856         case 6:
857                 return clean_up_driver_struct_level(mem_ctx, session_info,
858                                                     r->info.info6->architecture,
859                                                     &r->info.info6->driver_path,
860                                                     &r->info.info6->data_file,
861                                                     &r->info.info6->config_file,
862                                                     &r->info.info6->help_file,
863                                                     r->info.info6->dependent_files,
864                                                     &r->info.info6->version);
865         default:
866                 return WERR_NOT_SUPPORTED;
867         }
868 }
869
870 /****************************************************************************
871  This function sucks and should be replaced. JRA.
872 ****************************************************************************/
873
874 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
875                                       const struct spoolss_AddDriverInfo6 *src)
876 {
877         dst->version            = src->version;
878
879         dst->driver_name        = src->driver_name;
880         dst->architecture       = src->architecture;
881         dst->driver_path        = src->driver_path;
882         dst->data_file          = src->data_file;
883         dst->config_file        = src->config_file;
884         dst->help_file          = src->help_file;
885         dst->monitor_name       = src->monitor_name;
886         dst->default_datatype   = src->default_datatype;
887         dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
888         dst->dependent_files    = src->dependent_files;
889 }
890
891 /****************************************************************************
892 ****************************************************************************/
893
894 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
895                                                 connection_struct *conn,
896                                                 const char *driver_file,
897                                                 const char *short_architecture,
898                                                 uint32_t driver_version,
899                                                 uint32_t version)
900 {
901         struct smb_filename *smb_fname_old = NULL;
902         struct smb_filename *smb_fname_new = NULL;
903         char *old_name = NULL;
904         char *new_name = NULL;
905         NTSTATUS status;
906         WERROR ret;
907
908         old_name = talloc_asprintf(mem_ctx, "%s/%s",
909                                    short_architecture, driver_file);
910         W_ERROR_HAVE_NO_MEMORY(old_name);
911
912         new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
913                                    short_architecture, driver_version, driver_file);
914         if (new_name == NULL) {
915                 TALLOC_FREE(old_name);
916                 return WERR_NOMEM;
917         }
918
919         if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
920
921                 status = driver_unix_convert(conn, old_name, &smb_fname_old);
922                 if (!NT_STATUS_IS_OK(status)) {
923                         ret = WERR_NOMEM;
924                         goto out;
925                 }
926
927                 /* Setup a synthetic smb_filename struct */
928                 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
929                 if (!smb_fname_new) {
930                         ret = WERR_NOMEM;
931                         goto out;
932                 }
933
934                 smb_fname_new->base_name = new_name;
935
936                 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
937                           "'%s'\n", smb_fname_old->base_name,
938                           smb_fname_new->base_name));
939
940                 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
941                                    OPENX_FILE_EXISTS_TRUNCATE |
942                                    OPENX_FILE_CREATE_IF_NOT_EXIST,
943                                    0, false);
944
945                 if (!NT_STATUS_IS_OK(status)) {
946                         DEBUG(0,("move_driver_file_to_download_area: Unable "
947                                  "to rename [%s] to [%s]: %s\n",
948                                  smb_fname_old->base_name, new_name,
949                                  nt_errstr(status)));
950                         ret = WERR_ACCESS_DENIED;
951                         goto out;
952                 }
953         }
954
955         ret = WERR_OK;
956  out:
957         TALLOC_FREE(smb_fname_old);
958         TALLOC_FREE(smb_fname_new);
959         return ret;
960 }
961
962 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
963                                     struct spoolss_AddDriverInfoCtr *r)
964 {
965         struct spoolss_AddDriverInfo3 *driver;
966         struct spoolss_AddDriverInfo3 converted_driver;
967         const char *short_architecture;
968         struct smb_filename *smb_dname = NULL;
969         char *new_dir = NULL;
970         connection_struct *conn = NULL;
971         NTSTATUS nt_status;
972         int i;
973         TALLOC_CTX *ctx = talloc_tos();
974         int ver = 0;
975         char *oldcwd;
976         char *printdollar = NULL;
977         int printdollar_snum;
978         WERROR err = WERR_OK;
979
980         switch (r->level) {
981         case 3:
982                 driver = r->info.info3;
983                 break;
984         case 6:
985                 convert_level_6_to_level3(&converted_driver, r->info.info6);
986                 driver = &converted_driver;
987                 break;
988         default:
989                 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
990                 return WERR_UNKNOWN_LEVEL;
991         }
992
993         short_architecture = get_short_archi(driver->architecture);
994         if (!short_architecture) {
995                 return WERR_UNKNOWN_PRINTER_DRIVER;
996         }
997
998         printdollar_snum = find_service(ctx, "print$", &printdollar);
999         if (!printdollar) {
1000                 return WERR_NOMEM;
1001         }
1002         if (printdollar_snum == -1) {
1003                 return WERR_NO_SUCH_SHARE;
1004         }
1005
1006         nt_status = create_conn_struct_cwd(talloc_tos(),
1007                                        server_event_context(),
1008                                        server_messaging_context(),
1009                                        &conn,
1010                                        printdollar_snum,
1011                                        lp_pathname(talloc_tos(), printdollar_snum),
1012                                        session_info, &oldcwd);
1013         if (!NT_STATUS_IS_OK(nt_status)) {
1014                 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1015                          "returned %s\n", nt_errstr(nt_status)));
1016                 err = ntstatus_to_werror(nt_status);
1017                 return err;
1018         }
1019
1020         nt_status = set_conn_force_user_group(conn, printdollar_snum);
1021         if (!NT_STATUS_IS_OK(nt_status)) {
1022                 DEBUG(0, ("failed set force user / group\n"));
1023                 err = ntstatus_to_werror(nt_status);
1024                 goto err_free_conn;
1025         }
1026
1027         if (!become_user_by_session(conn, session_info)) {
1028                 DEBUG(0, ("failed to become user\n"));
1029                 err = WERR_ACCESS_DENIED;
1030                 goto err_free_conn;
1031         }
1032
1033         new_dir = talloc_asprintf(ctx,
1034                                 "%s/%d",
1035                                 short_architecture,
1036                                 driver->version);
1037         if (!new_dir) {
1038                 err = WERR_NOMEM;
1039                 goto err_exit;
1040         }
1041         nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1042         if (!NT_STATUS_IS_OK(nt_status)) {
1043                 err = WERR_NOMEM;
1044                 goto err_exit;
1045         }
1046
1047         DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1048
1049         nt_status = create_directory(conn, NULL, smb_dname);
1050         if (!NT_STATUS_IS_OK(nt_status)
1051          && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1052                 DEBUG(0, ("failed to create driver destination directory: %s\n",
1053                           nt_errstr(nt_status)));
1054                 err = ntstatus_to_werror(nt_status);
1055                 goto err_exit;
1056         }
1057
1058         /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1059          * listed for this driver which has already been moved, skip it (note:
1060          * drivers may list the same file name several times. Then check if the
1061          * file already exists in archi\version\, if so, check that the version
1062          * info (or time stamps if version info is unavailable) is newer (or the
1063          * date is later). If it is, move it to archi\version\filexxx.yyy.
1064          * Otherwise, delete the file.
1065          *
1066          * If a file is not moved to archi\version\ because of an error, all the
1067          * rest of the 'unmoved' driver files are removed from archi\. If one or
1068          * more of the driver's files was already moved to archi\version\, it
1069          * potentially leaves the driver in a partially updated state. Version
1070          * trauma will most likely occur if an client attempts to use any printer
1071          * bound to the driver. Perhaps a rewrite to make sure the moves can be
1072          * done is appropriate... later JRR
1073          */
1074
1075         DEBUG(5,("Moving files now !\n"));
1076
1077         if (driver->driver_path && strlen(driver->driver_path)) {
1078
1079                 err = move_driver_file_to_download_area(ctx,
1080                                                         conn,
1081                                                         driver->driver_path,
1082                                                         short_architecture,
1083                                                         driver->version,
1084                                                         ver);
1085                 if (!W_ERROR_IS_OK(err)) {
1086                         goto err_exit;
1087                 }
1088         }
1089
1090         if (driver->data_file && strlen(driver->data_file)) {
1091                 if (!strequal(driver->data_file, driver->driver_path)) {
1092
1093                         err = move_driver_file_to_download_area(ctx,
1094                                                                 conn,
1095                                                                 driver->data_file,
1096                                                                 short_architecture,
1097                                                                 driver->version,
1098                                                                 ver);
1099                         if (!W_ERROR_IS_OK(err)) {
1100                                 goto err_exit;
1101                         }
1102                 }
1103         }
1104
1105         if (driver->config_file && strlen(driver->config_file)) {
1106                 if (!strequal(driver->config_file, driver->driver_path) &&
1107                     !strequal(driver->config_file, driver->data_file)) {
1108
1109                         err = move_driver_file_to_download_area(ctx,
1110                                                                 conn,
1111                                                                 driver->config_file,
1112                                                                 short_architecture,
1113                                                                 driver->version,
1114                                                                 ver);
1115                         if (!W_ERROR_IS_OK(err)) {
1116                                 goto err_exit;
1117                         }
1118                 }
1119         }
1120
1121         if (driver->help_file && strlen(driver->help_file)) {
1122                 if (!strequal(driver->help_file, driver->driver_path) &&
1123                     !strequal(driver->help_file, driver->data_file) &&
1124                     !strequal(driver->help_file, driver->config_file)) {
1125
1126                         err = move_driver_file_to_download_area(ctx,
1127                                                                 conn,
1128                                                                 driver->help_file,
1129                                                                 short_architecture,
1130                                                                 driver->version,
1131                                                                 ver);
1132                         if (!W_ERROR_IS_OK(err)) {
1133                                 goto err_exit;
1134                         }
1135                 }
1136         }
1137
1138         if (driver->dependent_files && driver->dependent_files->string) {
1139                 for (i=0; driver->dependent_files->string[i]; i++) {
1140                         if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1141                             !strequal(driver->dependent_files->string[i], driver->data_file) &&
1142                             !strequal(driver->dependent_files->string[i], driver->config_file) &&
1143                             !strequal(driver->dependent_files->string[i], driver->help_file)) {
1144                                 int j;
1145                                 for (j=0; j < i; j++) {
1146                                         if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1147                                                 goto NextDriver;
1148                                         }
1149                                 }
1150
1151                                 err = move_driver_file_to_download_area(ctx,
1152                                                                         conn,
1153                                                                         driver->dependent_files->string[i],
1154                                                                         short_architecture,
1155                                                                         driver->version,
1156                                                                         ver);
1157                                 if (!W_ERROR_IS_OK(err)) {
1158                                         goto err_exit;
1159                                 }
1160                         }
1161                 NextDriver: ;
1162                 }
1163         }
1164
1165         err = WERR_OK;
1166  err_exit:
1167         unbecome_user();
1168  err_free_conn:
1169         TALLOC_FREE(smb_dname);
1170
1171         if (conn != NULL) {
1172                 vfs_ChDir(conn, oldcwd);
1173                 SMB_VFS_DISCONNECT(conn);
1174                 conn_free(conn);
1175         }
1176
1177         return err;
1178 }
1179
1180 /****************************************************************************
1181   Determine whether or not a particular driver is currently assigned
1182   to a printer
1183 ****************************************************************************/
1184
1185 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1186                            struct dcerpc_binding_handle *b,
1187                            const struct spoolss_DriverInfo8 *r)
1188 {
1189         int snum;
1190         int n_services = lp_numservices();
1191         bool in_use = False;
1192         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1193         WERROR result;
1194
1195         if (!r) {
1196                 return false;
1197         }
1198
1199         DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1200
1201         /* loop through the printers.tdb and check for the drivername */
1202
1203         for (snum=0; snum<n_services && !in_use; snum++) {
1204                 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1205                         continue;
1206                 }
1207
1208                 result = winreg_get_printer(mem_ctx, b,
1209                                             lp_servicename(talloc_tos(), snum),
1210                                             &pinfo2);
1211                 if (!W_ERROR_IS_OK(result)) {
1212                         continue; /* skip */
1213                 }
1214
1215                 if (strequal(r->driver_name, pinfo2->drivername)) {
1216                         in_use = True;
1217                 }
1218
1219                 TALLOC_FREE(pinfo2);
1220         }
1221
1222         DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1223
1224         if ( in_use ) {
1225                 struct spoolss_DriverInfo8 *driver = NULL;
1226                 WERROR werr;
1227
1228                 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1229
1230                 /* we can still remove the driver if there is one of
1231                    "Windows NT x86" version 2 or 3 left */
1232
1233                 if (!strequal("Windows NT x86", r->architecture)) {
1234                         werr = winreg_get_driver(mem_ctx, b,
1235                                                  "Windows NT x86",
1236                                                  r->driver_name,
1237                                                  DRIVER_ANY_VERSION,
1238                                                  &driver);
1239                 } else if (r->version == 2) {
1240                         werr = winreg_get_driver(mem_ctx, b,
1241                                                  "Windows NT x86",
1242                                                  r->driver_name,
1243                                                  3, &driver);
1244                 } else if (r->version == 3) {
1245                         werr = winreg_get_driver(mem_ctx, b,
1246                                                  "Windows NT x86",
1247                                                  r->driver_name,
1248                                                  2, &driver);
1249                 } else {
1250                         DEBUG(0, ("printer_driver_in_use: ERROR!"
1251                                   " unknown driver version (%d)\n",
1252                                   r->version));
1253                         werr = WERR_UNKNOWN_PRINTER_DRIVER;
1254                 }
1255
1256                 /* now check the error code */
1257
1258                 if ( W_ERROR_IS_OK(werr) ) {
1259                         /* it's ok to remove the driver, we have other architctures left */
1260                         in_use = False;
1261                         talloc_free(driver);
1262                 }
1263         }
1264
1265         /* report that the driver is not in use by default */
1266
1267         return in_use;
1268 }
1269
1270
1271 /**********************************************************************
1272  Check to see if a ogiven file is in use by *info
1273  *********************************************************************/
1274
1275 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1276 {
1277         int i = 0;
1278
1279         if ( !info )
1280                 return False;
1281
1282         /* mz: skip files that are in the list but already deleted */
1283         if (!file || !file[0]) {
1284                 return false;
1285         }
1286
1287         if (strequal(file, info->driver_path))
1288                 return True;
1289
1290         if (strequal(file, info->data_file))
1291                 return True;
1292
1293         if (strequal(file, info->config_file))
1294                 return True;
1295
1296         if (strequal(file, info->help_file))
1297                 return True;
1298
1299         /* see of there are any dependent files to examine */
1300
1301         if (!info->dependent_files)
1302                 return False;
1303
1304         while (info->dependent_files[i] && *info->dependent_files[i]) {
1305                 if (strequal(file, info->dependent_files[i]))
1306                         return True;
1307                 i++;
1308         }
1309
1310         return False;
1311
1312 }
1313
1314 /**********************************************************************
1315  Utility function to remove the dependent file pointed to by the
1316  input parameter from the list
1317  *********************************************************************/
1318
1319 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1320 {
1321
1322         /* bump everything down a slot */
1323
1324         while (files && files[idx+1]) {
1325                 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1326                 idx++;
1327         }
1328
1329         files[idx] = NULL;
1330
1331         return;
1332 }
1333
1334 /**********************************************************************
1335  Check if any of the files used by src are also used by drv
1336  *********************************************************************/
1337
1338 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1339                                    struct spoolss_DriverInfo8 *src,
1340                                    const struct spoolss_DriverInfo8 *drv)
1341 {
1342         bool    in_use = False;
1343         int     i = 0;
1344
1345         if ( !src || !drv )
1346                 return False;
1347
1348         /* check each file.  Remove it from the src structure if it overlaps */
1349
1350         if (drv_file_in_use(src->driver_path, drv)) {
1351                 in_use = True;
1352                 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1353                 src->driver_path = talloc_strdup(mem_ctx, "");
1354                 if (!src->driver_path) { return false; }
1355         }
1356
1357         if (drv_file_in_use(src->data_file, drv)) {
1358                 in_use = True;
1359                 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1360                 src->data_file = talloc_strdup(mem_ctx, "");
1361                 if (!src->data_file) { return false; }
1362         }
1363
1364         if (drv_file_in_use(src->config_file, drv)) {
1365                 in_use = True;
1366                 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1367                 src->config_file = talloc_strdup(mem_ctx, "");
1368                 if (!src->config_file) { return false; }
1369         }
1370
1371         if (drv_file_in_use(src->help_file, drv)) {
1372                 in_use = True;
1373                 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1374                 src->help_file = talloc_strdup(mem_ctx, "");
1375                 if (!src->help_file) { return false; }
1376         }
1377
1378         /* are there any dependentfiles to examine? */
1379
1380         if (!src->dependent_files)
1381                 return in_use;
1382
1383         while (src->dependent_files[i] && *src->dependent_files[i]) {
1384                 if (drv_file_in_use(src->dependent_files[i], drv)) {
1385                         in_use = True;
1386                         DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1387                         trim_dependent_file(mem_ctx, src->dependent_files, i);
1388                 } else
1389                         i++;
1390         }
1391
1392         return in_use;
1393 }
1394
1395 /****************************************************************************
1396   Determine whether or not a particular driver files are currently being
1397   used by any other driver.
1398
1399   Return value is True if any files were in use by other drivers
1400   and False otherwise.
1401
1402   Upon return, *info has been modified to only contain the driver files
1403   which are not in use
1404
1405   Fix from mz:
1406
1407   This needs to check all drivers to ensure that all files in use
1408   have been removed from *info, not just the ones in the first
1409   match.
1410 ****************************************************************************/
1411
1412 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1413                                  struct dcerpc_binding_handle *b,
1414                                  struct spoolss_DriverInfo8 *info)
1415 {
1416         int                             i;
1417         uint32                          version;
1418         struct spoolss_DriverInfo8      *driver;
1419         bool in_use = false;
1420         uint32_t num_drivers;
1421         const char **drivers;
1422         WERROR result;
1423
1424         if ( !info )
1425                 return False;
1426
1427         version = info->version;
1428
1429         /* loop over all driver versions */
1430
1431         DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1432
1433         /* get the list of drivers */
1434
1435         result = winreg_get_driver_list(mem_ctx, b,
1436                                         info->architecture, version,
1437                                         &num_drivers, &drivers);
1438         if (!W_ERROR_IS_OK(result)) {
1439                 return true;
1440         }
1441
1442         DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1443                      num_drivers, info->architecture, version));
1444
1445         /* check each driver for overlap in files */
1446
1447         for (i = 0; i < num_drivers; i++) {
1448                 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1449
1450                 driver = NULL;
1451
1452                 result = winreg_get_driver(mem_ctx, b,
1453                                            info->architecture, drivers[i],
1454                                            version, &driver);
1455                 if (!W_ERROR_IS_OK(result)) {
1456                         talloc_free(drivers);
1457                         return True;
1458                 }
1459
1460                 /* check if d2 uses any files from d1 */
1461                 /* only if this is a different driver than the one being deleted */
1462
1463                 if (!strequal(info->driver_name, driver->driver_name)) {
1464                         if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1465                                 /* mz: Do not instantly return -
1466                                  * we need to ensure this file isn't
1467                                  * also in use by other drivers. */
1468                                 in_use = true;
1469                         }
1470                 }
1471
1472                 talloc_free(driver);
1473         }
1474
1475         talloc_free(drivers);
1476
1477         DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1478
1479         return in_use;
1480 }
1481
1482 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1483                                         const char *short_arch,
1484                                         int vers,
1485                                         const char *fname)
1486 {
1487         TALLOC_CTX *tmp_ctx = talloc_new(conn);
1488         struct smb_filename *smb_fname = NULL;
1489         char *print_dlr_path;
1490         NTSTATUS status = NT_STATUS_NO_MEMORY;
1491
1492         print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1493                                          short_arch, vers, fname);
1494         if (print_dlr_path == NULL) {
1495                 goto err_out;
1496         }
1497
1498         status = create_synthetic_smb_fname(tmp_ctx, print_dlr_path,
1499                                             NULL, NULL, &smb_fname);
1500         if (!NT_STATUS_IS_OK(status)) {
1501                 goto err_out;
1502         }
1503
1504         status = unlink_internals(conn, NULL, 0, smb_fname, false);
1505 err_out:
1506         talloc_free(tmp_ctx);
1507         return status;
1508 }
1509
1510 /****************************************************************************
1511   Actually delete the driver files.  Make sure that
1512   printer_driver_files_in_use() return False before calling
1513   this.
1514 ****************************************************************************/
1515
1516 bool delete_driver_files(const struct auth_session_info *session_info,
1517                          const struct spoolss_DriverInfo8 *r)
1518 {
1519         const char *short_arch;
1520         connection_struct *conn;
1521         NTSTATUS nt_status;
1522         char *oldcwd;
1523         char *printdollar = NULL;
1524         int printdollar_snum;
1525         bool ret = false;
1526
1527         if (!r) {
1528                 return false;
1529         }
1530
1531         DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1532                 r->driver_name, r->version));
1533
1534         printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1535         if (!printdollar) {
1536                 return false;
1537         }
1538         if (printdollar_snum == -1) {
1539                 return false;
1540         }
1541
1542         nt_status = create_conn_struct_cwd(talloc_tos(),
1543                                        server_event_context(),
1544                                        server_messaging_context(),
1545                                        &conn,
1546                                        printdollar_snum,
1547                                        lp_pathname(talloc_tos(), printdollar_snum),
1548                                        session_info, &oldcwd);
1549         if (!NT_STATUS_IS_OK(nt_status)) {
1550                 DEBUG(0,("delete_driver_files: create_conn_struct "
1551                          "returned %s\n", nt_errstr(nt_status)));
1552                 return false;
1553         }
1554
1555         nt_status = set_conn_force_user_group(conn, printdollar_snum);
1556         if (!NT_STATUS_IS_OK(nt_status)) {
1557                 DEBUG(0, ("failed set force user / group\n"));
1558                 ret = false;
1559                 goto err_free_conn;
1560         }
1561
1562         if (!become_user_by_session(conn, session_info)) {
1563                 DEBUG(0, ("failed to become user\n"));
1564                 ret = false;
1565                 goto err_free_conn;
1566         }
1567
1568         if ( !CAN_WRITE(conn) ) {
1569                 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1570                 ret = false;
1571                 goto err_out;
1572         }
1573
1574         short_arch = get_short_archi(r->architecture);
1575         if (short_arch == NULL) {
1576                 DEBUG(0, ("bad architecture %s\n", r->architecture));
1577                 ret = false;
1578                 goto err_out;
1579         }
1580
1581         /* now delete the files */
1582
1583         if (r->driver_path && r->driver_path[0]) {
1584                 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1585                 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1586         }
1587
1588         if (r->config_file && r->config_file[0]) {
1589                 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1590                 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1591         }
1592
1593         if (r->data_file && r->data_file[0]) {
1594                 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1595                 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1596         }
1597
1598         if (r->help_file && r->help_file[0]) {
1599                 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1600                 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1601         }
1602
1603         if (r->dependent_files) {
1604                 int i = 0;
1605                 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1606                         DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1607                         driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1608                         i++;
1609                 }
1610         }
1611
1612         ret = true;
1613  err_out:
1614         unbecome_user();
1615  err_free_conn:
1616         if (conn != NULL) {
1617                 vfs_ChDir(conn, oldcwd);
1618                 SMB_VFS_DISCONNECT(conn);
1619                 conn_free(conn);
1620         }
1621         return ret;
1622 }
1623
1624 /* error code:
1625         0: everything OK
1626         1: level not implemented
1627         2: file doesn't exist
1628         3: can't allocate memory
1629         4: can't free memory
1630         5: non existent struct
1631 */
1632
1633 /*
1634         A printer and a printer driver are 2 different things.
1635         NT manages them separatelly, Samba does the same.
1636         Why ? Simply because it's easier and it makes sense !
1637
1638         Now explanation: You have 3 printers behind your samba server,
1639         2 of them are the same make and model (laser A and B). But laser B
1640         has an 3000 sheet feeder and laser A doesn't such an option.
1641         Your third printer is an old dot-matrix model for the accounting :-).
1642
1643         If the /usr/local/samba/lib directory (default dir), you will have
1644         5 files to describe all of this.
1645
1646         3 files for the printers (1 by printer):
1647                 NTprinter_laser A
1648                 NTprinter_laser B
1649                 NTprinter_accounting
1650         2 files for the drivers (1 for the laser and 1 for the dot matrix)
1651                 NTdriver_printer model X
1652                 NTdriver_printer model Y
1653
1654 jfm: I should use this comment for the text file to explain
1655         same thing for the forms BTW.
1656         Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1657
1658 */
1659
1660 /* Convert generic access rights to printer object specific access rights.
1661    It turns out that NT4 security descriptors use generic access rights and
1662    NT5 the object specific ones. */
1663
1664 void map_printer_permissions(struct security_descriptor *sd)
1665 {
1666         int i;
1667
1668         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1669                 se_map_generic(&sd->dacl->aces[i].access_mask,
1670                                &printer_generic_mapping);
1671         }
1672 }
1673
1674 void map_job_permissions(struct security_descriptor *sd)
1675 {
1676         int i;
1677
1678         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1679                 se_map_generic(&sd->dacl->aces[i].access_mask,
1680                                &job_generic_mapping);
1681         }
1682 }
1683
1684
1685 /****************************************************************************
1686  Check a user has permissions to perform the given operation.  We use the
1687  permission constants defined in include/rpc_spoolss.h to check the various
1688  actions we perform when checking printer access.
1689
1690    PRINTER_ACCESS_ADMINISTER:
1691        print_queue_pause, print_queue_resume, update_printer_sec,
1692        update_printer, spoolss_addprinterex_level_2,
1693        _spoolss_setprinterdata
1694
1695    PRINTER_ACCESS_USE:
1696        print_job_start
1697
1698    JOB_ACCESS_ADMINISTER:
1699        print_job_delete, print_job_pause, print_job_resume,
1700        print_queue_purge
1701
1702   Try access control in the following order (for performance reasons):
1703     1)  root and SE_PRINT_OPERATOR can do anything (easy check)
1704     2)  check security descriptor (bit comparisons in memory)
1705     3)  "printer admins" (may result in numerous calls to winbind)
1706
1707  ****************************************************************************/
1708 bool print_access_check(const struct auth_session_info *session_info,
1709                         struct messaging_context *msg_ctx, int snum,
1710                         int access_type)
1711 {
1712         struct spoolss_security_descriptor *secdesc = NULL;
1713         uint32 access_granted;
1714         size_t sd_size;
1715         NTSTATUS status;
1716         WERROR result;
1717         const char *pname;
1718         TALLOC_CTX *mem_ctx = NULL;
1719
1720         /* If user is NULL then use the current_user structure */
1721
1722         /* Always allow root or SE_PRINT_OPERATROR to do anything */
1723
1724         if (session_info->unix_token->uid == sec_initial_uid()
1725             || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1726                 return True;
1727         }
1728
1729         /* Get printer name */
1730
1731         pname = lp_printername(talloc_tos(), snum);
1732
1733         if (!pname || !*pname) {
1734                 errno = EACCES;
1735                 return False;
1736         }
1737
1738         /* Get printer security descriptor */
1739
1740         if(!(mem_ctx = talloc_init("print_access_check"))) {
1741                 errno = ENOMEM;
1742                 return False;
1743         }
1744
1745         result = winreg_get_printer_secdesc_internal(mem_ctx,
1746                                             get_session_info_system(),
1747                                             msg_ctx,
1748                                             pname,
1749                                             &secdesc);
1750         if (!W_ERROR_IS_OK(result)) {
1751                 talloc_destroy(mem_ctx);
1752                 errno = ENOMEM;
1753                 return False;
1754         }
1755
1756         if (access_type == JOB_ACCESS_ADMINISTER) {
1757                 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1758
1759                 /* Create a child security descriptor to check permissions
1760                    against.  This is because print jobs are child objects
1761                    objects of a printer. */
1762                 status = se_create_child_secdesc(mem_ctx,
1763                                                  &secdesc,
1764                                                  &sd_size,
1765                                                  parent_secdesc,
1766                                                  parent_secdesc->owner_sid,
1767                                                  parent_secdesc->group_sid,
1768                                                  false);
1769                 if (!NT_STATUS_IS_OK(status)) {
1770                         talloc_destroy(mem_ctx);
1771                         errno = map_errno_from_nt_status(status);
1772                         return False;
1773                 }
1774
1775                 map_job_permissions(secdesc);
1776         } else {
1777                 map_printer_permissions(secdesc);
1778         }
1779
1780         /* Check access */
1781         status = se_access_check(secdesc, session_info->security_token, access_type,
1782                                  &access_granted);
1783
1784         DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1785
1786         talloc_destroy(mem_ctx);
1787
1788         if (!NT_STATUS_IS_OK(status)) {
1789                 errno = EACCES;
1790         }
1791
1792         return NT_STATUS_IS_OK(status);
1793 }
1794
1795 /****************************************************************************
1796  Check the time parameters allow a print operation.
1797 *****************************************************************************/
1798
1799 bool print_time_access_check(const struct auth_session_info *session_info,
1800                              struct messaging_context *msg_ctx,
1801                              const char *servicename)
1802 {
1803         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1804         WERROR result;
1805         bool ok = False;
1806         time_t now = time(NULL);
1807         struct tm *t;
1808         uint32 mins;
1809
1810         result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1811                                     servicename, &pinfo2);
1812         if (!W_ERROR_IS_OK(result)) {
1813                 return False;
1814         }
1815
1816         if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1817                 ok = True;
1818         }
1819
1820         t = gmtime(&now);
1821         mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1822
1823         if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1824                 ok = True;
1825         }
1826
1827         TALLOC_FREE(pinfo2);
1828
1829         if (!ok) {
1830                 errno = EACCES;
1831         }
1832
1833         return ok;
1834 }
1835
1836 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1837                         const struct auth_session_info *session_info,
1838                         struct messaging_context *msg_ctx,
1839                         const char *printer)
1840 {
1841         WERROR result;
1842
1843         result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1844                                            printer, "");
1845         if (!W_ERROR_IS_OK(result)) {
1846                 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1847                 "%s\n", printer, win_errstr(result)));
1848         }
1849 }
1850
1851 void nt_printer_add(TALLOC_CTX *mem_ctx,
1852                     const struct auth_session_info *session_info,
1853                     struct messaging_context *msg_ctx,
1854                     const char *printer)
1855 {
1856         WERROR result;
1857
1858         result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1859                                                 printer);
1860         if (!W_ERROR_IS_OK(result)) {
1861                 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1862                           printer, win_errstr(result)));
1863         }
1864 }