LCOV - code coverage report
Current view: top level - source3/libads - sasl_wrapping.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 115 176 65.3 %
Date: 2024-04-21 15:09:00 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    ads sasl wrapping code
       4             :    Copyright (C) Stefan Metzmacher 2007
       5             :    
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "ads.h"
      22             : 
      23           0 : void ndr_print_ads_saslwrap_struct(struct ndr_print *ndr, const char *name, const struct ads_saslwrap *r)
      24             : {
      25           0 :         ndr_print_struct(ndr, name, "saslwrap");
      26           0 :         ndr->depth++;
      27           0 :         ndr_print_uint16(ndr, "wrap_type", r->wrap_type);
      28             : #ifdef HAVE_LDAP_SASL_WRAPPING
      29           0 :         ndr_print_ptr(ndr, "sbiod", r->sbiod);
      30             : #endif /* HAVE_LDAP_SASL_WRAPPING */
      31           0 :         ndr_print_ptr(ndr, "mem_ctx", r->mem_ctx);
      32           0 :         ndr_print_ptr(ndr, "wrap_ops", r->wrap_ops);
      33           0 :         ndr_print_ptr(ndr, "wrap_private_data", r->wrap_private_data);
      34           0 :         ndr_print_struct(ndr, name, "in");
      35           0 :         ndr->depth++;
      36           0 :         ndr_print_uint32(ndr, "ofs", r->in.ofs);
      37           0 :         ndr_print_uint32(ndr, "needed", r->in.needed);
      38           0 :         ndr_print_uint32(ndr, "left", r->in.left);
      39           0 :         ndr_print_uint32(ndr, "max_wrapped", r->in.max_wrapped);
      40           0 :         ndr_print_uint32(ndr, "min_wrapped", r->in.min_wrapped);
      41           0 :         ndr_print_uint32(ndr, "size", r->in.size);
      42           0 :         ndr_print_array_uint8(ndr, "buf", r->in.buf, r->in.size);
      43           0 :         ndr->depth--;
      44           0 :         ndr_print_struct(ndr, name, "out");
      45           0 :         ndr->depth++;
      46           0 :         ndr_print_uint32(ndr, "ofs", r->out.ofs);
      47           0 :         ndr_print_uint32(ndr, "left", r->out.left);
      48           0 :         ndr_print_uint32(ndr, "max_unwrapped", r->out.max_unwrapped);
      49           0 :         ndr_print_uint32(ndr, "sig_size", r->out.sig_size);
      50           0 :         ndr_print_uint32(ndr, "size", r->out.size);
      51           0 :         ndr_print_array_uint8(ndr, "buf", r->out.buf, r->out.size);
      52           0 :         ndr->depth--;
      53           0 : }
      54             : 
      55             : #ifdef HAVE_LDAP_SASL_WRAPPING
      56             : 
      57         307 : static int ads_saslwrap_setup(Sockbuf_IO_Desc *sbiod, void *arg)
      58             : {
      59         307 :         struct ads_saslwrap *wrap = (struct ads_saslwrap *)arg;
      60             : 
      61         307 :         wrap->sbiod  = (struct Sockbuf_IO_Desc *)sbiod;
      62             : 
      63         307 :         sbiod->sbiod_pvt = wrap;
      64             : 
      65         307 :         return 0;
      66             : }
      67             : 
      68         307 : static int ads_saslwrap_remove(Sockbuf_IO_Desc *sbiod)
      69             : {
      70         307 :         return 0;
      71             : }
      72             : 
      73        1299 : static ber_slen_t ads_saslwrap_prepare_inbuf(struct ads_saslwrap *wrap)
      74             : {
      75        1299 :         wrap->in.ofs = 0;
      76        1299 :         wrap->in.needed      = 0;
      77        1299 :         wrap->in.left        = 0;
      78        1299 :         wrap->in.size        = 4 + wrap->in.min_wrapped;
      79        1299 :         wrap->in.buf = talloc_array(wrap->mem_ctx,
      80             :                                        uint8_t, wrap->in.size);
      81        1299 :         if (!wrap->in.buf) {
      82           0 :                 return -1;
      83             :         }
      84             : 
      85        1299 :         return 0;
      86             : }
      87             : 
      88        1299 : static ber_slen_t ads_saslwrap_grow_inbuf(struct ads_saslwrap *wrap)
      89             : {
      90        1299 :         if (wrap->in.size == (4 + wrap->in.needed)) {
      91           0 :                 return 0;
      92             :         }
      93             : 
      94        1299 :         wrap->in.size        = 4 + wrap->in.needed;
      95        1299 :         wrap->in.buf = talloc_realloc(wrap->mem_ctx,
      96             :                                          wrap->in.buf,
      97             :                                          uint8_t, wrap->in.size);
      98        1299 :         if (!wrap->in.buf) {
      99           0 :                 return -1;
     100             :         }
     101             : 
     102        1299 :         return 0;
     103             : }
     104             : 
     105        1299 : static void ads_saslwrap_shrink_inbuf(struct ads_saslwrap *wrap)
     106             : {
     107        1299 :         talloc_free(wrap->in.buf);
     108             : 
     109        1299 :         wrap->in.buf = NULL;
     110        1299 :         wrap->in.size        = 0;
     111        1299 :         wrap->in.ofs = 0;
     112        1299 :         wrap->in.needed      = 0;
     113        1299 :         wrap->in.left        = 0;
     114        1299 : }
     115             : 
     116        9867 : static ber_slen_t ads_saslwrap_read(Sockbuf_IO_Desc *sbiod,
     117             :                                     void *buf, ber_len_t len)
     118             : {
     119        9867 :         struct ads_saslwrap *wrap =
     120             :                         (struct ads_saslwrap *)sbiod->sbiod_pvt;
     121           0 :         ber_slen_t ret;
     122             : 
     123             :         /* If ofs < 4 it means we don't have read the length header yet */
     124        9867 :         if (wrap->in.ofs < 4) {
     125        1299 :                 ret = ads_saslwrap_prepare_inbuf(wrap);
     126        1299 :                 if (ret < 0) return ret;
     127             : 
     128        1299 :                 ret = LBER_SBIOD_READ_NEXT(sbiod,
     129             :                                            wrap->in.buf + wrap->in.ofs,
     130             :                                            4 - wrap->in.ofs);
     131        1299 :                 if (ret <= 0) return ret;
     132        1299 :                 wrap->in.ofs += ret;
     133             : 
     134        1299 :                 if (wrap->in.ofs < 4) goto eagain;
     135             : 
     136        1299 :                 wrap->in.needed = RIVAL(wrap->in.buf, 0);
     137        1299 :                 if (wrap->in.needed > wrap->in.max_wrapped) {
     138           0 :                         errno = EINVAL;
     139           0 :                         return -1;
     140             :                 }
     141        1299 :                 if (wrap->in.needed < wrap->in.min_wrapped) {
     142           0 :                         errno = EINVAL;
     143           0 :                         return -1;
     144             :                 }
     145             : 
     146        1299 :                 ret = ads_saslwrap_grow_inbuf(wrap);
     147        1299 :                 if (ret < 0) return ret;
     148             :         }
     149             : 
     150             :         /*
     151             :          * if there's more data needed from the remote end,
     152             :          * we need to read more
     153             :          */
     154        9867 :         if (wrap->in.needed > 0) {
     155        2042 :                 ret = LBER_SBIOD_READ_NEXT(sbiod,
     156             :                                            wrap->in.buf + wrap->in.ofs,
     157             :                                            wrap->in.needed);
     158        2042 :                 if (ret <= 0) return ret;
     159        2042 :                 wrap->in.ofs += ret;
     160        2042 :                 wrap->in.needed -= ret;
     161             : 
     162        2042 :                 if (wrap->in.needed > 0) goto eagain;
     163             :         }
     164             : 
     165             :         /*
     166             :          * if we have a complete packet and have not yet unwrapped it
     167             :          * we need to call the mech specific unwrap() hook
     168             :          */
     169        9124 :         if (wrap->in.needed == 0 && wrap->in.left == 0) {
     170           0 :                 ADS_STATUS status;
     171        1299 :                 status = wrap->wrap_ops->unwrap(wrap);
     172        1299 :                 if (!ADS_ERR_OK(status)) {
     173           0 :                         errno = EACCES;
     174           0 :                         return -1;
     175             :                 }
     176             :         }
     177             : 
     178             :         /*
     179             :          * if we have unwrapped data give it to the caller
     180             :          */
     181        9124 :         if (wrap->in.left > 0) {
     182        9124 :                 ret = MIN(wrap->in.left, len);
     183        9124 :                 memcpy(buf, wrap->in.buf + wrap->in.ofs, ret);
     184        9124 :                 wrap->in.ofs += ret;
     185        9124 :                 wrap->in.left -= ret;
     186             : 
     187             :                 /*
     188             :                  * if no more is left shrink the inbuf,
     189             :                  * this will trigger reading a new SASL packet
     190             :                  * from the remote stream in the next call
     191             :                  */
     192        9124 :                 if (wrap->in.left == 0) {
     193        1299 :                         ads_saslwrap_shrink_inbuf(wrap);
     194             :                 }
     195             : 
     196        9124 :                 return ret;
     197             :         }
     198             : 
     199             :         /*
     200             :          * if we don't have anything for the caller yet,
     201             :          * tell him to ask again
     202             :          */
     203           0 : eagain:
     204         743 :         errno = EAGAIN;
     205         743 :         return -1;
     206             : }
     207             : 
     208        1606 : static ber_slen_t ads_saslwrap_prepare_outbuf(struct ads_saslwrap *wrap,
     209             :                                               uint32_t len)
     210             : {
     211        1606 :         wrap->out.ofs        = 0;
     212        1606 :         wrap->out.left       = 0;
     213        1606 :         wrap->out.size       = 4 + wrap->out.sig_size + len;
     214        1606 :         wrap->out.buf        = talloc_array(wrap->mem_ctx,
     215             :                                                uint8_t, wrap->out.size);
     216        1606 :         if (!wrap->out.buf) {
     217           0 :                 return -1;
     218             :         }
     219             : 
     220        1606 :         return 0;
     221             : }
     222             : 
     223        1606 : static void ads_saslwrap_shrink_outbuf(struct ads_saslwrap *wrap)
     224             : {
     225        1606 :         talloc_free(wrap->out.buf);
     226             : 
     227        1606 :         wrap->out.buf        = NULL;
     228        1606 :         wrap->out.size       = 0;
     229        1606 :         wrap->out.ofs        = 0;
     230        1606 :         wrap->out.left       = 0;
     231        1606 : }
     232             : 
     233        1606 : static ber_slen_t ads_saslwrap_write(Sockbuf_IO_Desc *sbiod,
     234             :                                      void *buf, ber_len_t len)
     235             : {
     236        1606 :         struct ads_saslwrap *wrap =
     237             :                         (struct ads_saslwrap *)sbiod->sbiod_pvt;
     238           0 :         ber_slen_t ret, rlen;
     239             : 
     240             :         /* if the buffer is empty, we need to wrap in incoming buffer */
     241        1606 :         if (wrap->out.left == 0) {
     242           0 :                 ADS_STATUS status;
     243             : 
     244        1606 :                 if (len == 0) {
     245           0 :                         errno = EINVAL;
     246           0 :                         return -1;
     247             :                 }
     248             : 
     249        1606 :                 rlen = MIN(len, wrap->out.max_unwrapped);
     250             : 
     251        1606 :                 ret = ads_saslwrap_prepare_outbuf(wrap, rlen);
     252        1606 :                 if (ret < 0) return ret;
     253             :                 
     254        1606 :                 status = wrap->wrap_ops->wrap(wrap, (uint8_t *)buf, rlen);
     255        1606 :                 if (!ADS_ERR_OK(status)) {
     256           0 :                         errno = EACCES;
     257           0 :                         return -1;
     258             :                 }
     259             : 
     260        1606 :                 RSIVAL(wrap->out.buf, 0, wrap->out.left - 4);
     261             :         } else {
     262           0 :                 rlen = -1;
     263             :         }
     264             : 
     265        1606 :         ret = LBER_SBIOD_WRITE_NEXT(sbiod,
     266             :                                     wrap->out.buf + wrap->out.ofs,
     267             :                                     wrap->out.left);
     268        1606 :         if (ret <= 0) return ret;
     269        1606 :         wrap->out.ofs += ret;
     270        1606 :         wrap->out.left -= ret;
     271             : 
     272        1606 :         if (wrap->out.left == 0) {
     273        1606 :                 ads_saslwrap_shrink_outbuf(wrap);
     274             :         }
     275             : 
     276        1606 :         if (rlen > 0) return rlen;
     277             : 
     278           0 :         errno = EAGAIN;
     279           0 :         return -1;
     280             : }
     281             : 
     282        7347 : static int ads_saslwrap_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
     283             : {
     284        7347 :         struct ads_saslwrap *wrap =
     285             :                         (struct ads_saslwrap *)sbiod->sbiod_pvt;
     286           0 :         int ret;
     287             : 
     288        7347 :         switch (opt) {
     289        7347 :         case LBER_SB_OPT_DATA_READY:
     290        7347 :                 if (wrap->in.left > 0) {
     291        3263 :                         return 1;
     292             :                 }
     293        4084 :                 ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
     294        4084 :                 break;
     295           0 :         default:
     296           0 :                 ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
     297           0 :                 break;
     298             :         }
     299             : 
     300        4084 :         return ret;
     301             : }
     302             : 
     303         307 : static int ads_saslwrap_close(Sockbuf_IO_Desc *sbiod)
     304             : {
     305         307 :         return 0;
     306             : }
     307             : 
     308             : static const Sockbuf_IO ads_saslwrap_sockbuf_io = {
     309             :         ads_saslwrap_setup,     /* sbi_setup */
     310             :         ads_saslwrap_remove,    /* sbi_remove */
     311             :         ads_saslwrap_ctrl,      /* sbi_ctrl */
     312             :         ads_saslwrap_read,      /* sbi_read */
     313             :         ads_saslwrap_write,     /* sbi_write */
     314             :         ads_saslwrap_close      /* sbi_close */
     315             : };
     316             : 
     317         307 : ADS_STATUS ads_setup_sasl_wrapping(struct ads_saslwrap *wrap, LDAP *ld,
     318             :                                    const struct ads_saslwrap_ops *ops,
     319             :                                    void *private_data)
     320             : {
     321           0 :         ADS_STATUS status;
     322           0 :         Sockbuf *sb;
     323         307 :         Sockbuf_IO *io = discard_const_p(Sockbuf_IO, &ads_saslwrap_sockbuf_io);
     324           0 :         int rc;
     325             : 
     326         307 :         rc = ldap_get_option(ld, LDAP_OPT_SOCKBUF, &sb);
     327         307 :         status = ADS_ERROR_LDAP(rc);
     328         307 :         if (!ADS_ERR_OK(status)) {
     329           0 :                 return status;
     330             :         }
     331             : 
     332             :         /* setup the real wrapping callbacks */
     333         307 :         rc = ber_sockbuf_add_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT, wrap);
     334         307 :         status = ADS_ERROR_LDAP(rc);
     335         307 :         if (!ADS_ERR_OK(status)) {
     336           0 :                 return status;
     337             :         }
     338             : 
     339         307 :         wrap->wrap_ops               = discard_const(ops);
     340         307 :         wrap->wrap_private_data      = private_data;
     341             : 
     342         307 :         return ADS_SUCCESS;
     343             : }
     344             : #else
     345           0 : ADS_STATUS ads_setup_sasl_wrapping(struct ads_saslwrap *wrap, LDAP *ld,
     346             :                                    const struct ads_saslwrap_ops *ops,
     347             :                                    void *private_data)
     348             : {
     349           0 :         return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
     350             : }
     351             : #endif /* HAVE_LDAP_SASL_WRAPPING */

Generated by: LCOV version 1.14