diff --git a/CHANGELOG.md b/CHANGELOG.md index c4e9000f..4374f521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Expected: July 2023 ### C/CLI-API changes on existing features Developers may need to change their code +* Added `uid` parameter to `clixon_process_register()` * Added output function to JSON output: * `xml2json_vec(...,skiptop)` --> `xml2json_vec(..., cligen_output, skiptop)` * `yang2cli_yspec` removed last argument `printgen`. diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index 1258bfab..174d09fd 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -436,7 +436,7 @@ filter_xpath_again(clicon_handle h, return retval; } -/*! Help function for NACM access and returnmessage +/*! Help function for NACM access and return message * * @param[in] h Clicon handle * @param[in] xret Result XML tree diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c index 8bac90ad..4b4690de 100644 --- a/apps/backend/backend_plugin_restconf.c +++ b/apps/backend/backend_plugin_restconf.c @@ -314,13 +314,14 @@ restconf_pseudo_process_control(clicon_handle h) if (clixon_process_register(h, RESTCONF_PROCESS, "Clixon RESTCONF process", NULL /* XXX network namespace */, + -1, restconf_rpc_wrapper, argv, nr) < 0) goto done; - if (argv != NULL) - free(argv); retval = 0; done: + if (argv != NULL) + free(argv); if (cb) cbuf_free(cb); return retval; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 9a853b86..77809909 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -1626,3 +1626,64 @@ cvec_append(cvec *cvv0, } return cvv2; } + +/*! Process control as defined by clixon-lib API + * + * @param[in] h Clicon handle + * @param[in] cvv Not used + * @param[in] arg Two strings: + * @code + * actions-daemon("Actions daemon operations") start, + * cli_process_control("Action process", "start"); + * @endcode + */ +int +cli_process_control(clicon_handle h, + cvec *cvv, + cvec *argv) +{ + int retval = -1; + char *name; + char *opstr; + cbuf *cb = NULL; + cxobj *xret = NULL; + cxobj *xerr; + + if (cvec_len(argv) != 2){ + clicon_err(OE_PLUGIN, EINVAL, "Requires two element: process name and operation"); + goto done; + } + name = cv_string_get(cvec_i(argv, 0)); + opstr = cv_string_get(cvec_i(argv, 1)); + if (clixon_process_op_str2int(opstr) == -1){ + clicon_err(OE_UNIX, 0, "No such process op: %s", opstr); + goto done; + } + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cb, ""); + cprintf(cb, "", CLIXON_LIB_NS); + cprintf(cb, "%s", name); + cprintf(cb, "%s", opstr); + cprintf(cb, ""); + cprintf(cb, ""); + if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, NULL) < 0) + goto done; + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ + clixon_netconf_error(xerr, "Get configuration", NULL); + goto done; + } + if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 1, NULL, cligen_output, 0, 1) < 0) + goto done; + retval = 0; + done: + if (xret) + xml_free(xret); + if (cb) + cbuf_free(cb); + return retval; +} diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 444b68eb..902f8e16 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -1515,7 +1515,6 @@ cli_show_statistics(clicon_handle h, if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 1, NULL, cligen_output, 0, 1) < 0) goto done; fprintf(stdout, "CLI:\n"); - retval = 0; done: if (xret) diff --git a/apps/cli/clixon_cli_api.h b/apps/cli/clixon_cli_api.h index faa01379..63b9f70a 100644 --- a/apps/cli/clixon_cli_api.h +++ b/apps/cli/clixon_cli_api.h @@ -80,8 +80,6 @@ int cli_notification_register(clicon_handle h, char *stream, enum format_enum fo char *filter, int status, int (*fn)(int, void*), void *arg); -/* cli_common.c: CLIgen new vector callbacks */ - int mtpoint_paths(yang_stmt *yspec0, char *mtpoint, char *api_path_fmt1, char **api_path_fmt01); int dbxml_body(cxobj *xbot, cvec *cvv); int identityref_add_ns(cxobj *x, void *arg); @@ -113,6 +111,7 @@ int cli_unlock(clicon_handle h, cvec *cvv, cvec *argv); int cli_copy_config(clicon_handle h, cvec *cvv, cvec *argv); int cli_help(clicon_handle h, cvec *vars, cvec *argv); cvec *cvec_append(cvec *cvv0, cvec *cvv1); +int cli_process_control(clicon_handle h, cvec *vars, cvec *argv); /* In cli_show.c */ int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv, diff --git a/lib/clixon/clixon_proc.h b/lib/clixon/clixon_proc.h index e57adcf4..ffd54440 100644 --- a/lib/clixon/clixon_proc.h +++ b/lib/clixon/clixon_proc.h @@ -52,19 +52,25 @@ typedef enum proc_operation { PROC_OP_STATUS } proc_operation; -/* Process RPC callback function */ -typedef int (proc_cb_t)(clicon_handle h, process_entry_t *pe, proc_operation *operation); +/*! Process RPC callback function + * + * @param[in] h Clixon handle + * @param[in] pe Process entry + * @param[in,out] op Process operation + */ +typedef int (proc_cb_t)(clicon_handle h, + process_entry_t *pe, + proc_operation *operation); /* * Prototypes */ int clixon_proc_socket(char **argv, int sock_flags, pid_t *pid, int *sock); int clixon_proc_socket_close(pid_t pid, int sock); -int clixon_proc_background(char **argv, const char *netns, pid_t *pid); int clixon_process_pid(clicon_handle h, const char *name, pid_t *pid); proc_operation clixon_process_op_str2int(char *opstr); int clixon_process_argv_get(clicon_handle h, const char *name, char ***argv, int *argc); -int clixon_process_register(clicon_handle h, const char *name, const char *descr, const char *netns, proc_cb_t *callback, char **argv, int argc); +int clixon_process_register(clicon_handle h, const char *name, const char *descr, const char *netns, uid_t uid, proc_cb_t *callback, char **argv, int argc); int clixon_process_delete_all(clicon_handle h); int clixon_process_operation(clicon_handle h, const char *name, proc_operation op, const int wrapit); int clixon_process_status(clicon_handle h, const char *name, cbuf *cbret); diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 77877f70..9b860512 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -243,7 +243,7 @@ clicon_log_str(int level, char *msg) { if (_logflags & CLICON_LOG_SYSLOG) - syslog(LOG_MAKEPRI(LOG_USER, level), "%s", msg); + syslog(LOG_MAKEPRI(LOG_USER, level), "%s", msg); // XXX this may block /* syslog makes own filtering, we do it here: * if normal (not debug) then filter loglevels >= debug */ diff --git a/lib/src/clixon_netconf_input.c b/lib/src/clixon_netconf_input.c index 9a3fa89f..4163ed4e 100644 --- a/lib/src/clixon_netconf_input.c +++ b/lib/src/clixon_netconf_input.c @@ -81,7 +81,7 @@ * @param[in] buf Packet buffer * @param[in] buflen Length of packet buffer * @param[out] eof Socket closed / eof? - * @retval 0 OK + * @retval n length * @retval -1 Error */ ssize_t diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 54a816e9..691866c3 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1688,6 +1688,7 @@ netconf_db_find(cxobj *xn, * cbuf_free(cb); * @endcode * @see clixon_netconf_error_fn + * XXX does not support prefixes properly */ int netconf_err2cb(cxobj *xerr, diff --git a/lib/src/clixon_proc.c b/lib/src/clixon_proc.c index 5a40c18b..f82903a9 100644 --- a/lib/src/clixon_proc.c +++ b/lib/src/clixon_proc.c @@ -50,7 +50,8 @@ description, namespace, start arguments, etc. Starts in STOPPED state: --> STOPPED - On operation "start" or "restart" it gets a pid and goes into RUNNING state: + On operation using clixon_process_operation(): + "start" or "restart" it gets a pid and goes into RUNNING state: STOPPED -- (re)start --> RUNNING(pid) When running, several things may happen: @@ -116,6 +117,7 @@ #include "clixon_hash.h" #include "clixon_handle.h" #include "clixon_options.h" +#include "clixon_uid.h" #include "clixon_event.h" #include "clixon_sig.h" #include "clixon_string.h" @@ -143,6 +145,7 @@ struct process_entry_t { char *pe_name; /* Name of process used for internal use. Unique with exiting=0 */ char *pe_description; /* Description of service */ char *pe_netns; /* Network namespace */ + uid_t pe_uid; /* UID of process or -1 to keep same as backend */ char **pe_argv; /* argv with command as element 0 and NULL-terminated */ int pe_argc; /* Length of argc */ pid_t pe_pid; /* Running process id (state) or 0 if dead (pid is set if exiting=1) */ @@ -150,7 +153,7 @@ struct process_entry_t { proc_state_t pe_state; /* stopped, running, exiting */ pid_t pe_exit_status;/* Status on exit as defined in waitpid */ struct timeval pe_starttime; /* Start time */ - proc_cb_t *pe_callback; /* Wrapper function, may be called from process_operation */ + proc_cb_t *pe_callback; /* Wrapper function, may be called from process_operation */ }; /* Forward declaration */ @@ -261,13 +264,15 @@ clixon_proc_socket_close(pid_t pid, * * @param[in] argv NULL-terminated Argument vector * @param[in] netns Network namespace (or NULL) + * @param[in] uid User-id or -1 to keep existing * @param[out] pid Process id * @retval 0 OK * @retval -1 Error. */ -int +static int clixon_proc_background(char **argv, const char *netns, + uid_t uid, pid_t *pid0) { int retval = -1; @@ -308,10 +313,14 @@ clixon_proc_background(char **argv, char nsfile[PATH_MAX]; int nsfd; #endif - + if (uid != -1){ + if (drop_priv_perm(uid) < 0) + goto done; + } clicon_debug(1, "%s child", __FUNCTION__); clicon_signal_unblock(0); signal(SIGTSTP, SIG_IGN); + if (chdir("/") < 0){ clicon_err(OE_UNIX, errno, "chdirq"); exit(1); @@ -425,6 +434,7 @@ clixon_process_argv_get(clicon_handle h, * @param[in] name Process name * @param[in] description Description of process * @param[in] netns Namespace netspace (or NULL) + * @param[in] uid UID of process (or -1 to keep same) * @param[in] callback Wrapper function * @param[in] argv NULL-terminated vector of vectors * @param[in] argc Length of argv @@ -437,6 +447,7 @@ clixon_process_register(clicon_handle h, const char *name, const char *description, const char *netns, + const uid_t uid, proc_cb_t *callback, char **argv, int argc) @@ -470,6 +481,7 @@ clixon_process_register(clicon_handle h, clicon_err(OE_DB, errno, "strdup netns"); goto done; } + pe->pe_uid = uid; pe->pe_argc = argc; if ((pe->pe_argv = calloc(argc, sizeof(char *))) == NULL){ clicon_err(OE_UNIX, errno, "calloc"); @@ -839,7 +851,8 @@ clixon_process_sched(int fd, if (proc_op_run(pe->pe_pid, &isrunning) < 0) goto done; if (!isrunning) - if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0) + if (clixon_proc_background(pe->pe_argv, pe->pe_netns, + pe->pe_uid, &pe->pe_pid) < 0) goto done; clicon_debug(1, "%s %s(%d) %s --%s--> %s", __FUNCTION__, pe->pe_name, pe->pe_pid, @@ -864,7 +877,8 @@ clixon_process_sched(int fd, case PROC_OP_START: if (isrunning) /* Already runs */ break; - if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0) + if (clixon_proc_background(pe->pe_argv, pe->pe_netns, + pe->pe_uid, &pe->pe_pid) < 0) goto done; clicon_debug(1, "%s %s(%d) %s --%s--> %s", __FUNCTION__, pe->pe_name, pe->pe_pid, @@ -967,7 +981,8 @@ clixon_process_waitpid(clicon_handle h) case PROC_OP_RESTART: /* This is the case where there is an existing process running. * it was killed above but still runs and needs to be reaped */ - if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0) + if (clixon_proc_background(pe->pe_argv, pe->pe_netns, + pe->pe_uid, &pe->pe_pid) < 0) goto done; gettimeofday(&pe->pe_starttime, NULL); clicon_debug(1, "%s %s(%d) %s --%s--> %s", __FUNCTION__, diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 9311bb1b..2affcde1 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -489,7 +489,7 @@ clicon_rpc_netconf_xml(clicon_handle h, * @param[in] db Name of database * @param[in] xpath XPath (or "") * @param[in] nsc Namespace context for filter - * @param[in] defaults Value of the with-defaults mode, rfc6243, or NULL + * @param[in] defaults Value of the with-defaults mode, rfc6243, or NULL * @param[out] xt XML tree. Free with xml_free. * Either or . * @retval 0 OK