From a9352b9c1363352d166399d08db783dc433ac2e3 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sat, 6 Sep 2014 18:17:50 -0400 Subject: [PATCH] Fix TLS in ACL's. Adds invoking_tls configuration parameter. This is like invoking_user but for remote connections. Add documentation for Access Control. --- doc/config.example | 12 ++- doc/pwmd.html | 298 +++++++++++++++++++++++++++++++---------------------- doc/pwmd.texi | 46 ++++++++- src/commands.c | 18 ++-- src/common.h | 1 + src/pwmd.c | 34 +++++- src/rcfile.c | 6 +- src/rcfile.h | 1 + src/tls.c | 5 +- src/xml.c | 23 +++-- 10 files changed, 297 insertions(+), 147 deletions(-) diff --git a/doc/config.example b/doc/config.example index 49aa55f4..1c2ace92 100644 --- a/doc/config.example +++ b/doc/config.example @@ -21,7 +21,15 @@ # Usernames or groups obtained via SO_PEERCRED which are allowed to # connect to the socket. Groups should be prefixed with a '@'. When not # specified only the invoking user is allowed. -#allowed = username,another_user,@group +#allowed = username,another_user,@group,-not_this_user + +# Username to use as the default in an element ACL. The default is the +# invoking user. +#invoking_user=nobody + +# Like invoking_user, but for remote connections, an SHA1 hash of a client +# TLS fingerprint. +#invoking_tls=#FINGERPRINT # When false, disable keeping backups for data files. #backup=true @@ -123,7 +131,7 @@ # A comma separated list of client x509 certificate fingerprints in # SHA-1 format that will be allowed to connect or open a file. See the # documentation for details. -#tls_access=ALLOWEDFINGERPRINT,ANOTHERFINGERPRINT +#tls_access=#ALLOWEDFINGERPRINT,#ANOTHERFINGERPRINT # Require the client to provide the key to open a file even if the file is # cached. diff --git a/doc/pwmd.html b/doc/pwmd.html index 276ed518..045ebc9b 100644 --- a/doc/pwmd.html +++ b/doc/pwmd.html @@ -62,19 +62,21 @@ Up: (dir)   [Introduction:  Overview of pwmd. -• Invoking:  Command line options. +• Access Control:  ACL of a single XML element. -• Configuration:  Configuration file options. +• Invoking:  Command line options. -• Commands:  Protocol commands. +• Configuration:  Configuration file options. -• Status Messages:  Status lines and their meaning. +• Commands:  Protocol commands. -• Target Attribute:  A kind of symbolic link. +• Status Messages:  Status lines and their meaning. -• Signals:  Signals known to pwmd. +• Target Attribute:  A kind of symbolic link. -• Concept Index:  Index of concepts. +• Signals:  Signals known to pwmd. + +• Concept Index:  Index of concepts. @@ -82,7 +84,7 @@ Up: (dir)   [

-Next: , Up: Top   [Contents]

+Next: , Up: Top   [Contents]

1 Overview of pwmd

@@ -147,13 +149,47 @@ characters. It also cannot begin with a ‘!’ since this reserved for the target attribute. See Target Attribute.


+ +
+

+Next: , Previous: , Up: Top   [Contents]

+
+ +

2 Access Control

+ +

Like a filesystem has an ACL to grant or limit access to directories or +files for a specific user or group, pwmd can limit a local user, +group or a TLS connection to a specific element path. This is done by storing +an ACL in the element attribute _acl. Its syntax is similar to the +allowed configuration parameter (see Configuration) with the +exception that a TLS fingerprint hash is prefixed with a #. +

+

Access is denied for all users that are not in the ACL of an element with the +exception of the invoking user (see the invoking_user and +invoking_tls configuration parameters (see Configuration)). The +connected client must be in the ACL for each element in an element +path otherwise an error is returned. As an example: +

+
+
<element _name="test" _acl="username,-@wheel,root">
+	<element _name="child"/>
+</element>
+
+ +

The user username would be allowed access to the test element +but not if it is a member of the wheel group. Although the root +user, who may be a member of the wheel group, is allowed. No users +other than the invoking_user is allowed access to the child +element. +

+

-Next: , Previous: , Up: Top   [Contents]

+Next: , Previous: , Up: Top   [Contents]

-

2 Invoking pwmd

+

3 Invoking pwmd

@@ -304,7 +340,7 @@ separated list of output keywords. Valid keywords are: init, Next: , Previous: , Up: Top   [Contents]

-

3 pwmd configuration file options

+

4 pwmd configuration file options

If no configuration file is specified with the pwmd -f @@ -336,6 +372,20 @@ a pwmd process. umask(2) setting.

+
invoking_user = username
+

This parameter is not to be confused with setuid or setguid upon startup. It +is the local username that may use the XPATH, XPATHATTR +and DUMP commands (except when disabled with the +disable_list_and_dump option). Other users are denied access to these +commands. This also specifies the user that may access any elements that lack +an _acl attribute (see Access Control). The default is the current +user. +

+
+
invoking_tls = hash
+

Like invoking_user, but is a hash of a TLS certificate fingerprint. +

+
allowed = [-]user,[-]@group,...

A comma separated list of local user names or group names allowed to connect to the socket. Groups should be prefixed with a ‘@’. When not specified @@ -531,7 +581,7 @@ a specific data file. The default is to allow only the invoking user. Next: , Previous: , Up: Configuration   [Contents]

-

4 Configuring remote connections over TLS.

+

5 Configuring remote connections over TLS.

Remote connections can also be made to pwmd over TLS. Authentication is done by using X509 client certificates that are signed with the same Certificate Authority (CA) as the server certificate. @@ -632,7 +682,7 @@ information about the format of this string. The default is SECURE256Commands, Previous: , Up: Configuration   [Contents]

-

5 Pinentry configuration

+

6 Pinentry configuration

The pinentry program is used to prompt the user for passphrase input or as a confirmation dialog; it needs to know where to prompt for @@ -652,7 +702,7 @@ need be done only once per client connection. To avoid the use of Next: , Previous: , Up: Top   [Contents]

-

6 Protocol commands and their syntax

+

7 Protocol commands and their syntax

@@ -722,7 +772,7 @@ Next: , P Next: , Up: Commands   [Contents]

-

7 AGENT command

+

8 AGENT command

Syntax:

@@ -740,7 +790,7 @@ Next: , Up: , Previous: , Up: Commands   [Contents]

-

8 ATTR command

+

9 ATTR command

Syntax:

@@ -793,7 +843,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

9 CACHETIMEOUT command

+

10 CACHETIMEOUT command

Syntax:

@@ -814,7 +864,7 @@ parameter. Next: , Previous: , Up: Commands   [Contents]

-

10 CLEARCACHE command

+

11 CLEARCACHE command

Syntax:

@@ -831,7 +881,7 @@ Next: , Previous: , Previous: , Up: Commands   [Contents]

-

11 COPY command

+

12 COPY command

Syntax:

@@ -859,7 +909,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

12 DELETE command

+

13 DELETE command

Syntax:

@@ -881,7 +931,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

13 DUMP command

+

14 DUMP command

Syntax:

@@ -899,7 +949,7 @@ dumping a specific node. Next: , Previous: , Up: Commands   [Contents]

-

14 GET command

+

15 GET command

Syntax:

@@ -920,7 +970,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

15 GETCONFIG command

+

16 GETCONFIG command

Syntax:

@@ -941,7 +991,7 @@ set with the OPTION command (see OPTION) will Next: , Previous: , Up: Commands   [Contents]

-

16 GETINFO command

+

17 GETINFO command

Syntax:

@@ -967,7 +1017,7 @@ via a data response rather than a status message. Next: , Previous: , Up: Commands   [Contents]

-

17 HELP command

+

18 HELP command

Syntax:

@@ -984,7 +1034,7 @@ Next: , Previous: , Previous: , Up: Commands   [Contents]

-

18 IMPORT command

+

19 IMPORT command

Syntax:

@@ -1010,7 +1060,7 @@ for details. Next: , Previous: , Up: Commands   [Contents]

-

19 ISCACHED command

+

20 ISCACHED command

Syntax:

@@ -1035,7 +1085,7 @@ command. Next: , Previous: , Up: Commands   [Contents]

-

20 KEYGRIP command

+

21 KEYGRIP command

Syntax:

@@ -1059,7 +1109,7 @@ GPG_ERR_NOT_SUPPORTED. Next: , Previous: , Up: Commands   [Contents]

-

21 LIST command

+

22 LIST command

Syntax:

@@ -1108,7 +1158,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

22 LOCK command

+

23 LOCK command

Syntax:

@@ -1128,7 +1178,7 @@ command. See UNLOCK. Next: , Previous: , Up: Commands   [Contents]

-

23 LS command

+

24 LS command

Syntax:

@@ -1146,7 +1196,7 @@ Next: , Previous: , Previous: , Up: Commands   [Contents]

-

24 MOVE command

+

25 MOVE command

Syntax:

@@ -1170,7 +1220,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

25 NOP command

+

26 NOP command

Syntax:

@@ -1187,7 +1237,7 @@ Next: , Previous: , Previous: , Up: Commands   [Contents]

-

26 OPEN command

+

27 OPEN command

Syntax:

@@ -1214,7 +1264,7 @@ file has been opened. Next: , Previous: , Up: Commands   [Contents]

-

27 OPTION command

+

28 OPTION command

Syntax:

@@ -1293,7 +1343,7 @@ an error. When -1, then an error will be returned immediately. Next: , Previous: , Up: Commands   [Contents]

-

28 PASSWD command

+

29 PASSWD command

Syntax:

@@ -1323,7 +1373,7 @@ the data file, although a passphrase may be required when changing it. Next: , Previous: , Up: Commands   [Contents]

-

29 REALPATH command

+

30 REALPATH command

Syntax:

@@ -1344,7 +1394,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

30 RENAME command

+

31 RENAME command

Syntax:

@@ -1365,7 +1415,7 @@ arguments are retrieved via a server INQUIRE. Next: , Previous: , Up: Commands   [Contents]

-

31 RESET command

+

32 RESET command

Syntax:

@@ -1382,7 +1432,7 @@ Next: , Previous: , Previous: , Up: Commands   [Contents]

-

32 SAVE command

+

33 SAVE command

Syntax:

@@ -1443,7 +1493,7 @@ has no effect with symmetrically encrypted data files. Next: , Previous: , Up: Commands   [Contents]

-

33 STORE command

+

34 STORE command

Syntax:

@@ -1474,7 +1524,7 @@ to prevent XML parsing and pwmd syntax errors. Next: , Previous: , Up: Commands   [Contents]

-

34 UNLOCK command

+

35 UNLOCK command

Syntax:

@@ -1493,7 +1543,7 @@ see ISCACHED). Next: , Previous: , Up: Commands   [Contents]

-

35 XPATH command

+

36 XPATH command

Syntax:

@@ -1528,7 +1578,7 @@ expression syntax. Previous: , Up: Commands   [Contents]

-

36 XPATHATTR command

+

37 XPATHATTR command

Syntax:

@@ -1562,7 +1612,7 @@ expression syntax. Next: , Previous: , Up: Top   [Contents]

-

37 Status messages and their meanings

+

38 Status messages and their meanings

Some commands send status messages to inform the client about certain operations or as a progress indicator. Status messages begin with a KEYWORD followed by a status description for status messages that @@ -1615,7 +1665,7 @@ and the other being the total bytes to be transferred. Next: , Previous: , Up: Top   [Contents]

-

38 The target attribute

+

39 The target attribute

A case sensitive attribute named target is treated specially when found in each element of an element path. This attribute, like other @@ -1673,7 +1723,7 @@ path after resolving all target attributes. Next: , Previous: , Up: Top   [Contents]

-

39 Recognized signals

+

40 Recognized signals

Sending the SIGHUP signal to a pwmd process will reload the configuration file and sending SIGUSR1 will clear the entire file @@ -1697,44 +1747,45 @@ Previous: , Up:

@@ -1746,44 +1797,45 @@ Previous: , Up: diff --git a/doc/pwmd.texi b/doc/pwmd.texi index fa5d45a2..c32efa43 100644 --- a/doc/pwmd.texi +++ b/doc/pwmd.texi @@ -34,6 +34,7 @@ their syntax. @menu * Introduction:: Overview of pwmd. +* Access Control:: ACL of a single XML element. * Invoking:: Command line options. * Configuration:: Configuration file options. * Commands:: Protocol commands. @@ -44,7 +45,7 @@ their syntax. @end menu @c Node, Next, Previous, Up -@node Introduction, Invoking, , Top +@node Introduction, Access Control, , Top @chapter Overview of @command{pwmd} @manpage pwmd.1 @@ -121,7 +122,36 @@ characters. It also cannot begin with a @samp{!} since this character is reserved for the @code{target} attribute. @xref{Target Attribute}. @c Node, Next, Previous, Up -@node Invoking, Configuration, Introduction, Top +@node Access Control, Invoking, Introduction, Top +@chapter Access Control + +Like a filesystem has an @abbr{ACL} to grant or limit access to directories or +files for a specific user or group, @command{pwmd} can limit a local user, +group or a TLS connection to a specific element path. This is done by storing +an ACL in the element attribute @code{_acl}. Its syntax is similar to the +@code{allowed} configuration parameter (@pxref{Configuration}) with the +exception that a TLS fingerprint hash is prefixed with a @key{#}. + +Access is denied for all users that are not in the ACL of an element with the +exception of the invoking user (see the @code{invoking_user} and +@code{invoking_tls} configuration parameters (@pxref{Configuration})). The +connected client must be in the @abbr{ACL} for each element in an element +path otherwise an error is returned. As an example: + +@example + + + +@end example + +The user @code{username} would be allowed access to the @code{test} element +but not if it is a member of the @code{wheel} group. Although the @code{root} +user, who may be a member of the @code{wheel} group, is allowed. No users +other than the @code{invoking_user} is allowed access to the @code{child} +element. + +@c Node, Next, Previous, Up +@node Invoking, Configuration, Access Control, Top @chapter Invoking @command{pwmd} @mancont @@ -280,6 +310,18 @@ Listen on the specified socket. The default is @file{~/.pwmd/socket}. Permissions to set after creating the socket. This will override any @cite{umask(2)} setting. +@item invoking_user = username +This parameter is not to be confused with setuid or setguid upon startup. It +is the local username that may use the @command{XPATH}, @command{XPATHATTR} +and @command{DUMP} commands (except when disabled with the +@code{disable_list_and_dump} option). Other users are denied access to these +commands. This also specifies the user that may access any elements that lack +an @code{_acl} attribute (@pxref{Access Control}). The default is the current +user. + +@item invoking_tls = hash +Like @code{invoking_user}, but is a hash of a TLS certificate fingerprint. + @item allowed = [-]user,[-]@@group,... A comma separated list of local user names or group names allowed to connect to the socket. Groups should be prefixed with a @samp{@@}. When not specified diff --git a/src/commands.c b/src/commands.c index df7a6c61..9f87a498 100644 --- a/src/commands.c +++ b/src/commands.c @@ -2447,8 +2447,10 @@ dump_command (assuan_context_t ctx, char *line) if (disable_list_and_dump == 1) return send_error (ctx, GPG_ERR_NOT_IMPLEMENTED); - else if (client->thd->peer->uid != invoking_uid) - return send_error (ctx, GPG_ERR_EPERM); + + rc = peer_is_self(client); + if (rc) + return send_error (ctx, rc); xmlDocDumpFormatMemory (client->doc, &xml, &len, 1); @@ -2666,8 +2668,10 @@ xpath_command (assuan_context_t ctx, char *line) if (disable_list_and_dump == 1) return send_error (ctx, GPG_ERR_NOT_IMPLEMENTED); - else if (client->thd->peer->uid != invoking_uid) - return send_error (ctx, GPG_ERR_EPERM); + + rc = peer_is_self(client); + if (rc) + return send_error (ctx, rc); rc = parse_options (&line, args, client); if (rc) @@ -2787,8 +2791,10 @@ xpathattr_command (assuan_context_t ctx, char *line) if (disable_list_and_dump == 1) return send_error (ctx, GPG_ERR_NOT_IMPLEMENTED); - else if (client->thd->peer->uid != invoking_uid) - return send_error (ctx, GPG_ERR_EPERM); + + rc = peer_is_self(client); + if (rc) + return send_error (ctx, rc); rc = parse_options (&line, args, client); if (rc) diff --git a/src/common.h b/src/common.h index 32c95266..87391a0c 100644 --- a/src/common.h +++ b/src/common.h @@ -110,5 +110,6 @@ gpg_error_t do_validate_peer (assuan_context_t ctx, const char *section, assuan_peercred_t * peer); gpg_error_t acl_check_common (struct client_s *client, const char *user, uid_t uid, gid_t gid, int *allowed); +gpg_error_t peer_is_self(struct client_s *client); #endif diff --git a/src/pwmd.c b/src/pwmd.c index 42dfa20d..22e452c0 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -603,9 +603,9 @@ do_validate_peer (assuan_context_t ctx, const char *section, char **users; int allowed = 0; gpg_error_t rc; -#ifdef WITH_GNUTLS struct client_s *client = assuan_get_pointer (ctx); +#ifdef WITH_GNUTLS if (client && client->thd->remote) return tls_validate_access (client, section); #endif @@ -629,6 +629,33 @@ do_validate_peer (assuan_context_t ctx, const char *section, return allowed ? 0 : GPG_ERR_INV_USER_ID; } +gpg_error_t +peer_is_self(struct client_s *client) +{ +#ifdef WITH_GNUTLS + if (client->thd->remote) + { + char *p = invoking_tls; + + if (!p) + return GPG_ERR_EPERM; + + if (*p == '#') // to avoid confusion with ACLs, accept the prefix + p++; + + if (!strcmp(client->thd->tls->fp, p)) + return 0; + + return GPG_ERR_EPERM; + } +#endif + + if (client->thd->peer->uid == invoking_uid) + return 0; + + return GPG_ERR_EPERM; +} + #ifdef HAVE_GETGRNAM_R gpg_error_t acl_check_common (struct client_s *client, const char *user, uid_t uid, @@ -669,6 +696,10 @@ acl_check_common (struct client_s *client, const char *user, uid_t uid, return 0; #endif } +#ifdef WITH_GNUTLS + else if (client->thd->remote) // Remote client with no TLS in the ACL + return 0; +#endif if (*user == '@') // all users in group { @@ -3113,6 +3144,7 @@ do_exit: xfree (socketarg); #ifdef WITH_GNUTLS gnutls_global_deinit (); + xfree (invoking_tls); #endif if (rcfile_tid) { diff --git a/src/rcfile.c b/src/rcfile.c index e30b03ca..9a5fe828 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -100,6 +100,7 @@ static struct config_params_s { "use_agent", PARAM_BOOL, "false"}, { "require_save_key", PARAM_BOOL, "true"}, { "invoking_user", PARAM_CHARP, NULL}, + { "invoking_tls", PARAM_CHARP, NULL}, { NULL, 0, NULL}, }; @@ -743,7 +744,10 @@ set_defaults (struct slist_s **config) } xfree (s); - // FIXME default TLS fp hash +#ifdef WITH_GNUTLS + invoking_tls = config_get_string_param(*config, "global", "invoking_tls", + &exists); +#endif invoking_uid = pwd->pw_uid; invoking_gid = pwd->pw_gid; return 0; diff --git a/src/rcfile.h b/src/rcfile.h index 84200155..129ce1c6 100644 --- a/src/rcfile.h +++ b/src/rcfile.h @@ -50,6 +50,7 @@ pthread_cond_t rcfile_cond; pthread_t rcfile_tid; uid_t invoking_uid; gid_t invoking_gid; +char *invoking_tls; struct slist_s *config_parse (const char *filename); void config_clear_keys (); diff --git a/src/tls.c b/src/tls.c index 82d10854..57f048e5 100644 --- a/src/tls.c +++ b/src/tls.c @@ -432,7 +432,7 @@ do_tls_validate_access (struct client_s *client, const char *section) int not = 0; char *fp = *p; - if (*fp && *fp == '+' && *(fp + 1) == 0) + if (*fp && *fp == '+' && *(fp + 1) == 0) // allow all connections { allowed = 1; continue; @@ -446,6 +446,9 @@ do_tls_validate_access (struct client_s *client, const char *section) break; } + if (*fp == '#') // avoid confusion with ACL's: allow prefixing the hash + fp++; + if (!strcasecmp (client->thd->tls->fp, fp)) allowed = not ? 0 : 1; } diff --git a/src/xml.c b/src/xml.c index c8e2c9f1..0812946f 100644 --- a/src/xml.c +++ b/src/xml.c @@ -169,31 +169,32 @@ attr_ctime (xmlNodePtr n) static gpg_error_t acl_check (struct client_s *client, xmlNodePtr n) { - gpg_error_t rc; + gpg_error_t rc = GPG_ERR_EPERM; xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl"); char **users = acl ? str_split((char *)acl, ",", 0) : NULL; char **p; int allowed = 0; - if (client->thd->peer->uid == invoking_uid) - return 0; - if (!acl || !users || !*users) { strv_free(users); - - if (client->thd->peer->uid != invoking_uid) - return GPG_ERR_EPERM; - - return 0; + return peer_is_self(client); } + if (!peer_is_self(client)) + return 0; + for (p = users; *p; p++) { - fprintf(stderr, "checking %s\n", *p); +#ifdef WITH_GNUTLS + rc = acl_check_common (client, *p, + client->thd->remote ? 0 : client->thd->peer->uid, + client->thd->remote ? 0 : client->thd->peer->gid, + &allowed); +#else rc = acl_check_common (client, *p, client->thd->peer->uid, client->thd->peer->gid, &allowed); - fprintf(stderr, "result: %i, %i\n", rc, allowed); +#endif } xmlFree(acl); -- 2.11.4.GIT