1/*
2 * Copyright (c) 2010 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/*
78**
79**  NAME
80**
81**      twr_np.c
82**
83**  FACILITY:
84**
85**      Protocol Tower Services for the internet address family
86**
87**  ABSTRACT:
88**
89**      The protocol tower service provides routines that:
90**
91**      o  convert a socket address to the lower floors of
92**         a protocol tower
93**
94**      o  convert a protocol tower to a socket address
95**
96**
97*/
98
99#include <commonp.h>    /* Common declarations for all RPC runtime */
100#include <com.h>        /* Common communications services */
101#include <twrp.h>	/* Private tower services */
102#include <npnaf.h>
103
104/*
105 *  Include the Internet specific socket address
106 */
107#if HAVE_SYS_UN_H
108#include <sys/un.h>
109#else
110#include <un.h>
111#endif
112#include <sys/param.h>
113#include <netdb.h>
114#include <ctype.h>
115
116/*
117**++
118**
119**  ROUTINE NAME:       twr_np_lower_flrs_from_sa
120**
121**  SCOPE:              PUBLIC - declared in twr.idl
122**
123**  DESCRIPTION:
124**
125**  Creates the canonical representation of an internet protocol tower's
126**  lower floors from a sockaddr. The canonical form can be transmitted
127**  on the wire, or included in a DNS tower.
128**
129**  INPUTS:
130**
131**      trans_prot      Integer value specifying the transport layer
132**                      protocol for the Internet address family.
133**                      For address family RPC_C_NAF_ID_NP specify:
134**
135**                         RPC_C_NETWORK_PROTOCOL_ID_NP for udp
136**
137**      sa              Internet-specific socket address data
138**                      structure.
139**
140**  INPUTS/OUTPUTS:     none
141**
142**  OUTPUTS:
143**
144**      lower_flrs      Returns the lower tower floors in a twr_t
145**                      structure (includes the floor count in the
146**                      "tower_octet_string" member).
147**
148**      status          A value indicating the return status of the routine:
149**                          twr_s_ok
150**                          twr_s_unknown_sa
151**
152**  IMPLICIT INPUTS:    none
153**
154**  IMPLICIT OUTPUTS:   none
155**
156**  FUNCTION VALUE:     void
157**
158**  SIDE EFFECTS:       none
159**
160**--
161**/
162
163PUBLIC void twr_np_lower_flrs_from_sa
164(
165    sockaddr_p_t      sa,
166    twr_p_t           *lower_flrs,
167    unsigned32        *status
168)
169{
170    unsigned8   protocol_id[TWR_C_NUM_NP_LOWER_FLRS];
171    unsigned16  id_size = TWR_C_TOWER_PROT_ID_SIZE,
172                floor_count,
173                related_data_size[TWR_C_NUM_NP_LOWER_FLRS],
174                twr_rep_16;
175    unsigned32  count,
176                twr_t_length;
177    byte_p_t    related_data_ptr[TWR_C_NUM_NP_LOWER_FLRS],
178                tmp_tower;
179    char hostname[MAXHOSTNAMELEN], *p;
180
181    CODING_ERROR (status);
182    RPC_VERIFY_INIT ();
183
184    RPC_DBG_GPRINTF(("(twr_np_lower_flrs_from_sa) called\n"));
185
186    if (sa->family == RPC_C_NAF_ID_UXD)
187    {
188        protocol_id[0] = TWR_C_FLR_PROT_ID_NP;
189        protocol_id[1] = TWR_C_FLR_PROT_ID_NB;
190    }
191    else
192    {
193        *status = twr_s_unknown_sa;
194        return;
195    }
196
197    /*
198     * Since we now know the socket address we're dealing with,
199     * collect the sizes of each field to allocate memory, and
200     * remember the pointers to the fields so we can copy the
201     * data once we have allocated the tower string.
202     */
203    floor_count = TWR_C_NUM_NP_LOWER_FLRS;
204
205    /*
206     * related_data[0] contains the pipe name (eg. \PIPE\lsass)
207     */
208    related_data_ptr[0] = (unsigned char*) ((struct sockaddr_un *)sa)->sun_path;
209    if (strncmp((char*) related_data_ptr[0], (char*) RPC_C_NP_DIR"/", RPC_C_NP_DIR_LEN + 1) == 0)
210    {
211        /* Path is relative, but do not chop off first /. */
212        related_data_ptr[0] += RPC_C_NP_DIR_LEN;
213    }
214    related_data_size[0] = strlen((char*) related_data_ptr[0]) + 1;
215
216    /*
217     * related_data[1] contains the NetBIOS name (eg. \\MYSERVER)
218     */
219    hostname[0] = '\\';
220    hostname[1] = '\\';
221    gethostname(&hostname[2], MAXHOSTNAMELEN - 3);
222    hostname[MAXHOSTNAMELEN - 1] = '\0';
223    for (p = &hostname[2]; *p != '\0'; p++)
224        *p = toupper((int)*p);
225    related_data_size[1] = strlen(hostname) + 1;
226    related_data_ptr[1] = (unsigned char*) hostname;
227
228    /*
229     * Calculate the length of the tower floors.
230     */
231
232    twr_t_length = TWR_C_TOWER_FLR_COUNT_SIZE;  /* to store floor count */
233
234    for ( count = 0; count < floor_count; count++ )
235    {
236        twr_t_length += TWR_C_FLR_OVERHEAD;
237        twr_t_length += related_data_size[count];
238    }
239
240    /*
241     * Next allocate space for the tower structure
242     */
243    RPC_MEM_ALLOC (
244        *lower_flrs,
245        twr_p_t,
246        sizeof (twr_t) + (twr_t_length - 1),
247        RPC_C_MEM_TOWER,
248        RPC_C_MEM_WAITOK );
249
250    /*
251     * Copy the length of the tower octet string into the tower structure
252     */
253    (*lower_flrs)->tower_length = twr_t_length;
254
255    /*
256     * Copy the floor information into the tower octet string
257     */
258
259    /*
260     * Use a temporary for the octet string since we need
261     * to increment the pointer.
262     */
263    tmp_tower = (*lower_flrs)->tower_octet_string;
264
265    /*
266     * Copy the number of floors into the tower octet string
267     */
268    twr_rep_16 = floor_count;
269    RPC_RESOLVE_ENDIAN_INT16 (twr_rep_16);
270    memcpy ((char *)tmp_tower, (char *)&twr_rep_16,
271            TWR_C_TOWER_FLR_COUNT_SIZE);
272
273    tmp_tower += TWR_C_TOWER_FLR_COUNT_SIZE;
274
275    /*
276     * Convert the protocol identifier size to its proper
277     * representation for use in the following loop.
278     */
279    RPC_RESOLVE_ENDIAN_INT16 (id_size);
280
281    for ( count = 0; count < floor_count; count++ )
282    {
283        /*
284         * Copy the length of the protocol identifier field into
285         * tower octet string.  (Converted before the loop.)
286         */
287        memcpy ((char *)tmp_tower, (char *)&id_size,
288                TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
289
290        tmp_tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE;
291
292        /*
293         * Copy the protocol identifier into tower octet string
294         * (1 byte so no need to convert endian representation).
295         */
296        memcpy ((char *)tmp_tower, (char *)&(protocol_id[count]),
297                TWR_C_TOWER_PROT_ID_SIZE);
298
299        tmp_tower += TWR_C_TOWER_PROT_ID_SIZE;
300
301        /*
302         * Copy the length of the address data field into
303         * tower octet string.
304         */
305        twr_rep_16 = related_data_size[count];
306        RPC_RESOLVE_ENDIAN_INT16 (twr_rep_16);
307        memcpy ((char *)tmp_tower, (char *)&twr_rep_16,
308                TWR_C_TOWER_FLR_RHS_COUNT_SIZE);
309
310        tmp_tower += TWR_C_TOWER_FLR_RHS_COUNT_SIZE;
311
312        /*
313         * If there is addressing data, copy the address data field into
314         * tower octet string
315         */
316        if (related_data_size[count])
317        {
318            memcpy ((char *)tmp_tower, (char *)related_data_ptr[count],
319                    related_data_size[count]);
320
321            /* Convert slashes */
322            for (p = (char*) tmp_tower; *p != '\0'; p++) {
323                if (*p == '/')
324                    *p = '\\';
325            }
326
327            /*
328             * Set up for the next floor.
329             */
330            tmp_tower += related_data_size[count];
331        }
332    }
333
334    *status = twr_s_ok;
335}
336
337/*
338**++
339**
340**  ROUTINE NAME:       twr_np_lower_flrs_to_sa
341**
342**  SCOPE:              PUBLIC - declared in twr.idl
343**
344**  DESCRIPTION:
345**
346**  Creates an internet sockaddr from the canonical representation of an
347**  internet protocol tower's lower floors.
348**
349**  INPUTS:
350**
351**      tower_octet_string
352**                      The protocol tower to convert to a sockaddr.
353**
354**  INPUTS/OUTPUTS:     none
355**
356**  OUTPUTS:
357**
358**      sa            Returns a pointer to the created sockaddr structure.
359**
360**      sa_len          Returns the length, in bytes, of the returned
361**                      "sa" argument.
362**
363**      status          A value indicating the return status of the routine:
364**                          twr_s_ok
365**                          twr_s_unknown_tower
366**
367**  IMPLICIT INPUTS:    none
368**
369**  IMPLICIT OUTPUTS:   none
370**
371**  FUNCTION VALUE:     void
372**
373**  SIDE EFFECTS:       none
374**
375**--
376**/
377
378PUBLIC void twr_np_lower_flrs_to_sa
379(
380    byte_p_t          tower_octet_string,
381    sockaddr_p_t      *sa,
382    unsigned32        *sa_len,
383    unsigned32        *status
384)
385{
386    unsigned8   id;
387    byte_p_t    tower;
388    unsigned16  count,
389                floor_count,
390                id_size,
391                addr_size;
392    unsigned32  length;
393    char       *p;
394
395    CODING_ERROR (status);
396    RPC_VERIFY_INIT ();
397
398    id_size = 0;
399
400    /*
401     * Make sure we have a pointer to some data structure.
402     */
403    if ( !(tower = tower_octet_string))
404    {
405        *status = twr_s_unknown_tower;
406        return;
407    }
408
409    RPC_DBG_GPRINTF(("(twr_np_lower_flrs_to_sa) called\n"));
410
411    /*
412     * Get the tower floor count
413     */
414    memcpy ((char *)&floor_count, (char *)tower, TWR_C_TOWER_FLR_COUNT_SIZE);
415    RPC_RESOLVE_ENDIAN_INT16 (floor_count);
416
417    tower += TWR_C_TOWER_FLR_COUNT_SIZE;
418
419    /*
420     * Skip over the (application's) upper floors while we look for the
421     * beginning of the np-specific lower floors.
422     */
423    for ( count = 0; count < floor_count; count++ )
424    {
425        /*
426         * Get the length of this floor's protocol id field (don't advance
427         * the pointer).
428         */
429        memcpy ((char *)&id_size, (char *)tower,
430                TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
431        RPC_RESOLVE_ENDIAN_INT16 (id_size);
432
433        /*
434         * Get the protocol id (don't advance the pointer).
435         * Expect one byte; no need to convert.
436         */
437        memcpy ((char *)&id, (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE),
438                TWR_C_TOWER_PROT_ID_SIZE);
439
440        /*
441         * See if we support the protocol id.
442         */
443        if ( (id_size == TWR_C_TOWER_PROT_ID_SIZE) &&
444             (id == TWR_C_FLR_PROT_ID_NP))
445        {
446            /*
447             * Indicate we found the beginning of the np floors.
448             */
449            *status = twr_s_ok;
450
451            break;
452        }
453        else
454        {
455            /*
456             * Skip this floor.  Get the address size in order
457             * to know how much to skip.
458             */
459            memcpy ((char *)&addr_size,
460                    (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE +
461                            id_size), TWR_C_TOWER_FLR_RHS_COUNT_SIZE);
462            RPC_RESOLVE_ENDIAN_INT16 (addr_size);
463
464            tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size +
465                     TWR_C_TOWER_FLR_RHS_COUNT_SIZE + addr_size;
466
467            /*
468             * For now, assume we don't find the floors we're looking for.
469             */
470            *status = twr_s_unknown_tower;
471        }
472    }
473
474    if (*status != twr_s_ok)
475    {
476        return;
477    }
478
479    /*
480     * Skip the floor's protocol id field length and protocol id
481     * (now move the pointer).  We already know it's
482     * TWR_C_FLR_PROT_ID_NP.
483     */
484    tower += (TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size);
485
486    /*
487     * Allocate space for sockaddr
488     */
489    length = sizeof(struct sockaddr_un);
490
491    RPC_MEM_ALLOC (
492        *sa,
493        sockaddr_p_t,
494        length,
495        RPC_C_MEM_SOCKADDR,
496        RPC_C_MEM_WAITOK );
497
498    *sa_len = length;
499
500    /*
501     * make sure unused bytes are null
502     */
503    memset ((char *) *sa, 0, length);
504
505    /*
506     * define this as an internet family socket
507     */
508    ((struct sockaddr_un *)(*sa))->sun_family = RPC_C_NAF_ID_UXD;
509
510    /*
511     * Get the length of pipe name
512     */
513    memcpy ((char *)&addr_size, (char *)tower, RPC_C_TOWER_FLR_RHS_COUNT_SIZE);
514    RPC_RESOLVE_ENDIAN_INT16 (addr_size);
515    tower += RPC_C_TOWER_FLR_RHS_COUNT_SIZE;
516
517    /*
518     * Copy the pipe name to the sockaddr
519     */
520    tower[addr_size - 1] = '\0';
521    addr_size += RPC_C_NP_DIR_LEN + 1;
522    if ((size_t)addr_size + 1 > sizeof(((struct sockaddr_un *)(*sa))->sun_path))
523    {
524        *status = rpc_s_no_memory;
525        RPC_MEM_FREE (*sa, RPC_C_MEM_SOCKADDR);
526        return;
527    }
528    snprintf(((struct sockaddr_un *)(*sa))->sun_path, length, "%s/%s",
529             RPC_C_NP_DIR, tower);
530    for (p = ((struct sockaddr_un *)(*sa))->sun_path; *p != '\0'; p++)
531    {
532        if (*p == '\\')
533            *p = '/';
534    }
535
536    *status = twr_s_ok;
537
538    /* For now, disregard the NetBIOS address. */
539}
540