diff options
-rw-r--r-- | source3/CodingSuggestions | 17 | ||||
-rw-r--r-- | source3/Makefile.in | 10 | ||||
-rw-r--r-- | source3/client/client.c | 2 | ||||
-rw-r--r-- | source3/groupdb/mapping.c | 4 | ||||
-rw-r--r-- | source3/include/includes.h | 7 | ||||
-rw-r--r-- | source3/include/secrets.h | 6 | ||||
-rw-r--r-- | source3/lib/util_sock.c | 31 | ||||
-rw-r--r-- | source3/libads/kerberos.c | 149 | ||||
-rw-r--r-- | source3/libads/krb5_setpw.c | 352 | ||||
-rw-r--r-- | source3/libads/ldap.c | 103 | ||||
-rw-r--r-- | source3/libsmb/clikrb5.c | 7 | ||||
-rw-r--r-- | source3/param/loadparm.c | 3 | ||||
-rw-r--r-- | source3/passdb/secrets.c | 36 | ||||
-rw-r--r-- | source3/printing/nt_printing.c | 3 | ||||
-rw-r--r-- | source3/rpcclient/cmd_lsarpc.c | 2 | ||||
-rw-r--r-- | source3/script/mkproto.awk | 2 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 43 | ||||
-rw-r--r-- | source3/utils/net.c | 233 | ||||
-rw-r--r-- | source3/utils/net_join.c | 143 |
19 files changed, 902 insertions, 251 deletions
diff --git a/source3/CodingSuggestions b/source3/CodingSuggestions index 60a358919a..48c51281f5 100644 --- a/source3/CodingSuggestions +++ b/source3/CodingSuggestions @@ -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 diff --git a/source3/Makefile.in b/source3/Makefile.in index 6b3b337a12..8a29a1f0ff 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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) diff --git a/source3/client/client.c b/source3/client/client.c index 7baab4b204..c684f3fea6 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -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); diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index 92a98ff7a4..c39bb8cdff 100644 --- a/source3/groupdb/mapping.c +++ b/source3/groupdb/mapping.c @@ -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]; diff --git a/source3/include/includes.h b/source3/include/includes.h index 8b61bc573c..adae49ddea 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -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 diff --git a/source3/include/secrets.h b/source3/include/secrets.h index 9abc3637e8..5990170ccc 100644 --- a/source3/include/secrets.h +++ b/source3/include/secrets.h @@ -22,7 +22,13 @@ #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" diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 340a83cf13..045e18ac22 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -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/source3/libads/kerberos.c b/source3/libads/kerberos.c new file mode 100644 index 0000000000..e4e946f0ce --- /dev/null +++ b/source3/libads/kerberos.c @@ -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/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c new file mode 100644 index 0000000000..5cb3de1bb5 --- /dev/null +++ b/source3/libads/krb5_setpw.c @@ -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 diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 2853dbbaa3..568e220c0b 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -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); @@ -68,6 +68,25 @@ char *ads_errstr(int 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 */ ADS_STRUCT *ads_init(const char *realm, @@ -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 diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index b4ce271235..37b92b8d99 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -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, diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index ab17f90a6e..548dd83769 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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) diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 86ef024bb0..9002c23d1b 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -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; @@ -169,6 +178,27 @@ BOOL secrets_store_trust_account_password(char *domain, uint8 new_pwd[16]) } /************************************************************************ + 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. ************************************************************************/ diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 8e022ac1f6..b03f9ff213 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -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; diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 9e1ab7be1b..ef9518a7fc 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -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 ) { diff --git a/source3/script/mkproto.awk b/source3/script/mkproto.awk index c1a9e405b2..f927d273bd 100644 --- a/source3/script/mkproto.awk +++ b/source3/script/mkproto.awk @@ -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; } diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index c9db359569..854513bb47 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -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); } diff --git a/source3/utils/net.c b/source3/utils/net.c index 1b116b6534..d1d63fe2af 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -37,11 +37,6 @@ #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/source3/utils/net_join.c b/source3/utils/net_join.c new file mode 100644 index 0000000000..793d72ac7e --- /dev/null +++ b/source3/utils/net_join.c @@ -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 |