root/source4/ntvfs/ipc/ipc_rap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rap_heap_save
  2. rap_heap_restore
  3. new_rap_srv_call
  4. rap_srv_pull_word
  5. rap_srv_pull_dword
  6. rap_srv_pull_string
  7. rap_srv_pull_bufsize
  8. rap_srv_pull_expect_multiple
  9. rap_push_string
  10. _rap_netshareenum
  11. _rap_netserverenum2
  12. api_Unsupported
  13. ipc_rap_call

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    RAP handlers
   4 
   5    Copyright (C) Volker Lendecke 2004
   6 
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "libcli/raw/interfaces.h"
  23 #include "libcli/rap/rap.h"
  24 #include "events/events.h"
  25 #include "ntvfs/ipc/proto.h"
  26 #include "librpc/ndr/libndr.h"
  27 #include "param/param.h"
  28 
  29 #define NDR_RETURN(call) do { \
  30         enum ndr_err_code _ndr_err; \
  31         _ndr_err = call; \
  32         if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
  33                 return ndr_map_error2ntstatus(_ndr_err); \
  34         } \
  35 } while (0)
  36 
  37 #define RAP_GOTO(call) do { \
  38         result = call; \
  39         if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) {\
  40                 goto buffer_overflow; \
  41         } \
  42         if (!NT_STATUS_IS_OK(result)) { \
  43                 goto done; \
  44         } \
  45 } while (0)
  46 
  47 #define NDR_GOTO(call) do { \
  48         enum ndr_err_code _ndr_err; \
  49         _ndr_err = call; \
  50         if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
  51                 RAP_GOTO(ndr_map_error2ntstatus(_ndr_err)); \
  52         } \
  53 } while (0)
  54 
  55 
  56 #define NERR_notsupported 50
  57 
  58 struct rap_string_heap {
  59         TALLOC_CTX *mem_ctx;
  60         int offset;
  61         int num_strings;
  62         const char **strings;
  63 };
  64 
  65 struct rap_heap_save {
  66         int offset, num_strings;
  67 };
  68 
  69 static void rap_heap_save(struct rap_string_heap *heap,
     /* [<][>][^][v][top][bottom][index][help] */
  70                           struct rap_heap_save *save)
  71 {
  72         save->offset = heap->offset;
  73         save->num_strings = heap->num_strings;
  74 }
  75 
  76 static void rap_heap_restore(struct rap_string_heap *heap,
     /* [<][>][^][v][top][bottom][index][help] */
  77                              struct rap_heap_save *save)
  78 {
  79         heap->offset = save->offset;
  80         heap->num_strings = save->num_strings;
  81 }
  82 
  83 struct rap_call {
  84         struct loadparm_context *lp_ctx;
  85 
  86         TALLOC_CTX *mem_ctx;
  87         uint16_t callno;
  88         const char *paramdesc;
  89         const char *datadesc;
  90 
  91         uint16_t status;
  92         uint16_t convert;
  93 
  94         uint16_t rcv_paramlen, rcv_datalen;
  95 
  96         struct ndr_push *ndr_push_param;
  97         struct ndr_push *ndr_push_data;
  98         struct rap_string_heap *heap;
  99 
 100         struct ndr_pull *ndr_pull_param;
 101         struct ndr_pull *ndr_pull_data;
 102 
 103         struct tevent_context *event_ctx;
 104 };
 105 
 106 #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
 107 
 108 static struct rap_call *new_rap_srv_call(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 109                                          struct tevent_context *ev_ctx,
 110                                          struct loadparm_context *lp_ctx,
 111                                          struct smb_trans2 *trans)
 112 {
 113         struct rap_call *call;
 114 
 115         call = talloc(mem_ctx, struct rap_call);
 116 
 117         if (call == NULL)
 118                 return NULL;
 119 
 120         ZERO_STRUCTP(call);
 121 
 122         call->lp_ctx = talloc_reference(call, lp_ctx);
 123         call->event_ctx = ev_ctx;
 124 
 125         call->mem_ctx = mem_ctx;
 126 
 127         call->ndr_pull_param = ndr_pull_init_blob(&trans->in.params, mem_ctx, lp_iconv_convenience(lp_ctx));
 128         call->ndr_pull_param->flags = RAPNDR_FLAGS;
 129 
 130         call->ndr_pull_data = ndr_pull_init_blob(&trans->in.data, mem_ctx, lp_iconv_convenience(lp_ctx));
 131         call->ndr_pull_data->flags = RAPNDR_FLAGS;
 132 
 133         call->heap = talloc(mem_ctx, struct rap_string_heap);
 134 
 135         if (call->heap == NULL)
 136                 return NULL;
 137 
 138         ZERO_STRUCTP(call->heap);
 139 
 140         call->heap->mem_ctx = mem_ctx;
 141 
 142         return call;
 143 }
 144 
 145 static NTSTATUS rap_srv_pull_word(struct rap_call *call, uint16_t *result)
     /* [<][>][^][v][top][bottom][index][help] */
 146 {
 147         enum ndr_err_code ndr_err;
 148 
 149         if (*call->paramdesc++ != 'W')
 150                 return NT_STATUS_INVALID_PARAMETER;
 151 
 152         ndr_err = ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, result);
 153         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 154                 return ndr_map_error2ntstatus(ndr_err);
 155         }
 156 
 157         return NT_STATUS_OK;
 158 }
 159 
 160 static NTSTATUS rap_srv_pull_dword(struct rap_call *call, uint32_t *result)
     /* [<][>][^][v][top][bottom][index][help] */
 161 {
 162         enum ndr_err_code ndr_err;
 163 
 164         if (*call->paramdesc++ != 'D')
 165                 return NT_STATUS_INVALID_PARAMETER;
 166 
 167         ndr_err = ndr_pull_uint32(call->ndr_pull_param, NDR_SCALARS, result);
 168         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 169                 return ndr_map_error2ntstatus(ndr_err);
 170         }
 171 
 172         return NT_STATUS_OK;
 173 }
 174 
 175 static NTSTATUS rap_srv_pull_string(struct rap_call *call, const char **result)
     /* [<][>][^][v][top][bottom][index][help] */
 176 {
 177         enum ndr_err_code ndr_err;
 178         char paramdesc = *call->paramdesc++;
 179 
 180         if (paramdesc == 'O') {
 181                 *result = NULL;
 182                 return NT_STATUS_OK;
 183         }
 184 
 185         if (paramdesc != 'z')
 186                 return NT_STATUS_INVALID_PARAMETER;
 187 
 188         ndr_err = ndr_pull_string(call->ndr_pull_param, NDR_SCALARS, result);
 189         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 190                 return ndr_map_error2ntstatus(ndr_err);
 191         }
 192 
 193         return NT_STATUS_OK;
 194 }
 195 
 196 static NTSTATUS rap_srv_pull_bufsize(struct rap_call *call, uint16_t *bufsize)
     /* [<][>][^][v][top][bottom][index][help] */
 197 {
 198         enum ndr_err_code ndr_err;
 199 
 200         if ( (*call->paramdesc++ != 'r') || (*call->paramdesc++ != 'L') )
 201                 return NT_STATUS_INVALID_PARAMETER;
 202 
 203         ndr_err = ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, bufsize);
 204         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 205                 return ndr_map_error2ntstatus(ndr_err);
 206         }
 207 
 208         call->heap->offset = *bufsize;
 209 
 210         return NT_STATUS_OK;
 211 }
 212 
 213 static NTSTATUS rap_srv_pull_expect_multiple(struct rap_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 214 {
 215         if ( (*call->paramdesc++ != 'e') || (*call->paramdesc++ != 'h') )
 216                 return NT_STATUS_INVALID_PARAMETER;
 217 
 218         return NT_STATUS_OK;
 219 }
 220 
 221 static NTSTATUS rap_push_string(struct ndr_push *data_push,
     /* [<][>][^][v][top][bottom][index][help] */
 222                                 struct rap_string_heap *heap,
 223                                 const char *str)
 224 {
 225         size_t space;
 226 
 227         if (str == NULL)
 228                 str = "";
 229 
 230         space = strlen(str)+1;
 231 
 232         if (heap->offset < space)
 233                 return NT_STATUS_BUFFER_TOO_SMALL;
 234 
 235         heap->offset -= space;
 236 
 237         NDR_RETURN(ndr_push_uint16(data_push, NDR_SCALARS, heap->offset));
 238         NDR_RETURN(ndr_push_uint16(data_push, NDR_SCALARS, 0));
 239 
 240         heap->strings = talloc_realloc(heap->mem_ctx,
 241                                          heap->strings,
 242                                          const char *,
 243                                          heap->num_strings + 1);
 244 
 245         if (heap->strings == NULL)
 246                 return NT_STATUS_NO_MEMORY;
 247 
 248         heap->strings[heap->num_strings] = str;
 249         heap->num_strings += 1;
 250 
 251         return NT_STATUS_OK;
 252 }
 253 
 254 static NTSTATUS _rap_netshareenum(struct rap_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 255 {
 256         struct rap_NetShareEnum r;
 257         NTSTATUS result;
 258 
 259         RAP_GOTO(rap_srv_pull_word(call, &r.in.level));
 260         RAP_GOTO(rap_srv_pull_bufsize(call, &r.in.bufsize));
 261         RAP_GOTO(rap_srv_pull_expect_multiple(call));
 262 
 263         switch(r.in.level) {
 264         case 0:
 265                 if (strcmp(call->datadesc, "B13") != 0)
 266                         return NT_STATUS_INVALID_PARAMETER;
 267                 break;
 268         case 1:
 269                 if (strcmp(call->datadesc, "B13BWz") != 0)
 270                         return NT_STATUS_INVALID_PARAMETER;
 271                 break;
 272         default:
 273                 return NT_STATUS_INVALID_PARAMETER;
 274                 break;
 275         }
 276 
 277         result = rap_netshareenum(call, call->event_ctx, call->lp_ctx, &r);
 278 
 279         if (!NT_STATUS_IS_OK(result))
 280                 return result;
 281 
 282         for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
 283 
 284                 int i = r.out.count;
 285                 uint32_t offset_save;
 286                 struct rap_heap_save heap_save;
 287 
 288                 offset_save = call->ndr_push_data->offset;
 289                 rap_heap_save(call->heap, &heap_save);
 290 
 291                 switch(r.in.level) {
 292                 case 0:
 293                         NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
 294                                               (const uint8_t *)r.out.info[i].info0.name,
 295                                               sizeof(r.out.info[i].info0.name)));
 296                         break;
 297                 case 1:
 298                         NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
 299                                               (const uint8_t *)r.out.info[i].info1.name,
 300                                               sizeof(r.out.info[i].info1.name)));
 301                         NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
 302                                               NDR_SCALARS, r.out.info[i].info1.pad));
 303                         NDR_GOTO(ndr_push_uint16(call->ndr_push_data,
 304                                                NDR_SCALARS, r.out.info[i].info1.type));
 305 
 306                         RAP_GOTO(rap_push_string(call->ndr_push_data,
 307                                                call->heap,
 308                                                r.out.info[i].info1.comment));
 309 
 310                         break;
 311                 }
 312 
 313                 if (call->ndr_push_data->offset > call->heap->offset) {
 314 
 315         buffer_overflow:
 316 
 317                         call->ndr_push_data->offset = offset_save;
 318                         rap_heap_restore(call->heap, &heap_save);
 319                         break;
 320                 }
 321         }
 322 
 323         call->status = r.out.status;
 324 
 325         NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
 326         NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
 327 
 328         result = NT_STATUS_OK;
 329 
 330  done:
 331         return result;
 332 }
 333 
 334 static NTSTATUS _rap_netserverenum2(struct rap_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 335 {
 336         struct rap_NetServerEnum2 r;
 337         NTSTATUS result;
 338 
 339         RAP_GOTO(rap_srv_pull_word(call, &r.in.level));
 340         RAP_GOTO(rap_srv_pull_bufsize(call, &r.in.bufsize));
 341         RAP_GOTO(rap_srv_pull_expect_multiple(call));
 342         RAP_GOTO(rap_srv_pull_dword(call, &r.in.servertype));
 343         RAP_GOTO(rap_srv_pull_string(call, &r.in.domain));
 344 
 345         switch(r.in.level) {
 346         case 0:
 347                 if (strcmp(call->datadesc, "B16") != 0)
 348                         return NT_STATUS_INVALID_PARAMETER;
 349                 break;
 350         case 1:
 351                 if (strcmp(call->datadesc, "B16BBDz") != 0)
 352                         return NT_STATUS_INVALID_PARAMETER;
 353                 break;
 354         default:
 355                 return NT_STATUS_INVALID_PARAMETER;
 356                 break;
 357         }
 358 
 359         result = rap_netserverenum2(call, call->lp_ctx, &r);
 360 
 361         if (!NT_STATUS_IS_OK(result))
 362                 return result;
 363 
 364         for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
 365 
 366                 int i = r.out.count;
 367                 uint32_t offset_save;
 368                 struct rap_heap_save heap_save;
 369 
 370                 offset_save = call->ndr_push_data->offset;
 371                 rap_heap_save(call->heap, &heap_save);
 372 
 373                 switch(r.in.level) {
 374                 case 0:
 375                         NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
 376                                               (const uint8_t *)r.out.info[i].info0.name,
 377                                               sizeof(r.out.info[i].info0.name)));
 378                         break;
 379                 case 1:
 380                         NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
 381                                               (const uint8_t *)r.out.info[i].info1.name,
 382                                               sizeof(r.out.info[i].info1.name)));
 383                         NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
 384                                               NDR_SCALARS, r.out.info[i].info1.version_major));
 385                         NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
 386                                               NDR_SCALARS, r.out.info[i].info1.version_minor));
 387                         NDR_GOTO(ndr_push_uint32(call->ndr_push_data,
 388                                                NDR_SCALARS, r.out.info[i].info1.servertype));
 389 
 390                         RAP_GOTO(rap_push_string(call->ndr_push_data,
 391                                                call->heap,
 392                                                r.out.info[i].info1.comment));
 393 
 394                         break;
 395                 }
 396 
 397                 if (call->ndr_push_data->offset > call->heap->offset) {
 398 
 399         buffer_overflow:
 400 
 401                         call->ndr_push_data->offset = offset_save;
 402                         rap_heap_restore(call->heap, &heap_save);
 403                         break;
 404                 }
 405         }
 406 
 407         call->status = r.out.status;
 408 
 409         NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
 410         NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
 411 
 412         result = NT_STATUS_OK;
 413 
 414  done:
 415         return result;
 416 }
 417 
 418 static NTSTATUS api_Unsupported(struct rap_call *call)
     /* [<][>][^][v][top][bottom][index][help] */
 419 {
 420         call->status = NERR_notsupported;
 421         call->convert = 0;
 422         return NT_STATUS_OK;
 423 }
 424 
 425 static const struct
 426 {
 427         const char *name;
 428         int id;
 429         NTSTATUS (*fn)(struct rap_call *call);
 430 } api_commands[] = {
 431         {"NetShareEnum", RAP_WshareEnum, _rap_netshareenum },
 432         {"NetServerEnum2", RAP_NetServerEnum2, _rap_netserverenum2 },
 433         {NULL, -1, api_Unsupported}
 434 };
 435 
 436 NTSTATUS ipc_rap_call(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 437                       struct smb_trans2 *trans)
 438 {
 439         int i;
 440         NTSTATUS result;
 441         struct rap_call *call;
 442         DATA_BLOB result_param, result_data;
 443         struct ndr_push *final_param;
 444         struct ndr_push *final_data;
 445 
 446         call = new_rap_srv_call(mem_ctx, event_ctx, lp_ctx, trans);
 447 
 448         if (call == NULL)
 449                 return NT_STATUS_NO_MEMORY;
 450 
 451         NDR_RETURN(ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, &call->callno));
 452         NDR_RETURN(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
 453                                   &call->paramdesc));
 454         NDR_RETURN(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
 455                                   &call->datadesc));
 456 
 457         call->ndr_push_param = ndr_push_init_ctx(call, lp_iconv_convenience(lp_ctx));
 458         call->ndr_push_data = ndr_push_init_ctx(call, lp_iconv_convenience(lp_ctx));
 459 
 460         if ((call->ndr_push_param == NULL) || (call->ndr_push_data == NULL))
 461                 return NT_STATUS_NO_MEMORY;
 462 
 463         call->ndr_push_param->flags = RAPNDR_FLAGS;
 464         call->ndr_push_data->flags = RAPNDR_FLAGS;
 465 
 466         result = NT_STATUS_INVALID_SYSTEM_SERVICE;
 467 
 468         for (i=0; api_commands[i].name != NULL; i++) {
 469                 if (api_commands[i].id == call->callno) {
 470                         DEBUG(5, ("Running RAP call %s\n",
 471                                   api_commands[i].name));
 472                         result = api_commands[i].fn(call);
 473                         break;
 474                 }
 475         }
 476 
 477         if (!NT_STATUS_IS_OK(result))
 478                 return result;
 479 
 480         result_param = ndr_push_blob(call->ndr_push_param);
 481         result_data = ndr_push_blob(call->ndr_push_data);
 482 
 483         final_param = ndr_push_init_ctx(call, lp_iconv_convenience(lp_ctx));
 484         final_data = ndr_push_init_ctx(call, lp_iconv_convenience(lp_ctx));
 485 
 486         if ((final_param == NULL) || (final_data == NULL))
 487                 return NT_STATUS_NO_MEMORY;
 488 
 489         final_param->flags = RAPNDR_FLAGS;
 490         final_data->flags = RAPNDR_FLAGS;
 491 
 492         NDR_RETURN(ndr_push_uint16(final_param, NDR_SCALARS, call->status));
 493         NDR_RETURN(ndr_push_uint16(final_param,
 494                                   NDR_SCALARS, call->heap->offset - result_data.length));
 495         NDR_RETURN(ndr_push_bytes(final_param, result_param.data,
 496                                  result_param.length));
 497 
 498         NDR_RETURN(ndr_push_bytes(final_data, result_data.data,
 499                                  result_data.length));
 500 
 501         for (i=call->heap->num_strings-1; i>=0; i--)
 502                 NDR_RETURN(ndr_push_string(final_data, NDR_SCALARS,
 503                                           call->heap->strings[i]));
 504 
 505         trans->out.setup_count = 0;
 506         trans->out.setup = NULL;
 507         trans->out.params = ndr_push_blob(final_param);
 508         trans->out.data = ndr_push_blob(final_data);
 509 
 510         return result;
 511 }

/* [<][>][^][v][top][bottom][index][help] */