Two diffs to add paramater self-checking
David Collier-Brown
davecb at canada.sun.com
Fri Jul 12 11:46:58 GMT 2002
These are for param/loadparm.c and utils/testparm.c, respectively,
to put in the self-checking that's been languishing...
After these go in, I'll start tracking smb.conf changes
again, so I can support them, any you can delete
samba-patches 298 (Self-check patches for 2.2.0 alpha 3,
11 Apr 2001)
--dave
--
David Collier-Brown, | Always do right. This will gratify
Performance & Engineering | some people and astonish the rest.
Americas Customer Engineering, | -- Mark Twain
(905) 415-2849 | davecb at canada.sun.com
-------------- next part --------------
--- loadparm.c 2002/07/11 00:46:17 1.1
+++ loadparm.c 2002/07/11 23:54:35
@@ -557,6 +557,9 @@
static BOOL handle_vfs_object(char *pszParmValue, char **ptr);
static BOOL handle_source_env(char *pszParmValue, char **ptr);
static BOOL handle_netbios_name(char *pszParmValue, char **ptr);
+static BOOL handle_netbios_aliases(char *pszParmValue,char **ptr);
+static BOOL handle_password_server(char *pszParmValue, char **ptr);
+static BOOL validate_netbios_name(char *pszParmValue);
static BOOL handle_winbind_uid(char *pszParmValue, char **ptr);
static BOOL handle_winbind_gid(char *pszParmValue, char **ptr);
static BOOL handle_wins_server_list(char *pszParmValue, char **ptr);
@@ -1813,6 +1816,7 @@
service * pserviceDest);
static void copy_service(service * pserviceDest,
service * pserviceSource, BOOL *pcopymapDest);
+static BOOL globals_ok(void);
static BOOL service_ok(int iService);
static BOOL do_parameter(char *pszParmName, char *pszParmValue);
static BOOL do_section(char *pszSectionName);
@@ -2182,52 +2186,245 @@
}
}
+
+
/***************************************************************************
-Check a service for consistency. Return False if the service is in any way
-incomplete or faulty, else True.
-***************************************************************************/
-static BOOL service_ok(int iService)
-{
- BOOL bRetval;
+Check globals for consistency. Return False if something fatal will happen.
+The messages use ERROR WARNING and NOTICE the same way service_ok does.
+This replaces do_global_checks in utils/testparm.c, and should be called at
+least once, and possibly each time the smb.conf file is reread.
+***************************************************************************/
+static BOOL globals_ok(void)
+{
+ BOOL bRetval = True;
+ SMB_STRUCT_STAT st;
+ char *wins;
+ static BOOL filesChecked = False;
+
+ /* Look for inconstancies in roughly decreasing order of severity, */
+
+ /* Check for both wins server and wins support, make sure server wins. */
+ /* DCB: The data structure changes in 2.0.7, requiring this check. */
+ wins = Globals.szWINSserver;
+ if (Globals.bWINSsupport == True && wins != NULL
+ && ! (wins[0] == '\0' || strwicmp(wins, "127.0.0.1") == 0)) {
+ DEBUG(0,( "ERROR: both wins server = yes and wins support == yes, "
+ "using wins server \"%s\".\n", wins));
+ Globals.bWINSsupport = False;
+ }
+
+ /* Make sure we have a lock directory, but only once. */
+ if (filesChecked == False) {
+ if (!directory_exist(Globals.szLockDir, &st)) {
+ DEBUG(0,("ERROR: lock directory \"%s\" does not exist\n",
+ Globals.szLockDir));
+ bRetval = False;
+ }
+ else if ((st.st_mode & 0777) != 0755) {
+ DEBUG(0,("WARNING: lock directory \"%s\" should have "
+ "permissions 0755 for browsing and locks to work\n",
+ Globals.szLockDir));
+ }
+ filesChecked = True;
+ }
+
+ /* Security = (server or domain) requires password server to be set. */
+ if ((Globals.szPasswordServer == NULL || Globals.szPasswordServer[0] == '\0'
+)
+ && (Globals.security == SEC_SERVER || Globals.security ==
+SEC_DOMAIN)) {
+ DEBUG(0,("ERROR: security = server and security = domain "
+ "both require a password server.\n"));
+ bRetval = False;
+ }
+
+ /* Password server should be a netbios name. */
+ if (Globals.szPasswordServer != NULL
+ && (strchr(Globals.szPasswordServer,'.') != NULL
+ || strlen(Globals.szPasswordServer) >= 15)) {
+ DEBUG(0,("ERROR: password server \"%s\" is not a legal "
+ "NetBIOS name, logons will fail.\n",
+ Globals.szPasswordServer));
+ bRetval = False;
+ }
+
+ /* Check unix password sync prerequisites. */
+ if (Globals.bUnixPasswdSync) {
+ if (Globals.security != SEC_USER) {
+ DEBUG(0,("WARNING: unix password sync = yes requires "
+ "security = user.\n"));
+ }
+ if (Globals.bEncryptPasswords == False) {
+ DEBUG(0,("WARNING: unix password sync = yes requires "
+ "encrypt passwords = yes.\n"));
+ }
+ }
+
+ /* Be sure update encrypted is done with NON-encrypted passwords. */
+ if (Globals.bUpdateEncrypt && Globals.bEncryptPasswords == False) {
+ DEBUG(0,("WARNING: update encrypted = yes requires encrypt "
+ "passwords = no.\n"));
+ }
- bRetval = True;
- if (ServicePtrs[iService]->szService[0] == '\0')
- {
- DEBUG(0,
- ("The following message indicates an internal error:\n"));
- DEBUG(0, ("No service name in service entry.\n"));
- bRetval = False;
- }
+ /* Er, should unix password sync be automatic if smb password file exists?
+*/
- /* The [printers] entry MUST be printable. I'm all for flexibility, but */
- /* I can't see why you'd want a non-printable printer service... */
- if (strwicmp(ServicePtrs[iService]->szService, PRINTERS_NAME) == 0) {
- if (!ServicePtrs[iService]->bPrint_ok) {
- DEBUG(0,
- ("WARNING: [%s] service MUST be printable!\n",
- ServicePtrs[iService]->szService));
- ServicePtrs[iService]->bPrint_ok = True;
- }
- /* [printers] service must also be non-browsable. */
- if (ServicePtrs[iService]->bBrowseable)
- ServicePtrs[iService]->bBrowseable = False;
- }
+ /* If unix password sync, check the prerequisites.*/
+ if (Globals.bUnixPasswdSync) {
+ /* See if the program is executable. */
+ { pstring passwd_prog;
+ char *p;
+ pstrcpy(passwd_prog, Globals.szPasswdProgram);
+ if ((p = strchr(passwd_prog, ' ')) != NULL) {
+ *p = '\0';
+ }
+ if (access(passwd_prog, X_OK) == -1) {
+ DEBUG(0,("WARNING: the unix password sync program \"%s\" "
+ "can't be executed, errno was %d (\"%s\").\n",
+ Globals.szPasswdProgram,
+ errno, strerror(errno)));
+ }
+ }
- if (ServicePtrs[iService]->szPath[0] == '\0' &&
- strwicmp(ServicePtrs[iService]->szService, HOMES_NAME) != 0)
- {
- DEBUG(0,
- ("No path in service %s - using %s\n",
- ServicePtrs[iService]->szService, tmpdir()));
- string_set(&ServicePtrs[iService]->szPath, tmpdir());
- }
+ /* And the passwd chat isn't expecting the old password. */
+ if (strstr(Globals.szPasswdChat, "%o") != 0) {
+ DEBUG(0,("WARNING: the 'passwd chat' script [%s] depends on "
+ "getting the old password via the %%o substitution. With "
+ "encrypted passwords this is not possible.\n",
+ Globals.szPasswdChat));
+ }
+
+ }
+
+ /* Check for announcing as something other than NT, which can */
+ /* interefere with serving browse lists. */
+ if (Globals.announce_as != ANNOUNCE_AS_NT_SERVER) {
+ DEBUG(0,( "WARNING: announce as not set to \"NT\", this may "
+ "interfere with browsing.\n"));
+ }
+ return True;
+}
- /* If a service is flagged unavailable, log the fact at level 0. */
- if (!ServicePtrs[iService]->bAvailable)
- DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
- ServicePtrs[iService]->szService));
- return (bRetval);
+/***************************************************************************
+Check a service for consistency. Return False if the service is in any way
+incomplete or faulty, else True.
+***************************************************************************/
+static BOOL service_ok(int iService)
+{
+ BOOL bRetval = True;
+ struct stat buf;
+ service *s = ServicePtrs[iService];
+
+ /* Look for inconstancies in roughly decreasing order of severity, */
+ /* Test for a missing service name. */
+ if (s->szService == NULL || s->szService[0] == '\0') {
+ DEBUG(0,( "The following message indicates an internal error:\n"));
+ DEBUGADD(0,( "ERROR: No service name in service entry.\n"));
+ bRetval = False;
+ }
+
+ /* Test for path not pointing to a dir (other tests follow). */
+ if (s->szPath != NULL && s->szPath[0] != '\0') {
+ if (stat(s->szPath,&buf) == -1) {
+ DEBUG(0,("ERROR: can't stat path %s in service [%s].\n",
+ s->szPath, s->szService));
+ DEBUGADD(0,("errno = %d (%s).\n", errno, strerror(errno)));
+ }
+ else if ((buf.st_mode & S_IFDIR) != S_IFDIR) {
+ DEBUG(0,("ERROR: Path %s in service [%s] isn't a directory.\n",
+ s->szPath, s->szService));
+ }
+ }
+
+ /* Contradictions in terms: */
+ /* The [printers] entry MUST be printable. I'm all for flexibility, but */
+ /* I can't see why you'd want a non-printable printer service... */
+ if (strwicmp(s->szService,PRINTERS_NAME) == 0) {
+ if (!s->bPrint_ok) {
+ DEBUG(0,( "ERROR: printer service [%s] MUST be printable!\n",
+ s->szService));
+ s->bPrint_ok = True;
+ }
+ }
+
+ /* Things that are inherently dangerous: WARNINGs. */
+
+ /* Look for map archive forced to fail by bad create mask. */
+ /* Ditto map system, map hidden. */
+ if (s->bMap_archive == True && (s->iCreate_mask & 0100) ==
+0) {
+ DEBUG(0,( "WARNING: map archive = yes in share [%s], but create "
+ "mask doesn't allow setting archive bit (100 octal).\n",
+ s->szService));
+ }
+
+ if (s->bMap_system == True && (s->iCreate_mask & 0010) ==
+0) {
+ DEBUG(0,( "WARNING: map system = yes in share [%s], but create "
+ "mask doesn't allow setting system bit (010 octal).\n",
+ s->szService));
+ }
+
+ if (s->bMap_hidden == True && (s->iCreate_mask & 0001) ==
+0) {
+ DEBUG(0,( "WARNING: map hidden = yes in share [%s], but create "
+ "mask doesn't allow setting hidden bit (001 octal).\n",
+ s->szService));
+ }
+
+ /* And see if force create mode sets any of the same three bits */
+ if ((s->iCreate_force_mode & 0100) != 0) {
+ DEBUG(0,( "WARNING: force create mode forces archive bit on "
+ "on all files in share [%s].\n",
+ s->szService));
+ }
+ if ((s->iCreate_force_mode & 0010) != 0) {
+ DEBUG(0,( "WARNING: force create mode forces system bit on "
+ "on all files in share [%s].\n",
+ s->szService));
+ }
+ if ((s->iCreate_force_mode & 0001) != 0) {
+ DEBUG(0,( "WARNING: force create mode forces hidden bit on "
+ "on all file in share [%s].\n",
+ s->szService));
+ }
+ /* Implausible overrides and missing prerequisites: WARNINGs. */
+ /* If a service is flagged unavailable, log the fact at level 0. */
+ if (!s->bAvailable) {
+ DEBUG(1,( "NOTICE: Service [%s] is marked available = no.\n",
+ s->szService));
+ }
+
+ /* If it's unbrowsable but we're serving browse lists, log that too. */
+ if (s->bBrowseable == False && Globals.bBrowseList == True
+ && strwicmp(s->szService,HOMES_NAME) != 0) {
+ DEBUG(0,( "NOTICE: Service [%s] is unbrowsable, but browse "
+ "lists are being served.\n", s->szService));
+ }
+
+ /* If we're syncing always, we need strict sync on too. */
+ if (s->bSyncAlways == True && s->bStrictSync == False) {
+ DEBUG(0,("NOTICE: In service [%s], sync always = yes, which requires "
+ "strict sync = yes.\n", s->szService));
+ }
+
+ /* We ned oplocks for level2 oplocks. */
+ if (s->bLevel2OpLocks == True && s->bOpLocks == False) {
+ DEBUG(0,("NOTICE: In service [%s], level 2 oplocks = yes, which "
+ "requires oplocks = yes as well.\n", s->szService));
+ }
+
+ /* Depending on defaults for proper execution: NOTICEs.*/
+ /* Test for missing path, substitute the default if unset. */
+ if (s->szPath != NULL && s->szPath[0] == '\0'
+ && strwicmp(s->szService,HOMES_NAME) != 0) {
+ DEBUG(0,("NOTICE: No path in service [%s], using %s\n",
+ s->szService,tmpdir()));
+ string_set(&s->szPath,tmpdir());
+ }
+
+ return (bRetval);
}
static struct file_lists
@@ -2318,6 +2515,9 @@
{
pstring netbios_name;
+ if (validate_netbios_name(pszParmValue) == False)
+ return False;
+
pstrcpy(netbios_name, pszParmValue);
standard_sub_basic(netbios_name);
@@ -2338,6 +2538,109 @@
}
/***************************************************************************
+handle_netbios_aliases -- validate and insert multiple netbios-name
+parameters. It's a pstring global, with the DOS_STRING attribute.
+***************************************************************************/
+static BOOL handle_netbios_aliases(char *pszParmValue, char **parm_ptr) {
+ char *p;
+ pstring buf;
+
+ *buf = '\0';
+ for (p=strtok(pszParmValue, " \t"); p != NULL; p=strtok(NULL," \t")) {
+ if (validate_netbios_name(p) == False)
+ return False;
+ pstrcat(buf,p);
+ pstrcat(buf," ");
+ }
+ buf[MIN(strlen(buf)-1,sizeof(buf))] = '\0';
+
+ /* I've treated it here as an uppercase pstring. P_USTRING --davecb */
+ string_set(parm_ptr,buf);
+ unix_to_dos(*(char **)parm_ptr);
+ strupper(*(char **)parm_ptr);
+ return True;
+}
+
+/***************************************************************************
+handle_password_server -- validate and insert multiple netbios-name
+parameters. It's a pstring global.
+***************************************************************************/
+static BOOL handle_password_server(char *pszParmValue, char **parm_ptr) {
+ char *p;
+ pstring buf;
+
+ *buf = '\0';
+ if (Globals.security != SEC_SERVER && Globals.security !=
+SEC_DOMAIN) {
+ DEBUG(0,("WARNING: password server set to \"%s\", ",pszParmValue));
+ DEBUGADD(0,("but security is neither server nor domain.\n"
+ "password server value ignored\n"));
+ return True;
+ }
+
+ /* a "*" by itself means search for Primary or Backup Domain controllers */
+ if (Globals.security == SEC_DOMAIN && *pszParmValue == '*') {
+ pstrcpy(buf,pszParmValue);
+ }
+ else {
+ for (p=strtok(pszParmValue, " \t"); p != NULL; p=strtok(NULL," \t")) {
+ if (validate_netbios_name(p) == False)
+ return False;
+ pstrcat(buf,p);
+ pstrcat(buf," ");
+ }
+ buf[MIN(strlen(buf)-1,sizeof(buf))] = '\0';
+ }
+
+ /* I've treated it here as an uppercase pstring. P_USTRING --davecb */
+ string_set(parm_ptr,buf);
+ unix_to_dos(*(char **)parm_ptr);
+ strupper(*(char **)parm_ptr);
+ return True;
+}
+
+/**************************************************************************
+validate a single netbios-name
+**************************************************************************/
+static char *legalNetbiosChars = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
+
+static BOOL validate_netbios_name(char *pszParmValue) {
+ int len, i;
+ char *p;
+
+ /* Alternative 1a: manage FQDN by removing domain */
+ if ((p = strchr(pszParmValue, '.')) != NULL) {
+ DEBUG(0,("WARNING: netbios name \"%s\" contained a dot,\n",
+ pszParmValue));
+ *p = '\0';
+ DEBUGADD(0,("which is only legal in DNS domain names.\n"));
+ DEBUGADD(0,("Name has been truncated to \"%s\".\n",
+ pszParmValue));
+ }
+
+ /* Alternative 1b: manage over-long name by truncating it */
+ len = strlen(pszParmValue);
+ if (len > 15) {
+ pszParmValue[15] = '\0';
+ len = 15;
+ DEBUG(0,("netbios name is longer than 15 characters, "
+ "and has been truncated to \"%s\".\n", pszParmValue));
+ }
+
+ /* Alternative 2: fail non-alphanumerics. */
+ if ((i = strspn(pszParmValue,legalNetbiosChars)) < len) {
+ DEBUG(0,("netbios name \"%s\" contains non-alphanumeric character "
+ "\"%c\", and cannot be set.\n", pszParmValue,
+ pszParmValue[i]));
+ return False;
+ }
+ return True;
+}
+
+
+
+/***************************************************************************
Do the work of sourcing in environment variable/value pairs.
***************************************************************************/
@@ -3495,6 +3798,8 @@
string_set(&Globals.szWINSserver, "127.0.0.1");
}
+ /* If we get here, check globals. */
+ bRetval = globals_ok();
return (bRetval);
}
-------------- next part --------------
--- testparm.c.old Fri Jul 12 14:07:35 2002
+++ testparm.c Fri Jul 12 14:07:43 2002
@@ -42,11 +42,133 @@
extern FILE *dbf;
/***********************************************
-Here we formerly did a set of 'hard coded' checks for bad
-configuration settings, called do_global_checks(void).
-This is now done in loadparm, in globals_ok() -- Dave C-B
+ Here we do a set of 'hard coded' checks for bad
+ configuration settings.
************************************************/
+static int do_global_checks(void)
+{
+ int ret = 0;
+ SMB_STRUCT_STAT st;
+
+ if (lp_security() == SEC_DOMAIN && !lp_encrypted_passwords()) {
+ printf("ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must also be set to 'true'.\n");
+ ret = 1;
+ }
+
+ if (lp_wins_support() && *lp_wins_server()) {
+ printf("ERROR: both 'wins support = true' and 'wins server = <server>' \
+cannot be set in the smb.conf file. nmbd will abort with this setting.\n");
+ ret = 1;
+ }
+
+ if (!directory_exist(lp_lockdir(), &st)) {
+ printf("ERROR: lock directory %s does not exist\n",
+ lp_lockdir());
+ ret = 1;
+ } else if ((st.st_mode & 0777) != 0755) {
+ printf("WARNING: lock directory %s should have permissions 0755 for browsing to work\n",
+ lp_lockdir());
+ ret = 1;
+ }
+
+ if (!directory_exist(lp_piddir(), &st)) {
+ printf("ERROR: pid directory %s does not exist\n",
+ lp_piddir());
+ ret = 1;
+ }
+
+ /*
+ * Password server sanity checks.
+ */
+
+ if((lp_security() == SEC_SERVER || lp_security() == SEC_DOMAIN) && !lp_passwordserver()) {
+ pstring sec_setting;
+ if(lp_security() == SEC_SERVER)
+ pstrcpy(sec_setting, "server");
+ else if(lp_security() == SEC_DOMAIN)
+ pstrcpy(sec_setting, "domain");
+
+ printf("ERROR: The setting 'security=%s' requires the 'password server' parameter be set \
+to a valid password server.\n", sec_setting );
+ ret = 1;
+ }
+
+ /*
+ * Password chat sanity checks.
+ */
+
+ if(lp_security() == SEC_USER && lp_unix_password_sync()) {
+
+ /*
+ * Check that we have a valid lp_passwd_program() if not using pam.
+ */
+
+#ifdef WITH_PAM
+ if (!lp_pam_password_change()) {
+#endif
+
+ if(lp_passwd_program() == NULL) {
+ printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd program' \
+parameter.\n" );
+ ret = 1;
+ } else {
+ pstring passwd_prog;
+ pstring truncated_prog;
+ char *p;
+
+ pstrcpy( passwd_prog, lp_passwd_program());
+ p = passwd_prog;
+ *truncated_prog = '\0';
+ next_token(&p, truncated_prog, NULL, sizeof(pstring));
+
+ if(access(truncated_prog, F_OK) == -1) {
+ printf("ERROR: the 'unix password sync' parameter is set and the 'passwd program' (%s) \
+cannot be executed (error was %s).\n", truncated_prog, strerror(errno) );
+ ret = 1;
+ }
+ }
+
+#ifdef WITH_PAM
+ }
+#endif
+
+ if(lp_passwd_chat() == NULL) {
+ printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd chat' \
+parameter.\n");
+ ret = 1;
+ }
+
+ /*
+ * Check that we have a valid script and that it hasn't
+ * been written to expect the old password.
+ */
+
+ if(lp_encrypted_passwords()) {
+ if(strstr( lp_passwd_chat(), "%o")!=NULL) {
+ printf("ERROR: the 'passwd chat' script [%s] expects to use the old plaintext password \
+via the %%o substitution. With encrypted passwords this is not possible.\n", lp_passwd_chat() );
+ ret = 1;
+ }
+ }
+ }
+
+ if (lp_status(-1) && lp_max_smbd_processes()) {
+ printf("ERROR: the 'max smbd processes' parameter is set and the 'status' parameter is set to 'no'.\n");
+ ret = 1;
+ }
+
+ if (strlen(lp_winbind_separator()) != 1) {
+ printf("ERROR: the 'winbind separator' parameter must be a single character.\n");
+ ret = 1;
+ }
+
+ if (*lp_winbind_separator() == '+') {
+ printf("'winbind separator = +' might cause problems with group membership.\n");
+ }
+
+ return ret;
+}
static void usage(char *pname)
{
@@ -124,6 +246,8 @@
}
printf("Loaded services file OK.\n");
+
+ ret = do_global_checks();
for (s=0;s<1000;s++) {
if (VALID_SNUM(s))
More information about the samba-technical
mailing list