Antti Andreimann <Antti.Andreimann@mail.ee> has done some changes to enable
authorAndrew Bartlett <abartlet@samba.org>
Sat, 15 Feb 2003 00:29:21 +0000 (00:29 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 15 Feb 2003 00:29:21 +0000 (00:29 +0000)
users w/o full administrative access on computer accounts to join a
computer into AD domain.

The patch and detailed changelog is available at:
http://www.itcollege.ee/~aandreim/samba

This is a list of changes in general:

1. When creating machine account do not fail if SD cannot be changed.
   setting SD is not mandatory and join will work perfectly without it.
2. Implement KPASSWD CHANGEPW protocol for changing trust password so
   machine account does not need to have reset password right for itself.
3. Command line utilities no longer interfere with user's existing
   kerberos ticket cache.
4. Command line utilities can do kerberos authentication even if
   username is specified (-U). Initial TGT will be requested in this case.

I've modified the patch to share the kinit code, rather than copying it,
and updated it to current CVS.  The other change included in the original patch
(local realms) has been left out for now.

Andrew Bartlett

13 files changed:
source/Makefile.in
source/client/client.c
source/client/smbmount.c
source/include/ads.h
source/libads/krb5_setpw.c
source/libads/ldap.c
source/libads/sasl.c
source/libads/util.c
source/libsmb/cliconnect.c
source/libsmb/clikrb5.c
source/torture/locktest.c
source/torture/torture.c
source/utils/net_ads.c

index b4559e2b4e780ef1d1cc03828a838cc60334285f..a14380ce6c01fbcfa34c0414d8ef6bdf8dfa9d4d 100644 (file)
@@ -176,8 +176,10 @@ UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
 
 PARAM_OBJ = param/loadparm.o param/params.o dynconfig.o
 
+KRBCLIENT_OBJ = libads/kerberos.o
+
 LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \
-            libads/krb5_setpw.o libads/kerberos.o libads/ldap_user.o \
+            libads/krb5_setpw.o libads/ldap_user.o \
             libads/ads_struct.o libads/ads_status.o \
              libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \
             libads/ads_ldap.o
@@ -186,22 +188,24 @@ LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o
 
 SECRETS_OBJ = passdb/secrets.o
 
+LIBNMB_OBJ = libsmb/unexpected.o libsmb/namecache.o libsmb/nmblib.o \
+            libsmb/namequery.o 
+
 LIBNTLMSSP_OBJ = libsmb/ntlmssp.o libsmb/ntlmssp_parse.o
 
-LIBSAMBA_OBJ = libsmb/nterr.o 
+LIBSAMBA_OBJ = libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o
 
 LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
             libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \
             libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \
             libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \
-            libsmb/namequery.o libsmb/nmblib.o libsmb/clistr.o \
-             libsmb/smbdes.o libsmb/smbencrypt.o \
+            libsmb/clistr.o \
              libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
             libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
-            libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \
-            libsmb/namecache.o libsmb/trustdom_cache.o \
-            $(RPC_PARSE_OBJ1) $(LIBNTLMSSP_OBJ) $(LIBSAMBA_OBJ)
+            libsmb/passchange.o libsmb/doserr.o \
+            libsmb/trustdom_cache.o \
+            $(RPC_PARSE_OBJ1) $(LIBNTLMSSP_OBJ) $(LIBSAMBA_OBJ) $(LIBNMB_OBJ)
 
 LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
               rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \
@@ -293,7 +297,7 @@ SAM_STATIC_MODULES = sam/sam_plugin.o sam/sam_skel.o sam/sam_ads.o
 SAM_OBJ = sam/account.o sam/get_set_account.o sam/get_set_group.o \
                sam/get_set_domain.o sam/interface.o $(SAM_STATIC_MODULES)
 
-SAMTEST_OBJ = torture/samtest.o torture/cmd_sam.o $(SAM_OBJ) $(LIB_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(READLINE_OBJ) lib/util_seaccess.o $(LIBADS_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) $(GROUPDB_OBJ)
+SAMTEST_OBJ = torture/samtest.o torture/cmd_sam.o $(SAM_OBJ) $(LIB_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(READLINE_OBJ) lib/util_seaccess.o $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) $(GROUPDB_OBJ)
 
 GROUPDB_OBJ = groupdb/mapping.o
 
@@ -340,7 +344,7 @@ SMBD_OBJ_BASE = $(SMBD_OBJ_SRV) $(MSDFS_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_
                $(LIB_OBJ) $(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ) \
                $(NOTIFY_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) \
                $(LIBMSRPC_OBJ) $(LIBMSRPC_SERVER_OBJ) \
-               $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) \
+               $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \
                $(LIB_SMBD_OBJ) $(REGISTRY_OBJ) $(POPT_LIB_OBJ)
 
 
@@ -368,7 +372,7 @@ NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
             nmbd/nmbd_subnetdb.o nmbd/nmbd_winsproxy.o nmbd/nmbd_winsserver.o \
             nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o
 
-NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(UBIQX_OBJ) \
            $(PROFILE_OBJ) $(LIB_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ)
 
 WREPL_OBJ1 = wrepld/server.o wrepld/process.o wrepld/parser.o wrepld/socket.o \
@@ -381,7 +385,7 @@ SWAT_OBJ1 = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
            web/swat.o web/neg_lang.o 
 
 SWAT_OBJ = $(SWAT_OBJ1) $(PRINTING_OBJ) $(LIBSMB_OBJ) $(LOCKING_OBJ) \
-           $(PARAM_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) \
+           $(PARAM_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) $(KRBCLIENT_OBJ) \
           $(UBIQX_OBJ) $(LIB_OBJ) $(GROUPDB_OBJ) $(PLAINTEXT_AUTH_OBJ)
 
 SMBSH_OBJ = smbwrapper/smbsh.o smbwrapper/shared.o \
@@ -395,7 +399,8 @@ SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
        printing/printing_db.o
 
 SMBTREE_OBJ = utils/smbtree.o $(LOCKING_OBJ) $(PARAM_OBJ) \
-             $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(LIBSMB_OBJ) 
+             $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(LIBSMB_OBJ) \
+            $(KRBCLIENT_OBJ)
 
 TESTPARM_OBJ = utils/testparm.o \
                $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) $(POPT_LIB_OBJ)
@@ -405,14 +410,14 @@ TESTPRNS_OBJ = utils/testprns.o $(PARAM_OBJ) $(PRINTING_OBJ) $(UBIQX_OBJ) \
 
 SMBPASSWD_OBJ = utils/smbpasswd.o $(PARAM_OBJ) $(SECRETS_OBJ) \
                $(LIBSMB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ)\
-                $(UBIQX_OBJ) $(LIB_OBJ)
+                $(UBIQX_OBJ) $(LIB_OBJ) $(KRBCLIENT_OBJ)
 
-PDBEDIT_OBJ = utils/pdbedit.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \
+PDBEDIT_OBJ = utils/pdbedit.o $(PARAM_OBJ) $(PASSDB_OBJ) $(LIBSAMBA_OBJ) \
                $(UBIQX_OBJ) $(LIB_OBJ) $(GROUPDB_OBJ) $(SECRETS_OBJ) \
                $(POPT_LIB_OBJ)
 
 SMBGROUPEDIT_OBJ = utils/smbgroupedit.o $(GROUPDB_OBJ) $(PARAM_OBJ) \
-               $(LIBSMB_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+               $(LIBSAMBA_OBJ) $(PASSDB_OBJ) $(SECRETS_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
 
 RPCCLIENT_OBJ1 = rpcclient/rpcclient.o rpcclient/cmd_lsarpc.o \
                 rpcclient/cmd_samr.o rpcclient/cmd_spoolss.o \
@@ -423,7 +428,7 @@ RPCCLIENT_OBJ1 = rpcclient/rpcclient.o rpcclient/cmd_lsarpc.o \
 RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \
              $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
              $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(LIBMSRPC_OBJ) \
-             $(READLINE_OBJ) $(GROUPDB_OBJ) \
+             $(READLINE_OBJ) $(GROUPDB_OBJ) $(KRBCLIENT_OBJ) \
             $(LIBADS_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ)
 
 PAM_WINBIND_OBJ = nsswitch/pam_winbind.po nsswitch/wb_common.po lib/snprintf.po
@@ -433,7 +438,7 @@ SMBW_OBJ1 = smbwrapper/smbw.o \
                smbwrapper/realcalls.o smbwrapper/shared.o \
                smbwrapper/smbw_cache.o
 
-SMBW_OBJ = $(SMBW_OBJ1) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+SMBW_OBJ = $(SMBW_OBJ1) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) \
                 $(UBIQX_OBJ) $(LIB_OBJ)
 
 SMBWRAPPER_OBJ1 = smbwrapper/wrapped.o
@@ -442,7 +447,7 @@ SMBWRAPPER_OBJ = $(SMBW_OBJ) $(SMBWRAPPER_OBJ1)
 
 LIBSMBCLIENT_OBJ = libsmb/libsmbclient.o libsmb/libsmb_compat.o \
                   libsmb/libsmb_cache.o $(LIB_OBJ) \
-                  $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
+                  $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
 
 # This shared library is intended for linking with unit test programs
 # to test Samba internals.  It's called libbigballofmud.so to
@@ -452,54 +457,56 @@ LIBBIGBALLOFMUD_MAJOR = 0
 
 LIBBIGBALLOFMUD_OBJ = $(LIB_OBJ) $(UBIQX_OBJ) $(PARAM_OBJ) $(SECRETS_OBJ) \
        $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) \
-       $(GROUPDB_OBJ)
+       $(GROUPDB_OBJ) $(KRBCLIENT_OBJ)
 
 LIBBIGBALLOFMUD_PICOBJS = $(LIBBIGBALLOFMUD_OBJ:.o=.po)
 
 CLIENT_OBJ1 = client/client.o client/clitar.o 
 
-CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
-             $(READLINE_OBJ) $(POPT_LIB_OBJ)
+CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+            $(LIB_OBJ) $(KRBCLIENT_OBJ) \
+             $(READLINE_OBJ) $(POPT_LIB_OBJ) 
 
 NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \
           utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \
           utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \
           utils/net_cache.o
 
-NET_OBJ = $(NET_OBJ1) $(SECRETS_OBJ) $(LIBSMB_OBJ) \
+NET_OBJ = $(NET_OBJ1) $(SECRETS_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
          $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
          $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
          $(LIBMSRPC_OBJ) $(LIBMSRPC_SERVER_OBJ) \
          $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ)
 
-CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) 
+CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+         $(LIB_OBJ) $(KRBCLIENT_OBJ)
 
 MOUNT_OBJ = client/smbmount.o \
-             $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) 
+             $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) 
 
 MNT_OBJ = client/smbmnt.o              
 
 UMOUNT_OBJ = client/smbumount.o
 
-NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) \
-                $(LIBSMB_OBJ) $(LIB_OBJ)
+NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBNMB_OBJ) \
+               $(LIB_OBJ)
 
 SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
                torture/denytest.o torture/mangle_test.o 
 
 SMBTORTURE_OBJ = $(SMBTORTURE_OBJ1) \
-       $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+       $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
 
-MASKTEST_OBJ = torture/masktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+MASKTEST_OBJ = torture/masktest.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
-MSGTEST_OBJ = torture/msgtest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+MSGTEST_OBJ = torture/msgtest.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
-LOCKTEST_OBJ = torture/locktest.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+LOCKTEST_OBJ = torture/locktest.o $(LOCKING_OBJ) $(KRBCLIENT_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
-NSSTEST_OBJ = torture/nsstest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+NSSTEST_OBJ = torture/nsstest.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
 VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
@@ -510,10 +517,12 @@ VFS_RECYCLE_OBJ = modules/vfs_recycle.o
 VFS_NETATALK_OBJ = modules/vfs_netatalk.o
 VFS_FAKE_PERMS_OBJ = modules/vfs_fake_perms.o
 
-LOCKTEST2_OBJ = torture/locktest2.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+LOCKTEST2_OBJ = torture/locktest2.o $(LOCKING_OBJ) $(LIBSMB_OBJ) \
+               $(KRBCLIENT_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ)
 
-SMBCACLS_OBJ = utils/smbcacls.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
+SMBCACLS_OBJ = utils/smbcacls.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+               $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_GET_SET_OBJ) \
                 $(LIBMSRPC_OBJ) $(SECRETS_OBJ)
 
@@ -526,19 +535,19 @@ RPCTORTURE_OBJ = torture/rpctorture.o \
              rpcclient/cmd_samr.o \
              rpcclient/cmd_srvsvc.o \
              rpcclient/cmd_netlogon.o \
-             $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+             $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) $(KRBCLIENT_OBJ) \
              $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_GET_SET_OBJ)
 
 DEBUG2HTML_OBJ = utils/debug2html.o ubiqx/debugparse.o
 
 SMBFILTER_OBJ = utils/smbfilter.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
-                 $(UBIQX_OBJ) $(LIB_OBJ)
+                 $(UBIQX_OBJ) $(LIB_OBJ) $(KRBCLIENT_OBJ) 
 
 PROTO_OBJ = $(SMBD_OBJ_MAIN) \
            $(SMBD_OBJ_SRV) $(NMBD_OBJ1) $(SWAT_OBJ1) $(LIB_OBJ) $(LIBSMB_OBJ) \
            $(SMBW_OBJ1) $(SMBWRAPPER_OBJ1) $(SMBTORTURE_OBJ1) $(RPCCLIENT_OBJ1) \
            $(LIBMSRPC_OBJ) $(LIBMSRPC_SERVER_OBJ) $(RPC_CLIENT_OBJ) \
-           $(RPC_PIPE_OBJ) $(RPC_PARSE_OBJ) \
+           $(RPC_PIPE_OBJ) $(RPC_PARSE_OBJ) $(KRBCLIENT_OBJ) \
            $(AUTH_OBJ) $(PARAM_OBJ) $(LOCKING_OBJ) $(SECRETS_OBJ) \
            $(PRINTING_OBJ) $(PRINTBACKEND_OBJ) $(OPLOCK_OBJ) $(NOTIFY_OBJ) \
            $(QUOTAOBJS) $(PASSDB_OBJ) $(GROUPDB_OBJ) $(MSDFS_OBJ) \
@@ -582,10 +591,10 @@ WINBINDD_OBJ1 = \
 
 WINBINDD_OBJ = \
                $(WINBINDD_OBJ1) $(PASSDB_GET_SET_OBJ) \
-               $(LIBNMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+               $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
                $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) \
                $(PROFILE_OBJ) $(UNIGRP_OBJ) \
-               $(SECRETS_OBJ) $(LIBADS_OBJ) 
+               $(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ)
 
 WBINFO_OBJ = nsswitch/wbinfo.o libsmb/smbencrypt.o libsmb/smbdes.o
 
index 4761b0ae5c570d1365de6b27e05f97cdb12d8771..e5a9592fcc079c0c8d6055022ebf5f480dab7d2f 100644 (file)
@@ -41,6 +41,7 @@ static pstring password;
 static pstring username;
 static pstring workgroup;
 static char *cmdstr;
+static BOOL got_user;
 static BOOL got_pass;
 static int io_bufsize = 64512;
 static BOOL use_kerberos;
@@ -2889,6 +2890,8 @@ static void remember_query_host(const char *arg,
                case 'U':
                        {
                                char *lp;
+
+                               got_user = True;
                                pstrcpy(username,optarg);
                                if ((lp=strchr_m(username,'%'))) {
                                        *lp = 0;
@@ -2985,7 +2988,6 @@ static void remember_query_host(const char *arg,
                case 'k':
 #ifdef HAVE_KRB5
                        use_kerberos = True;
-                       got_pass = True;
 #else
                        d_printf("No kerberos support compiled in\n");
                        exit(1);
@@ -2997,6 +2999,9 @@ static void remember_query_host(const char *arg,
                }
        }
 
+       if (use_kerberos && !got_user)
+                       got_pass = True;
+
        init_names();
 
        if(*new_name_resolve_order)
index 508521bedc164d75268fd65940cad4ef772b3c32..e2372d02b4e1e33d0062c9ed06f114af8239330c 100644 (file)
@@ -41,12 +41,16 @@ static pstring options;
 static struct in_addr dest_ip;
 static BOOL have_ip;
 static int smb_port = 0;
+static BOOL got_user;
 static BOOL got_pass;
 static uid_t mount_uid;
 static gid_t mount_gid;
 static int mount_ro;
 static unsigned mount_fmask;
 static unsigned mount_dmask;
+static BOOL use_kerberos;
+/* TODO: Add code to detect smbfs version in kernel */
+static BOOL status32_smbfs = False;
 
 static void usage(void);
 
@@ -155,11 +159,15 @@ static struct cli_state *do_connection(char *the_service)
        }
 
        /* SPNEGO doesn't work till we get NTSTATUS error support */
-       c->use_spnego = False;
+       /* But it is REQUIRED for kerberos authentication */
+       if(!use_kerberos) c->use_spnego = False;
 
        /* The kernel doesn't yet know how to sign it's packets */
        c->sign_info.allow_smb_signing = False;
 
+       /* Use kerberos authentication if specified */
+       c->use_kerberos = use_kerberos;
+
        if (!cli_session_request(c, &calling, &called)) {
                char *p;
                DEBUG(0,("%d: session request to %s failed (%s)\n", 
@@ -193,9 +201,17 @@ static struct cli_state *do_connection(char *the_service)
 
        /* This should be right for current smbfs. Future versions will support
          large files as well as unicode and oplocks. */
-       c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
-                               CAP_NT_FIND | CAP_STATUS32 | CAP_LEVEL_II_OPLOCKS);
-       c->force_dos_errors = True;
+       if (status32_smbfs) {
+           c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
+                                 CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
+       }
+       else {
+           c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
+                                CAP_NT_FIND | CAP_STATUS32 |
+                                CAP_LEVEL_II_OPLOCKS);
+           c->force_dos_errors = True;
+       }
+
        if (!cli_session_setup(c, username, 
                               password, strlen(password),
                               password, strlen(password),
@@ -629,8 +645,9 @@ static void read_credentials_file(char *filename)
                        pstrcpy(password, val);
                        got_pass = True;
                }
-               else if (strwicmp("username", param) == 0)
+               else if (strwicmp("username", param) == 0) {
                        pstrcpy(username, val);
+               }
 
                memset(buf, 0, sizeof(buf));
        }
@@ -652,6 +669,7 @@ static void usage(void)
       username=<arg>                  SMB username\n\
       password=<arg>                  SMB password\n\
       credentials=<filename>          file with username/password\n\
+      krb                             use kerberos (active directory)\n\
       netbiosname=<arg>               source NetBIOS name\n\
       uid=<arg>                       mount uid or username\n\
       gid=<arg>                       mount gid or groupname\n\
@@ -738,6 +756,7 @@ static void parse_mount_smb(int argc, char **argv)
                         if (!strcmp(opts, "username") || 
                            !strcmp(opts, "logon")) {
                                char *lp;
+                               got_user = True;
                                pstrcpy(username,opteq+1);
                                if ((lp=strchr_m(username,'%'))) {
                                        *lp = 0;
@@ -795,6 +814,16 @@ static void parse_mount_smb(int argc, char **argv)
                        } else if(!strcmp(opts, "guest")) {
                                *password = '\0';
                                got_pass = True;
+                       } else if(!strcmp(opts, "krb")) {
+#ifdef HAVE_KRB5
+
+                               use_kerberos = True;
+                               if(!status32_smbfs)
+                                       fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
+#else
+                               fprintf(stderr,"No kerberos support compiled in\n");
+                               exit(1);
+#endif
                        } else if(!strcmp(opts, "rw")) {
                                mount_ro = 0;
                        } else if(!strcmp(opts, "ro")) {
@@ -879,6 +908,10 @@ static void parse_mount_smb(int argc, char **argv)
 
        parse_mount_smb(argc, argv);
 
+       if (use_kerberos && !got_user) {
+               got_pass = True;
+       }
+
        if (*credentials != 0) {
                read_credentials_file(credentials);
        }
index 7f23e6506b133676ea9b5328f8a74fc67a687f63..304a997b2ce7dca3f5ff2f9a9328ec877791588c 100644 (file)
@@ -205,3 +205,6 @@ typedef void **ADS_MODLIST;
 #define ADS_AUTH_NO_BIND          0x02
 #define ADS_AUTH_ANON_BIND        0x04
 #define ADS_AUTH_SIMPLE_BIND      0x08
+
+/* Kerberos environment variable names */
+#define KRB5_ENV_CCNAME "KRB5CCNAME"
index 087b0e9a7156d99061d751b87535e02c66a14221..c3ec754e393fef0126f8927316a10004f63c5593 100644 (file)
 #ifdef HAVE_KRB5
 
 #define DEFAULT_KPASSWD_PORT   464
-#define KRB5_KPASSWD_VERS_CHANGEPW     1
-#define KRB5_KPASSWD_VERS_SETPW                0xff80
-#define KRB5_KPASSWD_ACCESSDENIED      5
-#define KRB5_KPASSWD_BAD_VERSION       6
-
-/* This implements the Kerb password change protocol as specifed in
- * kerb-chg-password-02.txt
+#define KRB5_KPASSWD_VERS_CHANGEPW             1
+#define KRB5_KPASSWD_VERS_SETPW                        2
+#define KRB5_KPASSWD_VERS_SETPW_MS             0xff80
+#define KRB5_KPASSWD_ACCESSDENIED              5
+#define KRB5_KPASSWD_BAD_VERSION               6
+#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED       7
+
+/* Those are defined by kerberos-set-passwd-02.txt and are probably 
+ * not supported by M$ implementation */
+#define KRB5_KPASSWD_POLICY_REJECT             8
+#define KRB5_KPASSWD_BAD_PRINCIPAL             9
+#define KRB5_KPASSWD_ETYPE_NOSUPP              10
+
+/* This implements kerberos password change protocol as specified in 
+ * kerb-chg-password-02.txt and kerberos-set-passwd-02.txt
+ * as well as microsoft version of the protocol 
+ * as specified in kerberos-set-passwd-00.txt
  */
 static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
 {
@@ -101,7 +111,8 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
        return ret;
 }      
 
-static krb5_error_code build_setpw_request(krb5_context context,
+static krb5_error_code build_kpasswd_request(uint16 pversion,
+                                          krb5_context context,
                                           krb5_auth_context auth_context,
                                           krb5_data *ap_req,
                                           const char *princ,
@@ -123,7 +134,14 @@ static krb5_error_code build_setpw_request(krb5_context context,
                return ret;
        }
 
-       setpw = encode_krb5_setpw(princ, passwd);
+       /* handle protocol differences in chpw and setpw */
+       if (pversion  == KRB5_KPASSWD_VERS_CHANGEPW)
+               setpw = data_blob(passwd, strlen(passwd));
+       else if (pversion == KRB5_KPASSWD_VERS_SETPW ||
+                pversion == KRB5_KPASSWD_VERS_SETPW_MS)
+               setpw = encode_krb5_setpw(princ, passwd);
+       else
+               return EINVAL;
 
        encoded_setpw.data = setpw.data;
        encoded_setpw.length = setpw.length;
@@ -144,7 +162,7 @@ static krb5_error_code build_setpw_request(krb5_context context,
 
        /* see the RFC for details */
        p = ((char *)packet->data) + 2;
-       RSSVAL(p, 0, 0xff80);
+       RSSVAL(p, 0, pversion);
        p += 2;
        RSSVAL(p, 0, ap_req->length);
        p += 2;
@@ -160,6 +178,49 @@ static krb5_error_code build_setpw_request(krb5_context context,
        return 0;
 }
 
+static krb5_error_code krb5_setpw_result_code_string(krb5_context context,
+                                                    int result_code,
+                                                    char **code_string)
+{
+   switch (result_code) {
+   case KRB5_KPASSWD_MALFORMED:
+      *code_string = "Malformed request error";
+      break;
+   case KRB5_KPASSWD_HARDERROR:
+      *code_string = "Server error";
+      break;
+   case KRB5_KPASSWD_AUTHERROR:
+      *code_string = "Authentication error";
+      break;
+   case KRB5_KPASSWD_SOFTERROR:
+      *code_string = "Password change rejected";
+      break;
+   case KRB5_KPASSWD_ACCESSDENIED:
+      *code_string = "Client does not have proper authorization";
+      break;
+   case KRB5_KPASSWD_BAD_VERSION:
+      *code_string = "Protocol version not supported";
+      break;
+   case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
+      *code_string = "Authorization ticket must have initial flag set";
+      break;
+   case KRB5_KPASSWD_POLICY_REJECT:
+      *code_string = "Password rejected due to policy requirements";
+      break;
+   case KRB5_KPASSWD_BAD_PRINCIPAL:
+      *code_string = "Target principal does not exist";
+      break;
+   case KRB5_KPASSWD_ETYPE_NOSUPP:
+      *code_string = "Unsupported encryption type";
+      break;
+   default:
+      *code_string = "Password change failed";
+      break;
+   }
+
+   return(0);
+}
+
 static krb5_error_code parse_setpw_reply(krb5_context context, 
                                         krb5_auth_context auth_context,
                                         krb5_data *packet)
@@ -194,8 +255,11 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
        p += 2;
 
        vnum = RSVAL(p, 0); p += 2;
-       
-       if (vnum != KRB5_KPASSWD_VERS_SETPW && vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
+
+       /* FIXME: According to standard there is only one type of reply */      
+       if (vnum != KRB5_KPASSWD_VERS_SETPW && 
+           vnum != KRB5_KPASSWD_VERS_SETPW_MS && 
+           vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
                DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));
                return KRB5KDC_ERR_BAD_PVNO;
        }
@@ -247,96 +311,56 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
        free(clearresult.data);
 
        if ((res_code < KRB5_KPASSWD_SUCCESS) || 
-           (res_code >= KRB5_KPASSWD_ACCESSDENIED)) {
+           (res_code > KRB5_KPASSWD_ETYPE_NOSUPP)) {
                return KRB5KRB_AP_ERR_MODIFIED;
        }
-       
-       return 0;
+
+       if(res_code == KRB5_KPASSWD_SUCCESS)
+                       return 0;
+       else {
+               char *errstr;
+               krb5_setpw_result_code_string(context, res_code, &errstr);
+               DEBUG(1, ("Error changing password: %s\n", errstr));
+
+               switch(res_code) {
+                       case KRB5_KPASSWD_ACCESSDENIED:
+                               return KRB5KDC_ERR_BADOPTION;
+                               break;
+                       case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
+                               return KV5M_ALT_METHOD;
+                               break;
+                       case KRB5_KPASSWD_ETYPE_NOSUPP:
+                               return KRB5KDC_ERR_ETYPE_NOSUPP;
+                               break;
+                       case KRB5_KPASSWD_BAD_PRINCIPAL:
+                               return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+                               break;
+                       case KRB5_KPASSWD_POLICY_REJECT:
+                               return KRB5KDC_ERR_POLICY;
+                               break;
+                       default:
+                               return KRB5KRB_ERR_GENERIC;
+                               break;
+               }
+       }
 }
 
-ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw, 
-                            int time_offset)
+static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
+                                         const char *kdc_host,
+                                         uint16 pversion,
+                                         krb5_creds *credsp,
+                                         const char *princ,
+                                         const char *newpw)
 {
-       krb5_context context;
        krb5_auth_context auth_context = NULL;
-       krb5_principal principal;
-       char *princ_name;
-       char *realm;
-       krb5_creds creds, *credsp;
-       krb5_ccache ccache;
        krb5_data ap_req, chpw_req, chpw_rep;
        int ret, sock, addr_len;
        struct sockaddr remote_addr, local_addr;
        krb5_address local_kaddr, remote_kaddr;
 
-       ret = krb5_init_context(&context);
-       if (ret) {
-               DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-       
-       if (time_offset != 0) {
-               krb5_set_real_time(context, time(NULL) + time_offset, 0);
-       }
-
-       ret = krb5_cc_default(context, &ccache);
-       if (ret) {
-               krb5_free_context(context);
-               DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-
-       ZERO_STRUCT(creds);
-       
-       realm = strchr(princ, '@');
-       realm++;
-
-       asprintf(&princ_name, "kadmin/changepw@%s", realm);
-       ret = krb5_parse_name(context, princ_name, &creds.server);
-       if (ret) {
-                krb5_free_context(context);
-               DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-       free(princ_name);
-
-       /* parse the principal we got as a function argument */
-       ret = krb5_parse_name(context, princ, &principal);
-       if (ret) {
-                krb5_free_context(context);
-               DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-
-       krb5_princ_set_realm(context, creds.server,
-                            krb5_princ_realm(context, principal));
-       
-       ret = krb5_cc_get_principal(context, ccache, &creds.client);
-       if (ret) {
-               krb5_free_principal(context, principal);
-                krb5_free_context(context);
-               DEBUG(1,("Failed to get principal from ccache (%s)\n", 
-                        error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-       
-       ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
-       if (ret) {
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
-               DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
-               return ADS_ERROR_KRB5(ret);
-       }
-       
-       /* we might have to call krb5_free_creds(...) from now on ... */
        ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
                                   NULL, credsp, &ap_req);
        if (ret) {
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
                DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
@@ -345,10 +369,7 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
        if (sock == -1) {
                int rc = errno;
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("failed to open kpasswd socket to %s (%s)\n", 
                         kdc_host, strerror(errno)));
                return ADS_ERROR_SYSTEM(rc);
@@ -366,23 +387,17 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
        if (ret) {
                close(sock);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
-       ret = build_setpw_request(context, auth_context, &ap_req,
+       ret = build_kpasswd_request(pversion, context, auth_context, &ap_req,
                                  princ, newpw, &chpw_req);
        if (ret) {
                close(sock);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
@@ -391,10 +406,7 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
                close(sock);
                free(chpw_req.data);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
                return ADS_ERROR_SYSTEM(errno);
        }
@@ -406,10 +418,7 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
        if (!chpw_rep.data) {
                close(sock);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
                errno = ENOMEM;
                return ADS_ERROR_SYSTEM(errno);
@@ -420,10 +429,7 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
                close(sock);
                free(chpw_rep.data);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
                return ADS_ERROR_SYSTEM(errno);
        }
@@ -435,10 +441,7 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
        if (ret) {
                free(chpw_rep.data);
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", 
                         error_message(ret)));
                return ADS_ERROR_KRB5(ret);
@@ -449,22 +452,194 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
 
        if (ret) {
                free(ap_req.data);
-               krb5_free_creds(context, credsp);
-               krb5_free_principal(context, creds.client);
-               krb5_free_principal(context, principal);
-               krb5_free_context(context);
+               krb5_auth_con_free(context, auth_context);
                DEBUG(1,("parse_setpw_reply failed (%s)\n", 
                         error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
        free(ap_req.data);
+       krb5_auth_con_free(context, auth_context);
+
+       return ADS_SUCCESS;
+}
+
+ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw, 
+                            int time_offset)
+{
+
+       ADS_STATUS aret;
+       krb5_error_code ret;
+       krb5_context context;
+       krb5_principal principal;
+       char *princ_name;
+       char *realm;
+       krb5_creds creds, *credsp;
+       krb5_ccache ccache;
+
+       ret = krb5_init_context(&context);
+       if (ret) {
+               DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+       
+       if (time_offset != 0) {
+               krb5_set_real_time(context, time(NULL) + time_offset, 0);
+       }
+
+       ret = krb5_cc_default(context, &ccache);
+       if (ret) {
+               krb5_free_context(context);
+               DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+
+       ZERO_STRUCT(creds);
+       
+       realm = strchr(princ, '@');
+       realm++;
+
+       asprintf(&princ_name, "kadmin/changepw@%s", realm);
+       ret = krb5_parse_name(context, princ_name, &creds.server);
+       if (ret) {
+                krb5_free_context(context);
+               DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+       free(princ_name);
+
+       /* parse the principal we got as a function argument */
+       ret = krb5_parse_name(context, princ, &principal);
+       if (ret) {
+                krb5_free_context(context);
+               DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+
+       krb5_princ_set_realm(context, creds.server,
+                            krb5_princ_realm(context, principal));
+       
+       ret = krb5_cc_get_principal(context, ccache, &creds.client);
+       if (ret) {
+               krb5_free_principal(context, principal);
+                krb5_free_context(context);
+               DEBUG(1,("Failed to get principal from ccache (%s)\n", 
+                        error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+       
+       ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 
+       if (ret) {
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
+               DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
+               return ADS_ERROR_KRB5(ret);
+       }
+       
+       /* we might have to call krb5_free_creds(...) from now on ... */
+
+       aret = do_krb5_kpasswd_request(context, kdc_host,
+                                      KRB5_KPASSWD_VERS_SETPW_MS,
+                                      credsp, princ, newpw);
+
        krb5_free_creds(context, credsp);
        krb5_free_principal(context, creds.client);
+       krb5_free_principal(context, creds.server);
        krb5_free_principal(context, principal);
        krb5_free_context(context);
 
-       return ADS_SUCCESS;
+       return aret;
+}
+
+/*
+  we use a prompter to avoid a crash bug in the kerberos libs when 
+  dealing with empty passwords
+  this prompter is just a string copy ...
+*/
+static krb5_error_code 
+kerb_prompter(krb5_context ctx, void *data,
+              const char *name,
+              const char *banner,
+              int num_prompts,
+              krb5_prompt prompts[])
+{
+       if (num_prompts == 0) return 0;
+
+       memset(prompts[0].reply->data, 0, prompts[0].reply->length);
+       if (prompts[0].reply->length > 0) {
+               if (data) {
+                       strncpy(prompts[0].reply->data, data, prompts[0].reply->length-1);
+                       prompts[0].reply->length = strlen(prompts[0].reply->data);
+               } else {
+                       prompts[0].reply->length = 0;
+               }
+       }
+       return 0;
+}
+
+ADS_STATUS krb5_chg_password(const char *kdc_host,
+                               const char *principal,
+                               const char *oldpw, 
+                               const char *newpw, 
+                               int time_offset)
+{
+    ADS_STATUS aret;
+    krb5_error_code ret;
+    krb5_context context;
+    krb5_principal princ;
+    krb5_get_init_creds_opt opts;
+    krb5_creds creds;
+    char *chpw_princ = NULL, *password;
+
+    ret = krb5_init_context(&context);
+    if (ret) {
+       DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
+       return ADS_ERROR_KRB5(ret);
+    }
+
+    if ((ret = krb5_parse_name(context, principal,
+                                    &princ))) {
+       krb5_free_context(context);
+       DEBUG(1,("Failed to parse %s (%s)\n", principal, error_message(ret)));
+       return ADS_ERROR_KRB5(ret);
+    }
+
+    krb5_get_init_creds_opt_init(&opts);
+    krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
+    krb5_get_init_creds_opt_set_renew_life(&opts, 0);
+    krb5_get_init_creds_opt_set_forwardable(&opts, 0);
+    krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+
+    /* We have to obtain an INITIAL changepw ticket for changing password */
+    asprintf(&chpw_princ, "kadmin/changepw@%s",
+                               (char *) krb5_princ_realm(context, princ));
+    password = strdup(oldpw);
+    ret = krb5_get_init_creds_password(context, &creds, princ, password,
+                                          kerb_prompter, NULL, 
+                                          0, chpw_princ, &opts);
+    SAFE_FREE(chpw_princ);
+    SAFE_FREE(password);
+
+    if (ret) {
+      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+       DEBUG(1,("Password incorrect while getting initial ticket"));
+      else
+       DEBUG(1,("krb5_get_init_creds_password failed (%s)\n", error_message(ret)));
+
+       krb5_free_principal(context, princ);
+       krb5_free_context(context);
+       return ADS_ERROR_KRB5(ret);
+    }
+
+    aret = do_krb5_kpasswd_request(context, kdc_host,
+                                  KRB5_KPASSWD_VERS_CHANGEPW,
+                                  &creds, principal, newpw);
+
+    krb5_free_principal(context, princ);
+    krb5_free_context(context);
+
+    return aret;
 }
 
 
@@ -480,7 +655,12 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server,
        return ADS_ERROR_KRB5(ret);
     }
 
-    return krb5_set_password(kpasswd_server, target_principal, new_password, time_offset);
+    if (!strcmp(auth_principal, target_principal))
+       return krb5_chg_password(kpasswd_server, target_principal,
+                                   auth_password, new_password, time_offset);
+    else
+       return krb5_set_password(kpasswd_server, target_principal,
+                                new_password, time_offset);
 }
 
 
@@ -515,4 +695,6 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
        return status;
 }
 
+
+
 #endif
index 47a94f0a08d364696ef55906d5433c487828d805..c92e4810783b2338df5bdbffd0da3ff3d53fe756 100644 (file)
@@ -1022,7 +1022,7 @@ char *ads_ou_string(const char *org_unit)
 static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, 
                                       const char *org_unit)
 {
-       ADS_STATUS ret;
+       ADS_STATUS ret, status;
        char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
        char *ou_str;
        TALLOC_CTX *ctx;
@@ -1089,9 +1089,21 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
        ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
        ads_mod_str(ctx, &mods, "operatingSystemVersion", VERSION);
 
-       ads_gen_add(ads, new_dn, mods);
-       ret = ads_set_machine_sd(ads, hostname, new_dn);
+       ret = ads_gen_add(ads, new_dn, mods);
 
+       if (!ADS_ERR_OK(ret))
+               goto done;
+
+       /* Do not fail if we can't set security descriptor
+        * it shouldn't be mandatory and probably we just 
+        * don't have enough rights to do it.
+        */
+       status = ads_set_machine_sd(ads, hostname, new_dn);
+
+       if (!ADS_ERR_OK(status)) {
+               DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
+                               ads_errstr(status)));
+       }
 done:
        talloc_destroy(ctx);
        return ret;
@@ -1406,7 +1418,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
  **/
 ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
 {
-       const char     *attrs[] = {"ntSecurityDescriptor", "objectSid", 0};
+       const char     *attrs[] = {"nTSecurityDescriptor", "objectSid", 0};
        char           *exp     = 0;
        size_t          sd_size = 0;
        struct berval   bval = {0, NULL};
@@ -1423,6 +1435,10 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
        SEC_DESC   *psd = 0;
        TALLOC_CTX *ctx = 0;    
 
+       /* Avoid segmentation fault in prs_mem_free if
+        * we have to bail out before prs_init */
+       ps_wire.is_dynamic = False;
+
        if (!ads) return ADS_ERROR(LDAP_SERVER_DOWN);
 
        ret = ADS_ERROR(LDAP_SUCCESS);
index 7aa77bf2a240405251323fd24561777d9a00fd77..29d4533a54fa056357e72184c1594114a95e63ee 100644 (file)
@@ -241,7 +241,12 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
        ADS_STATUS status;
        krb5_principal principal;
        krb5_context ctx;
-       krb5_enctype enc_types[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
+       krb5_enctype enc_types[] = {
+#ifdef ENCTYPE_ARCFOUR_HMAC
+                       ENCTYPE_ARCFOUR_HMAC,
+#endif
+                       ENCTYPE_DES_CBC_MD5,
+                       ENCTYPE_NULL};
        gss_OID_desc nt_principal = 
        {10, "\052\206\110\206\367\022\001\002\002\002"};
 
index 021f2d93e4aad7039beb1d7524513e8645d19f47..335cabc95261429172f0255b421f05553721292b 100644 (file)
@@ -29,7 +29,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
     char *new_password;
     char *service_principal;
     ADS_STATUS ret;
-     
+
     if ((password = secrets_fetch_machine_password()) == NULL) {
        DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
        return ADS_ERROR_SYSTEM(ENOENT);
@@ -38,15 +38,17 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
     tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
     new_password = strdup(tmp_password);
     asprintf(&service_principal, "HOST/%s", host_principal);
-    
-    ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, 
-                               service_principal, new_password, ads->auth.time_offset);
+
+    ret = kerberos_set_password(ads->auth.kdc_server, service_principal, password, service_principal, new_password, ads->auth.time_offset);
+
+    if (!ADS_ERR_OK(ret)) goto failed;
 
     if (!secrets_store_machine_password(new_password)) {
            DEBUG(1,("Failed to save machine password\n"));
            return ADS_ERROR_SYSTEM(EACCES);
     }
 
+failed:
     SAFE_FREE(service_principal);
     SAFE_FREE(new_password);
 
index 9c7b1684315e21cd181b4a4818ae68a5ead7abd1..90a7eca8e71a863709b8dfe98d8cb2469c598879 100644 (file)
@@ -445,6 +445,13 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
 }
 
 #ifdef HAVE_KRB5
+/****************************************************************************
+ Use in-memory credentials cache
+****************************************************************************/
+static void use_in_memory_ccache() {
+       setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads_testjoin", 1);
+}
+
 /****************************************************************************
  Do a spnego/kerberos encrypted session setup.
 ****************************************************************************/
@@ -656,6 +663,21 @@ static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user,
        fstrcpy(cli->user_name, user);
 
 #ifdef HAVE_KRB5
+       /* If password is set we reauthenticate to kerberos server
+        * and do not store results */
+
+       if (*pass) {
+               int ret;
+
+               use_in_memory_ccache();
+               ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */);
+
+               if (ret){
+                       DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
+                       return False;
+               }
+       }
+
        if (got_kerberos_mechanism && cli->use_kerberos) {
                return cli_session_setup_kerberos(cli, principal, workgroup);
        }
index 203d9d874b26f6c49fe3df2b629a94219f9030b7..e380d80bcc92deaf7c6978f99e3ac64c67b93df4 100644 (file)
@@ -278,6 +278,7 @@ DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
                ENCTYPE_ARCFOUR_HMAC, 
 #endif
                                    ENCTYPE_DES_CBC_MD5, 
+                                   ENCTYPE_DES_CBC_CRC, 
                                    ENCTYPE_NULL};
 
        retval = krb5_init_context(&context);
@@ -324,7 +325,6 @@ failed:
        return data_blob(NULL, 0);
 }
 
-
 #else /* HAVE_KRB5 */
  /* this saves a few linking headaches */
  DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
index 5f9a63802b31d351ed0b343c5ee87e6af0e4f9a0..63b9590dd61639605633ff0714623d50b89b347b 100644 (file)
@@ -24,6 +24,7 @@
 
 static fstring password[2];
 static fstring username[2];
+static int got_user;
 static int got_pass;
 static BOOL use_kerberos;
 static int numops = 1000;
@@ -602,13 +603,13 @@ static void usage(void)
                case 'k':
 #ifdef HAVE_KRB5
                        use_kerberos = True;
-                       got_pass = True;
 #else
                        d_printf("No kerberos support compiled in\n");
                        exit(1);
 #endif
                        break;
                case 'U':
+                       got_user = 1;
                        if (got_pass == 2) {
                                d_printf("Max of 2 usernames\n");
                                exit(1);
@@ -663,6 +664,8 @@ static void usage(void)
                }
        }
 
+       if(use_kerberos && !got_user) got_pass = True;
+
        argc -= optind;
        argv += optind;
 
index 56b8da768e53b529cfc022a9a55ce9df0f05561c..97e864de965d2a6a76deaee4fe76dba6ba332875 100644 (file)
@@ -4082,6 +4082,7 @@ static void usage(void)
 {
        int opt, i;
        char *p;
+       int gotuser = 0;
        int gotpass = 0;
        extern char *optarg;
        extern int optind;
@@ -4167,13 +4168,13 @@ static void usage(void)
                case 'k':
 #ifdef HAVE_KRB5
                        use_kerberos = True;
-                       gotpass = True;
 #else
                        d_printf("No kerberos support compiled in\n");
                        exit(1);
 #endif
                        break;
                case 'U':
+                       gotuser = 1;
                        fstrcpy(username,optarg);
                        p = strchr_m(username,'%');
                        if (p) {
@@ -4188,6 +4189,7 @@ static void usage(void)
                }
        }
 
+       if(use_kerberos && !gotuser) gotpass = True;
 
        while (!gotpass) {
                p = getpass("Password:");
index 867252c95f2ac9743b1d44ad0e7e271510892eae..d508320423bbe2770fd6dfe94793ba9441875a92 100644 (file)
@@ -110,6 +110,11 @@ static int net_ads_info(int argc, const char **argv)
        return 0;
 }
 
+static void use_in_memory_ccache() {
+       /* Use in-memory credentials cache so we do not interfere with
+        * existing credentials */
+       setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
+}
 
 static ADS_STRUCT *ads_startup(void)
 {
@@ -124,8 +129,10 @@ static ADS_STRUCT *ads_startup(void)
                opt_user_name = "administrator";
        }
 
-       if (opt_user_specified)
+       if (opt_user_specified) {
                need_password = True;
+               use_in_memory_ccache();
+       }
 
 retry:
        if (!opt_password && need_password) {
@@ -601,6 +608,8 @@ static int net_ads_join_ok(void)
  */
 int net_ads_testjoin(int argc, const char **argv)
 {
+       use_in_memory_ccache();
+
        /* Display success or failure */
        if (net_ads_join_ok() != 0) {
                fprintf(stderr,"Join to domain is not valid\n");
@@ -878,7 +887,8 @@ static int net_ads_password(int argc, const char **argv)
        (strchr(argv[0], '@') == NULL)) {
        return net_ads_usage(argc, argv);
     }
-    
+
+    use_in_memory_ccache();    
     c = strchr(auth_principal, '@');
     realm = ++c;
 
@@ -925,6 +935,8 @@ static int net_ads_change_localhost_pass(int argc, const char **argv)
 
     opt_password = secrets_fetch_machine_password();
 
+    use_in_memory_ccache();
+
     if (!(ads = ads_startup())) {
            return -1;
     }