allow-arbitrary-params-in-usershares [plain text]
Index: samba/source/param/loadparm.c
===================================================================
--- samba/source/param/loadparm.c.orig
+++ samba/source/param/loadparm.c
@@ -9,6 +9,7 @@
Copyright (C) Alexander Bokovoy 2002
Copyright (C) Stefan (metze) Metzmacher 2002
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) 2007 Apple Inc. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -305,6 +306,7 @@ typedef struct {
BOOL bASUSupport;
BOOL bUsershareOwnerOnly;
BOOL bUsershareAllowGuests;
+ BOOL bUsershareAllowFullConfig;
int restrict_anonymous;
int name_cache_timeout;
int client_signing;
@@ -1233,6 +1235,7 @@ static struct parm_struct parm_table[] =
{"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
{"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
{"usershare allow guests", P_BOOL, P_GLOBAL, &Globals.bUsershareAllowGuests, NULL, NULL, FLAG_ADVANCED},
+ {"usershare allow full config", P_BOOL, P_GLOBAL, &Globals.bUsershareAllowFullConfig, NULL, NULL, FLAG_ADVANCED},
{"usershare max shares", P_INTEGER, P_GLOBAL, &Globals.iUsershareMaxShares, NULL, NULL, FLAG_ADVANCED},
{"usershare owner only", P_BOOL, P_GLOBAL, &Globals.bUsershareOwnerOnly, NULL, NULL, FLAG_ADVANCED},
{"usershare path", P_STRING, P_GLOBAL, &Globals.szUsersharePath, NULL, NULL, FLAG_ADVANCED},
@@ -1667,6 +1670,8 @@ static void init_globals(BOOL first_time
Globals.bUsershareOwnerOnly = True;
/* By default disallow guest access to usershares. */
Globals.bUsershareAllowGuests = False;
+ /* By default don't allow arbitrary usershare configurations. */
+ Globals.bUsershareAllowFullConfig = False;
}
static TALLOC_CTX *lp_talloc;
@@ -1922,6 +1927,7 @@ FN_GLOBAL_LIST(lp_usershare_prefix_deny_
FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs)
FN_GLOBAL_BOOL(lp_usershare_allow_guests, &Globals.bUsershareAllowGuests)
+FN_GLOBAL_BOOL(lp_usershare_allow_full_config, &Globals.bUsershareAllowFullConfig)
FN_GLOBAL_BOOL(lp_usershare_owner_only, &Globals.bUsershareOwnerOnly)
FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios)
FN_GLOBAL_BOOL(lp_reset_on_zero_vc, &Globals.bResetOnZeroVC)
@@ -4381,84 +4387,33 @@ static BOOL check_usershare_stat(const c
}
/***************************************************************************
- Parse the contents of a usershare file.
+ Check whether the usershare configuration allows a particular path to be
+ shared.
***************************************************************************/
-enum usershare_err parse_usershare_file(TALLOC_CTX *ctx,
- SMB_STRUCT_STAT *psbuf,
- const char *servicename,
- int snum,
- char **lines,
- int numlines,
- pstring sharepath,
- pstring comment,
- SEC_DESC **ppsd,
- BOOL *pallow_guest)
+static enum usershare_err usershare_validate_path(int snum,
+ const char *servicename,
+ const SMB_STRUCT_STAT *svcstat,
+ const char *sharepath)
{
+ static const char const fn[] = "usershare_validate_path";
+
const char **prefixallowlist = lp_usershare_prefix_allow_list();
const char **prefixdenylist = lp_usershare_prefix_deny_list();
- int us_vers;
+
SMB_STRUCT_DIR *dp;
SMB_STRUCT_STAT sbuf;
- *pallow_guest = False;
-
- if (numlines < 4) {
- return USERSHARE_MALFORMED_FILE;
- }
-
- if (strcmp(lines[0], "#VERSION 1") == 0) {
- us_vers = 1;
- } else if (strcmp(lines[0], "#VERSION 2") == 0) {
- us_vers = 2;
- if (numlines < 5) {
- return USERSHARE_MALFORMED_FILE;
- }
- } else {
- return USERSHARE_BAD_VERSION;
- }
-
- if (strncmp(lines[1], "path=", 5) != 0) {
- return USERSHARE_MALFORMED_PATH;
- }
-
- pstrcpy(sharepath, &lines[1][5]);
- trim_string(sharepath, " ", " ");
-
- if (strncmp(lines[2], "comment=", 8) != 0) {
- return USERSHARE_MALFORMED_COMMENT_DEF;
- }
-
- pstrcpy(comment, &lines[2][8]);
- trim_string(comment, " ", " ");
- trim_char(comment, '"', '"');
-
- if (strncmp(lines[3], "usershare_acl=", 14) != 0) {
- return USERSHARE_MALFORMED_ACL_DEF;
- }
-
- if (!parse_usershare_acl(ctx, &lines[3][14], ppsd)) {
- return USERSHARE_ACL_ERR;
- }
-
- if (us_vers == 2) {
- if (strncmp(lines[4], "guest_ok=", 9) != 0) {
- return USERSHARE_MALFORMED_ACL_DEF;
- }
- if (lines[4][9] == 'y') {
- *pallow_guest = True;
- }
- }
-
- if (snum != -1 && (strcmp(sharepath, ServicePtrs[snum]->szPath) == 0)) {
+ if (snum != GLOBAL_SECTION_SNUM &&
+ (strcmp(sharepath, ServicePtrs[snum]->szPath) == 0)) {
/* Path didn't change, no checks needed. */
return USERSHARE_OK;
}
/* The path *must* be absolute. */
if (sharepath[0] != '/') {
- DEBUG(2,("parse_usershare_file: share %s: path %s is not an absolute path.\n",
- servicename, sharepath));
+ DEBUG(2,("%s: share %s: path %s is not an absolute path.\n",
+ fn, servicename, sharepath));
return USERSHARE_PATH_NOT_ABSOLUTE;
}
@@ -4467,12 +4422,12 @@ enum usershare_err parse_usershare_file(
if (prefixdenylist) {
int i;
for ( i=0; prefixdenylist[i]; i++ ) {
- DEBUG(10,("parse_usershare_file: share %s : checking prefixdenylist[%d]='%s' against %s\n",
- servicename, i, prefixdenylist[i], sharepath ));
+ DEBUG(10,("%s: share %s : checking prefixdenylist[%d]='%s' against %s\n",
+ fn, servicename, i, prefixdenylist[i], sharepath ));
if (memcmp( sharepath, prefixdenylist[i], strlen(prefixdenylist[i])) == 0) {
- DEBUG(2,("parse_usershare_file: share %s path %s starts with one of the "
+ DEBUG(2,("%s: share %s path %s starts with one of the "
"usershare prefix deny list entries.\n",
- servicename, sharepath));
+ fn, servicename, sharepath));
return USERSHARE_PATH_IS_DENIED;
}
}
@@ -4484,16 +4439,16 @@ enum usershare_err parse_usershare_file(
if (prefixallowlist) {
int i;
for ( i=0; prefixallowlist[i]; i++ ) {
- DEBUG(10,("parse_usershare_file: share %s checking prefixallowlist[%d]='%s' against %s\n",
- servicename, i, prefixallowlist[i], sharepath ));
+ DEBUG(10,("%s: share %s checking prefixallowlist[%d]='%s' against %s\n",
+ fn, servicename, i, prefixallowlist[i], sharepath ));
if (memcmp( sharepath, prefixallowlist[i], strlen(prefixallowlist[i])) == 0) {
break;
}
}
if (prefixallowlist[i] == NULL) {
- DEBUG(2,("parse_usershare_file: share %s path %s doesn't start with one of the "
+ DEBUG(2,("%s: share %s path %s doesn't start with one of the "
"usershare prefix allow list entries.\n",
- servicename, sharepath));
+ fn, servicename, sharepath));
return USERSHARE_PATH_NOT_ALLOWED;
}
}
@@ -4502,8 +4457,8 @@ enum usershare_err parse_usershare_file(
dp = sys_opendir(sharepath);
if (!dp) {
- DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
- servicename, sharepath));
+ DEBUG(2,("%s: share %s path %s is not a directory.\n",
+ fn, servicename, sharepath));
return USERSHARE_PATH_NOT_DIRECTORY;
}
@@ -4511,8 +4466,8 @@ enum usershare_err parse_usershare_file(
this directory. */
if (sys_stat(sharepath, &sbuf) == -1) {
- DEBUG(2,("parse_usershare_file: share %s : stat failed on path %s. %s\n",
- servicename, sharepath, strerror(errno) ));
+ DEBUG(2,("%s: share %s : stat failed on path %s. %s\n",
+ fn, servicename, sharepath, strerror(errno) ));
sys_closedir(dp);
return USERSHARE_POSIX_ERR;
}
@@ -4520,8 +4475,8 @@ enum usershare_err parse_usershare_file(
sys_closedir(dp);
if (!S_ISDIR(sbuf.st_mode)) {
- DEBUG(2,("parse_usershare_file: share %s path %s is not a directory.\n",
- servicename, sharepath ));
+ DEBUG(2,("%s: share %s path %s is not a directory.\n",
+ fn, servicename, sharepath ));
return USERSHARE_PATH_NOT_DIRECTORY;
}
@@ -4531,7 +4486,8 @@ enum usershare_err parse_usershare_file(
if (lp_usershare_owner_only()) {
/* root can share anything. */
- if ((psbuf->st_uid != 0) && (sbuf.st_uid != psbuf->st_uid)) {
+ if ((svcstat->st_uid != 0) &&
+ (sbuf.st_uid != svcstat->st_uid)) {
return USERSHARE_PATH_NOT_ALLOWED;
}
}
@@ -4539,6 +4495,282 @@ enum usershare_err parse_usershare_file(
return USERSHARE_OK;
}
+/* Handle versions 1 and 2. */
+static enum usershare_err parse_usershare_file_vers2(TALLOC_CTX *ctx,
+ const SMB_STRUCT_STAT *svcstat,
+ const char *servicename,
+ int snum,
+ int us_vers,
+ const char **lines,
+ int numlines)
+{
+ pstring sharepath;
+ pstring comment;
+ SEC_DESC *psd = NULL;
+ BOOL guest_ok = False;
+ BOOL applied_share_acl = False;
+ enum usershare_err ret = USERSHARE_MALFORMED_FILE;
+
+ if (us_vers != 1 && us_vers != 2) {
+ return USERSHARE_BAD_VERSION;
+ }
+
+ if (numlines < 4) {
+ return USERSHARE_MALFORMED_FILE;
+ }
+
+ if (us_vers == 2 && numlines < 5) {
+ return USERSHARE_MALFORMED_FILE;
+ }
+
+ if (strncmp(lines[1], "path=", 5) != 0) {
+ return USERSHARE_MALFORMED_PATH;
+ }
+ pstrcpy(sharepath, &lines[1][5]);
+ trim_string(sharepath, " ", " ");
+
+ ret = usershare_validate_path(snum, servicename, svcstat, sharepath);
+ if (ret != USERSHARE_OK) {
+ goto done;
+ }
+
+ if (snum != GLOBAL_SECTION_SNUM &&
+ !lp_do_parameter(snum, "path", sharepath)) {
+ ret = USERSHARE_MALFORMED_PATH;
+ goto done;
+ }
+
+ if (strncmp(lines[2], "comment=", 8) != 0) {
+ ret = USERSHARE_MALFORMED_COMMENT_DEF;
+ goto done;
+ }
+
+ pstrcpy(comment, &lines[2][8]);
+ trim_string(comment, " ", " ");
+ trim_char(comment, '"', '"');
+
+ if (snum != GLOBAL_SECTION_SNUM) {
+ lp_do_parameter(snum, "comment", comment);
+ }
+
+ if (strncmp(lines[3], "usershare_acl=", 14) != 0) {
+ ret = USERSHARE_MALFORMED_ACL_DEF;
+ goto done;
+ }
+
+ if (!parse_usershare_acl(ctx, &lines[3][14], &psd)) {
+ ret = USERSHARE_ACL_ERR;
+ goto done;
+ }
+
+ /* Write the ACL of the new/modified share. */
+ if (snum != GLOBAL_SECTION_SNUM) {
+ if (!set_share_security(servicename, psd)) {
+ DEBUG(0, ("Failed to set share "
+ "security for user share %s\n",
+ servicename ));
+ ret = USERSHARE_ACL_ERR;
+ goto done;
+ } else {
+ applied_share_acl = True;
+ }
+ }
+
+ if (us_vers == 2) {
+ if (strncmp(lines[4], "guest_ok=", 9) != 0) {
+ ret = USERSHARE_MALFORMED_ACL_DEF;
+ goto done;
+ }
+ if (lines[4][9] == 'y' && lp_usershare_allow_guests()) {
+ guest_ok = True;
+ }
+ }
+
+ if (snum != GLOBAL_SECTION_SNUM) {
+ lp_do_parameter(snum, "guest ok", guest_ok ? "yes" : "no");
+ }
+
+ ret = USERSHARE_OK;
+
+done:
+ /* Make sure we don't remove any existing share ACL just because we
+ * found a bogus usershare file.
+ */
+ if (applied_share_acl && ret != USERSHARE_OK) {
+ delete_share_security(snum2params_static(snum));
+ }
+
+ return ret;
+}
+
+/* Handle version 3. */
+static enum usershare_err parse_usershare_file_vers3(TALLOC_CTX *ctx,
+ const SMB_STRUCT_STAT *svcstat,
+ const char *servicename,
+ int snum,
+ int us_vers,
+ const char **lines,
+ int numlines)
+{
+ fstring param;
+ fstring value;
+
+ BOOL applied_share_acl = False;
+ enum usershare_err ret = USERSHARE_MALFORMED_FILE;
+ int i;
+
+ if (us_vers != 3) {
+ return USERSHARE_BAD_VERSION;
+ }
+
+ if (!lp_usershare_allow_full_config()) {
+ return USERSHARE_BAD_VERSION;
+ }
+
+ if (snum != GLOBAL_SECTION_SNUM) {
+ lp_do_parameter(snum, "guest ok", "no");
+ }
+
+ for (i = 1; i < numlines; ++i) {
+ const char *sep = strchr(lines[i], '=');
+ if (sep == NULL || /* no separator */
+ sep == lines[i] || /* no param */
+ *(sep + 1) == '\0') /* no value */ {
+ ret = USERSHARE_MALFORMED_FILE;
+ goto done;
+ }
+
+ /* More than 20 options is just silly - someone is messing with
+ * us if this is the case.
+ */
+ if (i > 20) {
+ ret = USERSHARE_MALFORMED_FILE;
+ goto done;
+ }
+
+ /* Make sure that both the param and the value will fit in an
+ * fstring. Note that we don't support comments in ths file
+ * format, so no need to trim them.
+ */
+ if (PTR_DIFF(sep, lines[i]) >= sizeof(fstring) ||
+ strlen(sep) >= sizeof(fstring)) {
+ ret = USERSHARE_MALFORMED_FILE;
+ goto done;
+ }
+
+ strncpy(param, lines[i], PTR_DIFF(sep, lines[i]));
+ param[PTR_DIFF(sep, lines[i])] = '\0';
+ trim_string(param, " ", " ");
+ trim_char(param, '"', '"');
+
+ strncpy(value, sep + 1, sizeof(fstring));
+ value[sizeof(fstring) - 1] = '\0';
+ trim_string(value, " ", " ");
+ trim_char(value, '"', '"');
+
+ if (strcmp(param, "path") == 0) {
+ ret = usershare_validate_path(snum, servicename,
+ svcstat, value);
+ if (ret != USERSHARE_OK) {
+ goto done;
+ }
+ } else if (strcmp(param, "guest ok") == 0) {
+ if (!lp_usershare_allow_guests()) {
+ continue;
+ }
+ } else if (strcmp(param, "usershare_acl") == 0) {
+ /* There's not standard config option for the
+ * usershare share ACL syntax, so we roll it by hand.
+ */
+ SEC_DESC *psd = NULL;
+
+ if (!parse_usershare_acl(ctx, value, &psd)) {
+ ret = USERSHARE_ACL_ERR;
+ goto done;
+ }
+
+ if (snum == GLOBAL_SECTION_SNUM) {
+ continue;
+ }
+
+ if (!set_share_security(servicename, psd)) {
+ DEBUG(0, ("Failed to set share "
+ "security for user share %s\n",
+ servicename ));
+ ret = USERSHARE_ACL_ERR;
+ goto done;
+ }
+
+ applied_share_acl = True;
+ continue;
+ }
+
+ if (snum == GLOBAL_SECTION_SNUM) {
+ continue;
+ }
+
+ if (!lp_do_parameter(snum, param, value)) {
+ DEBUG(0, ("Malformed parameter '%s' "
+ "on user share %s\n", param, servicename));
+ ret = USERSHARE_MALFORMED_FILE;
+ goto done;
+ }
+ }
+
+ ret = USERSHARE_OK;
+
+done:
+ /* Make sure we don't remove any existing share ACL just because we
+ * found a bogus usershare file.
+ */
+ if (applied_share_acl && ret != USERSHARE_OK) {
+ delete_share_security(snum2params_static(snum));
+ }
+
+ return ret;
+}
+
+/***************************************************************************
+ Parse the contents of a usershare file. Passing GLOBAL_SECTION_SNUM as the
+ service number means to to as much parsing and validation as possible without
+ actually applying the configuration changes.
+***************************************************************************/
+
+enum usershare_err parse_usershare_file(TALLOC_CTX *ctx,
+ const SMB_STRUCT_STAT *svcstat,
+ const char *servicename,
+ int snum,
+ const char **lines,
+ int numlines)
+{
+ int us_vers = -1;
+
+ if (strcmp(lines[0], "#VERSION 1") == 0) {
+ us_vers = 1;
+ } else if (strcmp(lines[0], "#VERSION 2") == 0) {
+ us_vers = 2;
+ } else if (strcmp(lines[0], "#VERSION 3") == 0) {
+ /* Version 3 adds the ability to specify arbitrary smb.conf
+ * parameters in a usershare file. We only allow this if
+ * permission is granted by the admin.
+ */
+ us_vers = 3;
+ }
+
+ switch (us_vers) {
+ case 1:
+ case 2:
+ return parse_usershare_file_vers2(ctx, svcstat, servicename,
+ snum, us_vers, lines, numlines);
+ case 3:
+ return parse_usershare_file_vers3(ctx, svcstat, servicename,
+ snum, us_vers, lines, numlines);
+ default:
+ return USERSHARE_BAD_VERSION;
+ }
+
+}
+
/***************************************************************************
Deal with a usershare file.
Returns:
@@ -4548,21 +4780,20 @@ enum usershare_err parse_usershare_file(
with permissions to share directory etc.
***************************************************************************/
-static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template)
+static int process_usershare_file(const char *dir_name,
+ const char *file_name,
+ int snum_template)
{
SMB_STRUCT_STAT sbuf;
SMB_STRUCT_STAT lsbuf;
pstring fname;
- pstring sharepath;
- pstring comment;
fstring service_name;
char **lines = NULL;
int numlines = 0;
int fd = -1;
int iService = -1;
TALLOC_CTX *ctx = NULL;
- SEC_DESC *psd = NULL;
- BOOL guest_ok = False;
+ service *saved_service = NULL;
/* Ensure share name doesn't contain invalid characters. */
if (!validate_net_name(file_name, INVALID_SHARENAME_CHARS, strlen(file_name))) {
@@ -4658,16 +4889,6 @@ static int process_usershare_file(const
return 1;
}
- if (parse_usershare_file(ctx, &sbuf, service_name,
- iService, lines, numlines, sharepath,
- comment, &psd, &guest_ok) != USERSHARE_OK) {
- talloc_destroy(ctx);
- file_lines_free(lines);
- return -1;
- }
-
- file_lines_free(lines);
-
/* Everything ok - add the service possibly using a template. */
if (iService < 0) {
const service *sp = &sDefault;
@@ -4678,24 +4899,50 @@ static int process_usershare_file(const
if ((iService = add_a_service(sp, service_name)) < 0) {
DEBUG(0, ("process_usershare_file: Failed to add "
"new service %s\n", service_name));
+ file_lines_free(lines);
talloc_destroy(ctx);
return -1;
}
+ /* Don't let this be valid until we have parsed the usershare
+ * file correctly.
+ */
+ ServicePtrs[iService]->valid = False;
+
/* Read only is controlled by usershare ACL below. */
ServicePtrs[iService]->bRead_only = False;
+ } else if (ServicePtrs[iService]->usershare == 0) {
+ /* We are modifying an existing service this is not a
+ * usershare. This is OK, but we do not want a corrupt or
+ * malicious usershare file to damage it. We save a copy of the
+ * service so that we can restore it if necessary.
+ */
+ saved_service = talloc_zero(ctx, service);
+ if (saved_service == NULL) {
+ file_lines_free(lines);
+ talloc_destroy(ctx);
+ return -1;
+ }
+
+ copy_service(saved_service, ServicePtrs[iService], NULL);
}
- /* Write the ACL of the new/modified share. */
- if (!set_share_security(service_name, psd)) {
- DEBUG(0, ("process_usershare_file: Failed to set share "
- "security for user share %s\n",
- service_name ));
- lp_remove_service(iService);
+ if (parse_usershare_file(ctx, &sbuf, service_name, iService,
+ (const char **)lines, numlines) != USERSHARE_OK) {
+ if (saved_service) {
+ free_service(ServicePtrs[iService]);
+ copy_service(ServicePtrs[iService],
+ saved_service, NULL);
+ free_service(saved_service);
+ } else {
+ lp_remove_service(iService);
+ }
talloc_destroy(ctx);
+ file_lines_free(lines);
return -1;
}
+ file_lines_free(lines);
talloc_destroy(ctx);
/* If from a template it may be marked invalid. */
@@ -4704,15 +4951,8 @@ static int process_usershare_file(const
/* Set the service as a valid usershare. */
ServicePtrs[iService]->usershare = USERSHARE_VALID;
- /* Set guest access. */
- if (lp_usershare_allow_guests()) {
- ServicePtrs[iService]->bGuest_ok = guest_ok;
- }
-
/* And note when it was loaded. */
ServicePtrs[iService]->usershare_last_mod = sbuf.st_mtime;
- string_set(&ServicePtrs[iService]->szPath, sharepath);
- string_set(&ServicePtrs[iService]->comment, comment);
return iService;
}
Index: samba/source/utils/net_usershare.c
===================================================================
--- samba/source/utils/net_usershare.c.orig
+++ samba/source/utils/net_usershare.c
@@ -3,6 +3,7 @@
Distributed SMB/CIFS Server Management Utility
Copyright (C) Jeremy Allison (jra@samba.org) 2005
+ Copyright (C) 2007 Apple Inc. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -289,6 +290,79 @@ static int process_share_list(int (*fn)(
Info function.
***************************************************************************/
+/* Parse the usershare_ok line from a version 1 - 3 usershare file and return a
+ * string containing the resolved ACL.
+ */
+static char * resolve_usershare_acl(void * ctx, const char * usershare_line)
+{
+ char *acl_str;
+ const char *acl_sep;
+ fstring acl_value;
+
+ int num_aces;
+ char sep_str[2];
+ SEC_DESC *psd = NULL;
+
+ sep_str[0] = *lp_winbind_separator();
+ sep_str[1] = '\0';
+
+ acl_sep = strchr(usershare_line, '=');
+ if (acl_sep == NULL || /* no separator */
+ acl_sep == usershare_line || /* no param */
+ *(acl_sep + 1) == '\0') /* no value */ {
+ /* Shouldn't happen because we already checked the syntax. */
+ DEBUG(0, ("invalid usershare_acl syntax: '%s'\n",
+ usershare_line));
+ return NULL;
+ }
+
+ strncpy(acl_value, acl_sep + 1, sizeof(fstring));
+ trim_string(acl_value, " ", " ");
+ trim_char(acl_value, '"', '"');
+
+ if (!parse_usershare_acl(ctx, acl_value, &psd)) {
+ /* Shouldn't happen because we already checked the syntax. */
+ DEBUG(0, ("invalid usershare_acl: %s\n", acl_value));
+ return NULL;
+ }
+
+ acl_str = talloc_strdup(ctx, "");
+
+ for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
+ const char *domain;
+ const char *name;
+ NTSTATUS ntstatus;
+
+ ntstatus = net_lookup_name_from_sid(ctx, &psd->dacl->aces[num_aces].trustee, &domain, &name);
+
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ if (domain && *domain) {
+ acl_str = talloc_asprintf_append(acl_str,
+ "%s%s", domain, sep_str);
+ }
+ acl_str = talloc_asprintf_append(acl_str, "%s", name);
+ } else {
+ fstring sidstr;
+ sid_to_string(sidstr, &psd->dacl->aces[num_aces].trustee);
+ acl_str = talloc_asprintf_append(acl_str, "%s", sidstr);
+ }
+
+ acl_str = talloc_asprintf_append(acl_str, ":");
+
+ if (psd->dacl->aces[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
+ acl_str = talloc_asprintf_append(acl_str, "D");
+ } else {
+ if (psd->dacl->aces[num_aces].access_mask & GENERIC_ALL_ACCESS) {
+ acl_str = talloc_asprintf_append(acl_str, "F");
+ } else {
+ acl_str = talloc_asprintf_append(acl_str, "R");
+ }
+ }
+ }
+
+ return acl_str;
+}
+
static int info_fn(struct file_list *fl, void *priv)
{
SMB_STRUCT_STAT sbuf;
@@ -297,18 +371,8 @@ static int info_fn(struct file_list *fl,
TALLOC_CTX *ctx = pi->ctx;
int fd = -1;
int numlines = 0;
- SEC_DESC *psd = NULL;
pstring basepath;
- pstring sharepath;
- pstring comment;
- pstring acl_str;
- int num_aces;
- char sep_str[2];
enum usershare_err us_err;
- BOOL guest_ok = False;
-
- sep_str[0] = *lp_winbind_separator();
- sep_str[1] = '\0';
get_basepath(basepath);
pstrcat(basepath, "/");
@@ -349,67 +413,45 @@ static int info_fn(struct file_list *fl,
}
/* Ensure it's well formed. */
- us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines,
- sharepath,
- comment,
- &psd,
- &guest_ok);
-
- file_lines_free(lines);
+ us_err = parse_usershare_file(ctx, &sbuf,
+ fl->pathname, GLOBAL_SECTION_SNUM,
+ (const char **)lines, numlines);
if (us_err != USERSHARE_OK) {
d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n",
basepath );
d_fprintf(stderr, "info_fn: Error was %s.\n",
get_us_error_code(us_err) );
+ file_lines_free(lines);
return -1;
}
- pstrcpy(acl_str, "usershare_acl=");
-
- for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
- const char *domain;
- const char *name;
- NTSTATUS ntstatus;
-
- ntstatus = net_lookup_name_from_sid(ctx, &psd->dacl->aces[num_aces].trustee, &domain, &name);
+ if (pi->op == US_LIST_OP) {
+ d_printf("%s\n", fl->pathname);
+ } else if (pi->op == US_INFO_OP) {
+ int i;
+ d_printf("[%s]\n", fl->pathname );
- if (NT_STATUS_IS_OK(ntstatus)) {
- if (domain && *domain) {
- pstrcat(acl_str, domain);
- pstrcat(acl_str, sep_str);
+ for (i = 0; i < numlines; ++i) {
+ if (*lines[i] == '#') {
+ continue;
}
- pstrcat(acl_str,name);
- } else {
- fstring sidstr;
- sid_to_string(sidstr, &psd->dacl->aces[num_aces].trustee);
- pstrcat(acl_str,sidstr);
- }
- pstrcat(acl_str, ":");
- if (psd->dacl->aces[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
- pstrcat(acl_str, "D,");
- } else {
- if (psd->dacl->aces[num_aces].access_mask & GENERIC_ALL_ACCESS) {
- pstrcat(acl_str, "F,");
+ if (strncmp(lines[i], "usershare_acl", 13) == 0) {
+ char *acl_str;
+
+ acl_str = resolve_usershare_acl(ctx, lines[i]);
+ if (acl_str) {
+ d_printf("usershare_acl=%s\n",
+ acl_str);
+ }
} else {
- pstrcat(acl_str, "R,");
+ d_printf("%s\n", lines[i]);
}
}
}
- acl_str[strlen(acl_str)-1] = '\0';
-
- if (pi->op == US_INFO_OP) {
- d_printf("[%s]\n", fl->pathname );
- d_printf("path=%s\n", sharepath );
- d_printf("comment=%s\n", comment);
- d_printf("%s\n", acl_str);
- d_printf("guest_ok=%c\n\n", guest_ok ? 'y' : 'n');
- } else if (pi->op == US_LIST_OP) {
- d_printf("%s\n", fl->pathname);
- }
-
+ file_lines_free(lines);
return 0;
}
@@ -545,6 +587,144 @@ static BOOL usershare_name_is_valid(cons
return True;
}
+
+/* Go through and validate the ACL string. Convert names to SID's as
+ * needed. Then run it through parse_usershare_acl to ensure it's valid.
+ */
+static char * usershare_parse_acl_from_arg(void * ctx, const char *arg_acl)
+{
+ char *us_acl;
+ const char *pacl;
+ int num_aces;
+ int i;
+ SEC_DESC *psd = NULL;
+
+ /* Start off the string we'll append to. */
+ us_acl = talloc_strdup(ctx, "");
+
+ pacl = arg_acl;
+ num_aces = 1;
+
+ /* Add the number of ',' characters to get the number of aces. */
+ num_aces += count_chars(pacl,',');
+
+ for (i = 0; i < num_aces; i++) {
+ DOM_SID sid;
+ const char *pcolon = strchr_m(pacl, ':');
+ const char *name;
+
+ if (pcolon == NULL) {
+ d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n",
+ pacl );
+ return NULL;
+ }
+
+ switch(pcolon[1]) {
+ case 'f':
+ case 'F':
+ case 'd':
+ case 'r':
+ case 'R':
+ break;
+ default:
+ d_fprintf(stderr, "net usershare add: malformed acl %s "
+ "(access control must be 'r', 'f', or 'd')\n",
+ pacl );
+ return NULL;
+ }
+
+ if (pcolon[2] != ',' && pcolon[2] != '\0') {
+ d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n",
+ pacl );
+ return NULL;
+ }
+
+ /* Get the name */
+ if ((name = talloc_strndup(ctx, pacl, pcolon - pacl)) == NULL) {
+ d_fprintf(stderr,
+ "net usershare add: memory allocation failure\n");
+ return NULL;
+ }
+ if (!string_to_sid(&sid, name)) {
+ /* Convert to a SID */
+ NTSTATUS ntstatus = net_lookup_sid_from_name(ctx, name, &sid);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ d_fprintf(stderr, "net usershare add: cannot convert name \"%s\" to a SID. %s.",
+ name, get_friendly_nt_error_msg(ntstatus) );
+ if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
+ d_fprintf(stderr, " Maybe smbd is not running.\n");
+ } else {
+ d_fprintf(stderr, "\n");
+ }
+
+ return NULL;
+ }
+ }
+ us_acl = talloc_asprintf_append(us_acl, "%s:%c,", sid_string_static(&sid), pcolon[1]);
+
+ /* Move to the next ACL entry. */
+ if (pcolon[2] == ',') {
+ pacl = &pcolon[3];
+ }
+ }
+
+ /* Remove the last ',' */
+ us_acl[strlen(us_acl)-1] = '\0';
+
+ if (!parse_usershare_acl(ctx, us_acl, &psd)) {
+ d_fprintf(stderr,
+ "net usershare add: malformed share acl %s\n", us_acl);
+ return NULL;
+ }
+
+ return us_acl;
+}
+
+static char * usershare_mkfile_vers2(void *ctx,
+ const char * us_path,
+ const char * us_comment,
+ const char * us_acl,
+ BOOL guest_ok)
+{
+ char * file_img;
+
+ file_img = talloc_strdup(ctx, "#VERSION 2\npath=");
+ file_img = talloc_asprintf_append(file_img,
+ "%s\ncomment=%s\nusershare_acl=%s\nguest_ok=%c\n",
+ us_path, us_comment, us_acl, guest_ok ? 'y' : 'n');
+
+ return file_img;
+}
+
+static char * usershare_mkfile_vers3(void *ctx,
+ const char * us_path,
+ const char * us_comment,
+ const char * us_acl,
+ BOOL guest_ok,
+ const char ** options,
+ int num_options)
+{
+ int i;
+ char *file_img;
+
+ /* More than 20 options is just silly. */
+ if (num_options > 20) {
+ return NULL;
+ }
+
+ file_img = talloc_strdup(ctx, "#VERSION 3\n");
+ file_img = talloc_asprintf_append(file_img,
+ "path=%s\ncomment=%s\nusershare_acl=%s\nguest ok=%s\n",
+ us_path, us_comment, us_acl,
+ guest_ok ? "yes" : "no");
+
+ for (i = 0; i < num_options; ++i) {
+ file_img = talloc_asprintf_append(file_img, "%s\n", options[i]);
+ }
+
+ return file_img;
+}
+
static int net_usershare_add(int argc, const char **argv)
{
TALLOC_CTX *ctx = NULL;
@@ -558,14 +738,12 @@ static int net_usershare_add(int argc, c
const char *arg_acl;
char *us_acl;
char *file_img;
- int num_aces = 0;
- int i;
int tmpfd;
- const char *pacl;
size_t to_write;
uid_t myeuid = geteuid();
BOOL guest_ok = False;
int num_usershares;
+ BOOL full_config = False;
us_comment = "";
arg_acl = "S-1-1-0:R";
@@ -573,7 +751,6 @@ static int net_usershare_add(int argc, c
switch (argc) {
case 0:
case 1:
- default:
return net_usershare_add_usage(argc, argv);
case 2:
sharename = strdup_lower(argv[0]);
@@ -590,6 +767,9 @@ static int net_usershare_add(int argc, c
us_comment = argv[2];
arg_acl = argv[3];
break;
+ default:
+ full_config = True;
+ /* FALLTHRU */
case 5:
sharename = strdup_lower(argv[0]);
us_path = argv[1];
@@ -614,6 +794,14 @@ static int net_usershare_add(int argc, c
return net_usershare_add_usage(argc, argv);
}
break;
+
+ }
+
+ if (full_config && !lp_usershare_allow_full_config()) {
+ d_fprintf(stderr, "net usershare add: full usershare control "
+ "is administratively disabled\n");
+ SAFE_FREE(sharename);
+ return -1;
}
/* Ensure we're under the "usershare max shares" number. Advisory only. */
@@ -674,92 +862,16 @@ static int net_usershare_add(int argc, c
return -1;
}
- /* No validation needed on comment. Now go through and validate the
- acl string. Convert names to SID's as needed. Then run it through
- parse_usershare_acl to ensure it's valid. */
+ /* No validation needed on comment. */
ctx = talloc_init("share_info");
-
- /* Start off the string we'll append to. */
- us_acl = talloc_strdup(ctx, "");
-
- pacl = arg_acl;
- num_aces = 1;
-
- /* Add the number of ',' characters to get the number of aces. */
- num_aces += count_chars(pacl,',');
-
- for (i = 0; i < num_aces; i++) {
- DOM_SID sid;
- const char *pcolon = strchr_m(pacl, ':');
- const char *name;
-
- if (pcolon == NULL) {
- d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n",
- pacl );
- talloc_destroy(ctx);
- SAFE_FREE(sharename);
- return -1;
- }
-
- switch(pcolon[1]) {
- case 'f':
- case 'F':
- case 'd':
- case 'r':
- case 'R':
- break;
- default:
- d_fprintf(stderr, "net usershare add: malformed acl %s "
- "(access control must be 'r', 'f', or 'd')\n",
- pacl );
- talloc_destroy(ctx);
- SAFE_FREE(sharename);
- return -1;
- }
-
- if (pcolon[2] != ',' && pcolon[2] != '\0') {
- d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n",
- pacl );
- talloc_destroy(ctx);
- SAFE_FREE(sharename);
- return -1;
- }
-
- /* Get the name */
- if ((name = talloc_strndup(ctx, pacl, pcolon - pacl)) == NULL) {
- d_fprintf(stderr, "talloc_strndup failed\n");
- talloc_destroy(ctx);
- SAFE_FREE(sharename);
- return -1;
- }
- if (!string_to_sid(&sid, name)) {
- /* Convert to a SID */
- NTSTATUS ntstatus = net_lookup_sid_from_name(ctx, name, &sid);
- if (!NT_STATUS_IS_OK(ntstatus)) {
- d_fprintf(stderr, "net usershare add: cannot convert name \"%s\" to a SID. %s.",
- name, get_friendly_nt_error_msg(ntstatus) );
- if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
- d_fprintf(stderr, " Maybe smbd is not running.\n");
- } else {
- d_fprintf(stderr, "\n");
- }
- talloc_destroy(ctx);
- SAFE_FREE(sharename);
- return -1;
- }
- }
- us_acl = talloc_asprintf_append(us_acl, "%s:%c,", sid_string_static(&sid), pcolon[1]);
-
- /* Move to the next ACL entry. */
- if (pcolon[2] == ',') {
- pacl = &pcolon[3];
- }
+ us_acl = usershare_parse_acl_from_arg(ctx, arg_acl);
+ if (us_acl == NULL) {
+ talloc_destroy(ctx);
+ SAFE_FREE(sharename);
+ return -1;
}
- /* Remove the last ',' */
- us_acl[strlen(us_acl)-1] = '\0';
-
if (guest_ok && !lp_usershare_allow_guests()) {
d_fprintf(stderr, "net usershare add: guest_ok=y requested "
"but the \"usershare allow guests\" parameter is not enabled "
@@ -815,9 +927,14 @@ static int net_usershare_add(int argc, c
}
/* Create the in-memory image of the file. */
- file_img = talloc_strdup(ctx, "#VERSION 2\npath=");
- file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\nguest_ok=%c\n",
- us_path, us_comment, us_acl, guest_ok ? 'y' : 'n');
+
+ if (full_config) {
+ file_img = usershare_mkfile_vers3(ctx, us_path, us_comment,
+ us_acl, guest_ok, &argv[5], argc - 5);
+ } else {
+ file_img = usershare_mkfile_vers2(ctx, us_path, us_comment,
+ us_acl, guest_ok);
+ }
to_write = strlen(file_img);