Differences

This shows you the differences between two versions of the page.

doc:techref:ubus [2013/05/11 20:15]
jaseg
doc:techref:ubus [2014/05/27 13:42] (current)
karlp final updates on ubus-http
Line 1: Line 1:
====== ubus (OpenWrt micro bus architecture) ====== ====== ubus (OpenWrt micro bus architecture) ======
-{{page>meta:infobox:construction&noheader&nofooter&noeditbtn}}+To provide communication between various daemons and applications in OpenWrt an ubus project has been developed. It consists of few parts including daemon, library and some extra helpers.
-The code can be found via git at ''git://nbd.name/luci2/libubox.git'' or via http at [[http://nbd.name/gitweb.cgi]] .+The heart of this project is ubusd daemon. It provides interface for other daemons to register themselves as well as sending messages. For those curious, this interface is implemented using Unix socket and it uses TLV (type-length-value) messages.
-===== Command line utility =====+To simplify development of software using ubus (connecting to it) a library called libubus has been created.
-The ''ubus'' command line client allows to interact with the ''ubusd'' rpc server, below is an explanation of its commands.+Every daemon registers set of own paths under specific namespace. Every path can provide multiple procedures with various amount of arguments. Procedures can reply with a message. 
 + 
 +The code is published under LGPL 2.1 and can be found via git at ''git://nbd.name/luci2/ubus.git'' or via http at [[http://nbd.name/gitweb.cgi?p=luci2/ubus.git;a=summary]]. It's included in OpenWrt since [[https://dev.openwrt.org/changeset/28499|r28499]]. 
 + 
 +===== Command-line ubus tool ===== 
 + 
 +The ''ubus'' command line tool allows to interact with the ''ubusd'' server (with all currently registered services). It's useful for investigating/debugging registered namespaces as well as writing shell scripts. For calling procedures with parameters and returning responses it uses user-friendly JSON format. Below is an explanation of its commands.
==== list ==== ==== list ====
Line 130: Line 136:
root@uplink:~# </code> root@uplink:~# </code>
-===== Lua binding =====+===== Access to ubus over HTTP =====
-The package ''libubus-lua'' implements a simple Lua binding to the ''libubus'' library to allow for easy client connections.+There is an ''uhttpd'' plugin called ''uhttpd-mod-ubus'' that allows ''ubus'' calls using HTTP protocol. Requests have to be send to the ''/ubus'' URL (unless changed) using ''POST'' method. This interface uses [[http://www.jsonrpc.org/specification|jsonrpc v2.0]]  There are a few steps that you will need to understand.  (Documentation written while using BarrierBreaker r40831, ymmv) 
 + 
 +==== ACLs ==== 
 +While logged into via ssh, you have direct, full access to ubus.  When you're accessing the ''/ubus'' url in uhttpd however, uhttpd runs "ubus call session access '{ ubus-rpc-session, requested-object, requested-method }' and whoever is providing the ubus session.* namespace is in charge of implementing the ACL.  This happens to be ''rpcd'' at the moment, with the http-json interface, for friendly operation with browser code, but this is just one possible implmementation.  Because we're using rpcd to implement the ACLs at this time, this allows/requires (depending on your point of view) ACLs to be configured in ''/usr/share/rpcd/acl.d/*.json''.  The __names__ of the files in ''/usr/share/rpcd/acl.d/*.json'' don't matter, but the top level keys define roles.  The default acl, listed below, __only__ defines the login methods, so you can login, but you still wouldn't be able to do anything. 
 +<code> 
 +
 +        "unauthenticated": { 
 +                "description": "Access controls for unauthenticated requests", 
 +                "read": { 
 +                        "ubus": { 
 +                                "session": [ "access", "login" ] 
 +                        } 
 +                } 
 +        } 
 +
 +</code> 
 + 
 +An example of a complicated ACL, allowing quite fine grained access to different ubus modules and methods is [[http://git.openwrt.org/?p=project/luci2/ui.git;a=blob;f=luci2/share/acl.d/luci2.json|available in the Luci2 project]] 
 + 
 +An example of a "security is for suckers" config, where a "superuser" ACL group is defined, allowing unrestricted access to everything, is shown below. (This illustrates the usage of '*' definitions in the ACLs, but keep reading for better examples)  Placing this file in ''/usr/share/rpcd/acl.d/superuser.json'' will help you move forward to the next steps. 
 + 
 +<code> 
 +
 +        "superuser": { 
 +                "description": "Super user access role", 
 +                "read": { 
 +                        "ubus": { 
 +                                "*": [ "*" ] 
 +                        }, 
 +                        "uci": [ "*" ] 
 +                }, 
 +                "write": { 
 +                        "ubus": { 
 +                                "*": [ "*" ] 
 +                        }, 
 +                        "uci": [ "*" ] 
 +                } 
 +        } 
 +
 +</code> 
 + 
 +Below is an example of an ACL definition that only allows access to some specific ubus modules, rather than unrestricted access to everything. 
 +<code> 
 +
 +        "lesssuperuser": { 
 +                "description": "not quite as super user", 
 +                "read": { 
 +                        "ubus": { 
 +                                "file": [ "*" ], 
 +                                "log": [ "*" ], 
 +                                "service": [ "*" ], 
 +                        }, 
 +                }, 
 +                "write": { 
 +                        "ubus": { 
 +                                "file": [ "*" ], 
 +                                "log": [ "*" ], 
 +                                "service": [ "*" ], 
 +                        }, 
 +                } 
 +        } 
 +
 +</code> 
 + 
 +Note: Before we leave this section, you may have noticed that there's both a "ubus" and a "uci" section, even though ubus has a uci method.  The uci: scope is used for the uci api provided by rpcd 
 +to allow defining per-file permissions because using the ubus scope you can only say "uci set" is allowed or not allowed but not specify that it is allowed to e.g. modify /e/c/system but not                    /e/c/network  If your application/ACL doesn't need UCI access, you can just leave out the UCI section altogether. 
 + 
 + 
 +==== Authentication ==== 
 +Now that we have an ACL that allows operations beyond just logging in, we can actually try this out.  As mentioned, ''rpcd'' is handling this, so you need an entry in ''/etc/config/rpcd'' 
 +<code> 
 +config login 
 + option username 'root' 
 + option password '$p$root' 
 + list read '*' 
 + list write '*' 
 +</code> 
 +The ''$p'' magic means to look in ''/etc/shadow'' and the ''$root'' part means to use the password for the root user in that file.  The list of read and write sections, those map acl roles to user accounts.  You can also use ''$1$<hash>''which is a "crypt()" hash, using SHA1, exactly as used in /etc/shadow.  You can generate these with, eg, "uhhtpd -m secret" 
 + 
 + 
 +To login and receive a session id: 
 +<code> 
 +$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "call", "params": [ "00000000000000000000000000000000", "session", "login", { "username": "root", "password": "secret"  } ] }'  http://your.server.ip/ubus 
 + 
 +{"jsonrpc":"2.0","id":1,"result":[0,{"ubus_rpc_session":"c1ed6c7b025d0caca723a816fa61b668","timeout":300,"expires":299,"acls":{"access-group":{"superuser":["read","write"],"unauthenticated":["read"]},"ubus":{"*":["*"],"session":["access","login"]},"uci":{"*":["read","write"]}},"data":{"username":"root"}}]} 
 +</code> 
 + 
 +The sessionid "00000000000000000000000000000000" (32 zeros) is a special null-session which just has enough access rights for the session.login ubus call.  A session has a timeout, that is specified when you login, but has a default.  You can request a longer timeout in your initial login call, with a "timeout" key in the login parameters section. 
 + 
 + 
 +If you ever receive a response like, ''{"jsonrpc":"2.0","id":1,"result":[6]}'' That is a valid jsonrpc response, 6 is the ubus code for UBUS_STATUS_PERMISSION_DENIED  (you'll get this if you try and login before setting up the "superuser" file, or any file that gives you anymore rights than just being allowed to attempt logins. 
 + 
 +To list all active sessions, try ''ubus call session list'' 
 + 
 +==== Session management ==== 
 + 
 +A session is automatically renewned on every use.  There are plans to use these sessions even for luci1, but at present, if you use this interface in a luci1 environment, you'll need to manage sessions yourself. 
 + 
 + 
 +==== Actually making calls ==== 
 + 
 +Now that you have a ''ubus_rpc_session'' you can make calls, based on your ACLs and the available ubus services.  ''ubus list -v'' is your primary documentation on what can be done, but see the rest of this page for more information.  For example, ''ubus list file -v'' returns  
 + 
 +<code> 
 +'file' @24a6bd4a 
 + "read":{"path":"String","data":"String"} 
 + "write":{"path":"String","data":"String"} 
 + "list":{"path":"String","data":"String"} 
 + "stat":{"path":"String","data":"String"} 
 + "exec":{"command":"String","params":"Array","env":"Table"} 
 +</code> 
 + 
 +The json container format is:   
 + 
 +<code> 
 +{ "jsonrpc": "2.0", 
 +  "id": <unique-id-to-identify-request>,  
 +  "method": "call", 
 +  "params": [ 
 +            <ubus_rpc_session>, <ubus_object>, <ubus_method>,  
 +            { <ubus_arguments> } 
 +            ] 
 +
 +</code> 
 +The "id" key is merely echo'ed by the server, so it needs not be strictly unique, it's mainly intended for client software to easily correlate responses to previously made requests. It's type is either a string or a number, so it can be an sha1 hash, md5 sum, sequence counter, unix timestamp, .... 
 + 
 +An example request to read a file would be:  
 +<code> 
 +$ curl -d '{ "jsonrpc": "2.0", "id": 1, "method": "call", "params": [ "7cba69a942c0e9db1eb7982cd91f3a48", "file", "read", { "path": "/tmp/hello.karl" } ] }'  http://eg-134867.local/ubus 
 +{"jsonrpc":"2.0","id":1,"result":[0,{"data":"this is the contents of a file\n"}]} 
 +</code> 
 + 
 + 
 + 
 +===== Lua module for ubus ===== 
 + 
 +This is even possible to use ''ubus'' in ''lua'' scripts. Of course it's not possible to use native libraries directly in ''lua'', so an extra module has been created. It's simply called ''ubus'' and is a simple interface between ''lua'' scripts and the ''ubus'' (it uses ''libubus'' internally).
==== Load module ==== ==== Load module ====
Line 172: Line 314:
===== Namespaces & Procedures ===== ===== Namespaces & Procedures =====
-==== Implemented ====+As explained earlier, there can be many different daemons (services) registered in ''ubus''. Below you will find a list of the most common projects with namespaces, paths and procedures they provide.
-=== netifd ===+==== netifd ===
 + 
 +[[http://nbd.name/gitweb.cgi?p=luci2/netifd.git;a=blob;f=DESIGN|Design of netifd]]
^ Path ^ Procedure ^ Signature ^ Description ^ ^ Path ^ Procedure ^ Signature ^ Description ^
Line 189: Line 333:
| ''network.interface.//name//'' | ''remove'' | ''{ }'' | Remove interface ''//name//'' (?) | | ''network.interface.//name//'' | ''remove'' | ''{ }'' | Remove interface ''//name//'' (?) |
-=== uhttpd-mod-ubus ===+==== rpcd ==== 
 + 
 +Project ''rpcd'' is set of small plugins providing sets of ''ubus'' procedures in separated namespaces. These plugins are not strictly related to any particular software (like ''netifd'' or ''dhcp'') so it wasn't worth it to implement them as separated projects. 
 + 
 +^ Path ^ Procedure ^ Signature ^ Description ^ 
 +| ''file'' | ''read'' | ? | ? | 
 +| ''file'' | ''write'' | ? | ? | 
 +| ''file'' | ''list'' | ? | ? | 
 +| ''file'' | ''stat'' | ? | ? | 
 +| ''file'' | ''exec'' | ? | ? | 
 +\\ 
 +^ Path ^ Procedure ^ Signature ^ Description ^ 
 +| ''iwinfo'' | ''info'' | ? | ? | 
 +| ''iwinfo'' | ''scan'' | ? | ? | 
 +| ''iwinfo'' | ''assoclist'' | ? | ? | 
 +| ''iwinfo'' | ''freqlist'' | ? | ? | 
 +| ''iwinfo'' | ''txpowerlist'' | ? | ? | 
 +| ''iwinfo'' | ''countrylist'' | ? | ? |
^ Path ^ Procedure ^ Signature ^ Description ^ ^ Path ^ Procedure ^ Signature ^ Description ^
Line 198: Line 359:
| ''session'' | ''revoke'' | ''{ "session": "//sid//", | ''session'' | ''revoke'' | ''{ "session": "//sid//",
  "objects": [ [ "path", "func" ], ... ] }'' | Within the session identified by ''//sid//'' revoke access to all specified procedures ''//func//'' in the namespace ''//path//'' listed in the ''//objects//'' array. If ''//objects//'' is unset, revoke all access |   "objects": [ [ "path", "func" ], ... ] }'' | Within the session identified by ''//sid//'' revoke access to all specified procedures ''//func//'' in the namespace ''//path//'' listed in the ''//objects//'' array. If ''//objects//'' is unset, revoke all access |
 +| ''session'' | ''access'' | ? | ? |
| ''session'' | ''set'' | ''{ "session": "//sid//", | ''session'' | ''set'' | ''{ "session": "//sid//",
  "values": { "//key//": //value//, ... } }'' | Within the session identified by ''//sid//'' store the given arbitrary values under their corresponding keys specified in the ''//values//'' object |   "values": { "//key//": //value//, ... } }'' | Within the session identified by ''//sid//'' store the given arbitrary values under their corresponding keys specified in the ''//values//'' object |
Line 204: Line 366:
| ''session'' | ''unset'' | ''{ "session": "//sid//", | ''session'' | ''unset'' | ''{ "session": "//sid//",
  "keys": [ "//key//", ... ] }'' | Within the session identified by ''//sid//'' unset all keys listed in the ''//keys//'' array. If the key list is unset, clear all keys |   "keys": [ "//key//", ... ] }'' | Within the session identified by ''//sid//'' unset all keys listed in the ''//keys//'' array. If the key list is unset, clear all keys |
-| ''session'' | ''extend'' | ''{ "session": "//sid//" }'' | Within the session identified by ''//sid//'' reset inactivity timeout counter | 
| ''session'' | ''destroy'' | ''{ "session": "//sid//" }'' | Terminate the session identified by the given ID ''//sid//'' | | ''session'' | ''destroy'' | ''{ "session": "//sid//" }'' | Terminate the session identified by the given ID ''//sid//'' |
- +| ''session'' | ''login'' | ? | ? |
-==== Planned ==== +
- +
-=== LuCI2 ===+
^ Path ^ Procedure ^ Signature ^ Description ^ ^ Path ^ Procedure ^ Signature ^ Description ^
Line 283: Line 441:
  - If the option named ''//oname//'' within named section ''//sname//'' was not found: ''UBUS_STATUS_NOT_FOUND'' else: ''UBUS_STATUS_OK''   - If the option named ''//oname//'' within named section ''//sname//'' was not found: ''UBUS_STATUS_NOT_FOUND'' else: ''UBUS_STATUS_OK''
</WRAP> | </WRAP> |
 +
 +===== Example code snippets =====
 +
 +==== Check if Link is up using devstatus and Json ====
 +
 +<code>
 +#!/bin/sh
 +
 +. /usr/share/libubox/jshn.sh
 +
 +WANDEV="$(uci get network.wan.ifname)"
 +
 +json_load "$(devstatus $WANDEV)"
 +
 +json_get_var var1 speed
 +json_get_var var2 link
 +
 +echo "Speed: $var1"
 +echo "Link: $var2"
 +</code>

Back to top

doc/techref/ubus.1368296158.txt.bz2 · Last modified: 2013/05/11 20:15 by jaseg