Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / appl / kauth / kauth.c
1 /*
2  * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * Little program that reads an srvtab or password and
36  * creates a suitable ticketfile and associated AFS tokens.
37  *
38  * If an optional command is given the command is executed in a
39  * new PAG and when the command exits the tickets are destroyed.
40  */
41
42 #include "kauth.h"
43
44 RCSID("$Id: kauth.c,v 1.97.2.1 2000/02/28 03:42:51 assar Exp $");
45
46 krb_principal princ;
47 static char srvtab[MaxPathLen];
48 static int lifetime = DEFAULT_TKT_LIFE;
49 static char remote_tktfile[MaxPathLen];
50 static char remoteuser[100];
51 static char *cell = 0;
52
53 static void
54 usage(void)
55 {
56     fprintf(stderr,
57             "Usage:\n"
58             "  %s [name]\n"
59             "or\n"
60             "  %s [-ad] [-n name] [-r remoteuser] [-t remote ticketfile]\n"
61             "        [-l lifetime (in minutes) ] [-f srvtab ] [-c AFS cell name ]\n"
62             "        [-h hosts... [--]] [command ... ]\n\n",
63             __progname, __progname);
64     fprintf(stderr, 
65             "A fully qualified name can be given: user[.instance][@realm]\n"
66             "Realm is converted to uppercase!\n");
67     exit(1);
68 }
69
70 #define EX_NOEXEC       126
71 #define EX_NOTFOUND     127
72
73 static int
74 doexec(int argc, char **argv)
75 {
76     int ret = simple_execvp(argv[0], argv);
77     if(ret == -2)
78         warn ("fork");
79     if(ret == -3)
80         warn("waitpid");
81     if(ret < 0)
82         return EX_NOEXEC;
83     if(ret == EX_NOEXEC || ret == EX_NOTFOUND)
84         warnx("Can't exec program ``%s''", argv[0]);
85         
86     return ret;
87 }
88
89 static RETSIGTYPE
90 renew(int sig)
91 {
92     int code;
93
94     signal(SIGALRM, renew);
95
96     code = krb_get_svc_in_tkt(princ.name, princ.instance, princ.realm,
97                               KRB_TICKET_GRANTING_TICKET,
98                               princ.realm, lifetime, srvtab);
99     if (code)
100         warnx ("%s", krb_get_err_text(code));
101     else if (k_hasafs())
102         {
103             if ((code = krb_afslog(cell, NULL)) != 0 && code != KDC_PR_UNKNOWN) {
104                 warnx ("%s", krb_get_err_text(code));
105             }
106         }
107
108     alarm(krb_life_to_time(0, lifetime)/2 - 60);
109     SIGRETURN(0);
110 }
111
112 static int
113 zrefresh(void)
114 {
115     switch (fork()) {
116     case -1:
117         err (1, "Warning: Failed to fork zrefresh");
118         return -1;
119     case 0:
120         /* Child */
121         execlp("zrefresh", "zrefresh", 0);
122         execl(BINDIR "/zrefresh", "zrefresh", 0);
123         exit(1);
124     default:
125         /* Parent */
126         break;
127     }
128     return 0;
129 }
130
131 static int
132 key_to_key(const char *user,
133            char *instance,
134            const char *realm,
135            const void *arg,
136            des_cblock *key)
137 {
138     memcpy(key, arg, sizeof(des_cblock));
139     return 0;
140 }
141
142 static int
143 get_ticket_address(krb_principal *princ, des_cblock *key)
144 {
145     int code;
146     unsigned char flags;
147     krb_principal service;
148     u_int32_t addr;
149     struct in_addr addr2;
150     des_cblock session;
151     int life;
152     u_int32_t time_sec;
153     des_key_schedule schedule;
154     CREDENTIALS c;
155         
156     code = get_ad_tkt(princ->name, princ->instance, princ->realm, 0);
157     if(code) {
158         warnx("get_ad_tkt: %s\n", krb_get_err_text(code));
159         return code;
160     }
161     code = krb_get_cred(princ->name, princ->instance, princ->realm, &c);
162     if(code) {
163         warnx("krb_get_cred: %s\n", krb_get_err_text(code));
164         return code;
165     }
166
167     des_set_key(key, schedule);
168     code = decomp_ticket(&c.ticket_st, 
169                          &flags,
170                          princ->name,
171                          princ->instance,
172                          princ->realm,
173                          &addr,
174                          session,
175                          &life,
176                          &time_sec,
177                          service.name,
178                          service.instance,
179                          key,
180                          schedule);
181     if(code) {
182         warnx("decomp_ticket: %s\n", krb_get_err_text(code));
183         return code;
184     }
185     memset(&session, 0, sizeof(session));
186     memset(schedule, 0, sizeof(schedule));
187     addr2.s_addr = addr;
188     fprintf(stdout, "ticket address = %s\n", inet_ntoa(addr2));
189
190
191
192 int
193 main(int argc, char **argv)
194 {
195     int code, more_args;
196     int ret;
197     int c;
198     char *file;
199     int pflag = 0;
200     int aflag = 0;
201     int version_flag = 0;
202     char passwd[100];
203     des_cblock key;
204     char **host;
205     int nhost;
206     char tf[MaxPathLen];
207
208     set_progname (argv[0]);
209
210     if ((file =  getenv("KRBTKFILE")) == 0)
211         file = TKT_FILE;  
212
213     memset(&princ, 0, sizeof(princ));
214     memset(srvtab, 0, sizeof(srvtab));
215     *remoteuser = '\0';
216     nhost = 0;
217     host = NULL;
218   
219     /* Look for kerberos name */
220     if (argc > 1 &&
221         argv[1][0] != '-' &&
222         krb_parse_name(argv[1], &princ) == 0)
223       {
224         argc--; argv++;
225         strupr(princ.realm);
226       }
227
228     while ((c = getopt(argc, argv, "ar:t:f:hdl:n:c:v")) != -1)
229         switch (c) {
230         case 'a':
231             aflag++;
232             break;
233         case 'd':
234             krb_enable_debug();
235             _kafs_debug = 1;
236             break;
237         case 'f':
238             strlcpy(srvtab, optarg, sizeof(srvtab));
239             break;
240         case 't':
241             strlcpy(remote_tktfile, optarg, sizeof(remote_tktfile));
242             break;
243         case 'r':
244             strlcpy(remoteuser, optarg, sizeof(remoteuser));
245             break;
246         case 'l':
247             lifetime = atoi(optarg);
248             if (lifetime == -1)
249                 lifetime = 255;
250             else if (lifetime < 5)
251                 lifetime = 1;
252             else
253                 lifetime = krb_time_to_life(0, lifetime*60);
254             if (lifetime > 255)
255                 lifetime = 255;
256             break;
257         case 'n':
258             if ((code = krb_parse_name(optarg, &princ)) != 0) {
259                 warnx ("%s", krb_get_err_text(code));
260                 usage();
261             }
262             strupr(princ.realm);
263             pflag = 1;
264             break;
265         case 'c':
266             cell = optarg;
267             break;
268         case 'h':
269             host = argv + optind;
270             for(nhost = 0; optind < argc && *argv[optind] != '-'; ++optind)
271                 ++nhost;
272             if(nhost == 0)
273                 usage();
274             break;
275         case 'v':
276             version_flag++;
277             print_version(NULL);
278             break;
279         case '?':
280         default:
281             usage();
282             break;
283         }
284   
285     if(version_flag) {
286         print_version(NULL);
287         exit(0);
288     }
289     if (princ.name[0] == '\0' && krb_get_default_principal (princ.name, 
290                                                             princ.instance, 
291                                                             princ.realm) < 0)
292         errx (1, "Could not get default principal");
293   
294     /* With root tickets assume remote user is root */
295     if (*remoteuser == '\0') {
296       if (strcmp(princ.instance, "root") == 0)
297         strlcpy(remoteuser, princ.instance, sizeof(remoteuser));
298       else
299         strlcpy(remoteuser, princ.name, sizeof(remoteuser));
300     }
301
302     more_args = argc - optind;
303   
304     if (princ.realm[0] == '\0')
305         if (krb_get_lrealm(princ.realm, 1) != KSUCCESS)
306             strlcpy(princ.realm, KRB_REALM, REALM_SZ);
307   
308     if (more_args) {
309         int f;
310       
311         do{
312             snprintf(tf, sizeof(tf), "%s%u_%u", TKT_ROOT, (unsigned)getuid(),
313                      (unsigned)(getpid()*time(0)));
314             f = open(tf, O_CREAT|O_EXCL|O_RDWR);
315         }while(f < 0);
316         close(f);
317         unlink(tf);
318         setenv("KRBTKFILE", tf, 1);
319         krb_set_tkt_string (tf);
320     }
321     
322     if (srvtab[0])
323         {
324             signal(SIGALRM, renew);
325
326             code = read_service_key (princ.name, princ.instance, princ.realm, 0, 
327                                      srvtab, (char *)&key);
328             if (code == KSUCCESS)
329                 code = krb_get_in_tkt(princ.name, princ.instance, princ.realm,
330                                       KRB_TICKET_GRANTING_TICKET,
331                                       princ.realm, lifetime,
332                                       key_to_key, NULL, key);
333             alarm(krb_life_to_time(0, lifetime)/2 - 60);
334         }
335     else {
336         char prompt[128];
337           
338         snprintf(prompt, sizeof(prompt), "%s's Password: ", krb_unparse_name(&princ));
339         if (des_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){
340             memset(passwd, 0, sizeof(passwd));
341             exit(1);
342         }
343         code = krb_get_pw_in_tkt2(princ.name, princ.instance, princ.realm, 
344                                   KRB_TICKET_GRANTING_TICKET, princ.realm, 
345                                   lifetime, passwd, &key);
346         
347         memset(passwd, 0, sizeof(passwd));
348     }
349     if (code) {
350         memset (key, 0, sizeof(key));
351         errx (1, "%s", krb_get_err_text(code));
352     }
353
354     if(aflag)
355         get_ticket_address(&princ, &key);
356
357     if (k_hasafs()) {
358         if (more_args)
359             k_setpag();
360         if ((code = krb_afslog(cell, NULL)) != 0 && code != KDC_PR_UNKNOWN) {
361             if(code > 0)
362                 warnx ("%s", krb_get_err_text(code));
363             else
364                 warnx ("failed to store AFS token");
365         }
366     }
367
368     for(ret = 0; nhost-- > 0; host++)
369         ret += rkinit(&princ, lifetime, remoteuser, remote_tktfile, &key, *host);
370   
371     if (ret)
372         return ret;
373
374     if (more_args) {
375         ret = doexec(more_args, &argv[optind]);
376         dest_tkt();
377         if (k_hasafs())
378             k_unlog();   
379     }
380     else
381         zrefresh();
382   
383     return ret;
384 }