1/* 2 Unix SMB/CIFS implementation. 3 4 TDR (Trivial Data Representation) helper functions 5 Based loosely on ndr.c by Andrew Tridgell. 6 7 Copyright (C) Jelmer Vernooij 2005 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "system/filesys.h" 25#include "system/network.h" 26#include "lib/tdr/tdr.h" 27 28#define TDR_BASE_MARSHALL_SIZE 1024 29 30#define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->data.length+(n))) 31 32#define TDR_PULL_NEED_BYTES(tdr, n) do { \ 33 if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \ 34 return NT_STATUS_BUFFER_TOO_SMALL; \ 35 } \ 36} while(0) 37 38#define TDR_BE(tdr) ((tdr)->flags & TDR_BIG_ENDIAN) 39 40#define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs) 41#define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs)) 42#define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs)) 43#define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v) 44#define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0) 45#define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0) 46 47/** 48 expand the available space in the buffer to 'size' 49*/ 50NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size) 51{ 52 if (talloc_get_size(tdr->data.data) >= size) { 53 return NT_STATUS_OK; 54 } 55 56 tdr->data.data = talloc_realloc(tdr, tdr->data.data, uint8_t, tdr->data.length + TDR_BASE_MARSHALL_SIZE); 57 58 if (tdr->data.data == NULL) 59 return NT_STATUS_NO_MEMORY; 60 61 return NT_STATUS_OK; 62} 63 64 65NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v) 66{ 67 TDR_PULL_NEED_BYTES(tdr, 1); 68 *v = TDR_CVAL(tdr, tdr->offset); 69 tdr->offset += 1; 70 return NT_STATUS_OK; 71} 72 73NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v) 74{ 75 TDR_PUSH_NEED_BYTES(tdr, 1); 76 TDR_SCVAL(tdr, tdr->data.length, *v); 77 tdr->data.length += 1; 78 return NT_STATUS_OK; 79} 80 81NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v) 82{ 83 tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v); 84 return NT_STATUS_OK; 85} 86 87NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v) 88{ 89 TDR_PULL_NEED_BYTES(tdr, 2); 90 *v = TDR_SVAL(tdr, tdr->offset); 91 tdr->offset += 2; 92 return NT_STATUS_OK; 93} 94 95NTSTATUS tdr_pull_uint1632(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v) 96{ 97 return tdr_pull_uint16(tdr, ctx, v); 98} 99 100NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v) 101{ 102 TDR_PUSH_NEED_BYTES(tdr, 2); 103 TDR_SSVAL(tdr, tdr->data.length, *v); 104 tdr->data.length += 2; 105 return NT_STATUS_OK; 106} 107 108NTSTATUS tdr_push_uint1632(struct tdr_push *tdr, const uint16_t *v) 109{ 110 return tdr_push_uint16(tdr, v); 111} 112 113NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v) 114{ 115 tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v); 116 return NT_STATUS_OK; 117} 118 119NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v) 120{ 121 TDR_PULL_NEED_BYTES(tdr, 4); 122 *v = TDR_IVAL(tdr, tdr->offset); 123 tdr->offset += 4; 124 return NT_STATUS_OK; 125} 126 127NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v) 128{ 129 TDR_PUSH_NEED_BYTES(tdr, 4); 130 TDR_SIVAL(tdr, tdr->data.length, *v); 131 tdr->data.length += 4; 132 return NT_STATUS_OK; 133} 134 135NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v) 136{ 137 tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v); 138 return NT_STATUS_OK; 139} 140 141NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset) 142{ 143 size_t ret; 144 145 if (length == -1) { 146 switch (chset) { 147 case CH_DOS: 148 length = ascii_len_n((const char*)tdr->data.data+tdr->offset, tdr->data.length-tdr->offset); 149 break; 150 case CH_UTF16: 151 length = utf16_len_n(tdr->data.data+tdr->offset, tdr->data.length-tdr->offset); 152 break; 153 154 default: 155 return NT_STATUS_INVALID_PARAMETER; 156 } 157 } 158 159 if (length == 0) { 160 *v = talloc_strdup(ctx, ""); 161 return NT_STATUS_OK; 162 } 163 164 TDR_PULL_NEED_BYTES(tdr, el_size*length); 165 166 if (!convert_string_talloc_convenience(ctx, tdr->iconv_convenience, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, discard_const_p(void *, v), &ret, false)) { 167 return NT_STATUS_INVALID_PARAMETER; 168 } 169 170 tdr->offset += length * el_size; 171 172 return NT_STATUS_OK; 173} 174 175NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset) 176{ 177 size_t ret, required; 178 179 if (length == -1) { 180 length = strlen(*v) + 1; /* Extra element for null character */ 181 } 182 183 required = el_size * length; 184 TDR_PUSH_NEED_BYTES(tdr, required); 185 186 if (!convert_string_convenience(tdr->iconv_convenience, CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->data.length, required, &ret, false)) { 187 return NT_STATUS_INVALID_PARAMETER; 188 } 189 190 /* Make sure the remaining part of the string is filled with zeroes */ 191 if (ret < required) { 192 memset(tdr->data.data+tdr->data.length+ret, 0, required-ret); 193 } 194 195 tdr->data.length += required; 196 197 return NT_STATUS_OK; 198} 199 200NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset) 201{ 202 tdr->print(tdr, "%-25s: %s", name, *v); 203 return NT_STATUS_OK; 204} 205 206/** 207 parse a hyper 208*/ 209NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v) 210{ 211 TDR_PULL_NEED_BYTES(tdr, 8); 212 *v = TDR_IVAL(tdr, tdr->offset); 213 *v |= (uint64_t)(TDR_IVAL(tdr, tdr->offset+4)) << 32; 214 tdr->offset += 8; 215 return NT_STATUS_OK; 216} 217 218/** 219 push a hyper 220*/ 221NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v) 222{ 223 TDR_PUSH_NEED_BYTES(tdr, 8); 224 TDR_SIVAL(tdr, tdr->data.length, ((*v) & 0xFFFFFFFF)); 225 TDR_SIVAL(tdr, tdr->data.length+4, ((*v)>>32)); 226 tdr->data.length += 8; 227 return NT_STATUS_OK; 228} 229 230/** 231 push a NTTIME 232*/ 233NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t) 234{ 235 TDR_CHECK(tdr_push_hyper(tdr, t)); 236 return NT_STATUS_OK; 237} 238 239/** 240 pull a NTTIME 241*/ 242NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t) 243{ 244 TDR_CHECK(tdr_pull_hyper(tdr, ctx, t)); 245 return NT_STATUS_OK; 246} 247 248/** 249 push a time_t 250*/ 251NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t) 252{ 253 return tdr_push_uint32(tdr, (uint32_t *)t); 254} 255 256/** 257 pull a time_t 258*/ 259NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t) 260{ 261 uint32_t tt; 262 TDR_CHECK(tdr_pull_uint32(tdr, ctx, &tt)); 263 *t = tt; 264 return NT_STATUS_OK; 265} 266 267NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t) 268{ 269 if (*t == (time_t)-1 || *t == 0) { 270 tdr->print(tdr, "%-25s: (time_t)%d", name, (int)*t); 271 } else { 272 tdr->print(tdr, "%-25s: %s", name, timestring(tdr, *t)); 273 } 274 275 return NT_STATUS_OK; 276} 277 278NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t) 279{ 280 tdr->print(tdr, "%-25s: %s", name, nt_time_string(tdr, *t)); 281 282 return NT_STATUS_OK; 283} 284 285NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r) 286{ 287 tdr->print(tdr, "%-25s: DATA_BLOB length=%u", name, r->length); 288 if (r->length) { 289 dump_data(10, r->data, r->length); 290 } 291 292 return NT_STATUS_OK; 293} 294 295#define TDR_ALIGN(l,n) (((l) & ((n)-1)) == 0?0:((n)-((l)&((n)-1)))) 296 297/* 298 push a DATA_BLOB onto the wire. 299*/ 300NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob) 301{ 302 if (tdr->flags & TDR_ALIGN2) { 303 blob->length = TDR_ALIGN(tdr->data.length, 2); 304 } else if (tdr->flags & TDR_ALIGN4) { 305 blob->length = TDR_ALIGN(tdr->data.length, 4); 306 } else if (tdr->flags & TDR_ALIGN8) { 307 blob->length = TDR_ALIGN(tdr->data.length, 8); 308 } 309 310 TDR_PUSH_NEED_BYTES(tdr, blob->length); 311 312 memcpy(tdr->data.data+tdr->data.length, blob->data, blob->length); 313 return NT_STATUS_OK; 314} 315 316/* 317 pull a DATA_BLOB from the wire. 318*/ 319NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob) 320{ 321 uint32_t length; 322 323 if (tdr->flags & TDR_ALIGN2) { 324 length = TDR_ALIGN(tdr->offset, 2); 325 } else if (tdr->flags & TDR_ALIGN4) { 326 length = TDR_ALIGN(tdr->offset, 4); 327 } else if (tdr->flags & TDR_ALIGN8) { 328 length = TDR_ALIGN(tdr->offset, 8); 329 } else if (tdr->flags & TDR_REMAINING) { 330 length = tdr->data.length - tdr->offset; 331 } else { 332 return NT_STATUS_INVALID_PARAMETER; 333 } 334 335 if (tdr->data.length - tdr->offset < length) { 336 length = tdr->data.length - tdr->offset; 337 } 338 339 TDR_PULL_NEED_BYTES(tdr, length); 340 341 *blob = data_blob_talloc(tdr, tdr->data.data+tdr->offset, length); 342 tdr->offset += length; 343 return NT_STATUS_OK; 344} 345 346struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic) 347{ 348 struct tdr_push *push = talloc_zero(mem_ctx, struct tdr_push); 349 350 if (push == NULL) 351 return NULL; 352 353 push->iconv_convenience = talloc_reference(push, ic); 354 355 return push; 356} 357 358struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic) 359{ 360 struct tdr_pull *pull = talloc_zero(mem_ctx, struct tdr_pull); 361 362 if (pull == NULL) 363 return NULL; 364 365 pull->iconv_convenience = talloc_reference(pull, ic); 366 367 return pull; 368} 369 370NTSTATUS tdr_push_to_fd(int fd, struct smb_iconv_convenience *iconv_convenience, tdr_push_fn_t push_fn, const void *p) 371{ 372 struct tdr_push *push = tdr_push_init(NULL, iconv_convenience); 373 374 if (push == NULL) 375 return NT_STATUS_NO_MEMORY; 376 377 if (NT_STATUS_IS_ERR(push_fn(push, p))) { 378 DEBUG(1, ("Error pushing data\n")); 379 talloc_free(push); 380 return NT_STATUS_UNSUCCESSFUL; 381 } 382 383 if (write(fd, push->data.data, push->data.length) < push->data.length) { 384 DEBUG(1, ("Error writing all data\n")); 385 return NT_STATUS_UNSUCCESSFUL; 386 } 387 388 talloc_free(push); 389 390 return NT_STATUS_OK; 391} 392 393void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3) 394{ 395 va_list ap; 396 char *s = NULL; 397 int i; 398 399 va_start(ap, format); 400 vasprintf(&s, format, ap); 401 va_end(ap); 402 403 for (i=0;i<tdr->level;i++) { DEBUG(0,(" ")); } 404 405 DEBUG(0,("%s\n", s)); 406 free(s); 407} 408