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