"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/obs-imap-gssapi.h" (8 Aug 2018, 11341 Bytes) of package /linux/misc/s-nail-14.9.11.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 latest Fossies "Diffs" side-by-side code changes report: 14.9.10_vs_14.9.11.

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