LCOV - code coverage report
Current view: top level - source4/auth/kerberos - krb5_init_context.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 307 428 71.7 %
Date: 2024-04-21 15:09:00 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      476137 : static krb5_error_code smb_krb5_context_destroy(struct smb_krb5_context *ctx)
      62             : {
      63             : #ifdef SAMBA4_USES_HEIMDAL
      64      393185 :         if (ctx->pvt_log_data) {
      65             :                 /* Otherwise krb5_free_context will try and close what we
      66             :                  * have already free()ed */
      67      393185 :                 krb5_set_warn_dest(ctx->krb5_context, NULL);
      68      393185 :                 krb5_closelog(ctx->krb5_context,
      69      393185 :                                 (krb5_log_facility *)ctx->pvt_log_data);
      70             :         }
      71             : #endif
      72      476137 :         krb5_free_context(ctx->krb5_context);
      73      476137 :         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      393185 : static void smb_krb5_debug_close(void *private_data) {
      79      393185 :         return;
      80             : }
      81             : #endif
      82             : 
      83             : #ifdef SAMBA4_USES_HEIMDAL
      84     2182483 : 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     2182483 :         DEBUGC(DBGC_KERBEROS, 3, ("Kerberos: %s\n", msg));
      91     2182483 : }
      92             : #endif
      93             : 
      94             : #ifdef SAMBA4_USES_HEIMDAL
      95             : /*
      96             :   handle recv events on a smb_krb5 socket
      97             : */
      98       21765 : static void smb_krb5_socket_recv(struct smb_krb5_socket *smb_krb5)
      99             : {
     100       21765 :         TALLOC_CTX *tmp_ctx = talloc_new(smb_krb5);
     101        1170 :         DATA_BLOB blob;
     102        1170 :         size_t nread, dsize;
     103             : 
     104       21765 :         smb_krb5->status = socket_pending(smb_krb5->sock, &dsize);
     105       21765 :         if (!NT_STATUS_IS_OK(smb_krb5->status)) {
     106           0 :                 talloc_free(tmp_ctx);
     107           0 :                 return;
     108             :         }
     109             : 
     110       21765 :         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
     111       21765 :         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       21765 :         smb_krb5->status = socket_recv(smb_krb5->sock, blob.data, blob.length, &nread);
     118       21765 :         if (!NT_STATUS_IS_OK(smb_krb5->status)) {
     119           0 :                 talloc_free(tmp_ctx);
     120           0 :                 return;
     121             :         }
     122       21765 :         blob.length = nread;
     123             : 
     124       21765 :         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       21765 :         DEBUG(4,("Received smb_krb5 packet of length %d\n",
     131             :                  (int)blob.length));
     132             : 
     133       21765 :         talloc_steal(smb_krb5, blob.data);
     134       21765 :         smb_krb5->reply = blob;
     135       21765 :         talloc_free(tmp_ctx);
     136             : }
     137             : 
     138       26182 : static NTSTATUS smb_krb5_full_packet(void *private_data, DATA_BLOB data)
     139             : {
     140       26182 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     141       26182 :         talloc_steal(smb_krb5, data.data);
     142       26182 :         smb_krb5->reply = data;
     143       26182 :         smb_krb5->reply.length -= 4;
     144       26182 :         smb_krb5->reply.data += 4;
     145       26182 :         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    16452917 : 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    16452917 :         len = smb_krb5->request.length;
     176    16452917 :         status = socket_send(smb_krb5->sock, &smb_krb5->request, &len);
     177             : 
     178    16452917 :         if (!NT_STATUS_IS_OK(status)) return;
     179             : 
     180       21765 :         TEVENT_FD_READABLE(smb_krb5->fde);
     181             : 
     182       21765 :         TEVENT_FD_NOT_WRITEABLE(smb_krb5->fde);
     183       21765 :         return;
     184             : }
     185             : 
     186             : 
     187             : /*
     188             :   handle fd events on a smb_krb5_socket
     189             : */
     190    16550964 : static void smb_krb5_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     191             :                                  uint16_t flags, void *private_data)
     192             : {
     193    16550964 :         struct smb_krb5_socket *smb_krb5 = talloc_get_type(private_data, struct smb_krb5_socket);
     194    16550964 :         switch (smb_krb5->hi->proto) {
     195    16474682 :         case KRB5_KRBHST_UDP:
     196    16474682 :                 if (flags & TEVENT_FD_READ) {
     197       21765 :                         smb_krb5_socket_recv(smb_krb5);
     198       21765 :                         return;
     199             :                 }
     200    16452917 :                 if (flags & TEVENT_FD_WRITE) {
     201    16452917 :                         smb_krb5_socket_send(smb_krb5);
     202    16452917 :                         return;
     203             :                 }
     204             :                 /* not reached */
     205           0 :                 return;
     206       76282 :         case KRB5_KRBHST_TCP:
     207       76282 :                 if (flags & TEVENT_FD_READ) {
     208       50050 :                         packet_recv(smb_krb5->packet);
     209       50050 :                         return;
     210             :                 }
     211       26232 :                 if (flags & TEVENT_FD_WRITE) {
     212       26232 :                         packet_queue_run(smb_krb5->packet);
     213       26232 :                         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       47951 : 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       47951 :         TALLOC_CTX *frame = talloc_stackframe();
     242       47951 :         if (frame == NULL) {
     243           0 :                 return ENOMEM;
     244             :         }
     245             : 
     246       47951 :         send_blob = data_blob_const(send_buf->data, send_buf->length);
     247             : 
     248       47955 :         for (a = ai; a; a = a->ai_next) {
     249        1755 :                 struct socket_address *remote_addr;
     250       47951 :                 smb_krb5 = talloc(frame, struct smb_krb5_socket);
     251       47951 :                 if (!smb_krb5) {
     252           0 :                         TALLOC_FREE(frame);
     253           0 :                         return ENOMEM;
     254             :                 }
     255       47951 :                 smb_krb5->hi = hi;
     256             : 
     257       47951 :                 switch (a->ai_family) {
     258       46196 :                 case PF_INET:
     259       46196 :                         name = "ipv4";
     260       46196 :                         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       47951 :                 status = NT_STATUS_INVALID_PARAMETER;
     272       47951 :                 switch (hi->proto) {
     273       21769 :                 case KRB5_KRBHST_UDP:
     274       21769 :                         status = socket_create(smb_krb5, name,
     275             :                                                SOCKET_TYPE_DGRAM,
     276             :                                                &smb_krb5->sock, 0);
     277       21769 :                         break;
     278       26182 :                 case KRB5_KRBHST_TCP:
     279       26182 :                         status = socket_create(smb_krb5, name,
     280             :                                                SOCKET_TYPE_STREAM,
     281             :                                                &smb_krb5->sock, 0);
     282       26182 :                         break;
     283           0 :                 case KRB5_KRBHST_HTTP:
     284           0 :                         TALLOC_FREE(frame);
     285           0 :                         return EINVAL;
     286             :                 }
     287       47951 :                 if (!NT_STATUS_IS_OK(status)) {
     288           0 :                         talloc_free(smb_krb5);
     289           4 :                         continue;
     290             :                 }
     291             : 
     292       47951 :                 remote_addr = socket_address_from_sockaddr(smb_krb5, a->ai_addr, a->ai_addrlen);
     293       47951 :                 if (!remote_addr) {
     294           0 :                         talloc_free(smb_krb5);
     295           0 :                         continue;
     296             :                 }
     297             : 
     298       47951 :                 status = socket_connect_ev(smb_krb5->sock, NULL, remote_addr, 0, ev);
     299       47951 :                 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       47951 :                 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       47951 :                 tevent_fd_set_close_fn(smb_krb5->fde, socket_tevent_fd_close_fn);
     315       47951 :                 socket_set_flags(smb_krb5->sock, SOCKET_FLAG_NOCLOSE);
     316             : 
     317       47951 :                 tevent_add_timer(ev, smb_krb5,
     318             :                                  timeval_current_ofs(timeout, 0),
     319             :                                  smb_krb5_request_timeout, smb_krb5);
     320             : 
     321       47951 :                 smb_krb5->status = NT_STATUS_OK;
     322       47951 :                 smb_krb5->reply = data_blob(NULL, 0);
     323             : 
     324       47951 :                 switch (hi->proto) {
     325       21769 :                 case KRB5_KRBHST_UDP:
     326       21769 :                         TEVENT_FD_WRITEABLE(smb_krb5->fde);
     327       21769 :                         smb_krb5->request = send_blob;
     328       21769 :                         break;
     329       26182 :                 case KRB5_KRBHST_TCP:
     330             : 
     331       26182 :                         smb_krb5->packet = packet_init(smb_krb5);
     332       26182 :                         if (smb_krb5->packet == NULL) {
     333           0 :                                 talloc_free(smb_krb5);
     334           0 :                                 return ENOMEM;
     335             :                         }
     336       26182 :                         packet_set_private(smb_krb5->packet, smb_krb5);
     337       26182 :                         packet_set_socket(smb_krb5->packet, smb_krb5->sock);
     338       26182 :                         packet_set_callback(smb_krb5->packet, smb_krb5_full_packet);
     339       26182 :                         packet_set_full_request(smb_krb5->packet, packet_full_request_u32);
     340       26182 :                         packet_set_error_handler(smb_krb5->packet, smb_krb5_error_handler);
     341       26182 :                         packet_set_event_context(smb_krb5->packet, ev);
     342       26182 :                         packet_set_fde(smb_krb5->packet, smb_krb5->fde);
     343             : 
     344       26182 :                         smb_krb5->request = data_blob_talloc(smb_krb5, NULL, send_blob.length + 4);
     345       26182 :                         RSIVAL(smb_krb5->request.data, 0, send_blob.length);
     346       26182 :                         memcpy(smb_krb5->request.data+4, send_blob.data, send_blob.length);
     347       26182 :                         packet_send(smb_krb5->packet, smb_krb5->request);
     348       26182 :                         break;
     349           0 :                 case KRB5_KRBHST_HTTP:
     350           0 :                         TALLOC_FREE(frame);
     351           0 :                         return EINVAL;
     352             :                 }
     353    17048827 :                 while ((NT_STATUS_IS_OK(smb_krb5->status)) && !smb_krb5->reply.length) {
     354    17000876 :                         if (tevent_loop_once(ev) != 0) {
     355           0 :                                 TALLOC_FREE(frame);
     356           0 :                                 return EINVAL;
     357             :                         }
     358             : 
     359    17000876 :                         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    16958163 :                                 ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     367             :                                                                     NULL, /* send_to_realm */
     368             :                                                                     func,
     369             :                                                                     data);
     370    16958163 :                                 if (ret != 0) {
     371           0 :                                         TALLOC_FREE(frame);
     372           0 :                                         return ret;
     373             :                                 }
     374             :                         }
     375             :                 }
     376       47951 :                 if (NT_STATUS_EQUAL(smb_krb5->status, NT_STATUS_IO_TIMEOUT)) {
     377           4 :                         talloc_free(smb_krb5);
     378           4 :                         continue;
     379             :                 }
     380             : 
     381       47947 :                 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       47947 :                 ret = krb5_data_copy(recv_buf, smb_krb5->reply.data, smb_krb5->reply.length);
     396       47947 :                 if (ret) {
     397           0 :                         TALLOC_FREE(frame);
     398           0 :                         return ret;
     399             :                 }
     400       47947 :                 talloc_free(smb_krb5);
     401             : 
     402       47947 :                 break;
     403             :         }
     404       47951 :         TALLOC_FREE(frame);
     405       47951 :         if (a) {
     406       47947 :                 return 0;
     407             :         }
     408           4 :         return KRB5_KDC_UNREACH;
     409             : }
     410             : 
     411       32558 : 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       32558 :         TALLOC_CTX *frame = talloc_stackframe();
     423       32558 :         if (frame == NULL) {
     424           0 :                 return ENOMEM;
     425             :         }
     426             : 
     427       32558 :         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       32558 :                 ev = talloc_get_type_abort(data, struct tevent_context);
     436             :         }
     437             : 
     438       32558 :         ret = krb5_krbhst_get_addrinfo(smb_krb5_context->krb5_context, hi, &ai);
     439       32558 :         if (ret) {
     440           0 :                 TALLOC_FREE(frame);
     441           0 :                 return ret;
     442             :         }
     443             : 
     444       32558 :         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       32558 :         TALLOC_FREE(frame);
     449       32558 :         return ret;
     450             : }
     451             : 
     452       15393 : 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       15393 :         krb5_krbhst_info hi = {
     460             :                 .proto = KRB5_KRBHST_TCP,
     461             :         };
     462           0 :         struct tevent_context *ev;
     463       15393 :         TALLOC_CTX *frame = talloc_stackframe();
     464       15393 :         if (frame == NULL) {
     465           0 :                 return ENOMEM;
     466             :         }
     467             : 
     468             :         /* no event context is passed in, create one for this loop */
     469       15393 :         ev = samba_tevent_context_init(frame);
     470       15393 :         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       15393 :         k5ret = smb_krb5_send_and_recv_func_int(smb_krb5_context, ev, &hi, ai, NULL, NULL,
     477             :                                                 timeout, send_buf, recv_buf);
     478       15393 :         TALLOC_FREE(frame);
     479       15393 :         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       11388 : static int smb_krb5_send_to_kdc_state_destructor(struct smb_krb5_send_to_kdc_state *state)
     493             : {
     494       11388 :         TDB_DATA key = make_tdb_data((uint8_t *)&state->key_ptr, sizeof(state->key_ptr));
     495         123 :         NTSTATUS status;
     496             : 
     497       11388 :         status = dbwrap_delete(smb_krb5_plugin_db, key);
     498       11388 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     499           0 :                 status = NT_STATUS_OK;
     500             :         }
     501       11388 :         if (!NT_STATUS_IS_OK(status)) {
     502           0 :                 return -1;
     503             :         }
     504             : 
     505       11388 :         state->smb_krb5_context = NULL;
     506       11388 :         return 0;
     507             : }
     508             : 
     509    16985044 : krb5_error_code smb_krb5_set_send_to_kdc_func(struct smb_krb5_context *smb_krb5_context,
     510             :                                               smb_krb5_send_to_realm_func send_to_realm,
     511             :                                               smb_krb5_send_to_kdc_func send_to_kdc,
     512             :                                               void *private_data)
     513             : {
     514    16985044 :         intptr_t key_ptr = (intptr_t)smb_krb5_context->krb5_context;
     515    16985044 :         TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
     516    16985044 :         intptr_t value_ptr = (intptr_t)NULL;
     517    16985044 :         TDB_DATA value = make_tdb_data(NULL, 0);
     518    16985044 :         struct db_record *rec = NULL;
     519    16985044 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     520        5292 :         NTSTATUS status;
     521             : 
     522    16985044 :         rec = dbwrap_fetch_locked(smb_krb5_plugin_db, smb_krb5_context, key);
     523    16985044 :         if (rec == NULL) {
     524           0 :                 return ENOMEM;
     525             :         }
     526             : 
     527    16985044 :         value = dbwrap_record_get_value(rec);
     528    16985044 :         if (value.dsize != 0) {
     529    16973618 :                 SMB_ASSERT(value.dsize == sizeof(value_ptr));
     530    16973618 :                 memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
     531    16973618 :                 state = talloc_get_type_abort((const void *)value_ptr,
     532             :                                               struct smb_krb5_send_to_kdc_state);
     533    16973618 :                 if (send_to_realm == NULL && send_to_kdc == NULL) {
     534           0 :                         status = dbwrap_record_delete(rec);
     535           0 :                         TALLOC_FREE(rec);
     536           0 :                         if (!NT_STATUS_IS_OK(status)) {
     537           0 :                                 return EINVAL;
     538             :                         }
     539           0 :                         return 0;
     540             :                 }
     541    16973618 :                 state->send_to_realm = send_to_realm;
     542    16973618 :                 state->send_to_kdc = send_to_kdc;
     543    16973618 :                 state->private_data = private_data;
     544    16973618 :                 TALLOC_FREE(rec);
     545    16973618 :                 return 0;
     546             :         }
     547             : 
     548       11426 :         if (send_to_kdc == NULL && send_to_realm == NULL) {
     549           0 :                 TALLOC_FREE(rec);
     550           0 :                 return 0;
     551             :         }
     552             : 
     553       11426 :         state = talloc_zero(smb_krb5_context,
     554             :                             struct smb_krb5_send_to_kdc_state);
     555       11426 :         if (state == NULL) {
     556           0 :                 TALLOC_FREE(rec);
     557           0 :                 return ENOMEM;
     558             :         }
     559       11426 :         state->key_ptr = key_ptr;
     560       11426 :         state->smb_krb5_context = smb_krb5_context;
     561       11426 :         state->send_to_realm = send_to_realm;
     562       11426 :         state->send_to_kdc = send_to_kdc;
     563       11426 :         state->private_data = private_data;
     564             : 
     565       11426 :         value_ptr = (intptr_t)state;
     566       11426 :         value = make_tdb_data((uint8_t *)&value_ptr, sizeof(value_ptr));
     567             : 
     568       11426 :         status = dbwrap_record_store(rec, value, TDB_INSERT);
     569       11426 :         TALLOC_FREE(rec);
     570       11426 :         if (!NT_STATUS_IS_OK(status)) {
     571           0 :                 return EINVAL;
     572             :         }
     573       11426 :         talloc_set_destructor(state, smb_krb5_send_to_kdc_state_destructor);
     574             : 
     575       11426 :         return 0;
     576             : }
     577             : 
     578       37804 : static krb5_error_code smb_krb5_plugin_init(krb5_context context, void **pctx)
     579             : {
     580       37804 :         *pctx = NULL;
     581       37804 :         return 0;
     582             : }
     583             : 
     584        5218 : static void smb_krb5_plugin_fini(void *ctx)
     585             : {
     586        5218 : }
     587             : 
     588       71843 : static void smb_krb5_send_to_kdc_state_parser(TDB_DATA key, TDB_DATA value,
     589             :                                               void *private_data)
     590             : {
     591       71843 :         struct smb_krb5_send_to_kdc_state **state =
     592             :                 (struct smb_krb5_send_to_kdc_state **)private_data;
     593        2925 :         intptr_t value_ptr;
     594             : 
     595       71843 :         SMB_ASSERT(value.dsize == sizeof(value_ptr));
     596       71843 :         memcpy(&value_ptr, value.dptr, sizeof(value_ptr));
     597       71843 :         *state = talloc_get_type_abort((const void *)value_ptr,
     598             :                                        struct smb_krb5_send_to_kdc_state);
     599       71843 : }
     600             : 
     601             : static struct smb_krb5_send_to_kdc_state *
     602      164978 : smb_krb5_send_to_kdc_get_state(krb5_context context)
     603             : {
     604      164978 :         intptr_t key_ptr = (intptr_t)context;
     605      164978 :         TDB_DATA key = make_tdb_data((uint8_t *)&key_ptr, sizeof(key_ptr));
     606      164978 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     607        6241 :         NTSTATUS status;
     608             : 
     609      164978 :         status = dbwrap_parse_record(smb_krb5_plugin_db, key,
     610             :                                      smb_krb5_send_to_kdc_state_parser,
     611             :                                      &state);
     612      164978 :         if (!NT_STATUS_IS_OK(status)) {
     613       89819 :                 return NULL;
     614             :         }
     615             : 
     616       71843 :         return state;
     617             : }
     618             : 
     619       73814 : static krb5_error_code smb_krb5_plugin_send_to_kdc(krb5_context context,
     620             :                                                    void *ctx,
     621             :                                                    krb5_krbhst_info *ho,
     622             :                                                    time_t timeout,
     623             :                                                    const krb5_data *in,
     624             :                                                    krb5_data *out)
     625             : {
     626       73814 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     627             : 
     628       73814 :         state = smb_krb5_send_to_kdc_get_state(context);
     629       73814 :         if (state == NULL) {
     630       39598 :                 return KRB5_PLUGIN_NO_HANDLE;
     631             :         }
     632             : 
     633       32558 :         if (state->send_to_kdc == NULL) {
     634           0 :                 return KRB5_PLUGIN_NO_HANDLE;
     635             :         }
     636             : 
     637       32558 :         return state->send_to_kdc(state->smb_krb5_context,
     638             :                                   state->private_data,
     639             :                                   ho, timeout, in, out);
     640             : }
     641             : 
     642       91164 : static krb5_error_code smb_krb5_plugin_send_to_realm(krb5_context context,
     643             :                                                      void *ctx,
     644             :                                                      krb5_const_realm realm,
     645             :                                                      time_t timeout,
     646             :                                                      const krb5_data *in,
     647             :                                                      krb5_data *out)
     648             : {
     649       91164 :         struct smb_krb5_send_to_kdc_state *state = NULL;
     650             : 
     651       91164 :         state = smb_krb5_send_to_kdc_get_state(context);
     652       91164 :         if (state == NULL) {
     653       50221 :                 return KRB5_PLUGIN_NO_HANDLE;
     654             :         }
     655             : 
     656       39285 :         if (state->send_to_realm == NULL) {
     657       21642 :                 return KRB5_PLUGIN_NO_HANDLE;
     658             :         }
     659             : 
     660       16473 :         return state->send_to_realm(state->smb_krb5_context,
     661             :                                     state->private_data,
     662             :                                     realm, timeout, in, out);
     663             : }
     664             : 
     665             : static krb5plugin_send_to_kdc_ftable smb_krb5_plugin_ftable = {
     666             :         KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
     667             :         smb_krb5_plugin_init,
     668             :         smb_krb5_plugin_fini,
     669             :         smb_krb5_plugin_send_to_kdc,
     670             :         smb_krb5_plugin_send_to_realm
     671             : };
     672             : #endif
     673             : 
     674             : krb5_error_code
     675      479465 : smb_krb5_init_context_basic(TALLOC_CTX *tmp_ctx,
     676             :                             struct loadparm_context *lp_ctx,
     677             :                             krb5_context *_krb5_context)
     678             : {
     679       13153 :         krb5_error_code ret;
     680             : #ifdef SAMBA4_USES_HEIMDAL
     681       13153 :         char **config_files;
     682       13153 :         const char *config_file, *realm;
     683             : #endif
     684       13153 :         krb5_context krb5_ctx;
     685             : 
     686      479465 :         ret = smb_krb5_init_context_common(&krb5_ctx);
     687      479465 :         if (ret) {
     688           0 :                 return ret;
     689             :         }
     690             : 
     691             :         /* The MIT Kerberos build relies on using the system krb5.conf file.
     692             :          * If you really want to use another file please set KRB5_CONFIG
     693             :          * accordingly. */
     694             : #ifdef SAMBA4_USES_HEIMDAL
     695      396091 :         config_file = lpcfg_config_path(tmp_ctx, lp_ctx, "krb5.conf");
     696      396091 :         if (!config_file) {
     697           0 :                 krb5_free_context(krb5_ctx);
     698           0 :                 return ENOMEM;
     699             :         }
     700             : 
     701             :         /* Use our local krb5.conf file by default */
     702      396091 :         ret = krb5_prepend_config_files_default(config_file, &config_files);
     703      396091 :         if (ret) {
     704           0 :                 DEBUG(1,("krb5_prepend_config_files_default failed (%s)\n",
     705             :                          smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     706           0 :                 krb5_free_context(krb5_ctx);
     707           0 :                 return ret;
     708             :         }
     709             : 
     710      396091 :         ret = krb5_set_config_files(krb5_ctx, config_files);
     711      396091 :         krb5_free_config_files(config_files);
     712      396091 :         if (ret) {
     713           0 :                 DEBUG(1,("krb5_set_config_files failed (%s)\n",
     714             :                          smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     715           0 :                 krb5_free_context(krb5_ctx);
     716           0 :                 return ret;
     717             :         }
     718             : 
     719             :         /*
     720             :          * This is already called in smb_krb5_init_context_common(),
     721             :          * but krb5_set_config_files() may resets it.
     722             :          */
     723      396091 :         krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
     724             : 
     725      396091 :         realm = lpcfg_realm(lp_ctx);
     726      396091 :         if (realm != NULL) {
     727      396091 :                 ret = krb5_set_default_realm(krb5_ctx, realm);
     728      396091 :                 if (ret) {
     729           0 :                         DEBUG(1,("krb5_set_default_realm failed (%s)\n",
     730             :                                  smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     731           0 :                         krb5_free_context(krb5_ctx);
     732           0 :                         return ret;
     733             :                 }
     734             :         }
     735             : 
     736      396091 :         if (smb_krb5_plugin_db == NULL) {
     737             :                 /*
     738             :                  * while krb5_plugin_register() takes a krb5_context,
     739             :                  * plugins are registered into a global list, so
     740             :                  * we only do that once
     741             :                  *
     742             :                  * We maintain a separate dispatch table for per
     743             :                  * krb5_context state.
     744             :                  */
     745       37744 :                 ret = krb5_plugin_register(krb5_ctx, PLUGIN_TYPE_DATA,
     746             :                                      KRB5_PLUGIN_SEND_TO_KDC,
     747             :                                      &smb_krb5_plugin_ftable);
     748       37744 :                 if (ret) {
     749           0 :                         DEBUG(1,("krb5_plugin_register(KRB5_PLUGIN_SEND_TO_KDC) failed (%s)\n",
     750             :                                  smb_get_krb5_error_message(krb5_ctx, ret, tmp_ctx)));
     751           0 :                         krb5_free_context(krb5_ctx);
     752           0 :                         return ret;
     753             :                 }
     754       37744 :                 smb_krb5_plugin_db = db_open_rbt(NULL);
     755       37744 :                 if (smb_krb5_plugin_db == NULL) {
     756           0 :                         DEBUG(1,("db_open_rbt() failed\n"));
     757           0 :                         krb5_free_context(krb5_ctx);
     758           0 :                         return ENOMEM;
     759             :                 }
     760             :         }
     761             : #endif
     762      479465 :         *_krb5_context = krb5_ctx;
     763      479465 :         return 0;
     764             : }
     765             : 
     766      478847 : krb5_error_code smb_krb5_init_context(void *parent_ctx,
     767             :                                       struct loadparm_context *lp_ctx,
     768             :                                       struct smb_krb5_context **smb_krb5_context)
     769             : {
     770       13153 :         krb5_error_code ret;
     771       13153 :         TALLOC_CTX *tmp_ctx;
     772       13153 :         krb5_context kctx;
     773             : #ifdef SAMBA4_USES_HEIMDAL
     774       13153 :         krb5_log_facility *logf;
     775             : #endif
     776             : 
     777      478847 :         tmp_ctx = talloc_new(parent_ctx);
     778      478847 :         *smb_krb5_context = talloc_zero(tmp_ctx, struct smb_krb5_context);
     779             : 
     780      478847 :         if (!*smb_krb5_context || !tmp_ctx) {
     781           0 :                 talloc_free(tmp_ctx);
     782           0 :                 return ENOMEM;
     783             :         }
     784             : 
     785      478847 :         ret = smb_krb5_init_context_basic(tmp_ctx, lp_ctx, &kctx);
     786      478847 :         if (ret) {
     787           0 :                 DEBUG(1,("smb_krb5_context_init_basic failed (%s)\n",
     788             :                          error_message(ret)));
     789           0 :                 talloc_free(tmp_ctx);
     790           0 :                 return ret;
     791             :         }
     792      478847 :         (*smb_krb5_context)->krb5_context = kctx;
     793             : 
     794      478847 :         talloc_set_destructor(*smb_krb5_context, smb_krb5_context_destroy);
     795             : 
     796             : #ifdef SAMBA4_USES_HEIMDAL
     797             :         /* TODO: Should we have a different name here? */
     798      395755 :         ret = krb5_initlog(kctx, "Samba", &logf);
     799             : 
     800      395755 :         if (ret) {
     801           0 :                 DEBUG(1,("krb5_initlog failed (%s)\n",
     802             :                          smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
     803           0 :                 talloc_free(tmp_ctx);
     804           0 :                 return ret;
     805             :         }
     806      395755 :         (*smb_krb5_context)->pvt_log_data = logf;
     807             : 
     808      395755 :         ret = krb5_addlog_func(kctx, logf, 0 /* min */, -1 /* max */,
     809             :                                smb_krb5_debug_wrapper,
     810             :                                 smb_krb5_debug_close, NULL);
     811      395755 :         if (ret) {
     812           0 :                 DEBUG(1,("krb5_addlog_func failed (%s)\n",
     813             :                          smb_get_krb5_error_message(kctx, ret, tmp_ctx)));
     814           0 :                 talloc_free(tmp_ctx);
     815           0 :                 return ret;
     816             :         }
     817      395755 :         krb5_set_warn_dest(kctx, logf);
     818             : #endif
     819      478847 :         talloc_steal(parent_ctx, *smb_krb5_context);
     820      478847 :         talloc_free(tmp_ctx);
     821             : 
     822      478847 :         return 0;
     823             : }
     824             : 
     825             : #ifdef SAMBA4_USES_HEIMDAL
     826       11974 : krb5_error_code smb_krb5_context_set_event_ctx(struct smb_krb5_context *smb_krb5_context,
     827             :                                                struct tevent_context *ev,
     828             :                                                struct tevent_context **previous_ev)
     829             : {
     830         585 :         int ret;
     831       11974 :         if (!ev) {
     832           0 :                 return EINVAL;
     833             :         }
     834             : 
     835       11974 :         *previous_ev = smb_krb5_context->current_ev;
     836             : 
     837       11974 :         smb_krb5_context->current_ev = talloc_reference(smb_krb5_context, ev);
     838       11974 :         if (!smb_krb5_context->current_ev) {
     839           0 :                 return ENOMEM;
     840             :         }
     841             : 
     842             :         /* Set use of our socket lib */
     843       11974 :         ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     844             :                                             NULL, /* send_to_realm */
     845             :                                             smb_krb5_send_and_recv_func,
     846             :                                             ev);
     847       11974 :         if (ret) {
     848           0 :                 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     849           0 :                 DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
     850             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
     851           0 :                 talloc_free(tmp_ctx);
     852           0 :                 talloc_unlink(smb_krb5_context, smb_krb5_context->current_ev);
     853           0 :                 smb_krb5_context->current_ev = NULL;
     854           0 :                 return ret;
     855             :         }
     856       11389 :         return 0;
     857             : }
     858             : 
     859       11974 : krb5_error_code smb_krb5_context_remove_event_ctx(struct smb_krb5_context *smb_krb5_context,
     860             :                                                   struct tevent_context *previous_ev,
     861             :                                                   struct tevent_context *ev)
     862             : {
     863         585 :         int ret;
     864       11974 :         talloc_unlink(smb_krb5_context, ev);
     865             :         /* If there was a mismatch with things happening on a stack, then don't wipe things */
     866       11974 :         smb_krb5_context->current_ev = previous_ev;
     867             :         /* Set use of our socket lib */
     868       11974 :         ret = smb_krb5_set_send_to_kdc_func(smb_krb5_context,
     869             :                                             NULL, /* send_to_realm */
     870             :                                             smb_krb5_send_and_recv_func,
     871             :                                             previous_ev);
     872       11974 :         if (ret) {
     873           0 :                 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     874           0 :                 DEBUG(1,("smb_krb5_set_send_recv_func failed (%s)\n",
     875             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, tmp_ctx)));
     876           0 :                 talloc_free(tmp_ctx);
     877           0 :                 return ret;
     878             :         }
     879       11389 :         return 0;
     880             : }
     881             : #endif

Generated by: LCOV version 1.14