* $Id: krb5-security.c,v 1.22 2006/06/16 10:55:05 martinea Exp $
*
* krb5-security.c - kerberos V5 security module
+ *
+ * XXX still need to check for initial keyword on connect so we can skip
+ * over shell garbage and other stuff that krb5 might want to spew out.
*/
-#include "config.h"
-#ifdef KRB5_SECURITY
#include "amanda.h"
#include "util.h"
-#include "arglist.h"
#include "event.h"
#include "packet.h"
#include "queue.h"
#include "security-util.h"
#include "stream.h"
#include "version.h"
+#include "sockaddr-util.h"
+
+#ifdef KRB5_HEIMDAL_INCLUDES
+#include "com_err.h"
+#endif
-#define BROKEN_MEMORY_CCACHE
+#define BROKEN_MEMORY_CCACHE
#ifdef BROKEN_MEMORY_CCACHE
/*
#endif /* HAVE_ON_EXIT */
#endif /* ! HAVE_ATEXIT */
#endif
-
#ifndef KRB5_HEIMDAL_INCLUDES
#include <gssapi/gssapi_generic.h>
#else
#include <krb5.h>
#ifndef KRB5_ENV_CCNAME
-#define KRB5_ENV_CCNAME "KRB5CCNAME"
-#endif
-
-/*#define KRB5_DEBUG*/
-
-#ifdef KRB5_DEBUG
-#define k5printf(x) dbprintf(x)
-#else
-#define k5printf(x)
+#define KRB5_ENV_CCNAME "KRB5CCNAME"
#endif
/*
* consider undefining when kdestroy() is fixed. The current version does
* not work under krb5-1.2.4 in rh7.3, perhaps others.
*/
-#define KDESTROY_VIA_UNLINK 1
-
-/*
- * Define this if you want all network traffic encrypted. This will
- * extract a serious performance hit.
- *
- * It would be nice if we could do this on a filesystem-by-filesystem basis.
- */
-/*#define AMANDA_KRB5_ENCRYPT*/
+#define KDESTROY_VIA_UNLINK 1
/*
* Where the keytab lives, if defined. Otherwise it expects something in the
* config file.
*/
-/* #define AMANDA_KEYTAB "/.amanda-v5-keytab" */
+/* #define AMANDA_KEYTAB "/.amanda-v5-keytab" */
/*
* The name of the principal we authenticate with, if defined. Otherwise
* it expects something in the config file.
*/
-/* #define AMANDA_PRINCIPAL "service/amanda" */
+/* #define AMANDA_PRINCIPAL "service/amanda" */
/*
* The lifetime of our tickets in seconds. This may or may not need to be
* configurable.
*/
-#define AMANDA_TKT_LIFETIME (12*60*60)
+#define AMANDA_TKT_LIFETIME (12*60*60)
+
/*
* The name of the service in /etc/services. This probably shouldn't be
* configurable.
*/
-#define AMANDA_KRB5_SERVICE_NAME "k5amanda"
+#define AMANDA_KRB5_SERVICE_NAME "k5amanda"
/*
* The default port to use if above entry in /etc/services doesn't exist
*/
-#define AMANDA_KRB5_DEFAULT_PORT 10082
+#define AMANDA_KRB5_DEFAULT_PORT 10082
/*
* The timeout in seconds for each step of the GSS negotiation phase
*/
-#define GSS_TIMEOUT 30
-
-/*
- * The largest buffer we can send/receive.
- */
-#define AMANDA_MAX_TOK_SIZE (MAX_TAPE_BLOCK_BYTES * 4)
-
-/*
- * Magic values for krb5_conn->handle
- */
-#define H_EOF -1 /* this connection has been shut down */
+#define GSS_TIMEOUT 30
/*
* This is the tcp stream buffer size
*/
-#define KRB5_STREAM_BUFSIZE (MAX_TAPE_BLOCK_BYTES * 2)
+#define KRB5_STREAM_BUFSIZE (32768 * 2)
/*
* This is the max number of outgoing connections we can have at once.
* to contact everything. We need to limit this to avoid blowing
* the max number of open file descriptors a process can have.
*/
-#define AMANDA_KRB5_MAXCONN 40
+#define AMANDA_KRB5_MAXCONN 40
-/*
- * This is a frame read off of the connection. Each frame has an
- * associated handle and a gss_buffer which contains a len,value pair.
- */
-struct krb5_frame {
- int handle; /* proto handle */
- gss_buffer_desc tok; /* token */
- TAILQ_ENTRY(krb5_frame) tq; /* queue handle */
-};
/*
- * This is a krb5 connection to a host. We should only have
- * one connection per host.
+ * Number of seconds krb5 has to start up
*/
-struct krb5_conn {
- int fd; /* tcp connection */
- struct { /* buffer read() calls */
- char buf[KRB5_STREAM_BUFSIZE]; /* buffer */
- size_t left; /* unread data */
- ssize_t size; /* size of last read */
- } readbuf;
- enum { unauthed, authed } state;
- event_handle_t *ev_read; /* read (EV_READFD) handle */
- int ev_read_refcnt; /* number of readers */
- char hostname[MAX_HOSTNAME_LENGTH+1]; /* human form of above */
- char *errmsg; /* error passed up */
- gss_ctx_id_t gss_context; /* GSSAPI context */
- int refcnt; /* number of handles using */
- TAILQ_HEAD(, krb5_frame) frameq; /* queue of read frames */
- TAILQ_ENTRY(krb5_conn) tq; /* queue handle */
-};
-
-
-struct krb5_stream;
+#define CONNECT_TIMEOUT 20
/*
- * This is the private handle data.
+ * Cache the local hostname
*/
-struct krb5_handle {
- security_handle_t sech; /* MUST be first */
- char *hostname; /* ptr to kc->hostname */
- struct krb5_stream *ks; /* virtual stream we xmit over */
-
- union {
- void (*recvpkt)(void *, pkt_t *, security_status_t);
- /* func to call when packet recvd */
- void (*connect)(void *, security_handle_t *, security_status_t);
- /* func to call when connected */
- } fn;
- void *arg; /* argument to pass function */
- void *datap; /* argument to pass function */
- event_handle_t *ev_wait; /* wait handle for connects */
- char *(*conf_fn)(char *, void *); /* used to get config info */
- event_handle_t *ev_timeout; /* timeout handle for recv */
-};
+static char myhostname[MAX_HOSTNAME_LENGTH+1];
-/*
- * This is the internal security_stream data for krb5.
- */
-struct krb5_stream {
- security_stream_t secstr; /* MUST be first */
- struct krb5_conn *kc; /* physical connection */
- int handle; /* protocol handle */
- event_handle_t *ev_read; /* read (EV_WAIT) event handle */
- void (*fn)(void *, void *, ssize_t);/* read event fn */
- void *arg; /* arg for previous */
- char buf[KRB5_STREAM_BUFSIZE];
- ssize_t len;
-};
/*
* Interface functions
*/
-static ssize_t krb5_sendpkt(void *, pkt_t *);
-static int krb5_stream_accept(void *);
-static int krb5_stream_auth(void *);
-static int krb5_stream_id(void *);
-static int krb5_stream_write(void *, const void *, size_t);
-static void * krb5_stream_client(void *, int);
-static void * krb5_stream_server(void *);
-static void krb5_accept(const struct security_driver *, int, int,
- void (*)(security_handle_t *, pkt_t *));
-static void krb5_close(void *);
-static void krb5_connect(const char *, char *(*)(char *, void *),
- void (*)(void *, security_handle_t *, security_status_t),
- void *, void *);
-static void krb5_recvpkt(void *, void (*)(void *, pkt_t *, security_status_t),
- void *, int);
-static void krb5_recvpkt_cancel(void *);
-static void krb5_stream_close(void *);
-static void krb5_stream_read(void *, void (*)(void *, void *, ssize_t), void *);
-static ssize_t krb5_stream_read_sync(void *, void **);
-static void krb5_stream_read_cancel(void *);
+static void krb5_accept(const struct security_driver *,
+ char *(*)(char *, void *),
+ int, int,
+ void (*)(security_handle_t *, pkt_t *),
+ void *);
+static void krb5_connect(const char *,
+ char *(*)(char *, void *),
+ void (*)(void *, security_handle_t *, security_status_t), void *, void *);
+
+static void krb5_init(void);
+#ifdef BROKEN_MEMORY_CCACHE
+static void cleanup(void);
+#endif
+static const char *get_tgt(char *keytab_name, char *principal_name);
+static int gss_server(struct tcp_conn *);
+static int gss_client(struct sec_handle *);
+static const char *gss_error(OM_uint32, OM_uint32);
+static char *krb5_checkuser(char *host, char *name, char *realm);
+
+static int k5_encrypt(void *cookie, void *buf, ssize_t buflen,
+ void **encbuf, ssize_t *encbuflen);
+static int k5_decrypt(void *cookie, void *buf, ssize_t buflen,
+ void **encbuf, ssize_t *encbuflen);
/*
* This is our interface to the outside world.
*/
const security_driver_t krb5_security_driver = {
- "krb5",
+ "KRB5",
krb5_connect,
krb5_accept,
- krb5_close,
- krb5_sendpkt,
- krb5_recvpkt,
- krb5_recvpkt_cancel,
- krb5_stream_server,
- krb5_stream_accept,
- krb5_stream_client,
- krb5_stream_close,
- krb5_stream_auth,
- krb5_stream_id,
- krb5_stream_write,
- krb5_stream_read,
- krb5_stream_read_sync,
- krb5_stream_read_cancel,
- sec_close_connection_none,
+ sec_close,
+ stream_sendpkt,
+ stream_recvpkt,
+ stream_recvpkt_cancel,
+ tcpma_stream_server,
+ tcpma_stream_accept,
+ tcpma_stream_client,
+ tcpma_stream_close,
+ sec_stream_auth,
+ sec_stream_id,
+ tcpm_stream_write,
+ tcpm_stream_read,
+ tcpm_stream_read_sync,
+ tcpm_stream_read_cancel,
+ tcpm_close_connection,
+ k5_encrypt,
+ k5_decrypt,
};
-/*
- * Cache the local hostname
- */
-static char hostname[MAX_HOSTNAME_LENGTH+1];
-
-/*
- * This is a queue of open connections
- */
-static struct {
- TAILQ_HEAD(, krb5_conn) tailq;
- int qlength;
-} krb5_connq = {
- TAILQ_HEAD_INITIALIZER(krb5_connq.tailq), 0
-};
-#define krb5_connq_first() TAILQ_FIRST(&krb5_connq.tailq)
-#define krb5_connq_next(kc) TAILQ_NEXT(kc, tq)
-#define krb5_connq_append(kc) do { \
- TAILQ_INSERT_TAIL(&krb5_connq.tailq, kc, tq); \
- krb5_connq.qlength++; \
-} while (0)
-#define krb5_connq_remove(kc) do { \
- assert(krb5_connq.qlength > 0); \
- TAILQ_REMOVE(&krb5_connq.tailq, kc, tq); \
- krb5_connq.qlength--; \
-} while (0)
-
static int newhandle = 1;
-/*
- * This is a function that should be called if a new security_handle_t is
- * created. If NULL, no new handles are created.
- * It is passed the new handle and the received pkt
- */
-static void (*accept_fn)(security_handle_t *, pkt_t *);
-
/*
* Local functions
*/
-static void init(void);
-#ifdef BROKEN_MEMORY_CCACHE
-static void cleanup(void);
-#endif
-static const char *get_tgt(char *, char *);
-static void open_callback(void *);
-static void connect_callback(void *);
-static void connect_timeout(void *);
-static int send_token(struct krb5_conn *, int, const gss_buffer_desc *);
-static ssize_t recv_token(struct krb5_conn *, int *, gss_buffer_desc *, int);
-static void recvpkt_callback(void *, void *, ssize_t);
-static void recvpkt_timeout(void *);
-static void stream_read_callback(void *);
-static void stream_read_sync_callback2(void *, void *, ssize_t);
-static int gss_server(struct krb5_conn *);
-static int gss_client(struct krb5_handle *);
-static const char *gss_error(OM_uint32, OM_uint32);
-
-#ifdef AMANDA_KRB5_ENCRYPT
-static int kdecrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
-static int kencrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
-#endif
-static struct krb5_conn *conn_get(const char *);
-static void conn_put(struct krb5_conn *);
-static void conn_read(struct krb5_conn *);
-static void conn_read_cancel(struct krb5_conn *);
-static void conn_read_callback(void *);
-static int conn_run_frameq(struct krb5_conn *, struct krb5_stream *);
-static char * krb5_checkuser(char *, char *, char *);
+static int runkrb5(struct sec_handle *);
+char *keytab_name;
+char *principal_name;
/*
* krb5 version of a security handle allocator. Logically sets
void * arg,
void * datap)
{
- struct krb5_handle *kh;
- struct hostent *he;
- struct servent *se;
- int fd;
- int port;
- const char *err;
- char *keytab_name = NULL;
- char *principal_name = NULL;
+ struct sec_handle *rh;
+ int result;
+ char *canonname;
+ assert(fn != NULL);
assert(hostname != NULL);
- k5printf(("krb5_connect: %s\n", hostname));
+ auth_debug(1, "krb5: krb5_connect: %s\n", hostname);
- /*
- * Make sure we're initted
- */
- init();
+ krb5_init();
- kh = alloc(SIZEOF(*kh));
- security_handleinit(&kh->sech, &krb5_security_driver);
- kh->hostname = NULL;
- kh->ks = NULL;
- kh->ev_wait = NULL;
- kh->ev_timeout = NULL;
+ rh = alloc(sizeof(*rh));
+ security_handleinit(&rh->sech, &krb5_security_driver);
+ rh->hostname = NULL;
+ rh->rs = NULL;
+ rh->ev_timeout = NULL;
+ rh->rc = NULL;
+
+ result = resolve_hostname(hostname, 0, NULL, &canonname);
+ if(result != 0) {
+ dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result));
+ security_seterror(&rh->sech, _("resolve_hostname(%s): %s\n"), hostname,
+ gai_strerror(result));
+ (*fn)(arg, &rh->sech, S_ERROR);
+ return;
+ }
+ if (canonname == NULL) {
+ dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname);
+ security_seterror(&rh->sech,
+ _("resolve_hostname(%s) did not return a canonical name\n"), hostname);
+ (*fn)(arg, &rh->sech, S_ERROR);
+ return;
+ }
+
+ rh->hostname = canonname; /* will be replaced */
+ canonname = NULL; /* steal reference */
+ rh->rs = tcpma_stream_client(rh, newhandle++);
+ rh->rc->conf_fn = conf_fn;
+ rh->rc->datap = datap;
+ rh->rc->recv_security_ok = NULL;
+ rh->rc->prefix_packet = NULL;
+
+ if (rh->rs == NULL)
+ goto error;
+
+ amfree(rh->hostname);
+ rh->hostname = stralloc(rh->rs->rc->hostname);
#ifdef AMANDA_KEYTAB
keytab_name = AMANDA_KEYTAB;
#else
if(conf_fn) {
- keytab_name = conf_fn("krb5keytab", datap);
+ keytab_name = conf_fn("krb5keytab", datap);
}
#endif
#ifdef AMANDA_PRINCIPAL
principal_name = AMANDA_PRINCIPAL;
#else
if(conf_fn) {
- principal_name = conf_fn("krb5principal", datap);
+ principal_name = conf_fn("krb5principal", datap);
}
#endif
- if ((err = get_tgt(keytab_name, principal_name)) != NULL) {
- security_seterror(&kh->sech, "%s: could not get TGT: %s",
- hostname, err);
- (*fn)(arg, &kh->sech, S_ERROR);
- return;
- }
-
- if ((he = gethostbyname(hostname)) == NULL) {
- security_seterror(&kh->sech,
- "%s: could not resolve hostname", hostname);
- (*fn)(arg, &kh->sech, S_ERROR);
- return;
- }
- kh->fn.connect = fn;
- kh->conf_fn = conf_fn;
- kh->arg = arg;
- kh->datap = datap;
- kh->hostname = stralloc(he->h_name);
- kh->ks = krb5_stream_client(kh, newhandle++);
-
- if (kh->ks == NULL)
- goto error;
-
- fd = kh->ks->kc->fd;
-
- if (fd < 0) {
- /*
- * We need to open a new connection. See if we have too
- * many connections open.
- */
- if (krb5_connq.qlength > AMANDA_KRB5_MAXCONN) {
- k5printf(("krb5_connect: too many conections (%d), delaying %s\n",
- krb5_connq.qlength, kh->hostname));
- krb5_stream_close(kh->ks);
- kh->ev_wait = event_register((event_id_t)open_callback,
- EV_WAIT, open_callback, kh);
- return;
- }
-
- if ((se = getservbyname(AMANDA_KRB5_SERVICE_NAME, "tcp")) == NULL)
- port = htons(AMANDA_KRB5_DEFAULT_PORT);
- else
- port = se->s_port;
-
- /*
- * Get a non-blocking socket.
- */
- fd = stream_client(kh->hostname, ntohs(port), KRB5_STREAM_BUFSIZE,
- KRB5_STREAM_BUFSIZE, NULL, 1);
- if (fd < 0) {
- security_seterror(&kh->sech,
- "can't connect to %s:%d: %s", hostname, ntohs(port),
- strerror(errno));
+ /*
+ * We need to open a new connection.
+ *
+ * XXX need to eventually limit number of outgoing connections here.
+ */
+ if(rh->rc->read == -1) {
+ if (runkrb5(rh) < 0)
goto error;
- }
- kh->ks->kc->fd = fd;
+ rh->rc->refcnt++;
}
+
/*
* The socket will be opened async so hosts that are down won't
* block everything. We need to register a write event
* so we will know when the socket comes alive.
+ *
+ * Overload rh->rs->ev_read to provide a write event handle.
* We also register a timeout.
*/
- kh->ev_wait = event_register((event_id_t)fd, EV_WRITEFD,
- connect_callback, kh);
- kh->ev_timeout = event_register((event_id_t)GSS_TIMEOUT, EV_TIME,
- connect_timeout, kh);
-
+ rh->fn.connect = fn;
+ rh->arg = arg;
+ rh->rs->ev_read = event_register((event_id_t)(rh->rs->rc->write),
+ EV_WRITEFD, sec_connect_callback, rh);
+ rh->ev_timeout = event_register(CONNECT_TIMEOUT, EV_TIME,
+ sec_connect_timeout, rh);
+
+ amfree(canonname);
return;
error:
- (*fn)(arg, &kh->sech, S_ERROR);
-}
-
-/*
- * Called when there are not too many connections open such that
- * we can open more.
- */
-static void
-open_callback(
- void * cookie)
-{
- struct krb5_handle *kh = cookie;
-
- event_release(kh->ev_wait);
-
- k5printf(("krb5: open_callback: possible connections available, retry %s\n",
- kh->hostname));
- krb5_connect(kh->hostname, kh->conf_fn, kh->fn.connect, kh->arg,kh->datap);
- amfree(kh->hostname);
- amfree(kh);
+ amfree(canonname);
+ (*fn)(arg, &rh->sech, S_ERROR);
}
/*
- * Called when a tcp connection is finished connecting and is ready
- * to be authenticated.
- */
-static void
-connect_callback(
- void * cookie)
-{
- struct krb5_handle *kh = cookie;
-
- event_release(kh->ev_wait);
- kh->ev_wait = NULL;
- event_release(kh->ev_timeout);
- kh->ev_timeout = NULL;
-
- if (kh->ks->kc->state == unauthed) {
- if (gss_client(kh) < 0) {
- (*kh->fn.connect)(kh->arg, &kh->sech, S_ERROR);
- return;
- }
- kh->ks->kc->state = authed;
- }
- assert(kh->ks->kc->gss_context != GSS_C_NO_CONTEXT);
-
- (*kh->fn.connect)(kh->arg, &kh->sech, S_OK);
-}
-
-/*
- * Called if a connection times out before completion.
- */
-static void
-connect_timeout(
- void * cookie)
-{
- struct krb5_handle *kh = cookie;
-
- event_release(kh->ev_wait);
- kh->ev_wait = NULL;
- event_release(kh->ev_timeout);
- kh->ev_timeout = NULL;
-
- (*kh->fn.connect)(kh->arg, &kh->sech, S_TIMEOUT);
-}
-/*
* Setup to handle new incoming connections
*/
static void
krb5_accept(
const struct security_driver *driver,
+ char *(*conf_fn)(char *, void *),
int in,
int out,
- void (*fn)(security_handle_t *, pkt_t *))
-{
- struct sockaddr_in sin;
- socklen_t len;
- struct krb5_conn *kc;
- struct hostent *he;
-
- /*
- * Make sure we're initted
- */
- init();
-
- /* shut up compiler */
- driver=driver;
- out=out;
-
- len = SIZEOF(sin);
- if (getpeername(in, (struct sockaddr *)&sin, &len) < 0)
- return;
- he = gethostbyaddr((void *)&sin.sin_addr, SIZEOF(sin.sin_addr), AF_INET);
- if (he == NULL)
- return;
-
- kc = conn_get(he->h_name);
- kc->fd = in;
- if (gss_server(kc) < 0)
- error("gss_server failed: %s\n", kc->errmsg);
- kc->state = authed;
- accept_fn = fn;
- conn_read(kc);
-}
-
-/*
- * Locate an existing connection to the given host, or create a new,
- * unconnected entry if none exists. The caller is expected to check
- * for the lack of a connection (kc->fd == -1) and set one up.
- */
-static struct krb5_conn *
-conn_get(
- const char * hostname)
+ void (*fn)(security_handle_t *, pkt_t *),
+ void *datap)
{
- struct krb5_conn *kc;
-
- k5printf(("krb5: conn_get: %s\n", hostname));
-
- for (kc = krb5_connq_first(); kc != NULL; kc = krb5_connq_next(kc)) {
- if (strcasecmp(hostname, kc->hostname) == 0)
- break;
- }
-
- if (kc != NULL) {
- kc->refcnt++;
- k5printf(("krb5: conn_get: exists, refcnt to %s is now %d\n",
- kc->hostname, kc->refcnt));
- return (kc);
- }
-
- k5printf(("krb5: conn_get: creating new handle\n"));
- /*
- * We can't be creating a new handle if we are the client
- */
- assert(accept_fn == NULL);
- kc = alloc(SIZEOF(*kc));
- kc->fd = -1;
- kc->readbuf.left = 0;
- kc->readbuf.size = 0;
- kc->state = unauthed;
- kc->ev_read = NULL;
- strncpy(kc->hostname, hostname, SIZEOF(kc->hostname) - 1);
- kc->hostname[SIZEOF(kc->hostname) - 1] = '\0';
- kc->errmsg = NULL;
- kc->gss_context = GSS_C_NO_CONTEXT;
- /*
- * [XXX] this is set to 2 in order to force the connection to stay
- * open and process more protocol requests. (basically consistant
- * with bsd-security.c, and theoretically krb4-security.c. This
- * needs to be addressed in a cleaner way.
- */
- kc->refcnt = 2;
- TAILQ_INIT(&kc->frameq);
- krb5_connq_append(kc);
- return (kc);
-}
-
-/*
- * Delete a reference to a connection, and close it if it is the last
- * reference.
- */
-static void
-conn_put(
- struct krb5_conn * kc)
-{
- OM_uint32 min_stat;
- struct krb5_frame *kf;
-
- assert(kc->refcnt > 0);
- if (--kc->refcnt > 0) {
- k5printf(("krb5: conn_put: decrementing refcnt for %s to %d\n",
- kc->hostname, kc->refcnt));
+ sockaddr_union sin;
+ socklen_t_equiv len;
+ struct tcp_conn *rc;
+ char hostname[NI_MAXHOST];
+ int result;
+ char *errmsg = NULL;
+
+ krb5_init();
+
+ len = sizeof(sin);
+ if (getpeername(in, (struct sockaddr *)&sin, &len) < 0) {
+ dbprintf(_("getpeername returned: %s\n"),
+ strerror(errno));
return;
- }
- k5printf(("krb5: conn_put: closing connection to %s\n", kc->hostname));
- if (kc->fd != -1)
- aclose(kc->fd);
- if (kc->ev_read != NULL)
- event_release(kc->ev_read);
- if (kc->errmsg != NULL)
- amfree(kc->errmsg);
- gss_delete_sec_context(&min_stat, &kc->gss_context, GSS_C_NO_BUFFER);
- while ((kf = TAILQ_FIRST(&kc->frameq)) != NULL) {
- TAILQ_REMOVE(&kc->frameq, kf, tq);
- if (kf->tok.value != NULL)
- amfree(kf->tok.value);
- amfree(kf);
- }
- krb5_connq_remove(kc);
- amfree(kc);
- /* signal that a connection is available */
- event_wakeup((event_id_t)open_callback);
-}
-/*
- * Turn on read events for a conn. Or, increase a refcnt if we are
- * already receiving read events.
- */
-static void
-conn_read(
- struct krb5_conn *kc)
-{
-
- if (kc->ev_read != NULL) {
- kc->ev_read_refcnt++;
- k5printf(("krb5: conn_read: incremented refcnt to %d for %s\n",
- kc->ev_read_refcnt, kc->hostname));
- return;
}
- k5printf(("krb5: conn_read registering event handler for %s\n",
- kc->hostname));
- kc->ev_read = event_register((event_id_t)kc->fd, EV_READFD, conn_read_callback, kc);
- kc->ev_read_refcnt = 1;
-}
-
-static void
-conn_read_cancel(
- struct krb5_conn * kc)
-{
-
- if (--kc->ev_read_refcnt > 0) {
- k5printf(("krb5: conn_read_cancel: decremented refcnt to %d for %s\n",
- kc->ev_read_refcnt, kc->hostname));
+ if ((result = getnameinfo((struct sockaddr *)&sin, len,
+ hostname, NI_MAXHOST, NULL, 0, 0) != 0)) {
+ dbprintf(_("getnameinfo failed: %s\n"),
+ gai_strerror(result));
return;
}
- k5printf(("krb5: conn_read_cancel: releasing event handler for %s\n",
- kc->hostname));
- event_release(kc->ev_read);
- kc->ev_read = NULL;
-}
-
-/*
- * frees a handle allocated by the above
- */
-static void
-krb5_close(
- void * inst)
-{
- struct krb5_handle *kh = inst;
-
- assert(kh != NULL);
-
- k5printf(("krb5: closing handle to %s\n", kh->hostname));
-
- if (kh->ks != NULL) {
- /* This may be null if we get here on an error */
- krb5_recvpkt_cancel(kh);
- security_stream_close(&kh->ks->secstr);
- }
- amfree(kh->hostname);
- amfree(kh);
-}
-
-/*
- * Transmit a packet. Encrypt first.
- */
-static ssize_t
-krb5_sendpkt(
- void * cookie,
- pkt_t * pkt)
-{
- struct krb5_handle *kh = cookie;
- gss_buffer_desc tok;
- int rval;
- unsigned char *buf;
-
- assert(kh != NULL);
- assert(pkt != NULL);
-
- k5printf(("krb5: sendpkt: enter\n"));
-
- if (pkt->body[0] == '\0') {
- tok.length = 1;
- tok.value = alloc(SIZEOF(pkt->type));
- memcpy(tok.value, &pkt->type, sizeof(unsigned char));
- } else {
- tok.length = strlen(pkt->body) + 2;
- tok.value = alloc(tok.length);
- buf = tok.value;
- *buf++ = (unsigned char)pkt->type;
- strncpy((char *)buf, pkt->body, tok.length - 2);
- buf[tok.length - 2] = '\0';
- }
-
- k5printf(("krb5: sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
- pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body));
-
- rval = krb5_stream_write(kh->ks, tok.value, tok.length);
- if (rval < 0)
- security_seterror(&kh->sech, security_stream_geterror(&kh->ks->secstr));
- /*@ignore@*/
- amfree(tok.value);
- /*@end@*/
- return (rval);
-}
-
-/*
- * Set up to receive a packet asyncronously, and call back when
- * it has been read.
- */
-static void
-krb5_recvpkt(
- void * cookie,
- void (*fn)(void *, pkt_t *, security_status_t),
- void * arg,
- int timeout)
-{
- struct krb5_handle *kh = cookie;
-
- assert(kh != NULL);
-
- k5printf(("krb5: recvpkt registered for %s\n", kh->hostname));
-
- /*
- * Reset any pending timeout on this handle
- */
- if (kh->ev_timeout != NULL)
- event_release(kh->ev_timeout);
-
- /*
- * Negative timeouts mean no timeout
- */
- if (timeout < 0)
- kh->ev_timeout = NULL;
- else
- kh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
- recvpkt_timeout, kh);
-
- kh->fn.recvpkt = fn;
- kh->arg = arg;
- krb5_stream_read(kh->ks, recvpkt_callback, kh);
-}
-
-/*
- * Remove a async receive request from the queue
- */
-static void
-krb5_recvpkt_cancel(
- void * cookie)
-{
- struct krb5_handle *kh = cookie;
-
- k5printf(("krb5: cancelling recvpkt for %s\n", kh->hostname));
-
- assert(kh != NULL);
-
- krb5_stream_read_cancel(kh->ks);
- if (kh->ev_timeout != NULL) {
- event_release(kh->ev_timeout);
- kh->ev_timeout = NULL;
- }
-}
-
-/*
- * This is called when a handle is woken up because data read off of the
- * net is for it.
- */
-static void
-recvpkt_callback(
- void *cookie,
- void *buf,
- ssize_t bufsize)
-{
- pkt_t pkt;
- struct krb5_handle *kh = cookie;
-
- assert(kh != NULL);
-
- /*
- * We need to cancel the recvpkt request before calling
- * the callback because the callback may reschedule us.
- */
- krb5_recvpkt_cancel(kh);
-
- switch (bufsize) {
- case 0:
- security_seterror(&kh->sech,
- "EOF on read from %s", kh->hostname);
- (*kh->fn.recvpkt)(kh->arg, NULL, S_ERROR);
- return;
- case -1:
- security_seterror(&kh->sech, security_stream_geterror(&kh->ks->secstr));
- (*kh->fn.recvpkt)(kh->arg, NULL, S_ERROR);
- return;
- default:
- parse_pkt(&pkt, buf, (size_t)bufsize);
- k5printf(("krb5: received %s pkt (%d) from %s, contains:\n\n\"%s\"\n\n",
- pkt_type2str(pkt.type), pkt.type, kh->hostname, pkt.body));
- (*kh->fn.recvpkt)(kh->arg, &pkt, S_OK);
+ if (check_name_give_sockaddr(hostname,
+ (struct sockaddr *)&sin, &errmsg) < 0) {
+ dbprintf(_("check_name_give_sockaddr(%s): %s\n"),
+ hostname, errmsg);
+ amfree(errmsg);
return;
}
-}
-
-/*
- * This is called when a handle times out before receiving a packet.
- */
-static void
-recvpkt_timeout(
- void * cookie)
-{
- struct krb5_handle *kh = cookie;
-
- assert(kh != NULL);
- k5printf(("krb5: recvpkt timeout for %s\n", kh->hostname));
- krb5_recvpkt_cancel(kh);
- (*kh->fn.recvpkt)(kh->arg, NULL, S_TIMEOUT);
+ rc = sec_tcp_conn_get(hostname, 0);
+ rc->conf_fn = conf_fn;
+ rc->datap = datap;
+ rc->recv_security_ok = NULL;
+ rc->prefix_packet = NULL;
+ copy_sockaddr(&rc->peer, &sin);
+ rc->read = in;
+ rc->write = out;
+ rc->driver = driver;
+ if (gss_server(rc) < 0)
+ error("gss_server failed: %s\n", rc->errmsg);
+ rc->accept_fn = fn;
+ sec_tcp_conn_read(rc);
}
/*
- * Create the server end of a stream. For krb5, this means setup a stream
- * object and allocate a new handle for it.
- */
-static void *
-krb5_stream_server(
- void * h)
-{
- struct krb5_handle *kh = h;
- struct krb5_stream *ks;
-
- assert(kh != NULL);
-
- ks = alloc(SIZEOF(*ks));
- security_streaminit(&ks->secstr, &krb5_security_driver);
- ks->kc = conn_get(kh->hostname);
- /*
- * Stream should already be setup!
- */
- if (ks->kc->fd < 0) {
- conn_put(ks->kc);
- amfree(ks);
- security_seterror(&kh->sech, "lost connection");
- return (NULL);
- }
- /*
- * so as not to conflict with the amanda server's handle numbers,
- * we start at 5000 and work down
- */
- ks->handle = (int)(5000 - newhandle++);
- ks->ev_read = NULL;
- k5printf(("krb5: stream_server: created stream %d\n", ks->handle));
- return (ks);
-}
-
-/*
- * Accept an incoming connection on a stream_server socket
- * Nothing needed for krb5.
+ * Forks a krb5 to the host listed in rc->hostname
+ * Returns negative on error, with an errmsg in rc->errmsg.
*/
static int
-krb5_stream_accept(
- void * s)
+runkrb5(
+ struct sec_handle * rh)
{
+ struct servent * sp;
+ int server_socket;
+ in_port_t my_port, port;
+ struct tcp_conn * rc = rh->rc;
+ const char *err;
- /* shut up compiler */
- s = s;
-
- return (0);
-}
-
-/*
- * Return a connected stream. For krb5, this means setup a stream
- * with the supplied handle.
- */
-static void *
-krb5_stream_client(
- void * h,
- int id)
-{
- struct krb5_handle *kh = h;
- struct krb5_stream *ks;
-
- assert(kh != NULL);
+ if ((sp = getservbyname(AMANDA_KRB5_SERVICE_NAME, "tcp")) == NULL)
+ port = htons(AMANDA_KRB5_DEFAULT_PORT);
+ else
+ port = sp->s_port;
- if (id <= 0) {
- security_seterror(&kh->sech,
- "%d: invalid security stream id", id);
- return (NULL);
+ if ((err = get_tgt(keytab_name, principal_name)) != NULL) {
+ security_seterror(&rh->sech, "%s: could not get TGT: %s",
+ rc->hostname, err);
+ return -1;
}
- ks = alloc(SIZEOF(*ks));
- security_streaminit(&ks->secstr, &krb5_security_driver);
- ks->handle = (int)id;
- ks->ev_read = NULL;
- ks->kc = conn_get(kh->hostname);
-
- k5printf(("krb5: stream_client: connected to stream %d\n", id));
-
- return (ks);
-}
+ set_root_privs(1);
+ server_socket = stream_client(rc->hostname,
+ (in_port_t)(ntohs(port)),
+ STREAM_BUFSIZE,
+ STREAM_BUFSIZE,
+ &my_port,
+ 0);
+ set_root_privs(0);
-/*
- * Close and unallocate resources for a stream.
- */
-static void
-krb5_stream_close(
- void * s)
-{
- struct krb5_stream *ks = s;
-
- assert(ks != NULL);
-
- k5printf(("krb5: stream_close: closing stream %d\n", ks->handle));
-
- krb5_stream_read_cancel(ks);
- conn_put(ks->kc);
- amfree(ks);
-}
-
-/*
- * Authenticate a stream
- * Nothing needed for krb5. The tcp connection is authenticated
- * on startup.
- */
-static int
-krb5_stream_auth(
- void * s)
-{
- /* shut up compiler */
- s = s;
-
- return (0);
-}
-
-/*
- * Returns the stream id for this stream. This is just the local
- * port.
- */
-static int
-krb5_stream_id(
- void * s)
-{
- struct krb5_stream *ks = s;
-
- assert(ks != NULL);
-
- return (ks->handle);
-}
-
-/*
- * Write a chunk of data to a stream. Blocks until completion.
- */
-static int
-krb5_stream_write(
- void * s,
- const void *buf,
- size_t size)
-{
- struct krb5_stream *ks = s;
- gss_buffer_desc tok;
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_buffer_desc enctok;
- OM_uint32 min_stat;
-#endif
- int rc;
-
- assert(ks != NULL);
-
- k5printf(("krb5: stream_write: writing %d bytes to %s:%d\n", size,
- ks->kc->hostname, ks->handle));
-
- tok.length = size;
- tok.value = (void *)buf; /* safe to discard const */
-#ifdef AMANDA_KRB5_ENCRYPT
- if (kencrypt(ks, &tok, &enctok) < 0)
- return (-1);
- rc = send_token(ks->kc, ks->handle, &enctok);
-#else
- rc = send_token(ks->kc, ks->handle, &tok);
-#endif
- if (rc < 0)
- security_stream_seterror(&ks->secstr, ks->kc->errmsg);
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_release_buffer(&min_stat, &enctok);
-#endif
- return (rc);
-}
-
-/*
- * Submit a request to read some data. Calls back with the given
- * function and arg when completed.
- */
-static void
-krb5_stream_read(
- void * s,
- void (*fn)(void *, void *, ssize_t),
- void * arg)
-{
- struct krb5_stream *ks = s;
-
- assert(ks != NULL);
-
- /*
- * Only one read request can be active per stream.
- */
- ks->fn = fn;
- ks->arg = arg;
-
- /*
- * First see if there's any queued frames for this stream.
- * If so, we're done.
- */
- if (conn_run_frameq(ks->kc, ks) > 0)
- return;
-
- if (ks->ev_read == NULL) {
- ks->ev_read = event_register((event_id_t)ks->kc, EV_WAIT,
- stream_read_callback, ks);
- conn_read(ks->kc);
+ if(server_socket < 0) {
+ security_seterror(&rh->sech,
+ "%s", strerror(errno));
+
+ return -1;
}
-}
-
-/*
- * Submit a request to read some data. Calls back with the given
- * function and arg when completed.
- */
-static ssize_t
-krb5_stream_read_sync(
- void * s,
- void **buf)
-{
- struct krb5_stream *ks = s;
-
- assert(ks != NULL);
-
- /*
- * Only one read request can be active per stream.
- */
- ks->fn = stream_read_sync_callback2;
- ks->arg = ks;
-
- /*
- * First see if there's any queued frames for this stream.
- * If so, we're done.
- */
- if (conn_run_frameq(ks->kc, ks) > 0)
- return ks->len;
-
- if (ks->ev_read != NULL)
- event_release(ks->ev_read);
-
- ks->ev_read = event_register((event_id_t)ks->kc, EV_WAIT,
- stream_read_callback, ks);
- conn_read(ks->kc);
- event_wait(ks->ev_read);
- buf = (void **)&ks->buf;
- return ks->len;
-}
-
-
-/*
- * Callback for krb5_stream_read_sync
- */
-static void
-stream_read_sync_callback2(
- void * arg,
- void * buf,
- ssize_t size)
-{
- struct krb5_stream *ks = arg;
-
- assert(ks != NULL);
-
- k5printf(("krb5: stream_read_sync_callback2: handle %d\n", ks->handle));
-
- memcpy(ks->buf, buf, (size_t)size);
- ks->len = size;
-}
-
-/*
- * Cancel a previous stream read request. It's ok if we didn't have a read
- * scheduled.
- */
-static void
-krb5_stream_read_cancel(
- void * s)
-{
- struct krb5_stream *ks = s;
- assert(ks != NULL);
+ rc->read = rc->write = server_socket;
- if (ks->ev_read != NULL) {
- event_release(ks->ev_read);
- ks->ev_read = NULL;
- conn_read_cancel(ks->kc);
+ if (gss_client(rh) < 0) {
+ return -1;
}
-}
-/*
- * Callback for krb5_stream_read
- */
-static void
-stream_read_callback(
- void * arg)
-{
- struct krb5_stream *ks = arg;
-
- assert(ks != NULL);
- k5printf(("krb5: stream_read_callback: handle %d\n", ks->handle));
-
- conn_run_frameq(ks->kc, ks);
+ return 0;
}
-/*
- * Run down a list of queued frames for a krb5_conn, and if we find one
- * that matches the passed handle, fire the read event. Only
- * process one frame.
- *
- * Returns 1 if a frame was found and processed.
- */
-static int
-conn_run_frameq(
- /*@keep@*/ struct krb5_conn * kc,
- /*@keep@*/ struct krb5_stream * ks)
-{
- struct krb5_frame *kf, *nextkf;
- gss_buffer_desc *enctok, *dectok;
-#ifdef AMANDA_KRB5_ENCRYPT
- OM_uint32 min_stat;
- gss_buffer_desc tok;
-#endif
-
- /*
- * Iterate through all of the frames in the queue. If one
- * is for us, process it. If we hit an EOF frame, shut down.
- * Stop after processing one frame, because we are only supposed
- * to return one read request.
- */
- for (kf = TAILQ_FIRST(&kc->frameq); kf != NULL; kf = nextkf) {
- nextkf = TAILQ_NEXT(kf, tq);
- if (kf->handle != ks->handle && kf->handle != H_EOF) {
- k5printf(("krb5: conn_frameq_run: not for us (handle %d)\n",
- kf->handle));
- continue;
- }
- /*
- * We want all listeners to see the EOF, so never remove it.
- * It will get cleaned up when the connection is closed
- * in conn_put().
- */
- if (kf->handle != H_EOF)
- TAILQ_REMOVE(&kc->frameq, kf, tq);
-
- /*
- * Remove the event first, and then call the callback.
- * We remove it first because we don't want to get in their
- * way if they reschedule it.
- */
- krb5_stream_read_cancel(ks);
-
- enctok = &kf->tok;
-
- if (enctok->length == 0) {
- assert(kf->handle == H_EOF);
- k5printf(("krb5: stream_read_callback: EOF\n"));
- (*ks->fn)(ks->arg, NULL, 0);
- return (1); /* stop after EOF */
- }
-
-#ifdef AMANDA_KRB5_ENCRYPT
- dectok = &tok;
- if (kdecrypt(ks, enctok, &tok) < 0) {
- k5printf(("krb5: stream_read_callback: kdecrypt error\n"));
- (*ks->fn)(ks->arg, NULL, -1);
- } else
-#else
- dectok = enctok;
-#endif
- {
- k5printf(("krb5: stream_read_callback: read %d bytes from %s:%d\n",
- dectok->length, ks->kc->hostname, ks->handle));
- (*ks->fn)(ks->arg, dectok->value, (ssize_t)dectok->length);
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_release_buffer(&min_stat, dectok);
-#endif
- }
- amfree(enctok->value);
- amfree(kf);
- return (1); /* stop after one frame */
- }
- return (0);
-}
/*
- * The callback for the netfd for the event handler
- * Determines if this packet is for this security handle,
- * and does the real callback if so.
- */
-static void
-conn_read_callback(
- void * cookie)
-{
- struct krb5_conn *kc = cookie;
- struct krb5_handle *kh;
- struct krb5_frame *kf;
- pkt_t pkt;
- gss_buffer_desc *dectok;
- int rc;
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_buffer_desc tok;
- OM_uint32 min_stat;
-#endif
-
- assert(cookie != NULL);
-
- k5printf(("krb5: conn_read_callback\n"));
-
- kf = alloc(SIZEOF(*kf));
- TAILQ_INSERT_TAIL(&kc->frameq, kf, tq);
-
- /* Read the data off the wire. If we get errors, shut down. */
- rc = recv_token(kc, &kf->handle, &kf->tok, 5);
- k5printf(("krb5: conn_read_callback: recv_token returned %d handle = %d\n",
- rc, kf->handle));
- if (rc <= 0) {
- kf->tok.value = NULL;
- kf->tok.length = 0;
- kf->handle = H_EOF;
- rc = event_wakeup((event_id_t)kc);
- k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
- return;
- }
-
- /* If there are events waiting on this handle, we're done */
- rc = event_wakeup((event_id_t)kc);
- k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
- if (rc > 0)
- return;
-
- /*
- * If there is no accept fn registered, then just leave the
- * packet queued. The caller may register a function later.
- */
- if (accept_fn == NULL) {
- k5printf(("krb5: no accept_fn so leaving packet queued.\n"));
- return;
- }
-
- kh = alloc(SIZEOF(*kh));
- security_handleinit(&kh->sech, &krb5_security_driver);
- kh->hostname = stralloc(kc->hostname);
- kh->ks = krb5_stream_client(kh, kf->handle);
- kh->ev_wait = NULL;
- kh->ev_timeout = NULL;
-
- TAILQ_REMOVE(&kc->frameq, kf, tq);
- k5printf(("krb5: new connection\n"));
-#ifdef AMANDA_KRB5_ENCRYPT
- dectok = &tok;
- rc = kdecrypt(kh->ks, &kf->tok, dectok);
-#else
- dectok = &kf->tok;
-#endif
-
-#ifdef AMANDA_KRB5_ENCRYPT
- if (rc < 0) {
- security_seterror(&kh->sech, security_geterror(&kh->ks->secstr));
- (*accept_fn)(&kh->sech, NULL);
- } else
-#endif
- {
- parse_pkt(&pkt, dectok->value, dectok->length);
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_release_buffer(&min_stat, dectok);
-#endif
- (*accept_fn)(&kh->sech, &pkt);
- }
- amfree(kf->tok.value);
- amfree(kf);
-
- /*
- * We can only accept one connection per process, since we're tcp
- * based and run out of inetd. So, delete our accept reference once
- * we've gotten the first connection.
- */
- /*
- * [XXX] actually, the protocol has been changed to have multiple
- * requests in one session be possible. By not resetting accept_fn,
- * this will caused them to be properly processed. this needs to be
- * addressed in a much cleaner way.
- */
- if (accept_fn != NULL)
- conn_put(kc);
- /* accept_fn = NULL; */
-}
-
-/*
* Negotiate a krb5 gss context from the client end.
*/
static int
gss_client(
- struct krb5_handle *kh)
+ struct sec_handle *rh)
{
- struct krb5_stream *ks = kh->ks;
- struct krb5_conn *kc = ks->kc;
- gss_buffer_desc send_tok, recv_tok;
+ struct sec_stream *rs = rh->rs;
+ struct tcp_conn *rc = rs->rc;
+ gss_buffer_desc send_tok, recv_tok, AA;
+ gss_OID doid;
OM_uint32 maj_stat, min_stat;
unsigned int ret_flags;
- int rc, rval = -1;
+ int rval = -1;
+ int rvalue;
gss_name_t gss_name;
+ char *errmsg = NULL;
- k5printf(("gss_client\n"));
+ auth_debug(1, "gss_client\n");
- send_tok.value = vstralloc("host/", ks->kc->hostname, NULL);
+ send_tok.value = vstralloc("host/", rs->rc->hostname, NULL);
send_tok.length = strlen(send_tok.value) + 1;
maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
&gss_name);
if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
- security_seterror(&kh->sech, "can't import name %s: %s",
+ security_seterror(&rh->sech, _("can't import name %s: %s"),
(char *)send_tok.value, gss_error(maj_stat, min_stat));
amfree(send_tok.value);
return (-1);
}
amfree(send_tok.value);
- kc->gss_context = GSS_C_NO_CONTEXT;
+ rc->gss_context = GSS_C_NO_CONTEXT;
+ maj_stat = gss_display_name(&min_stat, gss_name, &AA, &doid);
+ dbprintf(_("gss_name %s\n"), (char *)AA.value);
/*
* Perform the context-establishement loop.
min_stat = 0;
maj_stat = gss_init_sec_context(&min_stat,
GSS_C_NO_CREDENTIAL,
- &kc->gss_context,
+ &rc->gss_context,
gss_name,
GSS_C_NULL_OID,
(OM_uint32)GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,
amfree(recv_tok.value);
recv_tok.length = 0;
}
-
if (maj_stat != (OM_uint32)GSS_S_COMPLETE && maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
- security_seterror(&kh->sech,
- "error getting gss context: %s",
- gss_error(maj_stat, min_stat));
+ security_seterror(&rh->sech,
+ _("error getting gss context: %s %s"),
+ gss_error(maj_stat, min_stat), (char *)send_tok.value);
goto done;
}
/*
* Send back the response
*/
- if (send_tok.length != 0 && send_token(kc, ks->handle, &send_tok) < 0) {
- security_seterror(&kh->sech, kc->errmsg);
+ if (send_tok.length != 0 && tcpm_send_token(rc, rc->write, rs->handle, &errmsg, send_tok.value, send_tok.length) < 0) {
+ security_seterror(&rh->sech, "%s", rc->errmsg);
gss_release_buffer(&min_stat, &send_tok);
goto done;
}
if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
break;
- if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
- if (rc < 0)
- security_seterror(&kh->sech,
- "recv error in gss loop: %s", kc->errmsg);
+ rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg,
+ (void *)&recv_tok.value,
+ (ssize_t *)&recv_tok.length, 60);
+ if (rvalue <= 0) {
+ if (rvalue < 0)
+ security_seterror(&rh->sech,
+ _("recv error in gss loop: %s"), rc->errmsg);
else
- security_seterror(&kh->sech, "EOF in gss loop");
+ security_seterror(&rh->sech, _("EOF in gss loop"));
goto done;
}
}
rval = 0;
+ rc->auth = 1;
done:
gss_release_name(&min_stat, &gss_name);
return (rval);
*/
static int
gss_server(
- struct krb5_conn * kc)
+ struct tcp_conn *rc)
{
OM_uint32 maj_stat, min_stat, ret_flags;
- gss_buffer_desc send_tok, recv_tok;
+ gss_buffer_desc send_tok, recv_tok, AA;
gss_OID doid;
gss_name_t gss_name;
gss_cred_id_t gss_creds;
char *p, *realm, *msg;
uid_t euid;
- int rc, rval = -1;
+ int rval = -1;
+ int rvalue;
char errbuf[256];
+ char *errmsg = NULL;
- k5printf(("gss_server\n"));
+ auth_debug(1, "gss_server\n");
- assert(kc != NULL);
+ assert(rc != NULL);
/*
* We need to be root while in gss_acquire_cred() to read the host key
*/
euid = geteuid();
if (getuid() != 0) {
- snprintf(errbuf, SIZEOF(errbuf),
- "real uid is %ld, needs to be 0 to read krb5 host key",
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("real uid is %ld, needs to be 0 to read krb5 host key"),
(long)getuid());
goto out;
}
- if (seteuid(0) < 0) {
- snprintf(errbuf, SIZEOF(errbuf),
- "can't seteuid to uid 0: %s", strerror(errno));
+ if (!set_root_privs(0)) {
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("can't seteuid to uid 0: %s"), strerror(errno));
goto out;
}
- send_tok.value = vstralloc("host/", hostname, NULL);
+ rc->gss_context = GSS_C_NO_CONTEXT;
+ send_tok.value = vstralloc("host/", myhostname, NULL);
send_tok.length = strlen(send_tok.value) + 1;
for (p = send_tok.value; *p != '\0'; p++) {
if (isupper((int)*p))
maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
&gss_name);
if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
- seteuid(euid);
- snprintf(errbuf, SIZEOF(errbuf),
- "can't import name %s: %s", (char *)send_tok.value,
+ set_root_privs(0);
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("can't import name %s: %s"), (char *)send_tok.value,
gss_error(maj_stat, min_stat));
amfree(send_tok.value);
goto out;
}
amfree(send_tok.value);
+ maj_stat = gss_display_name(&min_stat, gss_name, &AA, &doid);
+ dbprintf(_("gss_name %s\n"), (char *)AA.value);
maj_stat = gss_acquire_cred(&min_stat, gss_name, 0,
GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_creds, NULL, NULL);
if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
- snprintf(errbuf, SIZEOF(errbuf),
- "can't acquire creds for host key host/%s: %s", hostname,
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("can't acquire creds for host key host/%s: %s"), myhostname,
gss_error(maj_stat, min_stat));
gss_release_name(&min_stat, &gss_name);
- seteuid(euid);
+ set_root_privs(0);
goto out;
}
gss_release_name(&min_stat, &gss_name);
for (recv_tok.length = 0;;) {
- if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
- if (rc < 0) {
- snprintf(errbuf, SIZEOF(errbuf),
- "recv error in gss loop: %s", kc->errmsg);
- amfree(kc->errmsg);
+ recv_tok.value = NULL;
+ rvalue = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg,
+ /* (void *) is to avoid type-punning warning */
+ (char **)(void *)&recv_tok.value,
+ (ssize_t *)&recv_tok.length, 60);
+ if (rvalue <= 0) {
+ if (rvalue < 0) {
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("recv error in gss loop: %s"), rc->errmsg);
+ amfree(rc->errmsg);
} else
- snprintf(errbuf, SIZEOF(errbuf), "EOF in gss loop");
+ g_snprintf(errbuf, SIZEOF(errbuf), _("EOF in gss loop"));
goto out;
}
- maj_stat = gss_accept_sec_context(&min_stat, &kc->gss_context,
+ maj_stat = gss_accept_sec_context(&min_stat, &rc->gss_context,
gss_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
&gss_name, &doid, &send_tok, &ret_flags, NULL, NULL);
if (maj_stat != (OM_uint32)GSS_S_COMPLETE &&
maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
- snprintf(errbuf, SIZEOF(errbuf),
- "error accepting context: %s", gss_error(maj_stat, min_stat));
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("error accepting context: %s"), gss_error(maj_stat, min_stat));
amfree(recv_tok.value);
goto out;
}
amfree(recv_tok.value);
- if (send_tok.length > 0 && send_token(kc, 0, &send_tok) < 0) {
- strncpy(errbuf, kc->errmsg, SIZEOF(errbuf) - 1);
+ if (send_tok.length != 0 && tcpm_send_token(rc, rc->write, 0, &errmsg, send_tok.value, send_tok.length) < 0) {
+ strncpy(errbuf, rc->errmsg, SIZEOF(errbuf) - 1);
errbuf[SIZEOF(errbuf) - 1] = '\0';
- amfree(kc->errmsg);
+ amfree(rc->errmsg);
gss_release_buffer(&min_stat, &send_tok);
goto out;
}
maj_stat = gss_display_name(&min_stat, gss_name, &send_tok, &doid);
if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
- snprintf(errbuf, SIZEOF(errbuf),
- "can't display gss name: %s", gss_error(maj_stat, min_stat));
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("can't display gss name: %s"), gss_error(maj_stat, min_stat));
gss_release_name(&min_stat, &gss_name);
goto out;
}
/* get rid of the realm */
if ((p = strchr(send_tok.value, '@')) == NULL) {
- snprintf(errbuf, SIZEOF(errbuf),
- "malformed gss name: %s", (char *)send_tok.value);
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("malformed gss name: %s"), (char *)send_tok.value);
amfree(send_tok.value);
goto out;
}
/*
* If the principal doesn't match, complain
*/
- if ((msg = krb5_checkuser(kc->hostname, send_tok.value, realm)) != NULL) {
- snprintf(errbuf, SIZEOF(errbuf),
- "access not allowed from %s: %s", (char *)send_tok.value, msg);
+ if ((msg = krb5_checkuser(rc->hostname, send_tok.value, realm)) != NULL) {
+ g_snprintf(errbuf, SIZEOF(errbuf),
+ _("access not allowed from %s: %s"), (char *)send_tok.value, msg);
amfree(send_tok.value);
goto out;
}
rval = 0;
out:
- seteuid(euid);
- if (rval != 0)
- kc->errmsg = stralloc(errbuf);
- k5printf(("gss_server returning %d\n", rval));
+ set_root_privs(0);
+ if (rval != 0) {
+ rc->errmsg = stralloc(errbuf);
+ } else {
+ rc->auth = 1;
+ }
+ auth_debug(1, _("gss_server returning %d\n"), rval);
return (rval);
}
* Setup some things about krb5. This should only be called once.
*/
static void
-init(void)
+krb5_init(void)
{
static int beenhere = 0;
- struct hostent *he;
char *p;
+ char *myfqhostname=NULL;
if (beenhere)
return;
beenhere = 1;
#ifndef BROKEN_MEMORY_CCACHE
- setenv(KRB5_ENV_CCNAME, "MEMORY:amanda_ccache", 1);
+ putenv(stralloc("KRB5_ENV_CCNAME=MEMORY:amanda_ccache"));
#else
/*
* MEMORY ccaches seem buggy and cause a lot of internal heap
*/
atexit(cleanup);
{
- char ccache[64];
- snprintf(ccache, SIZEOF(ccache), "FILE:/tmp/amanda_ccache.%ld.%ld",
- (long)geteuid(), (long)getpid());
- setenv(KRB5_ENV_CCNAME, ccache, 1);
+ char *ccache;
+ ccache = malloc(128);
+ g_snprintf(ccache, SIZEOF(ccache),
+ "KRB5_ENV_CCNAME=FILE:/tmp/amanda_ccache.%ld.%ld",
+ (long)geteuid(), (long)getpid());
+ putenv(ccache);
}
#endif
- gethostname(hostname, SIZEOF(hostname) - 1);
- hostname[SIZEOF(hostname) - 1] = '\0';
+ gethostname(myhostname, SIZEOF(myhostname) - 1);
+ myhostname[SIZEOF(myhostname) - 1] = '\0';
+
/*
- * In case it isn't fully qualified, do a DNS lookup.
+ * In case it isn't fully qualified, do a DNS lookup. Ignore
+ * any errors (this is best-effort).
*/
- if ((he = gethostbyname(hostname)) != NULL)
- strncpy(hostname, he->h_name, SIZEOF(hostname) - 1);
+ if (resolve_hostname(myhostname, SOCK_STREAM, NULL, &myfqhostname) == 0
+ && myfqhostname != NULL) {
+ strncpy(myhostname, myfqhostname, SIZEOF(myhostname)-1);
+ myhostname[SIZEOF(myhostname)-1] = '\0';
+ amfree(myfqhostname);
+ }
/*
* Lowercase the results. We assume all host/ principals will be
* lowercased.
*/
- for (p = hostname; *p != '\0'; p++) {
+ for (p = myhostname; *p != '\0'; p++) {
if (isupper((int)*p))
*p = tolower(*p);
}
{
#ifdef KDESTROY_VIA_UNLINK
char ccache[64];
- snprintf(ccache, SIZEOF(ccache), "/tmp/amanda_ccache.%ld.%ld",
+ g_snprintf(ccache, SIZEOF(ccache), "/tmp/amanda_ccache.%ld.%ld",
(long)geteuid(), (long)getpid());
unlink(ccache);
#else
krb5_error_code ret;
krb5_principal client = NULL, server = NULL;
krb5_creds creds;
- krb5_keytab keytab = NULL;
+ krb5_keytab keytab;
krb5_ccache ccache;
krb5_timestamp now;
+#ifdef KRB5_HEIMDAL_INCLUDES
+ krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
+#else
krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
+#endif
static char *error = NULL;
if (error != NULL) {
amfree(error);
error = NULL;
}
-
if ((ret = krb5_init_context(&context)) != 0) {
- error = vstralloc("error initializing krb5 context: ",
- error_message(ret), NULL);
+ error = vstrallocf(_("error initializing krb5 context: %s"),
+ error_message(ret));
return (error);
}
/*krb5_init_ets(context);*/
if(!keytab_name) {
- error = vstralloc("error -- no krb5 keytab defined", NULL);
+ error = vstrallocf(_("error -- no krb5 keytab defined"));
return(error);
}
if(!principal_name) {
- error = vstralloc("error -- no krb5 principal defined", NULL);
+ error = vstrallocf(_("error -- no krb5 principal defined"));
return(error);
}
* Resolve keytab file into a keytab object
*/
if ((ret = krb5_kt_resolve(context, keytab_name, &keytab)) != 0) {
- error = vstralloc("error resolving keytab ", keytab, ": ",
- error_message(ret), NULL);
+ error = vstrallocf(_("error resolving keytab %s: %s"), keytab_name,
+ error_message(ret));
return (error);
}
*/
ret = krb5_parse_name(context, principal_name, &client);
if (ret != 0) {
- error = vstralloc("error parsing ", principal_name, ": ",
- error_message(ret), NULL);
+ error = vstrallocf(_("error parsing %s: %s"), principal_name,
+ error_message(ret));
return (error);
}
+#ifdef KRB5_HEIMDAL_INCLUDES
+ ret = krb5_build_principal_ext(context, &server,
+ krb5_realm_length(*krb5_princ_realm(context, client)),
+ krb5_realm_data(*krb5_princ_realm(context, client)),
+ tgtname.length, tgtname.data,
+ krb5_realm_length(*krb5_princ_realm(context, client)),
+ krb5_realm_data(*krb5_princ_realm(context, client)),
+ 0);
+#else
ret = krb5_build_principal_ext(context, &server,
krb5_princ_realm(context, client)->length,
krb5_princ_realm(context, client)->data,
krb5_princ_realm(context, client)->length,
krb5_princ_realm(context, client)->data,
0);
+#endif
if (ret != 0) {
- error = vstralloc("error while building server name: ",
- error_message(ret), NULL);
+ error = vstrallocf(_("error while building server name: %s"),
+ error_message(ret));
return (error);
}
ret = krb5_timeofday(context, &now);
if (ret != 0) {
- error = vstralloc("error getting time of day: ", error_message(ret),
- NULL);
+ error = vstrallocf(_("error getting time of day: %s"), error_message(ret));
return (error);
}
keytab, 0, &creds, 0);
if (ret != 0) {
- error = vstralloc("error getting ticket for ", principal_name,
- ": ", error_message(ret), NULL);
+ error = vstrallocf(_("error getting ticket for %s: %s"),
+ principal_name, error_message(ret));
goto cleanup2;
}
if ((ret = krb5_cc_default(context, &ccache)) != 0) {
- error = vstralloc("error initializing ccache: ", error_message(ret),
- NULL);
+ error = vstrallocf(_("error initializing ccache: %s"), error_message(ret));
goto cleanup;
}
if ((ret = krb5_cc_initialize(context, ccache, client)) != 0) {
- error = vstralloc("error initializing ccache: ", error_message(ret),
- NULL);
+ error = vstrallocf(_("error initializing ccache: %s"), error_message(ret));
goto cleanup;
}
if ((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) {
- error = vstralloc("error storing creds in ccache: ",
- error_message(ret), NULL);
+ error = vstrallocf(_("error storing creds in ccache: %s"),
+ error_message(ret));
/* FALLTHROUGH */
}
krb5_cc_close(context, ccache);
return (error);
}
+#ifndef KDESTROY_VIA_UNLINK
/*
* get rid of tickets
*/
krb5_free_context(context);
return;
}
+#endif
/*
* Formats an error from the gss api
return ((const char *)msg.value);
}
-/*
- * Transmits a gss_buffer_desc over a krb5_handle, adding
- * the necessary headers to allow the remote end to decode it.
- * Encryption must be done by the caller.
- */
-static int
-send_token(
- struct krb5_conn * kc,
- int handle,
- const gss_buffer_desc * tok)
-{
- OM_uint32 netlength, nethandle;
- struct iovec iov[3];
-
- k5printf(("krb5: send_token: writing %d bytes to %s\n", tok->length,
- kc->hostname));
-
- if (tok->length > AMANDA_MAX_TOK_SIZE) {
- kc->errmsg = newvstralloc(kc->errmsg, "krb5 write error to ",
- kc->hostname, ": token too large", NULL);
- return (-1);
- }
-
- /*
- * Format is:
- * 32 bit length (network byte order)
- * 32 bit handle (network byte order)
- * data
- */
- netlength = (OM_uint32)htonl(tok->length);
- iov[0].iov_base = (void *)&netlength;
- iov[0].iov_len = SIZEOF(netlength);
-
- nethandle = (OM_uint32)htonl((uint32_t)handle);
- iov[1].iov_base = (void *)&nethandle;
- iov[1].iov_len = SIZEOF(nethandle);
-
- iov[2].iov_base = (void *)tok->value;
- iov[2].iov_len = tok->length;
-
- if (net_writev(kc->fd, iov, 3) < 0) {
- kc->errmsg = newvstralloc(kc->errmsg, "krb5 write error to ",
- kc->hostname, ": ", strerror(errno), NULL);
- return (-1);
- }
- return (0);
-}
-
-static ssize_t
-recv_token(
- struct krb5_conn * kc,
- int * handle,
- gss_buffer_desc * gtok,
- int timeout)
-{
- OM_uint32 netint[2];
-
- assert(kc->fd >= 0);
- assert(gtok != NULL);
-
- k5printf(("krb5: recv_token: reading from %s\n", kc->hostname));
-
- switch (net_read(kc->fd, &netint, SIZEOF(netint), timeout)) {
- case -1:
- kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
- NULL);
- k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
- return (-1);
- case 0:
- gtok->length = 0;
- return (0);
- default:
- break;
- }
- gtok->length = ntohl(netint[0]);
-
- if (gtok->length > AMANDA_MAX_TOK_SIZE) {
- kc->errmsg = newstralloc(kc->errmsg, "recv error: buffer too large");
- k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
- return (-1);
- }
-
- if (handle != NULL)
- *handle = ntohl(netint[1]);
-
- gtok->value = alloc(gtok->length);
- switch (net_read(kc->fd, gtok->value, gtok->length, timeout)) {
- case -1:
- kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
- NULL);
- k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
- amfree(gtok->value);
- return (-1);
- case 0:
- amfree(gtok->value);
- gtok->length = 0;
- break;
- default:
- break;
- }
-
- k5printf(("krb5: recv_token: read %d bytes from %s\n", gtok->length,
- kc->hostname));
- return ((ssize_t)gtok->length);
-}
-
-#ifdef AMANDA_KRB5_ENCRYPT
static int
-kencrypt(
- struct krb5_stream *ks,
- gss_buffer_desc * tok,
- gss_buffer_desc * enctok)
+k5_encrypt(
+ void *cookie,
+ void *buf,
+ ssize_t buflen,
+ void **encbuf,
+ ssize_t *encbuflen)
{
- int conf_state;
+ struct tcp_conn *rc = cookie;
+ gss_buffer_desc dectok;
+ gss_buffer_desc enctok;
OM_uint32 maj_stat, min_stat;
+ int conf_state;
- assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
- maj_stat = gss_seal(&min_stat, ks->kc->gss_context, 1,
- GSS_C_QOP_DEFAULT, tok, &conf_state, enctok);
- if (maj_stat != (OM_uint32)GSS_S_COMPLETE || conf_state == 0) {
- security_stream_seterror(&ks->secstr,
- "krb5 encryption failed to %s: %s",
- ks->kc->hostname, gss_error(maj_stat, min_stat));
- return (-1);
+ if (rc->conf_fn && rc->conf_fn("kencrypt", rc->datap)) {
+ auth_debug(1, _("krb5: k5_encrypt: enter %p\n"), rc);
+
+ dectok.length = buflen;
+ dectok.value = buf;
+
+ if (rc->auth == 1) {
+ assert(rc->gss_context != GSS_C_NO_CONTEXT);
+ maj_stat = gss_seal(&min_stat, rc->gss_context, 1,
+ GSS_C_QOP_DEFAULT, &dectok, &conf_state,
+ &enctok);
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE || conf_state == 0) {
+ auth_debug(1, _("krb5 encrypt error to %s: %s\n"),
+ rc->hostname, gss_error(maj_stat, min_stat));
+ return (-1);
+ }
+ auth_debug(1, _("krb5: k5_encrypt: give %zu bytes\n"),
+ enctok.length);
+ *encbuf = enctok.value;
+ *encbuflen = enctok.length;
+ } else {
+ *encbuf = buf;
+ *encbuflen = buflen;
+ }
+ auth_debug(1, _("krb5: k5_encrypt: exit\n"));
}
return (0);
}
+
static int
-kdecrypt(
- struct krb5_stream *ks,
- gss_buffer_desc * enctok,
- gss_buffer_desc * tok)
+k5_decrypt(
+ void *cookie,
+ void *buf,
+ ssize_t buflen,
+ void **decbuf,
+ ssize_t *decbuflen)
{
+ struct tcp_conn *rc = cookie;
+ gss_buffer_desc enctok;
+ gss_buffer_desc dectok;
OM_uint32 maj_stat, min_stat;
int conf_state, qop_state;
- k5printf(("krb5: kdecrypt: decrypting %d bytes\n", enctok->length));
-
- assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
- maj_stat = gss_unseal(&min_stat, ks->kc->gss_context, enctok, tok,
- &conf_state, &qop_state);
- if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
- security_stream_seterror(&ks->secstr, "krb5 decrypt error from %s: %s",
- ks->kc->hostname, gss_error(maj_stat, min_stat));
- return (-1);
+ if (rc->conf_fn && rc->conf_fn("kencrypt", rc->datap)) {
+ auth_debug(1, _("krb5: k5_decrypt: enter\n"));
+ if (rc->auth == 1) {
+ enctok.length = buflen;
+ enctok.value = buf;
+
+ auth_debug(1, _("krb5: k5_decrypt: decrypting %zu bytes\n"), enctok.length);
+
+ assert(rc->gss_context != GSS_C_NO_CONTEXT);
+ maj_stat = gss_unseal(&min_stat, rc->gss_context, &enctok, &dectok,
+ &conf_state, &qop_state);
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
+ auth_debug(1, _("krb5 decrypt error from %s: %s\n"),
+ rc->hostname, gss_error(maj_stat, min_stat));
+ return (-1);
+ }
+ auth_debug(1, _("krb5: k5_decrypt: give %zu bytes\n"),
+ dectok.length);
+ *decbuf = dectok.value;
+ *decbuflen = dectok.length;
+ } else {
+ *decbuf = buf;
+ *decbuflen = buflen;
+ }
+ auth_debug(1, _("krb5: k5_decrypt: exit\n"));
+ } else {
+ *decbuf = buf;
+ *decbuflen = buflen;
}
return (0);
}
-#endif
-
-/*
- * hackish, but you can #undef AMANDA_PRINCIPAL here, and you can both
- * hardcode a principal in your build and use the .k5amandahosts. This is
- * available because sites that run pre-releases of amanda 2.5.0 before
- * this feature was there do not behave this way...
- */
-
-/*#undef AMANDA_PRINCIPAL*/
/*
* check ~/.k5amandahosts to see if this principal is allowed in. If it's
if(strcmp(name, AMANDA_PRINCIPAL) == 0) {
return(NULL);
} else {
- return(vstralloc("does not match compiled in default"));
+ return(vstrallocf(_("does not match compiled in default")));
}
#else
struct passwd *pwd;
char *ptmp;
- char *result = "generic error"; /* default is to not permit */
+ char *result = _("generic error"); /* default is to not permit */
FILE *fp = NULL;
struct stat sbuf;
uid_t localuid;
char *line = NULL;
char *filehost = NULL, *fileuser = NULL, *filerealm = NULL;
- char n1[NUM_STR_SIZE];
- char n2[NUM_STR_SIZE];
assert( host != NULL);
assert( name != NULL);
if((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
- result = vstralloc("can not find user ", CLIENT_LOGIN, NULL);
+ result = vstrallocf(_("can not find user %s"), CLIENT_LOGIN);
}
localuid = pwd->pw_uid;
#endif
if(!ptmp) {
- result = vstralloc("could not find home directory for ", CLIENT_LOGIN, NULL);
+ result = vstrallocf(_("could not find home directory for %s"), CLIENT_LOGIN);
goto common_exit;
}
* the destination user mimicing the .k5login functionality.
*/
if(strcmp(name, CLIENT_LOGIN) != 0) {
- result = vstralloc(name, " does not match ",
- CLIENT_LOGIN, NULL);
+ result = vstrallocf(_("%s does not match %s"),
+ name, CLIENT_LOGIN);
return result;
}
result = NULL;
goto common_exit;
}
- k5printf(("opening ptmp: %s\n", (ptmp)?ptmp: "NULL!"));
+ auth_debug(1, _("opening ptmp: %s\n"), (ptmp)?ptmp: "NULL!");
if((fp = fopen(ptmp, "r")) == NULL) {
- result = vstralloc("can not open ", ptmp, NULL);
+ result = vstrallocf(_("can not open %s"), ptmp);
return result;
}
- k5printf(("opened ptmp\n"));
+ auth_debug(1, _("opened ptmp\n"));
if (fstat(fileno(fp), &sbuf) != 0) {
- result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
+ result = vstrallocf(_("cannot fstat %s: %s"), ptmp, strerror(errno));
goto common_exit;
}
if (sbuf.st_uid != localuid) {
- snprintf(n1, SIZEOF(n1), "%ld", (long) sbuf.st_uid);
- snprintf(n2, SIZEOF(n2), "%ld", (long) localuid);
- result = vstralloc(ptmp, ": ",
- "owned by id ", n1,
- ", should be ", n2,
- NULL);
+ result = vstrallocf(_("%s is owned by %ld, should be %ld"),
+ ptmp, (long)sbuf.st_uid, (long)localuid);
goto common_exit;
}
if ((sbuf.st_mode & 077) != 0) {
- result = stralloc2(ptmp,
- ": incorrect permissions; file must be accessible only by its owner");
+ result = vstrallocf(
+ _("%s: incorrect permissions; file must be accessible only by its owner"), ptmp);
goto common_exit;
- }
+ }
while ((line = agets(fp)) != NULL) {
if (line[0] == '\0') {
continue;
}
-#if defined(SHOW_SECURITY_DETAIL) /* { */
- k5printf(("%s: processing line: <%s>\n", debug_prefix(NULL), line));
-#endif /* } */
/* if there's more than one column, then it's the host */
if( (filehost = strtok(line, " \t")) == NULL) {
amfree(line);
amfree(line);
continue;
} else {
- k5printf(("found a host match\n"));
+ auth_debug(1, _("found a host match\n"));
}
if( (filerealm = strchr(fileuser, '@')) != NULL) {
* You likely only get this far if you've turned on cross-realm auth
* anyway...
*/
- k5printf(("comparing %s %s\n", fileuser, name));
+ auth_debug(1, _("comparing %s %s\n"), fileuser, name);
if(strcmp(fileuser, name) == 0) {
- k5printf(("found a match!\n"));
+ auth_debug(1, _("found a match!\n"));
if(realm && filerealm && (strcmp(realm, filerealm)!=0)) {
amfree(line);
continue;
}
amfree(line);
}
- result = vstralloc("no match in ", ptmp, NULL);
+ result = vstrallocf(_("no match in %s"), ptmp);
common_exit:
afclose(fp);
return(result);
#endif /* AMANDA_PRINCIPAL */
}
-
-#else
-
-void krb5_security_dummy(void);
-
-void
-krb5_security_dummy(void)
-{
-}
-
-#endif /* KRB5_SECURITY */