Example #1
0
 def _on_retry_server_error_response (self, dialog, response):
     dialog.destroy ()
     if response == Gtk.ResponseType.OK:
         debugprint ("%s: got retry response, reconnecting (as %s)..." %
                     (self, self._conn.thread.user))
         self._conn.reconnect (self._conn.thread.user,
                               reply_handler=self._reconnect_reply,
                               error_handler=self._reconnect_error)
     else:
         debugprint ("%s: got cancel response" % self)
         self._error (cups.IPPError (0, _("Operation canceled")))
Example #2
0
    def _call_with_pk_and_fallback(self, use_fallback, pk_function_name,
                                   pk_args, fallback_function, *args, **kwds):
        pk_function = None
        # take signature from kwds if is provided
        dbus_args_signature = kwds.pop('signature', None)

        if not use_fallback:
            cups_pk = self._get_cups_pk()
            if cups_pk:
                try:
                    pk_function = cups_pk.get_dbus_method(pk_function_name)
                except dbus.exceptions.DBusException:
                    pass

        if use_fallback or not pk_function:
            return fallback_function(*args, **kwds)

        pk_retval = 'PolicyKit communication issue'

        while True:
            try:
                # FIXME: async call or not?
                pk_retval = pk_function(*pk_args,
                                        signature=dbus_args_signature)

                # if the PK call has more than one return values, we pop the
                # first one as the error message
                if type(pk_retval) == tuple:
                    retval = pk_retval[1:]
                    # if there's no error, then we can safely return what we
                    # got
                    if pk_retval[0] == '':
                        # if there's only one item left in the tuple, we don't
                        # want to return the tuple, but the item
                        if len(retval) == 1:
                            return retval[0]
                        else:
                            return retval
                break
            except dbus.exceptions.DBusException as e:
                if e.get_dbus_name() == CUPS_PK_NEED_AUTH:
                    debugprint("DBus exception: %s" % e.get_dbus_message())
                    raise cups.IPPError(cups.IPP_NOT_AUTHORIZED, 'pkcancel')

                break

        # The PolicyKit call did not work (either a PK-error and we got a dbus
        # exception that wasn't handled, or an error in the mechanism itself)
        if pk_retval != '':
            debugprint('PolicyKit call to %s did not work: %s' %
                       (pk_function_name, repr(pk_retval)))
            return fallback_function(*args, **kwds)
    def _pk_error_handler(self, exc):
        if self._destroyed:
            return

        if exc.get_dbus_name() == CUPS_PK_NEED_AUTH:
            exc = cups.IPPError(cups.IPP_NOT_AUTHORIZED, 'pkcancel')
            try:
                Gdk.threads_enter()
            except:
                pass
            debugprint("%s: no auth, calling error handler %s" %
                       (self, self._client_error_handler))
            self._client_error_handler(self._conn, exc)
            try:
                Gdk.threads_leave()
            except:
                pass
            self._destroy()
            return

        debugprint("PolicyKit call to %s did not work: %s" %
                   (self._pk_method_name, repr(exc)))
        self.call_fallback_fn()
Example #4
0
    def run (self):
        if self.host == None:
            self.host = cups.getServer ()
        if self.port == None:
            self.port = cups.getPort ()
        if self._encryption == None:
            self._encryption = cups.getEncryption ()

        if self.user:
            cups.setUser (self.user)
        else:
            self.user = cups.getUser ()

        cups.setPasswordCB2 (self._auth)

        try:
            conn = cups.Connection (host=self.host,
                                    port=self.port,
                                    encryption=self._encryption)
            self._reply (None)
        except RuntimeError as e:
            conn = None
            self._error (e)

        while True:
            # Wait to find out what operation to try.
            debugprint ("Awaiting further instructions")
            self.idle = self._queue.empty ()
            item = self._queue.get ()
            debugprint ("Next task: %s" % repr (item))
            if item == None:
                # Our signal to quit.
                self._queue.task_done ()
                break

            self.idle = False
            (fn, args, kwds, rh, eh, ah) = item
            if rh != False:
                self._reply_handler = rh
            if eh != False:
                self._error_handler = eh
            if ah != False:
                self._auth_handler = ah

            if fn == True:
                # Our signal to change user and reconnect.
                self.user = args[0]
                cups.setUser (self.user)
                debugprint ("Set user=%s; reconnecting..." % self.user)
                cups.setPasswordCB2 (self._auth)

                try:
                    conn = cups.Connection (host=self.host,
                                            port=self.port,
                                            encryption=self._encryption)
                    debugprint ("...reconnected")

                    self._queue.task_done ()
                    self._reply (None)
                except RuntimeError as e:
                    debugprint ("...failed")
                    self._queue.task_done ()
                    self._error (e)

                continue

            # Normal IPP operation.  Try to perform it.
            try:
                debugprint ("Call %s" % fn)
                result = fn (conn, *args, **kwds)
                if fn == cups.Connection.adminGetServerSettings.__call__:
                    # Special case for a rubbish bit of API.
                    if result == {}:
                        # Authentication failed, but we aren't told that.
                        raise cups.IPPError (cups.IPP_NOT_AUTHORIZED, '')

                debugprint ("...success")
                self._reply (result)
            except Exception as e:
                debugprint ("...failure (%s)" % repr (e))
                self._error (e)

            self._queue.task_done ()

        debugprint ("Thread exiting")
        self._destroyed = True
        del self._conn # already destroyed
        del self._reply_handler
        del self._error_handler
        del self._auth_handler
        del self._queue
        del self._auth_queue
        del conn

        cups.setPasswordCB2 (None)
Example #5
0
    def _perform_authentication (self):
        self._passes += 1

        creds = global_authinfocache.lookup_auth_info (host=self._server, port=self._port)
        if creds is not None:
            if (creds[0] != 'root' or self._try_as_root):
                (self._use_user, self._use_password) = creds
            del creds

        debugprint ("Authentication pass: %d" % self._passes)
        if self._passes == 1:
            # Haven't yet tried the operation.  Set the password
            # callback and return > 0 so we try it for the first time.
            self._has_failed = False
            self._forbidden = False
            self._auth_called = False
            self._cancel = False
            self._cannot_auth = False
            self._dialog_shown = False
            cups.setPasswordCB (self._password_callback)
            debugprint ("Authentication: password callback set")
            return 1

        debugprint ("Forbidden: %s" % self._forbidden)
        if not self._has_failed:
            # Tried the operation and it worked.  Return 0 to signal to
            # break out of the loop.
            debugprint ("Authentication: Operation successful")
            return 0

        # Reset failure flag.
        self._has_failed = False

        if self._passes >= 2:
            # Tried the operation without a password and it failed.
            if (self._try_as_root and
                self._user != 'root' and
                (self._server[0] == '/' or self._forbidden)):
                # This is a UNIX domain socket connection so we should
                # not have needed a password (or it is not a UDS but
                # we got an HTTP_FORBIDDEN response), and so the
                # operation must not be something that the current
                # user is authorised to do.  They need to try as root,
                # and supply the password.  However, to get the right
                # prompt, we need to try as root but with no password
                # first.
                debugprint ("Authentication: Try as root")
                self._use_user = '******'
                self._auth_called = False
                try:
                    self._connect (allow_pk=False)
                except RuntimeError:
                    raise cups.IPPError (cups.IPP_SERVICE_UNAVAILABLE,
                                         'server-error-service-unavailable')

                return 1

        if not self._prompt_allowed:
            debugprint ("Authentication: prompting not allowed")
            self._cancel = True
            return 1

        if not self._auth_called:
            # We aren't even getting a chance to supply credentials.
            debugprint ("Authentication: giving up")
            self._cancel = True
            self._cannot_auth = True
            return 1

        # Reset the flag indicating whether we were given an auth callback.
        self._auth_called = False

        # If we're previously prompted, explain why we're prompting again.
        if self._dialog_shown:
            if self._lock:
                self._gui_event.clear ()
                GLib.timeout_add (1, self._show_not_authorized_dialog)
                self._gui_event.wait ()
            else:
                self._show_not_authorized_dialog ()

        if self._lock:
            self._gui_event.clear ()
            GLib.timeout_add (1, self._perform_authentication_with_dialog)
            self._gui_event.wait ()
        else:
            self._perform_authentication_with_dialog ()

        if self._cancel:
            debugprint ("cancelled")
            return -1

        cups.setUser (self._use_user)
        debugprint ("Authentication: Reconnect")
        try:
            self._connect (allow_pk=False)
        except RuntimeError:
            raise cups.IPPError (cups.IPP_SERVICE_UNAVAILABLE,
                                 'server-error-service-unavailable')

        return 1
Example #6
0
    def _authloop (self, fname, fn, *args, **kwds):
        self._passes = 0
        c = self._connection
        retry = False
        while True:
            try:
                if self._perform_authentication () == 0:
                    break

                if c != self._connection:
                    # We have reconnected.
                    fn = getattr (self._connection, fname)
                    c = self._connection

                cups.setUser (self._use_user)

                result = fn.__call__ (*args, **kwds)

                if fname == 'adminGetServerSettings':
                    # Special case for a rubbish bit of API.
                    if result == {}:
                        # Authentication failed, but we aren't told that.
                        raise cups.IPPError (cups.IPP_NOT_AUTHORIZED, '')
                break
            except cups.IPPError as e:
                (e, m) = e.args
                if self._use_pk and m == 'pkcancel':
                    raise cups.IPPError (0, _("Operation canceled"))

                if not self._cancel and (e == cups.IPP_NOT_AUTHORIZED or
                                         e == cups.IPP_FORBIDDEN or
                                         e == cups.IPP_AUTHENTICATION_CANCELED):
                    self._failed (e == cups.IPP_FORBIDDEN)
                elif not self._cancel and e == cups.IPP_SERVICE_UNAVAILABLE:
                    debugprint ("Got IPP_SERVICE_UNAVAILABLE")
                    debugprint (m)
                    if self._lock:
                        self._gui_event.clear ()
                        GLib.timeout_add (1, self._ask_retry_server_error, m)
                        self._gui_event.wait ()
                    else:
                        self._ask_retry_server_error (m)

                    if self._retry_response == Gtk.ResponseType.OK:
                        debugprint ("retrying operation...")
                        retry = True
                        self._passes -= 1
                        self._has_failed = True
                    else:
                        self._cancel = True
                        raise
                else:
                    if self._cancel and not self._cannot_auth:
                        raise cups.IPPError (0, _("Operation canceled"))

                    debugprint ("%s: %s" % (e, repr (m)))
                    raise
            except cups.HTTPError as e:
                (s,) = e.args
                if not self._cancel:
                    self._failed (s == cups.HTTP_FORBIDDEN)
                else:
                    raise

        return result
APP_ROOT = os.path.dirname(__file__)
FRONTEND_PATH = os.path.join(APP_ROOT, 'public')

app = Flask(__name__,
            template_folder=FRONTEND_PATH,
            static_folder=FRONTEND_PATH)

#PRINTER_NAME = "Brother_HL_L2305_series"
#PRINTER_NAME  = "BrGenPrintML2"
PRINTER_NAME = "Brother_HL-L2340D_series"
IPP_ERROR = "ipp error"
PRINT_FILES_PATH = os.path.join(APP_ROOT, 'print-files')

cups_conn = cups.Connection()
IPPError = cups.IPPError()
files = glob.glob(PRINT_FILES_PATH + "/*.txt")

if __name__ == '__main__':
    app.run(debug=False)


@app.route('/')
def index():
    return render_template("/index.html")


@app.route('/test')
def tester():
    return render_template("/tester.html")