source: trunk/athena/bin/authwatch/authwatch.c @ 21997

Revision 21997, 6.3 KB checked in by ghudson, 19 years ago (diff)
Modern gtk doesn't let us frob the window type of a widget after creation. So set it on creation, which means expanding out the relevant parts of gtk_message_dialog_new().
Line 
1/* Copyright 2002 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this software and
4 * its documentation for any purpose and without fee is hereby
5 * granted, provided that the above copyright notice appear in all
6 * copies and that both that copyright notice and this permission
7 * notice appear in supporting documentation, and that the name of
8 * M.I.T. not be used in advertising or publicity pertaining to
9 * distribution of the software without specific, written prior
10 * permission.  M.I.T. makes no representations about the suitability
11 * of this software for any purpose.  It is provided "as is" without
12 * express or implied warranty.
13 */
14
15/* authwatch: Watch the expiration time on the user's kerberos
16 * tickets; pop up a warning dialog when authentication is about to
17 * expire.
18 */
19
20static const char rcsid[] = "$Id: authwatch.c,v 1.6 2005-05-13 16:05:29 ghudson Exp $";
21
22#include <stdio.h>
23#include <sys/types.h>
24
25#include <krb5.h>
26#include <com_err.h>
27
28#include <gtk/gtk.h>
29
30#define MAX_TIMEOUT 60*5   /* Maximum interval between checks, in seconds */
31
32krb5_context k5_context;
33
34static gboolean expose_cb(GtkWidget *dialog, GdkEventExpose *event,
35                          gpointer unused);
36static gint timeout_cb(gpointer reset);
37
38
39/* Find the expiration time (unix time) of the TGT currently in the
40 * default krb5 credentials cache.  Returns 0 if there are no
41 * credentials currently accessible, or on krb5 library errors.
42 */
43
44time_t get_krb5_expiration()
45{
46  time_t expiration = 0;
47  krb5_ccache cc;
48  krb5_creds creds, mcreds;
49  krb5_data *realm;
50
51  memset(&creds, 0, sizeof(creds));
52  memset(&mcreds, 0, sizeof(mcreds));
53
54  /* Access the default credentials cache. */
55  if (krb5_cc_default(k5_context, &cc) != 0)
56    goto cleanup;
57
58  /* Fill in mcreds.client with the primary principal of the ccache */
59  if (krb5_cc_get_principal(k5_context, cc, &mcreds.client) != 0)
60    goto cleanup;
61
62  /* Fill in mcreds.server with "krbtgt/realm@realm" */
63  realm = krb5_princ_realm(k5_context, mcreds.client);
64  if (krb5_build_principal_ext(k5_context, &mcreds.server,
65                               realm->length, realm->data,
66                               KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
67                               realm->length, realm->data,
68                               NULL)
69      != 0)
70    goto cleanup;
71
72  /* Get the TGT from the ccache */
73  if (krb5_cc_retrieve_cred(k5_context, cc, (krb5_flags) 0,
74                            &mcreds, &creds) != 0)
75    goto cleanup;
76
77  expiration = creds.times.endtime;
78
79 cleanup:
80  krb5_free_cred_contents(k5_context, &creds);
81  krb5_free_cred_contents(k5_context, &mcreds);
82  krb5_cc_close(k5_context, cc);
83
84  return expiration;
85}
86
87/* Here on an expose event. */
88static gboolean expose_cb(GtkWidget *dialog, GdkEventExpose *event,
89                          gpointer unused)
90{
91  /* Force a state check. */
92  gtk_timeout_add(0, timeout_cb, GUINT_TO_POINTER(FALSE));
93  return FALSE;                 /* Continue with normal event handling. */
94}
95
96/* Run periodically by the gtk main loop.  We always remove the
97 * timeout which invoked us, but, if the argument is TRUE, we
98 * will add another timeout for the smaller of the predicted
99 * time until a state change, and MAX_TIMEOUT.
100 */
101static gint timeout_cb(gpointer reset)
102{
103  time_t now, expiration;
104  time_t duration = 0;
105  int nstate;
106  unsigned int timeout;
107  GtkContainer *container;
108  GList *children;
109
110  static GtkWidget *dialog = NULL;
111  static int state = -1;
112
113  static const struct {
114    const unsigned int tte;     /* Time to expiration, in seconds */
115    const char *message;        /* Formatted for a gtk_message_dialog */
116  } warnings[] = {
117    { 0,
118"You have no authentication.  Select ``Renew Authentication'' from the "
119"Athena ``Utilities'' menu to re-authenticate."
120    },
121
122    { 60,
123"Your authentication will expire in less than one minute.  Select "
124"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
125    },
126
127    { 60*5,
128"Your authentication will expire in less than five minutes.  Select "
129"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
130    },
131
132    { 60*15,
133"Your authentication will expire in less than fifteen minutes.  Select "
134"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
135    }
136  };
137  static const int nwarnings = sizeof(warnings) / sizeof(*warnings);
138
139  expiration = get_krb5_expiration();
140
141  time(&now);
142  if (expiration > now)
143    duration = expiration - now;
144
145  nstate = nwarnings;
146  do
147    {
148      if (duration > warnings[nstate - 1].tte)
149        break;
150      nstate--;
151    }
152  while (nstate > 0);
153
154  if (nstate != state)
155    {
156      state = nstate;
157
158      if (dialog != NULL)
159        gtk_widget_destroy(dialog);
160
161      if (state < nwarnings)
162        {
163          dialog = g_object_new(GTK_TYPE_MESSAGE_DIALOG,
164                                "message_type", GTK_MESSAGE_WARNING,
165                                "buttons", GTK_BUTTONS_OK,
166                                "type", GTK_WINDOW_POPUP, NULL);
167          if (dialog == NULL)
168            {
169              fprintf(stderr, "authwatch: error creating dialog window\n");
170              exit(1);
171            }
172          gtk_label_set_text(GTK_LABEL(GTK_MESSAGE_DIALOG(dialog)->label),
173                             warnings[state].message);
174          g_signal_connect(G_OBJECT(dialog), "response",
175                           G_CALLBACK(gtk_widget_destroy), NULL);
176          g_signal_connect(G_OBJECT(dialog), "destroy",
177                           G_CALLBACK(gtk_widget_destroyed), &dialog);
178          container = GTK_CONTAINER(GTK_DIALOG(dialog)->vbox);
179          children = gtk_container_get_children(container);
180          g_signal_connect(G_OBJECT(g_list_nth_data(children, 1)),
181                           "expose_event", G_CALLBACK(expose_cb), NULL);
182          g_list_free(children);
183          gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
184          gtk_widget_show(dialog);
185        }
186    }
187
188  if (GPOINTER_TO_UINT(reset))
189    {
190      /* Set our next callback for the predicted time until the next state
191       * change, or MAX_TIMEOUT, whichever is smaller.
192       */
193      if (state == 0)
194        timeout = MAX_TIMEOUT;
195      else
196        timeout = duration - warnings[state - 1].tte;
197      timeout = MIN(timeout, MAX_TIMEOUT);
198      gtk_timeout_add(timeout * 1000, timeout_cb, GUINT_TO_POINTER(TRUE));
199    }
200
201  return FALSE;   /* Remove the callback which called us. */
202}
203
204
205main(int argc, char **argv)
206{
207  krb5_error_code status;
208
209  gtk_init(&argc, &argv);
210
211  status = krb5_init_context(&k5_context);
212  if (status != 0)
213    {
214      fprintf(stderr, "authwatch: could not initialize Kerberos v5 library: %s\n",
215              error_message(status));
216      exit(1);
217    }
218
219  gtk_timeout_add(0, timeout_cb, GUINT_TO_POINTER(TRUE));
220  gtk_main();
221
222  exit(0);
223}
Note: See TracBrowser for help on using the repository browser.