diff options
-rw-r--r-- | source4/rpc_server/srvsvc/dcesrv_srvsvc.c | 351 | ||||
-rw-r--r-- | source4/torture/rpc/srvsvc.c | 267 |
2 files changed, 438 insertions, 180 deletions
diff --git a/source4/rpc_server/srvsvc/dcesrv_srvsvc.c b/source4/rpc_server/srvsvc/dcesrv_srvsvc.c index b8da68e920..983c51f137 100644 --- a/source4/rpc_server/srvsvc/dcesrv_srvsvc.c +++ b/source4/rpc_server/srvsvc/dcesrv_srvsvc.c @@ -1101,88 +1101,45 @@ static WERROR srvsvc_NetShareGetInfo(struct dcesrv_call_state *dce_call, TALLOC_ return WERR_UNKNOWN_LEVEL; } - -/* - srvsvc_NetShareSetInfo -*/ -static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct srvsvc_NetShareSetInfo *r) +static WERROR srvsvc_fill_share_info(struct share_info *info, int *count, + const char *share_name, int level, + const char *name, + const char *path, + const char *comment, + const char *password, + enum srvsvc_ShareType type, + int32_t max_users, + uint32_t csc_policy, + struct security_descriptor *sd) { - NTSTATUS nterr; - struct share_context *sctx = NULL; - struct share_config *scfg = NULL; - - ZERO_STRUCT(r->out); + int i = 0; - /* TODO: - access check - */ - - if (strcmp("", r->in.share_name) == 0) { - return WERR_INVALID_PARAM; - } - - nterr = share_get_context(mem_ctx, &sctx); - if (!NT_STATUS_IS_OK(nterr)) { - return ntstatus_to_werror(nterr); - } - - switch (r->in.level) { - case 0: - { - return WERR_NOT_SUPPORTED; - } - case 1: - { - return WERR_NOT_SUPPORTED; + if (level == 501) { + info[i].name = SHARE_CSC_POLICY; + info[i].type = SHARE_INFO_INT; + info[i].value = talloc(info, int); + *((int *)info[i].value) = csc_policy; + i++; } - case 2: - { - struct share_info *info; - int count = 8; - int i; + + switch(level) { - /* there are no more than 8 options in struct srvsvc_NetShareInfo2 */ - info = talloc_array(mem_ctx, struct share_info, count); - W_ERROR_HAVE_NO_MEMORY(info); - - i = 0; - - if (strcasecmp(r->in.share_name, r->in.info.info2->name) != 0) { - info[i].name = SHARE_NAME; - info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info2->name); - W_ERROR_HAVE_NO_MEMORY(info[i].value); - i++; - } + case 502: + /* TODO: check if unknown is csc_policy */ - info[i].name = SHARE_TYPE; - info[i].type = SHARE_INFO_STRING; - switch (r->in.info.info2->type) { - case 0x00: - info[i].value = talloc_strdup(info, "DISK"); - break; - case 0x01: - info[i].value = talloc_strdup(info, "PRINTER"); - break; - case 0x03: - info[i].value = talloc_strdup(info, "IPC"); - break; - default: - return WERR_INVALID_PARAM; - } - W_ERROR_HAVE_NO_MEMORY(info[i].value); - i++; + /* TODO: security descriptor */ - if (r->in.info.info2->path && r->in.info.info2->path[0]) { + case 2: + if (path && path[0]) { info[i].name = SHARE_PATH; info[i].type = SHARE_INFO_STRING; /* Windows will send a path in a form of C:\example\path */ - if (r->in.info.info2->path[1] == ':') { - info[i].value = talloc_strdup(info, &r->in.info.info2->path[2]); + if (path[1] == ':') { + info[i].value = talloc_strdup(info, &path[2]); } else { /* very strange let's try to set as is */ - info[i].value = talloc_strdup(info, r->in.info.info2->path); + info[i].value = talloc_strdup(info, path); } W_ERROR_HAVE_NO_MEMORY(info[i].value); all_string_sub((char *)info[i].value, "\\", "/", 0); @@ -1190,19 +1147,10 @@ static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_ i++; } - if (r->in.info.info2->comment && r->in.info.info2->comment[0]) { - info[i].name = SHARE_COMMENT; - info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info2->comment); - W_ERROR_HAVE_NO_MEMORY(info[i].value); - - i++; - } - - if (r->in.info.info2->password && r->in.info.info2->password[0]) { + if (password && password[0]) { info[i].name = SHARE_PASSWORD; info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info502->password); + info[i].value = talloc_strdup(info, password); W_ERROR_HAVE_NO_MEMORY(info[i].value); i++; @@ -1211,49 +1159,14 @@ static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_ info[i].name = SHARE_MAX_CONNECTIONS; info[i].type = SHARE_INFO_INT; info[i].value = talloc(info, int); - *((int *)info[i].value) = r->in.info.info2->max_users; + *((int *)info[i].value) = max_users; i++; - /* TODO: security descriptor */ - - nterr = share_set(sctx, r->in.share_name, info, i); - if (!NT_STATUS_IS_OK(nterr)) { - return ntstatus_to_werror(nterr); - } - - if (r->in.parm_error) { - r->out.parm_error = r->in.parm_error; - } - - return WERR_OK; - } case 501: - { - return WERR_NOT_SUPPORTED; - } - case 502: - { - struct share_info *info; - int count = 8; - int i; - - /* there are no more than 8 options in struct srvsvc_NetShareInfo502 */ - info = talloc_array(mem_ctx, struct share_info, count); - W_ERROR_HAVE_NO_MEMORY(info); - - i = 0; - - if (strcasecmp(r->in.share_name, r->in.info.info502->name) != 0) { - info[i].name = SHARE_NAME; - info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info502->name); - W_ERROR_HAVE_NO_MEMORY(info[i].value); - i++; - } - + case 1: info[i].name = SHARE_TYPE; info[i].type = SHARE_INFO_STRING; - switch (r->in.info.info502->type) { + switch (type) { case 0x00: info[i].value = talloc_strdup(info, "DISK"); break; @@ -1269,74 +1182,171 @@ static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_ W_ERROR_HAVE_NO_MEMORY(info[i].value); i++; - if (r->in.info.info502->path && r->in.info.info502->path[0]) { - info[i].name = SHARE_PATH; + case 1004: + if (comment) { + info[i].name = SHARE_COMMENT; info[i].type = SHARE_INFO_STRING; - - /* Windows will send a path in a form of C:\example\path */ - if (r->in.info.info2->path[1] == ':') { - info[i].value = talloc_strdup(info, &r->in.info.info502->path[2]); - } else { - /* very strange let's try to set as is */ - info[i].value = talloc_strdup(info, r->in.info.info502->path); - } + info[i].value = talloc_strdup(info, comment); W_ERROR_HAVE_NO_MEMORY(info[i].value); - all_string_sub((char *)info[i].value, "\\", "/", 0); i++; } - - if (r->in.info.info502->comment && r->in.info.info502->comment[0]) { - info[i].name = SHARE_COMMENT; + case 0: + if (name && + strcasecmp(share_name, name) != 0) { + info[i].name = SHARE_NAME; info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info502->comment); + info[i].value = talloc_strdup(info, name); W_ERROR_HAVE_NO_MEMORY(info[i].value); - i++; } - if (r->in.info.info502->password && r->in.info.info502->password[0]) { - info[i].name = SHARE_PASSWORD; - info[i].type = SHARE_INFO_STRING; - info[i].value = talloc_strdup(info, r->in.info.info502->password); - W_ERROR_HAVE_NO_MEMORY(info[i].value); + break; - i++; - } + default: + return WERR_UNKNOWN_LEVEL; + } - info[i].name = SHARE_MAX_CONNECTIONS; - info[i].type = SHARE_INFO_INT; - info[i].value = talloc(info, int); - *((int *)info[i].value) = r->in.info.info502->max_users; - i++; + *count = i; - /* TODO: security descriptor */ + return WERR_OK; +} - nterr = share_set(sctx, r->in.share_name, info, i); - if (!NT_STATUS_IS_OK(nterr)) { - return ntstatus_to_werror(nterr); - } +/* + srvsvc_NetShareSetInfo +*/ +static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct srvsvc_NetShareSetInfo *r) +{ + NTSTATUS nterr; + WERROR status; + struct share_context *sctx = NULL; + struct share_info *info; + int count; - if (r->in.parm_error) { - r->out.parm_error = r->in.parm_error; + /* TODO: - access check + */ + + /* there are no more than 10 options in all struct srvsvc_NetShareInfoXXX */ + info = talloc_array(mem_ctx, struct share_info, 10); + W_ERROR_HAVE_NO_MEMORY(info); + + ZERO_STRUCT(r->out); + + if (strcmp("", r->in.share_name) == 0) { + return WERR_INVALID_PARAM; + } + + nterr = share_get_context(mem_ctx, &sctx); + if (!NT_STATUS_IS_OK(nterr)) { + return ntstatus_to_werror(nterr); + } + + switch (r->in.level) { + case 0: + { + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + r->in.info.info0->name, + NULL, + NULL, + NULL, + 0, + 0, + 0, + NULL); + if (status != WERR_OK) { + return status; } - - return WERR_OK; + break; + } + case 1: + { + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + r->in.info.info1->name, + NULL, + r->in.info.info1->comment, + NULL, + r->in.info.info1->type, + 0, + 0, + NULL); + if (status != WERR_OK) { + return status; + } + break; + } + case 2: + { + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + r->in.info.info2->name, + r->in.info.info2->path, + r->in.info.info2->comment, + r->in.info.info2->password, + r->in.info.info2->type, + r->in.info.info2->max_users, + 0, + NULL); + if (status != WERR_OK) { + return status; + } + break; + } + case 501: + { + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + r->in.info.info501->name, + NULL, + r->in.info.info501->comment, + NULL, + r->in.info.info501->type, + 0, + r->in.info.info501->csc_policy, + NULL); + if (status != WERR_OK) { + return status; + } + break; + } + case 502: + { + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + r->in.info.info502->name, + r->in.info.info502->path, + r->in.info.info502->comment, + r->in.info.info502->password, + r->in.info.info502->type, + r->in.info.info502->max_users, + 0, + r->in.info.info502->sd); + if (status != WERR_OK) { + return status; + } + break; } case 1004: { - WERROR status; - union srvsvc_NetShareInfo info; - - /* r->in.info.comment; */ - - return WERR_NOT_SUPPORTED; + status = srvsvc_fill_share_info(info, &count, + r->in.share_name, r->in.level, + NULL, + NULL, + r->in.info.info1004->comment, + NULL, + 0, + 0, + 0, + NULL); + if (status != WERR_OK) { + return status; + } + break; } case 1005: { - WERROR status; - union srvsvc_NetShareInfo info; - /* r->in.info.dfs_flags; */ if (r->in.parm_error) { @@ -1349,7 +1359,16 @@ static WERROR srvsvc_NetShareSetInfo(struct dcesrv_call_state *dce_call, TALLOC_ return WERR_UNKNOWN_LEVEL; } - return WERR_UNKNOWN_LEVEL; + nterr = share_set(sctx, r->in.share_name, info, count); + if (!NT_STATUS_IS_OK(nterr)) { + return ntstatus_to_werror(nterr); + } + + if (r->in.parm_error) { + r->out.parm_error = r->in.parm_error; + } + + return WERR_OK; } diff --git a/source4/torture/rpc/srvsvc.c b/source4/torture/rpc/srvsvc.c index 685a71cfa3..696a42d167 100644 --- a/source4/torture/rpc/srvsvc.c +++ b/source4/torture/rpc/srvsvc.c @@ -500,6 +500,230 @@ static BOOL test_NetShareGetInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return ret; } +static BOOL test_NetShareAddSetDel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + struct srvsvc_NetShareAdd a; + struct srvsvc_NetShareSetInfo r; + struct srvsvc_NetShareGetInfo q; + struct srvsvc_NetShareDel d; + struct { + uint32_t level; + WERROR expected; + } levels[] = { + { 0, WERR_UNKNOWN_LEVEL }, + { 1, WERR_OK }, + { 2, WERR_OK }, + { 501, WERR_UNKNOWN_LEVEL }, + { 502, WERR_OK }, + { 1004, WERR_OK }, + { 1005, WERR_OK }, + { 1006, WERR_OK }, +/* { 1007, WERR_OK }, */ + { 1501, WERR_OK }, + }; + int i; + BOOL ret = True; + + a.in.server_unc = r.in.server_unc = q.in.server_unc = d.in.server_unc = + talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); + r.in.share_name = talloc_strdup(mem_ctx, "testshare"); + + a.in.level = 2; + a.in.info.info2 = talloc(mem_ctx, struct srvsvc_NetShareInfo2); + a.in.info.info2->name = r.in.share_name; + a.in.info.info2->type = STYPE_DISKTREE; + a.in.info.info2->comment = talloc_strdup(mem_ctx, "test comment"); + a.in.info.info2->permissions = 123434566; + a.in.info.info2->max_users = -1; + a.in.info.info2->current_users = 0; + a.in.info.info2->path = talloc_strdup(mem_ctx, "C:\\"); + a.in.info.info2->password = NULL; + + a.in.parm_error = NULL; + + status = dcerpc_srvsvc_NetShareAdd(p, mem_ctx, &a); + if (!NT_STATUS_IS_OK(status)) { + d_printf("NetShareAdd level 2 on share 'testshare' failed - %s\n", + nt_errstr(status)); + return False; + } else if (!W_ERROR_EQUAL(a.out.result, WERR_OK)) { + d_printf("NetShareAdd level 2 on share 'testshare' failed - %s\n", + win_errstr(a.out.result)); + return False; + } + + r.in.parm_error = NULL; + + q.in.level = 502; + + for (i = 0; i < ARRAY_SIZE(levels); i++) { + + r.in.level = levels[i].level; + ZERO_STRUCT(r.out); + + d_printf("testing NetShareSetInfo level %u on share '%s'\n", + r.in.level, r.in.share_name); + + switch (levels[i].level) { + case 0: + r.in.info.info0 = talloc(mem_ctx, struct srvsvc_NetShareInfo0); + r.in.info.info0->name = r.in.share_name; + break; + case 1: + r.in.info.info1 = talloc(mem_ctx, struct srvsvc_NetShareInfo1); + r.in.info.info1->name = r.in.share_name; + r.in.info.info1->type = STYPE_DISKTREE; + r.in.info.info1->comment = talloc_strdup(mem_ctx, "test comment 1"); + break; + case 2: + r.in.info.info2 = talloc(mem_ctx, struct srvsvc_NetShareInfo2); + r.in.info.info2->name = r.in.share_name; + r.in.info.info2->type = STYPE_DISKTREE; + r.in.info.info2->comment = talloc_strdup(mem_ctx, "test comment 2"); + r.in.info.info2->permissions = 0; + r.in.info.info2->max_users = 2; + r.in.info.info2->current_users = 1; + r.in.info.info2->path = talloc_strdup(mem_ctx, "::BLaH::"); /* "C:\\"); */ + r.in.info.info2->password = NULL; + break; + case 501: + r.in.info.info501 = talloc(mem_ctx, struct srvsvc_NetShareInfo501); + r.in.info.info501->name = r.in.share_name; + r.in.info.info501->type = STYPE_DISKTREE; + r.in.info.info501->comment = talloc_strdup(mem_ctx, "test comment 501"); + r.in.info.info501->csc_policy = 0; + break; + case 502: + r.in.info.info502 = talloc(mem_ctx, struct srvsvc_NetShareInfo502); + r.in.info.info502->name = r.in.share_name; + r.in.info.info502->type = STYPE_DISKTREE; + r.in.info.info502->comment = talloc_strdup(mem_ctx, "test comment 502"); + r.in.info.info502->permissions = 0; + r.in.info.info502->max_users = 502; + r.in.info.info502->current_users = 1; + r.in.info.info502->path = talloc_strdup(mem_ctx, "C:\\"); + r.in.info.info502->password = NULL; + r.in.info.info502->unknown = 0; + r.in.info.info502->sd = NULL; + break; + case 1004: + r.in.info.info1004 = talloc(mem_ctx, struct srvsvc_NetShareInfo1004); + r.in.info.info1004->comment = talloc_strdup(mem_ctx, "test comment 1004"); + break; + case 1005: + r.in.info.info1005 = talloc(mem_ctx, struct srvsvc_NetShareInfo1005); + r.in.info.info1005->dfs_flags = 0; + break; + case 1006: + r.in.info.info1006 = talloc(mem_ctx, struct srvsvc_NetShareInfo1006); + r.in.info.info1006->max_users = 1006; + break; +/* case 1007: + r.in.info.info1007 = talloc(mem_ctx, struct srvsvc_NetShareInfo1007); + r.in.info.info1007->flags = 0; + r.in.info.info1007->alternate_directory_name = talloc_strdup(mem_ctx, "test"); + break; +*/ + case 1501: + r.in.info.info1501 = talloc_zero(mem_ctx, struct sec_desc_buf); + break; + } + + status = dcerpc_srvsvc_NetShareSetInfo(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("NetShareGetInfo level %u on share '%s' failed - %s\n", + r.in.level, r.in.share_name, nt_errstr(status)); + ret = False; + continue; + } else if (!W_ERROR_EQUAL(r.out.result, levels[i].expected)) { + d_printf("NetShareSetInfo level %u on share '%s' failed - %s (expected %s)\n", + r.in.level, r.in.share_name, win_errstr(r.out.result), + win_errstr(levels[i].expected)); + ret = False; + continue; + } + + q.in.share_name = r.in.share_name; + + status = dcerpc_srvsvc_NetShareGetInfo(p, mem_ctx, &q); + if (!NT_STATUS_IS_OK(status)) { + d_printf("NetShareGetInfo level %u on share '%s' failed - %s\n", + q.in.level, q.in.share_name, nt_errstr(status)); + ret = False; + continue; + } else if (!W_ERROR_EQUAL(q.out.result, WERR_OK)) { + d_printf("NetShareGetInfo level %u on share '%s' failed - %s\n", + q.in.level, q.in.share_name, win_errstr(q.out.result)); + ret = False; + continue; + } + + if (strcmp(q.out.info.info502->name, r.in.share_name) != 0) { + ret = False; + } + switch (levels[i].level) { + case 0: + break; + case 1: + if (strcmp(q.out.info.info502->comment, "test comment 1") != 0) + ret = False; + break; + case 2: + if (strcmp(q.out.info.info502->comment, "test comment 2") != 0) + ret = False; + if (q.out.info.info2->max_users != 2) + ret = False; + if (strcmp(q.out.info.info2->path, "C:\\") != 0) + ret = False; + break; + case 501: + if (strcmp(q.out.info.info501->comment, "test comment 501") != 0) + ret = False; + break; + case 502: + if (strcmp(q.out.info.info502->comment, "test comment 502") != 0) + ret = False; + if (q.out.info.info2->max_users != 502) + ret = False; + if (strcmp(q.out.info.info2->path, "C:\\") != 0) + ret = False; + break; + case 1004: + if (strcmp(q.out.info.info502->comment, "test comment 1004") != 0) + ret = False; + break; + case 1005: + break; + case 1006: + if (q.out.info.info2->max_users != 1006) + ret = False; + break; +/* case 1007: + break; +*/ + case 1501: + break; + } + } + + d.in.share_name = r.in.share_name; + d.in.reserved = 0; + + status = dcerpc_srvsvc_NetShareDel(p, mem_ctx, &d); + if (!NT_STATUS_IS_OK(status)) { + d_printf("NetShareDel on share 'testshare502' failed - %s\n", + nt_errstr(status)); + ret = False; + } else if (!W_ERROR_EQUAL(a.out.result, WERR_OK)) { + d_printf("NetShareDel on share 'testshare502' failed - %s\n", + win_errstr(d.out.result)); + ret = False; + } + + return ret; +} + /**************************/ /* srvsvc_NetShare */ /**************************/ @@ -776,7 +1000,8 @@ static BOOL test_NetNameValidate(struct dcerpc_pipe *p, NTSTATUS status; struct srvsvc_NetNameValidate r; char *invalidc; - int i, n; + char *name; + int i, n, min, max; r.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); r.in.flags = 0x0; @@ -787,31 +1012,44 @@ static BOOL test_NetNameValidate(struct dcerpc_pipe *p, for (i = 1; i < 14; i++) { again: - /* Find maximum length accepted by this type */ - ZERO_STRUCT(r.out); - r.in.name_type = i; - r.in.name = talloc_strdup(mem_ctx, "A"); - n = 0; + /* let's limit ourselves to a maximum of 4096 bytes */ + r.in.name = name = talloc_array(mem_ctx, char, 4097); + max = 4096; + min = 0; + n = max; + + while (1) { + + /* Find maximum length accepted by this type */ + ZERO_STRUCT(r.out); + r.in.name_type = i; + memset(name, 'A', n); + name[n] = '\0'; - while (W_ERROR_IS_OK(r.out.result)) { status = dcerpc_srvsvc_NetNameValidate(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { d_printf("NetNameValidate failed while checking maximum size (%s)\n", nt_errstr(status)); break; } - - r.in.name = talloc_append_string(mem_ctx, r.in.name, "A"); - if (!r.in.name) { - d_printf("NetNameValidate: Out of memory!\n"); - return False; + + if (W_ERROR_IS_OK(r.out.result)) { + min = n; + n += (max - min + 1)/2; + continue; + + } else { + if ((min + 1) >= max) break; /* found it */ + + max = n; + n -= (max - min)/2; + continue; } - n++; } talloc_free(r.in.name); - d_printf("Maximum length for type %2d, flags %08x: %d\n", i, r.in.flags, n); + d_printf("Maximum length for type %2d, flags %08x: %d\n", i, r.in.flags, max); /* find invalid chars for this type check only ASCII between 0x20 and 0x7e */ @@ -877,6 +1115,7 @@ BOOL torture_rpc_srvsvc(struct torture_context *torture) ret &= test_NetRemoteTOD(p, mem_ctx); ret &= test_NetShareEnum(p, mem_ctx, True); ret &= test_NetShareGetInfo(p, mem_ctx, "ADMIN$", True); + ret &= test_NetShareAddSetDel(p, mem_ctx); ret &= test_NetNameValidate(p, mem_ctx); status = torture_rpc_connection(mem_ctx, &p, &dcerpc_table_srvsvc); |