Fix bug 6157
[ira/wip.git] / source3 / lib / popt_common.c
index 9a5a11202255e77aada34e8c29e3d47ae90cf887..e14477c9799b31c036ec4f81971fd9a9972d6f4a 100644 (file)
@@ -4,10 +4,11 @@
 
    Copyright (C) Tim Potter 2001,2002
    Copyright (C) Jelmer Vernooij 2002,2003
+   Copyright (C) James Peach 2006
 
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +17,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
  *             -i,--scope
  */
 
-extern pstring user_socket_options;
-extern BOOL AllowDebugChange;
+extern bool AllowDebugChange;
+extern bool override_logfile;
 
-struct user_auth_info cmdline_auth_info;
-
-static void popt_common_callback(poptContext con, 
-                          enum poptCallbackReason reason,
-                          const struct poptOption *opt,
-                          const char *arg, const void *data)
+static void set_logfile(poptContext con, const char * arg)
 {
-       pstring logfile;
+
+       char *lfile = NULL;
        const char *pname;
-       
+
        /* Find out basename of current program */
        pname = strrchr_m(poptGetInvocationName(con),'/');
 
        if (!pname)
                pname = poptGetInvocationName(con);
-       else 
+       else
                pname++;
 
+       if (asprintf(&lfile, "%s/log.%s", arg, pname) < 0) {
+               return;
+       }
+       lp_set_logfile(lfile);
+       SAFE_FREE(lfile);
+}
+
+static bool PrintSambaVersionString;
+
+static void popt_common_callback(poptContext con,
+                          enum poptCallbackReason reason,
+                          const struct poptOption *opt,
+                          const char *arg, const void *data)
+{
+
        if (reason == POPT_CALLBACK_REASON_PRE) {
-               pstr_sprintf(logfile, "%s/log.%s", dyn_LOGFILEBASE, pname);
-               lp_set_logfile(logfile);
+               set_logfile(con, get_dyn_LOGFILEBASE());
+               return;
+       }
+
+       if (reason == POPT_CALLBACK_REASON_POST) {
+
+               if (PrintSambaVersionString) {
+                       printf( "Version %s\n", samba_version_string());
+                       exit(0);
+               }
+
+               if (is_default_dyn_CONFIGFILE()) {
+                       if(getenv("SMB_CONF_PATH")) {
+                               set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH"));
+                       }
+               }
+
+               /* Further 'every Samba program must do this' hooks here. */
                return;
        }
 
@@ -69,19 +96,18 @@ static void popt_common_callback(poptContext con,
                break;
 
        case 'V':
-               printf( "Version %s\n", SAMBA_VERSION_STRING);
-               exit(0);
+               PrintSambaVersionString = True;
                break;
 
        case 'O':
                if (arg) {
-                       pstrcpy(user_socket_options,arg);
+                       lp_do_parameter(-1, "socket options", arg);
                }
                break;
 
        case 's':
                if (arg) {
-                       pstrcpy(dyn_CONFIGFILE, arg);
+                       set_dyn_CONFIGFILE(arg);
                }
                break;
 
@@ -93,8 +119,9 @@ static void popt_common_callback(poptContext con,
 
        case 'l':
                if (arg) {
-                       pstr_sprintf(logfile, "%s/log.%s", arg, pname);
-                       lp_set_logfile(logfile);
+                       set_logfile(con, arg);
+                       override_logfile = True;
+                       set_dyn_LOGFILEBASE(arg);
                }
                break;
 
@@ -113,7 +140,7 @@ static void popt_common_callback(poptContext con,
 }
 
 struct poptOption popt_common_connection[] = {
-       { NULL, 0, POPT_ARG_CALLBACK, popt_common_callback },
+       { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
        { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
          "SOCKETOPTIONS" },
        { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
@@ -124,42 +151,210 @@ struct poptOption popt_common_connection[] = {
 };
 
 struct poptOption popt_common_samba[] = {
-       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PREpopt_common_callback },
+       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
        { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
-       { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" },
-       { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Basename for log/debug files", "LOGFILEBASE" },
+       { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
+       { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" },
        { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
        POPT_TABLEEND
 };
 
+struct poptOption popt_common_configfile[] = {
+       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
+       { "configfile", 0, POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
+       POPT_TABLEEND
+};
+
 struct poptOption popt_common_version[] = {
-       { NULL, 0, POPT_ARG_CALLBACKpopt_common_callback },
+       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback },
        { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
        POPT_TABLEEND
 };
 
+struct poptOption popt_common_debuglevel[] = {
+       { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
+       { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
+       POPT_TABLEEND
+};
 
 
+/* Handle command line options:
+ *             --sbindir
+ *             --bindir
+ *             --swatdir
+ *             --lmhostsfile
+ *             --libdir
+ *             --modulesdir
+ *             --shlibext
+ *             --lockdir
+ *             --statedir
+ *             --cachedir
+ *             --piddir
+ *             --smb-passwd-file
+ *             --private-dir
+ */
+
+enum dyn_item{
+       DYN_SBINDIR = 1,
+       DYN_BINDIR,
+       DYN_SWATDIR,
+       DYN_LMHOSTSFILE,
+       DYN_LIBDIR,
+       DYN_MODULESDIR,
+       DYN_SHLIBEXT,
+       DYN_LOCKDIR,
+       DYN_STATEDIR,
+       DYN_CACHEDIR,
+       DYN_PIDDIR,
+       DYN_SMB_PASSWD_FILE,
+       DYN_PRIVATE_DIR,
+};
+
+
+static void popt_dynconfig_callback(poptContext con,
+                          enum poptCallbackReason reason,
+                          const struct poptOption *opt,
+                          const char *arg, const void *data)
+{
+
+       switch (opt->val) {
+       case DYN_SBINDIR:
+               if (arg) {
+                       set_dyn_SBINDIR(arg);
+               }
+               break;
+
+       case DYN_BINDIR:
+               if (arg) {
+                       set_dyn_BINDIR(arg);
+               }
+               break;
+
+       case DYN_SWATDIR:
+               if (arg) {
+                       set_dyn_SWATDIR(arg);
+               }
+               break;
+
+       case DYN_LMHOSTSFILE:
+               if (arg) {
+                       set_dyn_LMHOSTSFILE(arg);
+               }
+               break;
+
+       case DYN_LIBDIR:
+               if (arg) {
+                       set_dyn_LIBDIR(arg);
+               }
+               break;
+
+       case DYN_MODULESDIR:
+               if (arg) {
+                       set_dyn_MODULESDIR(arg);
+               }
+               break;
+
+       case DYN_SHLIBEXT:
+               if (arg) {
+                       set_dyn_SHLIBEXT(arg);
+               }
+               break;
+
+       case DYN_LOCKDIR:
+               if (arg) {
+                       set_dyn_LOCKDIR(arg);
+               }
+               break;
+
+       case DYN_STATEDIR:
+               if (arg) {
+                       set_dyn_STATEDIR(arg);
+               }
+               break;
+
+       case DYN_CACHEDIR:
+               if (arg) {
+                       set_dyn_CACHEDIR(arg);
+               }
+               break;
+
+       case DYN_PIDDIR:
+               if (arg) {
+                       set_dyn_PIDDIR(arg);
+               }
+               break;
+
+       case DYN_SMB_PASSWD_FILE:
+               if (arg) {
+                       set_dyn_SMB_PASSWD_FILE(arg);
+               }
+               break;
+
+       case DYN_PRIVATE_DIR:
+               if (arg) {
+                       set_dyn_PRIVATE_DIR(arg);
+               }
+               break;
+
+       }
+}
+
+const struct poptOption popt_common_dynconfig[] = {
+
+       { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_dynconfig_callback },
+
+       { "sbindir", '\0' , POPT_ARG_STRING, NULL, DYN_SBINDIR,
+           "Path to sbin directory", "SBINDIR" },
+       { "bindir", '\0' , POPT_ARG_STRING, NULL, DYN_BINDIR,
+           "Path to bin directory", "BINDIR" },
+       { "swatdir", '\0' , POPT_ARG_STRING, NULL, DYN_SWATDIR,
+           "Path to SWAT installation directory", "SWATDIR" },
+       { "lmhostsfile", '\0' , POPT_ARG_STRING, NULL, DYN_LMHOSTSFILE,
+           "Path to lmhosts file", "LMHOSTSFILE" },
+       { "libdir", '\0' , POPT_ARG_STRING, NULL, DYN_LIBDIR,
+           "Path to shared library directory", "LIBDIR" },
+       { "modulesdir", '\0' , POPT_ARG_STRING, NULL, DYN_MODULESDIR,
+           "Path to shared modules directory", "MODULESDIR" },
+       { "shlibext", '\0' , POPT_ARG_STRING, NULL, DYN_SHLIBEXT,
+           "Shared library extension", "SHLIBEXT" },
+       { "lockdir", '\0' , POPT_ARG_STRING, NULL, DYN_LOCKDIR,
+           "Path to lock file directory", "LOCKDIR" },
+       { "statedir", '\0' , POPT_ARG_STRING, NULL, DYN_STATEDIR,
+           "Path to persistent state file directory", "STATEDIR" },
+       { "cachedir", '\0' , POPT_ARG_STRING, NULL, DYN_CACHEDIR,
+           "Path to temporary cache file directory", "CACHEDIR" },
+       { "piddir", '\0' , POPT_ARG_STRING, NULL, DYN_PIDDIR,
+           "Path to PID file directory", "PIDDIR" },
+       { "smb-passwd-file", '\0' , POPT_ARG_STRING, NULL, DYN_SMB_PASSWD_FILE,
+           "Path to smbpasswd file", "SMB_PASSWD_FILE" },
+       { "private-dir", '\0' , POPT_ARG_STRING, NULL, DYN_PRIVATE_DIR,
+           "Path to private data directory", "PRIVATE_DIR" },
+
+       POPT_TABLEEND
+};
+
 /****************************************************************************
  * get a password from a a file or file descriptor
  * exit on failure
  * ****************************************************************************/
-static void get_password_file(struct user_auth_info *a)
+
+static void get_password_file(struct user_auth_info *auth_info)
 {
        int fd = -1;
        char *p;
-       BOOL close_it = False;
-       pstring spec;
+       bool close_it = False;
+       char *spec = NULL;
        char pass[128];
 
        if ((p = getenv("PASSWD_FD")) != NULL) {
-               pstrcpy(spec, "descriptor ");
-               pstrcat(spec, p);
+               if (asprintf(&spec, "descriptor %s", p) < 0) {
+                       return;
+               }
                sscanf(p, "%d", &fd);
-               close_it = False;
+               close_it = false;
        } else if ((p = getenv("PASSWD_FILE")) != NULL) {
                fd = sys_open(p, O_RDONLY, 0);
-               pstrcpy(spec, p);
+               spec = SMB_STRDUP(p);
                if (fd < 0) {
                        fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
                                        spec, strerror(errno));
@@ -168,6 +363,11 @@ static void get_password_file(struct user_auth_info *a)
                close_it = True;
        }
 
+       if (fd < 0) {
+               fprintf(stderr, "fd = %d, < 0\n", fd);
+               exit(1);
+       }
+
        for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
                p && p - pass < sizeof(pass);) {
                switch (read(fd, p, 1)) {
@@ -184,21 +384,27 @@ static void get_password_file(struct user_auth_info *a)
                        } else {
                                fprintf(stderr, "Error reading password from file %s: %s\n",
                                                spec, "empty password\n");
+                               SAFE_FREE(spec);
                                exit(1);
                        }
 
                default:
                        fprintf(stderr, "Error reading password from file %s: %s\n",
                                        spec, strerror(errno));
+                       SAFE_FREE(spec);
                        exit(1);
                }
        }
-       pstrcpy(a->password, pass);
-       if (close_it)
+       SAFE_FREE(spec);
+
+       set_cmdline_auth_info_password(auth_info, pass);
+       if (close_it) {
                close(fd);
+       }
 }
 
-static void get_credentials_file(const char *file, struct user_auth_info *info) 
+static void get_credentials_file(struct user_auth_info *auth_info,
+                                const char *file)
 {
        XFILE *auth;
        fstring buf;
@@ -240,15 +446,13 @@ static void get_credentials_file(const char *file, struct user_auth_info *info)
                while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
                        val++;
 
-               if (strwicmp("password", param) == 0)
-               {
-                       pstrcpy(info->password, val);
-                       info->got_pass = True;
-               }
-               else if (strwicmp("username", param) == 0)
-                       pstrcpy(info->username, val);
-               else if (strwicmp("domain", param) == 0)
+               if (strwicmp("password", param) == 0) {
+                       set_cmdline_auth_info_password(auth_info, val);
+               } else if (strwicmp("username", param) == 0) {
+                       set_cmdline_auth_info_username(auth_info, val);
+               } else if (strwicmp("domain", param) == 0) {
                        set_global_myworkgroup(val);
+               }
                memset(buf, 0, sizeof(buf));
        }
        x_fclose(auth);
@@ -261,43 +465,51 @@ static void get_credentials_file(const char *file, struct user_auth_info *info)
  *             -N,--no-pass
  *             -S,--signing
  *              -P --machine-pass
+ *             -e --encrypt
  */
 
 
-static void popt_common_credentials_callback(poptContext con, 
+static void popt_common_credentials_callback(poptContext con,
                                        enum poptCallbackReason reason,
                                        const struct poptOption *opt,
                                        const char *arg, const void *data)
 {
+       struct user_auth_info *auth_info = talloc_get_type_abort(
+               *((const char **)data), struct user_auth_info);
        char *p;
 
        if (reason == POPT_CALLBACK_REASON_PRE) {
-               cmdline_auth_info.use_kerberos = False;
-               cmdline_auth_info.got_pass = False;
-               cmdline_auth_info.signing_state = Undefined;
-               pstrcpy(cmdline_auth_info.username, "GUEST");   
+               set_cmdline_auth_info_username(auth_info, "GUEST");
 
-               if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME"));
+               if (getenv("LOGNAME")) {
+                       set_cmdline_auth_info_username(auth_info,
+                                                      getenv("LOGNAME"));
+               }
 
                if (getenv("USER")) {
-                       pstrcpy(cmdline_auth_info.username,getenv("USER"));
+                       char *puser = SMB_STRDUP(getenv("USER"));
+                       if (!puser) {
+                               exit(ENOMEM);
+                       }
+                       set_cmdline_auth_info_username(auth_info, puser);
 
-                       if ((p = strchr_m(cmdline_auth_info.username,'%'))) {
+                       if ((p = strchr_m(puser,'%'))) {
+                               size_t len;
                                *p = 0;
-                               pstrcpy(cmdline_auth_info.password,p+1);
-                               cmdline_auth_info.got_pass = True;
-                               memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password));
+                               len = strlen(p+1);
+                               set_cmdline_auth_info_password(auth_info, p+1);
+                               memset(strchr_m(getenv("USER"),'%')+1,'X',len);
                        }
+                       SAFE_FREE(puser);
                }
 
                if (getenv("PASSWD")) {
-                       pstrcpy(cmdline_auth_info.password,getenv("PASSWD"));
-                       cmdline_auth_info.got_pass = True;
+                       set_cmdline_auth_info_password(auth_info,
+                                                      getenv("PASSWD"));
                }
 
                if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
-                       get_password_file(&cmdline_auth_info);
-                       cmdline_auth_info.got_pass = True;
+                       get_password_file(auth_info);
                }
 
                return;
@@ -307,19 +519,27 @@ static void popt_common_credentials_callback(poptContext con,
        case 'U':
                {
                        char *lp;
+                       char *puser = SMB_STRDUP(arg);
 
-                       pstrcpy(cmdline_auth_info.username,arg);
-                       if ((lp=strchr_m(cmdline_auth_info.username,'%'))) {
+                       if ((lp=strchr_m(puser,'%'))) {
+                               size_t len;
                                *lp = 0;
-                               pstrcpy(cmdline_auth_info.password,lp+1);
-                               cmdline_auth_info.got_pass = True;
-                               memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password));
+                               set_cmdline_auth_info_username(auth_info,
+                                                              puser);
+                               set_cmdline_auth_info_password(auth_info,
+                                                              lp+1);
+                               len = strlen(lp+1);
+                               memset(strchr_m(arg,'%')+1,'X',len);
+                       } else {
+                               set_cmdline_auth_info_username(auth_info,
+                                                              puser);
                        }
+                       SAFE_FREE(puser);
                }
                break;
 
        case 'A':
-               get_credentials_file(arg, &cmdline_auth_info);
+               get_credentials_file(auth_info, arg);
                break;
 
        case 'k':
@@ -327,66 +547,46 @@ static void popt_common_credentials_callback(poptContext con,
                d_printf("No kerberos support compiled in\n");
                exit(1);
 #else
-               cmdline_auth_info.use_kerberos = True;
-               cmdline_auth_info.got_pass = True;
+               set_cmdline_auth_info_use_krb5_ticket(auth_info);
 #endif
                break;
 
        case 'S':
-               {
-                       cmdline_auth_info.signing_state = -1;
-                       if (strequal(arg, "off") || strequal(arg, "no") || strequal(arg, "false"))
-                               cmdline_auth_info.signing_state = False;
-                       else if (strequal(arg, "on") || strequal(arg, "yes") || strequal(arg, "true") ||
-                                       strequal(arg, "auto") )
-                               cmdline_auth_info.signing_state = True;
-                       else if (strequal(arg, "force") || strequal(arg, "required") || strequal(arg, "forced"))
-                               cmdline_auth_info.signing_state = Required;
-                       else {
-                               fprintf(stderr, "Unknown signing option %s\n", arg );
-                               exit(1);
-                       }
+               if (!set_cmdline_auth_info_signing_state(auth_info, arg)) {
+                       fprintf(stderr, "Unknown signing option %s\n", arg );
+                       exit(1);
                }
                break;
        case 'P':
-               {
-                       char *opt_password = NULL;
-                       /* it is very useful to be able to make ads queries as the
-                          machine account for testing purposes and for domain leave */
-                       
-                       if (!secrets_init()) {
-                               d_printf("ERROR: Unable to open secrets database\n");
-                               exit(1);
-                       }
-                       
-                       opt_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-                       
-                       if (!opt_password) {
-                               d_printf("ERROR: Unable to fetch machine password\n");
-                               exit(1);
-                       }
-                       pstr_sprintf(cmdline_auth_info.username, "%s$", 
-                                    global_myname());
-                       pstrcpy(cmdline_auth_info.password,opt_password);
-                       SAFE_FREE(opt_password);
-
-                       /* machine accounts only work with kerberos */
-                       cmdline_auth_info.use_kerberos = True;
-                       cmdline_auth_info.got_pass = True;
-               }
+               set_cmdline_auth_info_use_machine_account(auth_info);
+               break;
+       case 'N':
+               set_cmdline_auth_info_password(auth_info, "");
                break;
+       case 'e':
+               set_cmdline_auth_info_smb_encrypt(auth_info);
+               break;
+
        }
 }
 
+static struct user_auth_info *global_auth_info;
 
+void popt_common_set_auth_info(struct user_auth_info *auth_info)
+{
+       global_auth_info = auth_info;
+}
 
 struct poptOption popt_common_credentials[] = {
-       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_credentials_callback },
+       { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
+         (void *)popt_common_credentials_callback, 0,
+         (const char *)&global_auth_info },
        { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
-       { "no-pass", 'N', POPT_ARG_NONE, &cmdline_auth_info.got_pass, 0, "Don't ask for a password" },
-       { "kerberos", 'k', POPT_ARG_NONE, &cmdline_auth_info.use_kerberos, 'k', "Use kerberos (active directory) authentication" },
+       { "no-pass", 'N', POPT_ARG_NONE, NULL, 'N', "Don't ask for a password" },
+       { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use kerberos (active directory) authentication" },
        { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
        { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
        {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
+       {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
        POPT_TABLEEND
 };