]> eyrie.org Git - kerberos/kftgt.git/blob - kftgt.c
Fix POD syntax errors in kftgt man page
[kerberos/kftgt.git] / kftgt.c
1 /*  $Id: kftgt.c 2303 2005-12-22 00:58:47Z rra $
2 **
3 **  Client program for Kerberos v4 ticket forwarding.
4 */
5
6 /*
7  * INCLUDES
8  */
9
10 #include "config.h"
11
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <netdb.h>
20 #include <errno.h>
21 #include <memory.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <signal.h>
25 #include <stdarg.h>
26
27 #ifdef HAVE_KERBEROSIV_KRB_H
28 # include <kerberosIV/krb.h>
29 #else
30 # include <krb.h>
31 #endif
32
33 #include "kftgt.h"
34 #include "encrypt.h"
35 #include "marsh.h"
36
37 /** Exit values for various errors. */
38 enum kftgt_error {
39     SUCCESS             = 0,
40     ERROR_NOHOST        = 1,
41     ERROR_TIMEOUT       = 2,
42     ERROR_CONNECT       = 3,
43     ERROR_KERBEROS      = 4,
44     ERROR_SEND          = 5,
45     ERROR_SYSTEM        = 6
46 };
47
48 /*
49  * PROTOTYPES
50  */
51 char **read_options(int argc, char **argv);
52 enum kftgt_error kftgt(char *user, char *server);
53 char *parse_username(char *server,char **ruser);
54 int read_null_term(int s, char *buffer, int max);
55 void warn (char *fmt, ...);
56 int print_version(void);
57 int usage(int exitcode);
58
59 /*
60  * GLOBALS
61  */
62 static char *prog = "kftgt";
63 static int debug=0;
64 static int quiet=0;
65 static char *l_val="";
66 static char *f_val = "";
67 static int t_val=60;  /* default timeout */
68
69 /*
70  * FUNCTIONS
71  */
72
73 RETSIGTYPE 
74 timeout(int signo)
75 {
76   warn("timeout");
77   /* FIXME */
78   exit(ERROR_TIMEOUT);
79 }
80
81 int
82 main(int argc, char **argv)
83 {
84   enum kftgt_error status = SUCCESS;
85
86 #ifdef HAVE_DECL_KRB_IGNORE_IP_ADDRESS
87   krb_ignore_ip_address = 1;
88 #endif
89
90   argv = read_options(argc, argv);
91   while(*argv) {
92     char *ruser = l_val, *server;
93     server = parse_username(*argv,&ruser);
94     status = kftgt(ruser, server);
95     argv++;
96   }
97   exit(status);
98 }
99
100 char *
101 parse_username(char *server,char **ruser)
102 {
103   char *retval = server;
104   char *cp;
105
106   if ((cp = strchr(server,'@')) != NULL) {
107     retval = cp+1;
108     *cp = '\0';
109     *ruser = server;
110   } else {
111     *ruser = l_val;
112   }
113   return retval;
114 }
115
116 char **
117 read_options(int argc, char **argv)
118 {
119   int c;
120   extern int opterr;
121   opterr = 0;
122
123   prog = argv[0];
124
125   /* A quick hack to honor --help and --version */
126   if (argv[1])
127     if (argv[1][0] == '-' && argv[1][1] == '-' && argv[1][2] != '\0') {
128       switch(argv[1][2]) {
129       case 'h':
130         usage(0);
131         break;
132       case 'v':
133         print_version();
134         break;
135       default:
136         usage(1);
137         break;
138       }
139     }
140  
141   while ((c = getopt(argc, argv, "hl:f:vqdt:")) != EOF) {
142     switch (c) {
143     case 'd': /* Debug */
144       debug=1;
145       break;
146     case 'f': /* Ticket File */
147       f_val=optarg;
148       break;
149     case 'h': /* Help */
150       usage(0);
151       break;
152     case 'l': /* User name */
153       l_val=optarg;
154       break;
155     case 'q': /* Quiet */
156       quiet=1;
157       break;
158     case 't': /* Timeout */
159       t_val=atoi(optarg);
160       break;
161     case 'v':
162       print_version();
163       break;
164     default:
165       usage(1);
166       break;
167     }
168   }
169
170   if (t_val <= 0 || optind >= argc) {
171     usage(1);
172   }
173
174   return argv+optind;
175 }
176
177 enum kftgt_error
178 kftgt(char *ruser, char *server)
179 {
180   struct hostent *hp;
181   struct sockaddr_in saddr, caddr;
182   struct servent *se;
183   unsigned int addr;
184   size_t clen;
185   char *remote_host;
186   int status;
187   int sock, len;
188   KTEXT_ST ticket;
189
190   MSG_DAT msg_data;
191   CREDENTIALS cred;
192   CREDENTIALS tgtcred;
193   Key_schedule sched;
194   char buffer[KFTGT_MAX_BUFFER];
195   MSG_DAT m_data;
196
197   /* set alarm for timeout */
198   /* FIXME */
199   signal(SIGALRM, timeout);
200   alarm(t_val);
201
202   /*** Connect ***/
203
204   /* Assign port */
205   memset ((char *) &saddr, 0, sizeof (struct sockaddr_in));
206   if ((se = getservbyname ("kftgt", "tcp")) != NULL ||
207       (se = getservbyport(htons(SERVICE_PORT),"tcp")) != NULL) {
208     saddr.sin_port = se->s_port;
209   } else {
210     saddr.sin_port = htons(SERVICE_PORT);
211   }
212   endservent();
213
214   /* First check if valid IP address.  Otherwise check if valid name. */
215   if ((addr = inet_addr(server)) != -1) {
216     if ((hp = gethostbyaddr ((char *)&addr, sizeof(unsigned int),
217                              AF_INET)) == NULL) {
218       if (!quiet) {
219         fprintf(stderr,"%s: unknown host",server);
220       }
221       return ERROR_NOHOST;
222     }
223   } else if ((hp = gethostbyname (server)) == NULL) {
224     if (!quiet) {
225       fprintf(stderr,"%s: unknown host",server);
226     }
227     return ERROR_NOHOST;
228   }
229
230   /* Set up socket connection */
231   saddr.sin_family = AF_INET;
232   memcpy (&saddr.sin_addr, hp->h_addr, sizeof(hp->h_addr));
233
234   if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
235       if (!quiet) {
236         perror("socket");
237       }
238     return ERROR_SYSTEM;
239   }
240
241   if (connect (sock, (struct sockaddr *) &saddr,
242                sizeof(struct sockaddr_in)) < 0 ) {
243     if (!quiet) {
244       perror("connect");
245     }
246     (void)close(sock); /* Back out */
247     return ERROR_CONNECT;
248   }
249
250   /* copy the hostname into non-volatile storage */
251   remote_host = (char*)malloc(strlen(hp->h_name) + 1);
252   strcpy(remote_host, hp->h_name);
253
254   /* find out who I am */
255   clen = sizeof(caddr);
256   if (getsockname(sock, (struct sockaddr *) &caddr, &clen) < 0) {
257     if (!quiet)
258       perror("getsockname");
259     close(sock);
260     return ERROR_SYSTEM;
261   }
262
263   /*
264    * call Kerberos library routine to obtain an authenticator,
265    * pass it over the socket to the server, and obtain mutual
266    * authentication.
267    */
268
269   status = krb_sendauth((KRB_INT32)KOPT_DO_MUTUAL, sock, &ticket,
270                         SERVICE_PRINCIPAL,
271                         remote_host,
272                         krb_realmofhost(remote_host), 
273                         getpid(), 
274                         &msg_data,
275                         &cred,
276                         sched,
277                         &caddr, &saddr, KFTGT_PROTO_VERSION);
278
279   if (status != KSUCCESS) {
280     warn("cannot authenticate to server: %s",krb_err_txt[status]);
281     close(sock);
282     return ERROR_KERBEROS;
283   }
284
285   status = read_null_term(sock, buffer, sizeof(buffer));
286   if (status < 0) {
287     warn("read_null_term failed");
288     close(sock);
289     return ERROR_SEND;
290   }
291
292   if (strncmp(buffer,"ok",2)!=0) {
293     warn("%s",buffer);
294     close(sock);
295     return ERROR_SEND;
296   }
297
298   /*
299    * send over remote user name and ticket file, both NULL terminated
300    * and encrypted
301    */
302
303   if ( (len = marshall_params(ruser, f_val, buffer, sizeof(buffer))) <0) {
304     warn("unable to marshall params");
305     close(sock);
306     return ERROR_SYSTEM;
307   }
308
309   if (send_encrypted_chunk(buffer, len, sock, 
310                            &cred.session, sched, &caddr, &saddr) < 0) {
311     warn("error sending encrypted params");
312     close(sock);
313     return ERROR_SEND;
314   }
315
316   /* read encrypted response */
317
318   len = receive_encrypted_chunk(&m_data, buffer, sizeof(buffer), sock,
319                                 &cred.session, sched, &saddr, &caddr);
320
321   if (strncmp((char *) m_data.app_data,"ok",2)!=0) {
322     if (len > 0)
323       warn("%s",m_data.app_data);
324     else
325       warn("error receiving encrypted chunk");
326     close(sock);
327     return ERROR_SEND;
328   }
329
330   /* now send tgt */
331   /* get realm from cred for now */
332
333   if (krb_get_cred("krbtgt",cred.realm,cred.realm,&tgtcred) != GC_OK) {
334     warn("cannot get tgt from local ticket file");
335     close(sock);
336     return ERROR_KERBEROS;
337   }
338
339   len = marshall_cred(&tgtcred,buffer,sizeof(buffer));
340
341   if (len <= 0 || len >  KFTGT_MAX_BUFFER) {
342     warn("marshall of tgt failed");
343     close(sock);
344     return ERROR_SEND;
345   }
346
347   if (send_encrypted_chunk(buffer, len, sock, 
348                            &cred.session, sched, &caddr, &saddr) < 0) {
349     warn("error sending encrypted user name");
350     close(sock);
351     return ERROR_SEND;
352   }
353
354   len = receive_encrypted_chunk(&m_data,buffer,sizeof(buffer), sock,
355                                 &cred.session, sched, &saddr, &caddr);
356
357   if (strncmp((char *) m_data.app_data,"ok",2)!=0) {
358     if (len > 0)
359       warn("%s",m_data.app_data);
360     else
361       warn("error receiving encrypted chunk");
362     close(sock);
363     return ERROR_SEND;
364   }
365
366   if (!quiet) {
367     printf("%s: tgt %s.%s@%s forwarded to ",
368            prog,
369            cred.pname,
370            cred.pinst,
371            cred.realm);
372     if (ruser[0]) printf("%s at ",ruser);
373     printf("%s\n", server);
374   }
375   close(sock);
376   /* FIXME */
377   alarm(0);
378   return SUCCESS;
379 }
380
381 int
382 read_null_term(int s, char *buffer, int max)
383 {
384   int len=0;
385   while (max>0) {
386     read(s, buffer, 1);
387     len++;
388     if ( *buffer == 0 ) return len;
389     buffer++;
390     --max;
391   }
392   return -1;
393 }
394
395 /* warn
396  *
397  * Print error message, terminate connection and download, and exit
398  * Input:
399  *      fmt             format of error message in printf style
400  *      ...             % arguments supplied for fmt
401  * Returns:
402  *      nothing
403  */
404 void
405 warn (char *fmt, ...)
406 {
407   va_list argptr;
408
409   if (!quiet)
410     fprintf(stderr,"%s: ",prog);
411
412   va_start(argptr,fmt);
413   if (!quiet)
414     vfprintf(stderr,fmt,argptr);
415   va_end(argptr);
416
417   if (!quiet)
418     fprintf(stderr,"\n");
419 }
420
421 int
422 print_version(void)
423 {
424   fprintf(stderr,"%s version %s\n", prog, PACKAGE_VERSION);
425   exit(0);
426 }
427
428 int
429 usage(int exitcode)
430 {
431   fprintf(stderr,"Usage: %s [options] [user@]host [user2@host2 ...]\n",prog);
432   fprintf(stderr,"   -l user     remote user to forward tickets to\n");
433   fprintf(stderr,"   -f file     remote ticket filename\n");
434   fprintf(stderr,"   -t secs     timeout, default is 60 seconds\n");
435   fprintf(stderr,"   -v          version\n");
436   fprintf(stderr,"   -q          quiet\n");
437   fprintf(stderr,"   -d          debug info\n");
438   fprintf(stderr,"\n");
439   exit(exitcode);
440 }