Implement "bos addkey"
authorDavid Howells <dhowells@redhat.com>
Tue, 29 Apr 2014 18:12:26 +0000 (19:12 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 29 Apr 2014 18:12:26 +0000 (19:12 +0100)
Implement "bos addkey".  This requires the Kerberos library for the
string-to-key password transformation.

Signed-off-by: David Howells <dhowells@redhat.com>
compile_pykafs.py
py_passwd.c [new file with mode: 0644]
py_rxgen.h
rpc-api/bos.xg
rxgen/emit_py_module.pm
suite/commands/bos/addkey.py [new file with mode: 0644]

index 38206fd74132b20d468c368ec90f0037d3ccf6f6..aaba755d7ab8caa18d58fc48c227ea078520aeb3 100644 (file)
@@ -4,6 +4,7 @@ setup(name="kafs", version="0.1",
                              sources = [ "afs_xg.c",
                                          "kafs.c",
                                          "afs_py.c",
+                                         "py_passwd.c",
                                          "py_rxgen.c",
                                          "py_rxconn.c",
                                          "py_rxsplit.c",
@@ -13,4 +14,8 @@ setup(name="kafs", version="0.1",
                                  "-O0",
                                  "-Wp,-U_FORTIFY_SOURCE",
                              ],
+                             libraries = [
+                                 "k5crypto",
+                                 "krb5"
+                             ]
                          )])
diff --git a/py_passwd.c b/py_passwd.c
new file mode 100644 (file)
index 0000000..761caf7
--- /dev/null
@@ -0,0 +1,86 @@
+/* Password-to-key service
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <Python.h>
+#include "structmember.h"
+#include <krb5/krb5.h>
+#include "py_rxgen.h"
+
+/*
+ * Convert a string to an AFS DES key.
+ */
+PyObject *kafs_py_string_to_key(PyObject *_self, PyObject *args)
+{
+       krb5_error_code kresult;
+       krb5_context k5_ctx;
+       krb5_enctype enctype = ENCTYPE_DES_CBC_CRC;
+       krb5_data password;
+       krb5_data cellname;
+       krb5_data params;
+       krb5_keyblock key;
+       Py_buffer view;
+       PyObject *result;
+       char parambuf[1];
+
+       if (!PyArg_ParseTuple(args, "s#s#",
+                             &password.data, &password.length,
+                             &cellname.data, &cellname.length))
+               return NULL;
+
+       kresult = krb5_init_context(&k5_ctx);
+       if (kresult)
+               return PyErr_Format(PyExc_RuntimeError,
+                                   "Krb5: Failed to init context: %s",
+                                   krb5_get_error_message(k5_ctx, kresult));
+
+       password.magic = 0;
+       cellname.magic = 0;
+
+       /* Tell Kerberos to use the AFS-form DES */
+       parambuf[0] = 1;
+       params.data = parambuf;
+       params.length = 1;
+       params.magic = 0;
+
+       kresult = krb5_c_string_to_key_with_params(k5_ctx,
+                                                  enctype,
+                                                  &password,
+                                                  &cellname,
+                                                  &params,
+                                                  &key);
+       if (kresult) {
+               PyErr_Format(PyExc_RuntimeError,
+                            "Krb5: Failed to convert string to key: %s",
+                            krb5_get_error_message(k5_ctx, kresult));
+               krb5_free_context(k5_ctx);
+               return NULL;
+       }
+
+       result = PyByteArray_FromStringAndSize("", 0);
+       if (!result)
+               goto out;
+       if (PyByteArray_Resize(result, key.length) == -1)
+               goto out_free_result;
+       if (PyObject_GetBuffer(result, &view, PyBUF_SIMPLE | PyBUF_WRITABLE) < 0)
+               goto out_free_result;
+       memcpy(view.buf, key.contents, key.length);
+       PyBuffer_Release(&view);
+
+out:
+       krb5_free_keyblock_contents(k5_ctx, &key);
+       krb5_free_context(k5_ctx);
+       return result;
+
+out_free_result:
+       Py_DECREF(result);
+       result = NULL;
+       goto out;
+}
index ecf7b45f965b59c4d0bc3747fcc0c20ed79d5a3a..eb98fe5d1fc0787987378c7410399a8f81ce8a95 100644 (file)
@@ -48,6 +48,7 @@ struct py_rx_split_call {
 extern PyTypeObject py_rx_connectionType;
 
 extern PyObject *kafs_py_rx_new_connection(PyObject *, PyObject *);
+extern PyObject *kafs_py_string_to_key(PyObject *, PyObject *);
 
 extern int py_rxgen_initialise_members(PyObject *obj, PyObject *kw);
 
index edbb8a1b444ec3c422e7e55cc14eae80de6dbaba..443f11964b071501336ccbead67c74e7a6f2b311 100644 (file)
@@ -52,6 +52,7 @@ const BZSYNTAX                        = 39431;
 const BZIO                     = 39432;
 const BZNET                    = 39433;
 const BZBADTYPE                        = 39434;
+const BZKVNOINUSE              = 39435;
 
 const BOZO_BSSIZE              = 256;
 
index 7724c445f3c9ea19b585ee955fffa48634dc333e..1760eb03a0599f34ac4d9b99e93426b533f891c1 100644 (file)
@@ -52,6 +52,7 @@ sub emit_py_module() {
     print PYOUT "static PyMethodDef module_methods[] = {\n";
 
     print PYOUT "\t{\"rx_new_connection\", (PyCFunction)kafs_py_rx_new_connection, METH_VARARGS, \"\" },\n";
+    print PYOUT "\t{\"afs_string_to_key\", (PyCFunction)kafs_py_string_to_key, METH_VARARGS, \"\" },\n";
 
     foreach my $def (@py_func_defs) {
        print PYOUT "\t{\"", $def->{name}, "\", (PyCFunction)", $def->{c_func}, ", METH_VARARGS,";
diff --git a/suite/commands/bos/addkey.py b/suite/commands/bos/addkey.py
new file mode 100644 (file)
index 0000000..b18e323
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# AFS Server management toolkit: Add server keys
+# -*- coding: utf-8 -*-
+#
+
+__copyright__ = """
+Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+Written by David Howells (dhowells@redhat.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public Licence version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from afs.exception import AFSException
+from afs.argparse import *
+from afs.lib.output import *
+from afs.lib.time import *
+import kafs
+from getpass import getpass
+
+help = "Add a new server encryption key to the KeyFile file"
+
+command_arguments = [
+    [ "server",         get_bosserver,          "rs",         "<machine name>" ],
+    [ "key",            get_string,             "os"          "<key>" ],
+    [ "kvno",           get_string,             "rs"          "<key version number>" ],
+    [ "cell",           get_cell,               "os",         "<cell name>" ],
+    [ "noauth",         get_auth,               "fn" ],
+    [ "localauth",      get_auth,               "fn" ],
+    [ "verbose",        get_verbose,            "fn" ],
+    [ "encrypt",        get_dummy,              "fn" ],
+]
+
+cant_combine_arguments = [
+    ( "cell",           "localauth" ),
+    ( "noauth",         "localauth" ),
+]
+
+description = r"""
+Add a new server encryption key to the KeyFile file
+"""
+
+def main(params):
+    cell = params["cell"]
+    bos_conn = cell.open_bos_server(params["server"], params)
+
+    if "key" in params:
+        passwd = params["key"]
+    else:
+        passwd = getpass("Input key: ")
+        passwd2 = getpass("Retype input key: ")
+        if passwd != passwd2:
+            raise RuntimeError("Input key mismatch")
+
+    salted_passwd = kafs.afs_string_to_key(passwd, str(cell))
+    key = kafs.bozo_key()
+    key.data = salted_passwd
+
+    a = ""
+    for i in key.data:
+        a += "{:02x}".format(i)
+    verbose("Key: {:d}: ".format(len(key.data)), a, "\n")
+
+    try:
+        ret = kafs.BOZO_AddKey(bos_conn, int(params["kvno"]), key)
+    except kafs.AbortBZKVNOINUSE:
+        errorf("failed to set key {:s} (kvno already used - have to remove existing kvno's before reuse)\n", params["kvno"])