From 64355e40a8b3545f28da465241b772fbd80d48ce Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Thu, 20 Jul 2006 19:44:11 +0000 Subject: r17161: sync files from SAMBA_3_0_23 branch --- source/auth/auth_util.c | 3 +- source/nsswitch/winbindd_group.c | 8 +- source/nsswitch/winbindd_util.c | 28 +++++-- source/passdb/pdb_interface.c | 29 ++++++- source/passdb/pdb_ldap.c | 14 +++- source/passdb/pdb_tdb.c | 20 +++-- source/rpc_server/srv_samr_nt.c | 32 ++++++-- source/smbd/open.c | 160 ++++++++++++++++--------------------- source/utils/net_ads.c | 168 ++++++++++++++++++++++++++++++--------- 9 files changed, 306 insertions(+), 156 deletions(-) diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c index 493d7393d07..5298560ba43 100644 --- a/source/auth/auth_util.c +++ b/source/auth/auth_util.c @@ -955,7 +955,8 @@ NTSTATUS create_local_token(auth_serversupplied_info *server_info) return NT_STATUS_NO_MEMORY; } - if (server_info->was_mapped) { + if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) || + server_info->was_mapped) { status = create_token_from_username(server_info, server_info->unix_name, server_info->guest, diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c index c0da45d8d03..5528b6c78e4 100644 --- a/source/nsswitch/winbindd_group.c +++ b/source/nsswitch/winbindd_group.c @@ -42,7 +42,7 @@ static BOOL fill_grent(struct winbindd_gr *gr, const char *dom_name, { fstring full_group_name; - fill_domain_username( full_group_name, dom_name, gr_name, False); + fill_domain_username( full_group_name, dom_name, gr_name, True ); gr->gr_gid = unix_gid; @@ -146,7 +146,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, /* Append domain name */ - fill_domain_username(name, domain->name, the_name, False); + fill_domain_username(name, domain->name, the_name, True); len = strlen(name); @@ -752,7 +752,7 @@ void winbindd_getgrent(struct winbindd_cli_state *state) /* Fill in group entry */ fill_domain_username(domain_group_name, ent->domain_name, - name_list[ent->sam_entry_index].acct_name, False); + name_list[ent->sam_entry_index].acct_name, True); result = fill_grent(&group_list[group_list_ndx], ent->domain_name, @@ -929,7 +929,7 @@ void winbindd_list_groups(struct winbindd_cli_state *state) groups.sam_entries)[i].acct_name; fstring name; - fill_domain_username(name, domain->name, group_name, False); + fill_domain_username(name, domain->name, group_name, True); /* Append to extra data */ memcpy(&extra_data[extra_data_len], name, strlen(name)); diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index 67b94817adb..7e7ada52d73 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -812,14 +812,28 @@ BOOL is_in_gid_range(gid_t gid) /* Is this a domain which we may assume no DOMAIN\ prefix? */ -static BOOL assume_domain(const char *domain) { - if ((lp_winbind_use_default_domain() - || lp_winbind_trusted_domains_only()) && - strequal(lp_workgroup(), domain)) - return True; +static BOOL assume_domain(const char *domain) +{ + /* never assume the domain on a standalone server */ + + if ( lp_server_role() == ROLE_STANDALONE ) + return False; + + /* domain member servers may possibly assume for the domain name */ + + if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) { + if ( !strequal(lp_workgroup(), domain) ) + return False; + + if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() ) + return True; + } + + /* only left with a domain controller */ - if (strequal(get_global_sam_name(), domain)) + if ( strequal(get_global_sam_name(), domain) ) { return True; + } return False; } @@ -832,7 +846,7 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user) if ( !p ) { fstrcpy(user, domuser); - + if ( assume_domain(lp_workgroup())) { fstrcpy(domain, lp_workgroup()); } else { diff --git a/source/passdb/pdb_interface.c b/source/passdb/pdb_interface.c index 5d70c2c1227..3e47c97b04c 100644 --- a/source/passdb/pdb_interface.c +++ b/source/passdb/pdb_interface.c @@ -344,6 +344,7 @@ static NTSTATUS pdb_default_create_user(struct pdb_methods *methods, if ( !(pwd = Get_Pwnam_alloc(tmp_ctx, name)) ) { pstring add_script; int add_ret; + fstring name2; if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') { pstrcpy(add_script, lp_adduser_script()); @@ -357,7 +358,11 @@ static NTSTATUS pdb_default_create_user(struct pdb_methods *methods, return NT_STATUS_NO_SUCH_USER; } - all_string_sub(add_script, "%u", name, sizeof(add_script)); + /* lowercase the username before creating the Unix account for + compatibility with previous Samba releases */ + fstrcpy( name2, name ); + strlower_m( name2 ); + all_string_sub(add_script, "%u", name2, sizeof(add_script)); add_ret = smbrun(add_script,NULL); DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret)); @@ -383,6 +388,10 @@ static NTSTATUS pdb_default_create_user(struct pdb_methods *methods, return NT_STATUS_INTERNAL_ERROR; } + /* Use the username case specified in the original request */ + + pdb_set_username( sam_pass, name, PDB_SET ); + /* Disable the account on creation, it does not have a reasonable password yet. */ acb_info |= ACB_DISABLED; @@ -435,6 +444,7 @@ static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods, struct samu *sam_acct) { NTSTATUS status; + fstring username; status = pdb_delete_sam_account(sam_acct); if (!NT_STATUS_IS_OK(status)) { @@ -447,7 +457,14 @@ static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods, * not necessary present and maybe the sysadmin doesn't want to delete * the unix side */ - smb_delete_user( pdb_get_username(sam_acct) ); + + /* always lower case the username before handing it off to + external scripts */ + + fstrcpy( username, pdb_get_username(sam_acct) ); + strlower_m( username ); + + smb_delete_user( username ); return status; } @@ -504,6 +521,7 @@ NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname) { struct pdb_methods *pdb = pdb_get_methods(); uid_t uid; + NTSTATUS status; if (csamuser != NULL) { TALLOC_FREE(csamuser); @@ -520,7 +538,12 @@ NTSTATUS pdb_rename_sam_account(struct samu *oldname, const char *newname) return NT_STATUS_ACCESS_DENIED; } - return pdb->rename_sam_account(pdb, oldname, newname); + status = pdb->rename_sam_account(pdb, oldname, newname); + + /* always flush the cache here just to be safe */ + flush_pwnam_cache(); + + return status; } NTSTATUS pdb_update_login_attempts(struct samu *sam_acct, BOOL success) diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c index 4a9794e1861..e4486226264 100644 --- a/source/passdb/pdb_ldap.c +++ b/source/passdb/pdb_ldap.c @@ -1830,6 +1830,7 @@ static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods, const char *oldname; int rc; pstring rename_script; + fstring oldname_lower, newname_lower; if (!old_acct) { DEBUG(0, ("ldapsam_rename_sam_account: old_acct was NULL!\n")); @@ -1851,10 +1852,17 @@ static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods, DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n", oldname, newname)); - /* we have to allow the account name to end with a '$' */ - string_sub2(rename_script, "%unew", newname, sizeof(pstring), + /* We have to allow the account name to end with a '$'. + Also, follow the semantics in _samr_create_user() and lower case the + posix name but preserve the case in passdb */ + + fstrcpy( oldname_lower, oldname ); + strlower_m( oldname_lower ); + fstrcpy( newname_lower, newname ); + strlower_m( newname_lower ); + string_sub2(rename_script, "%unew", newname_lower, sizeof(pstring), True, False, True); - string_sub2(rename_script, "%uold", oldname, sizeof(pstring), + string_sub2(rename_script, "%uold", oldname_lower, sizeof(pstring), True, False, True); rc = smbrun(rename_script, NULL); diff --git a/source/passdb/pdb_tdb.c b/source/passdb/pdb_tdb.c index f3ae4b7b02e..45fdd12b273 100644 --- a/source/passdb/pdb_tdb.c +++ b/source/passdb/pdb_tdb.c @@ -1388,6 +1388,8 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods, pstring rename_script; BOOL interim_account = False; int rename_ret; + fstring oldname_lower; + fstring newname_lower; /* can't do anything without an external script */ @@ -1431,11 +1433,19 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods, goto done; } - /* rename the posix user */ - string_sub2(rename_script, "%unew", newname, sizeof(pstring), - True, False, True); - string_sub2(rename_script, "%uold", pdb_get_username(old_acct), - sizeof(pstring), True, False, True); + /* Rename the posix user. Follow the semantics of _samr_create_user() + so that we lower case the posix name but preserve the case in passdb */ + + fstrcpy( oldname_lower, pdb_get_username(old_acct) ); + strlower_m( oldname_lower ); + + fstrcpy( newname_lower, newname ); + strlower_m( newname_lower ); + + string_sub2(rename_script, "%unew", newname_lower, sizeof(pstring), + True, False, True); + string_sub2(rename_script, "%uold", oldname_lower, sizeof(pstring), + True, False, True); rename_ret = smbrun(rename_script, NULL); DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret)); diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c index da2bb8c3b56..7422b18d46e 100644 --- a/source/rpc_server/srv_samr_nt.c +++ b/source/rpc_server/srv_samr_nt.c @@ -2463,8 +2463,6 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, return NT_STATUS_NO_MEMORY; } - strlower_m(account); - nt_status = can_create(p->mem_ctx, account); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; @@ -3203,7 +3201,7 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) { - DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n")); + DEBUG(5, ("Changing trust account. Not updating /etc/passwd\n")); } else { /* update the UNIX password */ if (lp_unix_password_sync() ) { @@ -3385,10 +3383,25 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE if (!get_lsa_policy_samr_sid(p, pol, &sid, &acc_granted, &disp_info)) return NT_STATUS_INVALID_HANDLE; - /* observed when joining an XP client to a Samba domain */ + /* This is tricky. A WinXP domain join sets + (SA_RIGHT_USER_SET_PASSWORD|SA_RIGHT_USER_SET_ATTRIBUTES|SA_RIGHT_USER_ACCT_FLAGS_EXPIRY) + The MMC lusrmgr plugin includes these perms and more in the SamrOpenUser(). But the + standard Win32 API calls just ask for SA_RIGHT_USER_SET_PASSWORD in the SamrOpenUser(). + This should be enough for levels 18, 24, 25,& 26. Info level 23 can set more so + we'll use the set from the WinXP join as the basis. */ + + switch (switch_value) { + case 18: + case 24: + case 25: + case 26: + acc_required = SA_RIGHT_USER_SET_PASSWORD; + break; + default: + acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY; + break; + } - acc_required = SA_RIGHT_USER_SET_PASSWORD | SA_RIGHT_USER_SET_ATTRIBUTES | SA_RIGHT_USER_ACCT_FLAGS_EXPIRY; - if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, acc_required, "_samr_set_userinfo"))) { return r_u->status; } @@ -4027,6 +4040,7 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM BOOL can_add_accounts; uint32 acb_info; DISP_INFO *disp_info = NULL; + BOOL ret; DEBUG(5, ("_samr_delete_dom_user: %d\n", __LINE__)); @@ -4046,7 +4060,11 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM return NT_STATUS_NO_MEMORY; } - if(!pdb_getsampwsid(sam_pass, &user_sid)) { + become_root(); + ret = pdb_getsampwsid(sam_pass, &user_sid); + unbecome_root(); + + if( !ret ) { DEBUG(5,("_samr_delete_dom_user:User %s doesn't exist.\n", sid_string_static(&user_sid))); TALLOC_FREE(sam_pass); diff --git a/source/smbd/open.c b/source/smbd/open.c index 94441c5df9b..a3c3cc4fc95 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -185,7 +185,8 @@ static BOOL open_file(files_struct *fsp, SMB_STRUCT_STAT *psbuf, int flags, mode_t unx_mode, - uint32 access_mask) + uint32 access_mask, /* client requested access mask. */ + uint32 open_access_mask) /* what we're actually using in the open. */ { int accmode = (flags & O_ACCMODE); int local_flags = flags; @@ -239,7 +240,7 @@ static BOOL open_file(files_struct *fsp, local_flags = (flags & ~O_ACCMODE)|O_RDWR; } - if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || + if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || (!file_existed && (local_flags & O_CREAT)) || ((local_flags & O_TRUNC) == O_TRUNC) ) { @@ -1112,6 +1113,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, uint16 mid = get_current_mid(); struct timeval request_time = timeval_zero(); struct share_mode_lock *lck = NULL; + uint32 open_access_mask = access_mask; NTSTATUS status; if (conn->printer) { @@ -1202,12 +1204,14 @@ files_struct *open_file_ntcreate(connection_struct *conn, /* If file exists replace/overwrite. If file doesn't * exist create. */ flags2 |= (O_CREAT | O_TRUNC); + open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ break; case FILE_OVERWRITE_IF: /* If file exists replace/overwrite. If file doesn't * exist create. */ flags2 |= (O_CREAT | O_TRUNC); + open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ break; case FILE_OPEN: @@ -1234,6 +1238,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, return NULL; } flags2 |= O_TRUNC; + open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ break; case FILE_CREATE: @@ -1286,7 +1291,10 @@ files_struct *open_file_ntcreate(connection_struct *conn, /* This is a nasty hack - must fix... JRA. */ if (access_mask == MAXIMUM_ALLOWED_ACCESS) { - access_mask = FILE_GENERIC_ALL; + open_access_mask = access_mask = FILE_GENERIC_ALL; + if (flags2 & O_TRUNC) { + open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ + } } /* @@ -1351,7 +1359,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, fsp->inode = psbuf->st_ino; fsp->share_access = share_access; fsp->fh->private_options = create_options; - fsp->access_mask = access_mask; + fsp->access_mask = open_access_mask; /* We change this to the requested access_mask after the open is done. */ /* Ensure no SAMBA_PRIVATE bits can be set. */ fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK); @@ -1382,6 +1390,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, return NULL; } + /* Use the client requested access mask here, not the one we open with. */ status = open_mode_check(conn, fname, lck, access_mask, share_access, create_options, &file_existed); @@ -1417,6 +1426,8 @@ files_struct *open_file_ntcreate(connection_struct *conn, (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { files_struct *fsp_dup; + + /* Use the client requested access mask here, not the one we open with. */ fsp_dup = fcb_or_dos_open(conn, fname, dev, inode, access_mask, share_access, @@ -1532,119 +1543,88 @@ files_struct *open_file_ntcreate(connection_struct *conn, (unsigned int)flags, (unsigned int)flags2, (unsigned int)unx_mode)); - /* Drop the lock before doing any real file access. Allows kernel - oplock breaks to be processed. Handle any races after the open - call when we re-acquire the lock. */ - - if (lck) { - TALLOC_FREE(lck); - } - /* * open_file strips any O_TRUNC flags itself. */ fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode, - access_mask); + access_mask, open_access_mask); if (!fsp_open) { + if (lck != NULL) { + TALLOC_FREE(lck); + } file_free(fsp); return NULL; } - /* - * Deal with the race condition where two smbd's detect the - * file doesn't exist and do the create at the same time. One - * of them will win and set a share mode, the other (ie. this - * one) should check if the requested share mode for this - * create is allowed. - */ - - /* - * Now the file exists and fsp is successfully opened, - * fsp->dev and fsp->inode are valid and should replace the - * dev=0,inode=0 from a non existent file. Spotted by - * Nadav Danieli . JRA. - */ - - dev = fsp->dev; - inode = fsp->inode; + if (!file_existed) { - lck = get_share_mode_lock(NULL, dev, inode, - conn->connectpath, - fname); + /* + * Deal with the race condition where two smbd's detect the + * file doesn't exist and do the create at the same time. One + * of them will win and set a share mode, the other (ie. this + * one) should check if the requested share mode for this + * create is allowed. + */ - if (lck == NULL) { - DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname)); - fd_close(conn, fsp); - file_free(fsp); - set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION); - return NULL; - } + /* + * Now the file exists and fsp is successfully opened, + * fsp->dev and fsp->inode are valid and should replace the + * dev=0,inode=0 from a non existent file. Spotted by + * Nadav Danieli . JRA. + */ - /* - * The share entry is again *locked*..... - */ + dev = fsp->dev; + inode = fsp->inode; - /* First pass - send break only on batch oplocks. */ - if (delay_for_oplocks(lck, fsp, 1, oplock_request)) { - schedule_defer_open(lck, request_time); - fd_close(conn, fsp); - file_free(fsp); - TALLOC_FREE(lck); - set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION); - return NULL; - } - - status = open_mode_check(conn, fname, lck, - access_mask, share_access, - create_options, &file_existed); + lck = get_share_mode_lock(NULL, dev, inode, + conn->connectpath, + fname); - if (NT_STATUS_IS_OK(status)) { - /* We might be going to allow this open. Check oplock status again. */ - /* Second pass - send break for both batch or exclusive oplocks. */ - if (delay_for_oplocks(lck, fsp, 2, oplock_request)) { - schedule_defer_open(lck, request_time); + if (lck == NULL) { + DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname)); fd_close(conn, fsp); file_free(fsp); - TALLOC_FREE(lck); set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION); return NULL; } - } - if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { - /* DELETE_PENDING is not deferred for a second */ - fd_close(conn, fsp); - file_free(fsp); - TALLOC_FREE(lck); - set_saved_ntstatus(status); - return NULL; - } + status = open_mode_check(conn, fname, lck, + access_mask, share_access, + create_options, &file_existed); - if (!NT_STATUS_IS_OK(status)) { - struct deferred_open_record state; + if (!NT_STATUS_IS_OK(status)) { + struct deferred_open_record state; - fd_close(conn, fsp); - file_free(fsp); + fd_close(conn, fsp); + file_free(fsp); - state.delayed_for_oplocks = False; - state.dev = dev; - state.inode = inode; + state.delayed_for_oplocks = False; + state.dev = dev; + state.inode = inode; - /* Do it all over again immediately. In the second - * round we will find that the file existed and handle - * the DELETE_PENDING and FCB cases correctly. No need - * to duplicate the code here. Essentially this is a - * "goto top of this function", but don't tell - * anybody... */ + /* Do it all over again immediately. In the second + * round we will find that the file existed and handle + * the DELETE_PENDING and FCB cases correctly. No need + * to duplicate the code here. Essentially this is a + * "goto top of this function", but don't tell + * anybody... */ + + defer_open(lck, request_time, timeval_zero(), + &state); + TALLOC_FREE(lck); + return NULL; + } + + /* + * We exit this block with the share entry *locked*..... + */ - defer_open(lck, request_time, timeval_zero(), - &state); - TALLOC_FREE(lck); - return NULL; } + SMB_ASSERT(lck != NULL); + /* note that we ignore failure for the following. It is basically a hack for NFS, and NFS will never set one of these only read them. Nobody but Samba can ever set a deny @@ -1685,7 +1665,7 @@ files_struct *open_file_ntcreate(connection_struct *conn, if (file_existed) { /* stat opens on existing files don't get oplocks. */ - if (is_stat_open(fsp->access_mask)) { + if (is_stat_open(open_access_mask)) { fsp->oplock_type = NO_OPLOCK; } @@ -1828,7 +1808,7 @@ files_struct *open_file_fchmod(connection_struct *conn, const char *fname, /* note! we must use a non-zero desired access or we don't get a real file descriptor. Oh what a twisted web we weave. */ - fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA); + fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA,FILE_WRITE_DATA); /* * This is not a user visible file open. diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 5e84f229aa2..31a6b80912a 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -24,22 +24,6 @@ #include "includes.h" #include "utils/net.h" -/* Macro for checking RPC error codes to make things more readable */ - -#if 0 -#define CHECK_RPC_ERR(rpc, msg) \ - if (!NT_STATUS_IS_OK(result = rpc)) { \ - DEBUG(0, (msg ": %s\n", nt_errstr(result))); \ - goto done; \ - } - -#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \ - if (!NT_STATUS_IS_OK(result = rpc)) { \ - DEBUG(0, debug_args); \ - goto done; \ - } - -#endif #ifdef HAVE_ADS int net_ads_usage(int argc, const char **argv) @@ -944,7 +928,7 @@ done: static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s ) { ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN); - char *host_upn, *new_dn; + char *new_dn; ADS_MODLIST mods; const char *servicePrincipalName[3] = {NULL, NULL, NULL}; char *psp; @@ -980,9 +964,7 @@ static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s ) return ADS_ERROR(LDAP_NO_MEMORY); } - /* Windows only creates HOST/shortname & HOST/fqdn. We create - the UPN as well so that 'kinit -k' will work. You can only - request a TGT for entries with a UPN in AD. */ + /* Windows only creates HOST/shortname & HOST/fqdn. */ if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) ) goto done; @@ -995,9 +977,63 @@ static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s ) goto done; servicePrincipalName[1] = psp; - if (!(host_upn = talloc_asprintf(ctx, "%s@%s", servicePrincipalName[0], ads_s->config.realm))) + if (!(mods = ads_init_mods(ctx))) { goto done; + } + + /* fields of primary importance */ + + ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn); + ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); + + status = ads_gen_mod(ads_s, new_dn, mods); + +done: + ads_msgfree(ads_s, res); + + return status; +} + +/******************************************************************* + Set a machines dNSHostName and servicePrincipalName attributes + ********************************************************************/ +static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn ) +{ + ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN); + char *new_dn; + ADS_MODLIST mods; + LDAPMessage *res = NULL; + char *dn_string = NULL; + const char *machine_name = global_myname(); + int count; + + if ( !machine_name ) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + /* Find our DN */ + + status = ads_find_machine_acct(ads_s, (void **)(void *)&res, machine_name); + if (!ADS_ERR_OK(status)) + return status; + + if ( (count = ads_count_replies(ads_s, res)) != 1 ) { + DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count)); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) { + DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n")); + goto done; + } + + new_dn = talloc_strdup(ctx, dn_string); + ads_memfree(ads_s, dn_string); + if (!new_dn) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + /* now do the mods */ if (!(mods = ads_init_mods(ctx))) { @@ -1006,8 +1042,7 @@ static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s ) /* fields of primary importance */ - ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn); - ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName); + ads_mod_str(ctx, &mods, "userPrincipalName", upn); status = ads_gen_mod(ads_s, new_dn, mods); @@ -1017,7 +1052,6 @@ done: return status; } - /******************************************************************* join a domain using ADS (LDAP mods) ********************************************************************/ @@ -1105,6 +1139,19 @@ static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads ) return kerberos_secrets_store_des_salt( salt ); } +/********************************************************* + utility function to parse an integer parameter from + "parameter = value" +**********************************************************/ +static char* get_string_param( const char* param ) +{ + char *p; + + if ( (p = strchr( param, '=' )) == NULL ) + return NULL; + + return (p+1); +} /******************************************************************* join a domain using ADS (LDAP mods) ********************************************************************/ @@ -1119,6 +1166,10 @@ int net_ads_join(int argc, const char **argv) struct cldap_netlogon_reply cldap_reply; TALLOC_CTX *ctx; DOM_SID *domain_sid = NULL; + BOOL createupn = False; + const char *machineupn = NULL; + const char *create_in_ou = NULL; + int i; if ( check_ads_config() != 0 ) { d_fprintf(stderr, "Invalid configuration. Exiting....\n"); @@ -1142,11 +1193,30 @@ int net_ads_join(int argc, const char **argv) return -1; } - /* If we were given an OU, try to create the machine in the OU account - first and then do the normal RPC join */ + /* process additional command line args */ + + for ( i=0; i 0 ) { - status = net_precreate_machine_acct( ads, argv[0] ); + /* If we were given an OU, try to create the machine in + the OU account first and then do the normal RPC join */ + + if ( create_in_ou ) { + status = net_precreate_machine_acct( ads, create_in_ou ); if ( !ADS_ERR_OK(status) ) { d_fprintf( stderr, "Failed to pre-create the machine object " "in OU %s.\n", argv[0]); @@ -1208,11 +1278,24 @@ int net_ads_join(int argc, const char **argv) status = net_set_machine_spn( ctx, ads ); if ( !ADS_ERR_OK(status) ) { - d_fprintf(stderr, "Failed to set servicePrincipalNames. Only NTLM authentication will be possible.\n"); - d_fprintf(stderr, "Please ensure that the DNS domain of this server matches the AD domain,\n"); - d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n"); - /* don't fail */ + d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n"); + d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n"); + d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n"); + + /* Disable the machine account in AD. Better to fail than to leave + a confused admin. */ + + if ( net_ads_leave( 0, NULL ) != 0 ) { + d_fprintf( stderr, "Failed to disable machine account in AD. Please do so manually.\n"); + } + + /* clear out the machine password */ + + netdom_store_machine_account( lp_workgroup(), domain_sid, "" ); + netdom_store_machine_account( short_domain_name, domain_sid, "" ); + + return -1; } if ( !net_derive_salting_principal( ctx, ads ) ) { @@ -1221,6 +1304,22 @@ int net_ads_join(int argc, const char **argv) return -1; } + if ( createupn ) { + pstring upn; + + /* default to using the short UPN name */ + if ( !machineupn ) { + snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(), + ads->config.realm ); + machineupn = upn; + } + + status = net_set_machine_upn( ctx, ads, machineupn ); + if ( !ADS_ERR_OK(status) ) { + d_fprintf(stderr, "Failed to set userPrincipalName. Are you a Domain Admin?\n"); + } + } + /* Now build the keytab, using the same ADS connection */ if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) { DEBUG(1,("Error creating host keytab!\n")); @@ -1891,15 +1990,12 @@ int net_ads_help(int argc, const char **argv) {"GROUP", net_ads_group_usage}, {"PRINTER", net_ads_printer_usage}, {"SEARCH", net_ads_search_usage}, -#if 0 {"INFO", net_ads_info}, {"JOIN", net_ads_join}, - {"JOIN2", net_ads_join2}, {"LEAVE", net_ads_leave}, {"STATUS", net_ads_status}, {"PASSWORD", net_ads_password}, {"CHANGETRUSTPW", net_ads_changetrustpw}, -#endif {NULL, NULL} }; @@ -1991,4 +2087,4 @@ int net_ads(int argc, const char **argv) return net_ads_usage(argc, argv); } -#endif +#endif /* WITH_ADS */ -- cgit