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