diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 0fd9fad6..97b0ae79 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -1095,8 +1095,8 @@ from_client(int s,
goto done;
retval = 0;
done:
+ clicon_debug(1, "%s retval=%d", __FUNCTION__, retval);
if (msg)
free(msg);
- clicon_debug(1, "%s retval=%d", __FUNCTION__, retval);
return retval; /* -1 here terminates backend */
}
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index c8b49512..15c868ca 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -148,7 +148,60 @@ restconf_code2reason(int code)
return clicon_int2str(http_reason_phrase_map, code);
}
-/*!
+/*! HTTP error 400
+ * @param[in] r Fastcgi request handle
+ */
+int
+badrequest(FCGX_Request *r)
+{
+ char *path;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ path = FCGX_GetParam("DOCUMENT_URI", r->envp);
+ FCGX_FPrintF(r->out, "Status: 400\r\n"); /* 400 bad request */
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "
Clixon Bad request/h1>\n");
+ FCGX_FPrintF(r->out, "The requested URL %s or data is in some way badly formed.\n",
+ path);
+ return 0;
+}
+
+/*! HTTP error 401
+ * @param[in] r Fastcgi request handle
+ */
+int
+unauthorized(FCGX_Request *r)
+{
+ char *path;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ path = FCGX_GetParam("DOCUMENT_URI", r->envp);
+ FCGX_FPrintF(r->out, "Status: 401\r\n"); /* 401 unauthorized */
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "access-denied\n");
+ FCGX_FPrintF(r->out, "The requested URL %s was unauthorized.\n", path);
+ return 0;
+}
+
+/*! HTTP error 403
+ * @param[in] r Fastcgi request handle
+ */
+int
+forbidden(FCGX_Request *r)
+{
+ char *path;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ path = FCGX_GetParam("DOCUMENT_URI", r->envp);
+ FCGX_FPrintF(r->out, "Status: 403\r\n"); /* 403 forbidden */
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "Grideye Forbidden
\n");
+ FCGX_FPrintF(r->out, "The requested URL %s was forbidden.\n", path);
+ return 0;
+}
+
+/*! HTTP error 404
+ * @param[in] r Fastcgi request handle
*/
int
notfound(FCGX_Request *r)
@@ -165,31 +218,9 @@ notfound(FCGX_Request *r)
return 0;
}
-int
-badrequest(FCGX_Request *r)
-{
- char *path;
-
- clicon_debug(1, "%s", __FUNCTION__);
- path = FCGX_GetParam("DOCUMENT_URI", r->envp);
- FCGX_FPrintF(r->out, "Status: 400\r\n"); /* 400 bad request */
- FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
- FCGX_FPrintF(r->out, "Clixon Bad request/h1>\n");
- FCGX_FPrintF(r->out, "The requested URL %s or data is in some way badly formed.\n",
- path);
- return 0;
-}
-
-int
-notimplemented(FCGX_Request *r)
-{
- clicon_debug(1, "%s", __FUNCTION__);
- FCGX_FPrintF(r->out, "Status: 501\r\n");
- FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
- FCGX_FPrintF(r->out, "Not Implemented/h1>\n");
- return 0;
-}
-
+/*! HTTP error 409
+ * @param[in] r Fastcgi request handle
+ */
int
conflict(FCGX_Request *r)
{
@@ -200,6 +231,35 @@ conflict(FCGX_Request *r)
return 0;
}
+/*! HTTP error 500
+ * @param[in] r Fastcgi request handle
+ */
+int
+internal_server_error(FCGX_Request *r)
+{
+ char *path;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ path = FCGX_GetParam("DOCUMENT_URI", r->envp);
+ FCGX_FPrintF(r->out, "Status: 500\r\n"); /* 500 internal server error */
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "Grideye Internal server error when accessing %s
\n", path);
+ return 0;
+}
+
+/*! HTTP error 501
+ * @param[in] r Fastcgi request handle
+ */
+int
+notimplemented(FCGX_Request *r)
+{
+ clicon_debug(1, "%s", __FUNCTION__);
+ FCGX_FPrintF(r->out, "Status: 501\r\n");
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "Not Implemented/h1>\n");
+ return 0;
+}
+
/*! Specialization of clicon_debug with xml tree */
int
clicon_debug_xml(int dbglevel,
@@ -329,7 +389,10 @@ restconf_plugin_load(clicon_handle h)
(int)strlen(filename), filename);
if ((handle = plugin_load(h, filename, RTLD_NOW)) == NULL)
goto quit;
- _credentials_fn = dlsym(handle, PLUGIN_CREDENTIALS);
+ if ((_credentials_fn = dlsym(handle, PLUGIN_CREDENTIALS)) == NULL)
+ clicon_debug(1, "Failed to load %s", PLUGIN_CREDENTIALS);
+ else
+ clicon_debug(1, "%s callback loaded", PLUGIN_CREDENTIALS);
if ((plugins = realloc(plugins, (nplugins+1) * sizeof (*plugins))) == NULL) {
clicon_err(OE_UNIX, errno, "realloc");
goto quit;
@@ -383,6 +446,14 @@ restconf_plugin_start(clicon_handle h,
return 0;
}
+/*! Run the restconf user-defined credentials callback if present
+ * The callback is expected to return the authenticated user, or NULL if not
+ * authenticasted.
+ * If no callback exists, return user "none"
+ * @param[in] h Clicon handle
+ * @param[in] r Fastcgi request handle
+ * @param[out] user The authenticated user (or NULL). Malloced, must be freed.
+ */
int
restconf_credentials(clicon_handle h,
FCGX_Request *r,
@@ -397,13 +468,14 @@ restconf_credentials(clicon_handle h,
clicon_err(OE_XML, errno, "strdup");
goto done;
}
- retval = 0;
- goto done;
+ goto ok;
}
if (_credentials_fn(h, r, user) < 0)
- user = NULL;
+ *user = NULL;
+ ok:
retval = 0;
done:
+ clicon_debug(1, "%s retval:%d user:%s", __FUNCTION__, retval, *user);
return retval;
}
diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h
index 271207ff..59e381f4 100644
--- a/apps/restconf/restconf_lib.h
+++ b/apps/restconf/restconf_lib.h
@@ -45,10 +45,15 @@
*/
int restconf_err2code(char *tag);
const char *restconf_code2reason(int code);
-int notfound(FCGX_Request *r);
+
int badrequest(FCGX_Request *r);
-int notimplemented(FCGX_Request *r);
+int unauthorized(FCGX_Request *r);
+int forbidden(FCGX_Request *r);
+int notfound(FCGX_Request *r);
int conflict(FCGX_Request *r);
+int internal_server_error(FCGX_Request *r);
+int notimplemented(FCGX_Request *r);
+
int clicon_debug_xml(int dbglevel, char *str, cxobj *cx);
int test(FCGX_Request *r, int dbg);
cbuf *readdata(FCGX_Request *r);
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index b0216204..54b422ed 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -317,27 +317,37 @@ api_restconf(clicon_handle h,
if (str2cvec(data, '&', '=', &dvec) < 0)
goto done;
- retval = 0;
test(r, 1);
/* If present, check credentials. See "plugin_credentials" in plugin
* See RFC 8040 section 2.5
*/
if (restconf_credentials(h, r, &username) < 0)
goto done;
+ clicon_debug(1, "%s username:%s", __FUNCTION__, username);
clicon_debug(1, "%s credentials ok username:%s (should be non-NULL)",
__FUNCTION__, username);
- if (username == NULL)
- goto done;
- if (strcmp(method, "yang-library-version")==0)
- retval = api_yang_library_version(h, r);
- else if (strcmp(method, "data") == 0) /* restconf, skip /api/data */
- retval = api_data(h, r, path, pcvec, 2, qvec, data);
- else if (strcmp(method, "operations") == 0) /* rpc */
- retval = api_operations(h, r, path, pcvec, 2, qvec, data, username);
+ if (username == NULL){
+ unauthorized(r);
+ goto ok;
+ }
+ if (strcmp(method, "yang-library-version")==0){
+ if (api_yang_library_version(h, r) < 0)
+ goto done;
+ }
+ else if (strcmp(method, "data") == 0){ /* restconf, skip /api/data */
+ if (api_data(h, r, path, pcvec, 2, qvec, data) < 0)
+ goto done;
+ }
+ else if (strcmp(method, "operations") == 0){ /* rpc */
+ if (api_operations(h, r, path, pcvec, 2, qvec, data, username) < 0)
+ goto done;
+ }
else if (strcmp(method, "test") == 0)
- retval = test(r, 0);
+ test(r, 0);
else
- retval = notfound(r);
+ notfound(r);
+ ok:
+ retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (pvec)
diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index 0248ee7b..6be25d41 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -906,8 +906,17 @@ api_operation_post(clicon_handle h,
if ((xtop = xml_new("rpc", NULL, NULL)) == NULL)
goto done;
xbot = xtop;
+ /* XXX: something strange for rpc user */
if (api_path2xml(oppath, yspec, xtop, 1, &xbot, &y) < 0)
goto done;
+#if 1
+ {
+ cbuf *c = cbuf_new();
+ clicon_xml2cbuf(c, xtop, 0, 0);
+ clicon_debug(1, "%s xinput:%s", __FUNCTION__, cbuf_get(c));
+ cbuf_free(c);
+ }
+#endif
if (data && strlen(data)){
/* Parse input data as json or xml into xml */
if (parse_xml){
diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c
index dd913329..105b8661 100644
--- a/lib/src/clixon_xml_map.c
+++ b/lib/src/clixon_xml_map.c
@@ -1500,11 +1500,9 @@ api_path2xml_vec(char **vec,
name = local;
}
if (y0->yn_keyword == Y_SPEC){ /* top-node */
- clicon_debug(1, "%s 1 %s", __FUNCTION__, name);
y = yang_find_topnode((yang_spec*)y0, name, schemanode);
}
else {
- clicon_debug(1, "%s 2 %s", __FUNCTION__, name);
y = schemanode?yang_find_schemanode((yang_node*)y0, name):
yang_find_datanode((yang_node*)y0, name);
}
@@ -1593,7 +1591,6 @@ api_path2xml_vec(char **vec,
* @param[in] schemanode If set use schema nodes otherwise data nodes.
* @param[out] xbotp Resulting xml tree (end of xpath)
* @param[out] ybotp Yang spec matching xbotp
- * @see api_path2xml_vec
* @example
* api_path: /subif-entry=foo/subid
* xtop[in]
@@ -1602,6 +1599,7 @@ api_path2xml_vec(char **vec,
*
* xbotp:
* ybotp: Y_LEAF subid
+ * @see api_path2xml_vec
*/
int
api_path2xml(char *api_path,
@@ -1615,7 +1613,6 @@ api_path2xml(char *api_path,
char **vec = NULL;
int nvec;
- clicon_debug(1, "%s 0", __FUNCTION__);
if (*api_path!='/'){
clicon_err(OE_DB, 0, "Invalid key: %s", api_path);
goto done;