1/*
2 * Copyright (c) 2008 - 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include <smbclient/smbclient.h>
26#include <smbclient/ntstatus.h>
27#include <smbclient/smbclient_internal.h>
28
29#include <algorithm>
30#include <vector>
31#include <cstdlib>
32#include <assert.h>
33#include <string>
34
35#include "lmshare.h"
36#include "memory.hpp"
37#include "rpc_helpers.hpp"
38
39#define MEMPOOL_DEBUG 0
40
41struct free_function : public std::unary_function<void *, void>
42{
43    void operator()(void * ptr) const {
44#if MEMPOOL_DEBUG
45        SMBLogInfo("rpc_mempool(%llu): freeing ptr %p", ASL_LEVEL_DEBUG
46				  (unsigned long long)pthread_self(), ptr);
47#endif
48        std::free(ptr);
49    }
50};
51
52#ifndef __clang_analyzer__
53/* <12135199> Clang static analyzer does not understand the below code */
54
55rpc_mempool *
56rpc_mempool::allocate(
57					  size_t payload_size)
58{
59    void * ptr;
60
61    ptr = std::calloc(1, rpc_mempool::block_size() + payload_size);
62    if (!ptr) {
63        return NULL;
64    }
65
66    return new (ptr) rpc_mempool();
67}
68#endif
69
70void
71rpc_mempool::destroy(
72					 rpc_mempool * pool)
73{
74    pool->~rpc_mempool();
75    std::free(pool);
76}
77
78rpc_mempool::rpc_mempool()
79: ptrs(10)
80{
81#if MEMPOOL_DEBUG
82    SMBLogInfo("constructing rpc_mempool at %p", ASL_LEVEL_DEBUG, this);
83#endif
84    ptrs.resize(0);
85}
86
87rpc_mempool::~rpc_mempool()
88{
89#if MEMPOOL_DEBUG
90    SMBLogInfo("destroying rpc_mempool at %p", ASL_LEVEL_DEBUG, this);
91#endif
92    std::for_each(ptrs.begin(), ptrs.end(), free_function());
93}
94
95void *
96rpc_mempool::alloc(
97				   size_t sz)
98{
99    void * ptr = platform::allocate(NULL, sz);
100    if (ptr) {
101        ptrs.push_back(ptr);
102    }
103
104#if MEMPOOL_DEBUG
105    SMBLogInfo("rpc_mempool(%llu): allocated ptr %p for %u bytes", ASL_LEVEL_DEBUG,
106			  (unsigned long long)pthread_self(), ptr, (unsigned)sz);
107#endif
108    return ptr;
109}
110
111void
112rpc_mempool::free(
113				  void * ptr)
114{
115    ptr_list_type::iterator which =
116	std::find(ptrs.begin(), ptrs.end(), ptr);
117
118    assert(which != ptrs.end());
119    ptrs.erase(which);
120
121#if MEMPOOL_DEBUG
122    SMBLogInfo("rpc_mempool(%llu): freed ptr %p", ASL_LEVEL_DEBUG,
123			  (unsigned long long)pthread_self(), ptr);
124#endif
125    free_function f; f(ptr);
126}
127
128idl_void_p_t
129rpc_pool_allocate(idl_void_p_t context, idl_size_t sz)
130{
131    rpc_mempool * pool = (rpc_mempool *)context;
132    return pool->alloc(sz);
133}
134
135void
136rpc_pool_free(idl_void_p_t context, idl_void_p_t ptr)
137{
138    rpc_mempool * pool = (rpc_mempool *)context;
139    return pool->free(ptr);
140}
141
142rpc_binding::rpc_binding(const rpc_binding& src)
143{
144    unsigned32 status;
145    rpc_binding_copy(src.get(), &binding_handle, &status);
146    assert(status == rpc_s_ok);
147}
148
149rpc_binding::rpc_binding(const char * string_binding)
150{
151    error_status_t status;
152
153    rpc_binding_from_string_binding((idl_char *)string_binding,
154									&binding_handle, &status);
155    if (status != rpc_s_ok) {
156        SMBLogInfo("rpc_binding_from_string_binding failed on <%s> status %#08x",
157                   ASL_LEVEL_ERR,
158                   string_binding == NULL ? "nullstr" : string_binding,
159                   status);
160        binding_handle = NULL;
161    }
162}
163
164rpc_binding::~rpc_binding()
165{
166    if (binding_handle) {
167        error_status_t status;
168
169        rpc_network_close(binding_handle, &status);
170        rpc_binding_free(&binding_handle, &status);
171    }
172}
173
174// Return an appropriate binding for the given ServerName.
175rpc_binding
176make_rpc_binding(
177				 const char * ServerName,
178				 const char * EndPoint)
179{
180    char * binding_string = NULL;
181    char * endpoint_string = NULL;
182    uint32_t status;
183
184    if (!EndPoint) {
185        return rpc_binding();
186    }
187
188    if (ServerName) {
189        /* add in the "\pipe\" to the endpoint */
190        asprintf(&endpoint_string, "\\pipe\\%s]", EndPoint);
191
192        rpc_string_binding_compose(NULL,
193                                   (idl_char *) "ncacn_np",
194                                   (idl_char *) ServerName,
195                                   (idl_char *) endpoint_string,
196                                   NULL,
197                                   (idl_char **) &binding_string,
198                                   &status);
199        if (status != 0) {
200            SMBLogInfo("rpc_string_binding_compose failed on <%s>:<%s> status %#08x",
201                       ASL_LEVEL_ERR,
202                       ServerName == NULL ? "nullstr" : ServerName,
203                       EndPoint == NULL ? "nullstr" : EndPoint,
204                       status);
205
206            /* fallback to the old way instead */
207            asprintf(&binding_string, "ncacn_np:%s[%s]",
208                     ServerName, endpoint_string);
209        }
210
211        if (endpoint_string != NULL) {
212            free(endpoint_string);
213        }
214    }
215    else {
216        rpc_string_binding_compose(NULL,
217                                   (idl_char *) "ncalrpc",
218                                   NULL,
219                                   (idl_char *) EndPoint,
220                                   NULL,
221                                   (idl_char **) &binding_string,
222                                   &status);
223        if (status != 0) {
224            SMBLogInfo("rpc_string_binding_compose failed on <%s> status %#08x",
225                       ASL_LEVEL_ERR,
226                       EndPoint == NULL ? "nullstr" : EndPoint,
227                       status);
228
229            /* fallback to the old way instead */
230            asprintf(&binding_string, "ncalrpc:[%s]", EndPoint);
231        }
232    }
233
234    if (!binding_string) {
235        platform::invoke_new_handler();
236    }
237
238    rpc_binding binding(binding_string);
239
240    if (status == 0) {
241        /* rpc_string_binding_compose worked */
242        if (binding_string != NULL) {
243            rpc_string_free((idl_char **) &binding_string, &status);
244            if (status != 0) {
245                SMBLogInfo("rpc_string_free failed on <%s> status %#08x",
246                           ASL_LEVEL_ERR,
247                           binding_string == NULL ? "nullstr" : binding_string,
248                           status);
249            }
250        }
251    }
252    else {
253        /* must have used asprintf */
254        if (binding_string != NULL) {
255            free(binding_string);
256        }
257    }
258
259    return binding;
260}
261
262error_status_t
263rpc_exception_status(
264					 dcethread_exc * exc)
265{
266    int status;
267
268    status = dcethread_exc_getstatus(exc);
269    if (status == -1) {
270        SMBLogInfo("unexpected RPC exception: kind=%#x address=%p %s", ASL_LEVEL_DEBUG,
271				  exc->kind, exc->match.address, exc->name);
272        return rpc_m_unexpected_exc;
273    }
274
275    return status;
276}
277
278/* vim: set sw=4 ts=4 tw=79 et: */
279