"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/obs-imap-gssapi.h" (25 Mar 2018, 11186 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "obs-imap-gssapi.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Implementation of IMAP GSS-API authentication according to RFC 1731.
    3  *@ TODO GSS-API should also be joined into "a VFS".
    4  *
    5  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    6  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
    7  */
    8 /*
    9  * Copyright (c) 2004 Gunnar Ritter.
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *    This product includes software developed by Gunnar Ritter
   23  *    and his contributors.
   24  * 4. Neither the name of Gunnar Ritter nor the names of his contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
   29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   31  * ARE DISCLAIMED.  IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
   32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   38  * SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * Partially derived from sample code in:
   43  *
   44  * GSS-API Programming Guide
   45  * Part No: 816-1331-11
   46  * Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA 95054 U.S.A.
   47  *
   48  * (c) 2002 Sun Microsystems
   49  */
   50 /*
   51  * Copyright 1994 by OpenVision Technologies, Inc.
   52  *
   53  * Permission to use, copy, modify, distribute, and sell this software
   54  * and its documentation for any purpose is hereby granted without fee,
   55  * provided that the above copyright notice appears in all copies and
   56  * that both that copyright notice and this permission notice appear in
   57  * supporting documentation, and that the name of OpenVision not be used
   58  * in advertising or publicity pertaining to distribution of the software
   59  * without specific, written prior permission. OpenVision makes no
   60  * representations about the suitability of this software for any
   61  * purpose.  It is provided "as is" without express or implied warranty.
   62  *
   63  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   64  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   65  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   66  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
   67  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
   68  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   69  * PERFORMANCE OF THIS SOFTWARE.
   70  */
   71 
   72 #ifdef HAVE_GSSAPI
   73 #ifndef GSSAPI_REG_INCLUDE
   74 # include <gssapi/gssapi.h>
   75 # ifdef GSSAPI_OLD_STYLE
   76 #  include <gssapi/gssapi_generic.h>
   77 #  define GSS_C_NT_HOSTBASED_SERVICE   gss_nt_service_name
   78 #  define NAIL_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
   79 # endif
   80 #else
   81 # include <gssapi.h>
   82 #endif
   83 
   84 static void _imap_gssapi_error1(const char *s, OM_uint32 code, int typ);
   85 static void _imap_gssapi_error(const char *s, OM_uint32 maj_stat,
   86                OM_uint32 min_stat);
   87 static char * _imap_gssapi_last_at_before_slash(char const *sp);
   88 
   89 static void
   90 _imap_gssapi_error1(const char *s, OM_uint32 code, int typ)
   91 {
   92    OM_uint32 maj_stat, min_stat;
   93    gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
   94    OM_uint32 msg_ctx = 0;
   95    NYD_ENTER;
   96 
   97    do {
   98       maj_stat = gss_display_status(&min_stat, code, typ, GSS_C_NO_OID,
   99             &msg_ctx, &msg);
  100       if (maj_stat == GSS_S_COMPLETE) {
  101          fprintf(stderr, "GSS error: %s / %s\n", s, (char*)msg.value);
  102          gss_release_buffer(&min_stat, &msg);
  103       } else {
  104          fprintf(stderr, "GSS error: %s / unknown\n", s);
  105          break;
  106       }
  107    } while (msg_ctx);
  108    NYD_LEAVE;
  109 }
  110 
  111 static void
  112 _imap_gssapi_error(const char *s, OM_uint32 maj_stat, OM_uint32 min_stat)
  113 {
  114    NYD_ENTER;
  115    _imap_gssapi_error1(s, maj_stat, GSS_C_GSS_CODE);
  116    _imap_gssapi_error1(s, min_stat, GSS_C_MECH_CODE);
  117    NYD_LEAVE;
  118 }
  119 
  120 static char *
  121 _imap_gssapi_last_at_before_slash(char const *sp)
  122 {
  123    char const *cp;
  124    char c;
  125    NYD_ENTER;
  126 
  127    for (cp = sp; (c = *cp) != '\0'; ++cp)
  128       if (c == '/')
  129          break;
  130    while (cp > sp && *--cp != '@')
  131       ;
  132    if (*cp != '@')
  133       cp = NULL;
  134    NYD_LEAVE;
  135    return n_UNCONST(cp);
  136 }
  137 
  138 static enum okay
  139 _imap_gssapi(struct mailbox *mp, struct ccred *ccred)
  140 {
  141    char o[LINESIZE];
  142    struct str in, out;
  143    gss_buffer_desc send_tok, recv_tok;
  144    gss_name_t target_name;
  145    gss_ctx_id_t gss_context;
  146    OM_uint32 maj_stat, min_stat, ret_flags;
  147    int conf_state;
  148    FILE *queuefp = NULL;
  149    char *server, *cp;
  150    enum{
  151       a_F_NONE,
  152       a_F_RECV_TOK = 1u<<0,
  153       a_F_SEND_TOK = 1u<<1,
  154       a_F_TARGET_NAME = 1u<<2,
  155       a_F_GSS_CONTEXT = 1u<<3
  156    } f;
  157    enum okay ok;
  158    NYD_X;
  159 
  160    ok = STOP;
  161    f = a_F_NONE;
  162 
  163    {  size_t i = strlen(mp->mb_imap_account) +1;
  164       server = salloc(i);
  165       memcpy(server, mp->mb_imap_account, i);
  166    }
  167    if (!strncmp(server, "imap://", 7))
  168       server += 7;
  169    else if (!strncmp(server, "imaps://", 8))
  170       server += 8;
  171    if ((cp = _imap_gssapi_last_at_before_slash(server)) != NULL)
  172       server = &cp[1];
  173    for (cp = server; *cp; cp++)
  174       *cp = lowerconv(*cp);
  175    send_tok.value = salloc(send_tok.length = strlen(server) + 6);
  176    snprintf(send_tok.value, send_tok.length, "imap@%s", server);
  177    maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NT_HOSTBASED_SERVICE,
  178          &target_name);
  179    f |= a_F_TARGET_NAME;
  180    if (maj_stat != GSS_S_COMPLETE) {
  181       _imap_gssapi_error(send_tok.value, maj_stat, min_stat);
  182       goto jleave;
  183    }
  184 
  185    gss_context = GSS_C_NO_CONTEXT;
  186    maj_stat = gss_init_sec_context(&min_stat,
  187          GSS_C_NO_CREDENTIAL,
  188          &gss_context,
  189          target_name,
  190          GSS_C_NO_OID,
  191          GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
  192          0,
  193          GSS_C_NO_CHANNEL_BINDINGS,
  194          GSS_C_NO_BUFFER,
  195          NULL,
  196          &send_tok,
  197          &ret_flags,
  198          NULL);
  199    f |= a_F_SEND_TOK | a_F_GSS_CONTEXT;
  200    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
  201       _imap_gssapi_error("initializing GSS context", maj_stat, min_stat);
  202       goto jleave;
  203    }
  204 
  205    snprintf(o, sizeof o, "%s AUTHENTICATE GSSAPI\r\n", tag(1));
  206    IMAP_OUT(o, 0, goto jleave);
  207 
  208    /*
  209     * No response data expected.
  210     */
  211    imap_answer(mp, 1);
  212    if (response_type != RESPONSE_CONT)
  213       goto jleave;
  214    while (maj_stat == GSS_S_CONTINUE_NEEDED) {
  215       /* Pass token obtained from first gss_init_sec_context() call. */
  216       if(b64_encode_buf(&out, send_tok.value, send_tok.length,
  217             B64_SALLOC | B64_CRLF) == NULL)
  218          goto jleave;
  219       gss_release_buffer(&min_stat, &send_tok);
  220       f &= ~a_F_SEND_TOK;
  221       IMAP_OUT(out.s, 0, goto jleave);
  222       imap_answer(mp, 1);
  223       if (response_type != RESPONSE_CONT)
  224          goto jleave;
  225       out.s = NULL;
  226       in.s = responded_text;
  227       in.l = strlen(responded_text);
  228       if(!b64_decode(&out, &in))
  229          goto jebase64;
  230       recv_tok.value = out.s;
  231       recv_tok.length = out.l;
  232       maj_stat = gss_init_sec_context(&min_stat,
  233             GSS_C_NO_CREDENTIAL,
  234             &gss_context,
  235             target_name,
  236             GSS_C_NO_OID,
  237             GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
  238             0,
  239             GSS_C_NO_CHANNEL_BINDINGS,
  240             &recv_tok,
  241             NULL,
  242             &send_tok,
  243             &ret_flags,
  244             NULL);
  245       free(out.s);
  246       f |= a_F_SEND_TOK;
  247       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
  248          _imap_gssapi_error("initializing context", maj_stat, min_stat);
  249          goto jleave;
  250       }
  251    }
  252 
  253    gss_release_name(&min_stat, &target_name);
  254    f &= ~a_F_TARGET_NAME;
  255 
  256    /* Pass token obtained from second gss_init_sec_context() call */
  257    if(b64_encode_buf(&out, send_tok.value, send_tok.length,
  258          B64_SALLOC | B64_CRLF) == NULL)
  259       goto jleave;
  260    IMAP_OUT(out.s, 0, goto jleave);
  261 
  262    gss_release_buffer(&min_stat, &send_tok);
  263    f &= ~a_F_SEND_TOK;
  264 
  265    /*
  266     * First octet: bit-mask with protection mechanisms.
  267     * Second to fourth octet: maximum message size in network byte order.
  268     *
  269     * This code currently does not care about the values.
  270     */
  271    imap_answer(mp, 1);
  272    if (response_type != RESPONSE_CONT)
  273       goto jleave;
  274    out.s = NULL;
  275    in.s = responded_text;
  276    in.l = strlen(responded_text);
  277    if(!b64_decode(&out, &in)){
  278 jebase64:
  279       if(out.s != NULL)
  280          free(out.s);
  281       n_err(_("Invalid base64 encoding from GSSAPI server\n"));
  282       goto jleave;
  283    }
  284    recv_tok.value = out.s;
  285    recv_tok.length = out.l;
  286    maj_stat = gss_unwrap(&min_stat, gss_context, &recv_tok, &send_tok,
  287          &conf_state, NULL);
  288    free(out.s);
  289    gss_release_buffer(&min_stat, &send_tok);
  290    /*f &= ~a_F_SEND_TOK;*/
  291    if (maj_stat != GSS_S_COMPLETE) {
  292       _imap_gssapi_error("unwrapping data", maj_stat, min_stat);
  293       goto jleave;
  294    }
  295 
  296    /* First octet: bit-mask with protection mechanisms (1 = no protection
  297     *    mechanism).
  298     * Second to fourth octet: maximum message size in network byte order.
  299     * Fifth and following octets: user name string.
  300     */
  301    o[0] = 1;
  302    o[1] = 0;
  303    o[2] = o[3] = (char)0377;
  304    snprintf(&o[4], sizeof o - 4, "%s", ccred->cc_user.s);
  305    send_tok.value = o;
  306    send_tok.length = strlen(&o[4]) + 5;
  307    maj_stat = gss_wrap(&min_stat, gss_context, 0, GSS_C_QOP_DEFAULT, &send_tok,
  308          &conf_state, &recv_tok);
  309    f |= a_F_RECV_TOK;
  310    if (maj_stat != GSS_S_COMPLETE) {
  311       _imap_gssapi_error("wrapping data", maj_stat, min_stat);
  312       goto jleave;
  313    }
  314 
  315    if(b64_encode_buf(&out, recv_tok.value, recv_tok.length,
  316          B64_SALLOC | B64_CRLF) == NULL)
  317       goto jleave;
  318    IMAP_OUT(out.s, MB_COMD, goto jleave);
  319 
  320    while (mp->mb_active & MB_COMD)
  321       ok = imap_answer(mp, 1);
  322 jleave:
  323    if(f & a_F_RECV_TOK)
  324       gss_release_buffer(&min_stat, &recv_tok);
  325    if(f & a_F_SEND_TOK)
  326       gss_release_buffer(&min_stat, &send_tok);
  327    if(f & a_F_TARGET_NAME)
  328       gss_release_name(&min_stat, &target_name);
  329    if(f & a_F_GSS_CONTEXT)
  330       gss_delete_sec_context(&min_stat, &gss_context, GSS_C_NO_BUFFER);
  331    return ok;
  332 }
  333 
  334 # ifdef NAIL_DEFINED_GCC_C_NT_HOSTBASED_SERVICE
  335 #  undef GSS_C_NT_HOSTBASED_SERVICE
  336 # endif
  337 #endif /* HAVE_GSSAPI */
  338 
  339 /* s-it-mode */