auth_gss.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:13k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: GSSAPI authenticator
  3.  *
  4.  * Author: Mark Crispin
  5.  * Networks and Distributed Computing
  6.  * Computing & Communications
  7.  * University of Washington
  8.  * Administration Building, AG-44
  9.  * Seattle, WA  98195
  10.  * Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date: 12 January 1998
  13.  * Last Edited: 26 August 1999
  14.  *
  15.  * Copyright 1998 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made available
  24.  * "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. #define PROTOTYPE(x) x
  36. #define KRB5_PROVIDE_PROTOTYPES
  37. #include <gssapi/gssapi_generic.h>
  38. #include <gssapi/gssapi_krb5.h>
  39. #include <krb5.h>
  40. long auth_gssapi_valid (void);
  41. long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
  42.  NETMBX *mb,void *stream,unsigned long *trial,
  43.  char *user);
  44. char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]);
  45. AUTHENTICATOR auth_gss = {
  46.   T, /* secure authenticator */
  47.   "GSSAPI", /* authenticator name */
  48.   auth_gssapi_valid, /* check if valid */
  49.   auth_gssapi_client, /* client method */
  50.   auth_gssapi_server, /* server method */
  51.   NIL /* next authenticator */
  52. };
  53. #define AUTH_GSSAPI_P_NONE 1
  54. #define AUTH_GSSAPI_P_INTEGRITY 2
  55. #define AUTH_GSSAPI_P_PRIVACY 4
  56. #define AUTH_GSSAPI_C_MAXSIZE 8192
  57. #define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y)
  58. extern char *krb5_defkeyname; /* sneaky way to get this name */
  59. /* Placate const declarations */
  60. static gss_OID_desc *auth_gss_mech;
  61. static gss_OID_set_desc *auth_gss_mech_set;
  62. /* Check if GSSAPI valid on this system
  63.  * Returns: T if valid, NIL otherwise
  64.  */
  65. long auth_gssapi_valid (void)
  66. {
  67.   char *s,tmp[MAILTMPLEN];
  68.   OM_uint32 min;
  69.   gss_buffer_desc buf;
  70.   gss_name_t name;
  71.   struct stat sbuf;
  72.   sprintf (tmp,"host@%s",mylocalhost ());
  73.   buf.length = strlen (buf.value = tmp) + 1;
  74.   memcpy (&auth_gss_mech,&gss_mech_krb5,sizeof (gss_OID));
  75.   memcpy (&auth_gss_mech_set,&gss_mech_set_krb5,sizeof (gss_OID_set));
  76. /* see if can build a name */
  77.   if (gss_import_name (&min,&buf,gss_nt_service_name,&name) != GSS_S_COMPLETE)
  78.     return NIL; /* failed */
  79.   if ((s = strchr (krb5_defkeyname,':')) && stat (++s,&sbuf))
  80.     auth_gss.server = NIL; /* can't do server if no keytab */
  81.   gss_release_name (&min,&name);/* finished with name */
  82.   return LONGT;
  83. }
  84. /* Client authenticator
  85.  * Accepts: challenger function
  86.  *     responder function
  87.  *     parsed network mailbox structure
  88.  *     stream argument for functions
  89.  *     pointer to current trial count
  90.  *     returned user name
  91.  * Returns: T if success, NIL otherwise, number of trials incremented if retry
  92.  */
  93. long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
  94. NETMBX *mb,void *stream,unsigned long *trial,
  95. char *user)
  96. {
  97.   long ret = NIL;
  98.   char tmp[MAILTMPLEN];
  99.   OM_uint32 maj,min,mmaj,mmin;
  100.   OM_uint32 mctx = 0;
  101.   gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  102.   gss_buffer_desc chal,resp,buf;
  103.   gss_name_t crname = NIL;
  104.   long i;
  105.   int conf;
  106.   gss_qop_t qop;
  107.   *trial = 0; /* never retry */
  108.   if ((chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) &&
  109.       !chal.length) { /* get initial (empty) challenge */
  110.     sprintf (tmp,"%s@%s",mb->service,mb->host);
  111.     buf.length = strlen (buf.value = tmp) + 1;
  112. /* get service name */
  113.     if (gss_import_name(&min,&buf,gss_nt_service_name,&crname)!=GSS_S_COMPLETE)
  114.       (*responder) (stream,NIL,0);
  115.     else switch (maj = /* get context */
  116.  gss_init_sec_context (&min,GSS_C_NO_CREDENTIAL,&ctx,crname,
  117.        auth_gss_mech,
  118.        GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
  119.        0,GSS_C_NO_CHANNEL_BINDINGS,
  120.        GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL)) {
  121.     case GSS_S_CONTINUE_NEEDED:
  122.       do { /* negotiate authentication */
  123. if (chal.value) fs_give ((void **) &chal.value);
  124. /* send response */
  125. i = (*responder) (stream,resp.value,resp.length);
  126. gss_release_buffer (&min,&resp);
  127.       }
  128.       while (i && /* get next challenge */
  129.      (chal.value=(*challenger)(stream,(unsigned long *)&chal.length))&&
  130.      (maj = gss_init_sec_context (&min,GSS_C_NO_CREDENTIAL,&ctx,
  131.   crname,GSS_C_NO_OID,
  132.   GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,
  133.   0,GSS_C_NO_CHANNEL_BINDINGS,&chal,
  134.   NIL,&resp,NIL,NIL) ==
  135.       GSS_S_CONTINUE_NEEDED));
  136.     case GSS_S_COMPLETE:
  137.       if (chal.value) {
  138. fs_give ((void **) &chal.value);
  139. if (maj != GSS_S_COMPLETE) (*responder) (stream,NIL,0);
  140.       }
  141. /* get prot mechanisms and max size */
  142.       if ((maj == GSS_S_COMPLETE) &&
  143.   (*responder) (stream,resp.value ? resp.value : "",resp.length) &&
  144.   (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
  145.   (gss_unwrap (&min,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
  146.   (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
  147. /* make copy of flags and length */
  148. memcpy (tmp,resp.value,4);
  149. gss_release_buffer (&min,&resp);
  150. /* no session protection */
  151. tmp[0] = AUTH_GSSAPI_P_NONE;
  152. /* install user name */
  153. strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
  154. buf.value = tmp; buf.length = strlen (user) + 4;
  155. /* successful negotiation */
  156. if (gss_wrap (&min,ctx,FALSE,qop,&buf,&conf,&resp) == GSS_S_COMPLETE) {
  157.   if ((*responder) (stream,resp.value,resp.length)) ret = T;
  158.   gss_release_buffer (&min,&resp);
  159. }
  160. else (*responder) (stream,NIL,0);
  161.       }
  162. /* flush final challenge */
  163.       if (chal.value) fs_give ((void **) &chal.value);
  164. /* don't need context any more */
  165.       gss_delete_sec_context (&min,&ctx,NIL);
  166.       break;
  167.     case GSS_S_CREDENTIALS_EXPIRED:
  168.       if (chal.value) fs_give ((void **) &chal.value);
  169.       sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
  170.        mb->host);
  171.       mm_log (tmp,WARN);
  172.       (*responder) (stream,NIL,0);
  173.       break;
  174.     case GSS_S_FAILURE:
  175.       if (chal.value) fs_give ((void **) &chal.value);
  176.       if (min == (OM_uint32) KRB5_FCC_NOFILE) {
  177. sprintf (tmp,"No credentials cache found (try running kinit) for %s",
  178.  mb->host);
  179. mm_log (tmp,WARN);
  180.       }
  181.       else do switch (mmaj = gss_display_status (&mmin,min,GSS_C_MECH_CODE,
  182.  GSS_C_NO_OID,&mctx,&resp)) {
  183.       case GSS_S_COMPLETE:
  184.       case GSS_S_CONTINUE_NEEDED:
  185. sprintf (tmp,"GSSAPI failure: %s",(char *) resp.value);
  186. mm_log (tmp,WARN);
  187. gss_release_buffer (&mmin,&resp);
  188.       }
  189.       while (mmaj == GSS_S_CONTINUE_NEEDED);
  190.       (*responder) (stream,NIL,0);
  191.       break;
  192.     default: /* miscellaneous errors */
  193.       if (chal.value) fs_give ((void **) &chal.value);
  194.       do switch (mmaj = gss_display_status (&mmin,maj,GSS_C_GSS_CODE,
  195.     GSS_C_NO_OID,&mctx,&resp)) {
  196.       case GSS_S_COMPLETE:
  197. mctx = 0;
  198.       case GSS_S_CONTINUE_NEEDED:
  199. sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
  200. mm_log (tmp,WARN);
  201. gss_release_buffer (&mmin,&resp);
  202.       }
  203.       while (mmaj == GSS_S_CONTINUE_NEEDED);
  204.       do switch (mmaj = gss_display_status (&mmin,min,GSS_C_MECH_CODE,
  205.     GSS_C_NO_OID,&mctx,&resp)) {
  206.       case GSS_S_COMPLETE:
  207.       case GSS_S_CONTINUE_NEEDED:
  208. sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
  209. mm_log (tmp,WARN);
  210. gss_release_buffer (&mmin,&resp);
  211.       }
  212.       while (mmaj == GSS_S_CONTINUE_NEEDED);
  213.       (*responder) (stream,NIL,0);
  214.       break;
  215.     }
  216. /* finished with credentials name */
  217.     if (crname) gss_release_name (&min,&crname);
  218.   }
  219.   return ret; /* return status */
  220. }
  221. /* Server authenticator
  222.  * Accepts: responder function
  223.  *     argument count
  224.  *     argument vector
  225.  * Returns: authenticated user name or NIL
  226.  */
  227. char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
  228. {
  229.   char *ret = NIL;
  230.   char tmp[MAILTMPLEN];
  231.   unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
  232.   int conf;
  233.   OM_uint32 maj,min,mmaj,mmin,flags;
  234.   OM_uint32 mctx = 0;
  235.   gss_name_t crname,name;
  236.   gss_OID mech;
  237.   gss_buffer_desc chal,resp,buf;
  238.   gss_cred_id_t crd;
  239.   gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  240.   gss_qop_t qop = GSS_C_QOP_DEFAULT;
  241.   krb5_context ktx;
  242.   krb5_principal prnc;
  243. /* make service name */
  244.   sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
  245.    tcp_serverhost ());
  246.   buf.length = strlen (buf.value = tmp) + 1;
  247. /* acquire credentials */
  248.   if ((gss_import_name (&min,&buf,gss_nt_service_name,&crname)) ==
  249.       GSS_S_COMPLETE) {
  250.     if ((maj = gss_acquire_cred (&min,crname,0,auth_gss_mech_set,GSS_C_ACCEPT,
  251.  &crd,NIL,NIL)) == GSS_S_COMPLETE) {
  252.       if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) {
  253. do { /* negotiate authentication */
  254.   maj = gss_accept_sec_context (&min,&ctx,crd,&resp,
  255. GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
  256. &chal,&flags,NIL,NIL);
  257. /* don't need response any more */
  258.   fs_give ((void **) &resp.value);
  259. /* paranoia */
  260.   if (memcmp (mech->elements,gss_mech_krb5->elements,mech->length))
  261.     fatal ("GSSAPI is bogus");
  262.   switch (maj) { /* how did it go? */
  263.   case GSS_S_COMPLETE: /* successful */
  264.   case GSS_S_CONTINUE_NEEDED:
  265.     if (chal.value) { /* send challenge, get next response */
  266.       resp.value = (*responder) (chal.value,chal.length,
  267.  (unsigned long *) &resp.length);
  268.       gss_release_buffer (&min,&chal);
  269.     }
  270.     break;
  271.   }
  272. }
  273. while (resp.value && resp.length && (maj == GSS_S_CONTINUE_NEEDED));
  274. /* successful exchange? */
  275. if ((maj == GSS_S_COMPLETE) &&
  276.     (gss_display_name (&min,name,&buf,&mech) == GSS_S_COMPLETE)) {
  277. /* send security and size */
  278.   memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
  279.   tmp[0] = AUTH_GSSAPI_P_NONE;
  280.   if (gss_wrap (&min,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
  281.     resp.value = (*responder) (chal.value,chal.length,
  282.        (unsigned long *) &resp.length);
  283.     gss_release_buffer (&min,&chal);
  284.     if (gss_unwrap (&min,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
  285.       if (chal.value && (chal.length > 4) && (chal.length < MAILTMPLEN)
  286.   && (*((char *) chal.value) & AUTH_GSSAPI_P_NONE) &&
  287.   !krb5_init_context (&ktx)) {
  288. /* parse name as principal */
  289. if (!krb5_parse_name (ktx,buf.value,&prnc)) {
  290. /* copy flags/size/user name */
  291.   memcpy (tmp,chal.value,chal.length);
  292. /* make sure user name tied off */
  293.   tmp[chal.length] = '';
  294. /* OK for this principal to log in as user? */
  295.   if ((krb5_kuserok (ktx,prnc,tmp+4) &&
  296.        authserver_login (tmp+4,argc,argv)) ||
  297.       (krb5_kuserok (ktx,prnc,lcase (tmp+4)) &&
  298.        authserver_login (tmp+4,argc,argv))) ret = myusername();
  299. /* done with principal */
  300.   krb5_free_principal (ktx,prnc);
  301. }
  302. /* done with context */
  303. krb5_free_context (ktx);
  304.       }
  305. /* done with user name */
  306.       gss_release_buffer (&min,&chal);
  307.     }
  308. /* finished with response */
  309.     fs_give ((void **) &resp.value);
  310.   }
  311. /* don't need name buffer any more */
  312.   gss_release_buffer (&min,&buf);
  313. }
  314. /* don't need client name any more */
  315. gss_release_name (&min,&name);
  316. /* don't need context any more */
  317. if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&min,&ctx,NIL);
  318.       }
  319. /* finished with credentials */
  320.       gss_release_cred (&min,&crd);
  321.     }
  322.     else { /* can't acquire credentials! */
  323.       if (gss_display_name (&mmin,crname,&buf,&mech) == GSS_S_COMPLETE)
  324. SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
  325.       if (maj != GSS_S_FAILURE) do
  326. switch (mmaj = gss_display_status (&mmin,maj,GSS_C_GSS_CODE,
  327.    GSS_C_NO_OID,&mctx,&resp)) {
  328. case GSS_S_COMPLETE:
  329.   mctx = 0;
  330. case GSS_S_CONTINUE_NEEDED:
  331.   SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
  332.   gss_release_buffer (&mmin,&resp);
  333. }
  334.       while (mmaj == GSS_S_CONTINUE_NEEDED);
  335.       do switch (mmaj = gss_display_status (&mmin,min,GSS_C_MECH_CODE,
  336.     GSS_C_NO_OID,&mctx,&resp)) {
  337.       case GSS_S_COMPLETE:
  338.       case GSS_S_CONTINUE_NEEDED:
  339. SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
  340. gss_release_buffer (&mmin,&resp);
  341.       }
  342.       while (mmaj == GSS_S_CONTINUE_NEEDED);
  343.     }
  344. /* finished with credentials name */
  345.     gss_release_name (&min,&crname);
  346.   }
  347.   return ret; /* return status */
  348. }