Better support for "non-standard" GSS mechs
[metze/heimdal/wip.git] / kuser / kcpytkt.c
1
2 #include "kuser_locl.h"
3
4 static char *etypestr = 0;
5 static char *fromccachestr = 0;
6 static char *flagstr = 0;
7 static int  exp_ok = 0;
8 static int  quiet_flag = 0;
9 static int  version_flag = 0;
10 static int  help_flag = 0;
11
12 struct getargs args[] = {
13     { "cache",  'c', arg_string, &fromccachestr,
14       "Credentials cache", "cachename" },
15     { "enctype", 'e', arg_string, &etypestr,
16       "Encryption type", "enctype" },
17     { "flags", 'f', arg_string, &flagstr,
18       "Flags", "flags" },
19     { "expired-ok", 'E', arg_flag, &exp_ok,
20         "Keep expired tickets" },
21     { "quiet", 'q', arg_flag, &quiet_flag, "Quiet" },
22     { "version",        0, arg_flag, &version_flag },
23     { "help",           0, arg_flag, &help_flag }
24 };
25
26 static void
27 usage(int ret)
28 {
29     arg_printusage(args, sizeof(args)/sizeof(args[0]),
30                    "Usage: ", "dest_ccache service1 [service2 ...]");
31     exit (ret);
32 }
33
34 static void do_kcpytkt (int argc, char *argv[], char *fromccachestr, char *etypestr, int flags);
35
36 int main(int argc, char *argv[])
37 {
38     int optidx;
39     int flags = 0;
40
41     setprogname(argv[0]);
42
43     if (getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx))
44         usage(1);
45
46     if (help_flag)
47         usage(0);
48
49     if (version_flag) {
50         print_version(NULL);
51         exit(0);
52     }
53
54     argc -= optidx;
55     argv += optidx;
56
57     if (argc < 2)
58         usage(1);
59
60     if (flagstr)
61         flags = atoi(flagstr);
62
63     do_kcpytkt(argc, argv, fromccachestr, etypestr, flags);
64
65     return 0;
66 }
67
68 static void do_kcpytkt (int count, char *names[],
69                         char *fromccachestr, char *etypestr, int flags)
70 {
71     krb5_context context;
72     krb5_error_code ret;
73     int i, errors;
74     krb5_enctype etype;
75     krb5_ccache fromccache;
76     krb5_ccache destccache;
77     krb5_principal me;
78     krb5_creds in_creds, out_creds;
79     int retflags;
80     char *princ;
81
82     ret = krb5_init_context(&context);
83     if (ret)
84         errx(1, "krb5_init_context failed: %d", ret);
85
86     if (etypestr) {
87         ret = krb5_string_to_enctype(context, etypestr, &etype);
88         if (ret)
89             krb5_err(context, 1, ret, "Can't convert enctype %s", etypestr);
90         retflags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_MATCH_KEYTYPE;
91     } else {
92         etype = 0;
93         retflags = KRB5_TC_MATCH_SRV_NAMEONLY;
94     }
95
96     if (fromccachestr)
97         ret = krb5_cc_resolve(context, fromccachestr, &fromccache);
98     else
99         ret = krb5_cc_default(context, &fromccache);
100     if (ret)
101         krb5_err(context, 1, ret, "Can't resolve credentials cache");
102
103     ret = krb5_cc_get_principal(context, fromccache, &me);
104     if (ret)
105         krb5_err(context, 1, ret, "Can't query client principal name");
106
107     ret = krb5_cc_resolve(context, names[0], &destccache);
108     if (ret)
109         krb5_err(context, 1, ret, "Can't resolve destination cache");
110
111     errors = 0;
112
113     for (i = 1; i < count; i++) {
114         memset(&in_creds, 0, sizeof(in_creds));
115
116         in_creds.client = me;
117
118         ret = krb5_parse_name(context, names[i], &in_creds.server);
119         if (ret) {
120             if (!quiet_flag)
121                 krb5_warn(context, ret, "Parse error for %s", names[i]);
122             errors++;
123             continue;
124         }
125
126         ret = krb5_unparse_name(context, in_creds.server, &princ);
127         if (ret) {
128             krb5_warn(context, ret, "Unparse error for %s", names[i]);
129             errors++;
130             continue;
131         }
132
133         in_creds.session.keytype = etype;
134
135         if (!exp_ok) {
136             krb5_timeofday(context, &in_creds.times.endtime);
137             retflags |= KRB5_TC_MATCH_TIMES;
138         }
139
140         ret = krb5_cc_retrieve_cred(context, fromccache, retflags,
141                                     &in_creds, &out_creds);
142         if (ret) {
143             krb5_warn(context, ret, "Can't retrieve credentials for %s", princ);
144
145             krb5_free_unparsed_name(context, princ);
146
147             errors++;
148             continue;
149         }
150
151         ret = krb5_cc_store_cred(context, destccache, &out_creds);
152
153         krb5_free_principal(context, in_creds.server);
154
155         if (ret) {
156             krb5_warn(context, ret, "Can't store credentials for %s", princ);
157
158             krb5_free_cred_contents(context, &out_creds);
159             krb5_free_unparsed_name(context, princ);
160
161             errors++;
162             continue;
163         }
164
165         krb5_free_unparsed_name(context, princ);
166         krb5_free_cred_contents(context, &out_creds);
167     }
168
169     krb5_free_principal(context, me);
170     krb5_cc_close(context, fromccache);
171     krb5_cc_close(context, destccache);
172     krb5_free_context(context);
173
174     if (errors)
175         exit(1);
176
177     exit(0);
178 }