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