15772Sas200622 /* 25772Sas200622 * CDDL HEADER START 35772Sas200622 * 45772Sas200622 * The contents of this file are subject to the terms of the 55772Sas200622 * Common Development and Distribution License (the "License"). 65772Sas200622 * You may not use this file except in compliance with the License. 75772Sas200622 * 85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95772Sas200622 * or http://www.opensolaris.org/os/licensing. 105772Sas200622 * See the License for the specific language governing permissions 115772Sas200622 * and limitations under the License. 125772Sas200622 * 135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 185772Sas200622 * 195772Sas200622 * CDDL HEADER END 205772Sas200622 */ 215772Sas200622 /* 22*8670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 /* 278334SJose.Borrego@Sun.COM * NDR heap management. The heap is used for temporary storage by 285772Sas200622 * both the client and server side library routines. In order to 295772Sas200622 * support the different requirements of the various RPCs, the heap 305772Sas200622 * can grow dynamically if required. We start with a single block 315772Sas200622 * and perform sub-allocations from it. If an RPC requires more space 325772Sas200622 * we will continue to add it a block at a time. This means that we 335772Sas200622 * don't hog lots of memory on every call to support the few times 345772Sas200622 * that we actually need a lot heap space. 355772Sas200622 * 365772Sas200622 * Note that there is no individual free function. Once space has been 375772Sas200622 * allocated, it remains allocated until the heap is destroyed. This 385772Sas200622 * shouldn't be an issue because the heap is being filled with data to 395772Sas200622 * be marshalled or unmarshalled and we need it all to be there until 405772Sas200622 * the point that the entire heap is no longer required. 415772Sas200622 */ 425772Sas200622 435772Sas200622 #include <sys/errno.h> 445772Sas200622 #include <stdlib.h> 455772Sas200622 #include <string.h> 465772Sas200622 #include <strings.h> 475772Sas200622 #include <sys/uio.h> 485772Sas200622 495772Sas200622 #include <smbsrv/libsmb.h> 508334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h> 518334SJose.Borrego@Sun.COM #include <smbsrv/smb_sid.h> 525772Sas200622 535772Sas200622 /* 545772Sas200622 * Allocate a heap structure and the first heap block. For many RPC 555772Sas200622 * operations this will be the only time we need to malloc memory 565772Sas200622 * in this instance of the heap. The only point of note here is that 575772Sas200622 * we put the heap management data in the first block to avoid a 588334SJose.Borrego@Sun.COM * second malloc. Make sure that sizeof(ndr_heap_t) is smaller 598334SJose.Borrego@Sun.COM * than NDR_HEAP_BLKSZ. 605772Sas200622 * 615772Sas200622 * Note that the heap management data is at the start of the first block. 625772Sas200622 * 635772Sas200622 * Returns a pointer to the newly created heap, which is used like an 645772Sas200622 * opaque handle with the rest of the heap management interface.. 655772Sas200622 */ 668334SJose.Borrego@Sun.COM ndr_heap_t * 678334SJose.Borrego@Sun.COM ndr_heap_create(void) 685772Sas200622 { 698334SJose.Borrego@Sun.COM ndr_heap_t *heap; 705772Sas200622 char *base; 71*8670SJose.Borrego@Sun.COM size_t allocsize = sizeof (ndr_heap_t) + NDR_HEAP_BLKSZ; 725772Sas200622 73*8670SJose.Borrego@Sun.COM if ((heap = malloc(allocsize)) == NULL) 745772Sas200622 return (NULL); 755772Sas200622 76*8670SJose.Borrego@Sun.COM base = (char *)heap; 778334SJose.Borrego@Sun.COM bzero(heap, sizeof (ndr_heap_t)); 785772Sas200622 798334SJose.Borrego@Sun.COM heap->iovcnt = NDR_HEAP_MAXIOV; 805772Sas200622 heap->iov = heap->iovec; 815772Sas200622 heap->iov->iov_base = base; 828334SJose.Borrego@Sun.COM heap->iov->iov_len = sizeof (ndr_heap_t); 83*8670SJose.Borrego@Sun.COM heap->top = base + allocsize; 848334SJose.Borrego@Sun.COM heap->next = base + sizeof (ndr_heap_t); 855772Sas200622 865772Sas200622 return (heap); 875772Sas200622 } 885772Sas200622 895772Sas200622 /* 905772Sas200622 * Deallocate all of the memory associated with a heap. This is the 915772Sas200622 * only way to deallocate heap memory, it isn't possible to free the 925772Sas200622 * space obtained by individual malloc calls. 935772Sas200622 * 945772Sas200622 * Note that the first block contains the heap management data, which 955772Sas200622 * is deleted last. 965772Sas200622 */ 975772Sas200622 void 988334SJose.Borrego@Sun.COM ndr_heap_destroy(ndr_heap_t *heap) 995772Sas200622 { 1005772Sas200622 int i; 1015772Sas200622 char *p; 1025772Sas200622 1035772Sas200622 if (heap) { 1048334SJose.Borrego@Sun.COM for (i = 1; i < NDR_HEAP_MAXIOV; ++i) { 1055772Sas200622 if ((p = heap->iovec[i].iov_base) != NULL) 1065772Sas200622 free(p); 1075772Sas200622 } 1085772Sas200622 1095772Sas200622 free(heap); 1105772Sas200622 } 1115772Sas200622 } 1125772Sas200622 1135772Sas200622 /* 1145772Sas200622 * Allocate space in the specified heap. All requests are padded, if 1155772Sas200622 * required, to ensure dword alignment. If the current iov will be 1165772Sas200622 * exceeded, we allocate a new block and setup the next iov. Otherwise 1175772Sas200622 * all we have to do is move the next pointer and update the current 1185772Sas200622 * iov length. 1195772Sas200622 * 1205772Sas200622 * On success, a pointer to the allocated (dword aligned) area is 1215772Sas200622 * returned. Otherwise a null pointer is returned. 1225772Sas200622 */ 1235772Sas200622 void * 1248334SJose.Borrego@Sun.COM ndr_heap_malloc(ndr_heap_t *heap, unsigned size) 1255772Sas200622 { 1265772Sas200622 char *p; 1275772Sas200622 int incr_size; 1285772Sas200622 1298334SJose.Borrego@Sun.COM size += NDR_ALIGN4(size); 1305772Sas200622 1315772Sas200622 if (heap == NULL || size == 0) 1325772Sas200622 return (NULL); 1335772Sas200622 1345772Sas200622 p = heap->next; 1355772Sas200622 1365772Sas200622 if (p + size > heap->top) { 1375772Sas200622 if ((heap->iovcnt == 0) || ((--heap->iovcnt) == 0)) 1385772Sas200622 return (NULL); 1395772Sas200622 1408334SJose.Borrego@Sun.COM incr_size = (size < NDR_HEAP_BLKSZ) ? NDR_HEAP_BLKSZ : size; 1415772Sas200622 1425772Sas200622 if ((p = (char *)malloc(incr_size)) == NULL) 1435772Sas200622 return (NULL); 1445772Sas200622 1455772Sas200622 ++heap->iov; 1465772Sas200622 heap->iov->iov_base = p; 1475772Sas200622 heap->iov->iov_len = 0; 1485772Sas200622 heap->top = p + incr_size; 1495772Sas200622 } 1505772Sas200622 1515772Sas200622 heap->next = p + size; 1525772Sas200622 heap->iov->iov_len += size; 1535772Sas200622 return ((void *)p); 1545772Sas200622 } 1555772Sas200622 1565772Sas200622 /* 1575772Sas200622 * Convenience function to do heap strdup. 1585772Sas200622 */ 1595772Sas200622 void * 1608334SJose.Borrego@Sun.COM ndr_heap_strdup(ndr_heap_t *heap, const char *s) 1615772Sas200622 { 1625772Sas200622 int len; 1635772Sas200622 void *p; 1645772Sas200622 1655772Sas200622 if (s == NULL) 1665772Sas200622 return (NULL); 1675772Sas200622 1685772Sas200622 /* 1695772Sas200622 * We don't need to clutter the heap with empty strings. 1705772Sas200622 */ 1715772Sas200622 if ((len = strlen(s)) == 0) 1725772Sas200622 return (""); 1735772Sas200622 1748334SJose.Borrego@Sun.COM if ((p = ndr_heap_malloc(heap, len+1)) != NULL) 1755772Sas200622 (void) strcpy((char *)p, s); 1765772Sas200622 1775772Sas200622 return (p); 1785772Sas200622 } 1795772Sas200622 1805772Sas200622 /* 1818334SJose.Borrego@Sun.COM * Make an ndr_mstring_t from a regular string. 1828334SJose.Borrego@Sun.COM */ 1838334SJose.Borrego@Sun.COM int 1848334SJose.Borrego@Sun.COM ndr_heap_mstring(ndr_heap_t *heap, const char *s, ndr_mstring_t *out) 1858334SJose.Borrego@Sun.COM { 1868334SJose.Borrego@Sun.COM if (s == NULL || out == NULL) 1878334SJose.Borrego@Sun.COM return (-1); 1888334SJose.Borrego@Sun.COM 1898334SJose.Borrego@Sun.COM out->length = mts_wcequiv_strlen(s); 1908334SJose.Borrego@Sun.COM out->allosize = out->length + sizeof (mts_wchar_t); 1918334SJose.Borrego@Sun.COM 1928334SJose.Borrego@Sun.COM if ((out->str = ndr_heap_strdup(heap, s)) == NULL) 1938334SJose.Borrego@Sun.COM return (-1); 1948334SJose.Borrego@Sun.COM 1958334SJose.Borrego@Sun.COM return (0); 1968334SJose.Borrego@Sun.COM } 1978334SJose.Borrego@Sun.COM 1988334SJose.Borrego@Sun.COM /* 1995772Sas200622 * Our regular string marshalling always creates null terminated strings 2005772Sas200622 * but some Windows clients and servers are pedantic about the string 2015772Sas200622 * formats they will accept and require non-null terminated strings. 2025772Sas200622 * This function can be used to build a wide-char, non-null terminated 2035772Sas200622 * string in the heap as a varying/conformant array. We need to do the 2045772Sas200622 * wide-char conversion here because the marshalling code won't be 2055772Sas200622 * aware that this is really a string. 2065772Sas200622 */ 2075772Sas200622 void 2088334SJose.Borrego@Sun.COM ndr_heap_mkvcs(ndr_heap_t *heap, char *s, ndr_vcstr_t *vc) 2095772Sas200622 { 2105772Sas200622 int mlen; 2115772Sas200622 2127619SJose.Borrego@Sun.COM vc->wclen = mts_wcequiv_strlen(s); 2137619SJose.Borrego@Sun.COM vc->wcsize = vc->wclen; 2147619SJose.Borrego@Sun.COM 2158334SJose.Borrego@Sun.COM mlen = sizeof (ndr_vcs_t) + vc->wcsize + sizeof (mts_wchar_t); 2167619SJose.Borrego@Sun.COM 2178334SJose.Borrego@Sun.COM vc->vcs = ndr_heap_malloc(heap, mlen); 2185772Sas200622 2197619SJose.Borrego@Sun.COM if (vc->vcs) { 2207619SJose.Borrego@Sun.COM vc->vcs->vc_first_is = 0; 2217619SJose.Borrego@Sun.COM vc->vcs->vc_length_is = vc->wclen / sizeof (mts_wchar_t); 2227619SJose.Borrego@Sun.COM (void) mts_mbstowcs((mts_wchar_t *)vc->vcs->buffer, s, 2237619SJose.Borrego@Sun.COM vc->vcs->vc_length_is); 2247619SJose.Borrego@Sun.COM } 2257619SJose.Borrego@Sun.COM } 2265772Sas200622 2277619SJose.Borrego@Sun.COM void 2288334SJose.Borrego@Sun.COM ndr_heap_mkvcb(ndr_heap_t *heap, uint8_t *data, uint32_t datalen, 2298334SJose.Borrego@Sun.COM ndr_vcbuf_t *vcbuf) 2307619SJose.Borrego@Sun.COM { 2317619SJose.Borrego@Sun.COM int mlen; 2327619SJose.Borrego@Sun.COM 2337619SJose.Borrego@Sun.COM if (data == NULL || datalen == 0) { 2348334SJose.Borrego@Sun.COM bzero(vcbuf, sizeof (ndr_vcbuf_t)); 2357619SJose.Borrego@Sun.COM return; 2367619SJose.Borrego@Sun.COM } 2375772Sas200622 2387619SJose.Borrego@Sun.COM vcbuf->len = datalen; 2397619SJose.Borrego@Sun.COM vcbuf->size = datalen; 2407619SJose.Borrego@Sun.COM 2418334SJose.Borrego@Sun.COM mlen = sizeof (ndr_vcbuf_t) + datalen; 2427619SJose.Borrego@Sun.COM 2438334SJose.Borrego@Sun.COM vcbuf->vcb = ndr_heap_malloc(heap, mlen); 2447619SJose.Borrego@Sun.COM 2457619SJose.Borrego@Sun.COM if (vcbuf->vcb) { 2467619SJose.Borrego@Sun.COM vcbuf->vcb->vc_first_is = 0; 2477619SJose.Borrego@Sun.COM vcbuf->vcb->vc_length_is = datalen; 2487619SJose.Borrego@Sun.COM bcopy(data, vcbuf->vcb->buffer, datalen); 2495772Sas200622 } 2505772Sas200622 } 2515772Sas200622 2528334SJose.Borrego@Sun.COM /* 2538334SJose.Borrego@Sun.COM * Duplcate a SID in the heap. 2548334SJose.Borrego@Sun.COM */ 2558334SJose.Borrego@Sun.COM smb_sid_t * 2568334SJose.Borrego@Sun.COM ndr_heap_siddup(ndr_heap_t *heap, smb_sid_t *sid) 2578334SJose.Borrego@Sun.COM { 2588334SJose.Borrego@Sun.COM smb_sid_t *new_sid; 2598334SJose.Borrego@Sun.COM unsigned size; 2608334SJose.Borrego@Sun.COM 2618334SJose.Borrego@Sun.COM if (sid == NULL) 2628334SJose.Borrego@Sun.COM return (NULL); 2638334SJose.Borrego@Sun.COM 2648334SJose.Borrego@Sun.COM size = smb_sid_len(sid); 2658334SJose.Borrego@Sun.COM 2668334SJose.Borrego@Sun.COM if ((new_sid = ndr_heap_malloc(heap, size)) == NULL) 2678334SJose.Borrego@Sun.COM return (NULL); 2688334SJose.Borrego@Sun.COM 2698334SJose.Borrego@Sun.COM bcopy(sid, new_sid, size); 2708334SJose.Borrego@Sun.COM return (new_sid); 2718334SJose.Borrego@Sun.COM } 2728334SJose.Borrego@Sun.COM 2735772Sas200622 int 2748334SJose.Borrego@Sun.COM ndr_heap_used(ndr_heap_t *heap) 2755772Sas200622 { 2765772Sas200622 int used = 0; 2775772Sas200622 int i; 2785772Sas200622 2798334SJose.Borrego@Sun.COM for (i = 0; i < NDR_HEAP_MAXIOV; ++i) 2805772Sas200622 used += heap->iovec[i].iov_len; 2815772Sas200622 2825772Sas200622 return (used); 2835772Sas200622 } 2845772Sas200622 2855772Sas200622 int 2868334SJose.Borrego@Sun.COM ndr_heap_avail(ndr_heap_t *heap) 2875772Sas200622 { 2885772Sas200622 int avail; 2895772Sas200622 int count; 2905772Sas200622 2915772Sas200622 count = (heap->iovcnt == 0) ? 0 : (heap->iovcnt - 1); 2925772Sas200622 2938334SJose.Borrego@Sun.COM avail = count * NDR_HEAP_BLKSZ; 2945772Sas200622 avail += (heap->top - heap->next); 2955772Sas200622 2965772Sas200622 return (avail); 2975772Sas200622 } 298