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

Revision 23033, 6.1 KB checked in by ghudson, 16 years ago (diff)
In authwatch: * Refer to the correct grenew menu item for Athena 10.
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 Applications -> System Tools -> "
117"Renew Authentication to re-authenticate."
118    },
119
120    { 60,
121"Your authentication will expire in less than one minute.  Select "
122"Applications -> System Tools -> Renew Authentication to re-authenticate."
123    },
124
125    { 60*5,
126"Your authentication will expire in less than five minutes.  Select "
127"Applications -> System Tools -> Renew Authentication to re-authenticate."
128    },
129
130    { 60*15,
131"Your authentication will expire in less than fifteen minutes.  Select "
132"Applications -> System Tools -> Renew Authentication 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.