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

Revision 22165, 6.1 KB checked in by rbasch, 19 years ago (diff)
Set the expose callback for the container, instead of for its first child, as the callback is no longer invoked for the latter.
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.7 2005-08-01 15:56:13 rbasch 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
108  static GtkWidget *dialog = NULL;
109  static int state = -1;
110
111  static const struct {
112    const unsigned int tte;     /* Time to expiration, in seconds */
113    const char *message;        /* Formatted for a gtk_message_dialog */
114  } warnings[] = {
115    { 0,
116"You have no authentication.  Select ``Renew Authentication'' from the "
117"Athena ``Utilities'' menu to re-authenticate."
118    },
119
120    { 60,
121"Your authentication will expire in less than one minute.  Select "
122"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
123    },
124
125    { 60*5,
126"Your authentication will expire in less than five minutes.  Select "
127"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
128    },
129
130    { 60*15,
131"Your authentication will expire in less than fifteen minutes.  Select "
132"``Renew Authentication'' from the Athena ``Utilities'' menu to re-authenticate."
133    }
134  };
135  static const int nwarnings = sizeof(warnings) / sizeof(*warnings);
136
137  expiration = get_krb5_expiration();
138
139  time(&now);
140  if (expiration > now)
141    duration = expiration - now;
142
143  nstate = nwarnings;
144  do
145    {
146      if (duration > warnings[nstate - 1].tte)
147        break;
148      nstate--;
149    }
150  while (nstate > 0);
151
152  if (nstate != state)
153    {
154      state = nstate;
155
156      if (dialog != NULL)
157        gtk_widget_destroy(dialog);
158
159      if (state < nwarnings)
160        {
161          dialog = g_object_new(GTK_TYPE_MESSAGE_DIALOG,
162                                "message_type", GTK_MESSAGE_WARNING,
163                                "buttons", GTK_BUTTONS_OK,
164                                "type", GTK_WINDOW_POPUP, NULL);
165          if (dialog == NULL)
166            {
167              fprintf(stderr, "authwatch: error creating dialog window\n");
168              exit(1);
169            }
170          gtk_label_set_text(GTK_LABEL(GTK_MESSAGE_DIALOG(dialog)->label),
171                             warnings[state].message);
172          g_signal_connect(G_OBJECT(dialog), "response",
173                           G_CALLBACK(gtk_widget_destroy), NULL);
174          g_signal_connect(G_OBJECT(dialog), "destroy",
175                           G_CALLBACK(gtk_widget_destroyed), &dialog);
176          g_signal_connect(G_OBJECT(GTK_DIALOG(dialog)->vbox),
177                           "expose_event", G_CALLBACK(expose_cb), NULL);
178          gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
179          gtk_widget_show(dialog);
180        }
181    }
182
183  if (GPOINTER_TO_UINT(reset))
184    {
185      /* Set our next callback for the predicted time until the next state
186       * change, or MAX_TIMEOUT, whichever is smaller.
187       */
188      if (state == 0)
189        timeout = MAX_TIMEOUT;
190      else
191        timeout = duration - warnings[state - 1].tte;
192      timeout = MIN(timeout, MAX_TIMEOUT);
193      gtk_timeout_add(timeout * 1000, timeout_cb, GUINT_TO_POINTER(TRUE));
194    }
195
196  return FALSE;   /* Remove the callback which called us. */
197}
198
199
200main(int argc, char **argv)
201{
202  krb5_error_code status;
203
204  gtk_init(&argc, &argv);
205
206  status = krb5_init_context(&k5_context);
207  if (status != 0)
208    {
209      fprintf(stderr, "authwatch: could not initialize Kerberos v5 library: %s\n",
210              error_message(status));
211      exit(1);
212    }
213
214  gtk_timeout_add(0, timeout_cb, GUINT_TO_POINTER(TRUE));
215  gtk_main();
216
217  exit(0);
218}
Note: See TracBrowser for help on using the repository browser.