2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: krb5-security.c,v 1.22 2006/06/16 10:55:05 martinea Exp $
30 * krb5-security.c - kerberos V5 security module
42 #include "security-util.h"
46 #define BROKEN_MEMORY_CCACHE
48 #ifdef BROKEN_MEMORY_CCACHE
50 * If you don't have atexit() or on_exit(), you could just consider
51 * making atexit() empty and clean up your ticket files some other
56 #define atexit(func) on_exit(func, 0)
58 #define atexit(func) (you must to resolve lack of atexit)
59 #endif /* HAVE_ON_EXIT */
60 #endif /* ! HAVE_ATEXIT */
63 #ifndef KRB5_HEIMDAL_INCLUDES
64 #include <gssapi/gssapi_generic.h>
66 #include <gssapi/gssapi.h>
70 #ifndef KRB5_ENV_CCNAME
71 #define KRB5_ENV_CCNAME "KRB5CCNAME"
74 /*#define KRB5_DEBUG*/
77 #define k5printf(x) dbprintf(x)
83 * consider undefining when kdestroy() is fixed. The current version does
84 * not work under krb5-1.2.4 in rh7.3, perhaps others.
86 #define KDESTROY_VIA_UNLINK 1
89 * Define this if you want all network traffic encrypted. This will
90 * extract a serious performance hit.
92 * It would be nice if we could do this on a filesystem-by-filesystem basis.
94 /*#define AMANDA_KRB5_ENCRYPT*/
97 * Where the keytab lives, if defined. Otherwise it expects something in the
100 /* #define AMANDA_KEYTAB "/.amanda-v5-keytab" */
103 * The name of the principal we authenticate with, if defined. Otherwise
104 * it expects something in the config file.
106 /* #define AMANDA_PRINCIPAL "service/amanda" */
109 * The lifetime of our tickets in seconds. This may or may not need to be
112 #define AMANDA_TKT_LIFETIME (12*60*60)
115 * The name of the service in /etc/services. This probably shouldn't be
118 #define AMANDA_KRB5_SERVICE_NAME "k5amanda"
121 * The default port to use if above entry in /etc/services doesn't exist
123 #define AMANDA_KRB5_DEFAULT_PORT 10082
126 * The timeout in seconds for each step of the GSS negotiation phase
128 #define GSS_TIMEOUT 30
131 * The largest buffer we can send/receive.
133 #define AMANDA_MAX_TOK_SIZE (MAX_TAPE_BLOCK_BYTES * 4)
136 * Magic values for krb5_conn->handle
138 #define H_EOF -1 /* this connection has been shut down */
141 * This is the tcp stream buffer size
143 #define KRB5_STREAM_BUFSIZE (MAX_TAPE_BLOCK_BYTES * 2)
146 * This is the max number of outgoing connections we can have at once.
147 * planner/amcheck/etc will open a bunch of connections as it tries
148 * to contact everything. We need to limit this to avoid blowing
149 * the max number of open file descriptors a process can have.
151 #define AMANDA_KRB5_MAXCONN 40
154 * This is a frame read off of the connection. Each frame has an
155 * associated handle and a gss_buffer which contains a len,value pair.
158 int handle; /* proto handle */
159 gss_buffer_desc tok; /* token */
160 TAILQ_ENTRY(krb5_frame) tq; /* queue handle */
164 * This is a krb5 connection to a host. We should only have
165 * one connection per host.
168 int fd; /* tcp connection */
169 struct { /* buffer read() calls */
170 char buf[KRB5_STREAM_BUFSIZE]; /* buffer */
171 size_t left; /* unread data */
172 ssize_t size; /* size of last read */
174 enum { unauthed, authed } state;
175 event_handle_t *ev_read; /* read (EV_READFD) handle */
176 int ev_read_refcnt; /* number of readers */
177 char hostname[MAX_HOSTNAME_LENGTH+1]; /* human form of above */
178 char *errmsg; /* error passed up */
179 gss_ctx_id_t gss_context; /* GSSAPI context */
180 int refcnt; /* number of handles using */
181 TAILQ_HEAD(, krb5_frame) frameq; /* queue of read frames */
182 TAILQ_ENTRY(krb5_conn) tq; /* queue handle */
189 * This is the private handle data.
192 security_handle_t sech; /* MUST be first */
193 char *hostname; /* ptr to kc->hostname */
194 struct krb5_stream *ks; /* virtual stream we xmit over */
197 void (*recvpkt)(void *, pkt_t *, security_status_t);
198 /* func to call when packet recvd */
199 void (*connect)(void *, security_handle_t *, security_status_t);
200 /* func to call when connected */
202 void *arg; /* argument to pass function */
203 void *datap; /* argument to pass function */
204 event_handle_t *ev_wait; /* wait handle for connects */
205 char *(*conf_fn)(char *, void *); /* used to get config info */
206 event_handle_t *ev_timeout; /* timeout handle for recv */
210 * This is the internal security_stream data for krb5.
213 security_stream_t secstr; /* MUST be first */
214 struct krb5_conn *kc; /* physical connection */
215 int handle; /* protocol handle */
216 event_handle_t *ev_read; /* read (EV_WAIT) event handle */
217 void (*fn)(void *, void *, ssize_t);/* read event fn */
218 void *arg; /* arg for previous */
219 char buf[KRB5_STREAM_BUFSIZE];
224 * Interface functions
226 static ssize_t krb5_sendpkt(void *, pkt_t *);
227 static int krb5_stream_accept(void *);
228 static int krb5_stream_auth(void *);
229 static int krb5_stream_id(void *);
230 static int krb5_stream_write(void *, const void *, size_t);
231 static void * krb5_stream_client(void *, int);
232 static void * krb5_stream_server(void *);
233 static void krb5_accept(const struct security_driver *, int, int,
234 void (*)(security_handle_t *, pkt_t *));
235 static void krb5_close(void *);
236 static void krb5_connect(const char *, char *(*)(char *, void *),
237 void (*)(void *, security_handle_t *, security_status_t),
239 static void krb5_recvpkt(void *, void (*)(void *, pkt_t *, security_status_t),
241 static void krb5_recvpkt_cancel(void *);
242 static void krb5_stream_close(void *);
243 static void krb5_stream_read(void *, void (*)(void *, void *, ssize_t), void *);
244 static ssize_t krb5_stream_read_sync(void *, void **);
245 static void krb5_stream_read_cancel(void *);
248 * This is our interface to the outside world.
250 const security_driver_t krb5_security_driver = {
266 krb5_stream_read_sync,
267 krb5_stream_read_cancel,
268 sec_close_connection_none,
272 * Cache the local hostname
274 static char hostname[MAX_HOSTNAME_LENGTH+1];
277 * This is a queue of open connections
280 TAILQ_HEAD(, krb5_conn) tailq;
283 TAILQ_HEAD_INITIALIZER(krb5_connq.tailq), 0
285 #define krb5_connq_first() TAILQ_FIRST(&krb5_connq.tailq)
286 #define krb5_connq_next(kc) TAILQ_NEXT(kc, tq)
287 #define krb5_connq_append(kc) do { \
288 TAILQ_INSERT_TAIL(&krb5_connq.tailq, kc, tq); \
289 krb5_connq.qlength++; \
291 #define krb5_connq_remove(kc) do { \
292 assert(krb5_connq.qlength > 0); \
293 TAILQ_REMOVE(&krb5_connq.tailq, kc, tq); \
294 krb5_connq.qlength--; \
297 static int newhandle = 1;
300 * This is a function that should be called if a new security_handle_t is
301 * created. If NULL, no new handles are created.
302 * It is passed the new handle and the received pkt
304 static void (*accept_fn)(security_handle_t *, pkt_t *);
309 static void init(void);
310 #ifdef BROKEN_MEMORY_CCACHE
311 static void cleanup(void);
313 static const char *get_tgt(char *, char *);
314 static void open_callback(void *);
315 static void connect_callback(void *);
316 static void connect_timeout(void *);
317 static int send_token(struct krb5_conn *, int, const gss_buffer_desc *);
318 static ssize_t recv_token(struct krb5_conn *, int *, gss_buffer_desc *, int);
319 static void recvpkt_callback(void *, void *, ssize_t);
320 static void recvpkt_timeout(void *);
321 static void stream_read_callback(void *);
322 static void stream_read_sync_callback2(void *, void *, ssize_t);
323 static int gss_server(struct krb5_conn *);
324 static int gss_client(struct krb5_handle *);
325 static const char *gss_error(OM_uint32, OM_uint32);
327 #ifdef AMANDA_KRB5_ENCRYPT
328 static int kdecrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
329 static int kencrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
331 static struct krb5_conn *conn_get(const char *);
332 static void conn_put(struct krb5_conn *);
333 static void conn_read(struct krb5_conn *);
334 static void conn_read_cancel(struct krb5_conn *);
335 static void conn_read_callback(void *);
336 static int conn_run_frameq(struct krb5_conn *, struct krb5_stream *);
337 static char * krb5_checkuser(char *, char *, char *);
341 * krb5 version of a security handle allocator. Logically sets
342 * up a network "connection".
346 const char *hostname,
347 char * (*conf_fn)(char *, void *),
348 void (*fn)(void *, security_handle_t *, security_status_t),
352 struct krb5_handle *kh;
358 char *keytab_name = NULL;
359 char *principal_name = NULL;
361 assert(hostname != NULL);
363 k5printf(("krb5_connect: %s\n", hostname));
366 * Make sure we're initted
370 kh = alloc(SIZEOF(*kh));
371 security_handleinit(&kh->sech, &krb5_security_driver);
375 kh->ev_timeout = NULL;
378 keytab_name = AMANDA_KEYTAB;
381 keytab_name = conf_fn("krb5keytab", datap);
384 #ifdef AMANDA_PRINCIPAL
385 principal_name = AMANDA_PRINCIPAL;
388 principal_name = conf_fn("krb5principal", datap);
392 if ((err = get_tgt(keytab_name, principal_name)) != NULL) {
393 security_seterror(&kh->sech, "%s: could not get TGT: %s",
395 (*fn)(arg, &kh->sech, S_ERROR);
399 if ((he = gethostbyname(hostname)) == NULL) {
400 security_seterror(&kh->sech,
401 "%s: could not resolve hostname", hostname);
402 (*fn)(arg, &kh->sech, S_ERROR);
406 kh->conf_fn = conf_fn;
409 kh->hostname = stralloc(he->h_name);
410 kh->ks = krb5_stream_client(kh, newhandle++);
419 * We need to open a new connection. See if we have too
420 * many connections open.
422 if (krb5_connq.qlength > AMANDA_KRB5_MAXCONN) {
423 k5printf(("krb5_connect: too many conections (%d), delaying %s\n",
424 krb5_connq.qlength, kh->hostname));
425 krb5_stream_close(kh->ks);
426 kh->ev_wait = event_register((event_id_t)open_callback,
427 EV_WAIT, open_callback, kh);
431 if ((se = getservbyname(AMANDA_KRB5_SERVICE_NAME, "tcp")) == NULL)
432 port = htons(AMANDA_KRB5_DEFAULT_PORT);
437 * Get a non-blocking socket.
439 fd = stream_client(kh->hostname, ntohs(port), KRB5_STREAM_BUFSIZE,
440 KRB5_STREAM_BUFSIZE, NULL, 1);
442 security_seterror(&kh->sech,
443 "can't connect to %s:%d: %s", hostname, ntohs(port),
450 * The socket will be opened async so hosts that are down won't
451 * block everything. We need to register a write event
452 * so we will know when the socket comes alive.
453 * We also register a timeout.
455 kh->ev_wait = event_register((event_id_t)fd, EV_WRITEFD,
456 connect_callback, kh);
457 kh->ev_timeout = event_register((event_id_t)GSS_TIMEOUT, EV_TIME,
458 connect_timeout, kh);
463 (*fn)(arg, &kh->sech, S_ERROR);
467 * Called when there are not too many connections open such that
474 struct krb5_handle *kh = cookie;
476 event_release(kh->ev_wait);
478 k5printf(("krb5: open_callback: possible connections available, retry %s\n",
480 krb5_connect(kh->hostname, kh->conf_fn, kh->fn.connect, kh->arg,kh->datap);
481 amfree(kh->hostname);
486 * Called when a tcp connection is finished connecting and is ready
487 * to be authenticated.
493 struct krb5_handle *kh = cookie;
495 event_release(kh->ev_wait);
497 event_release(kh->ev_timeout);
498 kh->ev_timeout = NULL;
500 if (kh->ks->kc->state == unauthed) {
501 if (gss_client(kh) < 0) {
502 (*kh->fn.connect)(kh->arg, &kh->sech, S_ERROR);
505 kh->ks->kc->state = authed;
507 assert(kh->ks->kc->gss_context != GSS_C_NO_CONTEXT);
509 (*kh->fn.connect)(kh->arg, &kh->sech, S_OK);
513 * Called if a connection times out before completion.
519 struct krb5_handle *kh = cookie;
521 event_release(kh->ev_wait);
523 event_release(kh->ev_timeout);
524 kh->ev_timeout = NULL;
526 (*kh->fn.connect)(kh->arg, &kh->sech, S_TIMEOUT);
530 * Setup to handle new incoming connections
534 const struct security_driver *driver,
537 void (*fn)(security_handle_t *, pkt_t *))
539 struct sockaddr_in sin;
541 struct krb5_conn *kc;
545 * Make sure we're initted
549 /* shut up compiler */
554 if (getpeername(in, (struct sockaddr *)&sin, &len) < 0)
556 he = gethostbyaddr((void *)&sin.sin_addr, SIZEOF(sin.sin_addr), AF_INET);
560 kc = conn_get(he->h_name);
562 if (gss_server(kc) < 0)
563 error("gss_server failed: %s\n", kc->errmsg);
570 * Locate an existing connection to the given host, or create a new,
571 * unconnected entry if none exists. The caller is expected to check
572 * for the lack of a connection (kc->fd == -1) and set one up.
574 static struct krb5_conn *
576 const char * hostname)
578 struct krb5_conn *kc;
580 k5printf(("krb5: conn_get: %s\n", hostname));
582 for (kc = krb5_connq_first(); kc != NULL; kc = krb5_connq_next(kc)) {
583 if (strcasecmp(hostname, kc->hostname) == 0)
589 k5printf(("krb5: conn_get: exists, refcnt to %s is now %d\n",
590 kc->hostname, kc->refcnt));
594 k5printf(("krb5: conn_get: creating new handle\n"));
596 * We can't be creating a new handle if we are the client
598 assert(accept_fn == NULL);
599 kc = alloc(SIZEOF(*kc));
601 kc->readbuf.left = 0;
602 kc->readbuf.size = 0;
603 kc->state = unauthed;
605 strncpy(kc->hostname, hostname, SIZEOF(kc->hostname) - 1);
606 kc->hostname[SIZEOF(kc->hostname) - 1] = '\0';
608 kc->gss_context = GSS_C_NO_CONTEXT;
610 * [XXX] this is set to 2 in order to force the connection to stay
611 * open and process more protocol requests. (basically consistant
612 * with bsd-security.c, and theoretically krb4-security.c. This
613 * needs to be addressed in a cleaner way.
616 TAILQ_INIT(&kc->frameq);
617 krb5_connq_append(kc);
622 * Delete a reference to a connection, and close it if it is the last
627 struct krb5_conn * kc)
630 struct krb5_frame *kf;
632 assert(kc->refcnt > 0);
633 if (--kc->refcnt > 0) {
634 k5printf(("krb5: conn_put: decrementing refcnt for %s to %d\n",
635 kc->hostname, kc->refcnt));
638 k5printf(("krb5: conn_put: closing connection to %s\n", kc->hostname));
641 if (kc->ev_read != NULL)
642 event_release(kc->ev_read);
643 if (kc->errmsg != NULL)
645 gss_delete_sec_context(&min_stat, &kc->gss_context, GSS_C_NO_BUFFER);
646 while ((kf = TAILQ_FIRST(&kc->frameq)) != NULL) {
647 TAILQ_REMOVE(&kc->frameq, kf, tq);
648 if (kf->tok.value != NULL)
649 amfree(kf->tok.value);
652 krb5_connq_remove(kc);
654 /* signal that a connection is available */
655 event_wakeup((event_id_t)open_callback);
659 * Turn on read events for a conn. Or, increase a refcnt if we are
660 * already receiving read events.
664 struct krb5_conn *kc)
667 if (kc->ev_read != NULL) {
668 kc->ev_read_refcnt++;
669 k5printf(("krb5: conn_read: incremented refcnt to %d for %s\n",
670 kc->ev_read_refcnt, kc->hostname));
673 k5printf(("krb5: conn_read registering event handler for %s\n",
675 kc->ev_read = event_register((event_id_t)kc->fd, EV_READFD, conn_read_callback, kc);
676 kc->ev_read_refcnt = 1;
681 struct krb5_conn * kc)
684 if (--kc->ev_read_refcnt > 0) {
685 k5printf(("krb5: conn_read_cancel: decremented refcnt to %d for %s\n",
686 kc->ev_read_refcnt, kc->hostname));
689 k5printf(("krb5: conn_read_cancel: releasing event handler for %s\n",
691 event_release(kc->ev_read);
696 * frees a handle allocated by the above
702 struct krb5_handle *kh = inst;
706 k5printf(("krb5: closing handle to %s\n", kh->hostname));
708 if (kh->ks != NULL) {
709 /* This may be null if we get here on an error */
710 krb5_recvpkt_cancel(kh);
711 security_stream_close(&kh->ks->secstr);
713 amfree(kh->hostname);
718 * Transmit a packet. Encrypt first.
725 struct krb5_handle *kh = cookie;
733 k5printf(("krb5: sendpkt: enter\n"));
735 if (pkt->body[0] == '\0') {
737 tok.value = alloc(SIZEOF(pkt->type));
738 memcpy(tok.value, &pkt->type, sizeof(unsigned char));
740 tok.length = strlen(pkt->body) + 2;
741 tok.value = alloc(tok.length);
743 *buf++ = (unsigned char)pkt->type;
744 strncpy((char *)buf, pkt->body, tok.length - 2);
745 buf[tok.length - 2] = '\0';
748 k5printf(("krb5: sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
749 pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body));
751 rval = krb5_stream_write(kh->ks, tok.value, tok.length);
753 security_seterror(&kh->sech, security_stream_geterror(&kh->ks->secstr));
761 * Set up to receive a packet asyncronously, and call back when
767 void (*fn)(void *, pkt_t *, security_status_t),
771 struct krb5_handle *kh = cookie;
775 k5printf(("krb5: recvpkt registered for %s\n", kh->hostname));
778 * Reset any pending timeout on this handle
780 if (kh->ev_timeout != NULL)
781 event_release(kh->ev_timeout);
784 * Negative timeouts mean no timeout
787 kh->ev_timeout = NULL;
789 kh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
790 recvpkt_timeout, kh);
794 krb5_stream_read(kh->ks, recvpkt_callback, kh);
798 * Remove a async receive request from the queue
804 struct krb5_handle *kh = cookie;
806 k5printf(("krb5: cancelling recvpkt for %s\n", kh->hostname));
810 krb5_stream_read_cancel(kh->ks);
811 if (kh->ev_timeout != NULL) {
812 event_release(kh->ev_timeout);
813 kh->ev_timeout = NULL;
818 * This is called when a handle is woken up because data read off of the
828 struct krb5_handle *kh = cookie;
833 * We need to cancel the recvpkt request before calling
834 * the callback because the callback may reschedule us.
836 krb5_recvpkt_cancel(kh);
840 security_seterror(&kh->sech,
841 "EOF on read from %s", kh->hostname);
842 (*kh->fn.recvpkt)(kh->arg, NULL, S_ERROR);
845 security_seterror(&kh->sech, security_stream_geterror(&kh->ks->secstr));
846 (*kh->fn.recvpkt)(kh->arg, NULL, S_ERROR);
849 parse_pkt(&pkt, buf, (size_t)bufsize);
850 k5printf(("krb5: received %s pkt (%d) from %s, contains:\n\n\"%s\"\n\n",
851 pkt_type2str(pkt.type), pkt.type, kh->hostname, pkt.body));
852 (*kh->fn.recvpkt)(kh->arg, &pkt, S_OK);
858 * This is called when a handle times out before receiving a packet.
864 struct krb5_handle *kh = cookie;
868 k5printf(("krb5: recvpkt timeout for %s\n", kh->hostname));
870 krb5_recvpkt_cancel(kh);
871 (*kh->fn.recvpkt)(kh->arg, NULL, S_TIMEOUT);
875 * Create the server end of a stream. For krb5, this means setup a stream
876 * object and allocate a new handle for it.
882 struct krb5_handle *kh = h;
883 struct krb5_stream *ks;
887 ks = alloc(SIZEOF(*ks));
888 security_streaminit(&ks->secstr, &krb5_security_driver);
889 ks->kc = conn_get(kh->hostname);
891 * Stream should already be setup!
893 if (ks->kc->fd < 0) {
896 security_seterror(&kh->sech, "lost connection");
900 * so as not to conflict with the amanda server's handle numbers,
901 * we start at 5000 and work down
903 ks->handle = (int)(5000 - newhandle++);
905 k5printf(("krb5: stream_server: created stream %d\n", ks->handle));
910 * Accept an incoming connection on a stream_server socket
911 * Nothing needed for krb5.
918 /* shut up compiler */
925 * Return a connected stream. For krb5, this means setup a stream
926 * with the supplied handle.
933 struct krb5_handle *kh = h;
934 struct krb5_stream *ks;
939 security_seterror(&kh->sech,
940 "%d: invalid security stream id", id);
944 ks = alloc(SIZEOF(*ks));
945 security_streaminit(&ks->secstr, &krb5_security_driver);
946 ks->handle = (int)id;
948 ks->kc = conn_get(kh->hostname);
950 k5printf(("krb5: stream_client: connected to stream %d\n", id));
956 * Close and unallocate resources for a stream.
962 struct krb5_stream *ks = s;
966 k5printf(("krb5: stream_close: closing stream %d\n", ks->handle));
968 krb5_stream_read_cancel(ks);
974 * Authenticate a stream
975 * Nothing needed for krb5. The tcp connection is authenticated
982 /* shut up compiler */
989 * Returns the stream id for this stream. This is just the local
996 struct krb5_stream *ks = s;
1000 return (ks->handle);
1004 * Write a chunk of data to a stream. Blocks until completion.
1012 struct krb5_stream *ks = s;
1013 gss_buffer_desc tok;
1014 #ifdef AMANDA_KRB5_ENCRYPT
1015 gss_buffer_desc enctok;
1022 k5printf(("krb5: stream_write: writing %d bytes to %s:%d\n", size,
1023 ks->kc->hostname, ks->handle));
1026 tok.value = (void *)buf; /* safe to discard const */
1027 #ifdef AMANDA_KRB5_ENCRYPT
1028 if (kencrypt(ks, &tok, &enctok) < 0)
1030 rc = send_token(ks->kc, ks->handle, &enctok);
1032 rc = send_token(ks->kc, ks->handle, &tok);
1035 security_stream_seterror(&ks->secstr, ks->kc->errmsg);
1036 #ifdef AMANDA_KRB5_ENCRYPT
1037 gss_release_buffer(&min_stat, &enctok);
1043 * Submit a request to read some data. Calls back with the given
1044 * function and arg when completed.
1049 void (*fn)(void *, void *, ssize_t),
1052 struct krb5_stream *ks = s;
1057 * Only one read request can be active per stream.
1063 * First see if there's any queued frames for this stream.
1064 * If so, we're done.
1066 if (conn_run_frameq(ks->kc, ks) > 0)
1069 if (ks->ev_read == NULL) {
1070 ks->ev_read = event_register((event_id_t)ks->kc, EV_WAIT,
1071 stream_read_callback, ks);
1077 * Submit a request to read some data. Calls back with the given
1078 * function and arg when completed.
1081 krb5_stream_read_sync(
1085 struct krb5_stream *ks = s;
1090 * Only one read request can be active per stream.
1092 ks->fn = stream_read_sync_callback2;
1096 * First see if there's any queued frames for this stream.
1097 * If so, we're done.
1099 if (conn_run_frameq(ks->kc, ks) > 0)
1102 if (ks->ev_read != NULL)
1103 event_release(ks->ev_read);
1105 ks->ev_read = event_register((event_id_t)ks->kc, EV_WAIT,
1106 stream_read_callback, ks);
1108 event_wait(ks->ev_read);
1109 buf = (void **)&ks->buf;
1115 * Callback for krb5_stream_read_sync
1118 stream_read_sync_callback2(
1123 struct krb5_stream *ks = arg;
1127 k5printf(("krb5: stream_read_sync_callback2: handle %d\n", ks->handle));
1129 memcpy(ks->buf, buf, (size_t)size);
1134 * Cancel a previous stream read request. It's ok if we didn't have a read
1138 krb5_stream_read_cancel(
1141 struct krb5_stream *ks = s;
1145 if (ks->ev_read != NULL) {
1146 event_release(ks->ev_read);
1148 conn_read_cancel(ks->kc);
1153 * Callback for krb5_stream_read
1156 stream_read_callback(
1159 struct krb5_stream *ks = arg;
1163 k5printf(("krb5: stream_read_callback: handle %d\n", ks->handle));
1165 conn_run_frameq(ks->kc, ks);
1169 * Run down a list of queued frames for a krb5_conn, and if we find one
1170 * that matches the passed handle, fire the read event. Only
1171 * process one frame.
1173 * Returns 1 if a frame was found and processed.
1177 /*@keep@*/ struct krb5_conn * kc,
1178 /*@keep@*/ struct krb5_stream * ks)
1180 struct krb5_frame *kf, *nextkf;
1181 gss_buffer_desc *enctok, *dectok;
1182 #ifdef AMANDA_KRB5_ENCRYPT
1184 gss_buffer_desc tok;
1188 * Iterate through all of the frames in the queue. If one
1189 * is for us, process it. If we hit an EOF frame, shut down.
1190 * Stop after processing one frame, because we are only supposed
1191 * to return one read request.
1193 for (kf = TAILQ_FIRST(&kc->frameq); kf != NULL; kf = nextkf) {
1194 nextkf = TAILQ_NEXT(kf, tq);
1196 if (kf->handle != ks->handle && kf->handle != H_EOF) {
1197 k5printf(("krb5: conn_frameq_run: not for us (handle %d)\n",
1202 * We want all listeners to see the EOF, so never remove it.
1203 * It will get cleaned up when the connection is closed
1206 if (kf->handle != H_EOF)
1207 TAILQ_REMOVE(&kc->frameq, kf, tq);
1210 * Remove the event first, and then call the callback.
1211 * We remove it first because we don't want to get in their
1212 * way if they reschedule it.
1214 krb5_stream_read_cancel(ks);
1218 if (enctok->length == 0) {
1219 assert(kf->handle == H_EOF);
1220 k5printf(("krb5: stream_read_callback: EOF\n"));
1221 (*ks->fn)(ks->arg, NULL, 0);
1222 return (1); /* stop after EOF */
1225 #ifdef AMANDA_KRB5_ENCRYPT
1227 if (kdecrypt(ks, enctok, &tok) < 0) {
1228 k5printf(("krb5: stream_read_callback: kdecrypt error\n"));
1229 (*ks->fn)(ks->arg, NULL, -1);
1235 k5printf(("krb5: stream_read_callback: read %d bytes from %s:%d\n",
1236 dectok->length, ks->kc->hostname, ks->handle));
1237 (*ks->fn)(ks->arg, dectok->value, (ssize_t)dectok->length);
1238 #ifdef AMANDA_KRB5_ENCRYPT
1239 gss_release_buffer(&min_stat, dectok);
1242 amfree(enctok->value);
1244 return (1); /* stop after one frame */
1250 * The callback for the netfd for the event handler
1251 * Determines if this packet is for this security handle,
1252 * and does the real callback if so.
1258 struct krb5_conn *kc = cookie;
1259 struct krb5_handle *kh;
1260 struct krb5_frame *kf;
1262 gss_buffer_desc *dectok;
1264 #ifdef AMANDA_KRB5_ENCRYPT
1265 gss_buffer_desc tok;
1269 assert(cookie != NULL);
1271 k5printf(("krb5: conn_read_callback\n"));
1273 kf = alloc(SIZEOF(*kf));
1274 TAILQ_INSERT_TAIL(&kc->frameq, kf, tq);
1276 /* Read the data off the wire. If we get errors, shut down. */
1277 rc = recv_token(kc, &kf->handle, &kf->tok, 5);
1278 k5printf(("krb5: conn_read_callback: recv_token returned %d handle = %d\n",
1281 kf->tok.value = NULL;
1284 rc = event_wakeup((event_id_t)kc);
1285 k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
1289 /* If there are events waiting on this handle, we're done */
1290 rc = event_wakeup((event_id_t)kc);
1291 k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
1296 * If there is no accept fn registered, then just leave the
1297 * packet queued. The caller may register a function later.
1299 if (accept_fn == NULL) {
1300 k5printf(("krb5: no accept_fn so leaving packet queued.\n"));
1304 kh = alloc(SIZEOF(*kh));
1305 security_handleinit(&kh->sech, &krb5_security_driver);
1306 kh->hostname = stralloc(kc->hostname);
1307 kh->ks = krb5_stream_client(kh, kf->handle);
1309 kh->ev_timeout = NULL;
1311 TAILQ_REMOVE(&kc->frameq, kf, tq);
1312 k5printf(("krb5: new connection\n"));
1313 #ifdef AMANDA_KRB5_ENCRYPT
1315 rc = kdecrypt(kh->ks, &kf->tok, dectok);
1320 #ifdef AMANDA_KRB5_ENCRYPT
1322 security_seterror(&kh->sech, security_geterror(&kh->ks->secstr));
1323 (*accept_fn)(&kh->sech, NULL);
1327 parse_pkt(&pkt, dectok->value, dectok->length);
1328 #ifdef AMANDA_KRB5_ENCRYPT
1329 gss_release_buffer(&min_stat, dectok);
1331 (*accept_fn)(&kh->sech, &pkt);
1333 amfree(kf->tok.value);
1337 * We can only accept one connection per process, since we're tcp
1338 * based and run out of inetd. So, delete our accept reference once
1339 * we've gotten the first connection.
1343 * [XXX] actually, the protocol has been changed to have multiple
1344 * requests in one session be possible. By not resetting accept_fn,
1345 * this will caused them to be properly processed. this needs to be
1346 * addressed in a much cleaner way.
1348 if (accept_fn != NULL)
1350 /* accept_fn = NULL; */
1354 * Negotiate a krb5 gss context from the client end.
1358 struct krb5_handle *kh)
1360 struct krb5_stream *ks = kh->ks;
1361 struct krb5_conn *kc = ks->kc;
1362 gss_buffer_desc send_tok, recv_tok;
1363 OM_uint32 maj_stat, min_stat;
1364 unsigned int ret_flags;
1366 gss_name_t gss_name;
1368 k5printf(("gss_client\n"));
1370 send_tok.value = vstralloc("host/", ks->kc->hostname, NULL);
1371 send_tok.length = strlen(send_tok.value) + 1;
1372 maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
1374 if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
1375 security_seterror(&kh->sech, "can't import name %s: %s",
1376 (char *)send_tok.value, gss_error(maj_stat, min_stat));
1377 amfree(send_tok.value);
1380 amfree(send_tok.value);
1381 kc->gss_context = GSS_C_NO_CONTEXT;
1384 * Perform the context-establishement loop.
1386 * Every generated token is stored in send_tok which is then
1387 * transmitted to the server; every received token is stored in
1388 * recv_tok (empty on the first pass) to be processed by
1389 * the next call to gss_init_sec_context.
1391 * GSS-API guarantees that send_tok's length will be non-zero
1392 * if and only if the server is expecting another token from us,
1393 * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
1394 * and only if the server has another token to send us.
1397 recv_tok.value = NULL;
1398 for (recv_tok.length = 0;;) {
1400 maj_stat = gss_init_sec_context(&min_stat,
1401 GSS_C_NO_CREDENTIAL,
1405 (OM_uint32)GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,
1406 0, NULL, /* no channel bindings */
1407 (recv_tok.length == 0 ? GSS_C_NO_BUFFER : &recv_tok),
1408 NULL, /* ignore mech type */
1411 NULL); /* ignore time_rec */
1413 if (recv_tok.length != 0) {
1414 amfree(recv_tok.value);
1415 recv_tok.length = 0;
1418 if (maj_stat != (OM_uint32)GSS_S_COMPLETE && maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1419 security_seterror(&kh->sech,
1420 "error getting gss context: %s",
1421 gss_error(maj_stat, min_stat));
1426 * Send back the response
1428 if (send_tok.length != 0 && send_token(kc, ks->handle, &send_tok) < 0) {
1429 security_seterror(&kh->sech, kc->errmsg);
1430 gss_release_buffer(&min_stat, &send_tok);
1433 gss_release_buffer(&min_stat, &send_tok);
1436 * If we need to continue, then register for more packets
1438 if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
1441 if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
1443 security_seterror(&kh->sech,
1444 "recv error in gss loop: %s", kc->errmsg);
1446 security_seterror(&kh->sech, "EOF in gss loop");
1453 gss_release_name(&min_stat, &gss_name);
1458 * Negotiate a krb5 gss context from the server end.
1462 struct krb5_conn * kc)
1464 OM_uint32 maj_stat, min_stat, ret_flags;
1465 gss_buffer_desc send_tok, recv_tok;
1467 gss_name_t gss_name;
1468 gss_cred_id_t gss_creds;
1469 char *p, *realm, *msg;
1474 k5printf(("gss_server\n"));
1479 * We need to be root while in gss_acquire_cred() to read the host key
1480 * out of the default keytab. We also need to be root in
1481 * gss_accept_context() thanks to the replay cache code.
1484 if (getuid() != 0) {
1485 snprintf(errbuf, SIZEOF(errbuf),
1486 "real uid is %ld, needs to be 0 to read krb5 host key",
1490 if (seteuid(0) < 0) {
1491 snprintf(errbuf, SIZEOF(errbuf),
1492 "can't seteuid to uid 0: %s", strerror(errno));
1496 send_tok.value = vstralloc("host/", hostname, NULL);
1497 send_tok.length = strlen(send_tok.value) + 1;
1498 for (p = send_tok.value; *p != '\0'; p++) {
1499 if (isupper((int)*p))
1502 maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
1504 if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
1506 snprintf(errbuf, SIZEOF(errbuf),
1507 "can't import name %s: %s", (char *)send_tok.value,
1508 gss_error(maj_stat, min_stat));
1509 amfree(send_tok.value);
1512 amfree(send_tok.value);
1514 maj_stat = gss_acquire_cred(&min_stat, gss_name, 0,
1515 GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_creds, NULL, NULL);
1516 if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
1517 snprintf(errbuf, SIZEOF(errbuf),
1518 "can't acquire creds for host key host/%s: %s", hostname,
1519 gss_error(maj_stat, min_stat));
1520 gss_release_name(&min_stat, &gss_name);
1524 gss_release_name(&min_stat, &gss_name);
1526 for (recv_tok.length = 0;;) {
1527 if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
1529 snprintf(errbuf, SIZEOF(errbuf),
1530 "recv error in gss loop: %s", kc->errmsg);
1533 snprintf(errbuf, SIZEOF(errbuf), "EOF in gss loop");
1537 maj_stat = gss_accept_sec_context(&min_stat, &kc->gss_context,
1538 gss_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
1539 &gss_name, &doid, &send_tok, &ret_flags, NULL, NULL);
1541 if (maj_stat != (OM_uint32)GSS_S_COMPLETE &&
1542 maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1543 snprintf(errbuf, SIZEOF(errbuf),
1544 "error accepting context: %s", gss_error(maj_stat, min_stat));
1545 amfree(recv_tok.value);
1548 amfree(recv_tok.value);
1550 if (send_tok.length > 0 && send_token(kc, 0, &send_tok) < 0) {
1551 strncpy(errbuf, kc->errmsg, SIZEOF(errbuf) - 1);
1552 errbuf[SIZEOF(errbuf) - 1] = '\0';
1554 gss_release_buffer(&min_stat, &send_tok);
1557 gss_release_buffer(&min_stat, &send_tok);
1561 * If we need to get more from the client, then register for
1564 if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
1568 maj_stat = gss_display_name(&min_stat, gss_name, &send_tok, &doid);
1569 if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
1570 snprintf(errbuf, SIZEOF(errbuf),
1571 "can't display gss name: %s", gss_error(maj_stat, min_stat));
1572 gss_release_name(&min_stat, &gss_name);
1575 gss_release_name(&min_stat, &gss_name);
1577 /* get rid of the realm */
1578 if ((p = strchr(send_tok.value, '@')) == NULL) {
1579 snprintf(errbuf, SIZEOF(errbuf),
1580 "malformed gss name: %s", (char *)send_tok.value);
1581 amfree(send_tok.value);
1588 * If the principal doesn't match, complain
1590 if ((msg = krb5_checkuser(kc->hostname, send_tok.value, realm)) != NULL) {
1591 snprintf(errbuf, SIZEOF(errbuf),
1592 "access not allowed from %s: %s", (char *)send_tok.value, msg);
1593 amfree(send_tok.value);
1596 amfree(send_tok.value);
1602 kc->errmsg = stralloc(errbuf);
1603 k5printf(("gss_server returning %d\n", rval));
1608 * Setup some things about krb5. This should only be called once.
1613 static int beenhere = 0;
1621 #ifndef BROKEN_MEMORY_CCACHE
1622 setenv(KRB5_ENV_CCNAME, "MEMORY:amanda_ccache", 1);
1625 * MEMORY ccaches seem buggy and cause a lot of internal heap
1626 * corruption. malloc has been known to core dump. This behavior
1627 * has been witnessed in Cygnus' kerbnet 1.2, MIT's krb V 1.0.5 and
1628 * MIT's krb V -current as of 3/17/1999.
1630 * We just use a lame ccache scheme with a uid suffix.
1635 snprintf(ccache, SIZEOF(ccache), "FILE:/tmp/amanda_ccache.%ld.%ld",
1636 (long)geteuid(), (long)getpid());
1637 setenv(KRB5_ENV_CCNAME, ccache, 1);
1641 gethostname(hostname, SIZEOF(hostname) - 1);
1642 hostname[SIZEOF(hostname) - 1] = '\0';
1644 * In case it isn't fully qualified, do a DNS lookup.
1646 if ((he = gethostbyname(hostname)) != NULL)
1647 strncpy(hostname, he->h_name, SIZEOF(hostname) - 1);
1650 * Lowercase the results. We assume all host/ principals will be
1653 for (p = hostname; *p != '\0'; p++) {
1654 if (isupper((int)*p))
1659 #ifdef BROKEN_MEMORY_CCACHE
1663 #ifdef KDESTROY_VIA_UNLINK
1665 snprintf(ccache, SIZEOF(ccache), "/tmp/amanda_ccache.%ld.%ld",
1666 (long)geteuid(), (long)getpid());
1675 * Get a ticket granting ticket and stuff it in the cache
1680 char * principal_name)
1682 krb5_context context;
1683 krb5_error_code ret;
1684 krb5_principal client = NULL, server = NULL;
1686 krb5_keytab keytab = NULL;
1689 krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
1690 static char *error = NULL;
1692 if (error != NULL) {
1697 if ((ret = krb5_init_context(&context)) != 0) {
1698 error = vstralloc("error initializing krb5 context: ",
1699 error_message(ret), NULL);
1703 /*krb5_init_ets(context);*/
1706 error = vstralloc("error -- no krb5 keytab defined", NULL);
1710 if(!principal_name) {
1711 error = vstralloc("error -- no krb5 principal defined", NULL);
1716 * Resolve keytab file into a keytab object
1718 if ((ret = krb5_kt_resolve(context, keytab_name, &keytab)) != 0) {
1719 error = vstralloc("error resolving keytab ", keytab, ": ",
1720 error_message(ret), NULL);
1725 * Resolve the amanda service held in the keytab into a principal
1728 ret = krb5_parse_name(context, principal_name, &client);
1730 error = vstralloc("error parsing ", principal_name, ": ",
1731 error_message(ret), NULL);
1735 ret = krb5_build_principal_ext(context, &server,
1736 krb5_princ_realm(context, client)->length,
1737 krb5_princ_realm(context, client)->data,
1738 tgtname.length, tgtname.data,
1739 krb5_princ_realm(context, client)->length,
1740 krb5_princ_realm(context, client)->data,
1743 error = vstralloc("error while building server name: ",
1744 error_message(ret), NULL);
1748 ret = krb5_timeofday(context, &now);
1750 error = vstralloc("error getting time of day: ", error_message(ret),
1755 memset(&creds, 0, SIZEOF(creds));
1756 creds.times.starttime = 0;
1757 creds.times.endtime = now + AMANDA_TKT_LIFETIME;
1759 creds.client = client;
1760 creds.server = server;
1763 * Get a ticket for the service, using the keytab
1765 ret = krb5_get_in_tkt_with_keytab(context, 0, NULL, NULL, NULL,
1766 keytab, 0, &creds, 0);
1769 error = vstralloc("error getting ticket for ", principal_name,
1770 ": ", error_message(ret), NULL);
1774 if ((ret = krb5_cc_default(context, &ccache)) != 0) {
1775 error = vstralloc("error initializing ccache: ", error_message(ret),
1779 if ((ret = krb5_cc_initialize(context, ccache, client)) != 0) {
1780 error = vstralloc("error initializing ccache: ", error_message(ret),
1784 if ((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) {
1785 error = vstralloc("error storing creds in ccache: ",
1786 error_message(ret), NULL);
1789 krb5_cc_close(context, ccache);
1791 krb5_free_cred_contents(context, &creds);
1794 krb5_free_principal(context, client);
1795 krb5_free_principal(context, server);
1797 krb5_free_context(context);
1802 * get rid of tickets
1807 krb5_context context;
1810 if ((krb5_init_context(&context)) != 0) {
1813 if ((krb5_cc_default(context, &ccache)) != 0) {
1817 krb5_cc_destroy(context, ccache);
1818 krb5_cc_close(context, ccache);
1821 krb5_free_context(context);
1826 * Formats an error from the gss api
1833 static gss_buffer_desc msg;
1834 OM_uint32 min_stat, msg_ctx;
1837 gss_release_buffer(&min_stat, &msg);
1840 if (major == GSS_S_FAILURE)
1841 gss_display_status(&min_stat, minor, GSS_C_MECH_CODE, GSS_C_NULL_OID,
1844 gss_display_status(&min_stat, major, GSS_C_GSS_CODE, GSS_C_NULL_OID,
1846 return ((const char *)msg.value);
1850 * Transmits a gss_buffer_desc over a krb5_handle, adding
1851 * the necessary headers to allow the remote end to decode it.
1852 * Encryption must be done by the caller.
1856 struct krb5_conn * kc,
1858 const gss_buffer_desc * tok)
1860 OM_uint32 netlength, nethandle;
1861 struct iovec iov[3];
1863 k5printf(("krb5: send_token: writing %d bytes to %s\n", tok->length,
1866 if (tok->length > AMANDA_MAX_TOK_SIZE) {
1867 kc->errmsg = newvstralloc(kc->errmsg, "krb5 write error to ",
1868 kc->hostname, ": token too large", NULL);
1874 * 32 bit length (network byte order)
1875 * 32 bit handle (network byte order)
1878 netlength = (OM_uint32)htonl(tok->length);
1879 iov[0].iov_base = (void *)&netlength;
1880 iov[0].iov_len = SIZEOF(netlength);
1882 nethandle = (OM_uint32)htonl((uint32_t)handle);
1883 iov[1].iov_base = (void *)&nethandle;
1884 iov[1].iov_len = SIZEOF(nethandle);
1886 iov[2].iov_base = (void *)tok->value;
1887 iov[2].iov_len = tok->length;
1889 if (net_writev(kc->fd, iov, 3) < 0) {
1890 kc->errmsg = newvstralloc(kc->errmsg, "krb5 write error to ",
1891 kc->hostname, ": ", strerror(errno), NULL);
1899 struct krb5_conn * kc,
1901 gss_buffer_desc * gtok,
1904 OM_uint32 netint[2];
1906 assert(kc->fd >= 0);
1907 assert(gtok != NULL);
1909 k5printf(("krb5: recv_token: reading from %s\n", kc->hostname));
1911 switch (net_read(kc->fd, &netint, SIZEOF(netint), timeout)) {
1913 kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
1915 k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
1923 gtok->length = ntohl(netint[0]);
1925 if (gtok->length > AMANDA_MAX_TOK_SIZE) {
1926 kc->errmsg = newstralloc(kc->errmsg, "recv error: buffer too large");
1927 k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
1932 *handle = ntohl(netint[1]);
1934 gtok->value = alloc(gtok->length);
1935 switch (net_read(kc->fd, gtok->value, gtok->length, timeout)) {
1937 kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
1939 k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
1940 amfree(gtok->value);
1943 amfree(gtok->value);
1950 k5printf(("krb5: recv_token: read %d bytes from %s\n", gtok->length,
1952 return ((ssize_t)gtok->length);
1955 #ifdef AMANDA_KRB5_ENCRYPT
1958 struct krb5_stream *ks,
1959 gss_buffer_desc * tok,
1960 gss_buffer_desc * enctok)
1963 OM_uint32 maj_stat, min_stat;
1965 assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
1966 maj_stat = gss_seal(&min_stat, ks->kc->gss_context, 1,
1967 GSS_C_QOP_DEFAULT, tok, &conf_state, enctok);
1968 if (maj_stat != (OM_uint32)GSS_S_COMPLETE || conf_state == 0) {
1969 security_stream_seterror(&ks->secstr,
1970 "krb5 encryption failed to %s: %s",
1971 ks->kc->hostname, gss_error(maj_stat, min_stat));
1979 struct krb5_stream *ks,
1980 gss_buffer_desc * enctok,
1981 gss_buffer_desc * tok)
1983 OM_uint32 maj_stat, min_stat;
1984 int conf_state, qop_state;
1986 k5printf(("krb5: kdecrypt: decrypting %d bytes\n", enctok->length));
1988 assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
1989 maj_stat = gss_unseal(&min_stat, ks->kc->gss_context, enctok, tok,
1990 &conf_state, &qop_state);
1991 if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
1992 security_stream_seterror(&ks->secstr, "krb5 decrypt error from %s: %s",
1993 ks->kc->hostname, gss_error(maj_stat, min_stat));
2001 * hackish, but you can #undef AMANDA_PRINCIPAL here, and you can both
2002 * hardcode a principal in your build and use the .k5amandahosts. This is
2003 * available because sites that run pre-releases of amanda 2.5.0 before
2004 * this feature was there do not behave this way...
2007 /*#undef AMANDA_PRINCIPAL*/
2010 * check ~/.k5amandahosts to see if this principal is allowed in. If it's
2011 * hardcoded, then we don't check the realm
2014 krb5_checkuser( char * host,
2018 #ifdef AMANDA_PRINCIPAL
2019 if(strcmp(name, AMANDA_PRINCIPAL) == 0) {
2022 return(vstralloc("does not match compiled in default"));
2027 char *result = "generic error"; /* default is to not permit */
2032 char *filehost = NULL, *fileuser = NULL, *filerealm = NULL;
2033 char n1[NUM_STR_SIZE];
2034 char n2[NUM_STR_SIZE];
2036 assert( host != NULL);
2037 assert( name != NULL);
2039 if((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
2040 result = vstralloc("can not find user ", CLIENT_LOGIN, NULL);
2042 localuid = pwd->pw_uid;
2044 #ifdef USE_AMANDAHOSTS
2045 ptmp = stralloc2(pwd->pw_dir, "/.k5amandahosts");
2047 ptmp = stralloc2(pwd->pw_dir, "/.k5login");
2051 result = vstralloc("could not find home directory for ", CLIENT_LOGIN, NULL);
2056 * check to see if the ptmp file does nto exist.
2058 if(access(ptmp, R_OK) == -1 && errno == ENOENT) {
2060 * in this case we check to see if the principal matches
2061 * the destination user mimicing the .k5login functionality.
2063 if(strcmp(name, CLIENT_LOGIN) != 0) {
2064 result = vstralloc(name, " does not match ",
2065 CLIENT_LOGIN, NULL);
2072 k5printf(("opening ptmp: %s\n", (ptmp)?ptmp: "NULL!"));
2073 if((fp = fopen(ptmp, "r")) == NULL) {
2074 result = vstralloc("can not open ", ptmp, NULL);
2077 k5printf(("opened ptmp\n"));
2079 if (fstat(fileno(fp), &sbuf) != 0) {
2080 result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
2084 if (sbuf.st_uid != localuid) {
2085 snprintf(n1, SIZEOF(n1), "%ld", (long) sbuf.st_uid);
2086 snprintf(n2, SIZEOF(n2), "%ld", (long) localuid);
2087 result = vstralloc(ptmp, ": ",
2093 if ((sbuf.st_mode & 077) != 0) {
2094 result = stralloc2(ptmp,
2095 ": incorrect permissions; file must be accessible only by its owner");
2099 while ((line = agets(fp)) != NULL) {
2100 if (line[0] == '\0') {
2105 #if defined(SHOW_SECURITY_DETAIL) /* { */
2106 k5printf(("%s: processing line: <%s>\n", debug_prefix(NULL), line));
2108 /* if there's more than one column, then it's the host */
2109 if( (filehost = strtok(line, " \t")) == NULL) {
2115 * if there's only one entry, then it's a username and we have
2116 * no hostname. (so the principal is allowed from anywhere.
2118 if((fileuser = strtok(NULL, " \t")) == NULL) {
2119 fileuser = filehost;
2123 if(filehost && strcmp(filehost, host) != 0) {
2127 k5printf(("found a host match\n"));
2130 if( (filerealm = strchr(fileuser, '@')) != NULL) {
2131 *filerealm++ = '\0';
2135 * we have a match. We're going to be a little bit insecure
2136 * and indicate that the principal is correct but the realm is
2137 * not if that's the case. Technically we should say nothing
2138 * and let the user figure it out, but it's helpful for debugging.
2139 * You likely only get this far if you've turned on cross-realm auth
2142 k5printf(("comparing %s %s\n", fileuser, name));
2143 if(strcmp(fileuser, name) == 0) {
2144 k5printf(("found a match!\n"));
2145 if(realm && filerealm && (strcmp(realm, filerealm)!=0)) {
2155 result = vstralloc("no match in ", ptmp, NULL);
2160 #endif /* AMANDA_PRINCIPAL */
2165 void krb5_security_dummy(void);
2168 krb5_security_dummy(void)
2172 #endif /* KRB5_SECURITY */