added "net join" command
authorAndrew Tridgell <tridge@samba.org>
Sat, 24 Nov 2001 14:16:41 +0000 (14:16 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sat, 24 Nov 2001 14:16:41 +0000 (14:16 +0000)
this completes the first stage of the smbd ADS support

19 files changed:
source/CodingSuggestions
source/Makefile.in
source/client/client.c
source/groupdb/mapping.c
source/include/includes.h
source/include/secrets.h
source/lib/util_sock.c
source/libads/kerberos.c [new file with mode: 0644]
source/libads/krb5_setpw.c [new file with mode: 0644]
source/libads/ldap.c
source/libsmb/clikrb5.c
source/param/loadparm.c
source/passdb/secrets.c
source/printing/nt_printing.c
source/rpcclient/cmd_lsarpc.c
source/script/mkproto.awk
source/smbd/sesssetup.c
source/utils/net.c
source/utils/net_join.c [new file with mode: 0644]

index 60a358919ae82019844522986991dd62b1f3b196..48c51281f524a507c300e8565a945456bc778080 100644 (file)
@@ -115,6 +115,23 @@ Here are some other suggestions:
     comment start / ** so that they can be picked up by Doxygen, as in
     this file.
 
+23) Keep the scope narrow. This means making functions/variables
+    static whenever possible. We don't want our namespace
+    polluted. Each module should have a minimal number of externally
+    visible functions or variables.
+
+24) Use function pointers to keep knowledge about particular pieces of
+    code isolated in one place. We don't want a particular piece of
+    functionality to be spread out across lots of places - that makes
+    for fragile, hand to maintain code. Instead, design an interface
+    and use tables containing function pointers to implement specific
+    functionality. This is particularly important for command
+    interpreters. 
+
+25) Think carefully about what it will be like for someone else to add
+    to and maintain your code. If it would be hard for someone else to
+    maintain then do it another way. 
+
 The suggestions above are simply that, suggestions, but the information may
 help in reducing the routine rework done on new code.  The preceeding list
 is expected to change routinely as new support routines and macros are
index 6b3b337a120205c467b1762ee9708bd5d3e1c508..8a29a1f0ffe3ac03002b0fead2025ce7a38a9c06 100644 (file)
@@ -131,7 +131,7 @@ UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
 
 PARAM_OBJ = param/loadparm.o param/params.o dynconfig.o
 
-LIBADS_OBJ = libads/ldap.o
+LIBADS_OBJ = libads/ldap.o libads/krb5_setpw.o libads/kerberos.o passdb/secrets.o 
 
 LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
@@ -179,7 +179,7 @@ RPC_CLIENT_OBJ = rpc_client/cli_netlogon.o rpc_client/cli_pipe.o \
 
 LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
 
-PASSDB_OBJ = passdb/passdb.o passdb/secrets.o \
+PASSDB_OBJ = passdb/passdb.o \
                passdb/machine_sid.o passdb/pdb_smbpasswd.o \
                passdb/pdb_tdb.o passdb/pdb_ldap.o \
                passdb/pdb_nisplus.o
@@ -319,8 +319,8 @@ CLIENT_OBJ = client/client.o client/clitar.o \
              $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
              $(READLINE_OBJ)
 
-NET_OBJ = utils/net.o  $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
-          @BUILD_POPT@
+NET_OBJ = utils/net.o utils/net_join.o \
+       $(LIBSMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) @BUILD_POPT@
 
 CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
 
@@ -375,7 +375,7 @@ SMBFILTER_OBJ = utils/smbfilter.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
 
 PROTO_OBJ = $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) \
            $(SMBWRAPPER_OBJ) $(SMBTORTURE_OBJ) $(RPCCLIENT_OBJ1) \
-           $(LIBMSRPC_OBJ) $(RPC_CLIENT_OBJ) $(AUTH_OBJ)
+           $(LIBMSRPC_OBJ) $(RPC_CLIENT_OBJ) $(AUTH_OBJ) $(NET_OBJ)
 
 NSS_OBJ_0 = nsswitch/wins.o $(PARAM_OBJ) $(UBIQX_OBJ) $(LIBSMB_OBJ) $(LIB_OBJ) $(NSSWINS_OBJ)
 NSS_OBJ = $(NSS_OBJ_0:.o=.po)
index 7baab4b2043a32bdee62a3b6f8ad9ea05ec94872..c684f3fea69c94f1b5bfb0efb44fb96ffc74b582 100644 (file)
@@ -2159,7 +2159,7 @@ struct cli_state *do_connect(const char *server, const char *share)
                               password, strlen(password),
                               workgroup)) {
                /* if a password was not supplied then try again with a null username */
-               if (password[0] || !username[0] || 
+               if (password[0] || !username[0] || use_kerberos ||
                    !cli_session_setup(c, "", "", 0, "", 0, workgroup)) { 
                        d_printf("session setup failed: %s\n", cli_errstr(c));
                        cli_shutdown(c);
index 92a98ff7a448896db6e3d19427213104776f4a70..c39bb8cdffbe6adcfeaac483db823d44de929112 100644 (file)
@@ -233,7 +233,7 @@ add a privilege to a privilege array
 ****************************************************************************/
 BOOL add_privilege(uint32 *privilege, uint32 priv)
 {
-       int i;
+       int i=0;
 
        while (i<PRIV_ALL_INDEX && privilege[i]!=0 && privilege[i]!=priv)
                i++;
@@ -262,6 +262,7 @@ BOOL add_all_privilege(uint32 *privilege)
        add_privilege(privilege, SE_PRIV_ADD_USERS);
        add_privilege(privilege, SE_PRIV_ADD_MACHINES);
        add_privilege(privilege, SE_PRIV_PRINT_OPERATOR);
+       return True;
 }
 
 /****************************************************************************
@@ -301,7 +302,6 @@ BOOL default_group_mapping(void)
        fstring str_admins;
        fstring str_users;
        fstring str_guests;
-       int i;
 
        uint32 privilege_none[PRIV_ALL_INDEX];
        uint32 privilege_all[PRIV_ALL_INDEX];
index 8b61bc573ca6e97dbcde0fd7ec1f7acabe7e2be5..adae49ddeaa4ef32f2294dbf5b8d9063affabb2d 100644 (file)
@@ -737,6 +737,13 @@ typedef struct smb_wpasswd {
        wpstring       pw_shell;
 } SMB_STRUCT_WPASSWD;
 
+/* used in net.c */
+struct functable {
+       char *funcname;
+       int (*fn)();
+};
+
+
 /* Defines for wisXXX functions. */
 #define UNI_UPPER    0x1
 #define UNI_LOWER    0x2
index 9abc3637e8b95e7ca7b1b0ddc9e508b9cabcd303..5990170ccc9b5cf3fb4bbbfafc2444f3fbb9acea 100644 (file)
 #ifndef _SECRETS_H
 #define _SECRETS_H
 
+/* the first one is for the hashed password (NT4 style) the latter
+   for plaintext (ADS 
+*/
 #define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
+#define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
+
+
 #define SECRETS_DOMAIN_SID    "SECRETS/SID"
 #define SECRETS_SAM_SID       "SAM/SID"
 
index 340a83cf13f560ff406ebb512feafeccbd8ef6b1..045e18ac228a167f61721ffbd92a4bfd0678ebc2 100644 (file)
@@ -905,6 +905,37 @@ connect_again:
   return res;
 }
 
+/*
+  open a connected UDP socket to host on port
+*/
+int open_udp_socket(const char *host, int port)
+{
+       int type = SOCK_DGRAM;
+       struct sockaddr_in sock_out;
+       int res;
+       struct in_addr *addr;
+
+       addr = interpret_addr2(host);
+
+       res = socket(PF_INET, type, 0);
+       if (res == -1) {
+               return -1;
+       }
+
+       memset((char *)&sock_out,'\0',sizeof(sock_out));
+       putip((char *)&sock_out.sin_addr,(char *)addr);
+       sock_out.sin_port = htons(port);
+       sock_out.sin_family = PF_INET;
+
+       if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
+               close(res);
+               return -1;
+       }
+
+       return res;
+}
+
+
 /* the following 3 client_*() functions are nasty ways of allowing
    some generic functions to get info that really should be hidden in
    particular modules */
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
new file mode 100644 (file)
index 0000000..e4e946f
--- /dev/null
@@ -0,0 +1,149 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 3.0
+   kerberos utility library
+   Copyright (C) Andrew Tridgell 2001
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+/*
+  verify an incoming ticket and parse out the principal name and 
+  authorization_data if available 
+*/
+NTSTATUS ads_verify_ticket(const DATA_BLOB *ticket, 
+                          char **principal, DATA_BLOB *auth_data)
+{
+       krb5_context context;
+       krb5_auth_context auth_context = NULL;
+       krb5_keytab keytab = NULL;
+       krb5_data packet;
+       krb5_ticket *tkt = NULL;
+       krb5_data salt;
+       krb5_encrypt_block eblock;
+       int ret;
+       krb5_keyblock * key;
+       krb5_principal host_princ;
+       char *host_princ_s;
+       extern pstring global_myname;
+       fstring myname;
+       char *password_s;
+       krb5_data password;
+
+       if (!secrets_init()) {
+               DEBUG(1,("secrets_init failed\n"));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       password_s = secrets_fetch_machine_password();
+       if (!password_s) {
+               DEBUG(1,("failed to fetch machine password\n"));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       password.data = password_s;
+       password.length = strlen(password_s);
+
+       ret = krb5_init_context(&context);
+       if (ret) {
+               DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       ret = krb5_set_default_realm(context, lp_realm());
+       if (ret) {
+               DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       /* this whole process is far more complex than I would
+           like. We have to go through all this to allow us to store
+           the secret internally, instead of using /etc/krb5.keytab */
+       ret = krb5_auth_con_init(context, &auth_context);
+       if (ret) {
+               DEBUG(1,("krb5_auth_con_init failed (%s)\n", error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       fstrcpy(myname, global_myname);
+       strlower(myname);
+       asprintf(&host_princ_s, "HOST/%s@%s", myname, lp_realm());
+       ret = krb5_parse_name(context, host_princ_s, &host_princ);
+       if (ret) {
+               DEBUG(1,("krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       ret = krb5_principal2salt(context, host_princ, &salt);
+       if (ret) {
+               DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+    
+       if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_MD5);
+       
+       ret = krb5_string_to_key(context, &eblock, key, &password, &salt);
+       if (ret) {
+               DEBUG(1,("krb5_string_to_key failed (%s)\n", error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       krb5_auth_con_setuseruserkey(context, auth_context, key);
+
+       packet.length = ticket->length;
+       packet.data = (krb5_pointer)ticket->data;
+
+#if 0
+       file_save("/tmp/ticket.dat", ticket->data, ticket->length);
+#endif
+
+       if ((ret = krb5_rd_req(context, &auth_context, &packet, 
+                              NULL, keytab, NULL, &tkt))) {
+               DEBUG(3,("krb5_rd_req with auth failed (%s)\n", 
+                        error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       if (tkt->enc_part2) {
+               *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
+                                      tkt->enc_part2->authorization_data[0]->length);
+       }
+
+#if 0
+       if (tkt->enc_part2) {
+               file_save("/tmp/authdata.dat", 
+                         tkt->enc_part2->authorization_data[0]->contents,
+                         tkt->enc_part2->authorization_data[0]->length);
+       }
+#endif
+
+       if ((ret = krb5_unparse_name(context, tkt->enc_part2->client, principal))) {
+               DEBUG(3,("krb5_unparse_name failed (%s)\n", 
+                        error_message(ret)));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       return NT_STATUS_OK;
+}
+
+#endif
diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c
new file mode 100644 (file)
index 0000000..5cb3de1
--- /dev/null
@@ -0,0 +1,352 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 3.0
+   krb5 set password implementation
+   Copyright (C) Andrew Tridgell 2001
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+#if 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
+ */
+static DATA_BLOB encode_krb5_setpw(const char *hostname, 
+                                  const char *realm, const char *password)
+{
+       ASN1_DATA req;
+       DATA_BLOB ret;
+
+       memset(&req, 0, sizeof(req));
+       
+       asn1_push_tag(&req, ASN1_SEQUENCE(0));
+       asn1_push_tag(&req, ASN1_CONTEXT(0));
+       asn1_write_OctetString(&req, password, strlen(password));
+       asn1_pop_tag(&req);
+
+       asn1_push_tag(&req, ASN1_CONTEXT(1));
+       asn1_push_tag(&req, ASN1_SEQUENCE(0));
+
+       asn1_push_tag(&req, ASN1_CONTEXT(0));
+       asn1_write_Integer(&req, 1);
+       asn1_pop_tag(&req);
+
+       asn1_push_tag(&req, ASN1_CONTEXT(1));
+       asn1_push_tag(&req, ASN1_SEQUENCE(0));
+       asn1_write_GeneralString(&req, "HOST");
+       asn1_write_GeneralString(&req, hostname);
+       asn1_pop_tag(&req);
+       asn1_pop_tag(&req);
+       asn1_pop_tag(&req);
+       asn1_pop_tag(&req);
+
+       asn1_push_tag(&req, ASN1_CONTEXT(2));
+       asn1_write_GeneralString(&req, realm);
+       asn1_pop_tag(&req);
+       asn1_pop_tag(&req);
+
+       ret = data_blob(req.data, req.length);
+       asn1_free(&req);
+
+       return ret;
+}      
+
+static krb5_error_code build_setpw_request(krb5_context context,
+                                          krb5_auth_context auth_context,
+                                          krb5_data *ap_req,
+                                          const char *hostname,
+                                          const char *realm,
+                                          const char *passwd,
+                                          krb5_data *packet)
+{
+       krb5_error_code ret;
+       krb5_data cipherpw;
+       krb5_data encoded_setpw;
+       krb5_replay_data replay;
+       char *p;
+       DATA_BLOB setpw;
+
+       ret = krb5_auth_con_setflags(context,
+                                    auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+       if (ret) {
+               DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",
+                        error_message(ret)));
+               return ret;
+       }
+
+       setpw = encode_krb5_setpw(hostname, realm, passwd);
+
+       encoded_setpw.data = setpw.data;
+       encoded_setpw.length = setpw.length;
+
+       ret = krb5_mk_priv(context, auth_context,
+                          &encoded_setpw, &cipherpw, &replay);
+       if (ret) {
+               DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
+               return ret;
+       }
+
+       packet->data = (char *)malloc(ap_req->length + cipherpw.length + 6);
+
+       /* see the RFC for details */
+       p = packet->data + 2;
+       RSSVAL(p, 0, 0xff80); p += 2;
+       RSSVAL(p, 0, ap_req->length); p += 2;
+       memcpy(p, ap_req->data, ap_req->length); p += ap_req->length;
+       memcpy(p, cipherpw.data, cipherpw.length); p += cipherpw.length;
+       packet->length = PTR_DIFF(p,packet->data);
+       RSSVAL(packet->data, 0, packet->length);
+       
+       return 0;
+}
+
+static krb5_error_code parse_setpw_reply(krb5_context context, 
+                                        krb5_auth_context auth_context,
+                                        krb5_data *packet)
+{
+       krb5_data ap_rep;
+       char *p;
+       int vnum, ret, res_code;
+       krb5_data cipherresult;
+       krb5_data clearresult;
+       krb5_ap_rep_enc_part *ap_rep_enc;
+       krb5_replay_data replay;
+       
+       if (packet->length < 4) {
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       p = packet->data;
+       
+       if (packet->data[0] == 0x7e || packet->data[0] == 0x5e) {
+               /* it's an error packet. We should parse it ... */
+               DEBUG(1,("Got error packet 0x%x from kpasswd server\n",
+                        packet->data[0]));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       if (RSVAL(p, 0) != packet->length) {
+               DEBUG(1,("Bad packet length (%d/%d) from kpasswd server\n",
+                        RSVAL(p, 0), packet->length));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+
+       p += 2;
+
+       vnum = RSVAL(p, 0); p += 2;
+       
+       if (vnum != KRB5_KPASSWD_VERS_SETPW && vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
+               DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));
+               return KRB5KDC_ERR_BAD_PVNO;
+       }
+       
+       ap_rep.length = RSVAL(p, 0); p += 2;
+       
+       if (p + ap_rep.length >= packet->data + packet->length) {
+               DEBUG(1,("ptr beyond end of packet from kpasswd server\n"));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       if (ap_rep.length == 0) {
+               DEBUG(1,("got unencrypted setpw result?!\n"));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+
+       /* verify ap_rep */
+       ap_rep.data = p;
+       p += ap_rep.length;
+       
+       ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
+       if (ret) {
+               DEBUG(1,("failed to rd setpw reply (%s)\n", error_message(ret)));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+       
+       cipherresult.data = p;
+       cipherresult.length = (packet->data + packet->length) - p;
+               
+       ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+                          &replay);
+       if (ret) {
+               DEBUG(1,("failed to decrypt setpw reply (%s)\n", error_message(ret)));
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+
+       if (clearresult.length < 2) {
+               ret = KRB5KRB_AP_ERR_MODIFIED;
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       p = clearresult.data;
+       
+       res_code = RSVAL(p, 0);
+       
+       if ((res_code < KRB5_KPASSWD_SUCCESS) || 
+           (res_code > KRB5_KPASSWD_ACCESSDENIED)) {
+               return KRB5KRB_AP_ERR_MODIFIED;
+       }
+       
+       return 0;
+}
+
+NTSTATUS krb5_set_password(const char *kdc_host, const char *hostname,
+                          const char *realm,  const char *newpw)
+{
+       krb5_context context;
+       krb5_auth_context auth_context = NULL;
+       krb5_principal principal;
+       char *princ_name;
+       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 NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       ret = krb5_cc_default(context, &ccache);
+       if (ret) {
+               DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ZERO_STRUCT(creds);
+       
+       asprintf(&princ_name, "kadmin/changepw@%s", realm);
+       ret = krb5_parse_name(context, princ_name, &creds.server);
+       if (ret) {
+               DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       free(princ_name);
+
+       asprintf(&princ_name, "HOST/%s@%s", hostname, realm);
+       ret = krb5_parse_name(context, princ_name, &principal);
+       if (ret) {
+               DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       free(princ_name);
+
+       krb5_princ_set_realm(context, creds.server,
+                            krb5_princ_realm(context, principal));
+       
+       ret = krb5_cc_get_principal(context, ccache, &creds.client);
+       if (ret) {
+               DEBUG(1,("Failed to get principal from ccache (%s)\n", 
+                        error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+       if (ret) {
+               DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
+                                  NULL, credsp, &ap_req);
+       if (ret) {
+               DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
+       if (sock == -1) {
+               DEBUG(1,("failed to open kpasswd socket to %s (%s)\n", 
+                        kdc_host, strerror(errno)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       addr_len = sizeof(remote_addr);
+       getpeername(sock, &remote_addr, &addr_len);
+       addr_len = sizeof(local_addr);
+       getsockname(sock, &local_addr, &addr_len);
+       
+       remote_kaddr.addrtype = ADDRTYPE_INET;
+       remote_kaddr.length = sizeof(((struct sockaddr_in *)&remote_addr)->sin_addr);
+       remote_kaddr.contents = (char *)&(((struct sockaddr_in *)&remote_addr)->sin_addr);
+       local_kaddr.addrtype = ADDRTYPE_INET;
+       local_kaddr.length = sizeof(((struct sockaddr_in *)&local_addr)->sin_addr);
+       local_kaddr.contents = (char *)&(((struct sockaddr_in *)&local_addr)->sin_addr);
+
+       ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
+       if (ret) {
+               DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ret = build_setpw_request(context, auth_context, &ap_req,
+                                 hostname, realm, newpw, &chpw_req);
+       if (ret) {
+               DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (write(sock, chpw_req.data, chpw_req.length) != chpw_req.length) {
+               DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
+               return NT_STATUS_UNSUCCESSFUL;          
+       }
+
+       free(chpw_req.data);
+
+       chpw_rep.length = 1500;
+       chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+       ret = read(sock, chpw_rep.data, chpw_rep.length);
+       if (ret < 0) {
+               DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
+               return NT_STATUS_UNSUCCESSFUL;          
+       }
+
+       close(sock);
+       chpw_rep.length = ret;
+
+       ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
+       if (ret) {
+               DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", 
+                        error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ret = parse_setpw_reply(context, auth_context, &chpw_rep);
+       free(chpw_rep.data);
+
+       if (ret) {
+               DEBUG(1,("parse_setpw_reply failed (%s)\n", 
+                        error_message(ret)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       return NT_STATUS_OK;
+}
+
+#endif
index 2853dbbaa329e95ff2dbaa8b5bc97424b48d12ec..568e220c0b20dd18d653b98b9c188d6eb4e9137b 100644 (file)
@@ -44,7 +44,7 @@ static char *ads_build_dn(const char *realm)
 
        len = (numdots+1)*4 + strlen(r) + 1;
 
-ret = malloc(len);
+       ret = malloc(len);
        strlcpy(ret,"dc=", len);
        p=strtok(r,"."); 
        strlcat(ret, p, len);
@@ -67,6 +67,25 @@ char *ads_errstr(int rc)
        return ldap_err2string(rc);
 }
 
+/*
+  find the ldap server from DNS
+  this won't work till we add a DNS packet parser. Talk about a 
+  lousy resolv interface! 
+*/
+static char *find_ldap_server(ADS_STRUCT *ads)
+{
+       char *list = NULL;
+
+       if (ldap_domain2hostlist(ads->realm, &list) == LDAP_SUCCESS) {
+               char *p;
+               p = strchr(list, ':');
+               if (p) *p = 0;
+               return list;
+       }
+
+       return NULL;
+}
+
 /*
   initialise a ADS_STRUCT, ready for some ads_ ops
 */
@@ -76,7 +95,8 @@ ADS_STRUCT *ads_init(const char *realm,
 {
        ADS_STRUCT *ads;
        
-       ads = (ADS_STRUCT *)xmalloc(sizeof(*ads));
+       ads = (ADS_STRUCT *)malloc(sizeof(*ads));
+       if (!ads) return NULL;
        memset(ads, 0, sizeof(*ads));
        
        ads->realm = realm? strdup(realm) : NULL;
@@ -84,17 +104,42 @@ ADS_STRUCT *ads_init(const char *realm,
        ads->bind_path = bind_path? strdup(bind_path) : NULL;
        ads->ldap_port = LDAP_PORT;
 
+       if (!ads->realm) {
+               ads->realm = lp_realm();
+       }
        if (!ads->bind_path) {
                ads->bind_path = ads_build_dn(ads->realm);
        }
+       if (!ads->ldap_server) {
+               ads->ldap_server = find_ldap_server(ads);
+       }
+       if (!ads->kdc_server) {
+               /* assume its the same as LDAP */
+               ads->kdc_server = ads->ldap_server? strdup(ads->ldap_server) : NULL;
+       }
 
        return ads;
 }
 
+/*
+  free the memory used by the ADS structure initialized with 'ads_init(...)'
+*/
+void ads_destroy(ADS_STRUCT *ads)
+{
+       if (ads->ld) ldap_unbind(ads->ld);
+       SAFE_FREE(ads->realm);
+       SAFE_FREE(ads->ldap_server);
+       SAFE_FREE(ads->kdc_server);
+       SAFE_FREE(ads->bind_path);
+       ZERO_STRUCTP(ads);
+       free(ads);
+}
 
 /*
   this is a minimal interact function, just enough for SASL to talk
   GSSAPI/kerberos to W2K
+  Error handling is a bit of a problem. I can't see how to get Cyrus-sasl
+  to give sensible errors
 */
 static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in)
 {
@@ -102,7 +147,7 @@ static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in)
 
        while (interact->id != SASL_CB_LIST_END) {
                interact->result = strdup("");
-               interact->len = 0;
+               interact->len = strlen(interact->result);
                interact++;
        }
        
@@ -123,7 +168,8 @@ int ads_connect(ADS_STRUCT *ads)
        }
        ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
 
-       rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL, 0,
+       rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL, 
+                                         LDAP_SASL_QUIET,
                                          sasl_interact, NULL);
 
        return rc;
@@ -290,12 +336,11 @@ int ads_join_realm(ADS_STRUCT *ads, const char *hostname)
 {
        int rc;
        LDAPMessage *res;
-       char *principal;
 
        rc = ads_find_machine_acct(ads, (void **)&res, hostname);
        if (rc == LDAP_SUCCESS && ads_count_replies(ads, res) == 1) {
                DEBUG(0, ("Host account for %s already exists\n", hostname));
-               goto set_password;
+               return LDAP_SUCCESS;
        }
 
        rc = ads_add_machine_acct(ads, hostname);
@@ -311,14 +356,48 @@ int ads_join_realm(ADS_STRUCT *ads, const char *hostname)
                return -1;
        }
 
-set_password:
-       asprintf(&principal, "HOST/%s@%s", hostname, ads->realm);
-#if 0
-       krb5_set_principal_password(principal, ads->ldap_server, hostname, ads->realm);
-#endif
-       free(principal);
+       return LDAP_SUCCESS;
+}
 
+/*
+  delete a machine from the realm
+*/
+int ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
+{
+       int rc;
+       void *res;
+       char *hostnameDN; 
+
+       rc = ads_find_machine_acct(ads, &res, hostname);
+       if (rc != LDAP_SUCCESS || ads_count_replies(ads, res) != 1) {
+           DEBUG(0, ("Host account for %s does not exist.\n", hostname));
+           return -1;
+       }
+
+       hostnameDN = ldap_get_dn(ads->ld, (LDAPMessage *)res);
+       rc = ldap_delete_s(ads->ld, hostnameDN);
+       ldap_memfree(hostnameDN);
+       if (rc != LDAP_SUCCESS) {
+           DEBUG(0, ("ldap_delete_s: %s\n", ads_errstr(rc)));
+           return rc;
+       }
+
+       rc = ads_find_machine_acct(ads, &res, hostname);
+       if (rc == LDAP_SUCCESS && ads_count_replies(ads, res) == 1 ) {
+           DEBUG(0, ("Failed to remove host account.\n"));
+           /*hmmm, we need NTSTATUS */
+           return -1;
+       }
+       
        return LDAP_SUCCESS;
 }
 
+
+NTSTATUS ads_set_machine_password(ADS_STRUCT *ads,
+                                 const char *hostname, 
+                                 const char *password)
+{
+       return krb5_set_password(ads->kdc_server, hostname, ads->realm, password);
+}
+
 #endif
index b4ce271235ed7c6df9e5d2d5972f8ae1ab02da4b..37b92b8d99f102d8c2652ad9106e41b498b697fe 100644 (file)
@@ -95,6 +95,7 @@ DATA_BLOB krb5_get_ticket(char *principal)
        krb5_context context;
        krb5_auth_context auth_context = NULL;
        DATA_BLOB ret;
+       krb5_enctype enc_types[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
 
        retval = krb5_init_context(&context);
        if (retval) {
@@ -109,6 +110,12 @@ DATA_BLOB krb5_get_ticket(char *principal)
                goto failed;
        }
 
+       if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
+               DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
+                        error_message(retval)));
+               goto failed;
+       }
+
        if ((retval = krb5_mk_req2(context, 
                                   &auth_context, 
                                   0, 
index ab17f90a6ef8b352d847f284920d4fd0b4c2ec24..548dd837690e9c5e0785f7a27fd71970f5b33b93 100644 (file)
@@ -114,6 +114,7 @@ typedef struct
        char *szSocketOptions;
        char *szWorkGroup;
        char *szRealm;
+       char *szADSserver;
        char **szDomainAdminGroup;
        char **szDomainGuestGroup;
        char *szUsernameMap;
@@ -650,6 +651,7 @@ static struct parm_struct parm_table[] = {
        {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, 0},
        {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkGroup, NULL, NULL, FLAG_BASIC},
        {"realm", P_USTRING, P_GLOBAL, &Globals.szRealm, NULL, NULL, FLAG_BASIC},
+       {"ADS server", P_STRING, P_GLOBAL, &Globals.szADSserver, NULL, NULL, FLAG_BASIC},
        {"netbios name", P_UGSTRING, P_GLOBAL, global_myname, handle_netbios_name, NULL, FLAG_BASIC},
        {"netbios aliases", P_LIST, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL, 0},
        {"netbios scope", P_UGSTRING, P_GLOBAL, global_scope, NULL, NULL, 0},
@@ -1459,6 +1461,7 @@ FN_GLOBAL_STRING(lp_passwordserver, &Globals.szPasswordServer)
 FN_GLOBAL_STRING(lp_name_resolve_order, &Globals.szNameResolveOrder)
 FN_GLOBAL_STRING(lp_workgroup, &Globals.szWorkGroup)
 FN_GLOBAL_STRING(lp_realm, &Globals.szRealm)
+FN_GLOBAL_STRING(lp_ads_server, &Globals.szADSserver)
 FN_GLOBAL_STRING(lp_username_map, &Globals.szUsernameMap)
 #ifdef USING_GROUPNAME_MAP
 FN_GLOBAL_STRING(lp_groupname_map, &Globals.szGroupnameMap)
index 86ef024bb0bbf22c1c7d1a426edc0fce0ca78c13..9002c23d1bbc9a8aeb281d9f6dc3716d2e4e39d5 100644 (file)
@@ -1,8 +1,7 @@
 /* 
    Unix SMB/Netbios implementation.
    Version 3.0.
-   Samba registry functions
-   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Andrew Tridgell 1992-2001
    
    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
@@ -53,7 +52,7 @@ void *secrets_fetch(char *key, size_t *size)
 {
        TDB_DATA kbuf, dbuf;
        if (!tdb)
-               return False;
+               return NULL;
        kbuf.dptr = key;
        kbuf.dsize = strlen(key);
        dbuf = tdb_fetch(tdb, kbuf);
@@ -142,8 +141,18 @@ BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16],
                                          time_t *pass_last_set_time)
 {
        struct machine_acct_pass *pass;
+       char *plaintext;
        size_t size;
 
+       plaintext = secrets_fetch_machine_password();
+       if (plaintext) {
+               /* we have an ADS password - use that */
+               DEBUG(4,("Using ADS machine password\n"));
+               E_md4hash((uchar *)plaintext, ret_pwd);
+               SAFE_FREE(plaintext);
+               return True;
+       }
+
        if (!(pass = secrets_fetch(trust_keystr(domain), &size)) || 
            size != sizeof(*pass))
                return False;
@@ -168,6 +177,27 @@ BOOL secrets_store_trust_account_password(char *domain, uint8 new_pwd[16])
        return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass));
 }
 
+/************************************************************************
+ Routine to set the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+BOOL secrets_store_machine_password(char *pass)
+{
+       return secrets_store(SECRETS_MACHINE_PASSWORD, pass, strlen(pass)+1);
+}
+
+
+/************************************************************************
+ Routine to fetch the plaintext machine account password for a realm
+the password is assumed to be a null terminated ascii string
+************************************************************************/
+char *secrets_fetch_machine_password(void)
+{
+       return (char *)secrets_fetch(SECRETS_MACHINE_PASSWORD, NULL);
+}
+
+
+
 /************************************************************************
  Routine to delete the trust account password file for a domain.
 ************************************************************************/
index 8e022ac1f6c118038cb9eb561157fda7ccb897ed..b03f9ff213dd37b9a427ef37e0e6419d161c2cbc 100644 (file)
@@ -2464,8 +2464,7 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
 {
        pstring key;
        NT_PRINTER_INFO_LEVEL_2 info;
-       int             len = 0,
-                       devmode_length = 0;
+       int             len = 0;
        TDB_DATA kbuf, dbuf;
        fstring printername;
                
index 9e1ab7be1b9d6f4a6e0522d3cbd90f156680d3ba..ef9518a7fc4da2c5921f460f9e34b2262d041ad7 100644 (file)
@@ -426,8 +426,6 @@ static NTSTATUS cmd_lsa_lookupprivvalue(struct cli_state *cli,
 {
        POLICY_HND pol;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       
-       DOM_SID sid;
        LUID luid;
 
        if (argc != 2 ) {
index c1a9e405b2c167bc441bf5b2947dbde788c69540..f927d273bdafc21728195d5a780d06337ec8c59f 100644 (file)
@@ -122,7 +122,7 @@ END {
     gotstart = 1;
   }
 
-  if( $0 ~ /^DATA_BLOB|^ASN1_DATA|^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum.*\(|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) {
+  if( $0 ~ /^ADS_STRUCT|^DATA_BLOB|^ASN1_DATA|^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element|^NT_DEVICEMODE|^enum.*\(|^NT_USER_TOKEN|^SAM_ACCOUNT/ ) {
     gotstart = 1;
   }
 
index c9db35956992646578abe152f3c3a33b4e04f500..854513bb474b2742fe860fe6a3b71012a9dc9d4b 100644 (file)
@@ -73,16 +73,12 @@ static int reply_spnego_kerberos(connection_struct *conn,
                                 DATA_BLOB *secblob)
 {
        DATA_BLOB ticket;
-       krb5_context context;
-       krb5_auth_context auth_context = NULL;
-       krb5_keytab keytab = NULL;
-       krb5_data packet;
-       krb5_ticket *tkt = NULL;
-       int ret;
        char *realm, *client, *p;
        const struct passwd *pw;
        char *user;
        int sess_vuid;
+       NTSTATUS ret;
+       DATA_BLOB auth_data;
        auth_serversupplied_info *server_info = NULL;
 
        realm = lp_realm();
@@ -91,38 +87,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       ret = krb5_init_context(&context);
-       if (ret) {
-               DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
-
-       packet.length = ticket.length;
-       packet.data = (krb5_pointer)ticket.data;
-
-#if 0
-       file_save("/tmp/ticket.dat", ticket.data, ticket.length);
-#endif
-
-       if ((ret = krb5_rd_req(context, &auth_context, &packet, 
-                              NULL, keytab, NULL, &tkt))) {
-               DEBUG(3,("krb5_rd_req failed (%s)\n", 
-                        error_message(ret)));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
-
-#if 0
-       if (tkt->enc_part2) {
-               file_save("/tmp/authdata.dat", 
-                         tkt->enc_part2->authorization_data[0]->contents,
-                         tkt->enc_part2->authorization_data[0]->length);
-       }
-#endif
-
-       if ((ret = krb5_unparse_name(context, tkt->enc_part2->client,
-                                    &client))) {
-               DEBUG(3,("krb5_unparse_name failed (%s)\n", 
-                        error_message(ret)));
+       ret = ads_verify_ticket(&ticket, &client, &auth_data);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(1,("Failed to verify incoming ticket!\n"));
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
index 1b116b6534540d750a3012e2c4ed0a045ad78e5c..d1d63fe2af689334b3da6aaf4677ba5f0de6fc9e 100644 (file)
 
 #include <includes.h>
 
-struct functable {
-       char *funcname;
-       int (*fn)();
-};
-
 /***********************************************************************/
 /* Beginning of internationalization section.  Translatable constants  */
 /* should be kept in this area and referenced in the rest of the code. */
@@ -315,8 +310,8 @@ static struct in_addr dest_ip;
   run a function from a function table. If not found then
   call the specified usage function 
 */
-static int run_function(int argc, const char **argv, struct functable *table, 
-                       int (*usage_fn)(void))
+int net_run_function(int argc, const char **argv, struct functable *table, 
+                    int (*usage_fn)(void))
 {
        int i;
        if (argc < 1) {
@@ -506,16 +501,9 @@ static BOOL make_ipc_connection(unsigned flags)
        return True;
 }
 
-static int net_usage(void)
-{
-       d_printf(NET_USAGE);
-       return -1;
-}
 
-static int file_usage(void)
+static int general_usage(void)
 {
-       d_printf(NET_FILE_USAGE); /* command syntax */
-       
        d_printf(TARGET_USAGE, LOCAL_HOST); /* target options */
        d_printf(SERVER_USAGE);
        d_printf(IPADDRESS_USAGE);
@@ -530,6 +518,20 @@ static int file_usage(void)
        return -1;
 }
 
+static int net_usage(void)
+{
+       d_printf(NET_USAGE);
+       return -1;
+}
+
+static int file_usage(void)
+{
+       d_printf(NET_FILE_USAGE); /* command syntax */
+
+       general_usage();
+       return -1;
+}
+
 
 
 
@@ -594,26 +596,13 @@ static int net_file(int argc, const char **argv)
                return cli_NetFileEnum(cli, NULL, NULL, file_fn);
        }
 
-       return run_function(argc, argv, func, file_usage);
+       return net_run_function(argc, argv, func, file_usage);
 }
                       
 static int share_usage(void)
 {
        d_printf(NET_SHARE_USAGE); /* command syntax */
-       
-       d_printf(TARGET_USAGE, LOCAL_HOST); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(COMMENT_USAGE);
-       d_printf(MAXUSERS_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -686,7 +675,7 @@ static int net_share(int argc, const char **argv)
                return cli_RNetShareEnum(cli, share_fn, NULL);
        }
 
-       return run_function(argc, argv, func, share_usage);
+       return net_run_function(argc, argv, func, share_usage);
 }
                    
                
@@ -694,17 +683,7 @@ static int session_usage(void)
 {
        d_printf(NET_SESSION_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, LOCAL_HOST); /* Target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* Misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
     
@@ -781,7 +760,7 @@ static int net_session(int argc, const char **argv)
                return cli_NetSessionEnum(cli, list_sessions_func);
        }
 
-       return run_function(argc, argv, func, session_usage);
+       return net_run_function(argc, argv, func, session_usage);
 }
        
 /****************************************************************************
@@ -797,18 +776,7 @@ static int server_usage(void)
 {
        d_printf(NET_SERVER_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, DOMAIN_MASTER); /* Target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* Misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
                    
@@ -823,17 +791,7 @@ static int domain_usage(void)
 {
        d_printf(NET_DOMAIN_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, GLBL_LCL_MASTER); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -849,18 +807,7 @@ static int printq_usage(void)
 {
        d_printf(NET_PRINTQ_USAGE);
        
-       d_printf(TARGET_USAGE, LOCAL_HOST);
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE);
-       d_printf(PORT_USAGE);
-       d_printf(JOBID_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }      
 
@@ -949,7 +896,7 @@ static int net_printq(int argc, const char **argv)
                return cli_NetPrintQEnum(cli, enum_queue, enum_jobs);
        }
 
-       return run_function(argc, argv, func, printq_usage);
+       return net_run_function(argc, argv, func, printq_usage);
 }
 
        
@@ -957,20 +904,7 @@ static int user_usage(void)
 {
        d_printf(NET_USER_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, LOCAL_HOST); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(COMMENT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
-       d_printf(LONG_USAGE);
+       general_usage();
        return -1;
 } 
        
@@ -1047,7 +981,7 @@ int net_user(int argc, const char **argv)
                return cli_RNetUserEnum(cli, user_fn, NULL); 
        }
 
-       return run_function(argc, argv, func, user_usage);
+       return net_run_function(argc, argv, func, user_usage);
 }
 
 
@@ -1055,20 +989,7 @@ static int group_usage(void)
 {
        d_printf(NET_GROUP_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, LOCAL_HOST); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(COMMENT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       d_printf(CONF_USAGE);
-       d_printf(LONG_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1122,25 +1043,14 @@ static int net_group(int argc, const char **argv)
                return cli_RNetGroupEnum(cli, group_fn, NULL); 
        }
 
-       return run_function(argc, argv, func, group_usage);
+       return net_run_function(argc, argv, func, group_usage);
 }
 
 static int groupmember_usage(void)
 {
        d_printf(NET_GROUPMEMBER_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, LOCAL_HOST); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1181,25 +1091,14 @@ static int net_groupmember(int argc, const char **argv)
                {NULL, NULL}
        };
        
-       return run_function(argc, argv, func, groupmember_usage);
+       return net_run_function(argc, argv, func, groupmember_usage);
 }
 
 static int validate_usage(void)
 {
        d_printf(NET_VALIDATE_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, GLBL_LCL_MASTER); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1213,17 +1112,7 @@ static int service_usage(void)
 {
        d_printf(NET_SERVICE_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, GLBL_LCL_MASTER); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1257,25 +1146,14 @@ static int net_service(int argc, const char **argv)
                return cli_RNetServiceEnum(cli, group_fn, NULL); 
        }
 
-       return run_function(argc, argv, func, service_usage);
+       return net_run_function(argc, argv, func, service_usage);
 }
 
 static int password_usage(void)
 {
        d_printf(NET_PASSWORD_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, GLBL_LCL_MASTER); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1294,18 +1172,7 @@ static int admin_usage(void)
 {
        d_printf(NET_ADMIN_USAGE); /* command syntax */
        
-       d_printf(TARGET_USAGE, GLBL_LCL_MASTER); /* target options */
-       d_printf(SERVER_USAGE);
-       d_printf(IPADDRESS_USAGE);
-       d_printf(WORKGROUP_USAGE);
-       
-       d_printf(MISC_OPT_USAGE); /* misc options */
-       d_printf(PORT_USAGE);
-       d_printf(MYWORKGROUP_USAGE);
-       d_printf(DEBUG_USAGE);
-       d_printf(MYNAME_USAGE);
-       d_printf(USER_USAGE);
-       d_printf(CONF_USAGE);
+       general_usage();
        return -1;
 }
 
@@ -1316,18 +1183,6 @@ static int net_admin(int argc, const char **argv)
        return 0;
 }
 
-static int join_usage(void)
-{
-       d_printf(ERRMSG_NOT_IMPLEMENTED);
-       return -1;
-}
-
-static int net_join(int argc, const char **argv)
-{
-       d_printf(ERRMSG_NOT_IMPLEMENTED);
-       return 0;
-}
-
 static int help_usage(void)
 {
        d_printf("\n"\
@@ -1358,10 +1213,10 @@ static int net_help(int argc, const char **argv)
                {"ADMIN", admin_usage},
                {"SERVICE", service_usage},
                {"PASSWORD", password_usage},
-               {"JOIN", join_usage},
+               {"JOIN", net_join_usage},
                {NULL, NULL}};
 
-       return run_function(argc, argv, func, help_usage);
+       return net_run_function(argc, argv, func, help_usage);
 };
 
 /* main function table */
@@ -1397,6 +1252,7 @@ int main(int argc,char *argv[])
        const char ** argv_new;
        poptContext pc;
        char *servicesf = dyn_CONFIGFILE;
+       extern pstring global_myname;
 
        struct poptOption long_options[] = {
                {"help",        'h', POPT_ARG_NONE,   0,     'h'},
@@ -1479,10 +1335,17 @@ int main(int argc,char *argv[])
        if (!opt_workgroup) {
                opt_workgroup = lp_workgroup();
        }
+
+       if (!*global_myname) {
+               char *p;
+               fstrcpy(global_myname, myhostname());
+               p = strchr_m(global_myname, '.');
+               if (p) *p = 0;
+       }
        
        load_interfaces();
 
-       rc = run_function(argc_new-1, argv_new+1, net_func, net_usage);
+       rc = net_run_function(argc_new-1, argv_new+1, net_func, net_usage);
        
        DEBUG(2,("return code = %d\n", rc));
        return rc;
diff --git a/source/utils/net_join.c b/source/utils/net_join.c
new file mode 100644 (file)
index 0000000..793d72a
--- /dev/null
@@ -0,0 +1,143 @@
+/* 
+   Samba Unix/Linux SMB client library 
+   Version 3.0
+   join a realm
+   Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.  
+*/
+
+#include "includes.h"
+
+#if HAVE_ADS
+
+/* a lame random number generator - used /dev/urandom if possible */
+static unsigned one_random(void)
+{
+       int fd = -1;
+       static int initialised;
+       unsigned ret;
+
+       if (!initialised) {
+               initialised = 1;
+               fd = open("/dev/urandom", O_RDONLY);
+               srandom(time(NULL) ^ getpid());
+       }
+
+       if (fd == -1) {
+               return random();
+       }
+
+       read(fd, &ret, sizeof(ret));
+       return ret;
+}
+
+/*
+ * Generate a simple random password of 15 chars - not a cryptographic one
+ */
+static char *generate_random_password(int len)
+{
+       int i;
+       char *pass;
+
+       if (!(pass = malloc(len+1)))
+               return NULL;
+
+       for (i=0; i<len; ) {
+               char c = one_random() & 0x7f;
+               if (!isalnum(c) && !ispunct(c)) continue;
+               pass[i++] = c;
+       }
+       
+       return pass;
+}
+
+
+int net_join_usage(void)
+{
+       d_printf("\nnet join"\
+                "\n\tjoins the local machine to a ADS realm\n");
+       return -1;
+}
+
+int net_join(int argc, const char **argv)
+{
+       char *ldap_host;
+       char *hostname;
+       char *realm;
+       ADS_STRUCT *ads;
+       int rc;
+       char *password;
+       extern pstring global_myname;
+       NTSTATUS status;
+
+       hostname = strdup(global_myname);
+       strlower(hostname);
+       realm = lp_realm();
+       ldap_host = lp_ads_server();
+       if (!*ldap_host) ldap_host = NULL;
+       if (!*realm) realm = NULL;
+
+       if (!secrets_init()) {
+               DEBUG(1,("Failed to initialise secrets database\n"));
+               return -1;
+       }
+
+       password = generate_random_password(15);
+
+       ads = ads_init(realm, ldap_host, NULL);
+
+       rc = ads_connect(ads);
+       if (rc) {
+               d_printf("ads_connect: %s\n", ads_errstr(rc));
+               return -1;
+       }
+
+       rc = ads_join_realm(ads, hostname);
+       if (rc) {
+               d_printf("ads_join_realm: %s\n", ads_errstr(rc));
+               return -1;
+       }
+
+       status = ads_set_machine_password(ads, hostname, password);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("ads_set_machine_password: %s\n", get_nt_error_msg(status));
+               return -1;
+       }
+
+       if (!secrets_store_machine_password(password)) {
+               DEBUG(1,("Failed to save machine password\n"));
+               return -1;
+       }
+
+       d_printf("Joined %s to realm %s\n", hostname, realm);
+
+       return 0;
+}
+
+#else
+
+int net_join_usage(void)
+{
+       d_printf("ADS support not compiled in\n");
+       return -1;
+}
+
+int net_join(int argc, const char **argv)
+{
+       return net_join_usage();
+}
+
+#endif