1 NDRGEN(1ONBLD) illumos Build Tools NDRGEN(1ONBLD) 2 3 4 5 NAME 6 ndrgen - NDL RPC protocol compiler 7 8 SYNOPSIS 9 ndrgen [ -Y cpp-path ] file [ file ] ... 10 11 12 DESCRIPTION 13 The ndrgen utility is a tool that generates C code to implement a 14 DCERPC/MSRPC Network Data Representation (NDR) protocol. The input to 15 ndrgen is a language similar to C known as Network Data Language (NDL). 16 17 18 The ndrgen utility takes an input protocol definition file and 19 generates an output C source file that contains the marshalling 20 routines to implement the RPC protocol. If the input file is named 21 proto.ndl, ndrgen generates NDR routines in proto_ndr.c. Applications 22 must define the service definition and server-side stub table for use 23 with the RPC protocol. 24 25 26 The following is an example stub table and service definition: 27 28 static stub_table_t net_svc_stub_table[] = { 29 { svc_close, SVC_CLOSE }, 30 { svc_open, SVC_OPEN }, 31 { svc_read, SVC_READ }, 32 { svc_write, SVC_WRITE }, 33 {0} 34 }; 35 36 static service_t net_svc = { 37 "NETSVC", /* name */ 38 "Network Service", /* description */ 39 "\\netsvc", /* endpoint */ 40 "\\pipe\\netsvc", /* secondary address port */ 41 "12345678-1234-abcd-ef0001234567abcd", 1, /* abstract syntax */ 42 "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer syntax */ 43 0, /* bind_instance_size */ 44 0, /* bind_req() */ 45 0, /* unbind_and_close() */ 46 0, /* call_stub() */ 47 &TYPEINFO(svc_interface), /* interface ti */ 48 net_svc_stub_table /* stub_table */ 49 }; 50 51 52 53 The C preprocessor, which can be specified in the CC environment 54 variable or on the command line, is run on the input file before it is 55 interpreted by ndrgen. The NDRGEN preprocessor symbol is defined by 56 ndrgen for use by the ndrgen programmer. 57 58 59 The NDR generated by ndrgen is an MSRPC compatible implementation of 60 OSF DCE NDR. This implementation is based on the X/Open DCE: Remote 61 Procedure Call specification (CAE Specification (1997), DCE 1.1: Remote 62 Procedure Call Document Number: C706), enhanced for compatibility with 63 MSRPC Unicode (UCS-2) strings. 64 65 66 The following table shows the DCE RPC layering compared against ONC 67 RPC. 68 69 DCE RPC Layers ONC RPC Layers Remark 70 +---------------+ +---------------+ +----------------+ 71 +---------------+ +---------------+ 72 | Application | | Application | The application 73 +---------------+ +---------------+ 74 | Hand coded | | RPCGEN gen'd | 75 | client/server | | client/server | Generated stubs 76 | proto.ndl | | *_svc.c *_clnt| 77 | proto.c | | | 78 +---------------+ +---------------+ 79 | | | | Binding/PMAP 80 | RPC Library | | RPC Library | Calls/Return 81 +---------------+ +---------------+ 82 | RPC Protocol | | RPC Protocol | Headers 83 | rpcpdu.ndl | | | Authentication 84 +---------------+ +---------------+ 85 | NDRGEN gen'd | | RPCGEN gen'd | Aggregation 86 | NDR stubs | | XDR stubs | Composition 87 | *__ndr.c | | *_xdr.c | 88 +---------------+ +---------------+ 89 | NDR | | XDR | Byte order, padding 90 +---------------+ +---------------+ 91 | | | Network Conn | Large difference: 92 | Heap | | clnt_tcp | see below. 93 | Management | | clnt_udp | 94 +---------------+ +---------------+ 95 96 97 98 There are two major differences between the DCE RPC and ONC RPC: 99 100 1. DCE RPC only generates or processes packets from buffers. 101 Other layers must take care of packet transmission and 102 reception. The packet heaps are managed through a simple 103 interface provided by NDR streams. 104 105 ONC RPC communicates directly with the network. The 106 programmer must do specific setup for the RPC packet to be 107 placed in a buffer rather than sent to the wire. 108 109 2. DCE RPC uses application provided heaps to support 110 operations. A heap is a managed chunk of memory that NDR 111 manages as it allocates. When the operation and its result 112 are complete, the heap is disposed of as a single item. 113 Transactions, which are the anchor of most operations, 114 perform heap bookkeeping. 115 116 ONC RPC uses malloc() liberally throughout its run-time 117 system. To free results, ONC RPC supports an XDR_FREE 118 operation that traverses data structures freeing memory as 119 it goes. 120 121 122 The following terminology is used in the subsequent discussion of NDR. 123 124 Size 125 The size of an array in elements, such as the amount to malloc(). 126 127 128 Length 129 The number of significant elements of an array. 130 131 132 Known 133 Size or Length is known at build time. 134 135 136 Determined 137 Size or Length is determined at run time. 138 139 140 Fixed 141 The Size and Length are Known, such as a string constant: 142 143 char array[] = "A constant Size/Length"; 144 145 146 147 148 The following DCE RPC terminology is used in the subsequent discussion. 149 150 Conformant 151 The Size is Determined. The Length is the same as Size. 152 153 154 155 156 Varying 157 The Size is Known. The Length is Determined, such as a strcpy() of 158 a variable length string into a fixed length buffer: 159 160 char array[100]; 161 strcpy(array, "very short string"); 162 163 164 165 Varying and Conformant 166 The Size is Determined. The Length is separately Determined, such 167 as: 168 169 char *array = malloc(size); 170 strcpy(array, "short string"); 171 172 173 174 Strings 175 DCE RPC strings are represented as varying or varying and conformant 176 one-dimensional arrays. Characters can be single-byte or multi-byte as 177 long as all characters conform to a fixed element size. For instance, 178 UCS-2 is valid, but UTF-8 is not a valid DCE RPC string format. The 179 string is terminated by a null character of the appropriate element 180 size. 181 182 183 MSRPC strings are always varying and conformant format and not null 184 terminated. This format uses the size_is, first_is, and length_is 185 attributes: 186 187 typedef struct string { 188 DWORD size_is; 189 DWORD first_is; 190 DWORD length_is; 191 wchar_t string[ANY_SIZE_ARRAY]; 192 } string_t; 193 194 195 196 The size_is attribute is used to specify the number of data elements in 197 each dimension of an array. 198 199 200 The first_is attribute is used to define the lower bound for 201 significant elements in each dimension of an array. For strings, this 202 value is always zero. 203 204 205 The length_is attribute is used to define the number of significant 206 elements in each dimension of an array. For strings, this value is 207 typically the same as size_is, although it might be (size_is - 1) if 208 the string is null terminated. 209 210 211 MSRPC Unicode strings are not null terminated, which means that the 212 recipient must manually null-terminate the string after it has been 213 received. Note that there is often a wide-char pad following a string, 214 which might contain zero but this situation is not guaranteed. 215 216 4 bytes 4 bytes 4 bytes 2bytes 2bytes 2bytes 2bytes 217 +---------+---------+---------+------+------+------+------+ 218 |size_is |first_is |length_is| char | char | char | char | 219 +---------+---------+---------+------+------+------+------+ 220 221 222 223 Despite the general rule, some MSRPC services use null-terminated 224 Unicode strings. To compensate, MSRPC uses the following additional 225 string wrapper with two additional fields. Note that LPTSTR is 226 automatically converted to string_t by the NDR library. 227 228 typedef struct msrpc_string { 229 WORD length; 230 WORD maxlen; 231 LPTSTR str; 232 } msrpc_string_t; 233 234 235 236 Here, length is the array length in bytes excluding any terminating 237 null bytes and maxlen is the array length in bytes including the 238 terminating null bytes. 239 240 NDL Syntax 241 The ndrgen input must be a valid C header file. Thus, NDL is defined by 242 using macros to map to DCE RPC IDL. The following shows the mappings: 243 244 NDRGEN NDL DCE RPC IDL 245 ================================ 246 OPERATION(X) [operation(X)] 247 IN [in] 248 OUT [out] 249 INOUT [in out] 250 STRING [string] 251 SIZE_IS(X) [size_is(X)] 252 SWITCH(X) [switch_is(X)] 253 CASE(X) [case(X)] 254 DEFAULT [default] 255 INTERFACE(X) [interface(X)] 256 UUID(X) [uuid(X)] 257 ARG_IS(X) [arg_is(X)] 258 REFERENCE [reference] 259 ANY_SIZE_ARRAY * 260 IMPORT_EXTERN [extern] 261 262 263 264 The following shows the C data type associated with the NDRGEN NDL: 265 266 NDRGEN NDL C Data Type 267 ============================== 268 BYTE unsigned char 269 WORD unsigned short 270 DWORD unsigned long 271 LPTSTR wchar_t * 272 LPBYTE unsigned char * 273 LPWORD unsigned short * 274 LPDWORD unsigned long * 275 276 277 OPTIONS 278 The smbutil command supports the following global option: 279 280 -Y 281 Specifies the path to the cpp program. 282 283 284 EXAMPLES 285 The following is an example NDL header file: 286 287 #ifndef _SVC_NDL_ 288 #define _SVC_NDL_ 289 290 #include "ndrtypes.ndl" 291 292 /* 293 * Opnums: note that ndrgen does not automatically number 294 * operations and the values do not have to be sequential. 295 */ 296 #define SVC_CLOSE 0x00 297 #define SVC_OPEN 0x01 298 #define SVC_READ 0x02 299 #define SVC_WRITE 0x03 300 301 /* 302 * Define a file handle - choice of UUID format is 303 * arbitrary. Note that typedef's cannot be declared 304 * with the struct definition. 305 */ 306 struct svc_uuid { 307 DWORD data1; 308 DWORD data2; 309 WORD data3[2]; 310 BYTE data4[8]; 311 }; 312 typedef struct svc_uuid svc_handle_t; 313 314 struct xferbuf { 315 DWORD nbytes; 316 DWORD offset; 317 SIZE_IS(nbytes) BYTE *data; 318 }; 319 typedef struct xferbuf xferbuf_t; 320 321 /* 322 * Define the RPC operations. 323 */ 324 OPERATION(SVC_CLOSE) 325 struct svc_close { 326 IN svc_handle_t handle; 327 OUT DWORD status; 328 }; 329 330 OPERATION(SVC_OPEN) 331 struct svc_open { 332 IN LPTSTR servername; 333 IN LPTSTR path; 334 OUT svc_handle_t handle; 335 OUT DWORD status; 336 }; 337 338 OPERATION(SVC_READ) 339 struct svc_read { 340 IN svc_handle_t handle; 341 IN DWORD nbytes; 342 IN DWORD offset; 343 OUT xferbuf_t buf; 344 OUT DWORD status; 345 }; 346 347 OPERATION(SVC_WRITE) 348 struct svc_write { 349 IN svc_handle_t handle; 350 IN xferbuf_t buf; 351 OUT DWORD nbytes; 352 OUT DWORD status; 353 }; 354 355 /* 356 * Define the interface. 357 */ 358 INTERFACE(0) 359 union svc_interface { 360 CASE(SVC_CLOSE) 361 struct svc_close net_close; 362 CASE(SVC_OPEN) 363 struct svc_open net_open; 364 CASE(SVC_READ) 365 struct svc_read net_read; 366 CASE(SVC_WRITE) 367 struct svc_write net_write; 368 }; 369 typedef union svc_interface svc_interface_t; 370 EXTERNTYPEINFO(svc_interface) 371 372 #endif /* _SVC_NDL_ */ 373 374 375 EXIT STATUS 376 The following exit values are returned: 377 378 0 379 Successful operation. 380 381 382 >0 383 An error occurred. 384 385 386 ATTRIBUTES 387 See the attributes(5) man page for descriptions of the following 388 attributes: 389 390 391 392 393 +---------------+-----------------+ 394 |ATTRIBUTE TYPE | ATTRIBUTE VALUE | 395 +---------------+-----------------+ 396 |Availability | SUNWbtool | 397 +---------------+-----------------+ 398 399 SEE ALSO 400 cpp(1), rpcgen(1), cc(1B), attributes(5) 401 402 BUGS 403 Some cpp(1) macros used by ndrgen are not understood by /usr/bin/cpp or 404 /usr/sfw/bin/cpp. Simple NDL files generally do not pose a problem. If 405 problems occur, for example, when using unions, use /usr/libexec/cpp or 406 cw. 407 408 409 410 October 22, 2007 NDRGEN(1ONBLD)