コード例 #1
0
ファイル: server.py プロジェクト: saschalucas/ganeti
def _HandleServerRequestInner(handler, req_msg, reader):
    """Calls the handler function for the current request.

  """
    handler_context = _HttpServerRequest(req_msg.start_line.method,
                                         req_msg.start_line.path,
                                         req_msg.headers, req_msg.body,
                                         reader.sock)

    logging.debug("Handling request %r", handler_context)

    try:
        try:
            # Authentication, etc.
            handler.PreHandleRequest(handler_context)

            # Call actual request handler
            result = handler.HandleRequest(handler_context)
        except (http.HttpException, errors.RapiTestResult, KeyboardInterrupt,
                SystemExit):
            raise
        except Exception as err:
            logging.exception("Caught exception")
            raise http.HttpInternalServerError(message=str(err))
        except:
            logging.exception("Unknown exception")
            raise http.HttpInternalServerError(message="Unknown error")

        if not isinstance(result, (str, bytes)):
            raise http.HttpError("Handler function didn't return string type")

        return (http.HTTP_OK, handler_context.resp_headers, result)
    finally:
        # No reason to keep this any longer, even for exceptions
        handler_context.private = None
コード例 #2
0
ファイル: pam.py プロジェクト: vanloswang/ganeti
def Authenticate(cf, pam_handle, authtok=None):
    """Performs authentication via PAM.

  Perfroms two steps:
    - if authtok is provided then set it with pam_set_item
    - call pam_authenticate

  """
    try:
        authtok_copy = None
        if authtok:
            authtok_copy = cf.strndup(authtok, len(authtok))
            if not authtok_copy:
                raise http.HttpInternalServerError("Not enough memory for PAM")
            ret = cf.pam_set_item(c.pointer(pam_handle), PAM_AUTHTOK,
                                  authtok_copy)
            if ret != PAM_SUCCESS:
                raise http.HttpInternalServerError("pam_set_item failed [%d]" %
                                                   ret)

        ret = cf.pam_authenticate(pam_handle, 0)
        if ret == PAM_ABORT:
            raise http.HttpInternalServerError(
                "pam_authenticate requested abort")
        if ret != PAM_SUCCESS:
            raise http.HttpUnauthorized("Authentication failed")
    except:
        cf.pam_end(pam_handle, ret)
        raise
    finally:
        if authtok_copy:
            cf.free(authtok_copy)
コード例 #3
0
    def SubmitJob(self, op, cl=None):
        """Generic wrapper for submit job, for better http compatibility.

    @type op: list
    @param op: the list of opcodes for the job
    @type cl: None or luxi.Client
    @param cl: optional luxi client to use
    @rtype: string
    @return: the job ID

    """
        if cl is None:
            cl = self.GetClient()
        try:
            return cl.SubmitJob(op)
        except errors.JobQueueFull:
            raise http.HttpServiceUnavailable(
                "Job queue is full, needs archiving")
        except errors.JobQueueDrainError:
            raise http.HttpServiceUnavailable(
                "Job queue is drained, cannot submit")
        except rpcerr.NoMasterError as err:
            raise http.HttpBadGateway("Master seems to be unreachable: %s" %
                                      err)
        except rpcerr.PermissionError:
            raise http.HttpInternalServerError(
                "Internal error: no permission to"
                " connect to the master daemon")
        except rpcerr.TimeoutError as err:
            raise http.HttpGatewayTimeout("Timeout while talking to the master"
                                          " daemon: %s" % err)
コード例 #4
0
ファイル: pam.py プロジェクト: vanloswang/ganeti
def PutPamEnvVariable(cf, pam_handle, name, value):
    """Wrapper over pam_setenv.

  """
    setenv = "%s=" % name
    if value:
        setenv += value
    ret = cf.pam_putenv(pam_handle, setenv)
    if ret != PAM_SUCCESS:
        raise http.HttpInternalServerError("pam_putenv call failed [%d]" % ret)
コード例 #5
0
  def GetClient(self):
    """Wrapper for L{luxi.Client} with HTTP-specific error handling.

    """
    # Could be a function, pylint: disable=R0201
    try:
      return self._client_cls()
    except rpcerr.NoMasterError as err:
      raise http.HttpBadGateway("Can't connect to master daemon: %s" % err)
    except rpcerr.PermissionError:
      raise http.HttpInternalServerError("Internal error: no permission to"
                                         " connect to the master daemon")
コード例 #6
0
ファイル: baserlib.py プロジェクト: vladimir-ipatov/ganeti-1
class ResourceBase(object):
    """Generic class for resources.

  """
    # Default permission requirements
    GET_ACCESS = []
    PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
    POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
    DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]

    def __init__(self, items, queryargs, req, _client_cls=None):
        """Generic resource constructor.

    @param items: a list with variables encoded in the URL
    @param queryargs: a dictionary with additional options from URL
    @param req: Request context
    @param _client_cls: L{luxi} client class (unittests only)

    """
        assert isinstance(queryargs, dict)

        self.items = items
        self.queryargs = queryargs
        self._req = req

        if _client_cls is None:
            _client_cls = luxi.Client

        self._client_cls = _client_cls

        self.auth_user = ""

    def _GetRequestBody(self):
        """Returns the body data.

    """
        return self._req.private.body_data

    request_body = property(fget=_GetRequestBody)

    def _checkIntVariable(self, name, default=0):
        """Return the parsed value of an int argument.

    """
        val = self.queryargs.get(name, default)
        if isinstance(val, list):
            if val:
                val = val[0]
            else:
                val = default
        try:
            val = int(val)
        except (ValueError, TypeError):
            raise http.HttpBadRequest("Invalid value for the"
                                      " '%s' parameter" % (name, ))
        return val

    def _checkStringVariable(self, name, default=None):
        """Return the parsed value of a string argument.

    """
        val = self.queryargs.get(name, default)
        if isinstance(val, list):
            if val:
                val = val[0]
            else:
                val = default
        return val

    def getBodyParameter(self, name, *args):
        """Check and return the value for a given parameter.

    If a second parameter is not given, an error will be returned,
    otherwise this parameter specifies the default value.

    @param name: the required parameter

    """
        if args:
            return CheckParameter(self.request_body, name, default=args[0])

        return CheckParameter(self.request_body, name)

    def useLocking(self):
        """Check if the request specifies locking.

    """
        return bool(self._checkIntVariable("lock"))

    def useBulk(self):
        """Check if the request specifies bulk querying.

    """
        return bool(self._checkIntVariable("bulk"))

    def useForce(self):
        """Check if the request specifies a forced operation.

    """
        return bool(self._checkIntVariable("force"))

    def dryRun(self):
        """Check if the request specifies dry-run mode.

    """
        return bool(self._checkIntVariable("dry-run"))

    def GetClient(self):
        """Wrapper for L{luxi.Client} with HTTP-specific error handling.

    """
        # Could be a function, pylint: disable=R0201
        try:
            return self._client_cls()
        except rpcerr.NoMasterError, err:
            raise http.HttpBadGateway("Can't connect to master daemon: %s" %
                                      err)
        except rpcerr.PermissionError:
            raise http.HttpInternalServerError(
                "Internal error: no permission to"
                " connect to the master daemon")
コード例 #7
0
ファイル: baserlib.py プロジェクト: vladimir-ipatov/ganeti-1
                trail = getattr(opcode, constants.OPCODE_REASON, [])
                trail.append(self.GetAuthReason())
                setattr(opcode, constants.OPCODE_REASON, trail)
            return cl.SubmitJob(op)
        except errors.JobQueueFull:
            raise http.HttpServiceUnavailable(
                "Job queue is full, needs archiving")
        except errors.JobQueueDrainError:
            raise http.HttpServiceUnavailable(
                "Job queue is drained, cannot submit")
        except rpcerr.NoMasterError, err:
            raise http.HttpBadGateway("Master seems to be unreachable: %s" %
                                      err)
        except rpcerr.PermissionError:
            raise http.HttpInternalServerError(
                "Internal error: no permission to"
                " connect to the master daemon")
        except rpcerr.TimeoutError, err:
            raise http.HttpGatewayTimeout("Timeout while talking to the master"
                                          " daemon: %s" % err)


def GetResourceOpcodes(cls):
    """Returns all opcodes used by a resource.

  """
    return frozenset(
        filter(None, (getattr(cls, method_attrs.opcode, None)
                      for method_attrs in OPCODE_ATTRS)))

コード例 #8
0
ファイル: pam.py プロジェクト: vanloswang/ganeti
def ValidateRequest(cf,
                    username,
                    uri_access_rights,
                    password=None,
                    service=DEFAULT_SERVICE_NAME,
                    authtok=None,
                    uri=None,
                    method=None,
                    body=None):
    """Checks whether it's permitted to execute an rapi request.

  Calls pam_authenticate and then pam_acct_mgmt in order to check whether a
  request should be executed.

  @param cf: An instance of CFunctions class containing necessary imports
  @param username: username
  @param uri_access_rights: handler access rights
  @param password: password
  @param service: a service name that will be used for the interaction with PAM
  @param authtok: user's authentication token (e.g. some kind of signature)
  @param uri: an uri of a target resource obtained from an http header
  @param method: http method trying to access the uri
  @param body: a body of an RAPI request
  @return: On success - authenticated user name. Throws an exception otherwise.

  """
    ValidateParams(username, uri_access_rights, password, service, authtok,
                   uri, method, body)

    def ConversationFunction(num_msg, msg, resp, _app_data_ptr):
        """Conversation function that will be provided to PAM modules.

    The function replies with a password for each message with
    PAM_PROMPT_ECHO_OFF style and just ignores the others.

    """
        if num_msg > MAX_MSG_COUNT:
            logging.warning("Too many messages passed to conv function: [%d]",
                            num_msg)
            return PAM_BUF_ERR
        response = cf.calloc(num_msg, c.sizeof(PamResponse))
        if not response:
            logging.warning("calloc failed in conv function")
            return PAM_BUF_ERR
        resp[0] = c.cast(response, c.POINTER(PamResponse))
        for i in range(num_msg):
            if msg[i].contents.msg_style != PAM_PROMPT_ECHO_OFF:
                continue
            resp.contents[i].resp = cf.strndup(password, len(password))
            if not resp.contents[i].resp:
                logging.warning("strndup failed in conv function")
                for j in range(i):
                    cf.free(c.cast(resp.contents[j].resp, c.c_void_p))
                cf.free(response)
                return PAM_BUF_ERR
            resp.contents[i].resp_retcode = 0
        return PAM_SUCCESS

    pam_handle = PamHandleT()
    conv = PamConv(CONV_FUNC(ConversationFunction), 0)
    ret = cf.pam_start(service, username, c.pointer(conv),
                       c.pointer(pam_handle))
    if ret != PAM_SUCCESS:
        cf.pam_end(pam_handle, ret)
        raise http.HttpInternalServerError("pam_start call failed [%d]" % ret)

    Authenticate(cf, pam_handle, authtok)
    Authorize(cf, pam_handle, uri_access_rights, uri, method, body)

    # retrieve the authorized user name
    puser = c.c_void_p()
    ret = cf.pam_get_item(pam_handle, PAM_USER, c.pointer(puser))
    if ret != PAM_SUCCESS or not puser:
        cf.pam_end(pam_handle, ret)
        raise http.HttpInternalServerError("pam_get_item call failed [%d]" %
                                           ret)
    user_c_string = c.cast(puser, c.c_char_p)

    cf.pam_end(pam_handle, PAM_SUCCESS)
    return user_c_string.value