krb5auth.c

Go to the documentation of this file.
00001 
00008 /* $Id: krb5auth.c,v 1.4 2005/01/21 04:49:41 seymour Exp $ */
00009 /* $UTK_Copyright: $ */
00010 
00011 #ifdef KERBEROS5
00012 #include <stdio.h>
00013 #include <errno.h>
00014 #include <unistd.h>
00015 #include <sys/socket.h>
00016 #include <signal.h>
00017 #include <time.h>
00018 #include <krb5.h>
00019 #include <com_err.h>
00020 #include "proxylib.h"
00021 
00022 PROXY_KRB5_INFO proxy_krb5_info;
00023 
00024 char gridsolve_version[] = "GRIDSOLVE V0.1";
00025 
00036 int
00037 proxy_send_krb5_credentials (char *server_hostname, int comm)
00038 {
00039   krb5_context context;
00040   krb5_auth_context auth_context = 0;
00041   krb5_error_code retval;
00042   krb5_principal client, server;
00043   krb5_ccache cc;
00044 
00045   retval = krb5_init_context (&context);
00046   if (retval) {
00047     fprintf(stderr, "krb5_init_context failed: %s\n", error_message(retval));
00048     return -1;
00049   } 
00050 
00051   /*
00052    * XXX we're picking the service name "GridSolve" arbitrarily;
00053    * this should be registered with the appropriate folks.
00054    */
00055 
00056   retval = krb5_sname_to_principal(context, server_hostname,
00057                    "GridSolve",
00058                    KRB5_NT_SRV_HST, &server);
00059   if (retval) {
00060     fprintf (stderr, "krb5_sname_to_principal failed: %s\n",
00061          error_message (retval));
00062     return -1;
00063   }
00064 
00065   retval = krb5_cc_default (context, &cc);
00066 
00067   if (retval) {
00068     fprintf (stderr, "krb5_cc_default failed: %s\n",
00069          error_message (retval));
00070     krb5_free_principal (context, server);
00071     krb5_cc_close (context, cc);
00072     return -1;
00073   }
00074 
00075   retval = krb5_cc_get_principal (context, cc, &client);
00076 
00077   if (retval) {
00078     fprintf (stderr, "krb5_cc_get_principal failed: %s\n",
00079          error_message (retval));
00080     krb5_free_principal (context, server);
00081     krb5_cc_close (context, cc);
00082     return -1;
00083   }
00084 
00085   retval = krb5_sendauth (context, &auth_context,
00086               (krb5_context) &comm,
00087               gridsolve_version,
00088               client, server,
00089               AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
00090               NULL, NULL, cc, 0, 0, NULL);
00091   
00092   if (retval) {
00093     fprintf (stderr, "krb5_sendauth failed: %s\n",
00094          error_message (retval));
00095     krb5_free_principal (context, client);
00096     krb5_free_principal (context, server);
00097     krb5_cc_close (context, cc);
00098     return -1;
00099   }
00100 
00101   return 0;
00102 }
00103 
00112 int
00113 proxy_check_principal_name(char *name)
00114 {
00115     FILE *fp;
00116     char buf[1024];
00117     
00118     if ((fp = fopen (proxy_krb5_info.users_file, "r")) == NULL) {
00119     fprintf (stderr, "cannot open %s: %s\n", proxy_krb5_info.users_file, strerror (errno));
00120     return -1;
00121     }
00122     while (fgets (buf, sizeof (buf), fp)) {
00123     char *ptr;
00124     
00125     /* if '#' appears in the line, ignore it and everything following */
00126     if ( (ptr = strchr (buf, '#')) )
00127         *ptr = '\0';
00128     
00129     /* delete trailing spaces */
00130     ptr = buf + strlen (buf);
00131     while (ptr > buf && (ptr[-1] == ' ' || ptr[-1] == '\t' ||
00132                  ptr[-1] == '\n' || ptr[-1] == '\r'))
00133         *--ptr = '\0';
00134     
00135     /* skip over leading spaces */
00136     for (ptr = buf; *ptr == ' ' || *ptr == '\t'; ++ptr);
00137     
00138     /* if line is blank, continue */
00139     if (*ptr == '\0')
00140         continue;
00141     
00142     /* see if name matches */
00143     if (strcasecmp (ptr, name) == 0){
00144         return 1;
00145         }
00146     }
00147     fclose (fp);
00148     return -1;
00149 }
00150 
00159 int
00160 proxy_recv_krb5_credentials(int comm)
00161 {
00162   krb5_error_code retval;
00163   krb5_auth_context auth_context = NULL;
00164   krb5_ticket *ticket;
00165   char *name;
00166 
00167   fprintf(stderr, "Initializing Kerberos ... "); fflush(stderr);
00168   if(proxy_krb5_init() != 0){
00169     return -1;
00170   }
00171   fprintf(stderr, "success\n"); fflush(stderr);
00172 
00173   fprintf(stderr, "Initializing Authentication Context ... "); fflush(stderr);
00174   retval = krb5_auth_con_init(proxy_krb5_info.context, &auth_context);
00175   if(retval){
00176     fprintf(stderr, "krb5_auth_con_init() failed: %s\n", error_message(retval));
00177     return -1;
00178   }
00179   fprintf(stderr, "success\n"); fflush(stderr);
00180 
00181   fprintf(stderr, "Receiving authentication info from client ... "); fflush(stderr);
00182   retval = krb5_recvauth (proxy_krb5_info.context, &auth_context,
00183               (krb5_pointer) &comm, gridsolve_version,
00184               proxy_krb5_info.server, 0, proxy_krb5_info.keytab, &ticket);
00185   if (retval) {
00186       fprintf (stderr, "Authentication failed: %s\n",
00187            error_message(retval)); fflush(stderr);
00188       return -1;
00189   }
00190   fprintf(stderr, "success\n"); fflush(stderr);
00191   
00192   krb5_unparse_name (proxy_krb5_info.context, ticket->enc_part2->client, &name);
00193   krb5_free_ticket (proxy_krb5_info.context, ticket);
00194   
00195   /* it's not enough to know that the ticket is valid;
00196      (i.e. that the client is who he says he is),
00197      we also need to check to see whether client has permission */
00198 
00199   fprintf(stderr, "Authenticated, checking if %s is authorized ... ", name); fflush(stderr);
00200   if (proxy_check_principal_name (name) < 0) {
00201       fprintf (stderr, "permission denied.\n"); fflush(stderr);
00202       return -1;
00203   }
00204   else{
00205     fprintf (stderr, "yes\n");
00206     fflush(stderr);
00207   }
00208 
00209   free (name);
00210 
00211   fprintf(stderr, "Freeing authentication context ... "); fflush(stderr);
00212   retval = krb5_auth_con_free(proxy_krb5_info.context, auth_context);
00213   if(retval){
00214     fprintf(stderr, "krb5_auth_con_free() failed: %s\n", error_message(retval));
00215     return -1;
00216   }
00217   fprintf(stderr, "success\n"); fflush(stderr);
00218 
00219   return 0;
00220 }
00221 
00232 int 
00233 proxy_krb5_init()
00234 {
00235   krb5_error_code retval;
00236   char * keytab_filename;
00237   retval = krb5_init_context (&(proxy_krb5_info.context));
00238 
00239   if (retval)
00240   {
00241     fprintf (stderr,
00242          "krb5_init_context failed: %s\n", error_message(retval));
00243     return -1;
00244   }
00245 
00246   proxy_krb5_info.keytab = NULL;   /* Maybe do something different later */
00247   keytab_filename = getenv ("GRIDSOLVE_KEYTAB");
00248 
00249   if (keytab_filename == NULL)
00250   {
00251     fprintf (stderr, "Environment variable GRIDSOLVE_KEYTAB not defined\n");
00252     return -1;
00253   }
00254 
00255   retval = krb5_kt_resolve (proxy_krb5_info.context, keytab_filename, &(proxy_krb5_info.keytab));
00256   if(retval){
00257     fprintf (stderr, "krb5_kt_resolve() failed: %s\n", error_message(retval));
00258     return -1;
00259   } 
00260 
00261   proxy_krb5_info.users_file = getenv("GRIDSOLVE_USERS");
00262   if (proxy_krb5_info.users_file == NULL)
00263   {
00264     fprintf (stderr, "Environment variable GRIDSOLVE_USERS not defined\n");
00265     return -1;
00266   }
00267 
00268   retval = krb5_sname_to_principal (proxy_krb5_info.context, NULL, "GridSolve",
00269                     KRB5_NT_SRV_HST, &(proxy_krb5_info.server));
00270 
00271   if (retval)
00272   {
00273     fprintf (stderr, "krb5_sname_to_principal() failed: %s\n",
00274          error_message (retval));
00275     return -1;
00276   }
00277 
00278   return 0;
00279 }
00280   
00281 #endif /* KERBEROS5 */