s3-spoolss: fix return code of spoolss_DeletePrinter.
[abartlet/samba.git/.git] / source3 / rpc_server / srv_spoolss_nt.c
index 433fc81d3a48f2a54ef3d7405d3833fd8c6fbf37..445a65465b19a63dd4aacae01a2cfc4e2c714bb3 100644 (file)
@@ -315,7 +315,7 @@ static WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const c
        reload_services(false);
        unbecome_root();
 
-       if ( lp_servicenumber( sharename )  < 0 )
+       if ( lp_servicenumber( sharename )  > 0 )
                return WERR_ACCESS_DENIED;
 
        return WERR_OK;
@@ -2270,8 +2270,8 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx,
 
        if (!StrCaseCmp(value, "Architecture")) {
                *type = REG_SZ;
-
-               data->string = talloc_strdup(mem_ctx, "Windows NT x86");
+               data->string = talloc_strdup(mem_ctx,
+                       lp_parm_const_string(GLOBAL_SECTION_SNUM, "spoolss", "architecture", SPOOLSS_ARCHITECTURE_NT_X86));
                W_ERROR_HAVE_NO_MEMORY(data->string);
 
                return WERR_OK;
@@ -2340,27 +2340,30 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
        NTSTATUS ret;
        struct cli_state *the_cli;
        struct sockaddr_storage rm_addr;
+       char addr[INET6_ADDRSTRLEN];
 
        if ( is_zero_addr((struct sockaddr *)client_ss) ) {
+               DEBUG(2,("spoolss_connect_to_client: resolving %s\n",
+                       remote_machine));
                if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) {
                        DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
                        return false;
                }
-
-               if (ismyaddr((struct sockaddr *)&rm_addr)) {
-                       DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
-                       return false;
-               }
+               print_sockaddr(addr, sizeof(addr), &rm_addr);
        } else {
-               char addr[INET6_ADDRSTRLEN];
                rm_addr = *client_ss;
                print_sockaddr(addr, sizeof(addr), &rm_addr);
                DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
                        addr));
        }
 
-       /* setup the connection */
+       if (ismyaddr((struct sockaddr *)&rm_addr)) {
+               DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n",
+                       addr));
+               return false;
+       }
 
+       /* setup the connection */
        ret = cli_full_connection( &the_cli, global_myname(), remote_machine,
                &rm_addr, 0, "IPC$", "IPC",
                "", /* username */
@@ -2549,6 +2552,9 @@ WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
                        !get_printer_snum(p, r->in.handle, &snum, NULL) )
                return WERR_BADFID;
 
+       DEBUG(10,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: "
+               "client_address is %s\n", p->client_address));
+
        if (!interpret_string_addr(&client_ss, p->client_address,
                                   AI_NUMERICHOST)) {
                return WERR_SERVER_UNAVAILABLE;
@@ -4275,7 +4281,7 @@ static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx,
 WERROR _spoolss_EnumPrinters(pipes_struct *p,
                             struct spoolss_EnumPrinters *r)
 {
-       const char *name;
+       const char *name = NULL;
        WERROR result;
 
        /* that's an [in out] buffer */
@@ -4303,8 +4309,10 @@ WERROR _spoolss_EnumPrinters(pipes_struct *p,
         * Level 5: same as Level 2
         */
 
-       name = talloc_strdup_upper(p->mem_ctx, r->in.server);
-       W_ERROR_HAVE_NO_MEMORY(name);
+       if (name) {
+               name = talloc_strdup_upper(p->mem_ctx, r->in.server);
+               W_ERROR_HAVE_NO_MEMORY(name);
+       }
 
        switch (r->in.level) {
        case 0:
@@ -4498,8 +4506,7 @@ static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
 static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo1 *r,
                                        const struct spoolss_DriverInfo8 *driver,
-                                       const char *servername,
-                                       const char *architecture)
+                                       const char *servername)
 {
        r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
@@ -4837,6 +4844,8 @@ static WERROR fill_printer_driver_info8(TALLOC_CTX *mem_ctx,
 
        return WERR_OK;
 }
+
+#if 0 /* disabled until marshalling issues are resolved - gd */
 /********************************************************************
  ********************************************************************/
 
@@ -4955,7 +4964,7 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
 }
 
 /********************************************************************
- * fill a spoolss_DriverInfo101 sttruct
+ * fill a spoolss_DriverInfo101 struct
  ********************************************************************/
 
 static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
@@ -5010,380 +5019,25 @@ static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
 
        return WERR_OK;
 }
-
-/********************************************************************
- * construct_printer_driver_info_1
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo1 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR result;
-
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version))) {
-               free_a_printer(&printer, 2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
-       }
-
-       result = fill_printer_driver_info1(mem_ctx, r, driver, servername, architecture);
-
-       free_a_printer_driver(driver);
-       free_a_printer(&printer,2);
-
-       return result;
-}
-
+#endif
 /********************************************************************
- * construct_printer_driver_info_2
- * fill a printer_info_2 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo2 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
+static WERROR construct_printer_driver_info_level(TALLOC_CTX *mem_ctx,
+                                                 uint32_t level,
+                                                 union spoolss_DriverInfo *r,
+                                                 int snum,
+                                                 const char *servername,
+                                                 const char *architecture,
+                                                 uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        struct spoolss_DriverInfo8 *driver;
        WERROR result;
 
-       ZERO_STRUCT(printer);
-
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version))) {
-               free_a_printer(&printer, 2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
-       }
-
-       result = fill_printer_driver_info2(mem_ctx, r, driver, servername);
-
-       free_a_printer_driver(driver);
-       free_a_printer(&printer,2);
-
-       return result;
-}
-
-/********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo3 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR status;
-       ZERO_STRUCT(driver);
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-
-#if 0  /* JERRY */
-
-       /*
-        * I put this code in during testing.  Helpful when commenting out the
-        * support for DRIVER_INFO_6 in regards to win2k.  Not needed in general
-        * as win2k always queries the driver using an infor level of 6.
-        * I've left it in (but ifdef'd out) because I'll probably
-        * use it in experimentation again in the future.   --jerry 22/01/2002
-        */
-
-       if (!W_ERROR_IS_OK(status)) {
-               /*
-                * Is this a W2k client ?
-                */
-               if (version == 3) {
-                       /* Yes - try again with a WinNT driver. */
-                       version = 2;
-                       status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-                       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-               }
-#endif
-
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-#if 0  /* JERRY */
-       }
-#endif
-
-
-       status = fill_printer_driver_info3(mem_ctx, r, driver, servername);
-
-       free_a_printer_driver(driver);
-       free_a_printer(&printer,2);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_4
- * fill a printer_info_4 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_4(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo4 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR                          status;
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_4: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_4: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_4: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       status = fill_printer_driver_info4(mem_ctx, r, driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_5
- * fill a printer_info_5 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_5(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo5 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR                          status;
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_5: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_5: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_5: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       status = fill_printer_driver_info5(mem_ctx, r, driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_6
- * fill a printer_info_6 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo6 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR                          status;
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       status = fill_printer_driver_info6(mem_ctx, r, driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_8
- * fill a printer_info_8 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_8(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo8 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR                          status;
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_8: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_8: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_8: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       status = fill_printer_driver_info8(mem_ctx, r, driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_101
- * fill a printer_info_101 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
-                                               struct spoolss_DriverInfo101 *r,
-                                               int snum,
-                                               const char *servername,
-                                               const char *architecture,
-                                               uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       struct spoolss_DriverInfo8 *driver;
-       WERROR                          result;
-
        result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
 
-       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+       DEBUG(8,("construct_printer_driver_info_level: status: %s\n",
                win_errstr(result)));
 
        if (!W_ERROR_IS_OK(result)) {
@@ -5393,7 +5047,7 @@ static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
        result = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername,
                                      architecture, version);
 
-       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+       DEBUG(8,("construct_printer_driver_info_level: status: %s\n",
                win_errstr(result)));
 
        if (!W_ERROR_IS_OK(result)) {
@@ -5410,7 +5064,7 @@ static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
                version = 2;
                result = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername,
                                              architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n",
+               DEBUG(8,("construct_printer_driver_level: status: %s\n",
                        win_errstr(result)));
                if (!W_ERROR_IS_OK(result)) {
                        free_a_printer(&printer, 2);
@@ -5418,7 +5072,37 @@ static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
                }
        }
 
-       result = fill_printer_driver_info101(mem_ctx, r, driver, servername);
+       switch (level) {
+       case 1:
+               result = fill_printer_driver_info1(mem_ctx, &r->info1, driver, servername);
+               break;
+       case 2:
+               result = fill_printer_driver_info2(mem_ctx, &r->info2, driver, servername);
+               break;
+       case 3:
+               result = fill_printer_driver_info3(mem_ctx, &r->info3, driver, servername);
+               break;
+       case 4:
+               result = fill_printer_driver_info4(mem_ctx, &r->info4, driver, servername);
+               break;
+       case 5:
+               result = fill_printer_driver_info5(mem_ctx, &r->info5, driver, servername);
+               break;
+       case 6:
+               result = fill_printer_driver_info6(mem_ctx, &r->info6, driver, servername);
+               break;
+       case 8:
+               result = fill_printer_driver_info8(mem_ctx, &r->info8, driver, servername);
+               break;
+#if 0 /* disabled until marshalling issues are resolved - gd */
+       case 101:
+               result = fill_printer_driver_info101(mem_ctx, &r->info101, driver, servername);
+               break;
+#endif
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
        free_a_printer(&printer, 2);
        free_a_printer_driver(driver);
@@ -5462,76 +5146,11 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
                return WERR_BADFID;
        }
 
-       switch (r->in.level) {
-       case 1:
-               result = construct_printer_driver_info_1(p->mem_ctx,
-                                                        &r->out.info->info1,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 2:
-               result = construct_printer_driver_info_2(p->mem_ctx,
-                                                        &r->out.info->info2,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 3:
-               result = construct_printer_driver_info_3(p->mem_ctx,
-                                                        &r->out.info->info3,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 4:
-               result = construct_printer_driver_info_4(p->mem_ctx,
-                                                        &r->out.info->info4,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 5:
-               result = construct_printer_driver_info_5(p->mem_ctx,
-                                                        &r->out.info->info5,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 6:
-               result = construct_printer_driver_info_6(p->mem_ctx,
-                                                        &r->out.info->info6,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 8:
-               result = construct_printer_driver_info_8(p->mem_ctx,
-                                                        &r->out.info->info8,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 101:
-               result = construct_printer_driver_info_101(p->mem_ctx,
-                                                          &r->out.info->info101,
-                                                          snum,
-                                                          servername,
-                                                          r->in.architecture,
-                                                          r->in.client_major_version);
-               break;
-       default:
-               result = WERR_UNKNOWN_LEVEL;
-               break;
-       }
-
+       result = construct_printer_driver_info_level(p->mem_ctx, r->in.level,
+                                                    r->out.info, snum,
+                                                    servername,
+                                                    r->in.architecture,
+                                                    r->in.client_major_version);
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(r->out.info);
                return result;
@@ -6497,6 +6116,27 @@ static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/****************************************************************************
+fill_job_info3
+****************************************************************************/
+
+static WERROR fill_job_info3(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo3 *r,
+                            const print_queue_struct *queue,
+                            const print_queue_struct *next_queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter)
+{
+       r->job_id               = queue->job;
+       r->next_job_id          = 0;
+       if (next_queue) {
+               r->next_job_id  = next_queue->job;
+       }
+       r->reserved             = 0;
+
+       return WERR_OK;
+}
+
 /****************************************************************************
  Enumjobs at level 1.
 ****************************************************************************/
@@ -6595,6 +6235,57 @@ static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/****************************************************************************
+ Enumjobs at level 3.
+****************************************************************************/
+
+static WERROR enumjobs_level3(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
+                              const NT_PRINTER_INFO_LEVEL *ntprinter,
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
+{
+       union spoolss_JobInfo *info;
+       int i;
+       WERROR result = WERR_OK;
+
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       *count = num_queues;
+
+       for (i=0; i<*count; i++) {
+               const print_queue_struct *next_queue = NULL;
+
+               if (i+1 < *count) {
+                       next_queue = &queue[i+1];
+               }
+
+               result = fill_job_info3(info,
+                                       &info[i].info3,
+                                       &queue[i],
+                                       next_queue,
+                                       i,
+                                       snum,
+                                       ntprinter);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
+
+       *info_p = info;
+
+       return WERR_OK;
+}
+
 /****************************************************************
  _spoolss_EnumJobs
 ****************************************************************/
@@ -6651,6 +6342,10 @@ WERROR _spoolss_EnumJobs(pipes_struct *p,
                result = enumjobs_level2(p->mem_ctx, queue, count, snum,
                                         ntprinter, r->out.info, r->out.count);
                break;
+       case 3:
+               result = enumjobs_level3(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
+               break;
        default:
                result = WERR_UNKNOWN_LEVEL;
                break;
@@ -6765,7 +6460,7 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
                                                    union spoolss_DriverInfo,
                                                    count + ndrivers);
                        if (!info) {
-                               DEBUG(0,("enumprinterdrivers_level1: "
+                               DEBUG(0,("enumprinterdrivers_level_by_architecture: "
                                        "failed to enlarge driver info buffer!\n"));
                                result = WERR_NOMEM;
                                goto out;
@@ -6784,8 +6479,7 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
                        switch (level) {
                        case 1:
                                result = fill_printer_driver_info1(info, &info[count+i].info1,
-                                                                  driver, servername,
-                                                                  architecture);
+                                                                  driver, servername);
                                break;
                        case 2:
                                result = fill_printer_driver_info2(info, &info[count+i].info2,
@@ -6855,7 +6549,7 @@ static WERROR enumprinterdrivers_level(TALLOC_CTX *mem_ctx,
        uint32_t a,i;
        WERROR result = WERR_OK;
 
-       if (strequal(architecture, "all")) {
+       if (strequal(architecture, SPOOLSS_ARCHITECTURE_ALL)) {
 
                for (a=0; archi_table[a].long_archi != NULL; a++) {
 
@@ -6889,104 +6583,6 @@ static WERROR enumprinterdrivers_level(TALLOC_CTX *mem_ctx,
                                                        count_p);
 }
 
-/****************************************************************************
- Enumerates all printer drivers at level 1.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 1,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 2.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 2,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 3.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 3,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 4.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level4(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 4,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 5.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level5(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 5,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 6.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level6(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 6,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 8.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level8(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 8,
-                                       info_p, count);
-}
-
 /****************************************************************
  _spoolss_EnumPrinterDrivers
 ****************************************************************/
@@ -7015,46 +6611,11 @@ WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       switch (r->in.level) {
-       case 1:
-               result = enumprinterdrivers_level1(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 2:
-               result = enumprinterdrivers_level2(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 3:
-               result = enumprinterdrivers_level3(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 4:
-               result = enumprinterdrivers_level4(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 5:
-               result = enumprinterdrivers_level5(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 6:
-               result = enumprinterdrivers_level6(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 8:
-               result = enumprinterdrivers_level8(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       default:
-               return WERR_UNKNOWN_LEVEL;
-       }
-
+       result = enumprinterdrivers_level(p->mem_ctx, cservername,
+                                         r->in.environment,
+                                         r->in.level,
+                                         r->out.info,
+                                         r->out.count);
        if (!W_ERROR_IS_OK(result)) {
                return result;
        }
@@ -7577,6 +7138,15 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
                return WERR_NOMEM;
        }
 
+       /* samba does not have a concept of local, non-shared printers yet, so
+        * make sure we always setup sharename - gd */
+       if ((printer->info_2->sharename[0] == '\0') && (printer->info_2->printername != '\0')) {
+               DEBUG(5, ("spoolss_addprinterex_level_2: "
+                       "no sharename has been set, setting printername %s as sharename\n",
+                       printer->info_2->printername));
+               fstrcpy(printer->info_2->sharename, printer->info_2->printername);
+       }
+
        /* check to see if the printer already exists */
 
        if ((snum = print_queue_snum(printer->info_2->sharename)) != -1) {
@@ -7586,6 +7156,37 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
                return WERR_PRINTER_ALREADY_EXISTS;
        }
 
+       if (!lp_force_printername(GLOBAL_SECTION_SNUM)) {
+               if ((snum = print_queue_snum(printer->info_2->printername)) != -1) {
+                       DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n",
+                               printer->info_2->printername));
+                       free_a_printer(&printer, 2);
+                       return WERR_PRINTER_ALREADY_EXISTS;
+               }
+       }
+
+       /* validate printer info struct */
+       if (!info_ctr->info.info2->printername ||
+           strlen(info_ctr->info.info2->printername) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_INVALID_PRINTER_NAME;
+       }
+       if (!info_ctr->info.info2->portname ||
+           strlen(info_ctr->info.info2->portname) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PORT;
+       }
+       if (!info_ctr->info.info2->drivername ||
+           strlen(info_ctr->info.info2->drivername) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
+       if (!info_ctr->info.info2->printprocessor ||
+           strlen(info_ctr->info.info2->printprocessor) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PRINTPROCESSOR;
+       }
+
        /* FIXME!!!  smbd should check to see if the driver is installed before
           trying to add a printer like this  --jerry */
 
@@ -8155,8 +7756,15 @@ WERROR _spoolss_EnumPrinterData(pipes_struct *p,
 
                /* data - counted in bytes */
 
-               if (r->out.data && regval_size(val)) {
-                       memcpy(r->out.data, regval_data_p(val), regval_size(val));
+               /*
+                * See the section "Dynamically Typed Query Parameters"
+                * in MS-RPRN.
+                */
+
+               if (r->out.data && regval_data_p(val) &&
+                               regval_size(val) && r->in.data_offered) {
+                       memcpy(r->out.data, regval_data_p(val),
+                               MIN(regval_size(val),r->in.data_offered));
                }
 
                *r->out.data_needed = regval_size(val);
@@ -9313,12 +8921,20 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
                goto done;
        }
 
-       array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 1);
+       array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 2);
        if (!array) {
                result = WERR_NOMEM;
                goto done;
        }
 
+       if (!num_keys) {
+               array[0] = talloc_strdup(array, "");
+               if (!array[0]) {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
+       }
+
        for (i=0; i < num_keys; i++) {
 
                DEBUG(10,("_spoolss_EnumPrinterKey: adding keyname: %s\n",
@@ -9336,13 +8952,14 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
                goto done;
        }
 
+       *r->out._ndr_size = r->in.offered / 2;
        *r->out.needed = blob.length;
 
        if (r->in.offered < *r->out.needed) {
                result = WERR_MORE_DATA;
        } else {
                result = WERR_OK;
-               r->out.key_buffer->string = array;
+               r->out.key_buffer->string_array = array;
        }
 
  done:
@@ -9960,7 +9577,10 @@ WERROR _spoolss_XcvData(pipes_struct *p,
 
        *r->out.status_code = 0;
 
-       memcpy(r->out.out_data, out_data.data, out_data.length);
+       if (r->out.out_data && out_data.data && r->in.out_data_size && out_data.length) {
+               memcpy(r->out.out_data, out_data.data,
+                       MIN(r->in.out_data_size, out_data.length));
+       }
 
        return WERR_OK;
 }