LCOV - code coverage report
Current view: top level - source4/auth/kerberos - krb5_init_context.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 310 431 71.9 %
Date: 2024-02-29 22:57:05 Functions: 23 24 95.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Wrapper for krb5_init_context
       4             : 
       5             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    Copyright (C) Stefan Metzmacher 2004
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/kerberos.h"
      25             : #include <tevent.h>
      26             : #include "auth/kerberos/kerberos.h"
      27             : #include "lib/socket/socket.h"
      28             : #include "lib/stream/packet.h"
      29             : #include "system/network.h"
      30             : #include "param/param.h"
      31             : #include "libcli/resolve/resolve.h"
      32             : #include "../lib/tsocket/tsocket.h"
      33             : #include "krb5_init_context.h"
      34             : #ifdef SAMBA4_USES_HEIMDAL
      35             : #include "../lib/dbwrap/dbwrap.h"
      36             : #include "../lib/dbwrap/dbwrap_rbt.h"
      37             : #include "../lib/util/util_tdb.h"
      38             : #include <krb5/send_to_kdc_plugin.h>
      39             : #endif
      40             : 
      41             : /*
      42             :   context structure for operations on cldap packets
      43             : */
      44             : struct smb_krb5_socket {
      45             :         struct socket_context *sock;
      46             : 
      47             :         /* the fd event */
      48             :         struct tevent_fd *fde;
      49             : 
      50             :         NTSTATUS status;
      51             :         DATA_BLOB request, reply;
      52             : 
      53             :         struct packet_context *packet;
      54             : 
      55             :         size_t partial_read;
      56             : #ifdef SAMBA4_USES_HEIMDAL
      57             :         krb5_krbhst_info *hi;
      58             : #endif
      59             : };
      60             : 
      61      469575 : static krb5_error_code smb_krb5_context_destroy(struct smb_krb5_context *ctx)
      62             : {
      63             : #ifdef SAMBA4_USES_HEIMDAL
      64      386679 :         if (ctx->pvt_log_data) {
      65             :                 /* Otherwise krb5_free_context will try and close what we
      66             :                  * have already free()ed */
      67      386679 :                 krb5_set_warn_dest(ctx->krb5_context, NULL);
      68      386679 :                 krb5_closelog(ctx->krb5_context,
      69      386679 :                                 (krb5_log_facility *)ctx->pvt_log_data);
      70             :         }
      71             : #endif
      72      469575 :         krb5_free_context(ctx->krb5_context);
      73      469575 :         return 0;
      74             : }
      75             : 
      76             : #ifdef SAMBA4_USES_HEIMDAL
      77             : /* We never close down the DEBUG system, and no need to unreference the use */
      78      386679 : static void smb_krb5_debug_close(void *private_data) {
      79      386679 :         return;
      80             : }
      81             : #endif
      82             : 
      83             : #ifdef SAMBA4_USES_HEIMDAL
      84     2125783 : static void smb_krb5_debug_wrapper(
      85             : #ifdef HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT
      86             :                 krb5_context ctx,
      87             : #endif /* HAVE_KRB5_ADDLOG_FUNC_NEED_CONTEXT */
      88             :                 const char *timestr, const char *msg, void *private_data)
      89             : {
      90     2125783 :         DEBUGC(DBGC_KERBEROS, 3, ("Kerberos: %s\n", msg));
      91     2125783 : }
      92             : #endif
      93             : 
      94             : #ifdef SAMBA4_USES_HEIMDAL
      95             : /*
      96             :   handle recv events on a smb_krb5 socket
      97             : */
      98       21290 : static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5)
      99             : {
     100       21290 :         TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5);
     101        1170 :         DATA_BLOB blob;
     102        1170 :         size_t nread, dsize;
     103             : 
     104       21290 :         smb_krb5->status = socket_pending(smb_krb5->sock, &dsize);
     105       21290 :         if (!NT_STATUS_IS_OK(smb_krb5->status)) {
     106           0 :                 talloc_free(tmp_ctx);
     107           0 :                 return;
     108             :         }
     109             : 
     110       21290 :         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
     111       21290 :         if (blob.data == NULL && dsize != 0) {
     112           0 :                 smb_krb5->status = NT_STATUS_NO_MEMORY;
     113           0 :                 talloc_free(tmp_ctx);
     114           0 :                 return;
     115             :         }
     116             : 
     117       21290 :         smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread);
     118       21290 :         if (!NT_STATUS_IS_OK(smb_krb5->status)) {
     119           0 :                 talloc_free(tmp_ctx);
     120           0 :                 return;
     121             :         }
     122       21290 :         blob.length = nread;
     123             : 
     124       21290 :         if (nread == 0) {
     125           0 :                 smb_krb5->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
     126           0 :                 talloc_free(tmp_ctx);
     127           0 :                 return;
     128             :         }
     129             : 
     130       21290 :         DEBUG(4,("Received smb_krb5 packet of length %d\n",
     131             :                  (int)blob.length));
     132             : 
     133       21290 :         talloc_steal(smb_krb5, blob.data);
     134       21290 :         smb_krb5->reply = blob;
     135       21290 :         talloc_free(tmp_ctx);
     136             : }
     137             : 
     138       24302 : static NTSTATUS smb_krb5_full_packet(void *private_data, DATA_BLOB data)
     139             : {
     140       24302 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     141       24302 :         talloc_steal(smb_krb5, data.data);
     142       24302 :         smb_krb5->reply = data;
     143       24302 :         smb_krb5->reply.length -= 4;
     144       24302 :         smb_krb5->reply.data += 4;
     145       24302 :         return NT_STATUS_OK;
     146             : }
     147             : 
     148             : /*
     149             :   handle request timeouts
     150             : */
     151           4 : static void smb_krb5_request_timeout(struct tevent_context *event_ctx,
     152             :                                   struct tevent_timer *te, struct timeval t,
     153             :                                   void *private_data)
     154             : {
     155           4 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     156           4 :         DEBUG(5,("Timed out smb_krb5 packet\n"));
     157           4 :         smb_krb5->status = NT_STATUS_IO_TIMEOUT;
     158           4 : }
     159             : 
     160           0 : static void smb_krb5_error_handler(void *private_data, NTSTATUS status)
     161             : {
     162           0 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     163           0 :         smb_krb5->status = status;
     164           0 : }
     165             : 
     166             : /*
     167             :   handle send events on a smb_krb5 socket
     168             : */
     169    15139574 : static void smb_krb5_socket_send(struct smb_krb5_socket *smb_krb5)
     170             : {
     171        1170 :         NTSTATUS status;
     172             : 
     173        1170 :         size_t len;
     174             : 
     175    15139574 :         len = smb_krb5->request.length;
     176    15139574 :         status = socket_send(smb_krb5->sock, &smb_krb5->request, &len);
     177             : 
     178    15139574 :         if (!NT_STATUS_IS_OK(status)) return;
     179             : 
     180       21290 :         TEVENT_FD_READABLE(smb_krb5->fde);
     181             : 
     182       21290 :         TEVENT_FD_NOT_WRITEABLE(smb_krb5->fde);
     183       21290 :         return;
     184             : }
     185             : 
     186             : 
     187             : /*
     188             :   handle fd events on a smb_krb5_socket
     189             : */
     190    15231919 : static void smb_krb5_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     191             :                                  uint16_t flags, void *private_data)
     192             : {
     193    15231919 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     194    15231919 :         switch (smb_krb5->hi->proto) {
     195    15160864 :         case KRB5_KRBHST_UDP:
     196    15160864 :                 if (flags & TEVENT_FD_READ) {
     197       21290 :                         smb_krb5_socket_recv(smb_krb5);
     198       21290 :                         return;
     199             :                 }
     200    15139574 :                 if (flags & TEVENT_FD_WRITE) {
     201    15139574 :                         smb_krb5_socket_send(smb_krb5);
     202    15139574 :                         return;
     203             :                 }
     204             :                 /* not reached */
     205           0 :                 return;
     206       71055 :         case KRB5_KRBHST_TCP:
     207       71055 :                 if (flags & TEVENT_FD_READ) {
     208       46706 :                         packet_recv(smb_krb5->packet);
     209       46706 :                         return;
     210             :                 }
     211       24349 :                 if (flags & TEVENT_FD_WRITE) {
     212       24349 :                         packet_queue_run(smb_krb5->packet);
     213       24349 :                         return;
     214             :                 }
     215             :                 /* not reached */
     216           0 :                 return;
     217           0 :         case KRB5_KRBHST_HTTP:
     218             :                 /* can't happen */
     219           0 :                 break;
     220             :         }
     221             : }
     222             : 
     223       45596 : static krb5_error_code smb_krb5_send_and_recv_func_int(struct smb_krb5_context *smb_krb5_context,
     224             :                                                        struct tevent_context *ev,
     225             :                                                        krb5_krbhst_info *hi,
     226             :                                                        struct addrinfo *ai,
     227             :                                                        smb_krb5_send_to_kdc_func func,
     228             :                                                        void *data,
     229             :                                                        time_t timeout,
     230             :                                                        const krb5_data *send_buf,
     231             :                                                        krb5_data *recv_buf)
     232             : {
     233        1755 :         krb5_error_code ret;
     234        1755 :         NTSTATUS status;
     235        1755 :         const char *name;
     236        1755 :         struct addrinfo *a;
     237        1755 :         struct smb_krb5_socket *smb_krb5;
     238             : 
     239        1755 :         DATA_BLOB send_blob;
     240             : 
     241       45596 :         TALLOC_CTX *frame = talloc_stackframe();
     242       45596 :         if (frame == NULL) {
     243           0 :                 return ENOMEM;
     244             :         }
     245             : 
     246       45596 :         send_blob = data_blob_const(send_buf->data, send_buf->length);
     247             : 
     248       45600 :         for (a = ai; a; a = a->ai_next) {
     249        1755 :                 struct socket_address *remote_addr;
     250       45596 :                 smb_krb5 = talloc(frame, struct smb_krb5_socket);
     251       45596 :                 if (!smb_krb5) {
     252           0 :                         TALLOC_FREE(frame);
     253           0 :                         return ENOMEM;
     254             :                 }
     255       45596 :                 smb_krb5->hi = hi;
     256             : 
     257       45596 :                 switch (a->ai_family) {
     258       43841 :                 case PF_INET:
     259       43841 :                         name = "ipv4";
     260       43841 :                         break;
     261             : #ifdef HAVE_IPV6
     262           0 :                 case PF_INET6:
     263           0 :                         name = "ipv6";
     264           0 :                         break;
     265             : #endif
     266           0 :                 default:
     267           0 :                         TALLOC_FREE(frame);
     268           0 :                         return EINVAL;
     269             :                 }
     270             : 
     271       45596 :                 status = NT_STATUS_INVALID_PARAMETER;
     272       45596 :                 switch (hi->proto) {
     273       21294 :                 case KRB5_KRBHST_UDP:
     274       21294 :                         status = socket_create(smb_krb5, name,
     275             :                                                SOCKET_TYPE_DGRAM,
     276             :                                                &smb_krb5->sock, 0);
     277       21294 :                         break;
     278       24302 :                 case KRB5_KRBHST_TCP:
     279       24302 :                         status = socket_create(smb_krb5, name,
     280             :                                                SOCKET_TYPE_STREAM,
     281             :                                                &smb_krb5->sock, 0);
     282       24302 :                         break;
     283           0 :                 case KRB5_KRBHST_HTTP:
     284           0 :                         TALLOC_FREE(frame);
     285           0 :                         return EINVAL;
     286             :                 }
     287       45596 :                 if (!NT_STATUS_IS_OK(status)) {
     288           0 :                         talloc_free(smb_krb5);
     289           4 :                         continue;
     290             :                 }
     291             : 
     292       45596 :                 remote_addr = socket_address_from_sockaddr(smb_krb5, a->ai_addr, a->ai_addrlen);
     293       45596 :                 if (!remote_addr) {
     294           0 :                         talloc_free(smb_krb5);
     295           0 :                         continue;
     296             :                 }
     297             : 
     298       45596 :                 status = socket_connect_ev(smb_krb5->sock, NULL, remote_addr, 0, ev);
     299       45596 :                 if (!NT_STATUS_IS_OK(status)) {
     300           0 :                         talloc_free(smb_krb5);
     301           0 :                         continue;
     302             :                 }
     303             : 
     304             :                 /* Setup the FDE, start listening for read events
     305             :                  * from the start (otherwise we may miss a socket
     306             :                  * drop) and mark as AUTOCLOSE along with the fde */
     307             : 
     308             :                 /* This is equivalent to EVENT_FD_READABLE(smb_krb5->fde) */
     309       45596 :                 smb_krb5->fde = tevent_add_fd(ev, smb_krb5->sock,
     310             :                                               socket_get_fd(smb_krb5->sock),
     311             :                                               TEVENT_FD_READ,
     312             :                                               smb_krb5_socket_handler, smb_krb5);
     313             :                 /* its now the job of the event layer to close the socket */
     314       45596 :                 tevent_fd_set_close_fn(smb_krb5->fde, socket_tevent_fd_close_fn);
     315       45596 :                 socket_set_flags(smb_krb5->sock, SOCKET_FLAG_NOCLOSE);
     316             : 
     317       45596 :                 tevent_add_timer(ev, smb_krb5,
     318             :                                  timeval_current_ofs(timeout, 0),
     319             :                                  smb_krb5_request_timeout, smb_krb5);
     320             : 
     321       45596 :                 smb_krb5->status = NT_STATUS_OK;
     322       45596 :                 smb_krb5->reply = data_blob(NULL, 0);
     323             : 
     324       45596 :                 switch (hi->proto) {
     325       21294 :                 case KRB5_KRBHST_UDP:
     326       21294 :                         TEVENT_FD_WRITEABLE(smb_krb5->fde);
     327       21294 :                         smb_krb5->request = send_blob;
     328       21294 :                         break;
     329       24302 :                 case KRB5_KRBHST_TCP:
     330             : 
     331       24302 :                         smb_krb5->packet = packet_init(smb_krb5);
     332       24302 :                         if (smb_krb5->packet == NULL) {
     333           0 :                                 talloc_free(smb_krb5);
     334           0 :                                 return ENOMEM;
     335             :                         }
     336       24302 :                         packet_set_private(smb_krb5->packet, smb_krb5);
     337       24302 :                         packet_set_socket(smb_krb5->packet, smb_krb5->sock);
     338       24302 :                         packet_set_callback(smb_krb5->packet, smb_krb5_full_packet);
     339       24302 :                         packet_set_full_request(smb_krb5->packet, packet_full_request_u32);
     340       24302 :                         packet_set_error_handler(smb_krb5->packet, smb_krb5_error_handler);
     341       24302 :                         packet_set_event_context(smb_krb5->packet, ev);
     342       24302 :                         packet_set_fde(smb_krb5->packet, smb_krb5->fde);
     343             : 
     344       24302 :                         smb_krb5->request = data_blob_talloc(smb_krb5, NULL, send_blob.length + 4);
     345       24302 :                         RSIVAL(smb_krb5->request.data, 0, send_blob.length);
     346       24302 :                         memcpy(smb_krb5->request.data+4, send_blob.data, send_blob.length);
     347       24302 :                         packet_send(smb_krb5->packet, smb_krb5->request);
     348       24302 :                         break;
     349           0 :                 case KRB5_KRBHST_HTTP:
     350           0 :                         TALLOC_FREE(frame);
     351           0 :                         return EINVAL;
     352             :                 }
     353    15570442 :                 while ((NT_STATUS_IS_OK(smb_krb5->status)) && !smb_krb5->reply.length) {
     354    15524846 :                         if (tevent_loop_once(ev) != 0) {
     355           0 :                                 TALLOC_FREE(frame);
     356           0 :                                 return EINVAL;
     357             :                         }
     358             : 
     359    15524846 :                         if (func) {
     360             :                                 /* After each and every event loop, reset the
     361             :                                  * send_to_kdc pointers to what they were when
     362             :                                  * we entered this loop.  That way, if a
     363             :                                  * nested event has invalidated them, we put
     364             :                                  * it back before we return to the heimdal
     365             :                                  * code */
     366    15486498 :                                 ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     367             :                                                                     NULL, /* send_to_realm */
     368             :                                                                     func,
     369             :                                                                     data);
     370    15486498 :                                 if (ret != 0) {
     371           0 :                                         TALLOC_FREE(frame);
     372           0 :                                         return ret;
     373             :                                 }
     374             :                         }
     375             :                 }
     376       45596 :                 if (NT_STATUS_EQUAL(smb_krb5->status, NT_STATUS_IO_TIMEOUT)) {
     377           4 :                         talloc_free(smb_krb5);
     378           4 :                         continue;
     379             :                 }
     380             : 
     381       45592 :                 if (!NT_STATUS_IS_OK(smb_krb5->status)) {
     382           0 :                         struct tsocket_address *addr = socket_address_to_tsocket_address(smb_krb5, remote_addr);
     383           0 :                         const char *addr_string = NULL;
     384           0 :                         if (addr) {
     385           0 :                                 addr_string = tsocket_address_inet_addr_string(addr, smb_krb5);
     386             :                         } else {
     387           0 :                                 addr_string = NULL;
     388             :                         }
     389           0 :                         DEBUG(2,("Error reading smb_krb5 reply packet: %s from %s\n", nt_errstr(smb_krb5->status),
     390             :                                  addr_string));
     391           0 :                         talloc_free(smb_krb5);
     392           0 :                         continue;
     393             :                 }
     394             : 
     395       45592 :                 ret = krb5_data_copy(recv_buf, smb_krb5->reply.data, smb_krb5->reply.length);
     396       45592 :                 if (ret) {
     397           0 :                         TALLOC_FREE(frame);
     398           0 :                         return ret;
     399             :                 }
     400       45592 :                 talloc_free(smb_krb5);
     401             : 
     402       45592 :                 break;
     403             :         }
     404       45596 :         TALLOC_FREE(frame);
     405       45596 :         if (a) {
     406       45592 :                 return 0;
     407             :         }
     408           4 :         return KRB5_KDC_UNREACH;
     409             : }
     410             : 
     411       31847 : krb5_error_code smb_krb5_send_and_recv_func(struct smb_krb5_context *smb_krb5_context,
     412             :                                             void *data,
     413             :                                             krb5_krbhst_info *hi,
     414             :                                             time_t timeout,
     415             :                                             const krb5_data *send_buf,
     416             :                                             krb5_data *recv_buf)
     417             : {
     418        1755 :         krb5_error_code ret;
     419        1755 :         struct addrinfo *ai;
     420             : 
     421        1755 :         struct tevent_context *ev;
     422       31847 :         TALLOC_CTX *frame = talloc_stackframe();
     423       31847 :         if (frame == NULL) {
     424           0 :                 return ENOMEM;
     425             :         }
     426             : 
     427       31847 :         if (data == NULL) {
     428             :                 /* If no event context was available, then create one for this loop */
     429           0 :                 ev = samba_tevent_context_init(frame);
     430           0 :                 if (ev == NULL) {
     431           0 :                         TALLOC_FREE(frame);
     432           0 :                         return ENOMEM;
     433             :                 }
     434             :         } else {
     435       31847 :                 ev = talloc_get_type_abort(data, struct tevent_context);
     436             :         }
     437             : 
     438       31847 :         ret = krb5_krbhst_get_addrinfo(smb_krb5_context->krb5_context, hi, &ai);
     439       31847 :         if (ret) {
     440           0 :                 TALLOC_FREE(frame);
     441           0 :                 return ret;
     442             :         }
     443             : 
     444       31847 :         ret = smb_krb5_send_and_recv_func_int(smb_krb5_context,
     445             :                                               ev, hi, ai,
     446             :                                               smb_krb5_send_and_recv_func,
     447             :                                               data, timeout, send_buf, recv_buf);
     448       31847 :         TALLOC_FREE(frame);
     449       31847 :         return ret;
     450             : }
     451             : 
     452       13749 : krb5_error_code smb_krb5_send_and_recv_func_forced_tcp(struct smb_krb5_context *smb_krb5_context,
     453             :                                                        struct addrinfo *ai,
     454             :                                                        time_t timeout,
     455             :                                                        const krb5_data *send_buf,
     456             :                                                        krb5_data *recv_buf)
     457             : {
     458           0 :         krb5_error_code k5ret;
     459       13749 :         krb5_krbhst_info hi = {
     460             :                 .proto = KRB5_KRBHST_TCP,
     461             :         };
     462           0 :         struct tevent_context *ev;
     463       13749 :         TALLOC_CTX *frame = talloc_stackframe();
     464       13749 :         if (frame == NULL) {
     465           0 :                 return ENOMEM;
     466             :         }
     467             : 
     468             :         /* no event context is passed in, create one for this loop */
     469       13749 :         ev = samba_tevent_context_init(frame);
     470       13749 :         if (ev == NULL) {
     471           0 :                 TALLOC_FREE(frame);
     472           0 :                 return ENOMEM;
     473             :         }
     474             : 
     475             :         /* No need to pass in send_and_recv functions, we won't nest on this private event loop */
     476       13749 :         k5ret = smb_krb5_send_and_recv_func_int(smb_krb5_context, ev, &hi, ai, NULL, NULL,
     477             :                                                 timeout, send_buf, recv_buf);
     478       13749 :         TALLOC_FREE(frame);
     479       13749 :         return k5ret;
     480             : }
     481             : 
     482             : static struct db_context *smb_krb5_plugin_db;
     483             : 
     484             : struct smb_krb5_send_to_kdc_state {
     485             :         intptr_t key_ptr;
     486             :         struct smb_krb5_context *smb_krb5_context;
     487             :         smb_krb5_send_to_realm_func send_to_realm;
     488             :         smb_krb5_send_to_kdc_func send_to_kdc;
     489             :         void *private_data;
     490             : };
     491             : 
     492       10610 : static int smb_krb5_send_to_kdc_state_destructor(struct smb_krb5_send_to_kdc_state *state)
     493             : {
     494       10610 :         TDB_DATA key = make_tdb_data((uint8_t *)&state->key_ptr, sizeof(state->key_ptr));
     495       10610 :         struct db_record *rec = NULL;
     496         123 :         NTSTATUS status;
     497             : 
     498       10610 :         rec = dbwrap_fetch_locked(smb_krb5_plugin_db, state, key);
     499       10610 :         if (rec == NULL) {
     500           0 :                 return 0;
     501             :         }
     502             : 
     503       10610 :         status = dbwrap_record_delete(rec);
     504       10610 :         TALLOC_FREE(rec);
     505       10610 :         if (!NT_STATUS_IS_OK(status)) {
     506           0 :                 return -1;
     507             :         }
     508             : 
     509       10610 :         state->smb_krb5_context = NULL;
     510       10610 :         return 0;
     511             : }
     512             : 
     513    15511909 : krb5_error_code smb_krb5_set_send_to_kdc_func(struct smb_krb5_context *smb_krb5_context,
     514             :                                               smb_krb5_send_to_realm_func send_to_realm,
     515             :                                               smb_krb5_send_to_kdc_func send_to_kdc,
     516             :                                               void *private_data)
     517             : {
     518    15511909 :         intptr_t key_ptr = (intptr_t)smb_krb5_context->krb5_context;
     519    15511909 :         TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
     520    15511909 :         intptr_t value_ptr = (intptr_t)NULL;
     521    15511909 :         TDB_DATA value = make_tdb_data(NULL, 0);
     522    15511909 :         struct db_record *rec = NULL;
     523    15511909 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     524        5302 :         NTSTATUS status;
     525             : 
     526    15511909 :         rec = dbwrap_fetch_locked(smb_krb5_plugin_db, smb_krb5_context, key);
     527    15511909 :         if (rec == NULL) {
     528           0 :                 return ENOMEM;
     529             :         }
     530             : 
     531    15511909 :         value = dbwrap_record_get_value(rec);
     532    15511909 :         if (value.dsize != 0) {
     533    15501261 :                 SMB_ASSERT(value.dsize == sizeof(value_ptr));
     534    15501261 :                 memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
     535    15501261 :                 state = talloc_get_type_abort((const void *)value_ptr,
     536             :                                               struct smb_krb5_send_to_kdc_state);
     537    15501261 :                 if (send_to_realm == NULL && send_to_kdc == NULL) {
     538           0 :                         status = dbwrap_record_delete(rec);
     539           0 :                         TALLOC_FREE(rec);
     540           0 :                         if (!NT_STATUS_IS_OK(status)) {
     541           0 :                                 return EINVAL;
     542             :                         }
     543           0 :                         return 0;
     544             :                 }
     545    15501261 :                 state->send_to_realm = send_to_realm;
     546    15501261 :                 state->send_to_kdc = send_to_kdc;
     547    15501261 :                 state->private_data = private_data;
     548    15501261 :                 TALLOC_FREE(rec);
     549    15501261 :                 return 0;
     550             :         }
     551             : 
     552       10648 :         if (send_to_kdc == NULL && send_to_realm == NULL) {
     553           0 :                 TALLOC_FREE(rec);
     554           0 :                 return 0;
     555             :         }
     556             : 
     557       10648 :         state = talloc_zero(smb_krb5_context,
     558             :                             struct smb_krb5_send_to_kdc_state);
     559       10648 :         if (state == NULL) {
     560           0 :                 TALLOC_FREE(rec);
     561           0 :                 return ENOMEM;
     562             :         }
     563       10648 :         state->key_ptr = key_ptr;
     564       10648 :         state->smb_krb5_context = smb_krb5_context;
     565       10648 :         state->send_to_realm = send_to_realm;
     566       10648 :         state->send_to_kdc = send_to_kdc;
     567       10648 :         state->private_data = private_data;
     568             : 
     569       10648 :         value_ptr = (intptr_t)state;
     570       10648 :         value = make_tdb_data((uint8_t *)&value_ptr, sizeof(value_ptr));
     571             : 
     572       10648 :         status = dbwrap_record_store(rec, value, TDB_INSERT);
     573       10648 :         TALLOC_FREE(rec);
     574       10648 :         if (!NT_STATUS_IS_OK(status)) {
     575           0 :                 return EINVAL;
     576             :         }
     577       10648 :         talloc_set_destructor(state, smb_krb5_send_to_kdc_state_destructor);
     578             : 
     579       10648 :         return 0;
     580             : }
     581             : 
     582       37501 : static krb5_error_code smb_krb5_plugin_init(krb5_context context, void **pctx)
     583             : {
     584       37501 :         *pctx = NULL;
     585       37501 :         return 0;
     586             : }
     587             : 
     588        5218 : static void smb_krb5_plugin_fini(void *ctx)
     589             : {
     590        5218 : }
     591             : 
     592       68019 : static void smb_krb5_send_to_kdc_state_parser(TDB_DATA key, TDB_DATA value,
     593             :                                               void *private_data)
     594             : {
     595       68019 :         struct smb_krb5_send_to_kdc_state **state =
     596             :                 (struct smb_krb5_send_to_kdc_state **)private_data;
     597        2925 :         intptr_t value_ptr;
     598             : 
     599       68019 :         SMB_ASSERT(value.dsize == sizeof(value_ptr));
     600       68019 :         memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
     601       68019 :         *state = talloc_get_type_abort((const void *)value_ptr,
     602             :                                        struct smb_krb5_send_to_kdc_state);
     603       68019 : }
     604             : 
     605             : static struct smb_krb5_send_to_kdc_state *
     606      160240 : smb_krb5_send_to_kdc_get_state(krb5_context context)
     607             : {
     608      160240 :         intptr_t key_ptr = (intptr_t)context;
     609      160240 :         TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
     610      160240 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     611        6241 :         NTSTATUS status;
     612             : 
     613      160240 :         status = dbwrap_parse_record(smb_krb5_plugin_db, key,
     614             :                                      smb_krb5_send_to_kdc_state_parser,
     615             :                                      &state);
     616      160240 :         if (!NT_STATUS_IS_OK(status)) {
     617       88905 :                 return NULL;
     618             :         }
     619             : 
     620       68019 :         return state;
     621             : }
     622             : 
     623       72646 : static krb5_error_code smb_krb5_plugin_send_to_kdc(krb5_context context,
     624             :                                                    void *ctx,
     625             :                                                    krb5_krbhst_info *ho,
     626             :                                                    time_t timeout,
     627             :                                                    const krb5_data *in,
     628             :                                                    krb5_data *out)
     629             : {
     630       72646 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     631             : 
     632       72646 :         state = smb_krb5_send_to_kdc_get_state(context);
     633       72646 :         if (state == NULL) {
     634       39141 :                 return KRB5_PLUGIN_NO_HANDLE;
     635             :         }
     636             : 
     637       31847 :         if (state->send_to_kdc == NULL) {
     638           0 :                 return KRB5_PLUGIN_NO_HANDLE;
     639             :         }
     640             : 
     641       31847 :         return state->send_to_kdc(state->smb_krb5_context,
     642             :                                   state->private_data,
     643             :                                   ho, timeout, in, out);
     644             : }
     645             : 
     646       87594 : static krb5_error_code smb_krb5_plugin_send_to_realm(krb5_context context,
     647             :                                                      void *ctx,
     648             :                                                      krb5_const_realm realm,
     649             :                                                      time_t timeout,
     650             :                                                      const krb5_data *in,
     651             :                                                      krb5_data *out)
     652             : {
     653       87594 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     654             : 
     655       87594 :         state = smb_krb5_send_to_kdc_get_state(context);
     656       87594 :         if (state == NULL) {
     657       49764 :                 return KRB5_PLUGIN_NO_HANDLE;
     658             :         }
     659             : 
     660       36172 :         if (state->send_to_realm == NULL) {
     661       20713 :                 return KRB5_PLUGIN_NO_HANDLE;
     662             :         }
     663             : 
     664       14289 :         return state->send_to_realm(state->smb_krb5_context,
     665             :                                     state->private_data,
     666             :                                     realm, timeout, in, out);
     667             : }
     668             : 
     669             : static krb5plugin_send_to_kdc_ftable smb_krb5_plugin_ftable = {
     670             :         KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
     671             :         smb_krb5_plugin_init,
     672             :         smb_krb5_plugin_fini,
     673             :         smb_krb5_plugin_send_to_kdc,
     674             :         smb_krb5_plugin_send_to_realm
     675             : };
     676             : #endif
     677             : 
     678             : krb5_error_code
     679      472903 : smb_krb5_init_context_basic(TALLOC_CTX *tmp_ctx,
     680             :                             struct loadparm_context *lp_ctx,
     681             :                             krb5_context *_krb5_context)
     682             : {
     683       13153 :         krb5_error_code ret;
     684             : #ifdef SAMBA4_USES_HEIMDAL
     685       13153 :         char **config_files;
     686       13153 :         const char *config_file, *realm;
     687             : #endif
     688       13153 :         krb5_context krb5_ctx;
     689             : 
     690      472903 :         ret = smb_krb5_init_context_common(&krb5_ctx);
     691      472903 :         if (ret) {
     692           0 :                 return ret;
     693             :         }
     694             : 
     695             :         /* The MIT Kerberos build relies on using the system krb5.conf file.
     696             :          * If you really want to use another file please set KRB5_CONFIG
     697             :          * accordingly. */
     698             : #ifdef SAMBA4_USES_HEIMDAL
     699      389585 :         config_file = lpcfg_config_path(tmp_ctx, lp_ctx, "krb5.conf");
     700      389585 :         if (!config_file) {
     701           0 :                 krb5_free_context(krb5_ctx);
     702           0 :                 return ENOMEM;
     703             :         }
     704             : 
     705             :         /* Use our local krb5.conf file by default */
     706      389585 :         ret = krb5_prepend_config_files_default(config_file, &config_files);
     707      389585 :         if (ret) {
     708           0 :                 DEBUG(1,("krb5_prepend_config_files_default failed (%s)\n",
     709             :                          smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     710           0 :                 krb5_free_context(krb5_ctx);
     711           0 :                 return ret;
     712             :         }
     713             : 
     714      389585 :         ret = krb5_set_config_files(krb5_ctx, config_files);
     715      389585 :         krb5_free_config_files(config_files);
     716      389585 :         if (ret) {
     717           0 :                 DEBUG(1,("krb5_set_config_files failed (%s)\n",
     718             :                          smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     719           0 :                 krb5_free_context(krb5_ctx);
     720           0 :                 return ret;
     721             :         }
     722             : 
     723             :         /*
     724             :          * This is already called in smb_krb5_init_context_common(),
     725             :          * but krb5_set_config_files() may resets it.
     726             :          */
     727      389585 :         krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
     728             : 
     729      389585 :         realm = lpcfg_realm(lp_ctx);
     730      389585 :         if (realm != NULL) {
     731      389585 :                 ret = krb5_set_default_realm(krb5_ctx, realm);
     732      389585 :                 if (ret) {
     733           0 :                         DEBUG(1,("krb5_set_default_realm failed (%s)\n",
     734             :                                  smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     735           0 :                         krb5_free_context(krb5_ctx);
     736           0 :                         return ret;
     737             :                 }
     738             :         }
     739             : 
     740      389585 :         if (smb_krb5_plugin_db == NULL) {
     741             :                 /*
     742             :                  * while krb5_plugin_register() takes a krb5_context,
     743             :                  * plugins are registered into a global list, so
     744             :                  * we only do that once
     745             :                  *
     746             :                  * We maintain a separate dispatch table for per
     747             :                  * krb5_context state.
     748             :                  */
     749       37441 :                 ret = krb5_plugin_register(krb5_ctx, PLUGIN_TYPE_DATA,
     750             :                                      KRB5_PLUGIN_SEND_TO_KDC,
     751             :                                      &smb_krb5_plugin_ftable);
     752       37441 :                 if (ret) {
     753           0 :                         DEBUG(1,("krb5_plugin_register(KRB5_PLUGIN_SEND_TO_KDC) failed (%s)\n",
     754             :                                  smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     755           0 :                         krb5_free_context(krb5_ctx);
     756           0 :                         return ret;
     757             :                 }
     758       37441 :                 smb_krb5_plugin_db = db_open_rbt(NULL);
     759       37441 :                 if (smb_krb5_plugin_db == NULL) {
     760           0 :                         DEBUG(1,("db_open_rbt() failed\n"));
     761           0 :                         krb5_free_context(krb5_ctx);
     762           0 :                         return ENOMEM;
     763             :                 }
     764             :         }
     765             : #endif
     766      472903 :         *_krb5_context = krb5_ctx;
     767      472903 :         return 0;
     768             : }
     769             : 
     770      472285 : krb5_error_code smb_krb5_init_context(void *parent_ctx,
     771             :                                       struct loadparm_context *lp_ctx,
     772             :                                       struct smb_krb5_context **smb_krb5_context)
     773             : {
     774       13153 :         krb5_error_code ret;
     775       13153 :         TALLOC_CTX *tmp_ctx;
     776       13153 :         krb5_context kctx;
     777             : #ifdef SAMBA4_USES_HEIMDAL
     778       13153 :         krb5_log_facility *logf;
     779             : #endif
     780             : 
     781      472285 :         tmp_ctx = talloc_new(parent_ctx);
     782      472285 :         *smb_krb5_context = talloc_zero(tmp_ctx, struct smb_krb5_context);
     783             : 
     784      472285 :         if (!*smb_krb5_context || !tmp_ctx) {
     785           0 :                 talloc_free(tmp_ctx);
     786           0 :                 return ENOMEM;
     787             :         }
     788             : 
     789      472285 :         ret = smb_krb5_init_context_basic(tmp_ctx, lp_ctx, &kctx);
     790      472285 :         if (ret) {
     791           0 :                 DEBUG(1,("smb_krb5_context_init_basic failed (%s)\n",
     792             :                          error_message(ret)));
     793           0 :                 talloc_free(tmp_ctx);
     794           0 :                 return ret;
     795             :         }
     796      472285 :         (*smb_krb5_context)->krb5_context = kctx;
     797             : 
     798      472285 :         talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destroy);
     799             : 
     800             : #ifdef SAMBA4_USES_HEIMDAL
     801             :         /* TODO: Should we have a different name here? */
     802      389249 :         ret = krb5_initlog(kctx, "Samba", &logf);
     803             : 
     804      389249 :         if (ret) {
     805           0 :                 DEBUG(1,("krb5_initlog failed (%s)\n",
     806             :                          smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
     807           0 :                 talloc_free(tmp_ctx);
     808           0 :                 return ret;
     809             :         }
     810      389249 :         (*smb_krb5_context)->pvt_log_data = logf;
     811             : 
     812      389249 :         ret = krb5_addlog_func(kctx, logf, 0 /* min */, -1 /* max */,
     813             :                                smb_krb5_debug_wrapper,
     814             :                                 smb_krb5_debug_close, NULL);
     815      389249 :         if (ret) {
     816           0 :                 DEBUG(1,("krb5_addlog_func failed (%s)\n",
     817             :                          smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
     818           0 :                 talloc_free(tmp_ctx);
     819           0 :                 return ret;
     820             :         }
     821      389249 :         krb5_set_warn_dest(kctx, logf);
     822             : #endif
     823      472285 :         talloc_steal(parent_ctx, *smb_krb5_context);
     824      472285 :         talloc_free(tmp_ctx);
     825             : 
     826      472285 :         return 0;
     827             : }
     828             : 
     829             : #ifdef SAMBA4_USES_HEIMDAL
     830       11281 : krb5_error_code smb_krb5_context_set_event_ctx(struct smb_krb5_context *smb_krb5_context,
     831             :                                                struct tevent_context *ev,
     832             :                                                struct tevent_context **previous_ev)
     833             : {
     834         585 :         int ret;
     835       11281 :         if (!ev) {
     836           0 :                 return EINVAL;
     837             :         }
     838             : 
     839       11281 :         *previous_ev = smb_krb5_context->current_ev;
     840             : 
     841       11281 :         smb_krb5_context->current_ev = talloc_reference(smb_krb5_context, ev);
     842       11281 :         if (!smb_krb5_context->current_ev) {
     843           0 :                 return ENOMEM;
     844             :         }
     845             : 
     846             :         /* Set use of our socket lib */
     847       11281 :         ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     848             :                                             NULL, /* send_to_realm */
     849             :                                             smb_krb5_send_and_recv_func,
     850             :                                             ev);
     851       11281 :         if (ret) {
     852           0 :                 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     853           0 :                 DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
     854             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
     855           0 :                 talloc_free(tmp_ctx);
     856           0 :                 talloc_unlink(smb_krb5_context, smb_krb5_context->current_ev);
     857           0 :                 smb_krb5_context->current_ev = NULL;
     858           0 :                 return ret;
     859             :         }
     860       10696 :         return 0;
     861             : }
     862             : 
     863       11281 : krb5_error_code smb_krb5_context_remove_event_ctx(struct smb_krb5_context *smb_krb5_context,
     864             :                                                   struct tevent_context *previous_ev,
     865             :                                                   struct tevent_context *ev)
     866             : {
     867         585 :         int ret;
     868       11281 :         talloc_unlink(smb_krb5_context, ev);
     869             :         /* If there was a mismatch with things happening on a stack, then don't wipe things */
     870       11281 :         smb_krb5_context->current_ev = previous_ev;
     871             :         /* Set use of our socket lib */
     872       11281 :         ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     873             :                                             NULL, /* send_to_realm */
     874             :                                             smb_krb5_send_and_recv_func,
     875             :                                             previous_ev);
     876       11281 :         if (ret) {
     877           0 :                 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     878           0 :                 DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
     879             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
     880           0 :                 talloc_free(tmp_ctx);
     881           0 :                 return ret;
     882             :         }
     883       10696 :         return 0;
     884             : }
     885             : #endif

Generated by: LCOV version 1.14