* Implemented backend daemon drop privileges after initialization to

run as non-privileged user
This commit is contained in:
Olof hagsand 2019-09-14 18:34:32 +02:00
parent cacba627b5
commit 27fd99e7cd
61 changed files with 673 additions and 207 deletions

View file

@ -3,11 +3,17 @@
## 4.2.0 (Expected: September) ## 4.2.0 (Expected: September)
### Major New features ### Major New features
* Backend daemon drops privileges after initialization (to not run as root) * Backend daemon can drop privileges after initialization to run as non-privileged user
* New config option `CLICON_USER` with default value `clicon` * You can start as root and drop privileges either permanently or temporary
* Controlled by options: CLICON_BACKEND_USER and CLICON_BACKEND_PRIVELEGES
* Can also be set with `-U <user>` clixon_backend command-line option * Can also be set with `-U <user>` clixon_backend command-line option
* If dropped temporary, you can restore privileges with `restore_priv()`
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* Typical installation should now add a `clicon` user (as well as group)
* New clixon-config@2019-09-11.yang revision
* Added: CLICON_BACKEND_USER: drop of privileges to user,
* Added: CLICON_BACKEND_PRIVELEGES: how to drop privileges
* Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1 * Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1
* non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]` * non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]`
* Replaced JSON `null` with `[null]` as proper empty JSON leaf/leaf-list encoding. * Replaced JSON `null` with `[null]` as proper empty JSON leaf/leaf-list encoding.

View file

@ -242,45 +242,94 @@ xmldb_drop_priv(clicon_handle h,
return retval; return retval;
} }
/*! Drop root privileges uid and gid to Clixon user/group /*! Drop root privileges uid and gid to Clixon user/group and
* @param[in] h Clicon handle *
* If config options are right, drop process uid/guid privileges and change some
* file ownerships.
* "Right" means:
* - uid is currently 0 (started as root)
* - CLICON_BACKEND_USER is set
* - CLICON_BACKEND_PRIVILEGES is not "none"
* @param[in] h Clicon handle
* @param[in] gid Group id (assume already known)
* @retval 0 OK
* @retval -1 Error
*/ */
static int static int
drop_priv(clicon_handle h, check_drop_priv(clicon_handle h,
uid_t uid, gid_t gid)
gid_t gid)
{ {
int retval = -1; int retval = -1;
uid_t uid;
uid_t newuid = -1;
enum priv_mode_t priv_mode = PM_NONE;
char *backend_user = NULL;
/* Get privileges mode (for dropping privileges) */
priv_mode = clicon_backend_privileges_mode(h);
if (priv_mode == PM_NONE)
goto ok;
/* From here, drop privileges */
/* Check backend user exists */
if ((backend_user = clicon_backend_user(h)) == NULL){
clicon_err(OE_DEMON, EPERM, "Privileges cannot be dropped without specifying CLICON_BACKEND_USER\n");
goto done;
}
/* Get (wanted) new backend user id */
if (name2uid(backend_user, &newuid) < 0){
clicon_err(OE_DEMON, errno, "'%s' is not a valid user .\n", backend_user);
goto done;
}
/* get current backend userid, if already at this level OK */
if ((uid = getuid()) == newuid)
goto ok;
if (uid != 0){
clicon_err(OE_DEMON, EPERM, "Privileges can only be dropped from root user (uid is %u)\n", uid);
goto done;
}
/* When dropping priveleges, datastores are created if they do not exist.
* But when drops are not made, datastores are created on demand.
* XXX: move the creation to top-level so they are always created at init?
*/
if (xmldb_exists(h, "running") != 1) if (xmldb_exists(h, "running") != 1)
if (xmldb_create(h, "running") < 0) if (xmldb_create(h, "running") < 0)
goto done; goto done;
if (xmldb_drop_priv(h, "running", uid, gid) < 0) if (xmldb_drop_priv(h, "running", newuid, gid) < 0)
goto done; goto done;
if (xmldb_exists(h, "candidate") != 1) if (xmldb_exists(h, "candidate") != 1)
if (xmldb_create(h, "candidate") < 0) if (xmldb_create(h, "candidate") < 0)
goto done; goto done;
if (xmldb_drop_priv(h, "candidate", uid, gid) < 0) if (xmldb_drop_priv(h, "candidate", newuid, gid) < 0)
goto done; goto done;
if (xmldb_exists(h, "startup") != 1) if (xmldb_exists(h, "startup") != 1)
if (xmldb_create(h, "startup") < 0) if (xmldb_create(h, "startup") < 0)
goto done; goto done;
if (xmldb_drop_priv(h, "startup", uid, gid) < 0) if (xmldb_drop_priv(h, "startup", newuid, gid) < 0)
goto done; goto done;
if (setgid(gid) == -1) { if (setgid(gid) == -1) {
clicon_err(OE_DEMON, errno, "setgid %d", gid); clicon_err(OE_DEMON, errno, "setgid %d", gid);
goto done; goto done;
} }
if (setuid(uid) == -1) { switch (priv_mode){
clicon_err(OE_DEMON, errno, "setuid %d", uid); case PM_DROP_PERM:
goto done; if (drop_priv_perm(newuid) < 0)
} goto done;
/* Verify you cannot regain root privileges */ /* Verify you cannot regain root privileges */
if (setuid(0) != -1){ if (setuid(0) != -1){
clicon_err(OE_DEMON, EPERM, "Could regain root privilieges"); clicon_err(OE_DEMON, EPERM, "Could regain root privilieges");
goto done; goto done;
}
break;
case PM_DROP_TEMP:
if (drop_priv_temp(newuid) < 0)
goto done;
break;
case PM_NONE:
break; /* catched above */
} }
ok:
retval = 0; retval = 0;
done: done:
return retval; return retval;
@ -356,7 +405,7 @@ usage(clicon_handle h,
"\t-1\t\tRun once and then quit (dont wait for events)\n" "\t-1\t\tRun once and then quit (dont wait for events)\n"
"\t-s <mode>\tSpecify backend startup mode: none|startup|running|init)\n" "\t-s <mode>\tSpecify backend startup mode: none|startup|running|init)\n"
"\t-c <file>\tLoad extra xml configuration, but don't commit.\n" "\t-c <file>\tLoad extra xml configuration, but don't commit.\n"
"\t-U <user>\tRun backend daemon as this user\n" "\t-U <user>\tRun backend daemon as this user AND drop privileges permanently\n"
"\t-g <group>\tClient membership required to this group (default: %s)\n" "\t-g <group>\tClient membership required to this group (default: %s)\n"
"\t-y <file>\tLoad yang spec file (override yang main module)\n" "\t-y <file>\tLoad yang spec file (override yang main module)\n"
@ -382,7 +431,6 @@ main(int argc,
int once; int once;
enum startup_mode_t startup_mode; enum startup_mode_t startup_mode;
char *extraxml_file; char *extraxml_file;
char *backend_user = NULL;
char *backend_group = NULL; char *backend_group = NULL;
char *argv0 = argv[0]; char *argv0 = argv[0];
struct stat st; struct stat st;
@ -403,7 +451,6 @@ main(int argc,
int ret; int ret;
char *dir; char *dir;
gid_t gid = -1; gid_t gid = -1;
uid_t uid = -1;
/* In the startup, logs to stderr & syslog and debug flag set later */ /* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst); clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -536,7 +583,9 @@ main(int argc,
extraxml_file = optarg; extraxml_file = optarg;
break; break;
case 'U': /* config user (for socket and drop privileges) */ case 'U': /* config user (for socket and drop privileges) */
if (clicon_option_add(h, "CLICON_SOCK", optarg) < 0) if (clicon_option_add(h, "CLICON_USER", optarg) < 0)
goto done;
if (clicon_option_add(h, "CLICON_BACKEND_PRIVILEGES", "drop_permanent") < 0)
goto done; goto done;
break; break;
case 'g': /* config socket group */ case 'g': /* config socket group */
@ -616,17 +665,6 @@ main(int argc,
if (sockfamily==AF_UNIX && lstat(sock, &st) == 0) if (sockfamily==AF_UNIX && lstat(sock, &st) == 0)
unlink(sock); unlink(sock);
/* XXX maybe only if !foreground */
/* Sanity check: backend user exists */
if ((backend_user = clicon_user(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_user option not set");
return -1;
}
if (name2uid(backend_user, &uid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user .\n", backend_user);
goto done;
}
/* Sanity check: backend group exists */ /* Sanity check: backend group exists */
if ((backend_group = clicon_sock_group(h)) == NULL){ if ((backend_group = clicon_sock_group(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set"); clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
@ -634,13 +672,11 @@ main(int argc,
} }
if (group_name2gid(backend_group, &gid) < 0){ if (group_name2gid(backend_group, &gid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n" /* \n required here due to multi-line log */ clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n" /* \n required here due to multi-line log */
"The config demon requires a valid group to create a server UNIX socket\n" "The config demon requires a valid group to create a server UNIX socket\n"
"Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n" "Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n"
"or create the group and add the user to it. On linux for example:" "or create the group and add the user to it. Check documentation for how to do this on your platform",
" sudo groupadd %s\n" backend_group,
" sudo usermod -a -G %s user\n", clicon_configfile(h));
backend_group, clicon_configfile(h),
backend_group, backend_group);
goto done; goto done;
} }
@ -845,10 +881,10 @@ main(int argc,
goto done; goto done;
if (debug) if (debug)
clicon_option_dump(h, debug); clicon_option_dump(h, debug);
/* Drop root privileges (unless root) */ /* Depending on configure setting, privileges may be dropped here after
if (uid != 0) * initializations */
if (drop_priv(h, uid, gid) < 0) if (check_drop_priv(h, gid) < 0)
goto done; goto done;
if (stream_timer_setup(0, h) < 0) if (stream_timer_setup(0, h) < 0)
goto done; goto done;

View file

@ -106,15 +106,15 @@ Define a valid CLICON_SOCK_GROUP in the config file or via the -g option
or create the group and add the user to it. The default group is 'clicon'. or create the group and add the user to it. The default group is 'clicon'.
Add yourself and www-data, if you intend to use restconf. Add yourself and www-data, if you intend to use restconf.
Using groupadd and usermod: Using useradd and usermod:
``` ```
sudo groupadd clicon # sudo useradd clicon #
sudo usermod -a -G clicon <user> sudo usermod -a -G clicon <user>
sudo usermod -a -G clicon www-data sudo usermod -a -G clicon www-data
``` ```
Using addgroup and adduser (eg on busybox): Using adduser (eg on busybox):
``` ```
sudo addgroup clicon sudo adduser -D -H clicon
sudo adduser <user> clicon sudo adduser <user> clicon
``` ```
(you may have to restart shell) (you may have to restart shell)

View file

@ -65,6 +65,7 @@
#define LIBCLIXON_API 1 #define LIBCLIXON_API 1
#include <clixon/clixon_sig.h> #include <clixon/clixon_sig.h>
#include <clixon/clixon_uid.h>
#include <clixon/clixon_err.h> #include <clixon/clixon_err.h>
#include <clixon/clixon_queue.h> #include <clixon/clixon_queue.h>
#include <clixon/clixon_hash.h> #include <clixon/clixon_hash.h>

View file

@ -43,8 +43,4 @@ int clicon_file_dirent(const char *dir, struct dirent **ent,
int clicon_file_copy(char *src, char *target); int clicon_file_copy(char *src, char *target);
int group_name2gid(const char *name, gid_t *gid);
int name2uid(const char *name, uid_t *uid);
#endif /* _CLIXON_FILE_H_ */ #endif /* _CLIXON_FILE_H_ */

View file

@ -73,6 +73,13 @@ enum startup_mode_t{
SM_INIT SM_INIT
}; };
/*! See clixon-config.yang type priv_mode (privileges mode) */
enum priv_mode_t{
PM_NONE=0, /* Make no drop/change in privileges */
PM_DROP_PERM, /* Drop privileges permanently */
PM_DROP_TEMP, /* Drop privileges temporary */
};
/*! Datastore cache behaviour, see clixon_datastore.[ch] /*! Datastore cache behaviour, see clixon_datastore.[ch]
* See config option type datastore_cache in clixon-config.yang * See config option type datastore_cache in clixon-config.yang
*/ */
@ -167,8 +174,8 @@ static inline char *clicon_sock(clicon_handle h){
static inline char *clicon_sock_group(clicon_handle h){ static inline char *clicon_sock_group(clicon_handle h){
return clicon_option_str(h, "CLICON_SOCK_GROUP"); return clicon_option_str(h, "CLICON_SOCK_GROUP");
} }
static inline char *clicon_user(clicon_handle h){ static inline char *clicon_backend_user(clicon_handle h){
return clicon_option_str(h, "CLICON_USER"); return clicon_option_str(h, "CLICON_BACKEND_USER");
} }
static inline char *clicon_backend_pidfile(clicon_handle h){ static inline char *clicon_backend_pidfile(clicon_handle h){
return clicon_option_str(h, "CLICON_BACKEND_PIDFILE"); return clicon_option_str(h, "CLICON_BACKEND_PIDFILE");
@ -186,6 +193,7 @@ int clicon_sock_family(clicon_handle h);
int clicon_sock_port(clicon_handle h); int clicon_sock_port(clicon_handle h);
int clicon_autocommit(clicon_handle h); int clicon_autocommit(clicon_handle h);
int clicon_startup_mode(clicon_handle h); int clicon_startup_mode(clicon_handle h);
int clicon_backend_privileges_mode(clicon_handle h);
enum datastore_cache clicon_datastore_cache(clicon_handle h); enum datastore_cache clicon_datastore_cache(clicon_handle h);
enum regexp_mode clicon_yang_regexp(clicon_handle h); enum regexp_mode clicon_yang_regexp(clicon_handle h);
/*-- Specific option access functions for non-yang options --*/ /*-- Specific option access functions for non-yang options --*/

50
lib/clixon/clixon_uid.h Normal file
View file

@ -0,0 +1,50 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* uid, gid, privileges
*/
#ifndef _CLIXON_UID_H_
#define _CLIXON_UID_H_
/*
* Prototypes
*/
int group_name2gid(const char *name, gid_t *gid);
int name2uid(const char *name, uid_t *uid);
int drop_priv_temp(uid_t new_uid);
int drop_priv_perm(uid_t new_uid);
int restore_priv(void);
#endif /* _CLIXON_UID_H_ */

View file

@ -66,7 +66,7 @@ CPPFLAGS = @CPPFLAGS@
INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$(top_srcdir) INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$(top_srcdir)
SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \ SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
clixon_string.c clixon_regex.c clixon_handle.c \ clixon_string.c clixon_regex.c clixon_handle.c \
clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_file.c \ clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_file.c \
clixon_json.c clixon_yang.c clixon_yang_type.c clixon_yang_module.c \ clixon_json.c clixon_yang.c clixon_yang_type.c clixon_yang_module.c \

View file

@ -43,14 +43,12 @@
#include <errno.h> #include <errno.h>
#include <dirent.h> #include <dirent.h>
#include <regex.h> #include <regex.h>
#include <pwd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <grp.h>
/* cligen */ /* cligen */
#include <cligen/cligen.h> #include <cligen/cligen.h>
@ -210,61 +208,3 @@ clicon_file_copy(char *src,
errno = err; errno = err;
return retval; return retval;
} }
/*! Translate group name to gid. Return -1 if error or not found.
* @param[in] name Name of group
* @param[out] gid Group id
* @retval 0 OK
* @retval -1 Error. or not found
*/
int
group_name2gid(const char *name,
gid_t *gid)
{
int retval = -1;
char buf[1024];
struct group g0;
struct group *gr = &g0;
struct group *gtmp;
gr = &g0;
/* This leaks memory in ubuntu */
if (getgrnam_r(name, gr, buf, sizeof(buf), &gtmp) < 0){
clicon_err(OE_UNIX, errno, "getgrnam_r(%s)", name);
goto done;
}
if (gtmp == NULL){
clicon_err(OE_UNIX, 0, "No such group: %s", name);
goto done;
}
if (gid)
*gid = gr->gr_gid;
retval = 0;
done:
return retval;
}
int
name2uid(const char *name,
uid_t *uid)
{
int retval = -1;
char buf[1024];
struct passwd pwbuf;
struct passwd *pwbufp = NULL;
if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
clicon_err(OE_UNIX, errno, "getpwnam_r(%s)", name);
goto done;
}
if (pwbufp == NULL){
clicon_err(OE_UNIX, 0, "No such user: %s", name);
goto done;
}
if (uid)
*uid = pwbufp->pw_uid;
retval = 0;
done:
return retval;
}

View file

@ -82,6 +82,15 @@
*/ */
#define CLIXON_CONF_NS "http://clicon.org/config" #define CLIXON_CONF_NS "http://clicon.org/config"
/* Mapping between Cli generation from Yang string <--> constants,
see clixon-config.yang type cli_genmodel_type */
static const map_str2int cli_genmodel_map[] = {
{"NONE", GT_NONE},
{"VARS", GT_VARS},
{"ALL", GT_ALL},
{NULL, -1}
};
/* Mapping between Clicon startup modes string <--> constants, /* Mapping between Clicon startup modes string <--> constants,
see clixon-config.yang type startup_mode */ see clixon-config.yang type startup_mode */
static const map_str2int startup_mode_map[] = { static const map_str2int startup_mode_map[] = {
@ -92,6 +101,32 @@ static const map_str2int startup_mode_map[] = {
{NULL, -1} {NULL, -1}
}; };
/* Mapping between Clicon privilegese modes string <--> constants,
* see clixon-config.yang type priv_mode */
static const map_str2int priv_mode_map[] = {
{"none", PM_NONE},
{"drop_perm", PM_DROP_PERM},
{"drop_temp", PM_DROP_TEMP},
{NULL, -1}
};
/* Mapping between datastore cache string <--> constants,
* see clixon-config.yang type datastore_cache */
static const map_str2int datastore_cache_map[] = {
{"nocache", DATASTORE_NOCACHE},
{"cache", DATASTORE_CACHE},
{"cache-zerocopy", DATASTORE_CACHE_ZEROCOPY},
{NULL, -1}
};
/* Mapping between regular expression type string <--> constants,
* see clixon-config.yang type regexp_mode */
static const map_str2int yang_regexp_map[] = {
{"posix", REGEXP_POSIX},
{"libxml2", REGEXP_LIBXML2},
{NULL, -1}
};
/*! Print registry on file. For debugging. /*! Print registry on file. For debugging.
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] dbglevel Debug level * @param[in] dbglevel Debug level
@ -453,6 +488,9 @@ clicon_option_int(clicon_handle h,
} }
/*! Set option given as int. /*! Set option given as int.
* @param[in] h Clicon handle
* @param[in] name Name of option to set
* @param[in] val Integer value
*/ */
int int
clicon_option_int_set(clicon_handle h, clicon_option_int_set(clicon_handle h,
@ -468,7 +506,7 @@ clicon_option_int_set(clicon_handle h,
/*! Get options as bool but stored as string /*! Get options as bool but stored as string
* *
* @param[in] h clicon handle * @param[in] h Clicon handle
* @param[in] name name of option * @param[in] name name of option
* @retval 0 false, or does not exist, or does not have a boolean value * @retval 0 false, or does not exist, or does not have a boolean value
* @retval 1 true * @retval 1 true
@ -496,6 +534,9 @@ clicon_option_bool(clicon_handle h,
} }
/*! Set option given as bool /*! Set option given as bool
* @param[in] h Clicon handle
* @param[in] name Name of option to set
* @param[in] val Boolean value, 0 or 1
*/ */
int int
clicon_option_bool_set(clicon_handle h, clicon_option_bool_set(clicon_handle h,
@ -510,6 +551,8 @@ clicon_option_bool_set(clicon_handle h,
} }
/*! Delete option /*! Delete option
* @param[in] h Clicon handle
* @param[in] name Name of option to delete
*/ */
int int
clicon_option_del(clicon_handle h, clicon_option_del(clicon_handle h,
@ -530,8 +573,10 @@ clicon_option_del(clicon_handle h,
* But sometimes there are type conversions, etc which makes it more * But sometimes there are type conversions, etc which makes it more
* convenient to make wrapper functions. Or not? * convenient to make wrapper functions. Or not?
*-----------------------------------------------------------------*/ *-----------------------------------------------------------------*/
/*! Whether to generate CLIgen syntax from datamodel or not (0 or 1) /*! Wether to generate CLIgen syntax from datamodel or not (0 or 1)
* Must be used with a previous clicon_option_exists(). * Must be used with a previous clicon_option_exists().
* @param[in] h Clicon handle
* @retval flag If set, generate CLI code from yang model, otherwise not
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL
*/ */
int int
@ -546,6 +591,8 @@ clicon_cli_genmodel(clicon_handle h)
} }
/*! Generate code for CLI completion of existing db symbols /*! Generate code for CLI completion of existing db symbols
* @param[in] h Clicon handle
* @retval flag If set, generate auto-complete CLI specs
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_COMPLETION * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_COMPLETION
*/ */
int int
@ -559,14 +606,9 @@ clicon_cli_genmodel_completion(clicon_handle h)
return 0; return 0;
} }
static const map_str2int cli_genmodel_map[] = {
{"NONE", GT_NONE},
{"VARS", GT_VARS},
{"ALL", GT_ALL},
{NULL, -1}
};
/*! How to generate and show CLI syntax: VARS|ALL /*! How to generate and show CLI syntax: VARS|ALL
* @param[in] h Clicon handle
* @retval mode
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_TYPE * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_TYPE
*/ */
enum genmodel_type enum genmodel_type
@ -580,7 +622,9 @@ clicon_cli_genmodel_type(clicon_handle h)
return clicon_str2int(cli_genmodel_map, str); return clicon_str2int(cli_genmodel_map, str);
} }
/*! Get Dont include keys in cvec in cli vars callbacks /*! Get "do not include keys in cvec" in cli vars callbacks
* @param[in] h Clicon handle
* @retval flag If set, get only vars
* @see clixon-config@<date>.yang CLICON_CLI_VARONLY * @see clixon-config@<date>.yang CLICON_CLI_VARONLY
*/ */
int int
@ -596,6 +640,8 @@ clicon_cli_varonly(clicon_handle h)
/*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6 /*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6
* @see clixon-config@<date>.yang CLICON_SOCK_FAMILY * @see clixon-config@<date>.yang CLICON_SOCK_FAMILY
* @param[in] h Clicon handle
* @retval fam Socket family
*/ */
int int
clicon_sock_family(clicon_handle h) clicon_sock_family(clicon_handle h)
@ -613,6 +659,8 @@ clicon_sock_family(clicon_handle h)
} }
/*! Get port for backend socket in case of AF_INET or AF_INET6 /*! Get port for backend socket in case of AF_INET or AF_INET6
* @param[in] h Clicon handle
* @retval port Socket port
* @see clixon-config@<date>.yang CLICON_SOCK_PORT * @see clixon-config@<date>.yang CLICON_SOCK_PORT
*/ */
int int
@ -626,6 +674,8 @@ clicon_sock_port(clicon_handle h)
} }
/*! Set if all configuration changes are committed automatically /*! Set if all configuration changes are committed automatically
* @param[in] h Clicon handle
* @retval flag Autocommit (or not)
*/ */
int int
clicon_autocommit(clicon_handle h) clicon_autocommit(clicon_handle h)
@ -638,25 +688,37 @@ clicon_autocommit(clicon_handle h)
return 0; return 0;
} }
/*! Which method to boot/start clicon backen /*! Which method to boot/start clicon backend
* @param[in] h Clicon handle
* @retval mode Startup mode
*/ */
int int
clicon_startup_mode(clicon_handle h) clicon_startup_mode(clicon_handle h)
{ {
char *mode; char *mode;
if ((mode = clicon_option_str(h, "CLICON_STARTUP_MODE")) == NULL) if ((mode = clicon_option_str(h, "CLICON_STARTUP_MODE")) == NULL)
return -1; return -1;
return clicon_str2int(startup_mode_map, mode); return clicon_str2int(startup_mode_map, mode);
} }
static const map_str2int datastore_cache_map[] = { /*! Which privileges drop method to use
{"nocache", DATASTORE_NOCACHE}, * @param[in] h Clicon handle
{"cache", DATASTORE_CACHE}, * @retval mode Privileges mode
{"cache-zerocopy", DATASTORE_CACHE_ZEROCOPY}, */
{NULL, -1} int
}; clicon_backend_privileges_mode(clicon_handle h)
{
char *mode;
if ((mode = clicon_option_str(h, "CLICON_BACKEND_PRIVILEGES")) == NULL)
return -1;
return clicon_str2int(priv_mode_map, mode);
}
/*! Which datastore cache method to use /*! Which datastore cache method to use
* @param[in] h Clicon handle
* @retval method Datastore cache method
* @see clixon-config@<date>.yang CLICON_DATASTORE_CACHE * @see clixon-config@<date>.yang CLICON_DATASTORE_CACHE
*/ */
enum datastore_cache enum datastore_cache
@ -670,13 +732,9 @@ clicon_datastore_cache(clicon_handle h)
return clicon_str2int(datastore_cache_map, str); return clicon_str2int(datastore_cache_map, str);
} }
static const map_str2int yang_regexp_map[] = {
{"posix", REGEXP_POSIX},
{"libxml2", REGEXP_LIBXML2},
{NULL, -1}
};
/*! Which Yang regexp/pattern engine to use /*! Which Yang regexp/pattern engine to use
* @param[in] h Clicon handle
* @retval mode Regexp engine to use
* @see clixon-config@<date>.yang CLICON_YANG_REGEXP * @see clixon-config@<date>.yang CLICON_YANG_REGEXP
*/ */
enum regexp_mode enum regexp_mode
@ -696,7 +754,10 @@ clicon_yang_regexp(clicon_handle h)
* Such as handles to plugins, API:s and parsed structures * Such as handles to plugins, API:s and parsed structures
*--------------------------------------------------------------------*/ *--------------------------------------------------------------------*/
/* eg -q option, dont print notifications on stdout */ /*! Get quiet mode eg -q option, do not print notifications on stdout
* @param[in] h Clicon handle
* @retval flag quiet mode on or off
*/
int int
clicon_quiet_mode(clicon_handle h) clicon_quiet_mode(clicon_handle h)
{ {
@ -705,8 +766,14 @@ clicon_quiet_mode(clicon_handle h)
return 0; /* default */ return 0; /* default */
return atoi(s); return atoi(s);
} }
/*! Set quiet mode
* @param[in] h Clicon handle
* @param[in] val Flag value
*/
int int
clicon_quiet_mode_set(clicon_handle h, int val) clicon_quiet_mode_set(clicon_handle h,
int val)
{ {
return clicon_option_int_set(h, "CLICON_QUIET", val); return clicon_option_int_set(h, "CLICON_QUIET", val);
} }

200
lib/src/clixon_uid.c Normal file
View file

@ -0,0 +1,200 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* uid, gid, privileges
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define __USE_GNU /* For setresuid */
#include <unistd.h>
#undef __USE_GNU
#include <stdarg.h>
#include <signal.h>
#include <syslog.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
/* clicon */
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_uid.h"
/*! Translate group name to gid. Return -1 if error or not found.
* @param[in] name Name of group
* @param[out] gid Group id
* @retval 0 OK
* @retval -1 Error. or not found
*/
int
group_name2gid(const char *name,
gid_t *gid)
{
int retval = -1;
char buf[1024];
struct group g0;
struct group *gr = &g0;
struct group *gtmp;
gr = &g0;
/* This leaks memory in ubuntu */
if (getgrnam_r(name, gr, buf, sizeof(buf), &gtmp) < 0){
clicon_err(OE_UNIX, errno, "getgrnam_r(%s)", name);
goto done;
}
if (gtmp == NULL){
clicon_err(OE_UNIX, 0, "No such group: %s", name);
goto done;
}
if (gid)
*gid = gr->gr_gid;
retval = 0;
done:
return retval;
}
/*! Translate user name to uid. Return -1 if error or not found.
* @param[in] name Name of user
* @param[out] uid User id
* @retval 0 OK
* @retval -1 Error. or not found
*/
int
name2uid(const char *name,
uid_t *uid)
{
int retval = -1;
char buf[1024];
struct passwd pwbuf;
struct passwd *pwbufp = NULL;
if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
clicon_err(OE_UNIX, errno, "getpwnam_r(%s)", name);
goto done;
}
if (pwbufp == NULL){
clicon_err(OE_UNIX, 0, "No such user: %s", name);
goto done;
}
if (uid)
*uid = pwbufp->pw_uid;
retval = 0;
done:
return retval;
}
/* Privileges drop perm, temp and restore
* @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
*/
/*! Temporarily drop privileges
* @param[in] new_uid
*/
int
drop_priv_temp(uid_t new_uid)
{
int retval = -1;
if (setresuid(-1, new_uid, geteuid()) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
goto done;
}
if (geteuid() != new_uid){
clicon_err(OE_UNIX, errno, "geteuid");
goto done;
}
retval = 0;
done:
return retval;
}
/*! Permanently drop privileges
* @param[in] new_uid
*/
int
drop_priv_perm(uid_t new_uid)
{
int retval = -1;
uid_t ruid;
uid_t euid;
uid_t suid;
if (setresuid(new_uid, new_uid, new_uid) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
goto done;
}
if (getresuid(&ruid, &euid, &suid) < 0){
clicon_err(OE_UNIX, errno, "getresuid");
goto done;
}
if (ruid != new_uid ||
euid != new_uid ||
suid != new_uid){
clicon_err(OE_UNIX, EINVAL, "Non-matching uid");
goto done;
}
retval = 0;
done:
return retval;
}
/*! Restore privileges to saved level */
int
restore_priv(void)
{
int retval = -1;
uid_t ruid;
uid_t euid;
uid_t suid;
if (getresuid(&ruid, &euid, &suid) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
goto done;
}
if (setresuid(-1, suid, -1) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
goto done;
}
if (geteuid() != suid){
clicon_err(OE_UNIX, EINVAL, "Non-matching uid");
goto done;
}
retval = 0;
done:
return retval;
}

View file

@ -109,6 +109,14 @@ if [ ! -d $dir ]; then
mkdir $dir mkdir $dir
fi fi
# Some tests may set owner of testdir to something strange and quit, need
# to reset to me
if [ ! -G $dir ]; then
u=$(whoami)
sudo chown $u $dir
sudo chgrp $u $dir
fi
# If you bring your own backend BE=0 (it is already started),the backend may # If you bring your own backend BE=0 (it is already started),the backend may
# have created some files (eg unix socket) in $dir and therefore cannot # have created some files (eg unix socket) in $dir and therefore cannot
# be deleted # be deleted

View file

@ -218,7 +218,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -287,7 +287,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -126,7 +126,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -118,7 +118,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -132,7 +132,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -163,7 +163,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -191,7 +191,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -316,7 +316,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -194,7 +194,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -231,7 +231,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -188,7 +188,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -153,7 +153,7 @@ EOF
if [ $BE -ne 0 ]; then # Bring your own backend if [ $BE -ne 0 ]; then # Bring your own backend
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -216,7 +216,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -279,7 +279,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -258,7 +258,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -223,7 +223,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -211,7 +211,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -395,7 +395,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -743,7 +743,7 @@ expectfn "$clixon_cli -1f $cfg -l o set c threematch abcg" 255 '^CLI syntax erro
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -237,7 +237,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -145,7 +145,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

121
test/test_privileges.sh Executable file
View file

@ -0,0 +1,121 @@
#!/bin/bash
# Start clixon backend as root and unprivileged user (clicon)
# Drop privileges from root to clicon
# Test could do more:
# - test file ownership
# - drop_temp check if you can restore
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=example
cfg=$dir/conf_startup.xml
if [ $valgrindtest -ne 0 ]; then
return -1 # skip
fi
# Here $dir is created by the user that runs the script
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
</clixon-config>
EOF
# Create a pre-set running, startup and (extra) config.
# The configs are identified by an interface called run, startup, extra.
# Depending on startup mode (init, none, running, or startup)
# expect different output of an initial get-config of running
testrun(){
startuser=$1
beuser=$2
expectuser=$3
priv_mode=$4
expecterr=$5
# change owner (recursively) of all files in the test dir
sudo chown -R $startuser $dir
# change group (recursively) of all files in the test dir
sudo chgrp -R $startuser $dir
# kill old backend (if any)
new "kill old backend"
sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then
err
fi
# Kill all backends regardless of user or pid files (we mess with them in this test)
sudo pkill clixon_backend
# start backend as user
new "start backend -f $cfg -s init -D $DBG -o CLICON_BACKEND_PRIVILEGES=$priv_mode -o CLICON_BACKEND_USER=$beuser"
sudo -u $startuser $clixon_backend -f $cfg -s init -D $DBG -o CLICON_BACKEND_PRIVILEGES=$priv_mode -o CLICON_BACKEND_USER=$beuser
if [ $? -ne 0 ]; then
err
fi
pid=$(pgrep -f clixon_backend)
if [ $? -ne 0 ]; then
if [ $expecterr -eq 1 ]; then
return 0
fi
err
fi
new "waiting"
wait_backend
if [ $expecterr -eq 1 ]; then
err "Expected error"
fi
# Get uid now, and compare with expected user
u=$(ps -p $pid -uh | awk '{print $1}')
if [ $u != $expectuser ]; then
err "$expectuser but user is $u"
fi
new "Kill backend"
# Check if premature kill
pid=$(pgrep -f clixon_backend)
if [ -z "$pid" ]; then
err "backend already dead"
fi
# kill backend
stop_backend -f $cfg
} # testrun
new "Start as non-privileged user, expect same"
testrun $BUSER $BUSER $BUSER none 0
new "Start as privileged user , expect same"
testrun root root root none 0
new "Start as privileged user, drop privileges permanent"
testrun root $BUSER $BUSER drop_perm 0
new "Start as privileged user, drop privileges temporary"
testrun root $BUSER $BUSER drop_temp 0
new "Start as root, drop to root (strange usecase)"
testrun root root root drop_perm 0
new "Start as root, drop to root (strange usecase)"
testrun root root root drop_perm 0
new "Start as root, set user but dont drop (expect still root)"
testrun root $BUSER root none 0
new "Start as non-privileged, try to drop"
testrun $(whoami) $BUSER $BUSER drop_perm 1
sudo rm -rf $dir

View file

@ -278,7 +278,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -200,7 +200,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -116,7 +116,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -261,7 +261,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -157,7 +157,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -209,7 +209,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -89,7 +89,7 @@ testrun(){
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -108,7 +108,7 @@ new "Check running and startup exists and are same"
if [ ! -f $dir/startup_db ]; then if [ ! -f $dir/startup_db ]; then
err "startup should exist but does not" err "startup should exist but does not"
fi fi
echo "diff $dir/startup_db $dir/running_db"
d=$(sudo diff $dir/startup_db $dir/running_db) d=$(sudo diff $dir/startup_db $dir/running_db)
if [ -n "$d" ]; then if [ -n "$d" ]; then
err "running and startup should be equal" "$d" err "running and startup should be equal" "$d"
@ -117,14 +117,12 @@ fi
# clear startup # clear startup
sudo rm -f $dir/startup_db; sudo rm -f $dir/startup_db;
new "Run without startup option, check running is copied" new "Run without startup option, check running is not copied"
testrun "" testrun ""
new "Check startup is empty" new "Check startup is empty"
if [ ! -f $dir/startup_db ]; then if [ -f $dir/startup_db ]; then
err "startup does not exist" err "startup should not exist"
fi
if [ -s $dir/startup_db ]; then
err "startup is not empty"
fi fi
rm -rf $dir rm -rf $dir

View file

@ -164,7 +164,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -102,7 +102,7 @@ testrun(){
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -291,7 +291,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -224,7 +224,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -311,7 +311,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -628,7 +628,7 @@ EOF
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -306,7 +306,7 @@ testrange string "012" "01234567890" ""
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -107,7 +107,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -216,7 +216,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -283,7 +283,7 @@ runtest(){
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -274,7 +274,7 @@ stop_restconf
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -285,7 +285,7 @@ testrun(){
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -151,7 +151,7 @@ stop_restconf
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -147,7 +147,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -112,7 +112,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -286,7 +286,7 @@ fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -114,7 +114,7 @@ expecteof "$clixon_netconf -qf $cfg -D $DBG" 0 "<rpc><get-config><source><candid
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -100,7 +100,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -149,7 +149,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -193,7 +193,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -237,7 +237,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -281,7 +281,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -326,7 +326,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -372,7 +372,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi
@ -418,7 +418,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -137,7 +137,7 @@ if [ $BE -eq 0 ]; then
fi fi
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=$(pgrep -u $BUSER -f clixon_backend) pid=$(pgrep -u root -f clixon_backend)
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
err "backend already dead" err "backend already dead"
fi fi

View file

@ -41,7 +41,8 @@ module clixon-config {
revision 2019-09-11 { revision 2019-09-11 {
description description
"Added: CLICON_USER: user that backend daemon drops privileges to"; "Added: CLICON_BACKEND_USER: drop of privileges to user,
CLICON_BACKEND_PRIVILEGES: how to drop privileges";
} }
revision 2019-06-05 { revision 2019-06-05 {
description description
@ -183,6 +184,26 @@ module clixon-config {
} }
} }
} }
typedef priv_mode{
description
"Privilege mode, used for dropping (or not) priveleges to a non-provileged
user after initialization";
type enumeration{
enum none {
description
"Make no drop/change in privileges.";
}
enum drop_perm {
description
"After initialization, drop privileges permanently to a uid";
}
enum drop_temp {
description
"After initialization, drop privileges temporarily to a euid";
}
}
}
container clixon-config { container clixon-config {
leaf-list CLICON_FEATURE { leaf-list CLICON_FEATURE {
description description
@ -423,11 +444,25 @@ module clixon-config {
"Group membership to access clixon_backend unix socket and gid for "Group membership to access clixon_backend unix socket and gid for
deamon"; deamon";
} }
leaf CLICON_USER { leaf CLICON_BACKEND_USER {
type string; type string;
default "clicon";
description description
"User to access clixon_backend unix socket and uid for deamon"; "User name for backend (both foreground and daemonized).
If you set this value the backend if started as root will lower
the privileges after initialization.
The ownership of files created by the backend will also be set to this
user (eg datastores).
It also sets the backend unix socket owner to this user, but its group
is set by CLICON_SOCK_GROUP.
See also CLICON_PRIVILEGES setting";
}
leaf CLICON_BACKEND_PRIVILEGES {
type priv_mode;
default none;
description
"Backend privileges mode.
If CLICON_BACKEND_USER user is set, mode can be set to drop_perm or
drop_temp.";
} }
leaf CLICON_BACKEND_PIDFILE { leaf CLICON_BACKEND_PIDFILE {
type string; type string;