1/*
2 * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77#include "config.h"
78#include <dce/smb.h>
79#include <commonp.h>
80#include <com.h>
81#include <comprot.h>
82#include <comnaf.h>
83#include <comp.h>
84#include <comsoc_smb.h>
85#include <cnassm.h>
86#include <fcntl.h>
87#include <sys/un.h>
88#include <sys/types.h>
89#include <sys/stat.h>
90#include <cnp.h>
91#include <npnaf.h>
92#include <stddef.h>
93#include <sys/param.h>
94#include <sys/mount.h>
95
96#if HAVE_SMBCLIENT_FRAMEWORK
97#include <SMBClient/smbclient.h>
98#include <nttypes.h>
99rpc_socket_error_t rpc_smb_ntstatus_to_rpc_error(NTSTATUS status);
100
101#if !defined(kSMBOptionAllowGuestAuth)
102#define kSMBOptionAllowGuestAuth 0
103#endif
104
105#if !defined(kSMBOptionAllowAnonymousAuth)
106#define kSMBOptionAllowAnonymousAuth 0
107#endif
108
109#if defined(kPropertiesVersion)
110#define HAVE_SMBCLIENT_SMBGETSERVERPROPERTIES 1
111#endif
112
113#define SMBCLIENT_CONNECTION_FLAGS ( \
114    kSMBOptionNoPrompt          | \
115    kSMBOptionAllowGuestAuth    | \
116    kSMBOptionAllowAnonymousAuth \
117)
118
119#endif /* HAVE_SMBCLIENT_FRAMEWORK */
120
121#if HAVE_LW_BASE_H
122#include <lw/base.h>
123#endif
124
125#if HAVE_LWIO_LWIO_H
126#include <lwio/lwio.h>
127#endif
128
129#if HAVE_LWMAPSECURITY_LWMAPSECURITY_H
130#include <lwmapsecurity/lwmapsecurity.h>
131#endif
132
133#define SMB_SOCKET_LOCK(sock) (rpc__smb_socket_lock(sock))
134#define SMB_SOCKET_UNLOCK(sock) (rpc__smb_socket_unlock(sock))
135
136#ifndef RPC_C_SOCKET_MAX_RCVBUF
137#  define RPC_C_SOCKET_MAX_RCVBUF (64 * 1024)
138#endif
139
140#ifndef RPC_C_SOCKET_MAX_SNDBUF
141#  define RPC_C_SOCKET_MAX_SNDBUF (64 * 1024)
142#endif
143
144typedef struct rpc_smb_transport_info_s
145{
146    char* peer_principal;
147    struct
148    {
149        unsigned16 length;
150        unsigned char* data;
151    } session_key;
152#if HAVE_LIKEWISE_LWIO
153    PIO_CREDS creds;
154#endif
155} rpc_smb_transport_info_t, *rpc_smb_transport_info_p_t;
156
157typedef enum rpc_smb_state_e
158{
159    SMB_STATE_SEND,
160    SMB_STATE_RECV,
161    SMB_STATE_LISTEN,
162    SMB_STATE_ERROR
163} rpc_smb_state_t;
164
165typedef struct rpc_smb_buffer_s
166{
167    size_t capacity;
168    unsigned char* base;
169    unsigned char* start_cursor;
170    unsigned char* end_cursor;
171} rpc_smb_buffer_t, *rpc_smb_buffer_p_t;
172
173typedef struct rpc_smb_socket_s
174{
175    rpc_smb_state_t volatile state;
176    rpc_np_addr_t peeraddr;
177    rpc_np_addr_t localaddr;
178    rpc_smb_transport_info_t info;
179#if HAVE_LIKEWISE_LWIO
180    PIO_CONTEXT context;
181    IO_FILE_HANDLE np;
182#elif HAVE_SMBCLIENT_FRAMEWORK
183    SMBHANDLE handle;
184    SMBFID hFile;
185#endif
186    size_t maxSendBufferSize;
187    size_t maxRecvBufferSize;
188    rpc_smb_buffer_t sendbuffer;
189    rpc_smb_buffer_t recvbuffer;
190    struct
191    {
192#if HAVE_LIKEWISE_LWIO
193        IO_FILE_HANDLE* queue;
194#endif
195        size_t capacity;
196        size_t length;
197        int selectfd[2];
198    } accept_backlog;
199    dcethread* listen_thread;
200    dcethread_mutex lock;
201    dcethread_cond event;
202} rpc_smb_socket_t, *rpc_smb_socket_p_t;
203
204#if HAVE_SMBCLIENT_FRAMEWORK
205rpc_socket_error_t
206rpc_smb_ntstatus_to_rpc_error(
207    NTSTATUS status
208    )
209{
210    switch (status) {
211
212        case STATUS_SUCCESS:
213            return RPC_C_SOCKET_OK;
214
215        case STATUS_UNEXPECTED_IO_ERROR:
216            return RPC_C_SOCKET_EIO;
217
218        case STATUS_CONNECTION_REFUSED:
219            return RPC_C_SOCKET_ECONNREFUSED;
220
221        case STATUS_NO_SUCH_DEVICE:
222            return RPC_C_SOCKET_ENETUNREACH;
223
224        case STATUS_BUFFER_OVERFLOW:
225            return RPC_C_SOCKET_ENOSPC;
226
227        case STATUS_NO_MEMORY:
228            return RPC_C_SOCKET_ENOMEM;
229
230        case STATUS_OBJECT_PATH_SYNTAX_BAD:
231        case STATUS_INVALID_HANDLE:
232        case STATUS_INVALID_PARAMETER:
233        case STATUS_UNSUCCESSFUL:
234            return RPC_C_SOCKET_EINVAL;
235
236        case STATUS_LOGON_FAILURE:
237            return RPC_C_SOCKET_EAUTH;
238
239        case STATUS_BAD_NETWORK_NAME:
240            return RPC_C_SOCKET_ENOENT;
241
242        default:
243            RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc_smb_ntstatus_to_rpc_error - unmapped ntstatus 0x%x\n", status));
244            return (RPC_C_SOCKET_EIO);
245    }
246}
247
248#endif
249
250void
251rpc_smb_transport_info_from_lwio_creds(
252    void* creds ATTRIBUTE_UNUSED,
253    rpc_transport_info_handle_t* info,
254    unsigned32* st
255    )
256{
257    rpc_smb_transport_info_p_t smb_info = NULL;
258
259    smb_info = calloc(1, sizeof(*smb_info));
260
261    if (!smb_info)
262    {
263        *st = rpc_s_no_memory;
264        goto error;
265    }
266
267#if HAVE_LIKEWISE_LWIO
268    if (LwIoCopyCreds(creds, &smb_info->creds) != 0)
269    {
270        *st = rpc_s_no_memory;
271        goto error;
272    }
273#endif
274
275    *info = (rpc_transport_info_handle_t) smb_info;
276
277    *st = rpc_s_ok;
278
279error:
280
281    if (*st != rpc_s_ok && smb_info)
282    {
283        rpc_smb_transport_info_free((rpc_transport_info_handle_t) smb_info);
284    }
285
286    return;
287}
288
289INTERNAL
290void
291rpc__smb_transport_info_destroy(
292    rpc_smb_transport_info_p_t smb_info
293    )
294{
295    assert(smb_info != NULL);
296
297#if HAVE_LIKEWISE_LWIO
298    if (smb_info->creds)
299    {
300        LwIoDeleteCreds(smb_info->creds);
301    }
302#endif
303
304    if (smb_info->session_key.data)
305    {
306        free(smb_info->session_key.data);
307    }
308
309    if (smb_info->peer_principal)
310    {
311        free(smb_info->peer_principal);
312    }
313}
314
315void
316rpc_smb_transport_info_free(
317    rpc_transport_info_handle_t info
318    )
319{
320    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc_smb_transport_info_free called\n"));
321
322    if (info)
323    {
324        rpc__smb_transport_info_destroy((rpc_smb_transport_info_p_t) info);
325        free(info);
326    }
327}
328
329void
330rpc_smb_transport_info_inq_session_key(
331    rpc_transport_info_handle_t info,
332    unsigned char** sess_key,
333    unsigned16* sess_key_len
334    )
335{
336    rpc_smb_transport_info_p_t smb_info = (rpc_smb_transport_info_p_t) info;
337
338    if (sess_key)
339    {
340        *sess_key = smb_info->session_key.data;
341    }
342
343    if (sess_key_len)
344    {
345        *sess_key_len = (unsigned32) smb_info->session_key.length;
346    }
347}
348
349void
350rpc_smb_transport_info_inq_peer_principal_name(
351    rpc_transport_info_handle_t info,
352    unsigned char** principal
353    )
354{
355    rpc_smb_transport_info_p_t smb_info = (rpc_smb_transport_info_p_t) info;
356
357    if (principal)
358    {
359        *principal = (unsigned char*) smb_info->peer_principal;
360    }
361}
362
363INTERNAL
364boolean
365rpc__smb_transport_info_equal(
366    rpc_transport_info_handle_t info1,
367    rpc_transport_info_handle_t info2
368    )
369{
370    rpc_smb_transport_info_p_t smb_info1 = (rpc_smb_transport_info_p_t) info1;
371    rpc_smb_transport_info_p_t smb_info2 = (rpc_smb_transport_info_p_t) info2;
372
373    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_transport_info_equal called\n"));
374
375#if HAVE_LIKEWISE_LWIO
376    return
377        (smb_info2 == NULL
378         && smb_info1->creds == NULL) ||
379        (smb_info2 != NULL &&
380         ((smb_info1->creds == NULL && smb_info2->creds == NULL) ||
381          (smb_info1->creds != NULL && smb_info2->creds != NULL &&
382           LwIoCompareCredss(smb_info1->creds, smb_info2->creds))));
383#else
384    return (smb_info1 == smb_info2);
385#endif
386}
387
388INTERNAL
389inline
390size_t
391rpc__smb_buffer_pending(
392    rpc_smb_buffer_p_t buffer
393    )
394{
395    return buffer->end_cursor - buffer->start_cursor;
396}
397
398INTERNAL
399inline
400size_t
401rpc__smb_buffer_length(
402    rpc_smb_buffer_p_t buffer
403    )
404{
405    return buffer->end_cursor - buffer->base;
406}
407
408INTERNAL
409inline
410size_t
411rpc__smb_buffer_available(
412    rpc_smb_buffer_p_t buffer
413    )
414{
415    return (buffer->base + buffer->capacity) - buffer->end_cursor;
416}
417
418INTERNAL
419inline
420rpc_socket_error_t
421rpc__smb_buffer_ensure_available(
422    rpc_smb_buffer_p_t buffer,
423    size_t space
424    )
425{
426    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
427    unsigned char* new_base = NULL;
428
429    if (!buffer->base)
430    {
431        buffer->capacity = 2048;
432        buffer->base = malloc(buffer->capacity);
433
434        if (!buffer->base)
435        {
436            serr = RPC_C_SOCKET_ENOMEM;
437            goto error;
438        }
439
440        buffer->end_cursor = buffer->start_cursor = buffer->base;
441    }
442
443    if (space > rpc__smb_buffer_available(buffer))
444    {
445        while (space > rpc__smb_buffer_available(buffer))
446        {
447            buffer->capacity *= 2;
448        }
449
450        new_base = realloc(buffer->base, buffer->capacity);
451
452        if (!new_base)
453        {
454            serr = RPC_C_SOCKET_ENOMEM;
455            goto error;
456        }
457
458        buffer->start_cursor = new_base + (buffer->start_cursor - buffer->base);
459        buffer->end_cursor = new_base + (buffer->end_cursor - buffer->base);
460
461        buffer->base = new_base;
462    }
463
464error:
465
466    return serr;
467}
468
469INTERNAL
470size_t
471rpc__smb_fragment_size(
472    rpc_cn_common_hdr_p_t packet
473    )
474{
475    uint16_t result;
476    int packet_order = ((packet->drep[0] >> 4) & 1);
477    int native_order;
478
479#if __LITTLE_ENDIAN__
480    native_order = (NDR_LOCAL_INT_REP == ndr_c_int_big_endian) ? 0 : 1;
481#else
482    native_order = (NDR_LOCAL_INT_REP == ndr_c_int_little_endian) ? 0 : 1;
483#endif
484
485    if (packet_order != native_order)
486    {
487        result = SWAB_16(packet->frag_len);
488    }
489    else
490    {
491        result = packet->frag_len;
492    }
493
494    return (size_t) result;
495}
496
497INTERNAL
498inline
499size_t
500rpc__smb_buffer_packet_size(
501    rpc_smb_buffer_p_t buffer
502    )
503{
504    rpc_cn_common_hdr_p_t packet = (rpc_cn_common_hdr_p_t) buffer->start_cursor;
505
506    if (rpc__smb_buffer_pending(buffer) < sizeof(*packet))
507    {
508        return sizeof(*packet);
509    }
510    else
511    {
512        return (rpc__smb_fragment_size(packet));
513    }
514}
515
516INTERNAL
517inline
518boolean
519rpc__smb_buffer_packet_is_last(
520    rpc_smb_buffer_p_t buffer
521    )
522{
523    rpc_cn_common_hdr_p_t packet = (rpc_cn_common_hdr_p_t) buffer->start_cursor;
524
525    return (packet->flags & RPC_C_CN_FLAGS_LAST_FRAG) == RPC_C_CN_FLAGS_LAST_FRAG;
526}
527
528INTERNAL
529inline
530rpc_socket_error_t
531rpc__smb_buffer_append(
532    rpc_smb_buffer_p_t buffer,
533    void* data,
534    size_t data_size
535    )
536{
537    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
538
539    serr = rpc__smb_buffer_ensure_available(buffer, data_size);
540    if (serr)
541    {
542        goto error;
543    }
544
545    memcpy(buffer->end_cursor, data, data_size);
546
547    buffer->end_cursor += data_size;
548
549error:
550
551    return serr;
552}
553
554INTERNAL
555inline
556void
557rpc__smb_buffer_settle(
558    rpc_smb_buffer_p_t buffer
559    )
560{
561    size_t filled = buffer->end_cursor - buffer->start_cursor;
562    memmove(buffer->base, buffer->start_cursor, filled);
563    buffer->start_cursor = buffer->base;
564    buffer->end_cursor = buffer->base + filled;
565}
566
567/* Advance buffer start_cursor to the end of the last packet
568   or the last packet that is the final fragment in a series,
569   whichever comes first.  If the final fragment is found,
570   return true, otherwise false.
571*/
572INTERNAL
573inline
574boolean
575rpc__smb_buffer_advance_cursor(rpc_smb_buffer_p_t buffer, size_t* amount)
576{
577    boolean last;
578    size_t packet_size;
579
580    while (rpc__smb_buffer_packet_size(buffer) <= rpc__smb_buffer_pending(buffer))
581    {
582        last = rpc__smb_buffer_packet_is_last(buffer);
583        packet_size = rpc__smb_buffer_packet_size(buffer);
584
585        buffer->start_cursor += packet_size;
586
587        if (last)
588        {
589            if (amount)
590            {
591                *amount = buffer->start_cursor - buffer->base;
592            }
593
594            return true;
595        }
596    }
597
598    return false;
599}
600
601INTERNAL
602rpc_socket_error_t
603rpc__smb_socket_create(
604    rpc_smb_socket_p_t* out
605    )
606{
607    rpc_smb_socket_p_t sock = NULL;
608    int err = 0;
609
610    sock = calloc(1, sizeof(*sock));
611
612    if (!sock)
613    {
614        err = RPC_C_SOCKET_ENOMEM;
615        goto done;
616    }
617
618    sock->accept_backlog.selectfd[0] = -1;
619    sock->accept_backlog.selectfd[1] = -1;
620
621    /* Set up reasonable default local endpoint */
622    sock->localaddr.rpc_protseq_id = rpc_c_protseq_id_ncacn_np;
623    sock->localaddr.len = offsetof(rpc_np_addr_t, remote_host) + sizeof(sock->localaddr.remote_host);
624    sock->localaddr.sa.sun_family = AF_UNIX;
625    sock->localaddr.sa.sun_path[0] = '\0';
626    sock->localaddr.remote_host[0] = '\0';
627
628    dcethread_mutex_init_throw(&sock->lock, NULL);
629    dcethread_cond_init_throw(&sock->event, NULL);
630
631#if HAVE_SMBCLIENT_FRAMEWORK
632    sock->handle = NULL;
633    sock->hFile = 0;
634    sock->maxSendBufferSize = 0;
635    sock->maxRecvBufferSize = 0;
636#else
637    sock->maxSendBufferSize = 8192;
638    sock->maxRecvBufferSize = 8192;
639#endif
640
641#if HAVE_LIKEWISE_LWIO
642    err = LwNtStatusToErrno(LwIoOpenContextShared(&sock->context));
643    if (err)
644    {
645        goto error;
646    }
647#endif
648
649    *out = sock;
650
651done:
652
653    return err;
654
655#if HAVE_LIKEWISE_LWIO
656error:
657
658    if (sock)
659    {
660        if (sock->context)
661        {
662            LwIoCloseContext(sock->context);
663        }
664
665        dcethread_mutex_destroy_throw(&sock->lock);
666        dcethread_cond_destroy_throw(&sock->event);
667    }
668
669    goto done;
670#endif
671}
672
673INTERNAL
674void
675rpc__smb_socket_destroy(
676    rpc_smb_socket_p_t sock
677    )
678{
679#if HAVE_LIKEWISE_LWIO
680    size_t i;
681#endif
682
683    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_destroy called\n"));
684
685    if (!sock)
686    {
687        return;
688    }
689
690#if HAVE_LIKEWISE_LWIO
691    if (sock->accept_backlog.queue)
692    {
693        for (i = 0; i < sock->accept_backlog.capacity; i++)
694        {
695            if (sock->accept_backlog.queue[i])
696            {
697                NtCtxCloseFile(sock->context, sock->accept_backlog.queue[i]);
698            }
699        }
700
701        close(sock->accept_backlog.selectfd[0]);
702        close(sock->accept_backlog.selectfd[1]);
703
704        free(sock->accept_backlog.queue);
705    }
706
707    if (sock->np && sock->context)
708    {
709        NtCtxCloseFile(sock->context, sock->np);
710    }
711
712    if (sock->context)
713    {
714        LwIoCloseContext(sock->context);
715    }
716
717#elif HAVE_SMBCLIENT_FRAMEWORK
718
719    if (sock->hFile != 0)
720    {
721        SMBCloseFile(sock->handle, sock->hFile);
722        sock->hFile = 0;
723    }
724
725    if (sock->handle)
726    {
727        SMBReleaseServer(sock->handle);
728        sock->handle = NULL;
729    }
730
731#endif
732
733    if (sock->sendbuffer.base)
734    {
735        free(sock->sendbuffer.base);
736    }
737
738    if (sock->recvbuffer.base)
739    {
740        free(sock->recvbuffer.base);
741    }
742
743    rpc__smb_transport_info_destroy(&sock->info);
744
745    dcethread_mutex_destroy_throw(&sock->lock);
746    dcethread_cond_destroy_throw(&sock->event);
747
748    free(sock);
749}
750
751INTERNAL
752inline
753void
754rpc__smb_socket_lock(
755    rpc_smb_socket_p_t sock
756    )
757{
758    dcethread_mutex_lock_throw(&sock->lock);
759}
760
761INTERNAL
762inline
763void
764rpc__smb_socket_unlock(
765    rpc_smb_socket_p_t sock
766    )
767{
768    dcethread_mutex_unlock_throw(&sock->lock);
769}
770
771INTERNAL
772inline
773void
774rpc__smb_socket_change_state(
775    rpc_smb_socket_p_t sock,
776    rpc_smb_state_t state
777    )
778{
779    sock->state = state;
780    dcethread_cond_broadcast_throw(&sock->event);
781}
782
783INTERNAL
784inline
785void
786rpc__smb_socket_wait(
787    rpc_smb_socket_p_t sock
788    )
789{
790    DCETHREAD_TRY
791    {
792        dcethread_cond_wait_throw(&sock->event, &sock->lock);
793    }
794    DCETHREAD_CATCH_ALL(e)
795    {
796        dcethread_mutex_unlock(&sock->lock);
797        DCETHREAD_RAISE(*e);
798    }
799    DCETHREAD_ENDTRY;
800}
801
802INTERNAL
803rpc_socket_error_t
804rpc__smb_socket_construct(
805    rpc_socket_t sock,
806    rpc_protseq_id_t pseq_id ATTRIBUTE_UNUSED,
807#if HAVE_LIKEWISE_LWIO
808    rpc_transport_info_handle_t info
809#else
810    rpc_transport_info_handle_t info ATTRIBUTE_UNUSED
811#endif
812    )
813{
814    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
815    rpc_smb_socket_p_t smb_sock = NULL;
816#if HAVE_LIKEWISE_LWIO
817    rpc_smb_transport_info_p_t smb_info = (rpc_smb_transport_info_p_t) info;
818#endif
819
820    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_construct called\n"));
821
822    serr = rpc__smb_socket_create(&smb_sock);
823
824    if (serr)
825    {
826        goto error;
827    }
828
829#if HAVE_LIKEWISE_LWIO
830    if (smb_info)
831    {
832        if (smb_info->creds)
833        {
834            serr = NtStatusToErrno(LwIoCopyCreds(smb_info->creds, &smb_sock->info.creds));
835            if (serr)
836            {
837                goto error;
838            }
839        }
840    }
841#endif
842
843    sock->data.pointer = (void*) smb_sock;
844
845done:
846
847    return serr;
848
849error:
850
851    if (smb_sock)
852    {
853        rpc__smb_socket_destroy(smb_sock);
854    }
855
856    goto done;
857}
858
859INTERNAL
860rpc_socket_error_t
861rpc__smb_socket_destruct(
862    rpc_socket_t sock
863    )
864{
865    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
866
867    rpc__smb_socket_destroy(smb);
868    sock->data.pointer = NULL;
869
870    return RPC_C_SOCKET_OK;
871}
872
873INTERNAL
874rpc_socket_error_t
875rpc__smb_socket_bind(
876    rpc_socket_t sock,
877    rpc_addr_p_t addr
878    )
879{
880    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
881    rpc_np_addr_p_t npaddr = (rpc_np_addr_p_t) addr;
882    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
883
884    smb->localaddr = *npaddr;
885
886    return serr;
887}
888
889#if HAVE_SMBCLIENT_FRAMEWORK
890INTERNAL
891rpc_socket_error_t
892rpc__smbclient_connect(
893    rpc_smb_socket_p_t  smb,
894    const char *        netaddr,
895    const char *        pipename
896)
897{
898    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
899    char *              smbpath = NULL;
900    NTSTATUS            status;
901    boolean             have_mountpath = false;
902    unsigned_char_p_t   unescaped_netaddr;
903
904    if (netaddr[0] == '/')
905    {
906        struct statfs fsBuf;
907
908        /* see if its a mountpath instead of a host addr */
909        if (statfs ((char *) netaddr, &fsBuf) != 0)
910        {
911            RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
912               ("rpc__smb_socket_connect - statfs failed errno %d\n", errno));
913        }
914        else
915        {
916            /* its a mountpath, so use a different api
917             to find the existing smb session to share */
918            have_mountpath = 1;
919        }
920    }
921
922    if (have_mountpath == 0)
923    {
924        /* its not a mount path, so just pass in the URL string */
925
926#if defined(kPropertiesVersion)
927        /* unescape the netaddr */
928        rpc__string_netaddr_unescape((unsigned_char_p_t) netaddr,
929                                     &unescaped_netaddr,
930                                     &status);
931
932        smbpath = SMBCreateURLString(NULL, NULL, NULL,
933                                     (const char *) unescaped_netaddr,
934                                     NULL, -1);
935        /* free the escaped netaddr */
936        rpc_string_free (&unescaped_netaddr, &status);
937#else
938        /* Ick. Max OS 10.6 or earlier ... only have the old API. */
939        asprintf(&smbpath, "smb://%s", netaddr);
940#endif
941        if (smbpath == NULL)
942        {
943            RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
944                   ("rpc__smb_socket_connect - smbpath malloc failed\n"));
945            serr = RPC_C_SOCKET_ENOMEM;
946            goto error;
947        }
948    }
949
950    /* Never have a username or password here. Either we use an already
951     * existing authenticated session, or log in as guest, or fail. Never
952     * prompt for a username or password so always set kSMBOptionNoPrompt,
953     * but do allow guest or anonymous logins.
954     */
955
956    if (have_mountpath == 0)
957    {
958        RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
959               ("rpc__smb_socket_connect - SMBOpenServerEx <%s>\n",
960                smbpath));
961        status = SMBOpenServerEx(smbpath, &smb->handle, SMBCLIENT_CONNECTION_FLAGS);
962    }
963    else
964    {
965        RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
966               ("rpc__smb_socket_connect - SMBOpenServerWithMountPoint <%s>\n",
967                netaddr));
968#if defined(kPropertiesVersion)
969        status = SMBOpenServerWithMountPoint(netaddr, NULL,
970                        &smb->handle, SMBCLIENT_CONNECTION_FLAGS);
971#else
972        status = 0xC00000CC; /* STATUS_BAD_NETWORK_NAME */
973#endif
974    }
975
976    if (!NT_SUCCESS(status))
977    {
978        RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
979               ("rpc__smb_socket_connect - SMBOpenServerEx failed 0x%x\n",
980                status));
981        serr = rpc_smb_ntstatus_to_rpc_error (status);
982        goto error;
983    }
984
985    status = SMBCreateFile(smb->handle, pipename,
986           GENERIC_READ | GENERIC_WRITE,        /* dwDesiredAccess */
987           FILE_SHARE_READ | FILE_SHARE_WRITE,  /* dwShareMode */
988           NULL,                                /* lpSecurityAttributes */
989           FILE_OPEN,                           /* dwCreateDisposition */
990           0x0000,                              /* dwFlagsAndAttributes */
991           &smb->hFile);
992
993    if (!NT_SUCCESS(status))
994    {
995        RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
996                       ("rpc__smb_socket_connect - SMBCreateFile failed 0x%x\n",
997                        status));
998        serr = rpc_smb_ntstatus_to_rpc_error (status);
999        goto error;
1000    }
1001
1002error:
1003    if (smbpath)
1004        free(smbpath);
1005
1006    return serr;
1007}
1008
1009#endif /* HAVE_SMBCLIENT_FRAMEWORK */
1010
1011INTERNAL
1012rpc_socket_error_t
1013rpc__smb_socket_connect(
1014    rpc_socket_t sock,
1015    rpc_addr_p_t addr,
1016    rpc_cn_assoc_t *assoc ATTRIBUTE_UNUSED
1017    )
1018{
1019    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1020    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1021    char *netaddr = NULL;
1022    unsigned_char_t *endpoint = NULL;
1023    char *pipename = NULL;
1024    unsigned32 dbg_status = 0;
1025#if HAVE_LIKEWISE_LWIO
1026    PSTR smbpath = NULL;
1027    PBYTE sesskey = NULL;
1028    USHORT sesskeylen = 0;
1029    IO_FILE_NAME filename = { 0 };
1030    IO_STATUS_BLOCK io_status = { 0 };
1031    size_t len;
1032#endif
1033
1034    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_connect called\n"));
1035
1036    SMB_SOCKET_LOCK(smb);
1037
1038    /* Break address into host and endpoint */
1039    rpc__naf_addr_inq_netaddr (addr,
1040                               (unsigned_char_t**) &netaddr,
1041                               &dbg_status);
1042    rpc__naf_addr_inq_endpoint (addr,
1043                                (unsigned_char_t**) &endpoint,
1044                                &dbg_status);
1045
1046    RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1047                   ("rpc__smb_socket_connect - netaddr <%s>\n", netaddr));
1048    RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1049                   ("rpc__smb_socket_connect - ep <%s>\n", endpoint));
1050
1051    if (rpc__np_is_valid_endpoint(endpoint, &dbg_status))
1052    {
1053        pipename = (char *)endpoint + sizeof("\\pipe\\") - 1;
1054    }
1055    else
1056    {
1057        serr = RPC_C_SOCKET_EINVAL;
1058        goto error;
1059    }
1060
1061    RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1062                   ("rpc__smb_socket_connect - pipename <%s>\n", pipename));
1063
1064#if HAVE_LIKEWISE_LWIO
1065    len = strlen(netaddr) + strlen(pipename) + strlen("\\rdr\\\\IPC$\\") + 1;
1066    smbpath = malloc(len);
1067    if (smbpath == NULL) {
1068        RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1069                       ("rpc__smb_socket_connect - smbpath malloc failed\n"));
1070        serr = RPC_C_SOCKET_ENOMEM;
1071        goto error;
1072    }
1073    snprintf (smbpath, len, "\\rdr\\%s\\IPC$\\%s",
1074              (char*) netaddr, (char*) pipename);
1075#elif HAVE_SMBCLIENT_FRAMEWORK
1076    serr = rpc__smbclient_connect(smb, netaddr, pipename);
1077#else
1078    serr = RPC_C_SOCKET_ENOTSUP;
1079    goto error;
1080#endif
1081
1082#if HAVE_LIKEWISE_LWIO
1083
1084    serr = NtStatusToErrno(
1085        LwRtlCStringAllocatePrintf(
1086            &smbpath,
1087            "\\rdr\\%s\\IPC$\\%s",
1088            (char*) netaddr,
1089            (char*) pipename));
1090    if (serr)
1091    {
1092        goto error;
1093    }
1094
1095    serr = NtStatusToErrno(
1096        LwRtlWC16StringAllocateFromCString(
1097            &filename.FileName,
1098            smbpath));
1099    if (serr)
1100    {
1101        goto error;
1102    }
1103
1104    serr = NtStatusToErrno(
1105        NtCtxCreateFile(
1106            smb->context,                            /* IO context */
1107            smb->info.creds,                         /* Security token */
1108            &smb->np,                                /* Created handle */
1109            NULL,                                    /* Async control block */
1110            &io_status,                              /* Status block */
1111            &filename,                               /* Filename */
1112            NULL,                                    /* Security descriptor */
1113            NULL,                                    /* Security QOS */
1114            GENERIC_READ | GENERIC_WRITE,            /* Access mode */
1115            0,                                       /* Allocation size */
1116            0,                                       /* File attributes */
1117            FILE_SHARE_READ | FILE_SHARE_WRITE,      /* Sharing mode */
1118            FILE_OPEN,                               /* Create disposition */
1119            FILE_CREATE_TREE_CONNECTION,             /* Create options */
1120            NULL,                                    /* EA buffer */
1121            0,                                       /* EA buffer length */
1122            NULL                                     /* ECP List */
1123            ));
1124    if (serr)
1125    {
1126        goto error;
1127    }
1128
1129    serr = NtStatusToErrno(
1130        LwIoCtxGetSessionKey(
1131            smb->context,
1132            smb->np,
1133            &sesskeylen,
1134            &sesskey));
1135    if (serr)
1136    {
1137        goto error;
1138    }
1139
1140    smb->info.session_key.length = sesskeylen;
1141    smb->info.session_key.data = malloc(sesskeylen);
1142    if (!smb->info.session_key.data)
1143    {
1144        serr = RPC_C_SOCKET_ENOMEM;
1145        goto error;
1146    }
1147    memcpy(smb->info.session_key.data, sesskey, sesskeylen);
1148#endif
1149
1150    /* Save address for future inquiries on this socket */
1151    memcpy(&smb->peeraddr, addr, sizeof(smb->peeraddr));
1152
1153    /* Since we did a connect, we will be sending first */
1154    smb->state = SMB_STATE_SEND;
1155
1156done:
1157
1158#if HAVE_LIKEWISE_LWIO
1159    if (sesskey)
1160    {
1161        RtlMemoryFree(sesskey);
1162    }
1163
1164    if (filename.FileName)
1165    {
1166        RtlMemoryFree(filename.FileName);
1167    }
1168
1169    if (smbpath)
1170    {
1171        free(smbpath);
1172    }
1173#endif
1174
1175    SMB_SOCKET_UNLOCK(smb);
1176
1177    // rpc_string_free handles when *ptr is NULL
1178    rpc_string_free((unsigned_char_t**) &netaddr, &dbg_status);
1179    rpc_string_free((unsigned_char_t**) &endpoint, &dbg_status);
1180
1181    return serr;
1182
1183error:
1184
1185    goto done;
1186}
1187
1188INTERNAL
1189rpc_socket_error_t
1190rpc__smb_socket_accept(
1191#if HAVE_LIKEWISE_LWIO
1192    rpc_socket_t sock,
1193    rpc_addr_p_t addr,
1194    rpc_socket_t *newsock
1195#else
1196   rpc_socket_t sock ATTRIBUTE_UNUSED,
1197   rpc_addr_p_t addr ATTRIBUTE_UNUSED,
1198   rpc_socket_t *newsock ATTRIBUTE_UNUSED
1199#endif
1200    )
1201{
1202    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1203
1204    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_accept called\n"));
1205
1206#if !defined(HAVE_LIKEWISE_LWIO)
1207    serr = RPC_C_SOCKET_ENOTSUP;
1208#else
1209    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1210    rpc_socket_t npsock = NULL;
1211    rpc_smb_socket_p_t npsmb = NULL;
1212    IO_FILE_HANDLE np = NULL;
1213    size_t i;
1214    char c = 0;
1215    BYTE clientaddr[4] = {0, 0, 0, 0};
1216    USHORT clientaddrlen = sizeof(clientaddr);
1217
1218    *newsock = NULL;
1219
1220    SMB_SOCKET_LOCK(smb);
1221
1222    while (smb->accept_backlog.length == 0)
1223    {
1224        if (smb->state == SMB_STATE_ERROR)
1225        {
1226            serr = -1;
1227            goto error;
1228        }
1229
1230        rpc__smb_socket_wait(smb);
1231    }
1232
1233    for (i = 0; i < smb->accept_backlog.capacity; i++)
1234    {
1235        if (smb->accept_backlog.queue[i] != NULL)
1236        {
1237            np = smb->accept_backlog.queue[i];
1238            smb->accept_backlog.queue[i] = NULL;
1239            smb->accept_backlog.length--;
1240            if (read(smb->accept_backlog.selectfd[0], &c, sizeof(c)) != sizeof(c))
1241            {
1242                serr = errno;
1243                goto error;
1244            }
1245            dcethread_cond_broadcast_throw(&smb->event);
1246            break;
1247        }
1248    }
1249
1250    serr = rpc__socket_open(sock->pseq_id, NULL, &npsock);
1251    if (serr)
1252    {
1253        goto error;
1254    }
1255
1256    npsmb = (rpc_smb_socket_p_t) npsock->data.pointer;
1257
1258    npsmb->np = np;
1259    np = NULL;
1260
1261    npsmb->state = SMB_STATE_RECV;
1262
1263    memcpy(&npsmb->localaddr, &smb->localaddr, sizeof(npsmb->localaddr));
1264
1265    /* Use our address as a template for client address */
1266    memcpy(&npsmb->peeraddr, &smb->localaddr, sizeof(npsmb->peeraddr));
1267
1268    /* Query for client address */
1269    serr = NtStatusToErrno(
1270        LwIoCtxGetPeerAddress(
1271            npsmb->context,
1272            npsmb->np,
1273            clientaddr,
1274            &clientaddrlen));
1275    if (serr)
1276    {
1277        goto error;
1278    }
1279
1280    if (clientaddrlen == sizeof(clientaddr))
1281    {
1282        snprintf(npsmb->peeraddr.remote_host, sizeof(npsmb->peeraddr.remote_host) - 1,
1283                 "%u.%u.%u.%u", clientaddr[0], clientaddr[1], clientaddr[2], clientaddr[3]);
1284    }
1285
1286    if (addr)
1287    {
1288        memcpy(addr, &npsmb->peeraddr, sizeof(npsmb->peeraddr));
1289    }
1290
1291     serr = NtStatusToErrno(
1292        LwIoCtxGetPeerPrincipalName(
1293            npsmb->context,
1294            npsmb->np,
1295            &npsmb->info.peer_principal));
1296    if (serr)
1297    {
1298        goto error;
1299    }
1300
1301    serr = NtStatusToErrno(
1302        LwIoCtxGetSessionKey(
1303            npsmb->context,
1304            npsmb->np,
1305            &npsmb->info.session_key.length,
1306            &npsmb->info.session_key.data));
1307    if (serr)
1308    {
1309        goto error;
1310    }
1311
1312    *newsock = npsock;
1313
1314error:
1315
1316    if (np)
1317    {
1318        NtCtxCloseFile(smb->context, np);
1319    }
1320
1321    SMB_SOCKET_UNLOCK(smb);
1322#endif
1323
1324    return serr;
1325}
1326
1327#if HAVE_LIKEWISE_LWIO
1328INTERNAL
1329void*
1330rpc__smb_socket_listen_thread(void* data)
1331{
1332    int serr = RPC_C_SOCKET_OK;
1333    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) data;
1334    IO_STATUS_BLOCK status_block = { 0 };
1335    char *endpoint = NULL;
1336    char *pipename = NULL;
1337    unsigned32 dbg_status = 0;
1338    PSTR smbpath = NULL;
1339    IO_FILE_NAME filename = { 0 };
1340    size_t i;
1341    char c = 0;
1342    LONG64 default_timeout = 0;
1343
1344    SMB_SOCKET_LOCK(smb);
1345
1346    while (smb->state != SMB_STATE_LISTEN)
1347    {
1348        if (smb->state == SMB_STATE_ERROR)
1349        {
1350            goto error;
1351        }
1352
1353        rpc__smb_socket_wait(smb);
1354    }
1355
1356    /* Extract endpoint */
1357    rpc__naf_addr_inq_endpoint ((rpc_addr_p_t) &smb->localaddr,
1358                                (unsigned_char_t**) &endpoint,
1359                                &dbg_status);
1360
1361    if (rpc__np_is_valid_endpoint(endpoint, &dbg_status))
1362    {
1363        pipename = endpoint + sizeof("\\pipe\\") - 1;
1364    }
1365    else
1366    {
1367        serr = RPC_C_SOCKET_EINVAL;
1368        goto error;
1369    }
1370
1371    serr = NtStatusToErrno(
1372        LwRtlCStringAllocatePrintf(
1373            &smbpath,
1374            "\\npfs\\%s",
1375            (char*) pipename));
1376    if (serr)
1377    {
1378        goto error;
1379    }
1380
1381    serr = NtStatusToErrno(
1382        LwRtlWC16StringAllocateFromCString(
1383            &filename.FileName,
1384            smbpath));
1385    if (serr)
1386    {
1387        goto error;
1388    }
1389
1390    while (smb->state == SMB_STATE_LISTEN)
1391    {
1392        SMB_SOCKET_UNLOCK(smb);
1393
1394        serr = NtStatusToErrno(
1395            LwNtCtxCreateNamedPipeFile(
1396                smb->context,                            /* IO context */
1397                NULL,                                    /* Security token */
1398                &smb->np,                                /* NP handle */
1399                NULL,                                    /* Async control */
1400                &status_block,                           /* IO status block */
1401                &filename,                               /* Filename */
1402                NULL,                                    /* Security descriptor */
1403                NULL,                                    /* Security QOS */
1404                GENERIC_READ | GENERIC_WRITE,            /* Desired access mode */
1405                FILE_SHARE_READ | FILE_SHARE_WRITE,      /* Share access mode */
1406                FILE_CREATE,                             /* Create disposition */
1407                0,                                       /* Create options */
1408                0,                                       /* Named pipe type */
1409                0,                                       /* Read mode */
1410                0,                                       /* Completion mode */
1411                smb->accept_backlog.capacity,            /* Maximum instances */
1412                0,                                       /* Inbound quota */
1413                0,                                       /* Outbound quota */
1414                &default_timeout                         /* Default timeout */
1415                ));
1416        if (serr)
1417        {
1418            SMB_SOCKET_LOCK(smb);
1419            goto error;
1420        }
1421
1422        serr = NtStatusToErrno(
1423            LwIoCtxConnectNamedPipe(
1424                smb->context,
1425                smb->np,
1426                NULL,
1427                &status_block));
1428        if (serr)
1429        {
1430            SMB_SOCKET_LOCK(smb);
1431            goto error;
1432        }
1433
1434        SMB_SOCKET_LOCK(smb);
1435
1436        /* Wait for a slot to open in the accept queue */
1437        while (smb->accept_backlog.length == smb->accept_backlog.capacity)
1438        {
1439            if (smb->state == SMB_STATE_ERROR)
1440            {
1441                goto error;
1442            }
1443
1444            rpc__smb_socket_wait(smb);
1445        }
1446
1447        /* Put the handle into the accept queue */
1448        for (i = 0; i < smb->accept_backlog.capacity; i++)
1449        {
1450            if (smb->accept_backlog.queue[i] == NULL)
1451            {
1452                smb->accept_backlog.queue[i] = smb->np;
1453                smb->np = NULL;
1454                smb->accept_backlog.length++;
1455                if (write(smb->accept_backlog.selectfd[1], &c, sizeof(c)) != sizeof(c))
1456                {
1457                    serr = errno;
1458                    goto error;
1459                }
1460                dcethread_cond_broadcast_throw(&smb->event);
1461                break;
1462            }
1463        }
1464    }
1465
1466error:
1467    if (filename.FileName)
1468    {
1469        RtlMemoryFree(filename.FileName);
1470    }
1471
1472    if (smbpath)
1473    {
1474        RtlMemoryFree(smbpath);
1475    }
1476
1477    // rpc_string_free handles when *ptr is NULL
1478    rpc_string_free((unsigned_char_t**) &endpoint, &dbg_status);
1479
1480    if (serr)
1481    {
1482        rpc__smb_socket_change_state(smb, SMB_STATE_ERROR);
1483    }
1484
1485    SMB_SOCKET_UNLOCK(smb);
1486
1487    return NULL;
1488}
1489#endif
1490
1491INTERNAL
1492rpc_socket_error_t
1493rpc__smb_socket_listen(
1494#if HAVE_LIKEWISE_LWIO
1495   rpc_socket_t sock,
1496   int backlog
1497#else
1498    rpc_socket_t sock ATTRIBUTE_UNUSED,
1499    int backlog ATTRIBUTE_UNUSED
1500#endif
1501    )
1502{
1503    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1504    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_listen called\n"));
1505
1506#if !defined(HAVE_LIKEWISE_LWIO)
1507    serr = RPC_C_SOCKET_ENOTSUP;
1508    return serr;
1509#else
1510    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1511
1512    SMB_SOCKET_LOCK(smb);
1513
1514    smb->accept_backlog.capacity = backlog;
1515    smb->accept_backlog.length = 0;
1516    smb->accept_backlog.queue = calloc(backlog, sizeof(*smb->accept_backlog.queue));
1517
1518    if (!smb->accept_backlog.queue)
1519    {
1520        serr = RPC_C_SOCKET_ENOMEM;
1521        goto error;
1522    }
1523
1524    if (pipe(smb->accept_backlog.selectfd) != 0)
1525    {
1526        serr = errno;
1527        goto error;
1528    }
1529
1530    smb->state = SMB_STATE_LISTEN;
1531
1532    dcethread_create_throw(&smb->listen_thread, NULL, rpc__smb_socket_listen_thread, smb);
1533
1534error:
1535
1536    SMB_SOCKET_UNLOCK(smb);
1537#endif
1538    return serr;
1539}
1540
1541#if HAVE_SMBCLIENT_FRAMEWORK
1542INTERNAL
1543rpc_socket_error_t
1544smb_data_send(
1545#if SMB_NP_NO_TRANSACTIONS
1546    rpc_socket_t sock
1547#else
1548    rpc_socket_t sock ATTRIBUTE_UNUSED
1549#endif
1550    )
1551{
1552    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1553    rpc_smb_socket_p_t smb;
1554    unsigned char* cursor;
1555    size_t bytes_written = 0;
1556#if SMB_NP_NO_TRANSACTIONS
1557    NTSTATUS status;
1558
1559    smb = (rpc_smb_socket_p_t) sock->data.pointer;
1560    cursor = smb->sendbuffer.base;
1561#endif
1562
1563    do
1564    {
1565#if SMB_NP_NO_TRANSACTIONS
1566        /* <bms> Write the data out without using transactions */
1567        status = SMBWriteFile(smb->handle,
1568                              smb->hFile,
1569                              cursor,
1570                              0,
1571                              smb->sendbuffer.start_cursor - cursor,
1572                              &bytes_written);
1573
1574        if (!NT_SUCCESS(status))
1575        {
1576            RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_do_send - SMBWriteFile failed 0x%x\n", status));
1577            serr = rpc_smb_ntstatus_to_rpc_error (status);
1578        }
1579#else
1580        /* <bms> for transactions, do nothing here.  Later in the
1581         receive, we will do the send and receive in a single
1582         transaction. */
1583        serr = RPC_C_SOCKET_OK;
1584        goto error;
1585#endif
1586
1587        if (serr)
1588        {
1589            goto error;
1590        }
1591
1592        cursor += bytes_written;
1593    } while (cursor < smb->sendbuffer.start_cursor);
1594
1595    /* Settle the remaining data (which hopefully should be zero if
1596     the runtime calls us with complete packets) to the start of
1597     the send buffer */
1598    rpc__smb_buffer_settle(&smb->sendbuffer);
1599
1600error:
1601
1602    return serr;
1603}
1604
1605INTERNAL
1606rpc_socket_error_t
1607smb_data_do_recv(
1608    rpc_socket_t sock,
1609    size_t* count
1610)
1611{
1612    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1613    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1614    size_t bytes_requested = 0;
1615    size_t bytes_read = 0;
1616    NTSTATUS status = STATUS_SUCCESS;
1617#if !SMB_NP_NO_TRANSACTIONS
1618    unsigned char* cursor = smb->sendbuffer.base;
1619    rpc_cn_common_hdr_p_t packet;
1620    size_t frag_len;
1621    size_t bytes_written;
1622    int sent_data = 0;
1623#endif
1624
1625    *count = 0;
1626
1627    do
1628    {
1629        serr = rpc__smb_buffer_ensure_available(&smb->recvbuffer, smb->maxRecvBufferSize);
1630        if (serr)
1631        {
1632            goto error;
1633        }
1634
1635        bytes_read = 0;
1636        bytes_requested = rpc__smb_buffer_available(&smb->recvbuffer);
1637#if SMB_NP_NO_TRANSACTIONS
1638        /* <bms> Read the data in without using transactions */
1639        status = SMBReadFile(smb->handle,
1640                             smb->hFile,
1641                             smb->recvbuffer.end_cursor,
1642                             0,
1643                             bytes_requested,
1644                             &bytes_read);
1645
1646        if (!NT_SUCCESS(status))
1647        {
1648            RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1649                           ("rpc__smb_socket_do_recv - SMBReadFile failed 0x%x\n",
1650                            status));
1651            serr = rpc_smb_ntstatus_to_rpc_error (status);
1652        }
1653#else
1654        if ((smb->sendbuffer.start_cursor - cursor) != 0)
1655        {
1656            /* Check to see if this is a last fragment or not */
1657            packet = (rpc_cn_common_hdr_p_t) cursor;
1658            while (!(packet->flags & RPC_C_CN_FLAGS_LAST_FRAG))
1659            {
1660                /* its not a last fragment, so send with SMBWriteFile */
1661                frag_len = rpc__smb_fragment_size(packet);
1662
1663                /* Safety check to make sure we are not past the end
1664                 of the sendbuffer */
1665                if ( (cursor + frag_len) > smb->sendbuffer.start_cursor)
1666                {
1667                    RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1668                                   ("rpc__smb_socket_do_recv - past end of send buffer\n"));
1669                    serr = RPC_C_SOCKET_EIO;
1670                    goto error;
1671                }
1672
1673                bytes_written = 0;
1674                sent_data = 1;
1675                status = SMBWriteFile(smb->handle,
1676                                      smb->hFile,
1677                                      cursor,
1678                                      0,
1679                                      frag_len,
1680                                      &bytes_written);
1681
1682                if (!NT_SUCCESS(status))
1683                {
1684                    RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1685                                   ("rpc__smb_socket_do_send - SMBWriteFile failed 0x%x\n",
1686                                    status));
1687                    serr = rpc_smb_ntstatus_to_rpc_error (status);
1688                }
1689
1690                if (serr)
1691                {
1692                    goto error;
1693                }
1694                cursor += bytes_written;
1695                packet = (rpc_cn_common_hdr_p_t) cursor;
1696            }
1697        }
1698
1699        if ((smb->sendbuffer.start_cursor - cursor) == 0)
1700        {
1701            /* <bms> Must be reading in a fragment, so read the data in
1702             without using transactions */
1703            status = SMBReadFile(smb->handle,
1704                                 smb->hFile,
1705                                 smb->recvbuffer.end_cursor,
1706                                 0,
1707                                 bytes_requested,
1708                                 &bytes_read);
1709            if (!NT_SUCCESS(status))
1710            {
1711                RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1712                               ("rpc__smb_socket_do_recv - SMBReadFile failed 0x%x\n",
1713                                status));
1714                serr = rpc_smb_ntstatus_to_rpc_error (status);
1715            }
1716        }
1717        else
1718        {
1719            /* <bms> for transactions, do send and rcv in a single transaction. */
1720            sent_data = 1;
1721            status = SMBTransactNamedPipe(smb->handle,
1722                                          smb->hFile,
1723                                          cursor,
1724                                          smb->sendbuffer.start_cursor - cursor,
1725                                          smb->recvbuffer.end_cursor,
1726                                          bytes_requested,
1727                                          &bytes_read);
1728
1729            if (!NT_SUCCESS(status))
1730            {
1731                RPC_DBG_PRINTF(rpc_e_dbg_general, 7,
1732                               ("rpc__smb_socket_do_recv - SMBTransactNamedPipe failed 0x%x\n",
1733                                status));
1734                serr = rpc_smb_ntstatus_to_rpc_error (status);
1735            }
1736        }
1737
1738        if (sent_data == 1)
1739        {
1740            /* assume all the data got sent */
1741            rpc__smb_buffer_settle(&smb->sendbuffer);
1742            sent_data = 0;
1743            cursor = smb->sendbuffer.base;
1744        }
1745#endif
1746
1747        if (status == STATUS_END_OF_FILE)
1748        {
1749            serr = RPC_C_SOCKET_OK;
1750            bytes_read = 0;
1751        }
1752        else
1753        {
1754            smb->recvbuffer.end_cursor += bytes_read;
1755        }
1756
1757        if (((size_t)*count + bytes_read) > SIZE_T_MAX ||
1758            ((size_t)*count + bytes_read) < (size_t)*count) {
1759            serr = RPC_C_SOCKET_ENOSPC;
1760            goto error;
1761        }
1762
1763        *count += (size_t)bytes_read;
1764    } while (NT_SUCCESS(status) && bytes_read == bytes_requested);
1765
1766error:
1767
1768    return serr;
1769}
1770#endif
1771
1772INTERNAL
1773rpc_socket_error_t
1774rpc__smb_socket_do_send(
1775    rpc_socket_t sock
1776    )
1777{
1778#if HAVE_SMBCLIENT_FRAMEWORK
1779    return (smb_data_send (sock));
1780#elif HAVE_LIKEWISE_LWIO
1781    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1782    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1783    unsigned char* cursor = smb->sendbuffer.base;
1784    DWORD bytes_written = 0;
1785    IO_STATUS_BLOCK io_status = { 0 };
1786
1787    do
1788    {
1789        serr = NtStatusToErrno(
1790            NtCtxWriteFile(
1791                smb->context,                          /* IO context */
1792                smb->np,                               /* File handle */
1793                NULL,                                  /* Async control block */
1794                &io_status,                            /* IO status block */
1795                smb->sendbuffer.base,                  /* Buffer */
1796                smb->sendbuffer.start_cursor - cursor, /* Length */
1797                NULL,                                  /* Byte offset */
1798                NULL                                   /* Key */
1799                ));
1800
1801        if (serr)
1802        {
1803            goto error;
1804        }
1805
1806        bytes_written = io_status.BytesTransferred;
1807        cursor += bytes_written;
1808    } while (cursor < smb->sendbuffer.start_cursor);
1809
1810    /* Settle the remaining data (which hopefully should be zero if
1811       the runtime calls us with complete packets) to the start of
1812       the send buffer */
1813    rpc__smb_buffer_settle(&smb->sendbuffer);
1814
1815error:
1816
1817    return serr;
1818#else
1819    return RPC_C_SOCKET_ENOTSUP;
1820#endif
1821}
1822
1823INTERNAL
1824rpc_socket_error_t
1825rpc__smb_socket_do_recv(
1826    rpc_socket_t sock,
1827    size_t* count
1828    )
1829{
1830#if HAVE_SMBCLIENT_FRAMEWORK
1831    return (smb_data_do_recv (sock, count));
1832#elif HAVE_LIKEWISE_LWIO
1833    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1834    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1835    DWORD bytes_requested = 0;
1836    DWORD bytes_read = 0;
1837    IO_STATUS_BLOCK io_status = { 0 };
1838    NTSTATUS status = STATUS_SUCCESS;
1839
1840    *count = 0;
1841
1842    do
1843    {
1844        serr = rpc__smb_buffer_ensure_available(&smb->recvbuffer, smb->maxRecvBufferSize);
1845        if (serr)
1846        {
1847            goto error;
1848        }
1849
1850        bytes_read = 0;
1851        bytes_requested = rpc__smb_buffer_available(&smb->recvbuffer);
1852
1853        status = NtCtxReadFile(
1854            smb->context,                 /* IO context */
1855            smb->np,                      /* File handle */
1856            NULL,                         /* Async control block */
1857            &io_status,                   /* IO status block */
1858            smb->recvbuffer.end_cursor,   /* Buffer */
1859            bytes_requested,              /* Length */
1860            NULL,                         /* Byte offset */
1861            NULL                          /* Key */
1862            );
1863        if (status == STATUS_END_OF_FILE)
1864        {
1865            serr = 0;
1866            bytes_read = 0;
1867        }
1868        else
1869        {
1870            serr = NtStatusToErrno(status);
1871            bytes_read = io_status.BytesTransferred;
1872            smb->recvbuffer.end_cursor += bytes_read;
1873        }
1874
1875        if (((off_t)*count + bytes_read) > SIZE_T_MAX ||
1876            ((off_t)*count + bytes_read) < (off_t)*count) {
1877            serr = RPC_C_SOCKET_ENOSPC;
1878            goto error;
1879        }
1880
1881        *count += bytes_read;
1882    } while (NT_SUCCESS(status) && bytes_read == bytes_requested);
1883
1884error:
1885
1886    return serr;
1887#else
1888        return RPC_C_SOCKET_ENOTSUP;
1889#endif
1890
1891}
1892
1893INTERNAL
1894rpc_socket_error_t
1895rpc__smb_socket_sendmsg(
1896    rpc_socket_t sock,
1897    rpc_socket_iovec_p_t iov,
1898    int iov_len,
1899    rpc_addr_p_t addr ATTRIBUTE_UNUSED,
1900    size_t *cc
1901    )
1902{
1903    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1904    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1905    int i;
1906    size_t pending = 0;
1907
1908    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_sendmsg called\n"));
1909
1910    SMB_SOCKET_LOCK(smb);
1911
1912    /* Wait until we are in a state where we can send */
1913    while (smb->state != SMB_STATE_SEND)
1914    {
1915        if (smb->state == SMB_STATE_ERROR)
1916        {
1917            serr = -1;
1918            goto error;
1919        }
1920        rpc__smb_socket_wait(smb);
1921    }
1922
1923    *cc = 0;
1924
1925    /* Append all fragments into a single buffer */
1926    for (i = 0; i < iov_len; i++)
1927    {
1928        serr = rpc__smb_buffer_append(&smb->sendbuffer, iov[i].iov_base, iov[i].iov_len);
1929
1930        if (serr)
1931        {
1932            goto error;
1933        }
1934
1935        *cc += (int)iov[i].iov_len;
1936    }
1937
1938    /* Look for the last fragment and do send if we find it */
1939    if (rpc__smb_buffer_advance_cursor(&smb->sendbuffer, &pending))
1940    {
1941        serr = rpc__smb_socket_do_send(sock);
1942        if (serr)
1943        {
1944            goto error;
1945        }
1946
1947        /* Switch into recv mode */
1948        rpc__smb_socket_change_state(smb, SMB_STATE_RECV);
1949    }
1950
1951cleanup:
1952
1953    SMB_SOCKET_UNLOCK(smb);
1954
1955    return serr;
1956
1957error:
1958
1959    rpc__smb_socket_change_state(smb, SMB_STATE_ERROR);
1960
1961    goto cleanup;
1962}
1963
1964INTERNAL
1965rpc_socket_error_t
1966rpc__smb_socket_recvfrom(
1967    rpc_socket_t sock ATTRIBUTE_UNUSED,
1968    byte_p_t buf ATTRIBUTE_UNUSED,
1969    int len ATTRIBUTE_UNUSED,
1970    rpc_addr_p_t from ATTRIBUTE_UNUSED,
1971    size_t *cc ATTRIBUTE_UNUSED
1972)
1973{
1974    rpc_socket_error_t serr = RPC_C_SOCKET_ENOTSUP;
1975
1976    fprintf(stderr, "WARNING: unsupported smb socket function %s\n", __FUNCTION__);
1977    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_recvfrom called\n"));
1978
1979    return serr;
1980}
1981
1982INTERNAL
1983rpc_socket_error_t
1984rpc__smb_socket_recvmsg(
1985    rpc_socket_t sock,
1986    rpc_socket_iovec_p_t iov,
1987    int iov_len,
1988    rpc_addr_p_t addr,
1989    size_t *cc
1990)
1991{
1992    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1993    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
1994    int i;
1995    size_t pending;
1996    size_t count;
1997
1998    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_recvmsg called\n"));
1999
2000    SMB_SOCKET_LOCK(smb);
2001
2002    while (smb->state != SMB_STATE_RECV)
2003    {
2004        if (smb->state == SMB_STATE_ERROR)
2005        {
2006            serr = -1;
2007            goto error;
2008        }
2009        rpc__smb_socket_wait(smb);
2010    }
2011
2012    *cc = 0;
2013
2014    if (rpc__smb_buffer_length(&smb->recvbuffer) == 0)
2015    {
2016        /* Nothing in buffer, read a complete message */
2017        do
2018        {
2019            serr = rpc__smb_socket_do_recv(sock, &count);
2020            if (serr)
2021            {
2022                goto error;
2023            }
2024            if (count == 0)
2025            {
2026                break;
2027            }
2028        } while (!rpc__smb_buffer_advance_cursor(&smb->recvbuffer, NULL));
2029
2030        /* Reset cursor back to start to begin disperal into scatter buffer */
2031        smb->recvbuffer.start_cursor = smb->recvbuffer.base;
2032    }
2033
2034    for (i = 0; i < iov_len; i++)
2035    {
2036        pending = rpc__smb_buffer_pending(&smb->recvbuffer);
2037        if (iov[i].iov_len < pending)
2038        {
2039            memcpy(iov[i].iov_base, smb->recvbuffer.start_cursor, iov[i].iov_len);
2040
2041            smb->recvbuffer.start_cursor += iov[i].iov_len;
2042            *cc += (int)iov[i].iov_len;
2043        }
2044        else
2045        {
2046            memcpy(iov[i].iov_base, smb->recvbuffer.start_cursor, pending);
2047
2048            *cc += (int)pending;
2049
2050            /* Reset buffer because we have emptied it */
2051            smb->recvbuffer.start_cursor = smb->recvbuffer.end_cursor = smb->recvbuffer.base;
2052            /* Switch into send mode */
2053            rpc__smb_socket_change_state(smb, SMB_STATE_SEND);
2054        }
2055    }
2056
2057    if (addr)
2058    {
2059        memcpy(addr, &smb->peeraddr, sizeof(smb->peeraddr));
2060    }
2061
2062cleanup:
2063
2064    SMB_SOCKET_UNLOCK(smb);
2065
2066    return serr;
2067
2068error:
2069
2070    rpc__smb_socket_change_state(smb, SMB_STATE_ERROR);
2071
2072    goto cleanup;
2073}
2074
2075INTERNAL
2076rpc_socket_error_t
2077rpc__smb_socket_inq_endpoint(
2078    rpc_socket_t sock,
2079    rpc_addr_p_t addr
2080)
2081{
2082    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_inq_endpoint called\n"));
2083
2084    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2085    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
2086
2087    if (addr->len == 0)
2088    {
2089        addr->len = sizeof(addr->sa);
2090    }
2091
2092    addr->rpc_protseq_id = smb->localaddr.rpc_protseq_id;
2093    memcpy(&addr->sa, &smb->localaddr.sa, addr->len);
2094
2095    return serr;
2096}
2097
2098INTERNAL
2099rpc_socket_error_t
2100rpc__smb_socket_set_broadcast(
2101    rpc_socket_t sock ATTRIBUTE_UNUSED
2102)
2103{
2104    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_broadcast called\n"));
2105
2106    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2107
2108    return serr;
2109}
2110
2111#if HAVE_SMBCLIENT_FRAMEWORK && HAVE_SMBCLIENT_SMBGETSERVERPROPERTIES
2112INTERNAL
2113rpc__smbclient_set_bufs(
2114    rpc_socket_t sock,
2115    unsigned32 *ntxsize,
2116    unsigned32 *nrxsize
2117)
2118{
2119    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
2120    SMBServerPropertiesV1 server_properties;
2121    NTSTATUS status;
2122
2123    if ( !smb->handle || (smb->maxSendBufferSize != 0) )
2124    {
2125        return (RPC_C_SOCKET_OK);
2126    }
2127
2128    memset(&server_properties, 0, sizeof(server_properties));
2129
2130    /* try to get the max transaction size that is supported */
2131    status = SMBGetServerProperties(smb->handle, &server_properties,
2132            kPropertiesVersion, sizeof(server_properties));
2133    if (NT_SUCCESS(status))
2134    {
2135        smb->maxSendBufferSize = (unsigned32) MIN (server_properties.maxWriteBytes, server_properties.maxTransactBytes);
2136        smb->maxRecvBufferSize = (unsigned32) MIN (server_properties.maxReadBytes, server_properties.maxTransactBytes);
2137
2138        /* round down to nearest 1K */
2139        smb->maxSendBufferSize = (smb->maxSendBufferSize / 1024) * 1024;
2140        smb->maxRecvBufferSize = (smb->maxRecvBufferSize / 1024) * 1024;
2141
2142        /* fragments can not be bigger than UInt16 */
2143        if (smb->maxSendBufferSize > UINT16_MAX)
2144            smb->maxSendBufferSize = UINT16_MAX;
2145
2146        if (smb->maxRecvBufferSize > UINT16_MAX)
2147            smb->maxRecvBufferSize = UINT16_MAX;
2148    }
2149
2150    *ntxsize = (unsigned32) smb->maxSendBufferSize;
2151    *nrxsize = (unsigned32) smb->maxRecvBufferSize;
2152
2153    return (RPC_C_SOCKET_OK);
2154}
2155#endif
2156
2157INTERNAL
2158rpc_socket_error_t
2159rpc__smb_socket_set_bufs(
2160    rpc_socket_t sock ATTRIBUTE_UNUSED,
2161    unsigned32 txsize ATTRIBUTE_UNUSED,
2162    unsigned32 rxsize ATTRIBUTE_UNUSED,
2163    unsigned32 *ntxsize ATTRIBUTE_UNUSED,
2164    unsigned32 *nrxsize ATTRIBUTE_UNUSED
2165)
2166{
2167    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2168
2169    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_bufs called\n"));
2170
2171#if HAVE_SMBCLIENT_FRAMEWORK && HAVE_SMBCLIENT_SMBGETSERVERPROPERTIES
2172    serr = rpc__smbclient_set_bufs(sock, ntxsize, nrxsize);
2173#else
2174    *ntxsize = MIN(RPC_C_CN_LARGE_FRAG_SIZE, RPC_C_SOCKET_MAX_SNDBUF);
2175    *nrxsize = MIN(RPC_C_CN_LARGE_FRAG_SIZE, RPC_C_SOCKET_MAX_RCVBUF);
2176#endif
2177
2178    return serr;
2179}
2180
2181INTERNAL
2182rpc_socket_error_t
2183rpc__smb_socket_set_nbio(
2184    rpc_socket_t sock ATTRIBUTE_UNUSED
2185    )
2186{
2187    rpc_socket_error_t serr = RPC_C_SOCKET_ENOTSUP;
2188
2189    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_nbio called\n"));
2190    fprintf(stderr, "WARNING: unsupported smb socket function %s\n", __FUNCTION__);
2191
2192    return serr;
2193}
2194
2195INTERNAL
2196rpc_socket_error_t
2197rpc__smb_socket_set_close_on_exec(
2198    rpc_socket_t sock ATTRIBUTE_UNUSED
2199    )
2200{
2201    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_close_on_exec called\n"));
2202    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2203
2204    return serr;
2205}
2206
2207INTERNAL
2208rpc_socket_error_t
2209rpc__smb_socket_getpeername(
2210    rpc_socket_t sock,
2211    rpc_addr_p_t addr
2212    )
2213{
2214    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2215    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
2216
2217    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_getpeername called\n"));
2218    SMB_SOCKET_LOCK(smb);
2219
2220#if HAVE_LIKEWISE_LWIO
2221    if (!smb->np)
2222    {
2223        serr = RPC_C_SOCKET_EINVAL;
2224        goto error;
2225    }
2226#endif
2227
2228    memcpy(addr, &smb->peeraddr, sizeof(smb->peeraddr));
2229
2230error:
2231
2232    SMB_SOCKET_UNLOCK(smb);
2233
2234    return serr;
2235}
2236
2237INTERNAL
2238rpc_socket_error_t
2239rpc__smb_socket_get_if_id(
2240    rpc_socket_t sock ATTRIBUTE_UNUSED,
2241    rpc_network_if_id_t *network_if_id ATTRIBUTE_UNUSED
2242    )
2243{
2244    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2245
2246    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_get_if_id called\n"));
2247    *network_if_id = SOCK_STREAM;
2248
2249    return serr;
2250}
2251
2252INTERNAL
2253rpc_socket_error_t
2254rpc__smb_socket_set_keepalive(
2255    rpc_socket_t sock ATTRIBUTE_UNUSED
2256    )
2257{
2258    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_keepalive called\n"));
2259    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2260
2261    return serr;
2262}
2263
2264INTERNAL
2265rpc_socket_error_t
2266rpc__smb_socket_nowriteblock_wait(
2267    rpc_socket_t sock ATTRIBUTE_UNUSED,
2268    struct timeval *tmo ATTRIBUTE_UNUSED
2269    )
2270{
2271    rpc_socket_error_t serr = RPC_C_SOCKET_ENOTSUP;
2272
2273    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_nowriteblock_wait called\n"));
2274    fprintf(stderr, "WARNING: unsupported smb socket function %s\n", __FUNCTION__);
2275
2276    return serr;
2277}
2278
2279INTERNAL
2280rpc_socket_error_t
2281rpc__smb_socket_set_rcvtimeo(
2282    rpc_socket_t sock ATTRIBUTE_UNUSED,
2283    struct timeval *tmo ATTRIBUTE_UNUSED
2284    )
2285{
2286    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2287    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_set_rcvtimeo called\n"));
2288
2289    return serr;
2290}
2291
2292INTERNAL
2293rpc_socket_error_t
2294rpc__smb_socket_getpeereid(
2295    rpc_socket_t sock ATTRIBUTE_UNUSED,
2296    uid_t *euid ATTRIBUTE_UNUSED,
2297    gid_t *egid ATTRIBUTE_UNUSED
2298    )
2299{
2300    rpc_socket_error_t serr = RPC_C_SOCKET_ENOTSUP;
2301
2302    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_getpeereid called\n"));
2303    fprintf(stderr, "WARNING: unsupported smb socket function %s\n", __FUNCTION__);
2304
2305    return serr;
2306}
2307
2308INTERNAL
2309int
2310rpc__smb_socket_get_select_desc(
2311    rpc_socket_t sock
2312    )
2313{
2314    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_get_select_desc called\n"));
2315   rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
2316    return smb->accept_backlog.selectfd[0];
2317}
2318
2319INTERNAL
2320rpc_socket_error_t
2321rpc__smb_socket_enum_ifaces(
2322    rpc_socket_t sock ATTRIBUTE_UNUSED,
2323    rpc_socket_enum_iface_fn_p_t efun ATTRIBUTE_UNUSED,
2324    rpc_addr_vector_p_t *rpc_addr_vec ATTRIBUTE_UNUSED,
2325    rpc_addr_vector_p_t *netmask_addr_vec ATTRIBUTE_UNUSED,
2326    rpc_addr_vector_p_t *broadcast_addr_vec ATTRIBUTE_UNUSED
2327    )
2328{
2329    rpc_socket_error_t serr = RPC_C_SOCKET_ENOTSUP;
2330
2331    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_enum_ifaces called\n"));
2332    fprintf(stderr, "WARNING: unsupported smb socket function %s\n", __FUNCTION__);
2333
2334    return serr;
2335}
2336
2337INTERNAL
2338rpc_socket_error_t
2339rpc__smb_socket_inq_transport_info(
2340#if HAVE_LIKEWISE_LWIO
2341    rpc_socket_t sock,
2342#else
2343    rpc_socket_t sock ATTRIBUTE_UNUSED,
2344#endif
2345    rpc_transport_info_handle_t* info
2346    )
2347{
2348    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
2349#if HAVE_LIKEWISE_LWIO
2350    rpc_smb_socket_p_t smb = (rpc_smb_socket_p_t) sock->data.pointer;
2351#endif
2352    rpc_smb_transport_info_p_t smb_info = NULL;
2353
2354    RPC_DBG_PRINTF(rpc_e_dbg_general, 7, ("rpc__smb_socket_inq_transport_info called\n"));
2355
2356#if !defined(HAVE_LIKEWISE_LWIO)
2357    serr = RPC_C_SOCKET_ENOTSUP;
2358    goto error;
2359#else
2360    smb_info = calloc(1, sizeof(*smb_info));
2361
2362    if (!smb_info)
2363    {
2364        serr = RPC_C_SOCKET_ENOMEM;
2365        goto error;
2366    }
2367
2368    if (smb->info.creds)
2369    {
2370        serr = NtStatusToErrno(LwIoCopyCreds(smb->info.creds, &smb_info->creds));
2371        if (serr)
2372        {
2373            goto error;
2374        }
2375    }
2376
2377    if (smb->info.peer_principal)
2378    {
2379        smb_info->peer_principal = strdup(smb->info.peer_principal);
2380        if (!smb_info->peer_principal)
2381        {
2382            serr = RPC_C_SOCKET_ENOMEM;
2383            goto error;
2384        }
2385    }
2386
2387    if (smb->info.session_key.data)
2388    {
2389        smb_info->session_key.data = malloc(smb->info.session_key.length);
2390        if (!smb_info->session_key.data)
2391        {
2392            serr = RPC_C_SOCKET_ENOMEM;
2393            goto error;
2394        }
2395
2396        memcpy(smb_info->session_key.data, smb->info.session_key.data, smb->info.session_key.length);
2397        smb_info->session_key.length = smb->info.session_key.length;
2398    }
2399
2400    *info = (rpc_transport_info_handle_t) smb_info;
2401#endif
2402
2403error:
2404
2405    if (serr)
2406    {
2407        *info = NULL;
2408
2409        if (smb_info)
2410        {
2411            rpc_smb_transport_info_free((rpc_transport_info_handle_t) smb_info);
2412        }
2413    }
2414    return serr;
2415}
2416
2417/* ======================================================================== */
2418/*
2419 * R P C _ _ S M B _ S O C K E T _ D U P L I C A T E
2420 *
2421 * Wrap the native socket representation in a rpc_socket_t. We duplicate the
2422 * socket file descriptor because we will eventually end up close(2)ing it.
2423 *
2424 * Note that we sneakily replace the socket's vtable, thereby turning it into
2425 * a BSD socket. This is necessary because the native socket representation
2426 * that comes down from inetd or launchd is a file descriptor. If we used the
2427 * real SMB vtable, then we would be hooked into the Likewise SMB redirector
2428 * codem which is not what we want.
2429 */
2430
2431INTERNAL rpc_socket_error_t
2432rpc__smb_socket_duplicate(
2433    rpc_socket_t        sock,
2434    rpc_protseq_id_t    protseq_id,
2435    const void *        sockrep /* pointer to native representation */
2436    )
2437{
2438    const int *         sockfd = (const int *)sockrep;
2439    rpc_socket_error_t  serr = RPC_C_SOCKET_OK;
2440
2441    RPC_DBG_GPRINTF(("(rpc__smb_socket_duplicate) sockfd=%d\n",
2442                sockfd ? *sockfd : -1));
2443
2444    if (sockfd == NULL || *sockfd == -1) {
2445        return RPC_C_SOCKET_ENOTSOCK;
2446    }
2447
2448    if (protseq_id != rpc_c_protseq_id_ncacn_np)
2449    {
2450        return RPC_C_SOCKET_EINVAL;
2451    }
2452
2453    rpc__smb_socket_destruct(sock);
2454
2455    serr = rpc_g_bsd_socket_vtbl.socket_construct(sock,
2456            rpc_c_protseq_id_ncalrpc, NULL);
2457    if (RPC_SOCKET_IS_ERR(serr)) {
2458        return serr;
2459    }
2460
2461    // Flip the rpc_socket_t info ASAP in case some higer level
2462    // calls a generic rpc__socket routine.
2463    sock->vtbl = &rpc_g_bsd_socket_vtbl;
2464    sock->pseq_id = protseq_id;
2465
2466    serr = rpc_g_bsd_socket_vtbl.socket_duplicate(sock,
2467            rpc_c_protseq_id_ncacn_np, sockrep);
2468    if (RPC_SOCKET_IS_ERR(serr)) {
2469        return serr;
2470    }
2471
2472    return serr;
2473}
2474
2475INTERNAL
2476rpc_socket_error_t
2477rpc__smb_socket_transport_inq_access_token(
2478#if HAVE_LIKEWISE_LWMAPSECURITY
2479    rpc_transport_info_handle_t info,
2480    rpc_access_token_p_t* token
2481#else
2482   rpc_transport_info_handle_t info ATTRIBUTE_UNUSED,
2483   rpc_access_token_p_t* token ATTRIBUTE_UNUSED
2484#endif
2485    )
2486{
2487#if HAVE_LIKEWISE_LWMAPSECURITY
2488    rpc_smb_transport_info_p_t smb_info = (rpc_smb_transport_info_p_t) info;
2489    NTSTATUS status = STATUS_SUCCESS;
2490    PLW_MAP_SECURITY_CONTEXT context = NULL;
2491
2492    status = LwMapSecurityCreateContext(&context);
2493    if (status) goto error;
2494
2495    status = LwMapSecurityCreateAccessTokenFromCStringUsername(
2496        context,
2497        token,
2498        smb_info->peer_principal);
2499    if (status) goto error;
2500
2501error:
2502
2503    LwMapSecurityFreeContext(&context);
2504
2505    return LwNtStatusToErrno(status);
2506#else
2507    return RPC_C_SOCKET_ENOTSUP;
2508#endif
2509}
2510
2511rpc_socket_vtbl_t const rpc_g_smb_socket_vtbl =
2512{
2513    .socket_duplicate = rpc__smb_socket_duplicate,
2514    .socket_construct = rpc__smb_socket_construct,
2515    .socket_destruct = rpc__smb_socket_destruct,
2516    .socket_bind = rpc__smb_socket_bind,
2517    .socket_connect = rpc__smb_socket_connect,
2518    .socket_accept = rpc__smb_socket_accept,
2519    .socket_listen = rpc__smb_socket_listen,
2520    .socket_sendmsg = rpc__smb_socket_sendmsg,
2521    .socket_recvfrom = rpc__smb_socket_recvfrom,
2522    .socket_recvmsg = rpc__smb_socket_recvmsg,
2523    .socket_inq_endpoint = rpc__smb_socket_inq_endpoint,
2524    .socket_set_broadcast = rpc__smb_socket_set_broadcast,
2525    .socket_set_bufs = rpc__smb_socket_set_bufs,
2526    .socket_set_nbio = rpc__smb_socket_set_nbio,
2527    .socket_set_close_on_exec = rpc__smb_socket_set_close_on_exec,
2528    .socket_getpeername = rpc__smb_socket_getpeername,
2529    .socket_get_if_id = rpc__smb_socket_get_if_id,
2530    .socket_set_keepalive = rpc__smb_socket_set_keepalive,
2531    .socket_nowriteblock_wait = rpc__smb_socket_nowriteblock_wait,
2532    .socket_set_rcvtimeo = rpc__smb_socket_set_rcvtimeo,
2533    .socket_getpeereid = rpc__smb_socket_getpeereid,
2534    .socket_get_select_desc = rpc__smb_socket_get_select_desc,
2535    .socket_enum_ifaces = rpc__smb_socket_enum_ifaces,
2536    .socket_inq_transport_info = rpc__smb_socket_inq_transport_info,
2537    .transport_info_free = rpc_smb_transport_info_free,
2538    .transport_info_equal = rpc__smb_transport_info_equal,
2539    .transport_inq_access_token = rpc__smb_socket_transport_inq_access_token
2540};
2541