Adding username to all restconf backend calls

This commit is contained in:
Olof hagsand 2018-02-13 09:17:32 +07:00
parent 36d310de88
commit 278f3de840
7 changed files with 115 additions and 82 deletions

View file

@ -654,13 +654,13 @@ compare_dbs(clicon_handle h,
astext = cv_int32_get(cvec_i(argv, 0)); astext = cv_int32_get(cvec_i(argv, 0));
else else
astext = 0; astext = 0;
if (clicon_rpc_get_config(h, "running", "/", &xc1) < 0) if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
goto done; goto done;
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
if (clicon_rpc_get_config(h, "candidate", "/", &xc2) < 0) if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
goto done; goto done;
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
@ -827,7 +827,7 @@ save_config_file(clicon_handle h,
goto done; goto done;
} }
filename = cv_string_get(cv); filename = cv_string_get(cv);
if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0) if (clicon_rpc_get_config(h, dbstr,"/", NULL, &xt) < 0)
goto done; goto done;
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
@ -1171,7 +1171,7 @@ cli_copy_config(clicon_handle h,
cprintf(cb, xpath, keyname, fromname); cprintf(cb, xpath, keyname, fromname);
/* Get from object configuration and store in x1 */ /* Get from object configuration and store in x1 */
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0) if (clicon_rpc_get_config(h, db, cbuf_get(cb), NULL, &x1) < 0)
goto done; goto done;
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){ if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);

View file

@ -156,7 +156,7 @@ expand_dbvar(void *h,
goto done; goto done;
/* XXX read whole configuration, why not send xpath? */ /* XXX read whole configuration, why not send xpath? */
if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0) if (clicon_rpc_get_config(h, dbstr, "/", NULL, &xt) < 0)
goto done; goto done;
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
@ -484,7 +484,7 @@ cli_show_config(clicon_handle h,
else else
cprintf(cbxpath, "%s", xpath); cprintf(cbxpath, "%s", xpath);
/* Get configuration from database */ /* Get configuration from database */
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), &xt) < 0) if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), NULL, &xt) < 0)
goto done; goto done;
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
@ -568,7 +568,7 @@ show_conf_xpath(clicon_handle h,
} }
cv = cvec_find_var(cvv, "xpath"); cv = cvec_find_var(cvv, "xpath");
xpath = cv_string_get(cv); xpath = cv_string_get(cv);
if (clicon_rpc_get_config(h, str, xpath, &xt) < 0) if (clicon_rpc_get_config(h, str, xpath, NULL, &xt) < 0)
goto done; goto done;
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);

View file

@ -89,7 +89,8 @@
* @param[in] pcvec Vector of path ie DOCUMENT_URI element * @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec * @param[in] pi Offset, where to start pcvec
* @param[in] qvec Vector of query string (QUERY_STRING) * @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] dvec Stream input data * @param[in] dvec Stream input daat
* @param[in] username Authenticated user
*/ */
static int static int
api_data(clicon_handle h, api_data(clicon_handle h,
@ -98,7 +99,8 @@ api_data(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *data) char *data,
char *username)
{ {
int retval = -1; int retval = -1;
char *request_method; char *request_method;
@ -109,17 +111,17 @@ api_data(clicon_handle h,
if (strcmp(request_method, "OPTIONS")==0) if (strcmp(request_method, "OPTIONS")==0)
retval = api_data_options(h, r); retval = api_data_options(h, r);
else if (strcmp(request_method, "HEAD")==0) else if (strcmp(request_method, "HEAD")==0)
retval = api_data_head(h, r, pcvec, pi, qvec); retval = api_data_head(h, r, pcvec, pi, qvec, username);
else if (strcmp(request_method, "GET")==0) else if (strcmp(request_method, "GET")==0)
retval = api_data_get(h, r, pcvec, pi, qvec); retval = api_data_get(h, r, pcvec, pi, qvec, username);
else if (strcmp(request_method, "POST")==0) else if (strcmp(request_method, "POST")==0)
retval = api_data_post(h, r, api_path, pcvec, pi, qvec, data); retval = api_data_post(h, r, api_path, pcvec, pi, qvec, data, username);
else if (strcmp(request_method, "PUT")==0) else if (strcmp(request_method, "PUT")==0)
retval = api_data_put(h, r, api_path, pcvec, pi, qvec, data); retval = api_data_put(h, r, api_path, pcvec, pi, qvec, data, username);
else if (strcmp(request_method, "PATCH")==0) else if (strcmp(request_method, "PATCH")==0)
retval = api_data_patch(h, r, api_path, pcvec, pi, qvec, data); retval = api_data_patch(h, r, api_path, pcvec, pi, qvec, data, username);
else if (strcmp(request_method, "DELETE")==0) else if (strcmp(request_method, "DELETE")==0)
retval = api_data_delete(h, r, api_path, pi); retval = api_data_delete(h, r, api_path, pi, username);
else else
retval = notfound(r); retval = notfound(r);
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
@ -152,7 +154,7 @@ api_operations(clicon_handle h,
request_method = FCGX_GetParam("REQUEST_METHOD", r->envp); request_method = FCGX_GetParam("REQUEST_METHOD", r->envp);
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method); clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
if (strcmp(request_method, "GET")==0) if (strcmp(request_method, "GET")==0)
retval = api_operation_get(h, r, path, pcvec, pi, qvec, data); retval = api_operation_get(h, r, path, pcvec, pi, qvec, data, username);
else if (strcmp(request_method, "POST")==0) else if (strcmp(request_method, "POST")==0)
retval = api_operation_post(h, r, path, pcvec, pi, qvec, data, username); retval = api_operation_post(h, r, path, pcvec, pi, qvec, data, username);
else else
@ -335,7 +337,7 @@ api_restconf(clicon_handle h,
goto done; goto done;
} }
else if (strcmp(method, "data") == 0){ /* restconf, skip /api/data */ else if (strcmp(method, "data") == 0){ /* restconf, skip /api/data */
if (api_data(h, r, path, pcvec, 2, qvec, data) < 0) if (api_data(h, r, path, pcvec, 2, qvec, data, username) < 0)
goto done; goto done;
} }
else if (strcmp(method, "operations") == 0){ /* rpc */ else if (strcmp(method, "operations") == 0){ /* rpc */

View file

@ -218,6 +218,7 @@ api_data_get2(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *username,
int head) int head)
{ {
int retval = -1; int retval = -1;
@ -252,7 +253,7 @@ api_data_get2(clicon_handle h,
} }
path = cbuf_get(cbpath); path = cbuf_get(cbpath);
clicon_debug(1, "%s path:%s", __FUNCTION__, path); clicon_debug(1, "%s path:%s", __FUNCTION__, path);
if (clicon_rpc_get(h, path, &xret) < 0){ if (clicon_rpc_get(h, path, username, &xret) < 0){
notfound(r); notfound(r);
goto ok; goto ok;
} }
@ -341,9 +342,10 @@ api_data_head(clicon_handle h,
FCGX_Request *r, FCGX_Request *r,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec) cvec *qvec,
char *username)
{ {
return api_data_get2(h, r, pcvec, pi, qvec, 1); return api_data_get2(h, r, pcvec, pi, qvec, username, 1);
} }
/*! REST GET method /*! REST GET method
@ -374,9 +376,10 @@ api_data_get(clicon_handle h,
FCGX_Request *r, FCGX_Request *r,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec) cvec *qvec,
char *username)
{ {
return api_data_get2(h, r, pcvec, pi, qvec, 0); return api_data_get2(h, r, pcvec, pi, qvec, username, 0);
} }
/*! Generic REST POST method /*! Generic REST POST method
@ -412,7 +415,8 @@ api_data_post(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *data) char *data,
char *username)
{ {
int retval = -1; int retval = -1;
enum operation_type op = OP_CREATE; enum operation_type op = OP_CREATE;
@ -425,6 +429,7 @@ api_data_post(clicon_handle h,
yang_node *y = NULL; yang_node *y = NULL;
yang_spec *yspec; yang_spec *yspec;
cxobj *xa; cxobj *xa;
cxobj *xu;
char *media_content_type; char *media_content_type;
int parse_xml = 0; /* By default expect and parse JSON */ int parse_xml = 0; /* By default expect and parse JSON */
@ -446,6 +451,16 @@ api_data_post(clicon_handle h,
goto done; goto done;
/* Translate api_path to xtop/xbot */ /* Translate api_path to xtop/xbot */
xbot = xtop; xbot = xtop;
/* For internal XML protocol: add username attribute for backend access control
*/
if (username){
if ((xu = xml_new("username", xtop, NULL)) == NULL)
goto done;
xml_type_set(xu, CX_ATTR);
if (xml_value_set(xu, username) < 0)
goto done;
}
if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0) if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0)
goto done; goto done;
/* Parse input data as json or xml into xml */ /* Parse input data as json or xml into xml */
@ -589,7 +604,8 @@ api_data_put(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *data) char *data,
char *username)
{ {
int retval = -1; int retval = -1;
enum operation_type op = OP_REPLACE; enum operation_type op = OP_REPLACE;
@ -603,6 +619,7 @@ api_data_put(clicon_handle h,
yang_node *y = NULL; yang_node *y = NULL;
yang_spec *yspec; yang_spec *yspec;
cxobj *xa; cxobj *xa;
cxobj *xu;
char *media_content_type; char *media_content_type;
int parse_xml = 0; /* By default expect and parse JSON */ int parse_xml = 0; /* By default expect and parse JSON */
char *api_path; char *api_path;
@ -625,6 +642,15 @@ api_data_put(clicon_handle h,
goto done; goto done;
/* Translate api_path to xtop/xbot */ /* Translate api_path to xtop/xbot */
xbot = xtop; xbot = xtop;
/* For internal XML protocol: add username attribute for backend access control
*/
if (username){
if ((xu = xml_new("username", xtop, NULL)) == NULL)
goto done;
xml_type_set(xu, CX_ATTR);
if (xml_value_set(xu, username) < 0)
goto done;
}
if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0) if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0)
goto done; goto done;
/* Parse input data as json or xml into xml */ /* Parse input data as json or xml into xml */
@ -732,7 +758,8 @@ api_data_patch(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *data) char *data,
char *username)
{ {
notimplemented(r); notimplemented(r);
return 0; return 0;
@ -751,13 +778,15 @@ int
api_data_delete(clicon_handle h, api_data_delete(clicon_handle h,
FCGX_Request *r, FCGX_Request *r,
char *api_path, char *api_path,
int pi) int pi,
char *username)
{ {
int retval = -1; int retval = -1;
int i; int i;
cxobj *xtop = NULL; /* xpath root */ cxobj *xtop = NULL; /* xpath root */
cxobj *xbot = NULL; cxobj *xbot = NULL;
cxobj *xa; cxobj *xa;
cxobj *xu;
cbuf *cbx = NULL; cbuf *cbx = NULL;
yang_node *y = NULL; yang_node *y = NULL;
yang_spec *yspec; yang_spec *yspec;
@ -774,6 +803,15 @@ api_data_delete(clicon_handle h,
if ((xtop = xml_new("config", NULL, NULL)) == NULL) if ((xtop = xml_new("config", NULL, NULL)) == NULL)
goto done; goto done;
xbot = xtop; xbot = xtop;
/* For internal XML protocol: add username attribute for backend access control
*/
if (username){
if ((xu = xml_new("username", xtop, NULL)) == NULL)
goto done;
xml_type_set(xu, CX_ATTR);
if (xml_value_set(xu, username) < 0)
goto done;
}
if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0) if (api_path && api_path2xml(api_path, yspec, xtop, 0, &xbot, &y) < 0)
goto done; goto done;
if ((xa = xml_new("operation", xbot, NULL)) == NULL) if ((xa = xml_new("operation", xbot, NULL)) == NULL)
@ -822,8 +860,10 @@ api_operation_get(clicon_handle h,
cvec *pcvec, cvec *pcvec,
int pi, int pi,
cvec *qvec, cvec *qvec,
char *data) char *data,
char *username)
{ {
notimplemented(r);
return 0; return 0;
} }
@ -837,8 +877,6 @@ api_operation_get(clicon_handle h,
* @note We map post to edit-config create. * @note We map post to edit-config create.
POST {+restconf}/operations/<operation> POST {+restconf}/operations/<operation>
*/ */
int int
api_operation_post(clicon_handle h, api_operation_post(clicon_handle h,
@ -907,6 +945,16 @@ api_operation_post(clicon_handle h,
if ((xtop = xml_new("rpc", NULL, NULL)) == NULL) if ((xtop = xml_new("rpc", NULL, NULL)) == NULL)
goto done; goto done;
xbot = xtop; xbot = xtop;
/* For internal XML protocol: add username attribute for backend access control
*/
if (username){
if ((xa = xml_new("username", xtop, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, username) < 0)
goto done;
}
/* XXX: something strange for rpc user */ /* XXX: something strange for rpc user */
if (api_path2xml(oppath, yspec, xtop, 1, &xbot, &y) < 0) if (api_path2xml(oppath, yspec, xtop, 1, &xbot, &y) < 0)
goto done; goto done;
@ -951,34 +999,6 @@ api_operation_post(clicon_handle h,
} }
} }
} }
/* Non-standard: add username attribute for backend ACM (RFC 6536)
*
*/
if (username){
if ((xa = xml_new("username", xtop, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, username) < 0)
goto done;
}
#ifdef obsolete
{
cxobj *xa;
char *cookie;
char *cookieval = NULL;
if ((cookie = FCGX_GetParam("HTTP_COOKIE", r->envp)) != NULL &&
get_user_cookie(cookie, "c-user", &cookieval) ==0){
if ((xa = xml_new("id", xtop, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, cookieval) < 0)
goto done;
if (cookieval)
free(cookieval);
}
}
#endif
/* Send to backend */ /* Send to backend */
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
goto done; goto done;

View file

@ -46,23 +46,24 @@
*/ */
int api_data_options(clicon_handle h, FCGX_Request *r); int api_data_options(clicon_handle h, FCGX_Request *r);
int api_data_head(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi, int api_data_head(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi,
cvec *qvec); cvec *qvec, char *username);
int api_data_get(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi, int api_data_get(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi,
cvec *qvec); cvec *qvec, char *username);
int api_data_post(clicon_handle h, FCGX_Request *r, char *api_path, int api_data_post(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi, cvec *pcvec, int pi,
cvec *qvec, char *data); cvec *qvec, char *data, char *username);
int api_data_put(clicon_handle h, FCGX_Request *r, char *api_path, int api_data_put(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi, cvec *pcvec, int pi,
cvec *qvec, char *data); cvec *qvec, char *data, char *username);
int api_data_patch(clicon_handle h, FCGX_Request *r, char *api_path, int api_data_patch(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi, cvec *pcvec, int pi,
cvec *qvec, char *data); cvec *qvec, char *data, char *username);
int api_data_delete(clicon_handle h, FCGX_Request *r, char *api_path, int pi); int api_data_delete(clicon_handle h, FCGX_Request *r, char *api_path, int pi,
char *username);
int api_operation_get(clicon_handle h, FCGX_Request *r, int api_operation_get(clicon_handle h, FCGX_Request *r,
char *path, char *path,
cvec *pcvec, int pi, cvec *qvec, char *data); cvec *pcvec, int pi, cvec *qvec, char *data, char *username);
int api_operation_post(clicon_handle h, FCGX_Request *r, int api_operation_post(clicon_handle h, FCGX_Request *r,
char *path, char *path,

View file

@ -45,14 +45,14 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp); int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp); int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
int clicon_rpc_generate_error(char *format, cxobj *xerr); int clicon_rpc_generate_error(char *format, cxobj *xerr);
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret); int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *username, cxobj **xret);
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op, int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
char *xml); char *xml);
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2); int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
int clicon_rpc_delete_config(clicon_handle h, char *db); int clicon_rpc_delete_config(clicon_handle h, char *db);
int clicon_rpc_lock(clicon_handle h, char *db); int clicon_rpc_lock(clicon_handle h, char *db);
int clicon_rpc_unlock(clicon_handle h, char *db); int clicon_rpc_unlock(clicon_handle h, char *db);
int clicon_rpc_get(clicon_handle h, char *xpath, cxobj **xret); int clicon_rpc_get(clicon_handle h, char *xpath, char *username, cxobj **xret);
int clicon_rpc_close_session(clicon_handle h); int clicon_rpc_close_session(clicon_handle h);
int clicon_rpc_kill_session(clicon_handle h, int session_id); int clicon_rpc_kill_session(clicon_handle h, int session_id);
int clicon_rpc_validate(clicon_handle h, char *db); int clicon_rpc_validate(clicon_handle h, char *db);

View file

@ -236,6 +236,7 @@ clicon_rpc_generate_error(char *format,
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] db Name of database * @param[in] db Name of database
* @param[in] xpath XPath (or "") * @param[in] xpath XPath (or "")
* @param[in] username Authenticated user (extra attribute)
* @param[out] xt XML tree. Free with xml_free. * @param[out] xt XML tree. Free with xml_free.
* Either <config> or <rpc-error>. * Either <config> or <rpc-error>.
* @retval 0 OK * @retval 0 OK
@ -257,6 +258,7 @@ int
clicon_rpc_get_config(clicon_handle h, clicon_rpc_get_config(clicon_handle h,
char *db, char *db,
char *xpath, char *xpath,
char *username,
cxobj **xt) cxobj **xt)
{ {
int retval = -1; int retval = -1;
@ -267,7 +269,10 @@ clicon_rpc_get_config(clicon_handle h,
if ((cb = cbuf_new()) == NULL) if ((cb = cbuf_new()) == NULL)
goto done; goto done;
cprintf(cb, "<rpc><get-config><source><%s/></source>", db); cprintf(cb, "<rpc");
if (username)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, "><get-config><source><%s/></source>", db);
if (xpath && strlen(xpath)) if (xpath && strlen(xpath))
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath); cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
cprintf(cb, "</get-config></rpc>"); cprintf(cb, "</get-config></rpc>");
@ -485,6 +490,7 @@ clicon_rpc_unlock(clicon_handle h,
/*! Get database configuration and state data /*! Get database configuration and state data
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] xpath XPath (or "") * @param[in] xpath XPath (or "")
* @param[in] username Authenticated user (extra attribute)
* @param[out] xt XML tree. Free with xml_free. * @param[out] xt XML tree. Free with xml_free.
* Either <config> or <rpc-error>. * Either <config> or <rpc-error>.
* @retval 0 OK * @retval 0 OK
@ -505,6 +511,7 @@ clicon_rpc_unlock(clicon_handle h,
int int
clicon_rpc_get(clicon_handle h, clicon_rpc_get(clicon_handle h,
char *xpath, char *xpath,
char *username,
cxobj **xt) cxobj **xt)
{ {
int retval = -1; int retval = -1;
@ -515,7 +522,10 @@ clicon_rpc_get(clicon_handle h,
if ((cb = cbuf_new()) == NULL) if ((cb = cbuf_new()) == NULL)
goto done; goto done;
cprintf(cb, "<rpc><get>"); cprintf(cb, "<rpc");
if (username)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, "><get>");
if (xpath && strlen(xpath)) if (xpath && strlen(xpath))
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath); cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
cprintf(cb, "</get></rpc>"); cprintf(cb, "</get></rpc>");