dbus+policykit初级hello world应用

2011年8月23日 10:29

 

  因为Ylmf os要做的好用,操作习惯上更像windows。所以,跟其他发行版不一样。很多时候需要root权限的时候。我们的程序就自动的提升权限进行操作。以免用户输入密码。这样做也用弊端。如果一个恶意的程序获得了这个权限。就会造成很严重的后果。
  我们用dbus来进行这个权限的提升操作。其实dbus是一个消息总线。具体不展开来说。要了解请自行google。我们写了一个叫ylmfdbus的一个dbus服务。这个服务设计成可插拔的。如果我有一个新的程序中某一个模块需要在root权限下执行。就需要把这个功能抽象的写成一个GObject类。然后注册到ylmfdbus里面。我们就可以通过调用dbus的方法来在root下执行这个函数,或者模块。在执行这个被提权的函数时候,为了防止被恶意操作,我们加入policykit验证,在每次GObject方法调用的时候现调用policykit。
 
接下来,我们开始进行打怪升级。
我们现看看已有装备:
[Dbus相关]
ylmf-dbus-global-defines.h
com.ylmf.DBusGlib.conf
com.ylmf.DBusGlib.service
service-main.c
[PolicyKit相关]
policykit-ylmf.c 
policykit-ylmf.h
com.ylmf.PolicyKit.policy 
[Makefile]
Makefile
 
com.ylmf.DBusGlib.service这个文件很简单。就配置了一下我们服务的路径。这里已经配置好了,不用去管它。这件装备已经是顶级了。
com.ylmf.DBusGlib.conf这个文件是dbus服务的配置文件。如果我们需要添加了新的对象。要在里面配置一个新的路径。这个路径的作用是跟namespace的作用一样的。这里约定用com.ylmf.dbus.xxxx来命名。也就是说,如果你只是添加了一个对象。这个文件只用添加一行。说明路径就好了。
ylmf-dbus-global-defines.h用来宏定义的公共文件,每一个对象要定义两个东西。一个是object path,一个是object interface。也只有一个地方用到在main函数里面注册。注意,这里的object path要跟com.ylmf.DBusGlib.conf里面的path一样哦。
service-main.c就是我们ylmfdbus的main。很简单,自身只带了一个注册函数。
Makefile。每当我们新写了一个object。要相应的想里面添加内容。后面会详细说明。
 
文件policykit-ylmf.c是验证函数的实现,在我们注册的GOboject类里面,我们只用在开头#include policykit-ylmf.h调用里面的check_auth()方法就ok了。
com.ylmf.PolicyKit.policy这个文件是公共的权限说明文件。在它里面定义了你每一个动作(action)的id,说明,消息,权限等等信息。本来可以都用一个。但是为了代码的易懂。希望每一个函数都对应一个动作(action)。
 
 
以上是我们ylmfdbus已经有的装备。现在,我们来看怎么要写一个自己的object并且注册进去。
普通的gobject一般只用头文件和c文件。我们要写一个能注册到ylmfdbus里面的gobject需要多一些的内容。多出两个文件。一个xml用来描述方法然后通过dbus-binding-tool转换成一个xxx-glue.h约定的头文件。一个list文件通过glib-genmarshal来生成一个xxx-marshal.c文件,用来连接gobject的信号类型的c文件。
接下来说说gobject文件里面多的东西。
一个完整最小的类(hello world)应该包含以下东西:
/* helloworld.h */
#ifndef __HELLO_WORLD_H_
#define __HELLO_WORLD_H_

#include <glib-object.h>


G_BEGIN_DECLS

#define HELLO_WORLD_TYPE                  (hello_world_get_type())
#define HELLO_WORLD(o)                    (G_TYPE_CHECK_INSTANCE_CAST((o),HELLO_WORLD_TYPE,HelloWorld))
#define HELLO_WORLD_CLASS(o)              (G_TYPE_CHECK_CLASS_CAST((o),HELLO_WORLD_TYPE,HelloWorldClass))
#define HELLO_WORLD_GET_CLASS(o)          (G_TYPE_INSTANCE_GET_CLASS ((o), HELLO_WORLD_TYPE, HelloWorldClass))
#define IS_HELLO_WORLD(o)                 (G_TYPE_CHECK_INSTANCE_TYPE ((o), HELLO_WORLD_TYPE))
#define IS_HELLO_WORLD_CLASS(o)           (G_TYPE_CHECK_CLASS_TYPE ((o), HELLO_WORLD_TYPE))


typedef struct _HelloWorld HelloWorld;
typedef struct _HelloWorldClass HelloWorldClass;

struct _HelloWorld
{
    GObject parent;

};

struct _HelloWorldClass
{
    GObjectClass parent_class;

};


GType
hello_world_get_type(void);


G_END_DECLS


#endif //__HELLO_WORLD_H_
 
 
/* helloworld.c */
#ifdef HAVE_CONFIG_H
#   include <config.h>
#endif

#include <glib.h>

#include "helloworld.h"


static void
hello_world_finalize(GObject        *object);

static GObject*
hello_world_constructor(GType                  type,
                guint                  n_construct_properties,
                GObjectConstructParam *construct_properties);



G_DEFINE_TYPE(HelloWorld,hello_world,G_TYPE_OBJECT)


static void
hello_world_class_init(HelloWorldClass *klass)
{
    GObjectClass *object_class= G_OBJECT_CLASS(klass);

    object_class->constructor = hello_world_constructor;
    object_class->finalize = hello_world_finalize;
}


static void
hello_world_init(HelloWorld *objname)
{
}


static GObject*
hello_world_constructor(GType                  type,
                guint                  n_construct_properties,
                GObjectConstructParam *construct_properties)
{
    GObject *object;
    HelloWorld *objname;
    object = G_OBJECT_CLASS(hello_world_parent_class)->constructor(
                                    type,
                                    n_construct_properties,
                                    construct_properties);
    objname = HELLO_WORLD(object);
    return object;
}


static void
hello_world_finalize(GObject        *object)
{
    HelloWorld *objname;
    objname = HELLO_WORLD(object);
    if(G_OBJECT_CLASS(hello_world_parent_class)->finalize){
       G_OBJECT_CLASS(hello_world_parent_class)->finalize(object);
    }
}


HelloWorld*
hello_world_new(void)
{
    return HELLO_WORLD(g_object_new(HELLO_WORLD_TYPE,NULL));
}
 
 
 
我们应该注意到我们的helloworld类的有一个统一的前缀"hello_world"这个很重要。在我们用dbus-binding-tool和glib-genmarshal工具来自动生成代码的时候加参数的时候要是一样的。其次是描述接口的xml文件中标签<method name="">这里填写的是方法名的后缀。开头用大写。然后自己要在类里面实现这个方法。这个是基本的一个GObject对象,我们可以在后面写其他的方法了。在写其他方法的时候,我们必需要注意每一个方法有两个参数是固定的。第一个参数是这个对象本身的指针,最后一个参数是DBusGMethodInvocation类型的指针,这两个参数必须有。如果有其他的输入输出函数则需要在描述接口的xml文件中进行描述,描述接口的xml文件中每一个方法必须添加 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
 
例子:在xml里面写的是HelloWorld 然后前缀是ylmf_xxxx  生成的xxx-glue.h文件里面的方法名就是ylmf_xxxx_hello_world。
dbus-binding-tool --prefix= --mode=glib-server --output=xxx-glue.h xxx.xml
dbus-binding-tool --prefix=auto_login --mode-glib-server --output=auto-login-glue.h login.xml
 
然后在我们的类的c文件里面需要include xxxx-glue.h文件的时候。注意不要写到文件开头。要写到函数定义完实现具体函数前.
 
最后需要注意的地方 是我们在xxxx__class_init方法里面需要添加 dbus_g_object_type_install_info函数用来在注册的时候使得dbus认识这个object
 
如果每一个方法中有首先第一个传入参数必须是这个类本身,然后后面跟入需要传入的参数,并且在xml文件里面描述。如果需要返回,最好传入DBusGMethodInvocation这个类型。然后调用dbus_g_method_return来进行函数的调用
 
 
下载地址
http://u.115.com/file/clfvkwwz#Downloadhelloworlddbus.tar.gz