aboutsummaryrefslogtreecommitdiff
path: root/server/wallet-backend.8
diff options
context:
space:
mode:
Diffstat (limited to 'server/wallet-backend.8')
-rw-r--r--server/wallet-backend.8429
1 files changed, 429 insertions, 0 deletions
diff --git a/server/wallet-backend.8 b/server/wallet-backend.8
new file mode 100644
index 0000000..9bd8510
--- /dev/null
+++ b/server/wallet-backend.8
@@ -0,0 +1,429 @@
+.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.if !\nF .nr F 0
+.if \nF>0 \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "WALLET-BACKEND 8"
+.TH WALLET-BACKEND 8 "2018-06-04" "1.4" "wallet"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+wallet\-backend \- Wallet server for storing and retrieving secure data
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBwallet-backend\fR [\fB\-q\fR] \fIcommand\fR [\fIargs\fR ...]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBwallet-backend\fR implements the interface between \fBremctld\fR and the
+wallet system. It is written to run under \fBremctld\fR and expects the
+authenticated identity of the remote user in the \s-1REMOTE_USER\s0 environment
+variable. It uses \s-1REMOTE_HOST\s0 or \s-1REMOTE_ADDR\s0 if \s-1REMOTE_HOST\s0 isn't set for
+additional trace information. It accepts the command from \fBremctld\fR on
+the command line, creates a Wallet::Server object, and calls the
+appropriate methods.
+.PP
+This program is a fairly thin wrapper around Wallet::Server that
+translates command strings into method calls and returns the results. It
+does check all arguments except for the <data> argument to the store
+command and rejects any argument not matching \f(CW\*(C`^[\ew_/.\-]+\ez\*(C'\fR; in other
+words, only alphanumerics, underscore (\f(CW\*(C`_\*(C'\fR), slash (\f(CW\*(C`/\*(C'\fR), period (\f(CW\*(C`.\*(C'\fR),
+and hyphen (\f(CW\*(C`\-\*(C'\fR) are permitted in arguments. This provides some
+additional security over and above the checking already done by the rest
+of the wallet code.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.IP "\fB\-\-quiet\fR, \fB\-q\fR" 4
+.IX Item "--quiet, -q"
+If this option is given, \fBwallet-backend\fR will not log its actions to
+syslog.
+.SH "COMMANDS"
+.IX Header "COMMANDS"
+Most commands are only available to wallet administrators (users on the
+\&\f(CW\*(C`ADMIN\*(C'\fR \s-1ACL\s0). The exceptions are \f(CW\*(C`acl check\*(C'\fR, \f(CW\*(C`check\*(C'\fR, \f(CW\*(C`get\*(C'\fR,
+\&\f(CW\*(C`store\*(C'\fR, \f(CW\*(C`show\*(C'\fR, \f(CW\*(C`destroy\*(C'\fR, \f(CW\*(C`flag clear\*(C'\fR, \f(CW\*(C`flag set\*(C'\fR, \f(CW\*(C`getattr\*(C'\fR,
+\&\f(CW\*(C`setattr\*(C'\fR, and \f(CW\*(C`history\*(C'\fR. \f(CW\*(C`acl check\*(C'\fR and \f(CW\*(C`check\*(C'\fR can be run by
+anyone. All of the rest of those commands have their own ACLs except
+\&\f(CW\*(C`getattr\*(C'\fR and \f(CW\*(C`history\*(C'\fR, which use the \f(CW\*(C`show\*(C'\fR \s-1ACL,\s0 \f(CW\*(C`setattr\*(C'\fR, which
+uses the \f(CW\*(C`store\*(C'\fR \s-1ACL,\s0 and \f(CW\*(C`comment\*(C'\fR, which uses the owner or \f(CW\*(C`show\*(C'\fR \s-1ACL\s0
+depending on whether one is setting or retrieving the comment. If the
+appropriate \s-1ACL\s0 is set, it alone is checked to see if the user has access.
+Otherwise, \f(CW\*(C`destroy\*(C'\fR, \f(CW\*(C`get\*(C'\fR, \f(CW\*(C`store\*(C'\fR, \f(CW\*(C`show\*(C'\fR, \f(CW\*(C`getattr\*(C'\fR, \f(CW\*(C`setattr\*(C'\fR,
+\&\f(CW\*(C`history\*(C'\fR, and \f(CW\*(C`comment\*(C'\fR access is permitted if the user is authorized
+by the owner \s-1ACL\s0 of the object.
+.PP
+Administrators can run any command on any object or \s-1ACL\s0 except for \f(CW\*(C`get\*(C'\fR
+and \f(CW\*(C`store\*(C'\fR. For \f(CW\*(C`get\*(C'\fR and \f(CW\*(C`store\*(C'\fR, they must still be authorized by
+either the appropriate specific \s-1ACL\s0 or the owner \s-1ACL.\s0
+.PP
+If the locked flag is set on an object, no commands can be run on that
+object that change data except the \f(CW\*(C`flags\*(C'\fR commands, nor can the \f(CW\*(C`get\*(C'\fR
+command be used on that object. \f(CW\*(C`show\*(C'\fR, \f(CW\*(C`history\*(C'\fR, \f(CW\*(C`getacl\*(C'\fR,
+\&\f(CW\*(C`getattr\*(C'\fR, and \f(CW\*(C`owner\*(C'\fR, \f(CW\*(C`comment\*(C'\fR, or \f(CW\*(C`expires\*(C'\fR without an argument
+can still be used on that object.
+.PP
+For more information on attributes, see \s-1ATTRIBUTES\s0.
+.IP "acl add <id> <scheme> <identifier>" 4
+.IX Item "acl add <id> <scheme> <identifier>"
+Add an entry with <scheme> and <identifier> to the \s-1ACL\s0 <id>. <id> may be
+either the name of an \s-1ACL\s0 or its numeric identifier.
+.IP "acl check <id>" 4
+.IX Item "acl check <id>"
+Check whether an \s-1ACL\s0 with the \s-1ID\s0 <id> already exists. If it does, prints
+\&\f(CW\*(C`yes\*(C'\fR; if not, prints \f(CW\*(C`no\*(C'\fR.
+.IP "acl create <name>" 4
+.IX Item "acl create <name>"
+Create a new, empty \s-1ACL\s0 with name <name>. When setting an \s-1ACL\s0 on an
+object with a set of entries that don't match an existing \s-1ACL,\s0 first
+create a new \s-1ACL\s0 with \f(CW\*(C`acl create\*(C'\fR, add the appropriate entries to it
+with \f(CW\*(C`acl add\*(C'\fR, and then set the \s-1ACL\s0 on an object with the \f(CW\*(C`owner\*(C'\fR or
+\&\f(CW\*(C`setacl\*(C'\fR commands.
+.IP "acl destroy <id>" 4
+.IX Item "acl destroy <id>"
+Destroy the \s-1ACL\s0 <id>. This \s-1ACL\s0 must no longer be referenced by any object
+or the \s-1ACL\s0 destruction will fail. The special \s-1ACL\s0 named \f(CW\*(C`ADMIN\*(C'\fR cannot
+be destroyed.
+.IP "acl history <id>" 4
+.IX Item "acl history <id>"
+Display the history of the \s-1ACL\s0 <id>. Each change to the \s-1ACL\s0 (not
+including changes to the name of the \s-1ACL\s0) will be represented by two
+lines. The first line will have a timestamp of the change followed by a
+description of the change, and the second line will give the user who made
+the change and the host from which the change was made.
+.IP "acl remove <id> <scheme> <identifier>" 4
+.IX Item "acl remove <id> <scheme> <identifier>"
+Remove the entry with <scheme> and <identifier> from the \s-1ACL\s0 <id>. <id>
+may be either the name of an \s-1ACL\s0 or its numeric identifier. The last
+entry in the special \s-1ACL\s0 \f(CW\*(C`ADMIN\*(C'\fR cannot be removed to protect against
+accidental lockout, but administrators can remove themselves from the
+\&\f(CW\*(C`ADMIN\*(C'\fR \s-1ACL\s0 and can leave only a non-functioning entry on the \s-1ACL.\s0 Use
+caution when removing entries from the \f(CW\*(C`ADMIN\*(C'\fR \s-1ACL.\s0
+.IP "acl rename <id> <name>" 4
+.IX Item "acl rename <id> <name>"
+Renames the \s-1ACL\s0 identified by <id> to <name>. This changes the
+human-readable name, not the underlying numeric \s-1ID,\s0 so the \s-1ACL\s0's
+associations with objects will be unchanged. The \f(CW\*(C`ADMIN\*(C'\fR \s-1ACL\s0 may not be
+renamed. <id> may be either the current name or the numeric \s-1ID.\s0 <name>
+must not be all-numeric. To rename an \s-1ACL,\s0 the current user must be
+authorized by the \f(CW\*(C`ADMIN\*(C'\fR \s-1ACL.\s0
+.IP "acl replace <id> <new\-id>" 4
+.IX Item "acl replace <id> <new-id>"
+Find any objects owned by <id>, and then change their ownership to
+<new_id> instead. <new\-id> should already exist, and may already have
+some objects owned by it. <id> is not deleted afterwards, though in
+most cases that is probably your next step. The \f(CW\*(C`ADMIN\*(C'\fR \s-1ACL\s0 may not be
+replaced from. <id> and <new\-id> may be either the current name or the
+numeric \s-1ID.\s0 To replace an \s-1ACL,\s0 the current user must be authorized by
+the \f(CW\*(C`ADMIN\*(C'\fR \s-1ACL.\s0
+.IP "acl show <id>" 4
+.IX Item "acl show <id>"
+Display the name, numeric \s-1ID,\s0 and entries of the \s-1ACL\s0 <id>.
+.IP "autocreate <type> <name>" 4
+.IX Item "autocreate <type> <name>"
+Create a new object of type <type> with name <name>. The user must be
+listed in the default \s-1ACL\s0 for an object with that type and name, and the
+object will be created with that default \s-1ACL\s0 set as the object owner.
+.IP "check <type> <name>" 4
+.IX Item "check <type> <name>"
+Check whether an object of type <type> and name <name> already exists. If
+it does, prints \f(CW\*(C`yes\*(C'\fR; if not, prints \f(CW\*(C`no\*(C'\fR.
+.IP "comment <type> <name> [<comment>]" 4
+.IX Item "comment <type> <name> [<comment>]"
+If <comment> is not given, displays the current comment for the object
+identified by <type> and <name>, or \f(CW\*(C`No comment set\*(C'\fR if none is set.
+.Sp
+If <comment> is given, sets the comment on the object identified by
+<type> and <name> to <comment>. If <comment> is the empty string, clears
+the comment.
+.IP "create <type> <name>" 4
+.IX Item "create <type> <name>"
+Create a new object of type <type> with name <name>. With some backends,
+this will trigger creation of an entry in an external system as well.
+The new object will have no ACLs and no owner set, so usually the
+administrator will want to then set an owner with \f(CW\*(C`owner\*(C'\fR so that the
+object will be usable.
+.IP "destroy <type> <name>" 4
+.IX Item "destroy <type> <name>"
+Destroy the object identified by <type> and <name>. With some backends,
+this will trigger destruction of an object in an external system as well.
+.IP "expires <type> <name> [<date> [<time>]]" 4
+.IX Item "expires <type> <name> [<date> [<time>]]"
+If <date> is not given, displays the current expiration of the object
+identified by <type> and <name>, or \f(CW\*(C`No expiration set\*(C'\fR if none is set.
+The expiration will be displayed in seconds since epoch.
+.Sp
+If <date> is given, sets the expiration on the object identified by <type>
+and <name> to <date> and (if given) <time>. <date> and <time> must be in
+some format that can be parsed by the Perl Date::Parse module. Most
+common formats are supported; if in doubt, use \f(CW\*(C`YYYY\-MM\-DD HH:MM:SS\*(C'\fR. If
+<date> is the empty string, clears the expiration of the object.
+.Sp
+Currently, the expiration of an object is not used.
+.IP "flag clear <type> <name> <flag>" 4
+.IX Item "flag clear <type> <name> <flag>"
+Clears the flag <flag> on the object identified by <type> and <name>.
+.IP "flag set <type> <name> <flag>" 4
+.IX Item "flag set <type> <name> <flag>"
+Sets the flag <flag> on the object identified by <type> and <name>.
+Recognized flags are \f(CW\*(C`locked\*(C'\fR, which prevents all further actions on that
+object until the flag is cleared, and \f(CW\*(C`unchanging\*(C'\fR, which tells the
+object backend to not generate new data on get but instead return the same
+data as previously returned. The \f(CW\*(C`unchanging\*(C'\fR flag is not meaningful for
+objects that do not generate new data on the fly.
+.IP "get <type> <name>" 4
+.IX Item "get <type> <name>"
+Prints to standard output the data associated with the object identified
+by <type> and <name>. This may trigger generation of new data and
+invalidate old data for that object depending on the object type.
+.IP "getacl <type> <name> <acl>" 4
+.IX Item "getacl <type> <name> <acl>"
+Prints the \s-1ACL\s0 <acl>, which must be one of \f(CW\*(C`get\*(C'\fR, \f(CW\*(C`store\*(C'\fR, \f(CW\*(C`show\*(C'\fR,
+\&\f(CW\*(C`destroy\*(C'\fR, or \f(CW\*(C`flags\*(C'\fR, for the object identified by <type> and <name>.
+Prints \f(CW\*(C`No ACL set\*(C'\fR if that \s-1ACL\s0 isn't set on that object. Remember that
+if the \f(CW\*(C`get\*(C'\fR, \f(CW\*(C`store\*(C'\fR, or \f(CW\*(C`show\*(C'\fR ACLs aren't set, authorization falls
+back to checking the owner \s-1ACL.\s0 See the \f(CW\*(C`owner\*(C'\fR command for displaying
+or setting it.
+.IP "getattr <type> <name> <attr>" 4
+.IX Item "getattr <type> <name> <attr>"
+Prints the object attribute <attr> for the object identified by <type> and
+<name>. Attributes are used to store backend-specific information for a
+particular object type, and <attr> must be an attribute type known to the
+underlying object implementation. The attribute values, if any, are
+printed one per line. If the attribute is not set on this object, nothing
+is printed.
+.IP "history <type> <name>" 4
+.IX Item "history <type> <name>"
+Displays the history for the object identified by <type> and <name>. This
+human-readable output will have two lines for each action that changes the
+object, plus for any get action. The first line has the timestamp of the
+action and the action, and the second line gives the user who performed
+the action and the host from which they performed it.
+.IP "owner <type> <name> [<owner>]" 4
+.IX Item "owner <type> <name> [<owner>]"
+If <owner> is not given, displays the current owner \s-1ACL\s0 of the object
+identified by <type> and <name>, or \f(CW\*(C`No owner set\*(C'\fR if none is set. The
+result will be the name of an \s-1ACL.\s0
+.Sp
+If <owner> is given, sets the owner of the object identified by <type> and
+<name> to <owner>. If <owner> is the empty string, clears the owner of
+the object.
+.IP "rename <type> <name> <new\-name>" 4
+.IX Item "rename <type> <name> <new-name>"
+Renames an existing object. This currently only supports file objects,
+where it renames the object itself, then the name and location of the
+object in the file store.
+.IP "setacl <type> <name> <acl> <id>" 4
+.IX Item "setacl <type> <name> <acl> <id>"
+Sets the \s-1ACL\s0 <acl>, which must be one of \f(CW\*(C`get\*(C'\fR, \f(CW\*(C`store\*(C'\fR, \f(CW\*(C`show\*(C'\fR,
+\&\f(CW\*(C`destroy\*(C'\fR, or \f(CW\*(C`flags\*(C'\fR, to <id> on the object identified by <type> and
+<name>. If <id> is the empty string, clears that \s-1ACL\s0 on the object.
+.IP "setattr <type> <name> <attr> <value> [<value> ...]" 4
+.IX Item "setattr <type> <name> <attr> <value> [<value> ...]"
+Sets the object attribute <attr> for the object identified by <type> and
+<name>. Attributes are used to store backend-specific information for a
+particular object type, and <attr> must be an attribute type known to the
+underlying object implementation. To clear the attribute for this object,
+pass in a <value> of the empty string (\f(CW\*(Aq\*(Aq\fR).
+.IP "show <type> <name>" 4
+.IX Item "show <type> <name>"
+Displays the current object metadata for the object identified by <type>
+and <name>. This human-readable output will show the object type and
+name, the owner, any specific ACLs set on the object, the expiration if
+any, and the user, remote host, and time when the object was created, last
+stored, and last downloaded.
+.IP "store <type> <name> [<data>]" 4
+.IX Item "store <type> <name> [<data>]"
+Stores <data> for the object identified by <type> and <name> for later
+retrieval with \f(CW\*(C`get\*(C'\fR. Not all object types support this. If <data> is
+not given as an argument, it will be read from standard input.
+.IP "update <type> <name>" 4
+.IX Item "update <type> <name>"
+Prints to standard output the data associated with the object identified
+by <type> and <name>. If the object is one that can have changing
+information, such as a keytab or password, then we generate new data for
+that object regardless of whether there is current data or the unchanging
+flag is set.
+.SH "ATTRIBUTES"
+.IX Header "ATTRIBUTES"
+Object attributes store additional properties and configuration
+information for objects stored in the wallet. They are displayed as part
+of the object data with \f(CW\*(C`show\*(C'\fR, retrieved with \f(CW\*(C`getattr\*(C'\fR, and set with
+\&\f(CW\*(C`setattr\*(C'\fR.
+.SS "Keytab Attributes"
+.IX Subsection "Keytab Attributes"
+Keytab objects support the following attributes:
+.IP "enctypes" 4
+.IX Item "enctypes"
+Restricts the generated keytab to a specific set of encryption types. The
+values of this attribute must be enctype strings recognized by Kerberos
+(strings like \f(CW\*(C`aes256\-cts\-hmac\-sha1\-96\*(C'\fR or \f(CW\*(C`des\-cbc\-crc\*(C'\fR). Note that
+the salt should not be included; since the salt is irrelevant for keytab
+keys, it will always be set to \f(CW\*(C`normal\*(C'\fR by the wallet.
+.Sp
+If this attribute is set, the specified enctype list will be passed to
+ktadd when \fIget()\fR is called for that keytab. If it is not set, the default
+set in the \s-1KDC\s0 will be used.
+.Sp
+This attribute is ignored if the \f(CW\*(C`unchanging\*(C'\fR flag is set on a keytab.
+Keytabs retrieved with \f(CW\*(C`unchanging\*(C'\fR set will contain all keys present in
+the \s-1KDC\s0 for that Kerberos principal and therefore may contain different
+enctypes than those requested by this attribute.
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Russ Allbery <eagle@eyrie.org>
+.SH "COPYRIGHT AND LICENSE"
+.IX Header "COPYRIGHT AND LICENSE"
+Copyright 2007\-2008, 2010\-2013 The Board of Trustees of the Leland Stanford
+Junior University
+.PP
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the \*(L"Software\*(R"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+.PP
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+.PP
+\&\s-1THE SOFTWARE IS PROVIDED \*(L"AS IS\*(R", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\s0 \s-1IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.\s0
+.PP
+SPDX-License-Identifier: \s-1MIT\s0
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIWallet::Server\fR\|(3), \fIremctld\fR\|(8)
+.PP
+This program is part of the wallet system. The current version is
+available from <https://www.eyrie.org/~eagle/software/wallet/>.