r25181: sync winbind client code with samba3
[kai/samba.git] / source4 / nsswitch / wbinfo.c
index 68dc178bcdbe48cce6963b91df97eb78ad00cdc7..46e4668dbe66c65485c2e5bd0e85e263686627fe 100644 (file)
@@ -3,12 +3,12 @@
 
    Winbind status program.
 
-   Copyright (C) Tim Potter      2000-2002
-   Copyright (C) Andrew Bartlett 2002
+   Copyright (C) Tim Potter      2000-2003
+   Copyright (C) Andrew Bartlett 2002-2007
    
    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,
    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"
-#include "winbindd.h"
-#include "debug.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_WINBIND
+#include "pstring.h"
+#include "winbind_client.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "lib/cmdline/popt_common.h"
+#include "dynconfig.h"
+#include "param/param.h"
 
 extern int winbindd_fd;
 
-static char winbind_separator(void)
+static char winbind_separator_int(BOOL strict)
 {
        struct winbindd_response response;
        static BOOL got_sep;
@@ -43,9 +45,12 @@ static char winbind_separator(void)
 
        /* Send off request */
 
-       if (winbindd_request(WINBINDD_INFO, NULL, &response) !=
+       if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
            NSS_STATUS_SUCCESS) {
-               d_printf("could not obtain winbind separator!\n");
+               d_fprintf(stderr, "could not obtain winbind separator!\n");
+               if (strict) {
+                       return 0;
+               }
                /* HACK: (this module should not call lp_ funtions) */
                return *lp_winbind_separator();
        }
@@ -54,7 +59,10 @@ static char winbind_separator(void)
        got_sep = True;
 
        if (!sep) {
-               d_printf("winbind separator was NULL!\n");
+               d_fprintf(stderr, "winbind separator was NULL!\n");
+               if (strict) {
+                       return 0;
+               }
                /* HACK: (this module should not call lp_ funtions) */
                sep = *lp_winbind_separator();
        }
@@ -62,6 +70,11 @@ static char winbind_separator(void)
        return sep;
 }
 
+static char winbind_separator(void)
+{
+       return winbind_separator_int(False);
+}
+
 static const char *get_winbind_domain(void)
 {
        struct winbindd_response response;
@@ -71,9 +84,9 @@ static const char *get_winbind_domain(void)
 
        /* Send off request */
 
-       if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
+       if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
            NSS_STATUS_SUCCESS) {
-               d_printf("could not obtain winbind domain name!\n");
+               d_fprintf(stderr, "could not obtain winbind domain name!\n");
                
                /* HACK: (this module should not call lp_ funtions) */
                return lp_workgroup();
@@ -103,11 +116,100 @@ static BOOL parse_wbinfo_domain_user(const char *domuser, fstring domain,
        fstrcpy(user, p+1);
        fstrcpy(domain, domuser);
        domain[PTR_DIFF(p, domuser)] = 0;
-       strupper(domain);
+       strupper_m(domain);
 
        return True;
 }
 
+/* pull pwent info for a given user */
+
+static BOOL wbinfo_get_userinfo(char *user)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Send request */
+       
+       fstrcpy(request.data.username, user);
+
+       result = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
+       
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+       
+       d_printf( "%s:%s:%d:%d:%s:%s:%s\n",
+                         response.data.pw.pw_name,
+                         response.data.pw.pw_passwd,
+                         response.data.pw.pw_uid,
+                         response.data.pw.pw_gid,
+                         response.data.pw.pw_gecos,
+                         response.data.pw.pw_dir,
+                         response.data.pw.pw_shell );
+       
+       return True;
+}
+
+/* pull pwent info for a given uid */
+static BOOL wbinfo_get_uidinfo(int uid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       request.data.uid = uid;
+
+       result = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       d_printf( "%s:%s:%d:%d:%s:%s:%s\n",
+               response.data.pw.pw_name,
+               response.data.pw.pw_passwd,
+               response.data.pw.pw_uid,
+               response.data.pw.pw_gid,
+               response.data.pw.pw_gecos,
+               response.data.pw.pw_dir,
+               response.data.pw.pw_shell );
+
+       return True;
+}
+
+/* pull grent for a given group */
+static BOOL wbinfo_get_groupinfo(char *group)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Send request */
+
+       fstrcpy(request.data.groupname, group);
+
+       result = winbindd_request_response(WINBINDD_GETGRNAM, &request,
+                                 &response);
+
+       if ( result != NSS_STATUS_SUCCESS)
+               return False;
+
+       d_printf( "%s:%s:%d\n",
+                 response.data.gr.gr_name,
+                 response.data.gr.gr_passwd,
+                 response.data.gr.gr_gid );
+       
+       return True;
+}
+
 /* List groups a user is a member of */
 
 static BOOL wbinfo_get_usergroups(char *user)
@@ -117,21 +219,80 @@ static BOOL wbinfo_get_usergroups(char *user)
        NSS_STATUS result;
        int i;
        
+       ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
        /* Send request */
 
        fstrcpy(request.data.username, user);
 
-       result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+       result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
 
        if (result != NSS_STATUS_SUCCESS)
                return False;
 
        for (i = 0; i < response.data.num_entries; i++)
-               d_printf("%d\n", (int)((gid_t *)response.extra_data)[i]);
+               d_printf("%d\n", (int)((gid_t *)response.extra_data.data)[i]);
+
+       SAFE_FREE(response.extra_data.data);
+
+       return True;
+}
+
+
+/* List group SIDs a user SID is a member of */
+static BOOL wbinfo_get_usersids(char *user_sid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       int i;
+       const char *s;
 
-       SAFE_FREE(response.extra_data);
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Send request */
+       fstrcpy(request.data.sid, user_sid);
+
+       result = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       s = (const char *)response.extra_data.data;
+       for (i = 0; i < response.data.num_entries; i++) {
+               d_printf("%s\n", s);
+               s += strlen(s) + 1;
+       }
+
+       SAFE_FREE(response.extra_data.data);
+
+       return True;
+}
+
+static BOOL wbinfo_get_userdomgroups(const char *user_sid)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Send request */
+       fstrcpy(request.data.sid, user_sid);
+
+       result = winbindd_request_response(WINBINDD_GETUSERDOMGROUPS, &request,
+                                 &response);
+
+       if (result != NSS_STATUS_SUCCESS)
+               return False;
+
+       if (response.data.num_entries != 0)
+               printf("%s", (char *)response.extra_data.data);
+       
+       SAFE_FREE(response.extra_data.data);
 
        return True;
 }
@@ -150,14 +311,14 @@ static BOOL wbinfo_wins_byname(char *name)
 
        fstrcpy(request.data.winsreq, name);
 
-       if (winbindd_request(WINBINDD_WINS_BYNAME, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response) !=
            NSS_STATUS_SUCCESS) {
                return False;
        }
 
        /* Display response */
 
-       printf("%s\n", response.data.winsresp);
+       d_printf("%s\n", response.data.winsresp);
 
        return True;
 }
@@ -176,69 +337,162 @@ static BOOL wbinfo_wins_byip(char *ip)
 
        fstrcpy(request.data.winsreq, ip);
 
-       if (winbindd_request(WINBINDD_WINS_BYIP, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response) !=
            NSS_STATUS_SUCCESS) {
                return False;
        }
 
        /* Display response */
 
-       printf("%s\n", response.data.winsresp);
+       d_printf("%s\n", response.data.winsresp);
 
        return True;
 }
 
 /* List trusted domains */
 
-static BOOL wbinfo_list_domains(void)
+static BOOL wbinfo_list_domains(BOOL list_all_domains)
 {
+       struct winbindd_request request;
        struct winbindd_response response;
-       fstring name;
 
+       ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
        /* Send request */
 
-       if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response) !=
+       request.data.list_all_domains = list_all_domains;
+
+       if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
        /* Display response */
 
-       if (response.extra_data) {
-               const char *extra_data = (char *)response.extra_data;
-
-               while(next_token(&extra_data, name, ",", sizeof(fstring)))
+       if (response.extra_data.data) {
+               const char *extra_data = (char *)response.extra_data.data;
+               fstring name;
+               char *p;
+
+               while(next_token(&extra_data, name, "\n", sizeof(fstring))) {
+                       p = strchr(name, '\\');
+                       if (p == 0) {
+                               d_fprintf(stderr, "Got invalid response: %s\n",
+                                        extra_data);
+                               return False;
+                       }
+                       *p = 0;
                        d_printf("%s\n", name);
+               }
 
-               SAFE_FREE(response.extra_data);
+               SAFE_FREE(response.extra_data.data);
        }
 
        return True;
 }
 
+/* List own domain */
+
+static BOOL wbinfo_list_own_domain(void)
+{
+       d_printf("%s\n", get_winbind_domain());
+
+       return True;
+}
 
 /* show sequence numbers */
-static BOOL wbinfo_show_sequence(void)
+static BOOL wbinfo_show_sequence(const char *domain)
 {
+       struct winbindd_request  request;
        struct winbindd_response response;
 
        ZERO_STRUCT(response);
+       ZERO_STRUCT(request);
+
+       if ( domain )
+               fstrcpy( request.domain_name, domain );
 
        /* Send request */
 
-       if (winbindd_request(WINBINDD_SHOW_SEQUENCE, NULL, &response) !=
+       if (winbindd_request_response(WINBINDD_SHOW_SEQUENCE, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
        /* Display response */
 
-       if (response.extra_data) {
-               char *extra_data = (char *)response.extra_data;
+       if (response.extra_data.data) {
+               char *extra_data = (char *)response.extra_data.data;
                d_printf("%s", extra_data);
-               SAFE_FREE(response.extra_data);
+               SAFE_FREE(response.extra_data.data);
+       }
+
+       return True;
+}
+
+/* Show domain info */
+
+static BOOL wbinfo_domain_info(const char *domain_name)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if ((strequal(domain_name, ".")) || (domain_name[0] == '\0'))
+               fstrcpy(request.domain_name, get_winbind_domain());
+       else
+               fstrcpy(request.domain_name, domain_name);
+
+       /* Send request */
+
+       if (winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response) !=
+           NSS_STATUS_SUCCESS)
+               return False;
+
+       /* Display response */
+
+       d_printf("Name              : %s\n", response.data.domain_info.name);
+       d_printf("Alt_Name          : %s\n", response.data.domain_info.alt_name);
+
+       d_printf("SID               : %s\n", response.data.domain_info.sid);
+
+       d_printf("Active Directory  : %s\n",
+                response.data.domain_info.active_directory ? "Yes" : "No");
+       d_printf("Native            : %s\n",
+                response.data.domain_info.native_mode ? "Yes" : "No");
+
+       d_printf("Primary           : %s\n",
+                response.data.domain_info.primary ? "Yes" : "No");
+
+       d_printf("Sequence          : %d\n", response.data.domain_info.sequence_number);
+
+       return True;
+}
+
+/* Get a foreign DC's name */
+static BOOL wbinfo_getdcname(const char *domain_name)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.domain_name, domain_name);
+
+       /* Send request */
+
+       if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) !=
+           NSS_STATUS_SUCCESS) {
+               d_fprintf(stderr, "Could not get dc name for %s\n", domain_name);
+               return False;
        }
 
+       /* Display response */
+
+       d_printf("%s\n", response.data.dc_name);
+
        return True;
 }
 
@@ -251,13 +505,13 @@ static BOOL wbinfo_check_secret(void)
 
         ZERO_STRUCT(response);
 
-        result = winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response);
+        result = winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response);
                
        d_printf("checking the trust secret via RPC calls %s\n", 
                 (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
 
        if (result != NSS_STATUS_SUCCESS)       
-               d_printf("error code was %s (0x%x)\n", 
+               d_fprintf(stderr, "error code was %s (0x%x)\n", 
                         response.data.auth.nt_status_string, 
                         response.data.auth.nt_status);
        
@@ -278,7 +532,7 @@ static BOOL wbinfo_uid_to_sid(uid_t uid)
 
        request.data.uid = uid;
 
-       if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
@@ -303,7 +557,7 @@ static BOOL wbinfo_gid_to_sid(gid_t gid)
 
        request.data.gid = gid;
 
-       if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
@@ -328,7 +582,7 @@ static BOOL wbinfo_sid_to_uid(char *sid)
 
        fstrcpy(request.data.sid, sid);
 
-       if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
@@ -351,7 +605,7 @@ static BOOL wbinfo_sid_to_gid(char *sid)
 
        fstrcpy(request.data.sid, sid);
 
-       if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
@@ -376,7 +630,7 @@ static BOOL wbinfo_lookupsid(char *sid)
 
        fstrcpy(request.data.sid, sid);
 
-       if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
@@ -389,6 +643,22 @@ static BOOL wbinfo_lookupsid(char *sid)
        return True;
 }
 
+static const char *sid_type_lookup(enum lsa_SidType r)
+{
+       switch (r) {
+               case SID_NAME_USE_NONE: return "SID_NAME_USE_NONE"; break;
+               case SID_NAME_USER: return "SID_NAME_USER"; break;
+               case SID_NAME_DOM_GRP: return "SID_NAME_DOM_GRP"; break;
+               case SID_NAME_DOMAIN: return "SID_NAME_DOMAIN"; break;
+               case SID_NAME_ALIAS: return "SID_NAME_ALIAS"; break;
+               case SID_NAME_WKN_GRP: return "SID_NAME_WKN_GRP"; break;
+               case SID_NAME_DELETED: return "SID_NAME_DELETED"; break;
+               case SID_NAME_INVALID: return "SID_NAME_INVALID"; break;
+               case SID_NAME_UNKNOWN: return "SID_NAME_UNKNOWN"; break;
+       }
+       return "Invalid sid type\n";
+}
+
 /* Convert string to sid */
 
 static BOOL wbinfo_lookupname(char *name)
@@ -404,19 +674,80 @@ static BOOL wbinfo_lookupname(char *name)
        parse_wbinfo_domain_user(name, request.data.name.dom_name, 
                                 request.data.name.name);
 
-       if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response) !=
+       if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
        /* Display response */
 
-       d_printf("%s %d\n", response.data.sid.sid, response.data.sid.type);
+       d_printf("%s %s (%d)\n", response.data.sid.sid, sid_type_lookup(response.data.sid.type), response.data.sid.type);
 
        return True;
 }
 
 /* Authenticate a user with a plaintext password */
 
+static BOOL wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       char *p;
+
+       /* Send off request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       p = strchr(username, '%');
+
+       if (p) {
+               *p = 0;
+               fstrcpy(request.data.auth.user, username);
+               fstrcpy(request.data.auth.pass, p + 1);
+               *p = '%';
+       } else
+               fstrcpy(request.data.auth.user, username);
+
+       request.flags = flags;
+
+       fstrcpy(request.data.auth.krb5_cc_type, cctype);
+
+       request.data.auth.uid = geteuid();
+
+       result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
+
+       /* Display response */
+
+       d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", 
+               username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype);
+
+       if (response.data.auth.nt_status)
+               d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
+                        response.data.auth.nt_status_string, 
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
+
+       if (result == NSS_STATUS_SUCCESS) {
+
+               if (request.flags & WBFLAG_PAM_INFO3_TEXT) {
+                       if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) {
+                               d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n");
+                       }
+               }
+
+               if (response.data.auth.krb5ccname[0] != '\0') {
+                       d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname);
+               } else {
+                       d_printf("no credentials cached\n");
+               }
+       }
+
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/* Authenticate a user with a plaintext password */
+
 static BOOL wbinfo_auth(char *username)
 {
        struct winbindd_request request;
@@ -439,7 +770,7 @@ static BOOL wbinfo_auth(char *username)
         } else
                 fstrcpy(request.data.auth.user, username);
 
-       result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
+       result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
 
        /* Display response */
 
@@ -447,9 +778,10 @@ static BOOL wbinfo_auth(char *username)
                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
 
        if (response.data.auth.nt_status)
-               d_printf("error code was %s (0x%x)\n", 
+               d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
                         response.data.auth.nt_status_string, 
-                        response.data.auth.nt_status);
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
 
         return result == NSS_STATUS_SUCCESS;
 }
@@ -480,21 +812,72 @@ static BOOL wbinfo_auth_crap(char *username)
                
        parse_wbinfo_domain_user(username, name_domain, name_user);
 
+       request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
+
        fstrcpy(request.data.auth_crap.user, name_user);
 
-       fstrcpy(request.data.auth_crap.domain, name_domain);
+       fstrcpy(request.data.auth_crap.domain, 
+                             name_domain);
 
-       generate_random_buffer(request.data.auth_crap.chal, 8, False);
+       generate_random_buffer(request.data.auth_crap.chal, 8);
         
-        SMBencrypt(pass, request.data.auth_crap.chal, 
-                   (uchar *)request.data.auth_crap.lm_resp);
-        SMBNTencrypt(pass, request.data.auth_crap.chal,
-                     (uchar *)request.data.auth_crap.nt_resp);
+       if (lp_client_ntlmv2_auth()) {
+               DATA_BLOB server_chal;
+               DATA_BLOB names_blob;   
+
+               DATA_BLOB lm_response;
+               DATA_BLOB nt_response;
+
+               TALLOC_CTX *mem_ctx;
+               mem_ctx = talloc_new(NULL);
+               if (mem_ctx == NULL) {
+                       d_printf("talloc_new failed\n");
+                       return False;
+               }
+
+               server_chal = data_blob(request.data.auth_crap.chal, 8); 
+               
+               /* Pretend this is a login to 'us', for blob purposes */
+               names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(), lp_workgroup());
+               
+               if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain, pass, &server_chal, 
+                                     &names_blob,
+                                     &lm_response, &nt_response, NULL, NULL)) {
+                       data_blob_free(&names_blob);
+                       data_blob_free(&server_chal);
+                       return False;
+               }
+               data_blob_free(&names_blob);
+               data_blob_free(&server_chal);
+
+               memcpy(request.data.auth_crap.nt_resp, nt_response.data, 
+                      MIN(nt_response.length, 
+                          sizeof(request.data.auth_crap.nt_resp)));
+               request.data.auth_crap.nt_resp_len = nt_response.length;
+
+               memcpy(request.data.auth_crap.lm_resp, lm_response.data, 
+                      MIN(lm_response.length, 
+                          sizeof(request.data.auth_crap.lm_resp)));
+               request.data.auth_crap.lm_resp_len = lm_response.length;
+                      
+               data_blob_free(&nt_response);
+               data_blob_free(&lm_response);
 
-        request.data.auth_crap.lm_resp_len = 24;
-        request.data.auth_crap.nt_resp_len = 24;
+       } else {
+               if (lp_client_lanman_auth() 
+                   && SMBencrypt(pass, request.data.auth_crap.chal, 
+                              (unsigned char *)request.data.auth_crap.lm_resp)) {
+                       request.data.auth_crap.lm_resp_len = 24;
+               } else {
+                       request.data.auth_crap.lm_resp_len = 0;
+               }
+               SMBNTencrypt(pass, request.data.auth_crap.chal,
+                            (unsigned char *)request.data.auth_crap.nt_resp);
+
+               request.data.auth_crap.nt_resp_len = 24;
+       }
 
-       result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
+       result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
 
        /* Display response */
 
@@ -502,168 +885,102 @@ static BOOL wbinfo_auth_crap(char *username)
                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed");
 
        if (response.data.auth.nt_status)
-               d_printf("error code was %s (0x%x)\n", 
+               d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
                         response.data.auth.nt_status_string, 
-                        response.data.auth.nt_status);
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
 
         return result == NSS_STATUS_SUCCESS;
 }
 
 /* Print domain users */
 
-static BOOL print_domain_users(void)
+static BOOL print_domain_users(const char *domain)
 {
+       struct winbindd_request request;
        struct winbindd_response response;
        const char *extra_data;
        fstring name;
 
        /* Send request to winbind daemon */
 
+       ZERO_STRUCT(request);
        ZERO_STRUCT(response);
+       
+       if (domain) {
+               /* '.' is the special sign for our own domain */
+               if ( strequal(domain, ".") )
+                       fstrcpy( request.domain_name, get_winbind_domain() );
+               else
+                       fstrcpy( request.domain_name, domain );
+       }
 
-       if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response) !=
+       if (winbindd_request_response(WINBINDD_LIST_USERS, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
        /* Look through extra data */
 
-       if (!response.extra_data)
+       if (!response.extra_data.data)
                return False;
 
-       extra_data = (const char *)response.extra_data;
+       extra_data = (const char *)response.extra_data.data;
 
        while(next_token(&extra_data, name, ",", sizeof(fstring)))
                d_printf("%s\n", name);
        
-       SAFE_FREE(response.extra_data);
+       SAFE_FREE(response.extra_data.data);
 
        return True;
 }
 
 /* Print domain groups */
 
-static BOOL print_domain_groups(void)
+static BOOL print_domain_groups(const char *domain)
 {
+       struct winbindd_request  request;
        struct winbindd_response response;
        const char *extra_data;
        fstring name;
 
+       ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response) !=
+       if (domain) {
+               if ( strequal(domain, ".") )
+                       fstrcpy( request.domain_name, get_winbind_domain() );
+               else
+                       fstrcpy( request.domain_name, domain );
+       }
+
+       if (winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response) !=
            NSS_STATUS_SUCCESS)
                return False;
 
        /* Look through extra data */
 
-       if (!response.extra_data)
+       if (!response.extra_data.data)
                return False;
 
-       extra_data = (const char *)response.extra_data;
+       extra_data = (const char *)response.extra_data.data;
 
        while(next_token(&extra_data, name, ",", sizeof(fstring)))
                d_printf("%s\n", name);
 
-       SAFE_FREE(response.extra_data);
+       SAFE_FREE(response.extra_data.data);
        
        return True;
 }
 
-/* Set the authorised user for winbindd access in secrets.tdb */
-
-static BOOL wbinfo_set_auth_user(char *username)
-{
-       char *password;
-       fstring user, domain;
-
-       /* Separate into user and password */
-
-       parse_wbinfo_domain_user(username, domain, user);
-
-       password = strchr(user, '%');
-
-       if (password) {
-               *password = 0;
-               password++;
-       } else
-               password = "";
-
-       /* Store or remove DOMAIN\username%password in secrets.tdb */
-
-       secrets_init();
-
-       if (user[0]) {
-
-               if (!secrets_store(SECRETS_AUTH_USER, user,
-                                  strlen(user) + 1)) {
-                       d_fprintf(stderr, "error storing username\n");
-                       return False;
-               }
-
-               /* We always have a domain name added by the
-                  parse_wbinfo_domain_user() function. */
-
-               if (!secrets_store(SECRETS_AUTH_DOMAIN, domain,
-                                  strlen(domain) + 1)) {
-                       d_fprintf(stderr, "error storing domain name\n");
-                       return False;
-               }
-
-       } else {
-               secrets_delete(SECRETS_AUTH_USER);
-               secrets_delete(SECRETS_AUTH_DOMAIN);
-       }
-
-       if (password[0]) {
-
-               if (!secrets_store(SECRETS_AUTH_PASSWORD, password,
-                                  strlen(password) + 1)) {
-                       d_fprintf(stderr, "error storing password\n");
-                       return False;
-               }
-
-       } else
-               secrets_delete(SECRETS_AUTH_PASSWORD);
-
-       return True;
-}
-
-static void wbinfo_get_auth_user(void)
-{
-       char *user, *domain, *password;
-
-       /* Lift data from secrets file */
-
-       secrets_init();
-
-       user = secrets_fetch(SECRETS_AUTH_USER, NULL);
-       domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
-       password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
-
-       if (!user && !domain && !password) {
-               d_printf("No authorised user configured\n");
-               return;
-       }
-
-       /* Pretty print authorised user info */
-
-       d_printf("%s%s%s%s%s\n", domain ? domain : "", domain ? "\\" : "",
-                user, password ? "%" : "", password ? password : "");
-
-       SAFE_FREE(user);
-       SAFE_FREE(domain);
-       SAFE_FREE(password);
-}
-
 static BOOL wbinfo_ping(void)
 {
         NSS_STATUS result;
 
-       result = winbindd_request(WINBINDD_PING, NULL, NULL);
+       result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
 
        /* Display response */
 
-        d_printf("'ping' to winbindd %s on fd %d\n", 
+        d_printf("Ping to winbindd %s on fd %d\n", 
                (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", winbindd_fd);
 
         return result == NSS_STATUS_SUCCESS;
@@ -674,17 +991,28 @@ static BOOL wbinfo_ping(void)
 enum {
        OPT_SET_AUTH_USER = 1000,
        OPT_GET_AUTH_USER,
-       OPT_SEQUENCE
+       OPT_DOMAIN_NAME,
+       OPT_SEQUENCE,
+       OPT_GETDCNAME,
+       OPT_USERDOMGROUPS,
+       OPT_USERSIDS,
+       OPT_ALLOCATE_UID,
+       OPT_ALLOCATE_GID,
+       OPT_SEPARATOR,
+       OPT_LIST_ALL_DOMAINS,
+       OPT_LIST_OWN_DOMAIN,
+       OPT_UID_INFO,
+       OPT_GROUP_INFO,
 };
 
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
 {
        int opt;
 
        poptContext pc;
        static char *string_arg;
+       static char *opt_domain_name;
        static int int_arg;
-       BOOL got_command = False;
        int result = 1;
 
        struct poptOption long_options[] = {
@@ -693,10 +1021,10 @@ int main(int argc, char **argv)
                /* longName, shortName, argInfo, argPtr, value, descrip, 
                   argDesc */
 
-               { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users"},
-               { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups" },
-               { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP (WINS)", "NETBIOS-NAME" },
-               { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name (WINS)", "IP" },
+               { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"},
+               { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" },
+               { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" },
+               { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" },
                { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" },
                { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" },
                { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" },
@@ -705,29 +1033,33 @@ int main(int argc, char **argv)
                { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
                { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
                { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
-               { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "show sequence numbers of all domains" },
+               { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" },
+               { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" },
+               { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
+               { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" },
+               { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" },
+               { "uid-info", 0, POPT_ARG_INT, &int_arg, OPT_UID_INFO, "Get user info from uid", "UID" },
+               { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" },
                { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" },
+               { "user-domgroups", 0, POPT_ARG_STRING, &string_arg,
+                 OPT_USERDOMGROUPS, "Get user domain groups", "SID" },
+               { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" },
                { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" },
-               { "set-auth-user", 'A', POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" },
-               { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
-               { "ping", 'p', POPT_ARG_NONE, 0, 'p', "'ping' winbindd to see if it is alive" },
-               { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
-               { 0, 0, 0, 0 }
+               { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
+                 "Get a DC name for a foreign domain", "domainname" },
+               { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
+               { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
+#ifdef HAVE_KRB5
+               { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" },
+                       /* destroys wbinfo --help output */
+                       /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */
+#endif
+               { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL },
+               POPT_COMMON_VERSION
+               POPT_COMMON_SAMBA
+               POPT_TABLEEND
        };
 
-       /* Samba client initialisation */
-
-       if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
-               d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
-                       dyn_CONFIGFILE, strerror(errno));
-               exit(1);
-       }
-
-       if (!init_names())
-               return 1;
-
-       load_interfaces();
-
        /* Parse options */
 
        pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0);
@@ -740,11 +1072,7 @@ int main(int argc, char **argv)
        }
 
        while((opt = poptGetNextOpt(pc)) != -1) {
-               if (got_command) {
-                       d_fprintf(stderr, "No more than one command may be specified at once.\n");
-                       exit(1);
-               }
-               got_command = True;
+               /* get the generic configuration parameters like --domain */
        }
 
        poptFreeContext(pc);
@@ -755,124 +1083,197 @@ int main(int argc, char **argv)
        while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
                case 'u':
-                       if (!print_domain_users()) {
-                               d_printf("Error looking up domain users\n");
+                       if (!print_domain_users(opt_domain_name)) {
+                               d_fprintf(stderr, "Error looking up domain users\n");
                                goto done;
                        }
                        break;
                case 'g':
-                       if (!print_domain_groups()) {
-                               d_printf("Error looking up domain groups\n");
+                       if (!print_domain_groups(opt_domain_name)) {
+                               d_fprintf(stderr, "Error looking up domain groups\n");
                                goto done;
                        }
                        break;
                case 's':
                        if (!wbinfo_lookupsid(string_arg)) {
-                               d_printf("Could not lookup sid %s\n", string_arg);
+                               d_fprintf(stderr, "Could not lookup sid %s\n", string_arg);
                                goto done;
                        }
                        break;
                case 'n':
                        if (!wbinfo_lookupname(string_arg)) {
-                               d_printf("Could not lookup name %s\n", string_arg);
+                               d_fprintf(stderr, "Could not lookup name %s\n", string_arg);
                                goto done;
                        }
                        break;
                case 'N':
                        if (!wbinfo_wins_byname(string_arg)) {
-                               d_printf("Could not lookup WINS by name %s\n", string_arg);
+                               d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg);
                                goto done;
                        }
                        break;
                case 'I':
                        if (!wbinfo_wins_byip(string_arg)) {
-                               d_printf("Could not lookup WINS by IP %s\n", string_arg);
+                               d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg);
                                goto done;
                        }
                        break;
                case 'U':
                        if (!wbinfo_uid_to_sid(int_arg)) {
-                               d_printf("Could not convert uid %d to sid\n", int_arg);
+                               d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg);
                                goto done;
                        }
                        break;
                case 'G':
                        if (!wbinfo_gid_to_sid(int_arg)) {
-                               d_printf("Could not convert gid %d to sid\n",
+                               d_fprintf(stderr, "Could not convert gid %d to sid\n",
                                       int_arg);
                                goto done;
                        }
                        break;
                case 'S':
                        if (!wbinfo_sid_to_uid(string_arg)) {
-                               d_printf("Could not convert sid %s to uid\n",
+                               d_fprintf(stderr, "Could not convert sid %s to uid\n",
                                       string_arg);
                                goto done;
                        }
                        break;
                case 'Y':
                        if (!wbinfo_sid_to_gid(string_arg)) {
-                               d_printf("Could not convert sid %s to gid\n",
+                               d_fprintf(stderr, "Could not convert sid %s to gid\n",
                                       string_arg);
                                goto done;
                        }
                        break;
                case 't':
                        if (!wbinfo_check_secret()) {
-                               d_printf("Could not check secret\n");
+                               d_fprintf(stderr, "Could not check secret\n");
                                goto done;
                        }
                        break;
                case 'm':
-                       if (!wbinfo_list_domains()) {
-                               d_printf("Could not list trusted domains\n");
+                       if (!wbinfo_list_domains(False)) {
+                               d_fprintf(stderr, "Could not list trusted domains\n");
                                goto done;
                        }
                        break;
                case OPT_SEQUENCE:
-                       if (!wbinfo_show_sequence()) {
-                               d_printf("Could not show sequence numbers\n");
+                       if (!wbinfo_show_sequence(opt_domain_name)) {
+                               d_fprintf(stderr, "Could not show sequence numbers\n");
+                               goto done;
+                       }
+                       break;
+               case 'D':
+                       if (!wbinfo_domain_info(string_arg)) {
+                               d_fprintf(stderr, "Could not get domain info\n");
+                               goto done;
+                       }
+                       break;
+               case 'i':
+                       if (!wbinfo_get_userinfo(string_arg)) {
+                               d_fprintf(stderr, "Could not get info for user %s\n",
+                                                 string_arg);
+                               goto done;
+                       }
+                       break;
+               case OPT_UID_INFO:
+                       if ( !wbinfo_get_uidinfo(int_arg)) {
+                               d_fprintf(stderr, "Could not get info for uid "
+                                               "%d\n", int_arg);
+                               goto done;
+                       }
+                       break;
+               case OPT_GROUP_INFO:
+                       if ( !wbinfo_get_groupinfo(string_arg)) {
+                               d_fprintf(stderr, "Could not get info for "
+                                         "group %s\n", string_arg);
                                goto done;
                        }
                        break;
                case 'r':
                        if (!wbinfo_get_usergroups(string_arg)) {
-                               d_printf("Could not get groups for user %s\n", 
+                               d_fprintf(stderr, "Could not get groups for user %s\n", 
                                       string_arg);
                                goto done;
                        }
                        break;
+               case OPT_USERSIDS:
+                       if (!wbinfo_get_usersids(string_arg)) {
+                               d_fprintf(stderr, "Could not get group SIDs for user SID %s\n", 
+                                      string_arg);
+                               goto done;
+                       }
+                       break;
+               case OPT_USERDOMGROUPS:
+                       if (!wbinfo_get_userdomgroups(string_arg)) {
+                               d_fprintf(stderr, "Could not get user's domain groups "
+                                        "for user SID %s\n", string_arg);
+                               goto done;
+                       }
+                       break;
                case 'a': {
-                                         BOOL got_error = False;
-
-                                         if (!wbinfo_auth(string_arg)) {
-                                                 d_printf("Could not authenticate user %s with "
-                                                                  "plaintext password\n", string_arg);
-                                                 got_error = True;
-                                         }
-
-                                         if (!wbinfo_auth_crap(string_arg)) {
-                                                 d_printf("Could not authenticate user %s with "
-                                                                  "challenge/response\n", string_arg);
-                                                 got_error = True;
-                                         }
-
-                                         if (got_error)
-                                                 goto done;
-                                         break;
-                                 }
-               case 'p': {
-                                         if (!wbinfo_ping()) {
-                                                 d_printf("could not ping winbindd!\n");
-                                                 goto done;
-                                         }
-                                         break;
-                                 }
-               case OPT_SET_AUTH_USER:
-                       wbinfo_set_auth_user(string_arg);
+                               BOOL got_error = False;
+
+                               if (!wbinfo_auth(string_arg)) {
+                                       d_fprintf(stderr, "Could not authenticate user %s with "
+                                               "plaintext password\n", string_arg);
+                                       got_error = True;
+                               }
+
+                               if (!wbinfo_auth_crap(string_arg)) {
+                                       d_fprintf(stderr, "Could not authenticate user %s with "
+                                               "challenge/response\n", string_arg);
+                                       got_error = True;
+                               }
+
+                               if (got_error)
+                                       goto done;
+                               break;
+                       }
+               case 'K': {
+                               uint32_t flags =  WBFLAG_PAM_KRB5 |
+                                               WBFLAG_PAM_CACHED_LOGIN |
+                                               WBFLAG_PAM_FALLBACK_AFTER_KRB5 |
+                                               WBFLAG_PAM_INFO3_TEXT;
+
+                               if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) {
+                                       d_fprintf(stderr, "Could not authenticate user [%s] with "
+                                               "Kerberos (ccache: %s)\n", string_arg, "FILE");
+                                       goto done;
+                               }
+                               break;
+                       }
+               case 'p':
+                       if (!wbinfo_ping()) {
+                               d_fprintf(stderr, "could not ping winbindd!\n");
+                               goto done;
+                       }
+                       break;
+               case OPT_GETDCNAME:
+                       if (!wbinfo_getdcname(string_arg)) {
+                               goto done;
+                       }
+                       break;
+               case OPT_SEPARATOR: {
+                       const char sep = winbind_separator_int(True);
+                       if ( !sep ) {
+                               goto done;
+                       }
+                       d_printf("%c\n", sep);
+                       break;
+               }
+               case OPT_LIST_ALL_DOMAINS:
+                       if (!wbinfo_list_domains(True)) {
+                               goto done;
+                       }
+                       break;
+               case OPT_LIST_OWN_DOMAIN:
+                       if (!wbinfo_list_own_domain()) {
+                               goto done;
+                       }
                        break;
-               case OPT_GET_AUTH_USER:
-                       wbinfo_get_auth_user();
+               /* generic configuration options */
+               case OPT_DOMAIN_NAME:
                        break;
                default:
                        d_fprintf(stderr, "Invalid option\n");