source: trunk/athena/bin/grenew/grenew.c @ 24042

Revision 24042, 8.8 KB checked in by broder, 15 years ago (diff)
In grenew: * Support building on systems where krb5 no longer comes with krb4. (Trac: #380)
Line 
1/* Renew a credentials cache using a graphical interface. Much of the source
2 * is modified from that of kinit.
3 *
4 * $Id: grenew.c,v 1.6 2004-05-27 18:38:46 ghudson Exp $
5 */
6
7#include <gtk/gtk.h>
8#include <krb5.h>
9#ifdef HAVE_KRB4
10#include <kerberosIV/krb.h>
11#endif
12#include <string.h>
13#include <stdio.h>
14#include <com_err.h>
15
16char *progname = NULL;
17const char *name = NULL;
18
19static void quit();
20static void do_error_dialog(char *msg);
21static void do_fatal_dialog(char *msg);
22static void do_renew(GtkWidget *widget, GtkWidget *entry);
23static void dialog_response_cb(GtkWidget *w, gint response, GtkWidget *entry);
24static void create_window();
25int try_krb4(krb5_context kcontext, krb5_principal me, char *password,
26             krb5_deltat lifetime);
27int try_convert524(krb5_context kcontext, krb5_ccache ccache);
28
29/* library functions not declared inside the included headers. */
30#ifdef HAVE_KRB4
31void krb524_init_ets(krb5_context kcontext);
32int krb524_convert_creds_kdc(krb5_context kcontext,
33                             krb5_creds * k5creds,
34                             CREDENTIALS * k4creds);
35#endif HAVE_KRB4
36
37static void quit()
38{
39  exit(0);
40}
41
42static void do_error_dialog(char *msg)
43{
44  static GtkWidget *window = NULL;
45
46  if (window)
47    gtk_widget_destroy(window);
48  window = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_WARNING,
49                                  GTK_BUTTONS_OK, msg);
50  g_signal_connect(G_OBJECT(window), "response",
51                   G_CALLBACK(gtk_widget_destroy), NULL);
52  g_signal_connect(G_OBJECT(window), "destroy",
53                   G_CALLBACK(gtk_widget_destroyed), &window);
54  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
55  gtk_widget_show(window);
56}
57
58static void do_fatal_dialog(char *msg)
59{
60  GtkWidget *window;
61
62  msg = g_strdup_printf("Fatal Error:\n\n%s", msg);
63  window = gtk_message_dialog_new(NULL,
64                                  GTK_DIALOG_MODAL,
65                                  GTK_MESSAGE_ERROR,
66                                  GTK_BUTTONS_OK, msg);
67  g_signal_connect(G_OBJECT(window), "response",
68                   G_CALLBACK(quit), NULL);
69  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
70  gtk_widget_show(window);
71}
72
73static void do_renew(GtkWidget *widget, GtkWidget *entry)
74{
75  char *pass;
76  krb5_error_code code;
77  krb5_context kcontext;
78  krb5_principal me = NULL;
79  char *service_name = NULL;
80  krb5_ccache ccache = NULL;
81  krb5_creds my_creds;
82  char *msg = NULL;
83  krb5_deltat start_time = 0;
84  krb5_deltat lifetime = 10 * 60 * 60;
85  krb5_get_init_creds_opt opts;
86  int non_fatal = 0;
87
88  pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
89  gtk_entry_set_text(GTK_ENTRY(entry), "");
90
91  krb5_get_init_creds_opt_init(&opts);
92
93  if (!pass || !strlen(pass))
94    {
95      non_fatal = 1;
96      msg = g_strdup("Incorrect password: please try again.");
97    }
98  else if ((code = krb5_init_context(&kcontext)))
99    msg = g_strdup_printf("%s when initializing kerberos library",
100                          error_message(code));
101  else if ((code = krb5_cc_default(kcontext, &ccache)))
102    msg = g_strdup_printf("%s while getting default cache.",
103                          error_message(code));
104  else if ((code = krb5_parse_name(kcontext, name, &me)))
105    msg = g_strdup_printf("%s while parsing name %s.", error_message(code),
106                          name);
107  else if ((code = krb5_get_init_creds_password(kcontext,
108                                                &my_creds, me, pass,
109                                                krb5_prompter_posix, NULL,
110                                                start_time, service_name,
111                                                &opts)))
112    {
113      if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
114        {
115          non_fatal = 1;
116          msg = g_strdup("Incorrect password: please try again.");
117        }
118      else
119        {
120          msg = g_strdup_printf("%s while getting initial"
121                                " credentials", error_message(code));
122        }
123    }
124  else
125    {
126      int got_krb4 = try_krb4(kcontext, me, pass, lifetime);
127      if ((code = krb5_cc_initialize(kcontext, ccache, me)))
128        {
129          msg = g_strdup_printf("%s while initializing cache",
130                                error_message(code));
131        }
132      else if ((code = krb5_cc_store_cred(kcontext, ccache,
133                                          &my_creds)))
134        {
135          msg = g_strdup_printf("%s while storing credentials",
136                                error_message(code));
137        }
138      else
139        {
140          if (!got_krb4)
141            try_convert524(kcontext, ccache);
142          if (me)
143            krb5_free_principal(kcontext, me);
144          if (ccache)
145            krb5_cc_close(kcontext, ccache);
146
147          krb5_free_context(kcontext);
148        }
149    }
150
151  g_free(pass);
152
153  if (msg)
154    {
155      /* encountered an error. don't quit */
156      if (non_fatal)
157        do_error_dialog(msg);
158      else
159        do_fatal_dialog(msg);
160      g_free(msg);
161    }
162  else
163    /* no errors, we're done */
164    {
165      system("fsid -a > /dev/null");
166      system("zctl load /dev/null > /dev/null");
167      exit(0);
168    }
169}
170
171static void dialog_response_cb(GtkWidget *w, gint response, GtkWidget *entry)
172{
173  gtk_widget_grab_focus(GTK_WIDGET(entry));
174
175  if (response == GTK_RESPONSE_OK)
176    do_renew(w, entry);
177  else
178    quit();
179}
180
181static void create_window()
182{
183  GtkWidget *window;
184  GtkWidget *label;
185  GtkWidget *entry;
186  GtkWidget *button;
187
188  window = gtk_dialog_new_with_buttons("Renewing authentication",
189                                       NULL, 0,
190                                       GTK_STOCK_OK,
191                                       GTK_RESPONSE_OK,
192                                       GTK_STOCK_CANCEL,
193                                       GTK_RESPONSE_CANCEL,
194                                       NULL);
195
196  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
197
198  label = gtk_label_new("Type your password now to renew your authentication "
199                        "to the system, which expires every 10 hours.");
200  gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
201  gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
202  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), label, TRUE, TRUE, 0);
203  gtk_widget_show(label);
204
205  entry = gtk_entry_new();
206  gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
207  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), entry, TRUE, TRUE, 0);
208  gtk_widget_grab_focus(entry);
209  gtk_widget_show(entry);
210
211  g_signal_connect_object(G_OBJECT(entry), "activate",
212                          G_CALLBACK(do_renew), entry, 0);
213  g_signal_connect_object(G_OBJECT(window), "response",
214                          G_CALLBACK(dialog_response_cb), entry, 0);
215  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL);
216
217  gtk_widget_show(window);
218}
219
220/* This function is from kinit. */
221int try_krb4(kcontext, me, password, lifetime)
222        krb5_context kcontext;
223        krb5_principal me;
224        char *password;
225        krb5_deltat lifetime;
226{
227#ifdef HAVE_KRB4
228        krb5_error_code code;
229        int krbval;
230        char v4name[ANAME_SZ], v4inst[INST_SZ], v4realm[REALM_SZ];
231        int v4life;
232
233        /* Translate to a Kerberos 4 principal. */
234        code = krb5_524_conv_principal(kcontext, me, v4name, v4inst, v4realm);
235        if (code)
236                return(code);
237
238        v4life = lifetime / (5 * 60);
239        if (v4life < 1)
240                v4life = 1;
241        if (v4life > 255)
242                v4life = 255;
243
244        krbval = krb_get_pw_in_tkt(v4name, v4inst, v4realm, "krbtgt", v4realm,
245                                           v4life, password);
246
247        if (krbval != INTK_OK) {
248                fprintf(stderr, "Kerberos 4 error: %s\n",
249                        krb_get_err_text(krbval));
250                return 0;
251        }
252        return 1;
253#else
254        return 0;
255#endif
256}
257
258/* Convert krb5 tickets to krb4. This function was copied from kinit */
259int try_convert524(kcontext, ccache)
260         krb5_context kcontext;
261         krb5_ccache ccache;
262{
263#ifdef HAVE_KRB4
264        krb5_principal me, kpcserver;
265        krb5_error_code kpccode;
266        int kpcval;
267        krb5_creds increds, *v5creds;
268        CREDENTIALS v4creds;
269
270        /* or do this directly with krb524_convert_creds_kdc */
271        krb524_init_ets(kcontext);
272
273        if ((kpccode = krb5_cc_get_principal(kcontext, ccache, &me))) {
274                com_err(progname, kpccode, "while getting principal name");
275                return 0;
276        }
277
278        /* cc->ccache, already set up */
279        /* client->me, already set up */
280        if ((kpccode = krb5_build_principal(kcontext,
281                                                    &kpcserver,
282                                                    krb5_princ_realm(kcontext, me)->length,
283                                                    krb5_princ_realm(kcontext, me)->data,
284                                                    "krbtgt",
285                                                    krb5_princ_realm(kcontext, me)->data,
286                                                NULL))) {
287          com_err(progname, kpccode,
288                          "while creating service principal name");
289          return 0;
290        }
291
292        memset((char *) &increds, 0, sizeof(increds));
293        increds.client = me;
294        increds.server = kpcserver;
295        increds.times.endtime = 0;
296        increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
297        if ((kpccode = krb5_get_credentials(kcontext, 0,
298                                                ccache,
299                                                &increds,
300                                                &v5creds))) {
301                com_err(progname, kpccode,
302                        "getting V5 credentials");
303                return 0;
304        }
305        if ((kpccode = krb524_convert_creds_kdc(kcontext,
306                                                        v5creds,
307                                                        &v4creds))) {
308                com_err(progname, kpccode,
309                        "converting to V4 credentials");
310                return 0;
311        }
312        /* this is stolen from the v4 kinit */
313        /* initialize ticket cache */
314        if ((kpcval = in_tkt(v4creds.pname,v4creds.pinst)
315                 != KSUCCESS)) {
316                com_err(progname, kpcval,
317                        "trying to create the V4 ticket file");
318                return 0;
319        }
320        /* stash ticket, session key, etc. for future use */
321        if ((kpcval = krb_save_credentials(v4creds.service,
322                                                   v4creds.instance,
323                                                   v4creds.realm,
324                                                   v4creds.session,
325                                                   v4creds.lifetime,
326                                                   v4creds.kvno,
327                                                   &(v4creds.ticket_st),
328                                                   v4creds.issue_date))) {
329                com_err(progname, kpcval,
330                        "trying to save the V4 ticket");
331                return 0;
332        }
333        return 1;
334#else
335        return 0;
336#endif
337}
338
339int main(int argc, char **argv)
340{
341  gtk_init(&argc, &argv);
342
343  progname = g_get_prgname();
344  if (argc > 1)
345    name = argv[1];
346  else
347    name = g_get_user_name();
348  create_window();
349  gtk_main();
350  return 0;
351}
Note: See TracBrowser for help on using the repository browser.